]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Extract helper lookup_associated_impl_block
authorPhilip Herron <herron.philip@googlemail.com>
Thu, 20 Apr 2023 15:56:46 +0000 (16:56 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:34:15 +0000 (18:34 +0100)
This will look for a specified predicate that is associated with it so we
might have the predicate Foo<u16, i32> which would refer to:

  impl Foo<i32> for u16 {}

This is a general helper which can be used in several places.

gcc/rust/ChangeLog:

* typecheck/rust-hir-trait-reference.cc (AssociatedImplTrait::AssociatedImplTrait):
bind the predicate
(AssociatedImplTrait::get_trait): remove
(AssociatedImplTrait::get_predicate): new getter
* typecheck/rust-hir-trait-reference.h: bind predicate
* typecheck/rust-hir-type-check-item.cc: update ctor
* typecheck/rust-type-util.cc (lookup_associated_impl_block): new function
* typecheck/rust-type-util.h (class BaseType): remove unused forward decl
(lookup_associated_impl_block): new helper
* typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::is_equal): new
* typecheck/rust-tyty-subst.cc (SubstitutionRef::lookup_associated_impl): use new helper
(SubstitutionRef::monomorphize): update usage/error handling
* typecheck/rust-tyty-subst.h: remove old prototype
* typecheck/rust-tyty.h: add is_equal decl

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/typecheck/rust-hir-trait-reference.cc
gcc/rust/typecheck/rust-hir-trait-reference.h
gcc/rust/typecheck/rust-hir-type-check-item.cc
gcc/rust/typecheck/rust-type-util.cc
gcc/rust/typecheck/rust-type-util.h
gcc/rust/typecheck/rust-tyty-bounds.cc
gcc/rust/typecheck/rust-tyty-subst.cc
gcc/rust/typecheck/rust-tyty-subst.h
gcc/rust/typecheck/rust-tyty.h

index 36f426c2e40ec36acb7f16536c391f3520d6e227..499999429fdef2f8e831df270b67446dbec1979d 100644 (file)
@@ -442,16 +442,18 @@ TraitReference::satisfies_bound (const TraitReference &reference) const
 }
 
 AssociatedImplTrait::AssociatedImplTrait (TraitReference *trait,
+                                         TyTy::TypeBoundPredicate predicate,
                                          HIR::ImplBlock *impl,
                                          TyTy::BaseType *self,
                                          Resolver::TypeCheckContext *context)
-  : trait (trait), impl (impl), self (self), context (context)
+  : trait (trait), predicate (predicate), impl (impl), self (self),
+    context (context)
 {}
 
-TraitReference *
-AssociatedImplTrait::get_trait ()
+TyTy::TypeBoundPredicate &
+AssociatedImplTrait::get_predicate ()
 {
-  return trait;
+  return predicate;
 }
 
 HIR::ImplBlock *
@@ -465,6 +467,7 @@ AssociatedImplTrait::get_self ()
 {
   return self;
 }
+
 const TyTy::BaseType *
 AssociatedImplTrait::get_self () const
 {
index e9919f4f5337f014899e63b32a42e86b62b05758..8ccd29f0861d892254d3f462dce2dd95f068aca1 100644 (file)
@@ -238,11 +238,12 @@ private:
 class AssociatedImplTrait
 {
 public:
-  AssociatedImplTrait (TraitReference *trait, HIR::ImplBlock *impl,
+  AssociatedImplTrait (TraitReference *trait,
+                      TyTy::TypeBoundPredicate predicate, HIR::ImplBlock *impl,
                       TyTy::BaseType *self,
                       Resolver::TypeCheckContext *context);
 
-  TraitReference *get_trait ();
+  TyTy::TypeBoundPredicate &get_predicate ();
 
   HIR::ImplBlock *get_impl_block ();
 
@@ -257,6 +258,7 @@ public:
 
 private:
   TraitReference *trait;
+  TyTy::TypeBoundPredicate predicate;
   HIR::ImplBlock *impl;
   TyTy::BaseType *self;
   Resolver::TypeCheckContext *context;
index 5ffebe91a6c538c0fffa07a9b5042afb5e2714fb..6d6ab63e85f23fc7a23f8416bee8914d6435aaaf 100644 (file)
@@ -607,8 +607,8 @@ TypeCheckItem::validate_trait_impl_block (
     {
       trait_reference->clear_associated_types ();
 
-      AssociatedImplTrait associated (trait_reference, &impl_block, self,
-                                     context);
+      AssociatedImplTrait associated (trait_reference, specified_bound,
+                                     &impl_block, self, context);
       context->insert_associated_trait_impl (
        impl_block.get_mappings ().get_hirid (), std::move (associated));
       context->insert_associated_impl_mapping (
index e0c43c713c5ed175847643ded405114d539a5521..eea97ed4fef5a039288bcbd1cd52e864cee1dce1 100644 (file)
@@ -25,6 +25,7 @@
 #include "rust-casts.h"
 #include "rust-unify.h"
 #include "rust-coercion.h"
+#include "rust-hir-type-bounds.h"
 
 namespace Rust {
 namespace Resolver {
@@ -254,5 +255,112 @@ cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
   return casted;
 }
 
+AssociatedImplTrait *
+lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
+                             const TyTy::BaseType *binding, bool *ambigious)
+{
+  auto context = TypeCheckContext::get ();
+
+  // setup any associated type mappings for the specified bonds and this
+  // type
+  auto candidates = TypeBoundsProbe::Probe (binding);
+  std::vector<AssociatedImplTrait *> associated_impl_traits;
+  for (auto &probed_bound : candidates)
+    {
+      HIR::ImplBlock *associated_impl = probed_bound.second;
+
+      HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
+      AssociatedImplTrait *associated = nullptr;
+      bool found_impl_trait
+       = context->lookup_associated_trait_impl (impl_block_id, &associated);
+      if (found_impl_trait)
+       {
+         // compare the bounds from here i think is what we can do:
+         if (bound.is_equal (associated->get_predicate ()))
+           {
+             associated_impl_traits.push_back (associated);
+           }
+       }
+    }
+
+  if (associated_impl_traits.empty ())
+    return nullptr;
+
+  // This code is important when you look at slices for example when
+  // you have a slice such as:
+  //
+  // let slice = &array[1..3]
+  //
+  // the higher ranked bounds will end up having an Index trait
+  // implementation for Range<usize> so we need this code to resolve
+  // that we have an integer inference variable that needs to become
+  // a usize
+  //
+  // The other complicated issue is that we might have an intrinsic
+  // which requires the :Clone or Copy bound but the libcore adds
+  // implementations for all the integral types so when there are
+  // multiple candidates we need to resolve to the default
+  // implementation for that type otherwise its an error for
+  // ambiguous type bounds
+
+  // if we have a non-general inference variable we need to be
+  // careful about the selection here
+  bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
+  bool is_integer_infervar
+    = is_infer_var
+      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
+          == TyTy::InferType::InferTypeKind::INTEGRAL;
+  bool is_float_infervar
+    = is_infer_var
+      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
+          == TyTy::InferType::InferTypeKind::FLOAT;
+
+  AssociatedImplTrait *associate_impl_trait = nullptr;
+  if (associated_impl_traits.size () == 1)
+    {
+      // just go for it
+      associate_impl_trait = associated_impl_traits.at (0);
+    }
+  else if (is_integer_infervar)
+    {
+      TyTy::BaseType *type = nullptr;
+      bool ok = context->lookup_builtin ("i32", &type);
+      rust_assert (ok);
+
+      for (auto &impl : associated_impl_traits)
+       {
+         bool found = impl->get_self ()->is_equal (*type);
+         if (found)
+           {
+             associate_impl_trait = impl;
+             break;
+           }
+       }
+    }
+  else if (is_float_infervar)
+    {
+      TyTy::BaseType *type = nullptr;
+      bool ok = context->lookup_builtin ("f64", &type);
+      rust_assert (ok);
+
+      for (auto &impl : associated_impl_traits)
+       {
+         bool found = impl->get_self ()->is_equal (*type);
+         if (found)
+           {
+             associate_impl_trait = impl;
+             break;
+           }
+       }
+    }
+
+  if (associate_impl_trait == nullptr && ambigious != nullptr)
+    {
+      *ambigious = true;
+    }
+
+  return associate_impl_trait;
+}
+
 } // namespace Resolver
 } // namespace Rust
index d2523fc442085487ad9b4594c895e991544be070..85906d7d1850d402559074ec79370e5850e92e6f 100644 (file)
 #include "rust-tyty.h"
 
 namespace Rust {
-
-namespace TyTy {
-class BaseType;
-}
-
 namespace Resolver {
 
 bool
@@ -50,6 +45,11 @@ TyTy::BaseType *
 cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
           Location cast_locus);
 
+AssociatedImplTrait *
+lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
+                             const TyTy::BaseType *binding,
+                             bool *ambigious = nullptr);
+
 } // namespace Resolver
 } // namespace Rust
 
index dc4418ff27b7725fcd614aaaf661398e686eb2ab..947fd06e686181d3119854258db7533d322aca96 100644 (file)
@@ -680,6 +680,40 @@ TypeBoundPredicate::get_associated_type_items ()
   return items;
 }
 
+bool
+TypeBoundPredicate::is_equal (const TypeBoundPredicate &other) const
+{
+  // check they match the same trait reference
+  if (reference != other.reference)
+    return false;
+
+  // check that the generics match
+  if (get_num_substitutions () != other.get_num_substitutions ())
+    return false;
+
+  // then match the generics applied
+  for (size_t i = 0; i < get_num_substitutions (); i++)
+    {
+      const SubstitutionParamMapping &a = substitutions.at (i);
+      const SubstitutionParamMapping &b = other.substitutions.at (i);
+
+      const ParamType *ap = a.get_param_ty ();
+      const ParamType *bp = b.get_param_ty ();
+
+      const BaseType *apd = ap->destructure ();
+      const BaseType *bpd = bp->destructure ();
+
+      // FIXME use the unify_and infer inteface or try coerce
+      if (!apd->can_eq (bpd, false /*emit_errors*/))
+       {
+         if (!bpd->can_eq (apd, false /*emit_errors*/))
+           return false;
+       }
+    }
+
+  return true;
+}
+
 // trait item reference
 
 const Resolver::TraitItemReference *
index 9715b08ad04698c061cae632b2580541590a1426..9d8164cc6760e3f027448f5b493f0e82883df08c 100644 (file)
@@ -21,7 +21,7 @@
 #include "rust-hir-type-check.h"
 #include "rust-substitution-mapper.h"
 #include "rust-hir-type-check-type.h"
-#include "rust-hir-type-bounds.h"
+#include "rust-type-util.h"
 
 namespace Rust {
 namespace TyTy {
@@ -831,132 +831,6 @@ SubstitutionRef::solve_mappings_from_receiver_for_self (
                                       mappings.get_locus ());
 }
 
-Resolver::AssociatedImplTrait *
-SubstitutionRef::lookup_associated_impl (const SubstitutionParamMapping &subst,
-                                        const TypeBoundPredicate &bound,
-                                        const TyTy::BaseType *binding,
-                                        bool *error_flag) const
-{
-  auto context = Resolver::TypeCheckContext::get ();
-  const Resolver::TraitReference *specified_bound_ref = bound.get ();
-
-  // setup any associated type mappings for the specified bonds and this
-  // type
-  auto candidates = Resolver::TypeBoundsProbe::Probe (binding);
-  std::vector<Resolver::AssociatedImplTrait *> associated_impl_traits;
-  for (auto &probed_bound : candidates)
-    {
-      const Resolver::TraitReference *bound_trait_ref = probed_bound.first;
-      const HIR::ImplBlock *associated_impl = probed_bound.second;
-
-      HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
-      Resolver::AssociatedImplTrait *associated = nullptr;
-      bool found_impl_trait
-       = context->lookup_associated_trait_impl (impl_block_id, &associated);
-      if (found_impl_trait)
-       {
-         bool found_trait = specified_bound_ref->is_equal (*bound_trait_ref);
-         bool found_self = associated->get_self ()->can_eq (binding, false);
-         if (found_trait && found_self)
-           {
-             associated_impl_traits.push_back (associated);
-           }
-       }
-    }
-
-  if (associated_impl_traits.empty ())
-    return nullptr;
-
-  // This code is important when you look at slices for example when
-  // you have a slice such as:
-  //
-  // let slice = &array[1..3]
-  //
-  // the higher ranked bounds will end up having an Index trait
-  // implementation for Range<usize> so we need this code to resolve
-  // that we have an integer inference variable that needs to become
-  // a usize
-  //
-  // The other complicated issue is that we might have an intrinsic
-  // which requires the :Clone or Copy bound but the libcore adds
-  // implementations for all the integral types so when there are
-  // multiple candidates we need to resolve to the default
-  // implementation for that type otherwise its an error for
-  // ambiguous type bounds
-
-  // if we have a non-general inference variable we need to be
-  // careful about the selection here
-  bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
-  bool is_integer_infervar
-    = is_infer_var
-      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
-          == TyTy::InferType::InferTypeKind::INTEGRAL;
-  bool is_float_infervar
-    = is_infer_var
-      && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
-          == TyTy::InferType::InferTypeKind::FLOAT;
-
-  Resolver::AssociatedImplTrait *associate_impl_trait = nullptr;
-  if (associated_impl_traits.size () == 1)
-    {
-      // just go for it
-      associate_impl_trait = associated_impl_traits.at (0);
-    }
-  else if (is_integer_infervar)
-    {
-      TyTy::BaseType *type = nullptr;
-      bool ok = context->lookup_builtin ("i32", &type);
-      rust_assert (ok);
-
-      for (auto &impl : associated_impl_traits)
-       {
-         bool found = impl->get_self ()->is_equal (*type);
-         if (found)
-           {
-             associate_impl_trait = impl;
-             break;
-           }
-       }
-    }
-  else if (is_float_infervar)
-    {
-      TyTy::BaseType *type = nullptr;
-      bool ok = context->lookup_builtin ("f64", &type);
-      rust_assert (ok);
-
-      for (auto &impl : associated_impl_traits)
-       {
-         bool found = impl->get_self ()->is_equal (*type);
-         if (found)
-           {
-             associate_impl_trait = impl;
-             break;
-           }
-       }
-    }
-
-  if (associate_impl_trait == nullptr)
-    {
-      // go for the first one? or error out?
-      auto &mappings = *Analysis::Mappings::get ();
-      const auto &type_param = subst.get_generic_param ();
-      const auto *trait_ref = bound.get ();
-
-      RichLocation r (type_param.get_locus ());
-      r.add_range (bound.get_locus ());
-      r.add_range (mappings.lookup_location (binding->get_ref ()));
-
-      rust_error_at (r, "ambiguous type bound for trait %s and type %s",
-                    trait_ref->get_name ().c_str (),
-                    binding->get_name ().c_str ());
-
-      *error_flag = true;
-      return nullptr;
-    }
-
-  return associate_impl_trait;
-}
-
 void
 SubstitutionRef::prepare_higher_ranked_bounds ()
 {
@@ -987,16 +861,31 @@ SubstitutionRef::monomorphize ()
 
       for (const auto &bound : pty->get_specified_bounds ())
        {
-         bool error_flag = false;
+         bool ambigious = false;
          auto associated
-           = lookup_associated_impl (subst, bound, binding, &error_flag);
+           = Resolver::lookup_associated_impl_block (bound, binding,
+                                                     &ambigious);
+         if (associated == nullptr && ambigious)
+           {
+             // go for the first one? or error out?
+             auto &mappings = *Analysis::Mappings::get ();
+             const auto &type_param = subst.get_generic_param ();
+             const auto *trait_ref = bound.get ();
+
+             RichLocation r (type_param.get_locus ());
+             r.add_range (bound.get_locus ());
+             r.add_range (mappings.lookup_location (binding->get_ref ()));
+
+             rust_error_at (r, "ambiguous type bound for trait %s and type %s",
+                            trait_ref->get_name ().c_str (),
+                            binding->get_name ().c_str ());
+             return false;
+           }
+
          if (associated != nullptr)
            {
              associated->setup_associated_types (binding, bound);
            }
-
-         if (error_flag)
-           return false;
        }
     }
 
index 37423746f1313424319187928d9b4a50716ae36c..d6319e50c3f8b8665e1e06ec9ed8418bfbf0a2c4 100644 (file)
@@ -318,10 +318,6 @@ public:
   SubstitutionArgumentMappings get_used_arguments () const;
 
 protected:
-  Resolver::AssociatedImplTrait *lookup_associated_impl (
-    const SubstitutionParamMapping &subst, const TypeBoundPredicate &bound,
-    const TyTy::BaseType *binding, bool *error_flag) const;
-
   std::vector<SubstitutionParamMapping> substitutions;
   SubstitutionArgumentMappings used_arguments;
 };
index 65073da7118868c9073aa95f6e6056fcdaaaf578..cd6be349b38a9823cb614aa0231569d424bb248b 100644 (file)
@@ -438,6 +438,8 @@ public:
   TypeBoundPredicateItem
   lookup_associated_type (const std::string &search) override final;
 
+  bool is_equal (const TypeBoundPredicate &other) const;
+
 private:
   DefId reference;
   Location locus;