]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: improve handling of Self Type paths
authorPhilip Herron <herron.philip@googlemail.com>
Mon, 25 Nov 2024 21:37:19 +0000 (21:37 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Fri, 21 Mar 2025 11:33:03 +0000 (12:33 +0100)
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 <herron.philip@googlemail.com>
gcc/rust/typecheck/rust-hir-trait-resolve.cc
gcc/rust/typecheck/rust-hir-type-check-implitem.cc
gcc/rust/typecheck/rust-hir-type-check-path.cc
gcc/rust/typecheck/rust-hir-type-check-type.cc
gcc/rust/typecheck/rust-hir-type-check-type.h
gcc/rust/typecheck/rust-hir-type-check.h
gcc/rust/typecheck/rust-typecheck-context.cc
gcc/testsuite/rust/compile/issue-2907.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/nr2/exclude

index 6f2589a0d2ba7c4e78c877ccea72ab6e26d7fca3..2fbf123aa774fb80682e511e43850e0a43abeeb2 100644 (file)
@@ -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<TraitItemReference> 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;
 }
index 602076811c35b8baa6878fb6d123e989fcdf54a0..5da88b890f39a8fbf32c57d2a088dacd695ab039 100644 (file)
@@ -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;
 }
 
index cd0e941edd6da3102cb4e46ed38e17395f816eac..4746e7d730dab7bba5a8373a9cc15f01b7f71ff4 100644 (file)
@@ -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
index 0360c5504b78518a6b8a5ea1c8c25f5f94af32cf..89ede4e3013c81badcdae13c86146930faf1be8f 100644 (file)
@@ -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<HirId> 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<std::unique_ptr<HIR::TypePathSegment>> &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<TyTy::ADTType *> (tyseg);
+             auto last_variant = adt->get_variants ();
+             TyTy::VariantDef *variant = last_variant.back ();
 
-      if (candidate.is_enum_candidate ())
-       {
-         TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (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 ())
index ab29152ef45b9f88e447311191b6bde68d82d7dd..bf5589cbbabd679bb08b90a8f644312e807a2df7 100644 (file)
@@ -82,13 +82,18 @@ private:
   {}
 
   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<std::unique_ptr<HIR::TypePathSegment>> &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;
 };
index e0918e9d93ca989bd66ab282451a4732125a545e..08c3d354f795c453d7b804f6c9073fb9eab36c1f 100644 (file)
@@ -82,6 +82,37 @@ private:
   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 @@ public:
   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<bool (HirId, TyTy::BaseType *)> cb);
 
   bool have_loop_context () const;
@@ -245,6 +282,7 @@ private:
   std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
     return_type_stack;
   std::vector<TyTy::BaseType *> loop_type_stack;
+  std::vector<TypeCheckBlockContextItem> block_stack;
   std::map<DefId, TraitReference> trait_context;
   std::map<HirId, TyTy::BaseType *> receiver_context;
   std::map<HirId, AssociatedImplTrait> associated_impl_traits;
index 1cd5dabf8222d6a8d7d64379368c2fcd29aa5522..e72ce41606d0ebf00feedd6f412c55e4c29b31a1 100644 (file)
@@ -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<bool (HirId, TyTy::BaseType *)> 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 (file)
index 0000000..1af843f
--- /dev/null
@@ -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<B: Bar> 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);
+}
index b282f05637d232e817d965aa97bd4b1601c45b0c..00ac704fec2f59a36ea2b6c3e4e541ff3f030b13 100644 (file)
@@ -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