@@ -139,15 +139,23 @@ resolve_operator_overload_fn (
return false;
auto segment = HIR::PathIdentSegment (associated_item_name);
- auto candidate
+ auto candidates
= MethodResolver::Probe (ty, HIR::PathIdentSegment (associated_item_name),
true);
- bool have_implementation_for_lang_item = !candidate.is_error ();
+ bool have_implementation_for_lang_item = !candidates.empty ();
if (!have_implementation_for_lang_item)
return false;
+ // multiple candidates?
+ if (candidates.size () > 1)
+ {
+ // error out? probably not for this case
+ return false;
+ }
+
// Get the adjusted self
+ auto candidate = *candidates.begin ();
Adjuster adj (ty);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
@@ -25,18 +25,17 @@ namespace Resolver {
MethodResolver::MethodResolver (bool autoderef_flag,
const HIR::PathIdentSegment &segment_name)
- : AutoderefCycle (autoderef_flag), segment_name (segment_name),
- try_result (MethodCandidate::get_error ())
+ : AutoderefCycle (autoderef_flag), segment_name (segment_name), result ()
{}
-MethodCandidate
+std::set<MethodCandidate>
MethodResolver::Probe (const TyTy::BaseType *receiver,
const HIR::PathIdentSegment &segment_name,
bool autoderef_flag)
{
MethodResolver resolver (autoderef_flag, segment_name);
- bool ok = resolver.cycle (receiver);
- return ok ? resolver.try_result : MethodCandidate::get_error ();
+ resolver.cycle (receiver);
+ return resolver.result;
}
void
@@ -177,8 +176,18 @@ MethodResolver::select (const TyTy::BaseType &receiver)
(unsigned long) trait_fns.size (),
(unsigned long) predicate_items.size ());
- for (auto impl_item : inherent_impl_fns)
+ // see the follow for the proper fix to get rid of this we need to assemble
+ // candidates based on a match expression gathering the relevant impl blocks
+ // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694
+ TyTy::set_cmp_autoderef_mode ();
+
+ bool found_possible_candidate = false;
+ for (auto &impl_item : inherent_impl_fns)
{
+ bool is_trait_impl_block = impl_item.impl_block->has_trait_ref ();
+ if (is_trait_impl_block)
+ continue;
+
TyTy::FnType *fn = impl_item.ty;
rust_assert (fn->is_method ());
@@ -190,13 +199,50 @@ MethodResolver::select (const TyTy::BaseType &receiver)
{
PathProbeCandidate::ImplItemCandidate c{impl_item.item,
impl_item.impl_block};
- try_result = MethodCandidate{
+ auto try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
fn, impl_item.item->get_locus (), c),
adjustments};
- return true;
+ result.insert (std::move (try_result));
+ found_possible_candidate = true;
}
}
+ if (found_possible_candidate)
+ {
+ TyTy::reset_cmp_autoderef_mode ();
+ return true;
+ }
+
+ for (auto &impl_item : inherent_impl_fns)
+ {
+ bool is_trait_impl_block = impl_item.impl_block->has_trait_ref ();
+ if (!is_trait_impl_block)
+ continue;
+
+ TyTy::FnType *fn = impl_item.ty;
+ rust_assert (fn->is_method ());
+
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ rust_debug (
+ "dot-operator trait_impl_item fn_self={%s} can_eq receiver={%s}",
+ fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ());
+ if (fn_self->can_eq (&receiver, false))
+ {
+ PathProbeCandidate::ImplItemCandidate c{impl_item.item,
+ impl_item.impl_block};
+ auto try_result = MethodCandidate{
+ PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
+ fn, impl_item.item->get_locus (), c),
+ adjustments};
+ result.insert (std::move (try_result));
+ found_possible_candidate = true;
+ }
+ }
+ if (found_possible_candidate)
+ {
+ TyTy::reset_cmp_autoderef_mode ();
+ return true;
+ }
for (auto trait_item : trait_fns)
{
@@ -212,13 +258,19 @@ MethodResolver::select (const TyTy::BaseType &receiver)
PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
trait_item.item_ref,
nullptr};
- try_result = MethodCandidate{
+ auto try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
fn, trait_item.item->get_locus (), c),
adjustments};
- return true;
+ result.insert (std::move (try_result));
+ found_possible_candidate = true;
}
}
+ if (found_possible_candidate)
+ {
+ TyTy::reset_cmp_autoderef_mode ();
+ return true;
+ }
for (const auto &predicate : predicate_items)
{
@@ -238,15 +290,17 @@ MethodResolver::select (const TyTy::BaseType &receiver)
PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
nullptr};
- try_result = MethodCandidate{
+ auto try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
fn->clone (), trait_item->get_locus (), c),
adjustments};
- return true;
+ result.insert (std::move (try_result));
+ found_possible_candidate = true;
}
}
- return false;
+ TyTy::reset_cmp_autoderef_mode ();
+ return found_possible_candidate;
}
std::vector<MethodResolver::predicate_candidate>
@@ -35,6 +35,13 @@ struct MethodCandidate
}
bool is_error () const { return candidate.is_error (); }
+
+ DefId get_defid () const { return candidate.get_defid (); }
+
+ bool operator< (const MethodCandidate &c) const
+ {
+ return get_defid () < c.get_defid ();
+ }
};
class MethodResolver : private TypeCheckBase, protected AutoderefCycle
@@ -46,9 +53,10 @@ public:
TyTy::FnType *fntype;
};
- static MethodCandidate Probe (const TyTy::BaseType *receiver,
- const HIR::PathIdentSegment &segment_name,
- bool autoderef_flag = false);
+ static std::set<MethodCandidate>
+ Probe (const TyTy::BaseType *receiver,
+ const HIR::PathIdentSegment &segment_name,
+ bool autoderef_flag = false);
static std::vector<predicate_candidate> get_predicate_items (
const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
@@ -68,7 +76,7 @@ private:
std::vector<MethodResolver::predicate_candidate> predicate_items;
// mutable fields
- MethodCandidate try_result;
+ std::set<MethodCandidate> result;
};
} // namespace Resolver
@@ -93,8 +93,9 @@ public:
HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid ();
TyTy::BaseType *impl_type = nullptr;
- bool ok = context->lookup_type (impl_type_id, &impl_type);
- rust_assert (ok);
+ bool ok = query_type (impl_type_id, &impl_type);
+ if (!ok)
+ return;
std::string impl_item_name;
ok = ImplItemToName::resolve (impl_item, impl_item_name);
@@ -1015,10 +1015,10 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
- auto candidate
+ auto candidates
= MethodResolver::Probe (receiver_tyty,
expr.get_method_name ().get_segment ());
- if (candidate.is_error ())
+ if (candidates.empty ())
{
rust_error_at (
expr.get_method_name ().get_locus (),
@@ -1027,6 +1027,19 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
return;
}
+ if (candidates.size () > 1)
+ {
+ RichLocation r (expr.get_method_name ().get_locus ());
+ for (auto &c : candidates)
+ r.add_range (c.candidate.locus);
+
+ rust_error_at (
+ r, "multiple candidates found for method %<%s%>",
+ expr.get_method_name ().get_segment ().as_string ().c_str ());
+ return;
+ }
+
+ auto candidate = *candidates.begin ();
rust_debug_loc (expr.get_method_name ().get_locus (),
"resolved method to: {%u} {%s}",
candidate.candidate.ty->get_ref (),
@@ -1422,14 +1435,28 @@ TypeCheckExpr::resolve_operator_overload (
return false;
auto segment = HIR::PathIdentSegment (associated_item_name);
- auto candidate
+ auto candidates
= MethodResolver::Probe (lhs, HIR::PathIdentSegment (associated_item_name));
- bool have_implementation_for_lang_item = !candidate.is_error ();
+ bool have_implementation_for_lang_item = candidates.size () > 0;
if (!have_implementation_for_lang_item)
return false;
+ if (candidates.size () > 1)
+ {
+ // mutliple candidates
+ RichLocation r (expr.get_locus ());
+ for (auto &c : candidates)
+ r.add_range (c.candidate.locus);
+
+ rust_error_at (
+ r, "multiple candidates found for possible operator overload");
+
+ return false;
+ }
+
// Get the adjusted self
+ auto candidate = *candidates.begin ();
Adjuster adj (lhs);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
@@ -28,6 +28,10 @@
namespace Rust {
namespace TyTy {
+// we need to fix this properly by implementing the match for assembling
+// candidates
+extern bool autoderef_cmp_flag;
+
class BaseCmp : public TyConstVisitor
{
public:
@@ -1244,6 +1248,9 @@ public:
auto other_base_type = type.get_base ();
bool mutability_ok = base->is_mutable () ? type.is_mutable () : true;
+ if (autoderef_cmp_flag)
+ mutability_ok = base->mutability () == type.mutability ();
+
if (!mutability_ok)
{
BaseCmp::visit (type);
@@ -1289,9 +1296,10 @@ public:
auto base_type = base->get_base ();
auto other_base_type = type.get_base ();
- // rust is permissive about mutablity here you can always go from mutable to
- // immutable but not the otherway round
bool mutability_ok = base->is_mutable () ? type.is_mutable () : true;
+ if (autoderef_cmp_flag)
+ mutability_ok = base->mutability () == type.mutability ();
+
if (!mutability_ok)
{
BaseCmp::visit (type);
@@ -1370,7 +1378,7 @@ public:
void visit (const ArrayType &) override { ok = true; }
- void visit (const SliceType &) override { ok = true; }
+ void visit (const SliceType &) override { ok = !autoderef_cmp_flag; }
void visit (const BoolType &) override { ok = true; }
@@ -32,6 +32,19 @@
namespace Rust {
namespace TyTy {
+bool autoderef_cmp_flag = false;
+
+void
+set_cmp_autoderef_mode ()
+{
+ autoderef_cmp_flag = true;
+}
+void
+reset_cmp_autoderef_mode ()
+{
+ autoderef_cmp_flag = false;
+}
+
std::string
TypeKindFormat::to_string (TypeKind kind)
{
@@ -135,6 +135,11 @@ protected:
std::vector<TypeBoundPredicate> specified_bounds;
};
+extern void
+set_cmp_autoderef_mode ();
+extern void
+reset_cmp_autoderef_mode ();
+
class TyVisitor;
class TyConstVisitor;
class BaseType : public TypeBoundsMappings
@@ -3,13 +3,13 @@ struct Foo<A> {
}
impl Foo<isize> {
- fn bar(self) -> isize { // { dg-error "duplicate definitions with name bar" }
+ fn bar(self) -> isize {
self.a
}
}
impl Foo<char> {
- fn bar(self) -> char { // { dg-error "duplicate definitions with name bar" }
+ fn bar(self) -> char {
self.a
}
}
@@ -23,4 +23,6 @@ impl<T> Foo<T> {
fn main() {
let a = Foo { a: 123 };
a.bar();
+ // { dg-error "multiple candidates found for method .bar." "" { target *-*-* } .-1 }
+ // { dg-error "failed to type resolve expression" "" { target *-*-* } .-2 }
}
@@ -1,4 +1,4 @@
-/* { dg-output "imm_deref\n123\n" } */
+/* { dg-output "mut_deref\n123\n" } */
extern "C" {
fn printf(s: *const i8, ...);
}