diff options
author | Philip Herron <philip.herron@embecosm.com> | 2022-02-24 16:02:50 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2022-02-24 16:02:50 +0000 |
commit | 5d5396d52277be5e2c82249f889a78d909f29084 (patch) | |
tree | 7bd41cb281f4b437185efbc1b82822864f9ed30e /gcc | |
parent | 3b3079eba5f9faa5fe6623314a367b44070f9c19 (diff) | |
download | gcc-5d5396d52277be5e2c82249f889a78d909f29084.zip gcc-5d5396d52277be5e2c82249f889a78d909f29084.tar.gz gcc-5d5396d52277be5e2c82249f889a78d909f29084.tar.bz2 |
Refactor operator overloading code into cc file
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.cc | 186 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 186 |
2 files changed, 187 insertions, 185 deletions
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 0269433..2703d91 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -286,5 +286,191 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) infered = array_type->get_element_type ()->clone (); } +bool +TypeCheckExpr::resolve_operator_overload ( + Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExpr &expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs) +{ + // look up lang item for arithmetic type + std::string associated_item_name + = Analysis::RustLangItem::ToString (lang_item_type); + DefId respective_lang_item_id = UNKNOWN_DEFID; + bool lang_item_defined + = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id); + + // probe for the lang-item + if (!lang_item_defined) + return false; + + auto segment = HIR::PathIdentSegment (associated_item_name); + auto candidate + = MethodResolver::Probe (lhs, HIR::PathIdentSegment (associated_item_name)); + + bool have_implementation_for_lang_item = !candidate.is_error (); + if (!have_implementation_for_lang_item) + return false; + + // Get the adjusted self + Adjuster adj (lhs); + TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); + + // is this the case we are recursive + // handle the case where we are within the impl block for this lang_item + // otherwise we end up with a recursive operator overload such as the i32 + // operator overload trait + TypeCheckContextItem &fn_context = context->peek_context (); + if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM) + { + auto &impl_item = fn_context.get_impl_item (); + HIR::ImplBlock *parent = impl_item.first; + HIR::Function *fn = impl_item.second; + + if (parent->has_trait_ref () + && fn->get_function_name ().compare (associated_item_name) == 0) + { + TraitReference *trait_reference + = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); + if (!trait_reference->is_error ()) + { + TyTy::BaseType *lookup = nullptr; + bool ok = context->lookup_type (fn->get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); + + TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); + rust_assert (fntype->is_method ()); + + bool is_lang_item_impl + = trait_reference->get_mappings ().get_defid () + == respective_lang_item_id; + bool self_is_lang_item_self + = fntype->get_self_type ()->is_equal (*adjusted_self); + bool recursive_operator_overload + = is_lang_item_impl && self_is_lang_item_self; + + if (recursive_operator_overload) + return false; + } + } + } + + // store the adjustments for code-generation to know what to do + context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (), + std::move (candidate.adjustments)); + + // now its just like a method-call-expr + context->insert_receiver (expr.get_mappings ().get_hirid (), lhs); + + PathProbeCandidate &resolved_candidate = candidate.candidate; + TyTy::BaseType *lookup_tyty = candidate.candidate.ty; + NodeId resolved_node_id + = resolved_candidate.is_impl_candidate () + ? resolved_candidate.item.impl.impl_item->get_impl_mappings () + .get_nodeid () + : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid (); + + rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::BaseType *lookup = lookup_tyty; + TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup); + rust_assert (fn->is_method ()); + + auto root = lhs->get_root (); + bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; + if (root->get_kind () == TyTy::TypeKind::ADT) + { + const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root); + if (adt->has_substitutions () && fn->needs_substitution ()) + { + // consider the case where we have: + // + // struct Foo<X,Y>(X,Y); + // + // impl<T> Foo<T, i32> { + // fn test<X>(self, a:X) -> (T,X) { (self.0, a) } + // } + // + // In this case we end up with an fn type of: + // + // fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X) + // + // This means the instance or self we are calling this method for + // will be substituted such that we can get the inherited type + // arguments but then need to use the turbo fish if available or + // infer the remaining arguments. Luckily rust does not allow for + // default types GenericParams on impl blocks since these must + // always be at the end of the list + + auto s = fn->get_self_type ()->get_root (); + rust_assert (s->can_eq (adt, false)); + rust_assert (s->get_kind () == TyTy::TypeKind::ADT); + const TyTy::ADTType *self_adt + = static_cast<const TyTy::ADTType *> (s); + + // we need to grab the Self substitutions as the inherit type + // parameters for this + if (self_adt->needs_substitution ()) + { + rust_assert (adt->was_substituted ()); + + TyTy::SubstitutionArgumentMappings used_args_in_prev_segment + = GetUsedSubstArgs::From (adt); + + TyTy::SubstitutionArgumentMappings inherit_type_args + = self_adt->solve_mappings_from_receiver_for_self ( + used_args_in_prev_segment); + + // there may or may not be inherited type arguments + if (!inherit_type_args.is_error ()) + { + // need to apply the inherited type arguments to the + // function + lookup = fn->handle_substitions (inherit_type_args); + } + } + } + } + + // handle generics + if (!receiver_is_type_param) + { + if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); + } + } + + // type check the arguments if required + TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup); + rust_assert (type->num_params () > 0); + auto fnparam = type->param_at (0); + fnparam.second->unify (adjusted_self); // typecheck the self + if (rhs == nullptr) + { + rust_assert (type->num_params () == 1); + } + else + { + rust_assert (type->num_params () == 2); + auto fnparam = type->param_at (1); + fnparam.second->unify (rhs); // typecheck the rhs + } + + // get the return type + TyTy::BaseType *function_ret_tyty = type->get_return_type ()->clone (); + + // store the expected fntype + context->insert_operator_overload (expr.get_mappings ().get_hirid (), type); + + // set up the resolved name on the path + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); + + // return the result of the function back + infered = function_ret_tyty; + + return true; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 5b96854f..e222528 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -1240,191 +1240,7 @@ protected: bool resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExpr &expr, TyTy::BaseType *lhs, - TyTy::BaseType *rhs) - { - // look up lang item for arithmetic type - std::string associated_item_name - = Analysis::RustLangItem::ToString (lang_item_type); - DefId respective_lang_item_id = UNKNOWN_DEFID; - bool lang_item_defined - = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id); - - // probe for the lang-item - if (!lang_item_defined) - return false; - - auto segment = HIR::PathIdentSegment (associated_item_name); - auto candidate - = MethodResolver::Probe (lhs, - HIR::PathIdentSegment (associated_item_name)); - - bool have_implementation_for_lang_item = !candidate.is_error (); - if (!have_implementation_for_lang_item) - return false; - - // Get the adjusted self - Adjuster adj (lhs); - TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); - - // is this the case we are recursive - // handle the case where we are within the impl block for this lang_item - // otherwise we end up with a recursive operator overload such as the i32 - // operator overload trait - TypeCheckContextItem &fn_context = context->peek_context (); - if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM) - { - auto &impl_item = fn_context.get_impl_item (); - HIR::ImplBlock *parent = impl_item.first; - HIR::Function *fn = impl_item.second; - - if (parent->has_trait_ref () - && fn->get_function_name ().compare (associated_item_name) == 0) - { - TraitReference *trait_reference - = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); - if (!trait_reference->is_error ()) - { - TyTy::BaseType *lookup = nullptr; - bool ok - = context->lookup_type (fn->get_mappings ().get_hirid (), - &lookup); - rust_assert (ok); - rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); - - TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); - rust_assert (fntype->is_method ()); - - bool is_lang_item_impl - = trait_reference->get_mappings ().get_defid () - == respective_lang_item_id; - bool self_is_lang_item_self - = fntype->get_self_type ()->is_equal (*adjusted_self); - bool recursive_operator_overload - = is_lang_item_impl && self_is_lang_item_self; - - if (recursive_operator_overload) - return false; - } - } - } - - // store the adjustments for code-generation to know what to do - context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (), - std::move (candidate.adjustments)); - - // now its just like a method-call-expr - context->insert_receiver (expr.get_mappings ().get_hirid (), lhs); - - PathProbeCandidate &resolved_candidate = candidate.candidate; - TyTy::BaseType *lookup_tyty = candidate.candidate.ty; - NodeId resolved_node_id - = resolved_candidate.is_impl_candidate () - ? resolved_candidate.item.impl.impl_item->get_impl_mappings () - .get_nodeid () - : resolved_candidate.item.trait.item_ref->get_mappings () - .get_nodeid (); - - rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::BaseType *lookup = lookup_tyty; - TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup); - rust_assert (fn->is_method ()); - - auto root = lhs->get_root (); - bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; - if (root->get_kind () == TyTy::TypeKind::ADT) - { - const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root); - if (adt->has_substitutions () && fn->needs_substitution ()) - { - // consider the case where we have: - // - // struct Foo<X,Y>(X,Y); - // - // impl<T> Foo<T, i32> { - // fn test<X>(self, a:X) -> (T,X) { (self.0, a) } - // } - // - // In this case we end up with an fn type of: - // - // fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X) - // - // This means the instance or self we are calling this method for - // will be substituted such that we can get the inherited type - // arguments but then need to use the turbo fish if available or - // infer the remaining arguments. Luckily rust does not allow for - // default types GenericParams on impl blocks since these must - // always be at the end of the list - - auto s = fn->get_self_type ()->get_root (); - rust_assert (s->can_eq (adt, false)); - rust_assert (s->get_kind () == TyTy::TypeKind::ADT); - const TyTy::ADTType *self_adt - = static_cast<const TyTy::ADTType *> (s); - - // we need to grab the Self substitutions as the inherit type - // parameters for this - if (self_adt->needs_substitution ()) - { - rust_assert (adt->was_substituted ()); - - TyTy::SubstitutionArgumentMappings used_args_in_prev_segment - = GetUsedSubstArgs::From (adt); - - TyTy::SubstitutionArgumentMappings inherit_type_args - = self_adt->solve_mappings_from_receiver_for_self ( - used_args_in_prev_segment); - - // there may or may not be inherited type arguments - if (!inherit_type_args.is_error ()) - { - // need to apply the inherited type arguments to the - // function - lookup = fn->handle_substitions (inherit_type_args); - } - } - } - } - - // handle generics - if (!receiver_is_type_param) - { - if (lookup->needs_generic_substitutions ()) - { - lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); - } - } - - // type check the arguments if required - TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup); - rust_assert (type->num_params () > 0); - auto fnparam = type->param_at (0); - fnparam.second->unify (adjusted_self); // typecheck the self - if (rhs == nullptr) - { - rust_assert (type->num_params () == 1); - } - else - { - rust_assert (type->num_params () == 2); - auto fnparam = type->param_at (1); - fnparam.second->unify (rhs); // typecheck the rhs - } - - // get the return type - TyTy::BaseType *function_ret_tyty = type->get_return_type ()->clone (); - - // store the expected fntype - context->insert_operator_overload (expr.get_mappings ().get_hirid (), type); - - // set up the resolved name on the path - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); - - // return the result of the function back - infered = function_ret_tyty; - - return true; - } + TyTy::BaseType *rhs); private: TypeCheckExpr (bool inside_loop) |