From 3df65d5b4ec06c7ac1ec39d8d1a1c268b024531c Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Sun, 25 Apr 2021 15:41:56 +0100 Subject: Support partial substitution's When we have a generic data type with 2 type parameters A,B but then add an impl block for this type and this impl block only defines 1 Type parameter and substitutes the other type parameter with a concrete type we need to use the passed in mappings and the existing mappings to figure out how to adjust the type parameters to complete the substitution. Fixes: #386 --- gcc/rust/typecheck/rust-substitution-mapper.h | 4 +++ gcc/rust/typecheck/rust-tyty.cc | 35 ++++++++++++++++++--------- gcc/rust/typecheck/rust-tyty.h | 22 +++++++++++++++++ gcc/testsuite/rust.test/compile/generics19.rs | 12 +++++++++ gcc/testsuite/rust.test/compile/generics20.rs | 12 +++++++++ 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/rust.test/compile/generics19.rs create mode 100644 gcc/testsuite/rust.test/compile/generics20.rs (limited to 'gcc') diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index 37a82c4..d022019 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -133,6 +133,8 @@ public: { TyTy::SubstitutionArgumentMappings adjusted = type.adjust_mappings_for_this (mappings); + if (adjusted.is_error ()) + return; TyTy::BaseType *concrete = type.handle_substitions (adjusted); if (concrete != nullptr) @@ -143,6 +145,8 @@ public: { TyTy::SubstitutionArgumentMappings adjusted = type.adjust_mappings_for_this (mappings); + if (adjusted.is_error ()) + return; TyTy::BaseType *concrete = type.handle_substitions (adjusted); if (concrete != nullptr) diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index baa997b..8cc9089 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -242,15 +242,6 @@ SubstitutionArgumentMappings SubstitutionRef::adjust_mappings_for_this ( SubstitutionArgumentMappings &mappings) { - if (substitutions.size () > mappings.size ()) - { - rust_error_at (mappings.get_locus (), - "not enough type arguments: subs %s vs mappings %s", - subst_as_string ().c_str (), - mappings.as_string ().c_str ()); - return SubstitutionArgumentMappings::error (); - } - Analysis::Mappings *mappings_table = Analysis::Mappings::get (); std::vector resolved_mappings; @@ -259,13 +250,33 @@ SubstitutionRef::adjust_mappings_for_this ( auto &subst = substitutions.at (i); SubstitutionArg arg = SubstitutionArg::error (); - bool ok = mappings.get_argument_at (0, &arg); + if (mappings.size () == substitutions.size ()) + { + mappings.get_argument_at (i, &arg); + } + else + { + if (subst.needs_substitution ()) + { + // get from passed in mappings + mappings.get_argument_for_symbol (subst.get_param_ty (), &arg); + } + else + { + // we should already have this somewhere + used_arguments.get_argument_for_symbol (subst.get_param_ty (), + &arg); + } + } + + bool ok = !arg.is_error (); if (!ok) { rust_error_at (mappings_table->lookup_location ( subst.get_param_ty ()->get_ref ()), - "failed to find parameter type: %s", - subst.get_param_ty ()->as_string ().c_str ()); + "failed to find parameter type: %s vs mappings [%s]", + subst.get_param_ty ()->as_string ().c_str (), + mappings.as_string ().c_str ()); return SubstitutionArgumentMappings::error (); } diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index bc4c9c4..f3ff609 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -408,6 +408,15 @@ public: void override_context (); + bool needs_substitution () const + { + auto p = get_param_ty (); + if (!p->can_resolve ()) + return true; + + return p->resolve ()->get_kind () == TypeKind::PARAM; + } + private: std::unique_ptr &generic; ParamType *param; @@ -437,6 +446,8 @@ public: static SubstitutionArg error () { return SubstitutionArg (nullptr, nullptr); } + bool is_error () const { return param == nullptr || argument == nullptr; } + bool is_conrete () const { return argument != nullptr && argument->get_kind () != TyTy::TypeKind::ERROR @@ -600,6 +611,17 @@ public: return used_arguments; } + size_t num_required_substitutions () const + { + size_t n = 0; + for (auto &p : substitutions) + { + if (p.needs_substitution ()) + n++; + } + return n; + } + // We are trying to subst into Struct Foo {} // in the case of Foo{...} // diff --git a/gcc/testsuite/rust.test/compile/generics19.rs b/gcc/testsuite/rust.test/compile/generics19.rs new file mode 100644 index 0000000..9a5b4cb --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics19.rs @@ -0,0 +1,12 @@ +struct Foo(X, Y); + +impl Foo { + fn new(a: T) -> Self { + Self(123, a) + } +} + +fn main() { + let a; + a = Foo::new(false); +} diff --git a/gcc/testsuite/rust.test/compile/generics20.rs b/gcc/testsuite/rust.test/compile/generics20.rs new file mode 100644 index 0000000..8fe1cff --- /dev/null +++ b/gcc/testsuite/rust.test/compile/generics20.rs @@ -0,0 +1,12 @@ +struct Foo(A, B); + +impl Foo { + fn new(a: T, b: T) -> Self { + Self(a, b) + } +} + +fn main() { + let a; + a = Foo::new(123, 456); +} -- cgit v1.1