diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-07-13 20:34:04 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-07-14 18:57:17 +0100 |
commit | 60b1209d64cee3b47cf9b3f5b9da4f74f03a25bb (patch) | |
tree | ef91aff90b40bb5f3b33d5ea1df31e53419ad6e3 | |
parent | b4ea3a19464b9bc79dad9cf5bb9bffc660718632 (diff) | |
download | gcc-60b1209d64cee3b47cf9b3f5b9da4f74f03a25bb.zip gcc-60b1209d64cee3b47cf9b3f5b9da4f74f03a25bb.tar.gz gcc-60b1209d64cee3b47cf9b3f5b9da4f74f03a25bb.tar.bz2 |
Fix Placeholder type checking
When we are checking a trait impl block, associated types can equal any
type this ensures we update the traits associated types inline with
respective trait-impl-block that implements this trait.
Fixes #456
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-ref.h | 83 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-trait-resolve.h | 103 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-implitem.h | 1 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check.cc | 123 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits6.rs | 23 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/traits3.rs | 22 |
6 files changed, 238 insertions, 117 deletions
diff --git a/gcc/rust/typecheck/rust-hir-trait-ref.h b/gcc/rust/typecheck/rust-hir-trait-ref.h index 96498a5..e255fc4 100644 --- a/gcc/rust/typecheck/rust-hir-trait-ref.h +++ b/gcc/rust/typecheck/rust-hir-trait-ref.h @@ -27,6 +27,7 @@ namespace Resolver { // Data Objects for the associated trait items in a structure we can work with // https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/associated-constants.html +class TypeCheckContext; class TraitItemReference { public: @@ -39,17 +40,11 @@ public: }; TraitItemReference (std::string identifier, bool optional, TraitItemType type, - const HIR::TraitItem *hir_trait_item, TyTy::BaseType *ty, - Location locus) - : identifier (identifier), optional_flag (optional), type (type), - hir_trait_item (hir_trait_item), ty (ty), locus (locus) - {} + HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions, + Location locus); - TraitItemReference (TraitItemReference const &other) - : identifier (other.identifier), optional_flag (other.optional_flag), - type (other.type), hir_trait_item (other.hir_trait_item), ty (other.ty), - locus (other.locus) - {} + TraitItemReference (TraitItemReference const &other); TraitItemReference &operator= (TraitItemReference const &other) { @@ -57,8 +52,13 @@ public: optional_flag = other.optional_flag; type = other.type; hir_trait_item = other.hir_trait_item; - ty = other.ty; + self = other.self; locus = other.locus; + context = other.context; + + inherited_substitutions.reserve (other.inherited_substitutions.size ()); + for (size_t i = 0; i < other.inherited_substitutions.size (); i++) + inherited_substitutions.push_back (other.inherited_substitutions.at (i)); return *this; } @@ -68,7 +68,8 @@ public: static TraitItemReference error () { - return TraitItemReference ("", false, ERROR, nullptr, nullptr, Location ()); + return TraitItemReference ("", false, ERROR, nullptr, nullptr, {}, + Location ()); } static TraitItemReference &error_node () @@ -82,7 +83,7 @@ public: std::string as_string () const { return "(" + trait_item_type_as_string (type) + " " + identifier + " " - + ty->as_string () + ")"; + + ")"; } static std::string trait_item_type_as_string (TraitItemType ty) @@ -109,17 +110,65 @@ public: const HIR::TraitItem *get_hir_trait_item () const { return hir_trait_item; } - TyTy::BaseType *get_tyty () const { return ty; } - Location get_locus () const { return locus; } + const Analysis::NodeMapping &get_mappings () const + { + return hir_trait_item->get_mappings (); + } + + TyTy::BaseType *get_tyty () const + { + rust_assert (hir_trait_item != nullptr); + + switch (type) + { + case CONST: + return get_type_from_constant ( + static_cast</*const*/ HIR::TraitItemConst &> (*hir_trait_item)); + break; + + case TYPE: + return get_type_from_typealias ( + static_cast</*const*/ HIR::TraitItemType &> (*hir_trait_item)); + + case FN: + return get_type_from_fn ( + static_cast</*const*/ HIR::TraitItemFunc &> (*hir_trait_item)); + break; + + default: + return get_error (); + } + + gcc_unreachable (); + return get_error (); + } + private: + TyTy::ErrorType *get_error () const + { + return new TyTy::ErrorType (get_mappings ().get_hirid ()); + } + + TyTy::BaseType *get_type_from_typealias (/*const*/ + HIR::TraitItemType &type) const; + + TyTy::BaseType * + get_type_from_constant (/*const*/ HIR::TraitItemConst &constant) const; + + TyTy::BaseType *get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const; + std::string identifier; bool optional_flag; TraitItemType type; - const HIR::TraitItem *hir_trait_item; - TyTy::BaseType *ty; + HIR::TraitItem *hir_trait_item; + std::vector<TyTy::SubstitutionParamMapping> inherited_substitutions; Location locus; + + TyTy::BaseType + *self; // this is the implict Self TypeParam required for methods + Resolver::TypeCheckContext *context; }; class TraitReference diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 1b83be3..3de68c8 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -55,24 +55,11 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::TYPE, - &type, ty, locus); + &type, self, substitutions, locus); } void visit (HIR::TraitItemConst &cst) override { - // attempt to lookup the type of the trait item function - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (cst.get_mappings ().get_hirid (), &ty)) - { - auto resolved = TypeCheckType::Resolve (cst.get_type ().get ()); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (cst.get_locus (), - "failed to resolve trait constant type"); - return; - } - } - // create trait-item-ref Location locus = cst.get_locus (); bool is_optional = cst.has_expr (); @@ -80,95 +67,11 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::CONST, - &cst, ty, locus); + &cst, self, substitutions, locus); } void visit (HIR::TraitItemFunc &fn) override { - // FIXME this is duplicated in a few places and could be refactored - - // attempt to lookup the type of the trait item function - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (fn.get_mappings ().get_hirid (), &ty)) - { - HIR::TraitFunctionDecl &function = fn.get_decl (); - if (function.has_generics ()) - { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - // Skipping Lifetime completely until better handling. - break; - - case HIR::GenericParam::GenericKind::TYPE: { - auto param_type = TypeResolveGenericParam::Resolve ( - generic_param.get ()); - context->insert_type (generic_param->get_mappings (), - param_type); - - substitutions.push_back (TyTy::SubstitutionParamMapping ( - static_cast<HIR::TypeParam &> (*generic_param), - param_type)); - } - break; - } - } - } - - TyTy::BaseType *ret_type = nullptr; - if (!function.has_return_type ()) - ret_type = new TyTy::TupleType (fn.get_mappings ().get_hirid ()); - else - { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); - if (resolved->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at (fn.get_locus (), - "failed to resolve return type"); - return; - } - - ret_type = resolved->clone (); - ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); - } - - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - if (function.is_method ()) - { - // add the synthetic self param at the front, this is a placeholder - // for compilation to know parameter names. The types are ignored - // but we reuse the HIR identifier pattern which requires it - HIR::SelfParam &self_param = function.get_self (); - HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern ( - "self", self_param.get_locus (), self_param.is_ref (), - self_param.is_mut (), std::unique_ptr<HIR::Pattern> (nullptr)); - context->insert_type (self_param.get_mappings (), self->clone ()); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, - self->clone ())); - } - - for (auto ¶m : function.get_function_params ()) - { - // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ()); - params.push_back (std::pair<HIR::Pattern *, TyTy::BaseType *> ( - param.get_param_name (), param_tyty)); - - context->insert_type (param.get_mappings (), param_tyty); - } - - ty = new TyTy::FnType (fn.get_mappings ().get_hirid (), - function.get_function_name (), - function.is_method (), std::move (params), - ret_type, std::move (substitutions)); - context->insert_type (fn.get_mappings (), ty); - } - // create trait-item-ref Location locus = fn.get_locus (); bool is_optional = fn.has_block_defined (); @@ -176,7 +79,7 @@ public: resolved = TraitItemReference (identifier, is_optional, TraitItemReference::TraitItemType::FN, &fn, - ty, locus); + self, substitutions, locus); } private: diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index b0264e5..0f704ae 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -289,6 +289,7 @@ public: return; } + context->insert_type (trait_item_ref.get_mappings (), lookup->clone ()); resolved_trait_item = trait_item_ref; } diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index d21fb3d..1d97deb 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -375,5 +375,128 @@ TypeCheckType::visit (HIR::ArrayType &type) TyTy::TyVar (base->get_ref ())); } +// rust-hir-trait-ref.h + +TraitItemReference::TraitItemReference ( + std::string identifier, bool optional, TraitItemType type, + HIR::TraitItem *hir_trait_item, TyTy::BaseType *self, + std::vector<TyTy::SubstitutionParamMapping> substitutions, Location locus) + : identifier (identifier), optional_flag (optional), type (type), + hir_trait_item (hir_trait_item), inherited_substitutions (substitutions), + locus (locus), self (self), context (TypeCheckContext::get ()) +{} + +TraitItemReference::TraitItemReference (TraitItemReference const &other) + : identifier (other.identifier), optional_flag (other.optional_flag), + type (other.type), hir_trait_item (other.hir_trait_item), + locus (other.locus), self (other.self), context (TypeCheckContext::get ()) +{ + inherited_substitutions.reserve (other.inherited_substitutions.size ()); + for (size_t i = 0; i < other.inherited_substitutions.size (); i++) + inherited_substitutions.push_back (other.inherited_substitutions.at (i)); +} + +TyTy::BaseType * +TraitItemReference::get_type_from_typealias (/*const*/ + HIR::TraitItemType &type) const +{ + TyTy::TyVar var (get_mappings ().get_hirid ()); + return var.get_tyty (); +} + +TyTy::BaseType * +TraitItemReference::get_type_from_constant ( + /*const*/ HIR::TraitItemConst &constant) const +{ + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); + TyTy::BaseType *expr + = TypeCheckExpr::Resolve (constant.get_expr ().get (), false); + + return type->unify (expr); +} + +TyTy::BaseType * +TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const +{ + std::vector<TyTy::SubstitutionParamMapping> substitutions + = inherited_substitutions; + + HIR::TraitFunctionDecl &function = fn.get_decl (); + if (function.has_generics ()) + { + for (auto &generic_param : function.get_generic_params ()) + { + switch (generic_param.get ()->get_kind ()) + { + case HIR::GenericParam::GenericKind::LIFETIME: + // Skipping Lifetime completely until better handling. + break; + + case HIR::GenericParam::GenericKind::TYPE: { + auto param_type + = TypeResolveGenericParam::Resolve (generic_param.get ()); + context->insert_type (generic_param->get_mappings (), + param_type); + + substitutions.push_back (TyTy::SubstitutionParamMapping ( + static_cast<HIR::TypeParam &> (*generic_param), param_type)); + } + break; + } + } + } + + TyTy::BaseType *ret_type = nullptr; + if (!function.has_return_type ()) + ret_type = new TyTy::TupleType (fn.get_mappings ().get_hirid ()); + else + { + auto resolved + = TypeCheckType::Resolve (function.get_return_type ().get ()); + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + { + rust_error_at (fn.get_locus (), "failed to resolve return type"); + return get_error (); + } + + ret_type = resolved->clone (); + ret_type->set_ref ( + function.get_return_type ()->get_mappings ().get_hirid ()); + } + + std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + if (function.is_method ()) + { + // add the synthetic self param at the front, this is a placeholder + // for compilation to know parameter names. The types are ignored + // but we reuse the HIR identifier pattern which requires it + HIR::SelfParam &self_param = function.get_self (); + HIR::IdentifierPattern *self_pattern + = new HIR::IdentifierPattern ("self", self_param.get_locus (), + self_param.is_ref (), + self_param.is_mut (), + std::unique_ptr<HIR::Pattern> (nullptr)); + context->insert_type (self_param.get_mappings (), self->clone ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, + self->clone ())); + } + + for (auto ¶m : function.get_function_params ()) + { + // get the name as well required for later on + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); + params.push_back ( + std::pair<HIR::Pattern *, TyTy::BaseType *> (param.get_param_name (), + param_tyty)); + + context->insert_type (param.get_mappings (), param_tyty); + } + + return new TyTy::FnType (fn.get_mappings ().get_hirid (), + function.get_function_name (), function.is_method (), + std::move (params), ret_type, substitutions); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/testsuite/rust/compile/torture/traits6.rs b/gcc/testsuite/rust/compile/torture/traits6.rs new file mode 100644 index 0000000..5aae2e3 --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/traits6.rs @@ -0,0 +1,23 @@ +trait Foo { + type A; + // { dg-warning "unused name .Foo::A." "" { target *-*-* } .-1 } + + fn baz(a: Self::A) -> Self::A; + // { dg-warning "unused name .a." "" { target *-*-* } .-1 } + // { dg-warning "unused name .Foo::baz." "" { target *-*-* } .-2 } +} + +struct Bar<T>(T); + +impl<T> Foo for Bar<T> { + type A = T; + + fn baz(a: Self::A) -> T { + a + } +} + +fn main() { + let a; + a = Bar::<i32>::baz(123); +} diff --git a/gcc/testsuite/rust/compile/traits3.rs b/gcc/testsuite/rust/compile/traits3.rs new file mode 100644 index 0000000..c971a11 --- /dev/null +++ b/gcc/testsuite/rust/compile/traits3.rs @@ -0,0 +1,22 @@ +trait Foo { + type A; + + fn baz(a: Self::A) -> Self::A; +} + +struct Bar<T>(T); + +impl<T> Foo for Bar<T> { + type A = i32; + + fn baz(a: f32) -> f32 { + // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 } + // { dg-error "method .baz. has an incompatible type for trait .Foo." "" { target *-*-* } .-2 } + a + } +} + +fn main() { + let a; + a = Bar::<i32>::baz(123f32); +} |