aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-05-10 22:37:35 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-05-10 23:31:49 +0100
commit99d1330b79a6b8457b45bba2a7b9940b1f2e9acd (patch)
tree43459717de6d35d858dce11932a29700444967d6
parent3ff2b34d5bf7bd4e9bb3cadcb72c1d91c8771f82 (diff)
downloadgcc-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
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h65
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc163
-rw-r--r--gcc/rust/typecheck/rust-tyty.h15
-rw-r--r--gcc/testsuite/rust.test/compile/generics29.rs16
-rw-r--r--gcc/testsuite/rust.test/compile/generics30.rs16
-rw-r--r--gcc/testsuite/rust.test/compile/generics31.rs15
-rw-r--r--gcc/testsuite/rust.test/compile/generics32.rs15
7 files changed, 218 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 &param_mapping = substitutions.at (i);
+ SubstitutionArg &arg = mappings.get_mappings ().at (i);
+
+ if (param_mapping.needs_substitution ())
+ {
+ SubstitutionArg adjusted (&param_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;
diff --git a/gcc/testsuite/rust.test/compile/generics29.rs b/gcc/testsuite/rust.test/compile/generics29.rs
new file mode 100644
index 0000000..e09a104
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/generics29.rs
@@ -0,0 +1,16 @@
+struct Foo<A, B>(A, B);
+
+impl Foo<i32, f32> {
+ fn test<X>(self, a: X) -> X {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ a
+ }
+}
+
+fn main() {
+ let a;
+ a = Foo(123, 456f32);
+
+ let b;
+ b = a.test::<bool>(false);
+}
diff --git a/gcc/testsuite/rust.test/compile/generics30.rs b/gcc/testsuite/rust.test/compile/generics30.rs
new file mode 100644
index 0000000..229f6d1
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/generics30.rs
@@ -0,0 +1,16 @@
+struct Foo<A, B>(A, B);
+
+impl<T> Foo<T, f32> {
+ fn test<X>(self, a: X) -> X {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ a
+ }
+}
+
+fn main() {
+ let a;
+ a = Foo(123, 456f32);
+
+ let b;
+ b = a.test::<bool>(false);
+}
diff --git a/gcc/testsuite/rust.test/compile/generics31.rs b/gcc/testsuite/rust.test/compile/generics31.rs
new file mode 100644
index 0000000..68ad4bf
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/generics31.rs
@@ -0,0 +1,15 @@
+struct Foo<A, B>(A, B);
+
+impl<T> Foo<T, f32> {
+ fn test<X>(self, a: X) -> (T, X) {
+ (self.0, a)
+ }
+}
+
+fn main() {
+ let a;
+ a = Foo(123, 456f32);
+
+ let b;
+ b = a.test::<bool>(false);
+}
diff --git a/gcc/testsuite/rust.test/compile/generics32.rs b/gcc/testsuite/rust.test/compile/generics32.rs
new file mode 100644
index 0000000..21b9cae
--- /dev/null
+++ b/gcc/testsuite/rust.test/compile/generics32.rs
@@ -0,0 +1,15 @@
+struct Foo<A, B>(A, B);
+
+impl<T> Foo<T, f32> {
+ fn test<X>(self, a: X) -> (T, X) {
+ (self.0, a)
+ }
+}
+
+fn main() {
+ let a;
+ a = Foo(123, 456f32);
+
+ let b;
+ b = a.test(false);
+}