aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-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
+}