diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-item.h | 341 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve.cc | 16 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-implitem.h | 88 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits4.rs | 26 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/traits5.rs | 26 |
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 ¶m : 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 ¶m : 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 ¶m : 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 ¶m : 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); +} |