aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h341
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc16
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h88
-rw-r--r--gcc/testsuite/rust/compile/torture/traits4.rs26
-rw-r--r--gcc/testsuite/rust/compile/torture/traits5.rs26
5 files changed, 378 insertions, 119 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index ad817dc..1f1ff30 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -28,11 +28,168 @@
namespace Rust {
namespace Resolver {
-class ResolveItem : public ResolverBase
+class ResolveTraitItems : public ResolverBase
{
using Rust::Resolver::ResolverBase::visit;
public:
+ static void go (AST::TraitItem *item, const CanonicalPath &self)
+ {
+ ResolveTraitItems resolver (self);
+ item->accept_vis (resolver);
+ };
+
+ void visit (AST::TraitItemType &type) override
+ {
+ // insert Self::type_alias for TypePath lookup
+ auto path
+ = self.append (ResolveTraitItemTypeToCanonicalPath::resolve (type));
+ resolver->get_type_scope ().insert (
+ path, type.get_node_id (), type.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (type.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ // FIXME this stops the erronious unused decls which will be fixed later on
+ resolver->get_type_scope ().append_reference_for_def (type.get_node_id (),
+ type.get_node_id ());
+
+ // TODO resolve the type-bounds
+ }
+
+ void visit (AST::TraitItemFunc &func) override
+ {
+ NodeId scope_node_id = func.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ AST::TraitFunctionDecl &function = func.get_trait_function_decl ();
+ if (function.has_generics ())
+ {
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), func.get_node_id ());
+ }
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get (), func.get_node_id ());
+
+ // we make a new scope so the names of parameters are resolved and shadowed
+ // correctly
+ for (auto &param : function.get_function_params ())
+ {
+ ResolveType::go (param.get_type ().get (), param.get_node_id ());
+ PatternDeclaration::go (param.get_pattern ().get (),
+ param.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
+ param.get_node_id ());
+ }
+
+ // trait items have an optional body
+ if (func.has_definition ())
+ ResolveExpr::go (func.get_definition ().get (), func.get_node_id ());
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ }
+
+ void visit (AST::TraitItemMethod &func) override
+ {
+ NodeId scope_node_id = func.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ AST::TraitMethodDecl &function = func.get_trait_method_decl ();
+ if (function.has_generics ())
+ {
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), func.get_node_id ());
+ }
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get (), func.get_node_id ());
+
+ // self turns into (self: Self) as a function param
+ AST::SelfParam &self_param = function.get_self_param ();
+ AST::IdentifierPattern self_pattern (
+ self_param.get_node_id (), "self", self_param.get_locus (),
+ self_param.get_has_ref (), self_param.get_is_mut (),
+ std::unique_ptr<AST::Pattern> (nullptr));
+
+ std::vector<std::unique_ptr<AST::TypePathSegment> > segments;
+ segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+ new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+ AST::TypePath self_type_path (std::move (segments),
+ self_param.get_locus ());
+
+ ResolveType::go (&self_type_path, self_param.get_node_id ());
+ PatternDeclaration::go (&self_pattern, self_param.get_node_id ());
+
+ resolver->mark_assignment_to_decl (self_pattern.get_node_id (),
+ self_pattern.get_node_id ());
+
+ // we make a new scope so the names of parameters are resolved and shadowed
+ // correctly
+ for (auto &param : function.get_function_params ())
+ {
+ ResolveType::go (param.get_type ().get (), param.get_node_id ());
+ PatternDeclaration::go (param.get_pattern ().get (),
+ param.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
+ param.get_node_id ());
+ }
+
+ // trait items have an optional body
+ if (func.has_definition ())
+ ResolveExpr::go (func.get_definition ().get (), func.get_node_id ());
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ }
+
+ void visit (AST::TraitItemConst &constant) override
+ {
+ ResolveType::go (constant.get_type ().get (), constant.get_node_id ());
+ ResolveExpr::go (constant.get_expr ().get (), constant.get_node_id ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ resolver->mark_decl_mutability (constant.get_node_id (), false);
+ resolver->mark_assignment_to_decl (constant.get_node_id (),
+ constant.get_node_id ());
+ }
+
+private:
+ ResolveTraitItems (const CanonicalPath &self)
+ : ResolverBase (UNKNOWN_NODEID), self (self)
+ {}
+
+ const CanonicalPath &self;
+};
+
+class ResolveItem : public ResolverBase
+{
+public:
+ using Rust::Resolver::ResolverBase::visit;
+
static void go (AST::Item *item)
{
ResolveItem resolver;
@@ -169,7 +326,10 @@ public:
void visit (AST::InherentImpl &impl_block) override
{
NodeId scope_node_id = impl_block.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
if (impl_block.has_generics ())
{
@@ -186,6 +346,7 @@ public:
if (resolved_node == UNKNOWN_NODEID)
{
resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
return;
}
@@ -197,11 +358,15 @@ public:
impl_block.get_type ()->get_locus_slow ());
for (auto &impl_item : impl_block.get_impl_items ())
- impl_item->accept_vis (*this);
+ {
+ resolve_impl_item (impl_item.get (), Self);
+ }
resolver->get_type_scope ().peek ()->clear_name (
Self, impl_block.get_type ()->get_node_id ());
+
resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
}
void visit (AST::Method &method) override
@@ -268,7 +433,10 @@ public:
void visit (AST::TraitImpl &impl_block) override
{
NodeId scope_node_id = impl_block.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
if (impl_block.has_generics ())
{
@@ -286,6 +454,7 @@ public:
if (trait_resolved_node == UNKNOWN_NODEID)
{
resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
return;
}
@@ -296,6 +465,7 @@ public:
if (type_resolved_node == UNKNOWN_NODEID)
{
resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
return;
}
@@ -307,7 +477,9 @@ public:
impl_block.get_type ()->get_locus_slow ());
for (auto &impl_item : impl_block.get_impl_items ())
- impl_item->accept_vis (*this);
+ {
+ resolve_impl_item (impl_item.get (), Self);
+ }
resolver->get_type_scope ().peek ()->clear_name (
Self, impl_block.get_type ()->get_node_id ());
@@ -317,150 +489,85 @@ public:
void visit (AST::Trait &trait) override
{
NodeId scope_node_id = trait.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
// we need to inject an implicit self TypeParam here
AST::TypeParam *implicit_self
= new AST::TypeParam ("Self", trait.get_locus ());
trait.insert_implict_self (
std::unique_ptr<AST::GenericParam> (implicit_self));
+ CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ());
for (auto &generic : trait.get_generic_params ())
{
ResolveGenericParam::go (generic.get (), trait.get_node_id ());
}
- for (auto &item : trait.get_trait_items ())
- item->accept_vis (*this);
+ // Self is an implicit TypeParam so lets mark it as such
+ resolver->get_type_scope ().append_reference_for_def (
+ Self.get_id (), implicit_self->get_node_id ());
- resolver->get_type_scope ().pop ();
- }
-
- void visit (AST::TraitItemFunc &func) override
- {
- NodeId scope_node_id = func.get_node_id ();
- resolver->get_name_scope ().push (scope_node_id);
- resolver->get_type_scope ().push (scope_node_id);
- resolver->get_label_scope ().push (scope_node_id);
- resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
- resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
-
- AST::TraitFunctionDecl &function = func.get_trait_function_decl ();
- if (function.has_generics ())
- {
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (generic.get (), func.get_node_id ());
- }
-
- if (function.has_return_type ())
- ResolveType::go (function.get_return_type ().get (), func.get_node_id ());
-
- // we make a new scope so the names of parameters are resolved and shadowed
- // correctly
- for (auto &param : function.get_function_params ())
+ for (auto &item : trait.get_trait_items ())
{
- ResolveType::go (param.get_type ().get (), param.get_node_id ());
- PatternDeclaration::go (param.get_pattern ().get (),
- param.get_node_id ());
-
- // the mutability checker needs to verify for immutable decls the number
- // of assignments are <1. This marks an implicit assignment
- resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
- param.get_node_id ());
+ ResolveTraitItems::go (item.get (), Self);
}
- // trait items have an optional body
- if (func.has_definition ())
- ResolveExpr::go (func.get_definition ().get (), func.get_node_id ());
-
- resolver->get_name_scope ().pop ();
resolver->get_type_scope ().pop ();
- resolver->get_label_scope ().pop ();
+ resolver->get_name_scope ().pop ();
}
- void visit (AST::TraitItemMethod &func) override
- {
- NodeId scope_node_id = func.get_node_id ();
- resolver->get_name_scope ().push (scope_node_id);
- resolver->get_type_scope ().push (scope_node_id);
- resolver->get_label_scope ().push (scope_node_id);
- resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
- resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
-
- AST::TraitMethodDecl &function = func.get_trait_method_decl ();
- if (function.has_generics ())
- {
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (generic.get (), func.get_node_id ());
- }
-
- if (function.has_return_type ())
- ResolveType::go (function.get_return_type ().get (), func.get_node_id ());
-
- // self turns into (self: Self) as a function param
- AST::SelfParam &self_param = function.get_self_param ();
- AST::IdentifierPattern self_pattern (
- self_param.get_node_id (), "self", self_param.get_locus (),
- self_param.get_has_ref (), self_param.get_is_mut (),
- std::unique_ptr<AST::Pattern> (nullptr));
-
- std::vector<std::unique_ptr<AST::TypePathSegment> > segments;
- segments.push_back (std::unique_ptr<AST::TypePathSegment> (
- new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+protected:
+ void resolve_impl_item (AST::TraitImplItem *item, const CanonicalPath &self);
+ void resolve_impl_item (AST::InherentImplItem *item,
+ const CanonicalPath &self);
- AST::TypePath self_type_path (std::move (segments),
- self_param.get_locus ());
-
- ResolveType::go (&self_type_path, self_param.get_node_id ());
- PatternDeclaration::go (&self_pattern, self_param.get_node_id ());
-
- resolver->mark_assignment_to_decl (self_pattern.get_node_id (),
- self_pattern.get_node_id ());
-
- // we make a new scope so the names of parameters are resolved and shadowed
- // correctly
- for (auto &param : function.get_function_params ())
- {
- ResolveType::go (param.get_type ().get (), param.get_node_id ());
- PatternDeclaration::go (param.get_pattern ().get (),
- param.get_node_id ());
-
- // the mutability checker needs to verify for immutable decls the number
- // of assignments are <1. This marks an implicit assignment
- resolver->mark_assignment_to_decl (param.get_pattern ()->get_node_id (),
- param.get_node_id ());
- }
-
- // trait items have an optional body
- if (func.has_definition ())
- ResolveExpr::go (func.get_definition ().get (), func.get_node_id ());
+ ResolveItem () : ResolverBase (UNKNOWN_NODEID) {}
+};
- resolver->get_name_scope ().pop ();
- resolver->get_type_scope ().pop ();
- resolver->get_label_scope ().pop ();
- }
+class ResolveImplItems : public ResolveItem
+{
+ using Rust::Resolver::ResolveItem::visit;
- void visit (AST::TraitItemConst &constant) override
+public:
+ static void go (AST::InherentImplItem *item, const CanonicalPath &self)
{
- ResolveType::go (constant.get_type ().get (), constant.get_node_id ());
- ResolveExpr::go (constant.get_expr ().get (), constant.get_node_id ());
+ ResolveImplItems resolver (self);
+ item->accept_vis (resolver);
+ };
- // the mutability checker needs to verify for immutable decls the number
- // of assignments are <1. This marks an implicit assignment
- resolver->mark_decl_mutability (constant.get_node_id (), false);
- resolver->mark_assignment_to_decl (constant.get_node_id (),
- constant.get_node_id ());
- }
+ static void go (AST::TraitImplItem *item, const CanonicalPath &self)
+ {
+ ResolveImplItems resolver (self);
+ item->accept_vis (resolver);
+ };
- void visit (AST::TraitItemType &alias) override
+ void visit (AST::TypeAlias &alias) override
{
- // nothing to do here until we start supporting Type Bounds
+ ResolveItem::visit (alias);
+
+ auto path
+ = self.append (CanonicalPath::new_seg (alias.get_node_id (),
+ alias.get_new_type_name ()));
+ resolver->get_type_scope ().insert (
+ path, alias.get_node_id (), alias.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (alias.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ // FIXME this stops the erronious unused decls which will be fixed later on
+ resolver->get_type_scope ().append_reference_for_def (alias.get_node_id (),
+ alias.get_node_id ());
}
private:
- ResolveItem () : ResolverBase (UNKNOWN_NODEID) {}
+ ResolveImplItems (const CanonicalPath &self) : ResolveItem (), self (self) {}
+
+ const CanonicalPath &self;
};
} // namespace Resolver
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index b568e1c..18047db 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -619,5 +619,21 @@ ResolveType::visit (AST::ArrayType &type)
ResolveExpr::go (type.get_size_expr ().get (), type.get_node_id ());
}
+// rust-ast-resolve-item.h
+
+void
+ResolveItem::resolve_impl_item (AST::TraitImplItem *item,
+ const CanonicalPath &self)
+{
+ ResolveImplItems::go (item, self);
+}
+
+void
+ResolveItem::resolve_impl_item (AST::InherentImplItem *item,
+ const CanonicalPath &self)
+{
+ ResolveImplItems::go (item, self);
+}
+
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index d617882..b0264e5 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -41,6 +41,14 @@ public:
item->accept_vis (resolver);
}
+ void visit (HIR::TypeAlias &alias) override
+ {
+ TyTy::BaseType *actual_type
+ = TypeCheckType::Resolve (alias.get_type_aliased ().get ());
+
+ context->insert_type (alias.get_mappings (), actual_type);
+ }
+
void visit (HIR::ConstantItem &constant) override
{
TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ());
@@ -204,9 +212,85 @@ public:
return resolver.resolved_trait_item;
}
- void visit (HIR::ConstantItem &constant) override { gcc_unreachable (); }
+ void visit (HIR::ConstantItem &constant) override
+ {
+ TypeCheckImplItem::visit (constant);
+
+ // we get the error checking from the base method here
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (constant.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ const TraitItemReference &trait_item_ref
+ = trait_reference.lookup_trait_item (
+ constant.get_identifier (), TraitItemReference::TraitItemType::CONST);
- void visit (HIR::TypeAlias &type) override { gcc_unreachable (); }
+ // unknown trait item
+ if (trait_item_ref.is_error ())
+ {
+ RichLocation r (constant.get_locus ());
+ r.add_range (trait_reference.get_locus ());
+ rust_error_at (r, "constant %<%s%> is not a member of trait %<%s%>",
+ constant.get_identifier ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ // check the types are compatible
+ if (!trait_item_ref.get_tyty ()->can_eq (lookup, true))
+ {
+ RichLocation r (constant.get_locus ());
+ r.add_range (trait_item_ref.get_locus ());
+
+ rust_error_at (
+ r, "constant %<%s%> has an incompatible type for trait %<%s%>",
+ constant.get_identifier ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ resolved_trait_item = trait_item_ref;
+ }
+
+ void visit (HIR::TypeAlias &type) override
+ {
+ TypeCheckImplItem::visit (type);
+
+ // we get the error checking from the base method here
+ TyTy::BaseType *lookup;
+ if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
+ return;
+
+ const TraitItemReference &trait_item_ref
+ = trait_reference.lookup_trait_item (
+ type.get_new_type_name (), TraitItemReference::TraitItemType::TYPE);
+
+ // unknown trait item
+ if (trait_item_ref.is_error ())
+ {
+ RichLocation r (type.get_locus ());
+ r.add_range (trait_reference.get_locus ());
+ rust_error_at (r, "type alias %<%s%> is not a member of trait %<%s%>",
+ type.get_new_type_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ // check the types are compatible
+ if (!trait_item_ref.get_tyty ()->can_eq (lookup, true))
+ {
+ RichLocation r (type.get_locus ());
+ r.add_range (trait_item_ref.get_locus ());
+
+ rust_error_at (
+ r, "type alias %<%s%> has an incompatible type for trait %<%s%>",
+ type.get_new_type_name ().c_str (),
+ trait_reference.get_name ().c_str ());
+ return;
+ }
+
+ resolved_trait_item = trait_item_ref;
+ }
void visit (HIR::Function &function) override
{
diff --git a/gcc/testsuite/rust/compile/torture/traits4.rs b/gcc/testsuite/rust/compile/torture/traits4.rs
new file mode 100644
index 0000000..1db5f32
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/traits4.rs
@@ -0,0 +1,26 @@
+trait Foo {
+ type A;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ type B;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+
+ fn new(a: Self::A, b: Self::B) -> Self;
+ // { dg-warning "unused name .a." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .b." "" { target *-*-* } .-2 }
+ // { dg-warning "unused name .Foo::new." "" { target *-*-* } .-3 }
+}
+
+struct Baz(i32, f32);
+
+impl Foo for Baz {
+ type A = i32;
+ type B = f32;
+
+ fn new(a: Self::A, b: Self::B) -> Self {
+ Baz(a, b)
+ }
+}
+
+fn main() {
+ Baz::new(123, 456f32);
+}
diff --git a/gcc/testsuite/rust/compile/torture/traits5.rs b/gcc/testsuite/rust/compile/torture/traits5.rs
new file mode 100644
index 0000000..87c0283
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/traits5.rs
@@ -0,0 +1,26 @@
+trait Foo {
+ type A;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ type B;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+
+ fn new(a: Self::A, b: Self::B) -> Self;
+ // { dg-warning "unused name .a." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .b." "" { target *-*-* } .-2 }
+ // { dg-warning "unused name .Foo::new." "" { target *-*-* } .-3 }
+}
+
+struct Baz(i32, f32);
+
+impl Foo for Baz {
+ type A = i32;
+ type B = f32;
+
+ fn new(a: i32, b: f32) -> Self {
+ Baz(a, b)
+ }
+}
+
+fn main() {
+ Baz::new(123, 456f32);
+}