]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: qualified path syntax is used to disambiguate predicates
authorPhilip Herron <herron.philip@googlemail.com>
Thu, 20 Apr 2023 16:10:15 +0000 (17:10 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:34:15 +0000 (18:34 +0100)
When resolving a qualified path we need to use the predicate to lookup the
relevant assoicated impl block where possible. The issue here is that
it might not have one due to a valid error in the impl block or it might
be used within a trait this is a valid case. Generally we will be able to
resolve to an impl block then it can grab that type and move on.

Fixes #2135

gcc/rust/ChangeLog:

* typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): use the predicate
(TypeCheckExpr::resolve_segments): cleanup

gcc/testsuite/ChangeLog:

* rust/compile/issue-2135.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/typecheck/rust-hir-type-check-path.cc
gcc/testsuite/rust/compile/issue-2135.rs [new file with mode: 0644]

index dd7bc9aee6e26b20450ec4eb6a6e32cab732379d..9b5c6fee10109e0414e6fba0126c47274afbebd4 100644 (file)
@@ -69,49 +69,63 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
   // inherit the bound
   root->inherit_bounds ({specified_bound});
 
-  // setup the associated types
-  const TraitReference *specified_bound_ref = specified_bound.get ();
-  auto candidates = TypeBoundsProbe::Probe (root);
-  AssociatedImplTrait *associated_impl_trait = nullptr;
-  for (auto &probed_bound : candidates)
+  // lookup the associated item from the specified bound
+  HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
+  HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
+  TyTy::TypeBoundPredicateItem item
+    = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
+  if (item.is_error ())
     {
-      const TraitReference *bound_trait_ref = probed_bound.first;
-      const HIR::ImplBlock *associated_impl = probed_bound.second;
-
-      HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
-      AssociatedImplTrait *associated = nullptr;
-      bool found_impl_trait
-       = context->lookup_associated_trait_impl (impl_block_id, &associated);
-      if (found_impl_trait)
+      rust_error_at (item_seg.get_locus (), "unknown associated item");
+      return;
+    }
+
+  // we try to look for the real impl item if possible
+  HIR::ImplItem *impl_item = nullptr;
+
+  // lookup the associated impl trait for this if we can (it might be generic)
+  AssociatedImplTrait *associated_impl_trait
+    = lookup_associated_impl_block (specified_bound, root);
+  if (associated_impl_trait != nullptr)
+    {
+      for (auto &i :
+          associated_impl_trait->get_impl_block ()->get_impl_items ())
        {
-         bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
-         bool found_self = associated->get_self ()->can_eq (root, false);
-         if (found_trait && found_self)
+         bool found = i->get_impl_item_name ().compare (
+                        item_seg_identifier.as_string ())
+                      == 0;
+         if (found)
            {
-             associated_impl_trait = associated;
+             impl_item = i.get ();
              break;
            }
        }
     }
 
-  if (associated_impl_trait != nullptr)
+  NodeId root_resolved_node_id = UNKNOWN_NODEID;
+  if (impl_item == nullptr)
     {
-      associated_impl_trait->setup_associated_types (root, specified_bound);
+      // this may be valid as there could be a default trait implementation here
+      // and we dont need to worry if the trait item is actually implemented or
+      // not because this will have already been validated as part of the trait
+      // impl block
+      infered = item.get_tyty_for_receiver (root);
+      root_resolved_node_id
+       = item.get_raw_item ()->get_mappings ().get_nodeid ();
     }
-
-  // lookup the associated item from the specified bound
-  HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
-  HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
-  TyTy::TypeBoundPredicateItem item
-    = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
-  if (item.is_error ())
+  else
     {
-      rust_error_at (item_seg.get_locus (), "unknown associated item");
-      return;
-    }
+      HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid ();
+      bool ok = query_type (impl_item_id, &infered);
+      if (!ok)
+       {
+         // FIXME
+         // I think query_type should error if required here anyway
+         return;
+       }
 
-  // infer the root type
-  infered = item.get_tyty_for_receiver (root);
+      root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid ();
+    }
 
   // turbo-fish segment path::<ty>
   if (item_seg.has_generic_args ())
@@ -129,10 +143,7 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
     }
 
   // continue on as a path-in-expression
-  const TraitItemReference *trait_item_ref = item.get_raw_item ();
-  NodeId root_resolved_node_id = trait_item_ref->get_mappings ().get_nodeid ();
   bool fully_resolved = expr.get_segments ().size () <= 1;
-
   if (fully_resolved)
     {
       resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
@@ -321,7 +332,8 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
       // candidate is found then we search extensions from traits
       auto candidates
        = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
-                               false, true /*ignore_mandatory_trait_items*/);
+                               false /*probe_bounds*/,
+                               true /*ignore_mandatory_trait_items*/);
       if (candidates.size () == 0)
        {
          candidates
diff --git a/gcc/testsuite/rust/compile/issue-2135.rs b/gcc/testsuite/rust/compile/issue-2135.rs
new file mode 100644 (file)
index 0000000..563345e
--- /dev/null
@@ -0,0 +1,19 @@
+pub trait Foo<A> {
+    fn foo(self, _: A) -> u16;
+}
+
+impl Foo<u16> for u16 {
+    fn foo(self, _: u16) -> u16 {
+        self
+    }
+}
+
+impl Foo<u8> for u16 {
+    fn foo(self, _: u8) -> u16 {
+        self
+    }
+}
+
+pub fn bar() -> u16 {
+    <u16 as Foo<u16>>::foo(0u16, 0u16)
+}