aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-07-13 20:34:04 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-07-14 18:57:17 +0100
commit60b1209d64cee3b47cf9b3f5b9da4f74f03a25bb (patch)
treeef91aff90b40bb5f3b33d5ea1df31e53419ad6e3
parentb4ea3a19464b9bc79dad9cf5bb9bffc660718632 (diff)
downloadgcc-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.h83
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.h103
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h1
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc123
-rw-r--r--gcc/testsuite/rust/compile/torture/traits6.rs23
-rw-r--r--gcc/testsuite/rust/compile/traits3.rs22
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 &param : 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 &param : 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);
+}