aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-02-11 14:51:22 +0000
committerPhilip Herron <philip.herron@embecosm.com>2022-02-11 15:34:17 +0000
commitc0e5ca327ba69655de7eae9628b85ad5a615dd77 (patch)
tree59405bd9b3abb50f0db69d80c6c924c0a4ed2c68
parent9023bb8687347559702340c24cd72301f0656a59 (diff)
downloadgcc-c0e5ca327ba69655de7eae9628b85ad5a615dd77.zip
gcc-c0e5ca327ba69655de7eae9628b85ad5a615dd77.tar.gz
gcc-c0e5ca327ba69655de7eae9628b85ad5a615dd77.tar.bz2
Support deref_mut lang item during method resolution
When we have method resolution we need to look at any deref lang items for the receiver. The precise rules need to be tested rigorously to ensure this is right. Fixes #890
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/backend/rust-compile-base.h3
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc39
-rw-r--r--gcc/rust/typecheck/rust-autoderef.cc69
-rw-r--r--gcc/rust/typecheck/rust-autoderef.h29
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.cc359
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.h270
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h1
-rw-r--r--gcc/testsuite/rust/execute/torture/method3.rs78
-rw-r--r--gcc/testsuite/rust/execute/torture/method4.rs78
10 files changed, 605 insertions, 322 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 4f76216..5d02f06 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -89,6 +89,7 @@ GRS_OBJS = \
rust/rust-hir-type-check-type.o \
rust/rust-hir-type-check-struct.o \
rust/rust-hir-type-check-pattern.o \
+ rust/rust-hir-dot-operator.o \
rust/rust-autoderef.o \
rust/rust-substitution-mapper.o \
rust/rust-lint-marklive.o \
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index a52886c..54116da 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -67,6 +67,9 @@ protected:
tree resolve_deref_adjustment (Resolver::Adjustment &adjustment,
tree expression, Location locus);
+ tree resolve_indirection_adjustment (Resolver::Adjustment &adjustment,
+ tree expression, Location locus);
+
static void setup_attributes_on_fndecl (
tree fndecl, bool is_main_entry_point, bool has_visibility,
const HIR::FunctionQualifiers &qualifiers, const AST::AttrVec &attrs);
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index a592e35..65f159e 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -1199,9 +1199,14 @@ HIRCompileBase::resolve_adjustements (
e = address_expression (e, locus);
break;
- case Resolver::Adjustment::AdjustmentType::DEREF_REF:
+ case Resolver::Adjustment::AdjustmentType::DEREF:
+ case Resolver::Adjustment::AdjustmentType::DEREF_MUT:
e = resolve_deref_adjustment (adjustment, e, locus);
break;
+
+ case Resolver::Adjustment::AdjustmentType::INDIRECTION:
+ e = resolve_indirection_adjustment (adjustment, e, locus);
+ break;
}
}
@@ -1212,17 +1217,9 @@ tree
HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
tree expression, Location locus)
{
- rust_assert (adjustment.is_deref_adjustment ());
-
- tree expected_type
- = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
- if (!adjustment.has_operator_overload ())
- {
- return ctx->get_backend ()->indirect_expression (expected_type,
- expression,
- true, /* known_valid*/
- locus);
- }
+ rust_assert (adjustment.is_deref_adjustment ()
+ || adjustment.is_deref_mut_adjustment ());
+ rust_assert (adjustment.has_operator_overload ());
TyTy::FnType *lookup = adjustment.get_deref_operator_fn ();
HIR::ImplItem *resolved_item = adjustment.get_deref_hir_item ();
@@ -1246,13 +1243,19 @@ HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
// make the call
auto fncontext = ctx->peek_fn ();
- tree deref_call
- = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address,
- {adjusted_argument}, nullptr,
- locus);
+ return ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address,
+ {adjusted_argument}, nullptr,
+ locus);
+}
+
+tree
+HIRCompileBase::resolve_indirection_adjustment (
+ Resolver::Adjustment &adjustment, tree expression, Location locus)
+{
+ tree expected_type
+ = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
- // do the indirect expression
- return ctx->get_backend ()->indirect_expression (expected_type, deref_call,
+ return ctx->get_backend ()->indirect_expression (expected_type, expression,
true, /* known_valid*/
locus);
}
diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
index fd2f7d3..2862252 100644
--- a/gcc/rust/typecheck/rust-autoderef.cc
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -19,6 +19,7 @@
#include "rust-autoderef.h"
#include "rust-hir-path-probe.h"
#include "rust-hir-dot-operator.h"
+#include "rust-hir-trait-resolve.h"
namespace Rust {
namespace Resolver {
@@ -29,26 +30,6 @@ resolve_operator_overload_fn (
TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item,
Adjustment::AdjustmentType *requires_ref_adjustment);
-bool
-Adjuster::needs_address (const std::vector<Adjustment> &adjustments)
-{
- for (auto &adjustment : adjustments)
- {
- switch (adjustment.get_type ())
- {
- case Adjustment::AdjustmentType::IMM_REF:
- case Adjustment::AdjustmentType::MUT_REF:
- case Adjustment::AdjustmentType::DEREF_REF:
- return true;
-
- default:
- break;
- }
- }
-
- return false;
-}
-
TyTy::BaseType *
Adjuster::adjust_type (const std::vector<Adjustment> &adjustments)
{
@@ -59,23 +40,22 @@ Adjuster::adjust_type (const std::vector<Adjustment> &adjustments)
}
Adjustment
-Adjuster::try_deref_type (const TyTy::BaseType *ty)
+Adjuster::try_deref_type (const TyTy::BaseType *ty,
+ Analysis::RustLangItem::ItemType deref_lang_item)
{
- // probe for the lang-item
- TyTy::BaseType *resolved_base = ty->clone ();
-
HIR::ImplItem *impl_item = nullptr;
TyTy::FnType *fn = nullptr;
Adjustment::AdjustmentType requires_ref_adjustment
= Adjustment::AdjustmentType::ERROR;
bool operator_overloaded
- = resolve_operator_overload_fn (Analysis::RustLangItem::ItemType::DEREF, ty,
- &fn, &impl_item, &requires_ref_adjustment);
- if (operator_overloaded)
+ = resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item,
+ &requires_ref_adjustment);
+ if (!operator_overloaded)
{
- resolved_base = fn->get_return_type ()->clone ();
+ return Adjustment::get_error ();
}
+ auto resolved_base = fn->get_return_type ()->clone ();
bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF;
if (!is_valid_type)
return Adjustment::get_error ();
@@ -83,12 +63,41 @@ Adjuster::try_deref_type (const TyTy::BaseType *ty)
TyTy::ReferenceType *ref_base
= static_cast<TyTy::ReferenceType *> (resolved_base);
- auto infered = ref_base->get_base ()->clone ();
+ Adjustment::AdjustmentType adjustment_type
+ = Adjustment::AdjustmentType::ERROR;
+ switch (deref_lang_item)
+ {
+ case Analysis::RustLangItem::ItemType::DEREF:
+ adjustment_type = Adjustment::AdjustmentType::DEREF;
+ break;
- return Adjustment::get_op_overload_deref_adjustment (infered, fn, impl_item,
+ case Analysis::RustLangItem::ItemType::DEREF_MUT:
+ adjustment_type = Adjustment::AdjustmentType::DEREF_MUT;
+ break;
+
+ default:
+ break;
+ }
+
+ return Adjustment::get_op_overload_deref_adjustment (adjustment_type,
+ ref_base, fn, impl_item,
requires_ref_adjustment);
}
+Adjustment
+Adjuster::try_raw_deref_type (const TyTy::BaseType *ty)
+{
+ bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF;
+ if (!is_valid_type)
+ return Adjustment::get_error ();
+
+ const TyTy::ReferenceType *ref_base
+ = static_cast<const TyTy::ReferenceType *> (ty);
+ auto infered = ref_base->get_base ()->clone ();
+
+ return Adjustment (Adjustment::AdjustmentType::INDIRECTION, infered);
+}
+
static bool
resolve_operator_overload_fn (
Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty,
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
index a6c9d08..f389aff 100644
--- a/gcc/rust/typecheck/rust-autoderef.h
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -33,7 +33,9 @@ public:
IMM_REF,
MUT_REF,
- DEREF_REF
+ DEREF,
+ DEREF_MUT,
+ INDIRECTION,
};
// ctor for all adjustments except derefs
@@ -42,11 +44,12 @@ public:
{}
static Adjustment get_op_overload_deref_adjustment (
- const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item,
+ AdjustmentType type, const TyTy::BaseType *expected, TyTy::FnType *fn,
+ HIR::ImplItem *deref_item,
Adjustment::AdjustmentType requires_ref_adjustment)
{
- return Adjustment (Adjustment::DEREF_REF, expected, fn, deref_item,
- requires_ref_adjustment);
+ rust_assert (type == DEREF || type == DEREF_MUT);
+ return Adjustment (type, expected, fn, deref_item, requires_ref_adjustment);
}
AdjustmentType get_type () const { return type; }
@@ -69,8 +72,12 @@ public:
return "IMM_REF";
case AdjustmentType::MUT_REF:
return "MUT_REF";
- case AdjustmentType::DEREF_REF:
- return "DEREF_REF";
+ case AdjustmentType::DEREF:
+ return "DEREF";
+ case AdjustmentType::DEREF_MUT:
+ return "DEREF_MUT";
+ case AdjustmentType::INDIRECTION:
+ return "INDIRECTION";
}
gcc_unreachable ();
return "";
@@ -80,7 +87,9 @@ public:
bool is_error () const { return type == ERROR; }
- bool is_deref_adjustment () const { return type == DEREF_REF; }
+ bool is_deref_adjustment () const { return type == DEREF; }
+
+ bool is_deref_mut_adjustment () const { return type == DEREF_MUT; }
bool has_operator_overload () const { return deref_operator_fn != nullptr; }
@@ -120,9 +129,11 @@ public:
TyTy::BaseType *adjust_type (const std::vector<Adjustment> &adjustments);
- static bool needs_address (const std::vector<Adjustment> &adjustments);
+ static Adjustment
+ try_deref_type (const TyTy::BaseType *ty,
+ Analysis::RustLangItem::ItemType deref_lang_item);
- static Adjustment try_deref_type (const TyTy::BaseType *ty);
+ static Adjustment try_raw_deref_type (const TyTy::BaseType *ty);
private:
const TyTy::BaseType *base;
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
new file mode 100644
index 0000000..84bbc0c
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -0,0 +1,359 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-hir-dot-operator.h"
+#include "rust-hir-path-probe.h"
+#include "rust-hir-trait-resolve.h"
+
+namespace Rust {
+namespace Resolver {
+
+MethodCandidate
+MethodResolver::Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ bool autoderef_flag)
+{
+ const TyTy::BaseType *r = receiver;
+ std::vector<Adjustment> adjustments;
+ while (true)
+ {
+ auto res = Try (r, segment_name, adjustments);
+ if (!res.is_error ())
+ return res;
+
+ // 4. deref to to 1, if cannot deref then quit
+ if (autoderef_flag)
+ return MethodCandidate::get_error ();
+
+ Adjustment deref
+ = Adjuster::try_deref_type (r, Analysis::RustLangItem::ItemType::DEREF);
+ if (!deref.is_error ())
+ {
+ auto deref_r = deref.get_expected ();
+ adjustments.push_back (deref);
+ auto res = Try (deref_r, segment_name, adjustments);
+ if (!res.is_error ())
+ {
+ return res;
+ }
+
+ adjustments.pop_back ();
+ }
+
+ Adjustment deref_mut = Adjuster::try_deref_type (
+ r, Analysis::RustLangItem::ItemType::DEREF_MUT);
+ if (!deref_mut.is_error ())
+ {
+ auto deref_r = deref_mut.get_expected ();
+ adjustments.push_back (deref_mut);
+ auto res = Try (deref_r, segment_name, adjustments);
+ if (!res.is_error ())
+ {
+ return res;
+ }
+
+ adjustments.pop_back ();
+ }
+
+ if (!deref_mut.is_error ())
+ {
+ auto deref_r = deref_mut.get_expected ();
+ adjustments.push_back (deref_mut);
+ Adjustment raw_deref = Adjuster::try_raw_deref_type (deref_r);
+ adjustments.push_back (raw_deref);
+ deref_r = raw_deref.get_expected ();
+
+ auto res = Try (deref_r, segment_name, adjustments);
+ if (!res.is_error ())
+ {
+ return res;
+ }
+
+ adjustments.pop_back ();
+ adjustments.pop_back ();
+ }
+
+ if (!deref.is_error ())
+ {
+ r = deref.get_expected ();
+ adjustments.push_back (deref);
+ }
+ Adjustment raw_deref = Adjuster::try_raw_deref_type (r);
+ if (raw_deref.is_error ())
+ return MethodCandidate::get_error ();
+
+ r = raw_deref.get_expected ();
+ adjustments.push_back (raw_deref);
+ }
+ return MethodCandidate::get_error ();
+}
+
+MethodCandidate
+MethodResolver::Try (const TyTy::BaseType *r,
+ const HIR::PathIdentSegment &segment_name,
+ std::vector<Adjustment> &adjustments)
+{
+ PathProbeCandidate c = PathProbeCandidate::get_error ();
+ const std::vector<TyTy::TypeBoundPredicate> &specified_bounds
+ = r->get_specified_bounds ();
+
+ // 1. try raw
+ MethodResolver raw (*r, segment_name, specified_bounds);
+ c = raw.select ();
+ if (!c.is_error ())
+ {
+ return MethodCandidate{c, adjustments};
+ }
+
+ // 2. try ref
+ TyTy::ReferenceType *r1
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ Mutability::Imm);
+ MethodResolver imm_ref (*r1, segment_name, specified_bounds);
+ c = imm_ref.select ();
+ if (!c.is_error ())
+ {
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::IMM_REF, r1));
+ return MethodCandidate{c, adjustments};
+ }
+
+ // 3. try mut ref
+ TyTy::ReferenceType *r2
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ Mutability::Mut);
+ MethodResolver mut_ref (*r2, segment_name, specified_bounds);
+ c = mut_ref.select ();
+ if (!c.is_error ())
+ {
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::MUT_REF, r2));
+ return MethodCandidate{c, adjustments};
+ }
+
+ return MethodCandidate::get_error ();
+}
+
+PathProbeCandidate
+MethodResolver::select ()
+{
+ struct impl_item_candidate
+ {
+ HIR::Function *item;
+ HIR::ImplBlock *impl_block;
+ TyTy::FnType *ty;
+ };
+
+ // assemble inherent impl items
+ std::vector<impl_item_candidate> inherent_impl_fns;
+ mappings->iterate_impl_items (
+ [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
+ bool is_trait_impl = impl->has_trait_ref ();
+ if (is_trait_impl)
+ return true;
+
+ bool is_fn
+ = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
+ if (!is_fn)
+ return true;
+
+ HIR::Function *func = static_cast<HIR::Function *> (item);
+ if (!func->is_method ())
+ return true;
+
+ bool name_matches
+ = func->get_function_name ().compare (segment_name.as_string ()) == 0;
+ if (!name_matches)
+ return true;
+
+ TyTy::BaseType *ty = nullptr;
+ if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+ return true;
+ if (ty->get_kind () == TyTy::TypeKind::ERROR)
+ return true;
+
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ inherent_impl_fns.push_back ({func, impl, fnty});
+
+ return true;
+ });
+
+ struct trait_item_candidate
+ {
+ const HIR::TraitItemFunc *item;
+ const HIR::Trait *trait;
+ TyTy::FnType *ty;
+ const TraitReference *reference;
+ const TraitItemReference *item_ref;
+ };
+
+ std::vector<trait_item_candidate> trait_fns;
+ mappings->iterate_impl_blocks ([&] (HirId id,
+ HIR::ImplBlock *impl) mutable -> bool {
+ bool is_trait_impl = impl->has_trait_ref ();
+ if (!is_trait_impl)
+ return true;
+
+ // look for impl implementation else lookup the associated trait item
+ for (auto &impl_item : impl->get_impl_items ())
+ {
+ bool is_fn = impl_item->get_impl_item_type ()
+ == HIR::ImplItem::ImplItemType::FUNCTION;
+ if (!is_fn)
+ continue;
+
+ HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
+ if (!func->is_method ())
+ continue;
+
+ bool name_matches
+ = func->get_function_name ().compare (segment_name.as_string ()) == 0;
+ if (!name_matches)
+ continue;
+
+ TyTy::BaseType *ty = nullptr;
+ if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
+ continue;
+ if (ty->get_kind () == TyTy::TypeKind::ERROR)
+ continue;
+
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ inherent_impl_fns.push_back ({func, impl, fnty});
+ return true;
+ }
+
+ TraitReference *trait_ref
+ = TraitResolver::Resolve (*impl->get_trait_ref ().get ());
+ rust_assert (!trait_ref->is_error ());
+
+ auto item_ref
+ = trait_ref->lookup_trait_item (segment_name.as_string (),
+ TraitItemReference::TraitItemType::FN);
+ if (item_ref->is_error ())
+ return true;
+
+ const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
+ HIR::TraitItem *item = item_ref->get_hir_trait_item ();
+ rust_assert (item->get_item_kind () == HIR::TraitItem::TraitItemKind::FUNC);
+ HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
+
+ TyTy::BaseType *ty = item_ref->get_tyty ();
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref};
+ trait_fns.push_back (candidate);
+
+ return true;
+ });
+
+ // lookup specified bounds for an associated item
+ struct precdicate_candidate
+ {
+ TyTy::TypeBoundPredicateItem lookup;
+ TyTy::FnType *fntype;
+ };
+
+ std::vector<precdicate_candidate> predicate_items;
+ for (auto &bound : specified_bounds)
+ {
+ TyTy::TypeBoundPredicateItem lookup
+ = bound.lookup_associated_item (segment_name.as_string ());
+ if (lookup.is_error ())
+ continue;
+
+ bool is_fn = lookup.get_raw_item ()->get_trait_item_type ()
+ == TraitItemReference::TraitItemType::FN;
+ if (!is_fn)
+ continue;
+
+ TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty ();
+ rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
+
+ precdicate_candidate candidate{lookup, fnty};
+ predicate_items.push_back (candidate);
+ }
+
+ for (auto impl_item : inherent_impl_fns)
+ {
+ TyTy::FnType *fn = impl_item.ty;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ PathProbeCandidate::ImplItemCandidate c{impl_item.item,
+ impl_item.impl_block};
+ return PathProbeCandidate (
+ PathProbeCandidate::CandidateType::IMPL_FUNC, fn,
+ impl_item.item->get_locus (), c);
+ }
+ }
+
+ for (auto trait_item : trait_fns)
+ {
+ TyTy::FnType *fn = trait_item.ty;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
+ trait_item.item_ref,
+ nullptr};
+ return PathProbeCandidate (
+ PathProbeCandidate::CandidateType::TRAIT_FUNC, fn,
+ trait_item.item->get_locus (), c);
+ }
+ }
+
+ for (auto predicate : predicate_items)
+ {
+ TyTy::FnType *fn = predicate.fntype;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (fn_self->can_eq (&receiver, false))
+ {
+ const TraitReference *trait_ref
+ = predicate.lookup.get_parent ()->get ();
+ const TraitItemReference *trait_item
+ = predicate.lookup.get_raw_item ();
+
+ TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver (
+ receiver.get_root (),
+ predicate.lookup.get_parent ()->get_generic_args ());
+
+ PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
+ nullptr};
+ return PathProbeCandidate (
+ PathProbeCandidate::CandidateType::TRAIT_FUNC, subst,
+ trait_item->get_locus (), c);
+ }
+ }
+
+ return PathProbeCandidate::get_error ();
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index f48211b..f14300a 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -20,7 +20,6 @@
#define RUST_HIR_DOT_OPERATOR
#include "rust-hir-path-probe.h"
-#include "rust-hir-trait-resolve.h"
namespace Rust {
namespace Resolver {
@@ -46,273 +45,14 @@ protected:
public:
static MethodCandidate Probe (const TyTy::BaseType *receiver,
const HIR::PathIdentSegment &segment_name,
- bool autoderef_flag = false)
- {
- const TyTy::BaseType *r = receiver;
- std::vector<Adjustment> adjustments;
- while (true)
- {
- PathProbeCandidate c = PathProbeCandidate::get_error ();
- const std::vector<TyTy::TypeBoundPredicate> &specified_bounds
- = r->get_specified_bounds ();
-
- // 1. try raw
- MethodResolver raw (*r, segment_name, specified_bounds);
- c = raw.select ();
- if (!c.is_error ())
- return MethodCandidate{c, adjustments};
-
- // 2. try ref
- TyTy::ReferenceType *r1
- = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
- Mutability::Imm);
- MethodResolver imm_ref (*r1, segment_name, specified_bounds);
- c = imm_ref.select ();
- if (!c.is_error ())
- {
- adjustments.push_back (
- Adjustment (Adjustment::AdjustmentType::IMM_REF, r1));
- return MethodCandidate{c, adjustments};
- }
-
- // 3. try mut ref
- TyTy::ReferenceType *r2
- = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
- Mutability::Mut);
- MethodResolver mut_ref (*r2, segment_name, specified_bounds);
- c = mut_ref.select ();
- if (!c.is_error ())
- {
- adjustments.push_back (
- Adjustment (Adjustment::AdjustmentType::MUT_REF, r2));
- return MethodCandidate{c, adjustments};
- }
-
- // 4. deref to to 1, if cannot deref then quit
- if (autoderef_flag)
- {
- return MethodCandidate::get_error ();
- }
- else
- {
- Adjustment deref = Adjuster::try_deref_type (r);
- if (deref.is_error ())
- return MethodCandidate::get_error ();
-
- r = deref.get_expected ();
- adjustments.push_back (deref);
- }
- }
- return MethodCandidate::get_error ();
- }
+ bool autoderef_flag = false);
protected:
- PathProbeCandidate select ()
- {
- struct impl_item_candidate
- {
- HIR::Function *item;
- HIR::ImplBlock *impl_block;
- TyTy::FnType *ty;
- };
-
- // assemble inherent impl items
- std::vector<impl_item_candidate> inherent_impl_fns;
- mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item,
- HIR::ImplBlock *impl) mutable -> bool {
- bool is_trait_impl = impl->has_trait_ref ();
- if (is_trait_impl)
- return true;
-
- bool is_fn
- = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
- if (!is_fn)
- return true;
-
- HIR::Function *func = static_cast<HIR::Function *> (item);
- if (!func->is_method ())
- return true;
-
- bool name_matches
- = func->get_function_name ().compare (segment_name.as_string ()) == 0;
- if (!name_matches)
- return true;
-
- TyTy::BaseType *ty = nullptr;
- if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
- return true;
- if (ty->get_kind () == TyTy::TypeKind::ERROR)
- return true;
-
- rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
-
- inherent_impl_fns.push_back ({func, impl, fnty});
-
- return true;
- });
-
- struct trait_item_candidate
- {
- const HIR::TraitItemFunc *item;
- const HIR::Trait *trait;
- TyTy::FnType *ty;
- const TraitReference *reference;
- const TraitItemReference *item_ref;
- };
-
- std::vector<trait_item_candidate> trait_fns;
- mappings->iterate_impl_blocks ([&] (HirId id,
- HIR::ImplBlock *impl) mutable -> bool {
- bool is_trait_impl = impl->has_trait_ref ();
- if (!is_trait_impl)
- return true;
-
- // look for impl implementation else lookup the associated trait item
- for (auto &impl_item : impl->get_impl_items ())
- {
- bool is_fn = impl_item->get_impl_item_type ()
- == HIR::ImplItem::ImplItemType::FUNCTION;
- if (!is_fn)
- continue;
-
- HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
- if (!func->is_method ())
- continue;
-
- bool name_matches
- = func->get_function_name ().compare (segment_name.as_string ())
- == 0;
- if (!name_matches)
- continue;
-
- TyTy::BaseType *ty = nullptr;
- if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty))
- continue;
- if (ty->get_kind () == TyTy::TypeKind::ERROR)
- continue;
+ static MethodCandidate Try (const TyTy::BaseType *r,
+ const HIR::PathIdentSegment &segment_name,
+ std::vector<Adjustment> &adjustments);
- rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
-
- inherent_impl_fns.push_back ({func, impl, fnty});
- return true;
- }
-
- TraitReference *trait_ref
- = TraitResolver::Resolve (*impl->get_trait_ref ().get ());
- rust_assert (!trait_ref->is_error ());
-
- auto item_ref
- = trait_ref->lookup_trait_item (segment_name.as_string (),
- TraitItemReference::TraitItemType::FN);
- if (item_ref->is_error ())
- return true;
-
- const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
- HIR::TraitItem *item = item_ref->get_hir_trait_item ();
- rust_assert (item->get_item_kind ()
- == HIR::TraitItem::TraitItemKind::FUNC);
- HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
-
- TyTy::BaseType *ty = item_ref->get_tyty ();
- rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
-
- trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref};
- trait_fns.push_back (candidate);
-
- return true;
- });
-
- // lookup specified bounds for an associated item
- struct precdicate_candidate
- {
- TyTy::TypeBoundPredicateItem lookup;
- TyTy::FnType *fntype;
- };
-
- std::vector<precdicate_candidate> predicate_items;
- for (auto &bound : specified_bounds)
- {
- TyTy::TypeBoundPredicateItem lookup
- = bound.lookup_associated_item (segment_name.as_string ());
- if (lookup.is_error ())
- continue;
-
- bool is_fn = lookup.get_raw_item ()->get_trait_item_type ()
- == TraitItemReference::TraitItemType::FN;
- if (!is_fn)
- continue;
-
- TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty ();
- rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF);
- TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
-
- precdicate_candidate candidate{lookup, fnty};
- predicate_items.push_back (candidate);
- }
-
- for (auto impl_item : inherent_impl_fns)
- {
- TyTy::FnType *fn = impl_item.ty;
- rust_assert (fn->is_method ());
-
- TyTy::BaseType *fn_self = fn->get_self_type ();
- if (fn_self->can_eq (&receiver, false))
- {
- PathProbeCandidate::ImplItemCandidate c{impl_item.item,
- impl_item.impl_block};
- return PathProbeCandidate (
- PathProbeCandidate::CandidateType::IMPL_FUNC, fn,
- impl_item.item->get_locus (), c);
- }
- }
-
- for (auto trait_item : trait_fns)
- {
- TyTy::FnType *fn = trait_item.ty;
- rust_assert (fn->is_method ());
-
- TyTy::BaseType *fn_self = fn->get_self_type ();
- if (fn_self->can_eq (&receiver, false))
- {
- PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
- trait_item.item_ref,
- nullptr};
- return PathProbeCandidate (
- PathProbeCandidate::CandidateType::TRAIT_FUNC, fn,
- trait_item.item->get_locus (), c);
- }
- }
-
- for (auto predicate : predicate_items)
- {
- TyTy::FnType *fn = predicate.fntype;
- rust_assert (fn->is_method ());
-
- TyTy::BaseType *fn_self = fn->get_self_type ();
- if (fn_self->can_eq (&receiver, false))
- {
- const TraitReference *trait_ref
- = predicate.lookup.get_parent ()->get ();
- const TraitItemReference *trait_item
- = predicate.lookup.get_raw_item ();
-
- TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver (
- receiver.get_root (),
- predicate.lookup.get_parent ()->get_generic_args ());
-
- PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
- nullptr};
- return PathProbeCandidate (
- PathProbeCandidate::CandidateType::TRAIT_FUNC, subst,
- trait_item->get_locus (), c);
- }
- }
-
- return PathProbeCandidate::get_error ();
- }
+ PathProbeCandidate select ();
MethodResolver (const TyTy::BaseType &receiver,
const HIR::PathIdentSegment &segment_name,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 2cb4461..a4b8f0a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -258,6 +258,7 @@ public:
// Get the adjusted self
Adjuster adj (receiver_tyty);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
+ adjusted_self->debug ();
// store the adjustments for code-generation to know what to do
context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
diff --git a/gcc/testsuite/rust/execute/torture/method3.rs b/gcc/testsuite/rust/execute/torture/method3.rs
new file mode 100644
index 0000000..0e9e8ff
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/method3.rs
@@ -0,0 +1,78 @@
+// { dg-additional-options "-w" }
+// { dg-output "mut_deref\nfoobar: 123\n" }
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+ type Target;
+
+ fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "deref_mut"]
+pub trait DerefMut: Deref {
+ fn deref_mut(&mut self) -> &mut Self::Target;
+}
+
+impl<T> Deref for &T {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ *self
+ }
+}
+
+impl<T> Deref for &mut T {
+ type Target = T;
+ fn deref(&self) -> &T {
+ *self
+ }
+}
+
+pub struct Bar(i32);
+impl Bar {
+ pub fn foobar(&mut self) -> i32 {
+ self.0
+ }
+}
+
+pub struct Foo<T>(T);
+impl<T> Deref for Foo<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for Foo<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe {
+ let a = "mut_deref\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c);
+ }
+
+ &mut self.0
+ }
+}
+
+pub fn main() -> i32 {
+ let bar = Bar(123);
+ let mut foo: Foo<Bar> = Foo(bar);
+ let foobar = foo.foobar();
+
+ unsafe {
+ let a = "foobar: %i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, foobar);
+ }
+
+ foobar - 123
+}
diff --git a/gcc/testsuite/rust/execute/torture/method4.rs b/gcc/testsuite/rust/execute/torture/method4.rs
new file mode 100644
index 0000000..5c6fdfe
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/method4.rs
@@ -0,0 +1,78 @@
+// { dg-additional-options "-w" }
+// { dg-output "mut_deref\nfoobar: 123\n" }
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+ type Target;
+
+ fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "deref_mut"]
+pub trait DerefMut: Deref {
+ fn deref_mut(&mut self) -> &mut Self::Target;
+}
+
+impl<T> Deref for &T {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ *self
+ }
+}
+
+impl<T> Deref for &mut T {
+ type Target = T;
+ fn deref(&self) -> &T {
+ *self
+ }
+}
+
+pub struct Bar(i32);
+impl Bar {
+ pub fn foobar(&mut self) -> i32 {
+ self.0
+ }
+}
+
+pub struct Foo<T>(T);
+impl<T> Deref for Foo<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for Foo<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe {
+ let a = "mut_deref\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c);
+ }
+
+ &mut self.0
+ }
+}
+
+pub fn main() -> i32 {
+ let mut bar = Bar(123);
+ let mut foo: Foo<&mut Bar> = Foo(&mut bar);
+ let foobar = foo.foobar();
+
+ unsafe {
+ let a = "foobar: %i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, foobar);
+ }
+
+ foobar - 123
+}