public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-7693] gccrs: Add method selection to operator overloading
@ 2024-01-16 17:54 Arthur Cohen
  0 siblings, 0 replies; only message in thread
From: Arthur Cohen @ 2024-01-16 17:54 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:5cfff8be03aac6e7d95e6dd54c69b5bd0cf824d8

commit r14-7693-g5cfff8be03aac6e7d95e6dd54c69b5bd0cf824d8
Author: Philip Herron <herron.philip@googlemail.com>
Date:   Sun Jun 25 21:21:36 2023 +0100

    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>

Diff:
---
 gcc/rust/typecheck/rust-autoderef.cc           |  8 ++++--
 gcc/rust/typecheck/rust-hir-dot-operator.cc    | 39 ++++++++++++++++++++++++++
 gcc/rust/typecheck/rust-hir-dot-operator.h     |  4 +++
 gcc/rust/typecheck/rust-hir-type-check-expr.cc | 12 ++++++--
 gcc/rust/typecheck/rust-type-util.cc           | 18 ++++++++++++
 gcc/rust/typecheck/rust-type-util.h            |  4 +++
 gcc/testsuite/rust/compile/issue-2304.rs       | 23 +++++++++++++++
 7 files changed, 102 insertions(+), 6 deletions(-)

diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc
index 8f5f6242aa2..9450cfaa068 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 28bc0c0c9a5..af4b87ef2cc 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 aa31d7a118e..804b18fbff2 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 734c4b49a5f..8affe983ba8 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 8e8871cab4d..561509cda00 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -231,6 +231,24 @@ coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
   return coerced;
 }
 
+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 938f410296a..595388ef34f 100644
--- a/gcc/rust/typecheck/rust-type-util.h
+++ b/gcc/rust/typecheck/rust-type-util.h
@@ -45,6 +45,10 @@ TyTy::BaseType *
 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);
diff --git a/gcc/testsuite/rust/compile/issue-2304.rs b/gcc/testsuite/rust/compile/issue-2304.rs
new file mode 100644
index 00000000000..243cf100539
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2304.rs
@@ -0,0 +1,23 @@
+#[lang = "add"]
+pub trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+macro_rules! add_impl {
+    ($($t:ty)*) => ($(
+        impl Add for $t {
+            type Output = $t;
+
+            fn add(self, other: $t) -> $t { self + other }
+        }
+    )*)
+}
+
+add_impl! { usize u8 u16 u32 u64  /*isize i8 i16 i32 i64*/  f32 f64 }
+
+pub fn test() {
+    let x: usize = 123;
+    let mut i = 0;
+    let _bug = i + x;
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-01-16 17:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-16 17:54 [gcc r14-7693] gccrs: Add method selection to operator overloading Arthur Cohen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).