diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 03614200ba25..4f94d0fdd70f 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -278,6 +278,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) } self->inherit_bounds (specified_bounds); + context->push_block_context (TypeCheckBlockContextItem (trait_reference)); std::vector item_refs; for (auto &item : trait_reference->get_trait_items ()) { @@ -307,6 +308,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) // resolve the blocks of functions etc because it can end up in a recursive // loop of trying to resolve traits as required by the types tref->on_resolved (); + context->pop_block_context (); return tref; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 6a748f4666b2..a72ab9731d1d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -335,7 +335,10 @@ TypeCheckImplItem::Resolve ( // resolve TypeCheckImplItem resolver (parent, self, substitutions); + resolver.context->push_block_context (TypeCheckBlockContextItem (&parent)); item.accept_vis (resolver); + resolver.context->pop_block_context (); + return resolver.result; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index 08ec718e6eb4..d3f341264482 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -355,6 +355,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, NodeId resolved_node_id = root_resolved_node_id; TyTy::BaseType *prev_segment = tyseg; bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM; + bool reciever_is_dyn = prev_segment->get_kind () == TyTy::TypeKind::DYNAMIC; for (size_t i = offset; i < segments.size (); i++) { @@ -434,7 +435,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, } } - if (associated_impl_block != nullptr) + if (associated_impl_block != nullptr && !reciever_is_dyn) { // associated types HirId impl_block_id diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index c17e3247113a..aaff8db99bad 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -133,11 +133,16 @@ TypeCheckType::visit (HIR::TypePath &path) // this can happen so we need to look up the root then resolve the // remaining segments if possible + bool wasBigSelf = false; size_t offset = 0; NodeId resolved_node_id = UNKNOWN_NODEID; - TyTy::BaseType *root = resolve_root_path (path, &offset, &resolved_node_id); + TyTy::BaseType *root + = resolve_root_path (path, &offset, &resolved_node_id, &wasBigSelf); if (root->get_kind () == TyTy::TypeKind::ERROR) - return; + { + rust_debug_loc (path.get_locus (), "failed to resolve type-path type"); + return; + } TyTy::BaseType *path_type = root->clone (); path_type->set_ref (path.get_mappings ().get_hirid ()); @@ -147,13 +152,18 @@ TypeCheckType::visit (HIR::TypePath &path) if (fully_resolved) { translated = path_type; + rust_debug_loc (path.get_locus (), "root resolved type-path to: [%s]", + translated->debug_str ().c_str ()); return; } translated = resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (), path.get_segments (), offset, path_type, - path.get_mappings (), path.get_locus ()); + path.get_mappings (), path.get_locus (), wasBigSelf); + + rust_debug_loc (path.get_locus (), "resolved type-path to: [%s]", + translated->debug_str ().c_str ()); } void @@ -192,10 +202,11 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) } rust_assert (ok); - translated = resolve_segments (root_resolved_node_id, - path.get_mappings ().get_hirid (), - path.get_segments (), 0, translated, - path.get_mappings (), path.get_locus ()); + translated + = resolve_segments (root_resolved_node_id, + path.get_mappings ().get_hirid (), + path.get_segments (), 0, translated, + path.get_mappings (), path.get_locus (), false); return; } @@ -356,12 +367,14 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) translated = resolve_segments (root_resolved_node_id, path.get_mappings ().get_hirid (), path.get_segments (), - 0, translated, path.get_mappings (), path.get_locus ()); + 0, translated, path.get_mappings (), path.get_locus (), + false); } TyTy::BaseType * TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, - NodeId *root_resolved_node_id) + NodeId *root_resolved_node_id, + bool *wasBigSelf) { TyTy::BaseType *root_tyty = nullptr; *offset = 0; @@ -403,6 +416,9 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, return root_tyty; } + if (seg->is_ident_only () && seg->as_string () == "Self") + *wasBigSelf = true; + // node back to HIR tl::optional hid = mappings.lookup_node_to_hir (ref_node_id); if (!hid.has_value ()) @@ -509,12 +525,57 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, return root_tyty; } +bool +TypeCheckType::resolve_associated_type (const std::string &search, + TypeCheckBlockContextItem &ctx, + TyTy::BaseType **result) +{ + if (ctx.is_trait_block ()) + { + HIR::Trait &trait = ctx.get_trait (); + for (auto &item : trait.get_trait_items ()) + { + if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::TYPE) + continue; + + if (item->trait_identifier () == search) + { + HirId item_id = item->get_mappings ().get_hirid (); + if (query_type (item_id, result)) + return true; + } + } + + // FIXME + // query any parent trait? + + return false; + } + + // look for any segment in here which matches + HIR::ImplBlock &block = ctx.get_impl_block (); + for (auto &item : block.get_impl_items ()) + { + if (item->get_impl_item_type () != HIR::ImplItem::TYPE_ALIAS) + continue; + + if (item->get_impl_item_name () == search) + { + HirId item_id = item->get_impl_mappings ().get_hirid (); + if (query_type (item_id, result)) + return true; + } + } + + return false; +} + TyTy::BaseType * TypeCheckType::resolve_segments ( NodeId root_resolved_node_id, HirId expr_id, std::vector> &segments, size_t offset, TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, - location_t expr_locus) + location_t expr_locus, bool tySegIsBigSelf) { NodeId resolved_node_id = root_resolved_node_id; TyTy::BaseType *prev_segment = tyseg; @@ -527,66 +588,84 @@ TypeCheckType::resolve_segments ( bool probe_bounds = true; bool probe_impls = !reciever_is_generic; bool ignore_mandatory_trait_items = !reciever_is_generic; + bool first_segment = i == offset; + bool selfResolveOk = false; - // probe the path is done in two parts one where we search impls if no - // candidate is found then we search extensions from traits - auto candidates - = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), - probe_impls, false, - ignore_mandatory_trait_items); - if (candidates.size () == 0) + if (first_segment && tySegIsBigSelf && context->have_block_context () + && context->peek_block_context ().is_impl_block ()) + { + TypeCheckBlockContextItem ctx = context->peek_block_context (); + TyTy::BaseType *lookup = nullptr; + selfResolveOk + = resolve_associated_type (seg->as_string (), ctx, &lookup); + if (selfResolveOk) + { + prev_segment = tyseg; + tyseg = lookup; + } + } + if (!selfResolveOk) { - candidates + // probe the path is done in two parts one where we search impls if no + // candidate is found then we search extensions from traits + auto candidates = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), - false, probe_bounds, + probe_impls, false, ignore_mandatory_trait_items); - if (candidates.size () == 0) { - rust_error_at ( - seg->get_locus (), - "failed to resolve path segment using an impl Probe"); + candidates + = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), + false, probe_bounds, + ignore_mandatory_trait_items); + if (candidates.size () == 0) + { + rust_error_at ( + seg->get_locus (), + "failed to resolve path segment using an impl Probe"); + return new TyTy::ErrorType (expr_id); + } + } + + if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg->get_ident_segment (), + seg->get_locus ()); return new TyTy::ErrorType (expr_id); } - } - if (candidates.size () > 1) - { - ReportMultipleCandidateError::Report (candidates, - seg->get_ident_segment (), - seg->get_locus ()); - return new TyTy::ErrorType (expr_id); - } + auto &candidate = *candidates.begin (); + prev_segment = tyseg; + tyseg = candidate.ty; - auto &candidate = *candidates.begin (); - prev_segment = tyseg; - tyseg = candidate.ty; + if (candidate.is_enum_candidate ()) + { + TyTy::ADTType *adt = static_cast (tyseg); + auto last_variant = adt->get_variants (); + TyTy::VariantDef *variant = last_variant.back (); - if (candidate.is_enum_candidate ()) - { - TyTy::ADTType *adt = static_cast (tyseg); - auto last_variant = adt->get_variants (); - TyTy::VariantDef *variant = last_variant.back (); - - rich_location richloc (line_table, seg->get_locus ()); - richloc.add_fixit_replace ("not a type"); - - rust_error_at (richloc, ErrorCode::E0573, - "expected type, found variant of %<%s::%s%>", - adt->get_name ().c_str (), - variant->get_identifier ().c_str ()); - return new TyTy::ErrorType (expr_id); - } + rich_location richloc (line_table, seg->get_locus ()); + richloc.add_fixit_replace ("not a type"); - if (candidate.is_impl_candidate ()) - { - resolved_node_id - = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid (); - } - else - { - resolved_node_id - = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); + rust_error_at (richloc, ErrorCode::E0573, + "expected type, found variant of %<%s::%s%>", + adt->get_name ().c_str (), + variant->get_identifier ().c_str ()); + return new TyTy::ErrorType (expr_id); + } + + if (candidate.is_impl_candidate ()) + { + resolved_node_id + = candidate.item.impl.impl_item->get_impl_mappings () + .get_nodeid (); + } + else + { + resolved_node_id + = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); + } } if (seg->is_generic_segment ()) diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 814903f316bd..10acde081b7d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -82,13 +82,18 @@ class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor {} TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset, - NodeId *root_resolved_node_id); + NodeId *root_resolved_node_id, + bool *wasBigSelf); TyTy::BaseType *resolve_segments ( NodeId root_resolved_node_id, HirId expr_id, std::vector> &segments, size_t offset, TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, - location_t expr_locus); + location_t expr_locus, bool tySegIsBigSelf); + + bool resolve_associated_type (const std::string &search, + TypeCheckBlockContextItem &ctx, + TyTy::BaseType **result); TyTy::BaseType *translated; }; diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 5a78f62221fd..65c929af9477 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -82,6 +82,37 @@ class TypeCheckContextItem Item item; }; +class TypeCheckBlockContextItem +{ +public: + enum ItemType + { + IMPL_BLOCK, + TRAIT + }; + + TypeCheckBlockContextItem (HIR::ImplBlock *block); + TypeCheckBlockContextItem (HIR::Trait *trait); + + bool is_impl_block () const; + bool is_trait_block () const; + + HIR::ImplBlock &get_impl_block (); + HIR::Trait &get_trait (); + +private: + union Item + { + HIR::ImplBlock *block; + HIR::Trait *trait; + + Item (HIR::ImplBlock *block); + Item (HIR::Trait *trait); + }; + ItemType type; + Item item; +}; + /** * Interned lifetime representation in TyTy * @@ -154,6 +185,12 @@ class TypeCheckContext void push_return_type (TypeCheckContextItem item, TyTy::BaseType *return_type); void pop_return_type (); + + bool have_block_context () const; + TypeCheckBlockContextItem peek_block_context (); + void push_block_context (TypeCheckBlockContextItem item); + void pop_block_context (); + void iterate (std::function cb); bool have_loop_context () const; @@ -245,6 +282,7 @@ class TypeCheckContext std::vector> return_type_stack; std::vector loop_type_stack; + std::vector block_stack; std::map trait_context; std::map receiver_context; std::map associated_impl_traits; diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 418abd3421c4..b37be49c749a 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -177,6 +177,32 @@ TypeCheckContext::peek_context () return return_type_stack.back ().first; } +bool +TypeCheckContext::have_block_context () const +{ + return !block_stack.empty (); +} + +TypeCheckBlockContextItem +TypeCheckContext::peek_block_context () +{ + rust_assert (!block_stack.empty ()); + return block_stack.back (); +} + +void +TypeCheckContext::push_block_context (TypeCheckBlockContextItem block) +{ + block_stack.push_back (block); +} + +void +TypeCheckContext::pop_block_context () +{ + rust_assert (!block_stack.empty ()); + block_stack.pop_back (); +} + void TypeCheckContext::iterate (std::function cb) { @@ -802,5 +828,43 @@ TypeCheckContextItem::get_defid () const return UNKNOWN_DEFID; } +// TypeCheckBlockContextItem + +TypeCheckBlockContextItem::Item::Item (HIR::ImplBlock *b) : block (b) {} + +TypeCheckBlockContextItem::Item::Item (HIR::Trait *t) : trait (t) {} + +TypeCheckBlockContextItem::TypeCheckBlockContextItem (HIR::ImplBlock *block) + : type (TypeCheckBlockContextItem::ItemType::IMPL_BLOCK), item (block) +{} + +TypeCheckBlockContextItem::TypeCheckBlockContextItem (HIR::Trait *trait) + : type (TypeCheckBlockContextItem::ItemType::TRAIT), item (trait) +{} + +bool +TypeCheckBlockContextItem::is_impl_block () const +{ + return type == IMPL_BLOCK; +} + +bool +TypeCheckBlockContextItem::is_trait_block () const +{ + return type == TRAIT; +} + +HIR::ImplBlock & +TypeCheckBlockContextItem::get_impl_block () +{ + return *(item.block); +} + +HIR::Trait & +TypeCheckBlockContextItem::get_trait () +{ + return *(item.trait); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/testsuite/rust/compile/issue-2907.rs b/gcc/testsuite/rust/compile/issue-2907.rs new file mode 100644 index 000000000000..1af843f582e4 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2907.rs @@ -0,0 +1,33 @@ +#![feature(lang_items)] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Bar {} + +pub trait Foo { + type Ty; + + fn foo(self) -> Self::Ty; +} + +impl Foo for B { + type Ty = u32; + + fn foo(self) -> Self::Ty { + // { dg-warning "unused name" "" { target *-*-* } .-1 } + 14 + } +} + +struct Qux; + +impl Bar for Qux {} + +fn main() { + let a = Qux; + a.foo(); + + let b = Qux; + Foo::foo(b); +} diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index b282f05637d2..00ac704fec2f 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -205,4 +205,5 @@ issue-2953-2.rs issue-1773.rs issue-2905-1.rs issue-2905-2.rs +issue-2907.rs # please don't delete the trailing newline