]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Fix compilation of trait-items which map to impl items
authorPhilip Herron <herron.philip@googlemail.com>
Mon, 3 Feb 2025 16:19:30 +0000 (16:19 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 24 Mar 2025 12:07:02 +0000 (13:07 +0100)
When we have paths such as Try::from_error the Try references the Trait
and then from_error references the from_error trait item. So this resolves
directly to a trait implementation which has the type:

  fn <Self> (v: placeholder) -> Self

Remember that a path such as: Try::from_error gets handled by doing a
clever substitution: <T? as Try>::from_error

The main piece here is that we resolve this function type and for
monomoprhization we know this is a trait call but we know that all trait's
have an implicit Self type param which in this case is Result<i32, i32>
so when it comes to knowing which impl block this is we got rid of the old
bad insert/lookup receiver hack and use the specified type to know which
impl block we are talking about to generate the function.

The hard part here is inside rust-compil-item.cc, where we have the
'concete' type which is the trait item fntype of:

  fn <Result<i32, i32>> (v : i32) -> Result<i32,i32>

This does not really match the signiture of the impl item for Result
which is:

  fn <T, E> (v: i32) -> Result<T, E>

So what we need to do is actually infer this by inputing inference
variables on the impl fntype then unify'ing the trait object to this to
compute the types of this to monomorphize this.

Fixes Rust-GCC#3381

gcc/rust/ChangeLog:

* backend/rust-compile-expr.cc (CompileExpr::visit): remove receiver interface
* backend/rust-compile-item.cc (CompileItem::visit): monomorphize trait to impl item
* backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): use trait item Self
* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): remove receiver interface
(TypeCheckExpr::resolve_fn_trait_call): likewise
* typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): likewise
(TypeCheckExpr::resolve_segments): likewise
* typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise
* typecheck/rust-hir-type-check.h: likewise
* typecheck/rust-typecheck-context.cc (TypeCheckContext::insert_receiver): remove
(TypeCheckContext::lookup_receiver): remove

gcc/testsuite/ChangeLog:

* rust/execute/torture/issue-3381.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/backend/rust-compile-expr.cc
gcc/rust/backend/rust-compile-item.cc
gcc/rust/backend/rust-compile-resolve-path.cc
gcc/rust/typecheck/rust-hir-type-check-expr.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.h
gcc/rust/typecheck/rust-typecheck-context.cc
gcc/testsuite/rust/execute/torture/issue-3381.rs [new file with mode: 0644]

index 48713e7b8b4d981ebeba12f48942a51a4e61920c..21f4ca1ba1801d5f46748ab4e05f1ba32d4f62a0 100644 (file)
@@ -1394,8 +1394,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
   TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype);
 
   TyTy::BaseType *receiver = nullptr;
-  ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
-                                          &receiver);
+  ok = ctx->get_tyctx ()->lookup_type (
+    expr.get_receiver ().get_mappings ().get_hirid (), &receiver);
   rust_assert (ok);
 
   bool is_dyn_dispatch
@@ -1532,8 +1532,8 @@ CompileExpr::resolve_operator_overload (
 
   TyTy::BaseType *receiver = nullptr;
   bool ok
-    = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (),
-                                         &receiver);
+    = ctx->get_tyctx ()->lookup_type (lhs_expr.get_mappings ().get_hirid (),
+                                     &receiver);
   rust_assert (ok);
 
   bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM;
index 39d4b9eb4fad39415455d9cbfb9fedf3d4b48c6d..7ce984864c8a48b6e134afa147e8f3e8d94ec5f1 100644 (file)
@@ -19,6 +19,8 @@
 #include "rust-compile-item.h"
 #include "rust-compile-implitem.h"
 #include "rust-compile-extern.h"
+#include "rust-substitution-mapper.h"
+#include "rust-type-util.h"
 #include "rust-immutable-name-resolution-context.h"
 
 namespace Rust {
@@ -165,12 +167,33 @@ CompileItem::visit (HIR::Function &function)
       // is given
       if (concrete == nullptr)
        return;
-      else
+
+      rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
+      TyTy::FnType *concrete_fnty = static_cast<TyTy::FnType *> (concrete);
+      bool is_trait_item_concrete
+       = ctx->get_mappings ()
+           .lookup_trait_item_defid (concrete_fnty->get_id ())
+           .has_value ();
+      if (!is_trait_item_concrete)
        {
          rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
          fntype = static_cast<TyTy::FnType *> (concrete);
-         fntype->monomorphize ();
        }
+      else
+       {
+         TyTy::BaseType *infer
+           = Resolver::SubstMapper::InferSubst (fntype, function.get_locus ());
+         TyTy::BaseType *resolved
+           = Resolver::unify_site (function.get_mappings ().get_hirid (),
+                                   TyTy::TyWithLocation (infer),
+                                   TyTy::TyWithLocation (concrete),
+                                   function.get_locus ());
+
+         rust_assert (resolved->is<TyTy::FnType> ());
+         fntype = resolved->as<TyTy::FnType> ();
+       }
+
+      fntype->monomorphize ();
     }
   else
     {
index fbf9a3dab590039639756f107f15cf0084c538a0..c54cc09b67be067bcf67fdd6884b4f2e31e2be7c 100644 (file)
@@ -297,16 +297,20 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
            trait->get_mappings ().get_defid (), &trait_ref);
          rust_assert (ok);
 
-         TyTy::BaseType *receiver = nullptr;
-         ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
-                                                  &receiver);
-         rust_assert (ok);
-         receiver = receiver->destructure ();
-
          // the type resolver can only resolve type bounds to their trait
          // item so its up to us to figure out if this path should resolve
          // to an trait-impl-block-item or if it can be defaulted to the
          // trait-impl-item's definition
+         //
+         // because we know this is resolved to a trait item we can actually
+         // just grab the Self type parameter here for the receiver to match
+         // the appropriate impl block
+
+         rust_assert (lookup->is<TyTy::FnType> ());
+         auto fn = lookup->as<TyTy::FnType> ();
+         rust_assert (fn->get_num_type_params () > 0);
+         auto &self = fn->get_substs ().at (0);
+         auto receiver = self.get_param_ty ();
          auto candidates
            = Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
                                                   trait_ref);
index 23773f138367799e5369f68d174312b386271aeb..860975301a0ec83bef3a444b93c15e825ba60561 100644 (file)
@@ -1105,8 +1105,6 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
       return;
     }
 
-  context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
-
   rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
                  receiver_tyty->debug_str ().c_str ());
   auto candidates
@@ -1750,9 +1748,6 @@ TypeCheckExpr::resolve_operator_overload (
   context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
                                      std::move (candidate.adjustments));
 
-  // now its just like a method-call-expr
-  context->insert_receiver (expr.get_mappings ().get_hirid (), lhs);
-
   PathProbeCandidate &resolved_candidate = candidate.candidate;
   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
   NodeId resolved_node_id
@@ -1997,7 +1992,6 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
   HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
   context->insert_autoderef_mappings (autoderef_mappings_id,
                                      std::move (candidate.adjustments));
-  context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
 
   PathProbeCandidate &resolved_candidate = candidate.candidate;
   TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
index 2525f61a8c726ee779284a37b5768800e259a1f9..a5243631fbda21ffe79fbba5755f20ac703d6b2e 100644 (file)
@@ -171,7 +171,6 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
          resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
                                          root_resolved_node_id);
        }
-      context->insert_receiver (expr.get_mappings ().get_hirid (), root);
       return;
     }
 
@@ -559,8 +558,6 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
     }
 
   rust_assert (resolved_node_id != UNKNOWN_NODEID);
-  context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
-
   if (flag_name_resolution_2_0)
     {
       auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> (
index 99173d8282f9af0f7c2ce8894d1d77bdf1dfd804..93913e89cb782e391404c8194a16eb38ac8b55c7 100644 (file)
@@ -360,8 +360,6 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
          resolver->insert_resolved_type (path.get_mappings ().get_nodeid (),
                                          root_resolved_node_id);
        }
-
-      context->insert_receiver (path.get_mappings ().get_hirid (), root);
       return;
     }
 
@@ -704,9 +702,7 @@ TypeCheckType::resolve_segments (
        }
     }
 
-  context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
   rust_assert (resolved_node_id != UNKNOWN_NODEID);
-
   if (flag_name_resolution_2_0)
     {
       auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> (
index ef1f2dd021480e6333be1147a8971843f8a88aa5..d8742939d95c68d9b59e4bfc55d6d8853783ed99 100644 (file)
@@ -202,9 +202,6 @@ public:
   void insert_trait_reference (DefId id, TraitReference &&ref);
   bool lookup_trait_reference (DefId id, TraitReference **ref);
 
-  void insert_receiver (HirId id, TyTy::BaseType *t);
-  bool lookup_receiver (HirId id, TyTy::BaseType **ref);
-
   void insert_associated_trait_impl (HirId id,
                                     AssociatedImplTrait &&associated);
   bool lookup_associated_trait_impl (HirId id,
@@ -282,7 +279,6 @@ private:
   std::vector<TyTy::BaseType *> loop_type_stack;
   StackedContexts<TypeCheckBlockContextItem> block_stack;
   std::map<DefId, TraitReference> trait_context;
-  std::map<HirId, TyTy::BaseType *> receiver_context;
   std::map<HirId, AssociatedImplTrait> associated_impl_traits;
 
   // trait-id -> list of < self-tyty:impl-id>
index 8ff8839f7336afecd738bbb20f66fbff70b52fef..f6ef2688aaa0fb5847cc7d306cda65e9d25ab405 100644 (file)
@@ -254,23 +254,6 @@ TypeCheckContext::lookup_trait_reference (DefId id, TraitReference **ref)
   return true;
 }
 
-void
-TypeCheckContext::insert_receiver (HirId id, TyTy::BaseType *t)
-{
-  receiver_context[id] = t;
-}
-
-bool
-TypeCheckContext::lookup_receiver (HirId id, TyTy::BaseType **ref)
-{
-  auto it = receiver_context.find (id);
-  if (it == receiver_context.end ())
-    return false;
-
-  *ref = it->second;
-  return true;
-}
-
 void
 TypeCheckContext::insert_associated_trait_impl (
   HirId id, AssociatedImplTrait &&associated)
diff --git a/gcc/testsuite/rust/execute/torture/issue-3381.rs b/gcc/testsuite/rust/execute/torture/issue-3381.rs
new file mode 100644 (file)
index 0000000..62dbcd0
--- /dev/null
@@ -0,0 +1,90 @@
+/* { dg-output "Err: 15\r*\n" } */
+#[lang = "sized"]
+trait Sized {}
+
+enum Result<T, E> {
+    #[lang = "Ok"]
+    Ok(T),
+    #[lang = "Err"]
+    Err(E),
+}
+
+#[lang = "try"]
+pub trait Try {
+    type Ok;
+    type Error;
+
+    #[lang = "into_result"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn into_result(self) -> Result<Self::Ok, Self::Error>;
+
+    #[lang = "from_error"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn from_error(v: Self::Ok) -> Self;
+
+    #[lang = "from_ok"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn from_ok(v: Self::Error) -> Self;
+}
+
+impl<T, E> Try for Result<T, E> {
+    type Ok = T;
+    type Error = E;
+
+    fn into_result(self) -> Result<T, E> {
+        self
+    }
+
+    fn from_ok(v: T) -> Self {
+        Result::Ok(v)
+    }
+
+    fn from_error(v: E) -> Self {
+        Result::Err(v)
+    }
+}
+
+pub trait From<T>: Sized {
+    fn from(_: T) -> Self;
+}
+
+impl<T> From<T> for T {
+    fn from(t: T) -> Self {
+        t
+    }
+}
+
+fn print(s: &str, value: i32) {
+    extern "C" {
+        fn printf(s: *const i8, ...);
+    }
+
+    unsafe {
+        printf(s as *const str as *const i8, value);
+    }
+}
+
+fn baz() -> Result<i32, i32> {
+    Result::Err(15)
+}
+
+fn foo() -> Result<i32, i32> {
+    let b = match baz() {
+        Result::Ok(value) => value,
+        Result::Err(err) => {
+            return Try::from_error(From::from(err));
+        }
+    };
+
+    Result::Ok(15 + b)
+}
+
+fn main() -> i32 {
+    let a = foo();
+    match a {
+        Result::Ok(value) => print("Ok: %i\n", value),
+        Result::Err(err) => print("Err: %i\n", err),
+    };
+
+    0
+}