aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <herron.philip@googlemail.com>2023-05-23 17:55:32 +0100
committerPhilip Herron <philip.herron@embecosm.com>2023-05-26 16:28:04 +0000
commitd47f52a583133e7ea1b703bdc1e0461aa650a414 (patch)
tree2f71627c5274a15229e55d69eca9c992b4a98fb8
parente656f08b6f7794c0c04a808fec50ea9a079577c7 (diff)
downloadgcc-d47f52a583133e7ea1b703bdc1e0461aa650a414.zip
gcc-d47f52a583133e7ea1b703bdc1e0461aa650a414.tar.gz
gcc-d47f52a583133e7ea1b703bdc1e0461aa650a414.tar.bz2
gccrs: support deref cycles to resolve to trait items
Fixes #2190 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (HIRCompileBase::resolve_deref_adjustment): reuse op overload code * typecheck/rust-autoderef.cc (Adjuster::try_deref_type): update (Adjuster::try_raw_deref_type): likewise * typecheck/rust-autoderef.h: likewise * typecheck/rust-hir-dot-operator.cc (MethodResolver::select): improve debug loging gcc/testsuite/ChangeLog: * rust/compile/issue-2190-1.rs: New test. * rust/compile/issue-2190-2.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc11
-rw-r--r--gcc/rust/typecheck/rust-autoderef.cc106
-rw-r--r--gcc/rust/typecheck/rust-autoderef.h15
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.cc5
-rw-r--r--gcc/testsuite/rust/compile/issue-2190-1.rs11
-rw-r--r--gcc/testsuite/rust/compile/issue-2190-2.rs20
6 files changed, 106 insertions, 62 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 8db52d4..b35db09 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -2367,15 +2367,8 @@ HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
rust_assert (adjustment.has_operator_overload ());
TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
- HIR::ImplItem *resolved_item = adjustment.get_deref_hir_item ();
-
- tree fn_address = error_mark_node;
- if (!lookup->has_subsititions_defined ())
- fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, nullptr,
- true, locus);
- else
- fn_address = CompileInherentImplItem::Compile (resolved_item, ctx, lookup,
- true, locus);
+ TyTy::BaseType *receiver = adjustment.get_actual ();
+ tree fn_address = resolve_method_address (lookup, receiver, locus);
// does it need a reference to call
tree adjusted_argument = expression;
diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
index 078a570..4ad0904 100644
--- a/gcc/rust/typecheck/rust-autoderef.cc
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -28,7 +28,7 @@ namespace Resolver {
static bool
resolve_operator_overload_fn (
Analysis::RustLangItem::ItemType lang_item_type, TyTy::BaseType *ty,
- TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+ TyTy::FnType **resolved_fn,
Adjustment::AdjustmentType *requires_ref_adjustment);
TyTy::BaseType *
@@ -44,19 +44,18 @@ Adjustment
Adjuster::try_deref_type (TyTy::BaseType *ty,
Analysis::RustLangItem::ItemType deref_lang_item)
{
- HIR::ImplItem *impl_item = nullptr;
TyTy::FnType *fn = nullptr;
Adjustment::AdjustmentType requires_ref_adjustment
= Adjustment::AdjustmentType::ERROR;
bool operator_overloaded
- = resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item,
+ = resolve_operator_overload_fn (deref_lang_item, ty, &fn,
&requires_ref_adjustment);
if (!operator_overloaded)
{
return Adjustment::get_error ();
}
- auto resolved_base = fn->get_return_type ()->clone ();
+ auto resolved_base = fn->get_return_type ()->destructure ();
bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF;
if (!is_valid_type)
return Adjustment::get_error ();
@@ -81,7 +80,7 @@ Adjuster::try_deref_type (TyTy::BaseType *ty,
}
return Adjustment::get_op_overload_deref_adjustment (adjustment_type, ty,
- ref_base, fn, impl_item,
+ ref_base, fn,
requires_ref_adjustment);
}
@@ -94,7 +93,7 @@ Adjuster::try_raw_deref_type (TyTy::BaseType *ty)
const TyTy::ReferenceType *ref_base
= static_cast<const TyTy::ReferenceType *> (ty);
- auto infered = ref_base->get_base ()->clone ();
+ auto infered = ref_base->get_base ()->destructure ();
return Adjustment (Adjustment::AdjustmentType::INDIRECTION, ty, infered);
}
@@ -122,8 +121,8 @@ Adjuster::try_unsize_type (TyTy::BaseType *ty)
static bool
resolve_operator_overload_fn (
- Analysis::RustLangItem::ItemType lang_item_type, TyTy::BaseType *ty,
- TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
+ Analysis::RustLangItem::ItemType lang_item_type, TyTy::BaseType *lhs,
+ TyTy::FnType **resolved_fn,
Adjustment::AdjustmentType *requires_ref_adjustment)
{
auto context = TypeCheckContext::get ();
@@ -139,35 +138,69 @@ resolve_operator_overload_fn (
if (!lang_item_defined)
return false;
+ // we might be in a static or const context and unknown is fine
+ TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
+ if (context->have_function_context ())
+ {
+ current_context = context->peek_context ();
+ }
+
+ // this flags stops recurisve calls to try and deref when none is available
+ // which will cause an infinite loop
+ bool autoderef_flag = true;
auto segment = HIR::PathIdentSegment (associated_item_name);
- auto candidates
- = MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name),
- true);
+ auto candidates = MethodResolver::Probe (lhs, segment, autoderef_flag);
+
+ // remove any recursive candidates
+ std::set<MethodCandidate> resolved_candidates;
+ for (auto &c : candidates)
+ {
+ const TyTy::BaseType *candidate_type = c.candidate.ty;
+ rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
+
+ const TyTy::FnType &fn
+ = *static_cast<const TyTy::FnType *> (candidate_type);
- bool have_implementation_for_lang_item = !candidates.empty ();
+ DefId current_fn_defid = current_context.get_defid ();
+ bool recursive_candidated = fn.get_id () == current_fn_defid;
+ if (!recursive_candidated)
+ {
+ resolved_candidates.insert (c);
+ }
+ }
+
+ bool have_implementation_for_lang_item = resolved_candidates.size () > 0;
if (!have_implementation_for_lang_item)
return false;
- // multiple candidates?
- if (candidates.size () > 1)
+ if (resolved_candidates.size () > 1)
{
- // error out? probably not for this case
+ // no need to error out as we are just trying to see if there is a fit
return false;
}
// Get the adjusted self
- auto candidate = *candidates.begin ();
- Adjuster adj (ty);
+ MethodCandidate candidate = *resolved_candidates.begin ();
+ Adjuster adj (lhs);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
- // is this the case we are recursive
- // handle the case where we are within the impl block for this
- // lang_item otherwise we end up with a recursive operator overload
- // such as the i32 operator overload trait
- TypeCheckContextItem fn_context = context->peek_context ();
- if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
+ PathProbeCandidate &resolved_candidate = candidate.candidate;
+ TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
+ rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::BaseType *lookup = lookup_tyty;
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ rust_assert (fn->is_method ());
+
+ rust_debug ("is_impl_item_candidate: %s",
+ resolved_candidate.is_impl_candidate () ? "true" : "false");
+
+ // in the case where we resolve to a trait bound we have to be careful we are
+ // able to do so there is a case where we are currently resolving the deref
+ // operator overload function which is generic and this might resolve to the
+ // trait item of deref which is not valid as its just another recursive case
+ if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
{
- auto &impl_item = fn_context.get_impl_item ();
+ auto &impl_item = current_context.get_impl_item ();
HIR::ImplBlock *parent = impl_item.first;
HIR::Function *fn = impl_item.second;
@@ -201,24 +234,17 @@ resolve_operator_overload_fn (
}
}
- TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
-
- // rust only support impl item deref operator overloading ie you must have an
- // impl block for it
- rust_assert (candidate.candidate.type
- == PathProbeCandidate::CandidateType::IMPL_FUNC);
- *impl_item = candidate.candidate.item.impl.impl_item;
-
- rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::BaseType *lookup = lookup_tyty;
- TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
- rust_assert (fn->is_method ());
+ // we found a valid operator overload
+ fn->prepare_higher_ranked_bounds ();
+ rust_debug ("resolved operator overload to: {%u} {%s}",
+ candidate.candidate.ty->get_ref (),
+ candidate.candidate.ty->debug_str ().c_str ());
if (fn->needs_substitution ())
{
- if (ty->get_kind () == TyTy::TypeKind::ADT)
+ if (lhs->get_kind () == TyTy::TypeKind::ADT)
{
- const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty);
+ const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (lhs);
auto s = fn->get_self_type ()->get_root ();
rust_assert (s->can_eq (adt, false));
@@ -265,8 +291,8 @@ resolve_operator_overload_fn (
rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
fn = static_cast<TyTy::FnType *> (lookup);
- Location unify_locus = mappings->lookup_location (ty->get_ref ());
- unify_site (ty->get_ref (),
+ Location unify_locus = mappings->lookup_location (lhs->get_ref ());
+ unify_site (lhs->get_ref (),
TyTy::TyWithLocation (fn->get_self_type ()),
TyTy::TyWithLocation (adjusted_self), unify_locus);
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
index 1d5dacf..74e7c5f 100644
--- a/gcc/rust/typecheck/rust-autoderef.h
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -42,18 +42,15 @@ public:
// ctor for all adjustments except derefs
Adjustment (AdjustmentType type, TyTy::BaseType *actual,
TyTy::BaseType *expected)
- : Adjustment (type, actual, expected, nullptr, nullptr,
- AdjustmentType::ERROR)
+ : Adjustment (type, actual, expected, nullptr, AdjustmentType::ERROR)
{}
static Adjustment get_op_overload_deref_adjustment (
AdjustmentType type, TyTy::BaseType *actual, TyTy::BaseType *expected,
- TyTy::FnType *fn, HIR::ImplItem *deref_item,
- Adjustment::AdjustmentType requires_ref_adjustment)
+ TyTy::FnType *fn, Adjustment::AdjustmentType requires_ref_adjustment)
{
rust_assert (type == DEREF || type == DEREF_MUT);
- return Adjustment (type, actual, expected, fn, deref_item,
- requires_ref_adjustment);
+ return Adjustment (type, actual, expected, fn, requires_ref_adjustment);
}
AdjustmentType get_type () const { return type; }
@@ -107,15 +104,12 @@ public:
return requires_ref_adjustment;
}
- HIR::ImplItem *get_deref_hir_item () const { return deref_item; }
-
private:
Adjustment (AdjustmentType type, TyTy::BaseType *actual,
TyTy::BaseType *expected, TyTy::FnType *deref_operator_fn,
- HIR::ImplItem *deref_item,
Adjustment::AdjustmentType requires_ref_adjustment)
: type (type), actual (actual), expected (expected),
- deref_operator_fn (deref_operator_fn), deref_item (deref_item),
+ deref_operator_fn (deref_operator_fn),
requires_ref_adjustment (requires_ref_adjustment)
{}
@@ -127,7 +121,6 @@ private:
//
// the fn that we are calling
TyTy::FnType *deref_operator_fn;
- HIR::ImplItem *deref_item;
// operator overloads can requre a reference
Adjustment::AdjustmentType requires_ref_adjustment;
};
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 29c3e4c..3239029 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -66,8 +66,9 @@ MethodResolver::try_hook (const TyTy::BaseType &r)
bool
MethodResolver::select (TyTy::BaseType &receiver)
{
- rust_debug ("MethodResolver::select reciever=[%s]",
- receiver.debug_str ().c_str ());
+ rust_debug ("MethodResolver::select reciever=[%s] path=[%s]",
+ receiver.debug_str ().c_str (),
+ segment_name.as_string ().c_str ());
struct impl_item_candidate
{
diff --git a/gcc/testsuite/rust/compile/issue-2190-1.rs b/gcc/testsuite/rust/compile/issue-2190-1.rs
new file mode 100644
index 0000000..85091b2
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2190-1.rs
@@ -0,0 +1,11 @@
+#[lang = "deref"]
+trait Deref {
+ type Target;
+ fn deref(&self) -> &Self::Target;
+}
+
+fn foo<T: Deref<Target = i32>>(t: &T) -> i32 {
+ t.max(2)
+ // { dg-error "failed to resolve method for .max." "" { target *-*-* } .-1 }
+ // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-2190-2.rs b/gcc/testsuite/rust/compile/issue-2190-2.rs
new file mode 100644
index 0000000..48ab72b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2190-2.rs
@@ -0,0 +1,20 @@
+// { dg-options "-w" }
+#[lang = "deref"]
+trait Deref {
+ type Target;
+ fn deref(&self) -> &Self::Target;
+}
+
+fn foo<T: Deref<Target = i32>>(t: &T) -> i32 {
+ t.max(2)
+}
+
+impl i32 {
+ fn max(self, other: i32) -> i32 {
+ if self > other {
+ self
+ } else {
+ other
+ }
+ }
+}