From d3c98218eae5829609456cd3e2f7d1a8f2bba507 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 3 Feb 2025 16:19:30 +0000 Subject: [PATCH] gccrs: Fix compilation of trait-items which map to impl items 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 (v: placeholder) -> Self Remember that a path such as: Try::from_error gets handled by doing a clever substitution: ::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 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 > (v : i32) -> Result This does not really match the signiture of the impl item for Result which is: fn (v: i32) -> Result 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 --- gcc/rust/backend/rust-compile-expr.cc | 8 +- gcc/rust/backend/rust-compile-item.cc | 27 +++++- gcc/rust/backend/rust-compile-resolve-path.cc | 16 ++-- .../typecheck/rust-hir-type-check-expr.cc | 6 -- .../typecheck/rust-hir-type-check-path.cc | 3 - .../typecheck/rust-hir-type-check-type.cc | 4 - gcc/rust/typecheck/rust-hir-type-check.h | 4 - gcc/rust/typecheck/rust-typecheck-context.cc | 17 ---- .../rust/execute/torture/issue-3381.rs | 90 +++++++++++++++++++ 9 files changed, 129 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/issue-3381.rs diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index a72156b6aa3..021495afb93 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -1394,8 +1394,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) TyTy::FnType *fntype = static_cast (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; diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 2b6836ac391..3e028c3b943 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -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 (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 (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 ()); + fntype = resolved->as (); + } + + fntype->monomorphize (); } else { diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index c862a81e212..1b9dee69a10 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -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 ()); + auto fn = lookup->as (); + 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); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 356a960f317..2fb4d3cba34 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -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; diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index a4f294b5290..73d97384789 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -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 ( diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 6dc62d68f72..ff6813a513d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -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 ( diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 42ef2d14325..21ecf2ce786 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -202,9 +202,6 @@ class TypeCheckContext 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 @@ class TypeCheckContext std::vector loop_type_stack; StackedContexts block_stack; std::map trait_context; - std::map receiver_context; std::map associated_impl_traits; // trait-id -> list of < self-tyty:impl-id> diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index d3ff29a4bdb..4cee74ae250 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -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 index 00000000000..62dbcd0b2fd --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-3381.rs @@ -0,0 +1,90 @@ +/* { dg-output "Err: 15\r*\n" } */ +#[lang = "sized"] +trait Sized {} + +enum Result { + #[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; + + #[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 Try for Result { + type Ok = T; + type Error = E; + + fn into_result(self) -> Result { + self + } + + fn from_ok(v: T) -> Self { + Result::Ok(v) + } + + fn from_error(v: E) -> Self { + Result::Err(v) + } +} + +pub trait From: Sized { + fn from(_: T) -> Self; +} + +impl From 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 { + Result::Err(15) +} + +fn foo() -> Result { + 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 +}