public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Support deref_mut lang item during method resolution
@ 2022-06-08 12:05 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:05 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c0e5ca327ba69655de7eae9628b85ad5a615dd77

commit c0e5ca327ba69655de7eae9628b85ad5a615dd77
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Fri Feb 11 14:51:22 2022 +0000

    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

Diff:
---
 gcc/rust/Make-lang.in                         |   1 +
 gcc/rust/backend/rust-compile-base.h          |   3 +
 gcc/rust/backend/rust-compile-expr.cc         |  39 +--
 gcc/rust/typecheck/rust-autoderef.cc          |  69 ++---
 gcc/rust/typecheck/rust-autoderef.h           |  29 ++-
 gcc/rust/typecheck/rust-hir-dot-operator.cc   | 359 ++++++++++++++++++++++++++
 gcc/rust/typecheck/rust-hir-dot-operator.h    | 270 +------------------
 gcc/rust/typecheck/rust-hir-type-check-expr.h |   1 +
 gcc/testsuite/rust/execute/torture/method3.rs |  78 ++++++
 gcc/testsuite/rust/execute/torture/method4.rs |  78 ++++++
 10 files changed, 605 insertions(+), 322 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 4f762160a54..5d02f060d29 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 a52886c9676..54116daa37e 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 a592e352c00..65f159ef603 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 fd2f7d3a905..286225266a2 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 a6c9d088a89..f389aff62c0 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 00000000000..84bbc0c4e0a
--- /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 f48211bb4f2..f14300a4bfe 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 2cb4461886e..a4b8f0ac530 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 00000000000..0e9e8ff42a0
--- /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 00000000000..5c6fdfe02c3
--- /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
+}


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

only message in thread, other threads:[~2022-06-08 12:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:05 [gcc/devel/rust/master] Support deref_mut lang item during method resolution Thomas Schwinge

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).