aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust
diff options
context:
space:
mode:
authorPhilip Herron <herron.philip@googlemail.com>2023-06-25 21:21:36 +0100
committerPhilip Herron <philip.herron@embecosm.com>2023-06-25 21:07:02 +0000
commit337ed0fd1ba488754335b824263cff297e26e3bd (patch)
tree192bf2909d4be2f4ff8edb68a095c59ec297dc02 /gcc/rust
parent04eb580efaad6d74a6d93b47fc551f93cf40577d (diff)
downloadgcc-337ed0fd1ba488754335b824263cff297e26e3bd.zip
gcc-337ed0fd1ba488754335b824263cff297e26e3bd.tar.gz
gcc-337ed0fd1ba488754335b824263cff297e26e3bd.tar.bz2
gccrs: Add method selection to operator overloading
When we do operator overloading we can get multiple candidates and we need to use the optional arguments to filter the candidates event further. In the bug we had: <integer> + <usize> Without the Add impl blocks for the primitive interger types we unify against the rhs to figure out that the lhs should be a usize but when we are using the impl blocks we need to use the rhs to ensure that its possible to coerce the rhs to the expected fntype parameter to filter the candidates. Fixes #2304 gcc/rust/ChangeLog: * typecheck/rust-autoderef.cc: use new selection filter * typecheck/rust-hir-dot-operator.cc (MethodResolver::Select): new slection Filter * typecheck/rust-hir-dot-operator.h: New select prototype * typecheck/rust-hir-type-check-expr.cc: call select * typecheck/rust-type-util.cc (try_coercion): new helper * typecheck/rust-type-util.h (try_coercion): helper prototype gcc/testsuite/ChangeLog: * rust/compile/issue-2304.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
Diffstat (limited to 'gcc/rust')
-rw-r--r--gcc/rust/typecheck/rust-autoderef.cc8
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.cc39
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.h4
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.cc12
-rw-r--r--gcc/rust/typecheck/rust-type-util.cc18
-rw-r--r--gcc/rust/typecheck/rust-type-util.h4
6 files changed, 79 insertions, 6 deletions
diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
index 7d91156..ae41663 100644
--- a/gcc/rust/typecheck/rust-autoderef.cc
+++ b/gcc/rust/typecheck/rust-autoderef.cc
@@ -170,18 +170,20 @@ resolve_operator_overload_fn (
}
}
- bool have_implementation_for_lang_item = resolved_candidates.size () > 0;
+ auto selected_candidates
+ = MethodResolver::Select (resolved_candidates, lhs, {});
+ bool have_implementation_for_lang_item = selected_candidates.size () > 0;
if (!have_implementation_for_lang_item)
return false;
- if (resolved_candidates.size () > 1)
+ if (selected_candidates.size () > 1)
{
// no need to error out as we are just trying to see if there is a fit
return false;
}
// Get the adjusted self
- MethodCandidate candidate = *resolved_candidates.begin ();
+ MethodCandidate candidate = *selected_candidates.begin ();
Adjuster adj (lhs);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc
index 3239029..775a4a4 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.cc
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc
@@ -41,6 +41,45 @@ MethodResolver::Probe (TyTy::BaseType *receiver,
return resolver.result;
}
+std::set<MethodCandidate>
+MethodResolver::Select (std::set<MethodCandidate> &candidates,
+ TyTy::BaseType *receiver,
+ std::vector<TyTy::BaseType *> arguments)
+{
+ std::set<MethodCandidate> selected;
+ for (auto &candidate : candidates)
+ {
+ TyTy::BaseType *candidate_type = candidate.candidate.ty;
+ rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType &fn = *static_cast<TyTy::FnType *> (candidate_type);
+
+ // match the number of arguments
+ if (fn.num_params () != (arguments.size () + 1))
+ continue;
+
+ // match the arguments
+ bool failed = false;
+ for (size_t i = 0; i < arguments.size (); i++)
+ {
+ TyTy::BaseType *arg = arguments.at (i);
+ TyTy::BaseType *param = fn.get_params ().at (i + 1).second;
+ TyTy::BaseType *coerced
+ = try_coercion (0, TyTy::TyWithLocation (param),
+ TyTy::TyWithLocation (arg), Location ());
+ if (coerced->get_kind () == TyTy::TypeKind::ERROR)
+ {
+ failed = true;
+ break;
+ }
+ }
+
+ if (!failed)
+ selected.insert (candidate);
+ }
+
+ return selected;
+}
+
void
MethodResolver::try_hook (const TyTy::BaseType &r)
{
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index db04ad8..5451c13 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -57,6 +57,10 @@ public:
Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name,
bool autoderef_flag = false);
+ static std::set<MethodCandidate>
+ Select (std::set<MethodCandidate> &candidates, TyTy::BaseType *receiver,
+ std::vector<TyTy::BaseType *> arguments);
+
static std::vector<predicate_candidate> get_predicate_items (
const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index bd30746..ccc5dfe 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -1619,11 +1619,17 @@ TypeCheckExpr::resolve_operator_overload (
}
}
- bool have_implementation_for_lang_item = resolved_candidates.size () > 0;
+ std::vector<TyTy::BaseType *> select_args = {};
+ if (rhs != nullptr)
+ select_args = {rhs};
+ auto selected_candidates
+ = MethodResolver::Select (resolved_candidates, lhs, select_args);
+
+ bool have_implementation_for_lang_item = selected_candidates.size () > 0;
if (!have_implementation_for_lang_item)
return false;
- if (resolved_candidates.size () > 1)
+ if (selected_candidates.size () > 1)
{
// mutliple candidates
RichLocation r (expr.get_locus ());
@@ -1637,7 +1643,7 @@ TypeCheckExpr::resolve_operator_overload (
}
// Get the adjusted self
- MethodCandidate candidate = *resolved_candidates.begin ();
+ MethodCandidate candidate = *selected_candidates.begin ();
Adjuster adj (lhs);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc
index 1c93c60..e9e2f7e 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -232,6 +232,24 @@ coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
}
TyTy::BaseType *
+try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
+ Location locus)
+{
+ TyTy::BaseType *expected = lhs.get_ty ();
+ TyTy::BaseType *expr = rhs.get_ty ();
+
+ rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
+ expected->debug_str ().c_str (), expr->debug_str ().c_str ());
+
+ auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
+ true /*allow-autodref*/);
+ if (result.is_error ())
+ return new TyTy::ErrorType (id);
+
+ return result.tyty;
+}
+
+TyTy::BaseType *
cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
Location cast_locus)
{
diff --git a/gcc/rust/typecheck/rust-type-util.h b/gcc/rust/typecheck/rust-type-util.h
index d6f1b8c..9d3a59b 100644
--- a/gcc/rust/typecheck/rust-type-util.h
+++ b/gcc/rust/typecheck/rust-type-util.h
@@ -46,6 +46,10 @@ coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
Location coercion_locus);
TyTy::BaseType *
+try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
+ Location coercion_locus);
+
+TyTy::BaseType *
cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
Location cast_locus);