diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-05-10 22:37:35 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-05-10 23:31:49 +0100 |
commit | 99d1330b79a6b8457b45bba2a7b9940b1f2e9acd (patch) | |
tree | 43459717de6d35d858dce11932a29700444967d6 /gcc/rust | |
parent | 3ff2b34d5bf7bd4e9bb3cadcb72c1d91c8771f82 (diff) | |
download | gcc-99d1330b79a6b8457b45bba2a7b9940b1f2e9acd.zip gcc-99d1330b79a6b8457b45bba2a7b9940b1f2e9acd.tar.gz gcc-99d1330b79a6b8457b45bba2a7b9940b1f2e9acd.tar.bz2 |
Handle inherited type arguments for methods
MethodCallExpr's support generic arguments so we need to handle adjusting
any inherited type arguments from the receiver and apply them to the func.
This changes the handle_substitutions function for ADT, FnType and Params
to be permissive that we can send single arguments to partially substitute
the type such as the case when we inherit arguments in methods calls. This
is safe because the other interfaces enforce the type checking and number
of arguments etc.
Fixes #423
Diffstat (limited to 'gcc/rust')
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 65 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.cc | 163 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 15 |
3 files changed, 156 insertions, 87 deletions
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 5df6b70..3e081ec 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -255,13 +255,70 @@ public: TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver_tyty); if (adt->has_substitutions () && fn->needs_substitution ()) { - rust_assert (adt->was_substituted ()); - auto used_args_in_prev_segment = GetUsedSubstArgs::From (adt); - lookup - = SubstMapperInternal::Resolve (fn, used_args_in_prev_segment); + // 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 (); + rust_assert (s->can_eq (adt)); + rust_assert (s->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *self_adt = static_cast<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); + } + } } } + // apply any remaining generic arguments + if (expr.get_method_name ().has_generic_args ()) + { + HIR::GenericArgs &args = expr.get_method_name ().get_generic_args (); + lookup + = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (), + &args); + if (lookup->get_kind () == TyTy::TypeKind::ERROR) + return; + } + else if (lookup->needs_generic_substitutions ()) + { + lookup = SubstMapper::InferSubst (lookup, + expr.get_method_name ().get_locus ()); + } + TyTy::BaseType *function_ret_tyty = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, context); if (function_ret_tyty == nullptr diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 8c45573..e74ab93 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -247,6 +247,9 @@ SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args) return SubstitutionArgumentMappings::error (); } + // for inherited arguments + size_t offs = used_arguments.size (); + std::vector<SubstitutionArg> mappings; for (auto &arg : args.get_type_args ()) { @@ -257,8 +260,8 @@ SubstitutionRef::get_mappings_from_generic_args (HIR::GenericArgs &args) return SubstitutionArgumentMappings::error (); } - SubstitutionArg subst_arg (&substitutions.at (mappings.size ()), - resolved); + SubstitutionArg subst_arg (&substitutions.at (offs), resolved); + offs++; mappings.push_back (std::move (subst_arg)); } @@ -345,6 +348,31 @@ SubstitutionRef::adjust_mappings_for_this ( mappings.get_locus ()); } +// this function assumes that the mappings being passed are for the same type as +// this new substitution reference so ordering matters here +SubstitutionArgumentMappings +SubstitutionRef::solve_mappings_from_receiver_for_self ( + SubstitutionArgumentMappings &mappings) +{ + std::vector<SubstitutionArg> resolved_mappings; + + rust_assert (mappings.size () == get_num_substitutions ()); + for (size_t i = 0; i < get_num_substitutions (); i++) + { + SubstitutionParamMapping ¶m_mapping = substitutions.at (i); + SubstitutionArg &arg = mappings.get_mappings ().at (i); + + if (param_mapping.needs_substitution ()) + { + SubstitutionArg adjusted (¶m_mapping, arg.get_tyty ()); + resolved_mappings.push_back (std::move (adjusted)); + } + } + + return SubstitutionArgumentMappings (resolved_mappings, + mappings.get_locus ()); +} + void ADTType::accept_vis (TyVisitor &vis) { @@ -457,13 +485,6 @@ ADTType::clone () ADTType * ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) { - if (subst_mappings.size () != get_num_substitutions ()) - { - rust_error_at (subst_mappings.get_locus (), - "invalid number of generic arguments to generic ADT type"); - return nullptr; - } - ADTType *adt = static_cast<ADTType *> (clone ()); adt->set_ty_ref (mappings->get_next_hir_id ()); adt->used_arguments = subst_mappings; @@ -473,8 +494,8 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); - rust_assert (ok); - sub.fill_param_ty (arg.get_tyty ()); + if (ok) + sub.fill_param_ty (arg.get_tyty ()); } adt->iterate_fields ([&] (StructFieldType *field) mutable -> bool { @@ -486,27 +507,22 @@ ADTType::handle_substitions (SubstitutionArgumentMappings subst_mappings) SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (p, &arg); - if (!ok) - { - rust_error_at (subst_mappings.get_locus (), - "Failed to resolve parameter type: %s", - p->as_string ().c_str ()); - return false; - } - - auto argt = arg.get_tyty (); - bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; - bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; - - if (arg_is_param || arg_is_concrete) - { - auto new_field = argt->clone (); - new_field->set_ref (fty->get_ref ()); - field->set_field_type (new_field); - } - else + if (ok) { - field->get_field_type ()->set_ty_ref (argt->get_ref ()); + auto argt = arg.get_tyty (); + bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; + bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; + + if (arg_is_param || arg_is_concrete) + { + auto new_field = argt->clone (); + new_field->set_ref (fty->get_ref ()); + field->set_field_type (new_field); + } + else + { + field->get_field_type ()->set_ty_ref (argt->get_ref ()); + } } } else if (fty->has_subsititions_defined () @@ -695,14 +711,6 @@ FnType::clone () FnType * FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) { - if (subst_mappings.size () != get_num_substitutions ()) - { - rust_error_at ( - subst_mappings.get_locus (), - "invalid number of generic arguments to generic Function type"); - return nullptr; - } - FnType *fn = static_cast<FnType *> (clone ()); fn->set_ty_ref (mappings->get_next_hir_id ()); fn->used_arguments = subst_mappings; @@ -713,8 +721,8 @@ FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); - rust_assert (ok); - sub.fill_param_ty (arg.get_tyty ()); + if (ok) + sub.fill_param_ty (arg.get_tyty ()); } auto fty = fn->get_return_type (); @@ -725,27 +733,22 @@ FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (p, &arg); - if (!ok) + if (ok) { - rust_error_at (subst_mappings.get_locus (), - "Failed to resolve parameter type: %s", - p->as_string ().c_str ()); - return nullptr; - } - - auto argt = arg.get_tyty (); - bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; - bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; + auto argt = arg.get_tyty (); + bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; + bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; - if (arg_is_param || arg_is_concrete) - { - auto new_field = argt->clone (); - new_field->set_ref (fty->get_ref ()); - fn->type = new_field; - } - else - { - fty->set_ty_ref (argt->get_ref ()); + if (arg_is_param || arg_is_concrete) + { + auto new_field = argt->clone (); + new_field->set_ref (fty->get_ref ()); + fn->type = new_field; + } + else + { + fty->set_ty_ref (argt->get_ref ()); + } } } else if (fty->needs_generic_substitutions () @@ -778,27 +781,22 @@ FnType::handle_substitions (SubstitutionArgumentMappings subst_mappings) SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (p, &arg); - if (!ok) + if (ok) { - rust_error_at (subst_mappings.get_locus (), - "Failed to resolve parameter type: %s", - p->as_string ().c_str ()); - return nullptr; - } - - auto argt = arg.get_tyty (); - bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; - bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; - - if (arg_is_param || arg_is_concrete) - { - auto new_field = argt->clone (); - new_field->set_ref (fty->get_ref ()); - param.second = new_field; - } - else - { - fty->set_ty_ref (argt->get_ref ()); + auto argt = arg.get_tyty (); + bool arg_is_param = argt->get_kind () == TyTy::TypeKind::PARAM; + bool arg_is_concrete = argt->get_kind () != TyTy::TypeKind::INFER; + + if (arg_is_param || arg_is_concrete) + { + auto new_field = argt->clone (); + new_field->set_ref (fty->get_ref ()); + param.second = new_field; + } + else + { + fty->set_ty_ref (argt->get_ref ()); + } } } else if (fty->has_subsititions_defined () @@ -1396,9 +1394,8 @@ ParamType::handle_substitions (SubstitutionArgumentMappings mappings) SubstitutionArg arg = SubstitutionArg::error (); bool ok = mappings.get_argument_for_symbol (this, &arg); - rust_assert (ok); - - p->set_ty_ref (arg.get_tyty ()->get_ref ()); + if (ok) + p->set_ty_ref (arg.get_tyty ()->get_ref ()); return p; } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index dd530ec..7425030 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -698,6 +698,21 @@ public: SubstitutionArgumentMappings adjust_mappings_for_this (SubstitutionArgumentMappings &mappings); + // struct Foo<A, B>(A, B); + // + // impl<T> Foo<T, f32>; + // -> fn test<X>(self, a: X) -> X + // + // We might invoke this via: + // + // a = Foo(123, 456f32); + // b = a.test::<bool>(false); + // + // we need to figure out relevant generic arguemts for self to apply to the + // fntype + SubstitutionArgumentMappings solve_mappings_from_receiver_for_self ( + SubstitutionArgumentMappings &mappings); + BaseType *infer_substitions (Location locus) { std::vector<SubstitutionArg> args; |