From 1b3374d15a9d8a28e2947bc07da3b2a67fedc366 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 25 Nov 2024 21:37:19 +0000 Subject: [PATCH] gccrs: improve handling of Self Type paths TypePaths have special handling for Self where we can look at the current ctx for more acurate TypeAlias information if required. We cant do this for Impl contexts but not for Traits as we might as well fall back to the TypePathProbe. The other issue was the dyn type comming in because Foo::foo and Foo is a trait reference we represent this as a dyn type as the root resolved path but then find the associated impl block for this but we cannot do this when we have resolved to a Dyn because this is just a representation that we know we are talking about a trait not because we are actually working with a real Dyn type. Fixes Rust-GCC#2907 gcc/rust/ChangeLog: * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): track trait * typecheck/rust-hir-type-check-implitem.cc: trait block * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_segments): dont when dyn * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): look at Self contenxt (TypeCheckType::resolve_root_path): track if Self (TypeCheckType::resolve_associated_type): look at current context for associated types * typecheck/rust-hir-type-check-type.h: change prototype * typecheck/rust-hir-type-check.h (class TypeCheckBlockContextItem): new context system to track current state * typecheck/rust-typecheck-context.cc (TypeCheckContext::have_block_context): likewise (TypeCheckContext::peek_block_context): likewise (TypeCheckContext::push_block_context): likewise (TypeCheckContext::pop_block_context): likewise (TypeCheckBlockContextItem::Item::Item): likewise (TypeCheckBlockContextItem::TypeCheckBlockContextItem): likewise (TypeCheckBlockContextItem::is_impl_block): likewise (TypeCheckBlockContextItem::is_trait_block): likewise (TypeCheckBlockContextItem::get_impl_block): likewise (TypeCheckBlockContextItem::get_trait): likewise gcc/testsuite/ChangeLog: * rust/compile/nr2/exclude: nr2 cant handle this * rust/compile/issue-2907.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/typecheck/rust-hir-trait-resolve.cc | 2 + .../typecheck/rust-hir-type-check-implitem.cc | 3 + .../typecheck/rust-hir-type-check-path.cc | 3 +- .../typecheck/rust-hir-type-check-type.cc | 195 ++++++++++++------ gcc/rust/typecheck/rust-hir-type-check-type.h | 9 +- gcc/rust/typecheck/rust-hir-type-check.h | 38 ++++ gcc/rust/typecheck/rust-typecheck-context.cc | 64 ++++++ gcc/testsuite/rust/compile/issue-2907.rs | 33 +++ gcc/testsuite/rust/compile/nr2/exclude | 1 + 9 files changed, 287 insertions(+), 61 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-2907.rs 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