]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Support for Sized builtin marker trait
authorPhilip Herron <herron.philip@googlemail.com>
Mon, 13 Feb 2023 17:51:19 +0000 (17:51 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 6 Apr 2023 08:47:23 +0000 (10:47 +0200)
When implementing general bounds checking as part of unify calls, we did
not check associated types on bounds which lead to alot of missed error
checking. This now recursively checks the bounds and the associated types
with a decent error message. This also required us to implement the Sized
marker trait to keep existing test-cases happy.

Fixes #1725

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/ChangeLog:

* typecheck/rust-hir-trait-reference.cc (TraitReference::clear_associated_types): make const
(TraitReference::clear_associated_type_projections): new interface
* typecheck/rust-hir-trait-reference.h:
* typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): refactor
(TraitItemReference::associated_type_reset): reset projections
* typecheck/rust-hir-type-bounds.h:
* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): fix bounds
* typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::TypeBoundsProbe): refactor into cc file
(TypeBoundsProbe::Probe): refactor
(TypeBoundsProbe::is_bound_satisfied_for_type): likewise
(TypeBoundsProbe::assemble_sized_builtin): add builtin for Sized
(TypeCheckBase::get_predicate_from_bound): refactor
(TypeBoundPredicate::lookup_associated_type): refactor
* typecheck/rust-tyty-subst.cc (SubstitutionRef::lookup_associated_impl)
(SubstitutionRef::prepare_higher_ranked_bounds): new interface to clear hanging bounds
(SubstitutionRef::monomorphize): refactor
* typecheck/rust-tyty-subst.h:
* typecheck/rust-tyty.cc (BaseType::get_locus): helper
(BaseType::satisfies_bound): ensure bounds are satisfied and assoicated types
(ParamType::ParamType): new field in constructor
(ParamType::clone): update clone
(ParamType::set_implicit_self_trait): new interface
(ParamType::is_implicit_self_trait): likewise
* typecheck/rust-tyty.h: cleanup
* util/rust-hir-map.cc (Mappings::Mappings): builtin marker
(Mappings::~Mappings): delete marker
(Mappings::lookup_builtin_marker): lookup
* util/rust-hir-map.h: update header

gcc/testsuite/ChangeLog:

* rust/compile/issue-1725-1.rs: New test.
* rust/compile/issue-1725-2.rs: New test.

14 files changed:
gcc/rust/typecheck/rust-hir-trait-reference.cc
gcc/rust/typecheck/rust-hir-trait-reference.h
gcc/rust/typecheck/rust-hir-trait-resolve.cc
gcc/rust/typecheck/rust-hir-type-bounds.h
gcc/rust/typecheck/rust-hir-type-check-expr.cc
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.cc
gcc/rust/typecheck/rust-tyty.h
gcc/rust/util/rust-hir-map.cc
gcc/rust/util/rust-hir-map.h
gcc/testsuite/rust/compile/issue-1725-1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-1725-2.rs [new file with mode: 0644]

index 8574988fb0bf29d4103da9e1c501e6145a5c05a4..a1229adc06c5ff361db576be6c92a1d9d4c8d98f 100644 (file)
@@ -343,14 +343,26 @@ TraitReference::on_resolved ()
 }
 
 void
-TraitReference::clear_associated_types ()
+TraitReference::clear_associated_types () const
 {
-  for (auto &item : item_refs)
+  for (const auto &item : item_refs)
+    {
+      bool is_assoc_type = item.get_trait_item_type ()
+                          == TraitItemReference::TraitItemType::TYPE;
+      if (is_assoc_type)
+       item.associated_type_reset (false);
+    }
+}
+
+void
+TraitReference::clear_associated_type_projections () const
+{
+  for (const auto &item : item_refs)
     {
       bool is_assoc_type = item.get_trait_item_type ()
                           == TraitItemReference::TraitItemType::TYPE;
       if (is_assoc_type)
-       item.associated_type_reset ();
+       item.associated_type_reset (true);
     }
 }
 
index f3703efcced0551b0980e2c5efb1a66456fcd77f..d20b2952e5b2b67ff1b7db127a364a62c0bae91f 100644 (file)
@@ -106,7 +106,7 @@ public:
 
   void associated_type_set (TyTy::BaseType *ty) const;
 
-  void associated_type_reset () const;
+  void associated_type_reset (bool only_projections) const;
 
   bool is_object_safe () const;
 
@@ -212,7 +212,9 @@ public:
 
   void on_resolved ();
 
-  void clear_associated_types ();
+  void clear_associated_types () const;
+
+  void clear_associated_type_projections () const;
 
   bool is_equal (const TraitReference &other) const;
 
index 6e23093eceb1d45773e72765940147d6d292c733..2d7985703cfb5206d4f50d159f09314b4c94a300 100644 (file)
@@ -161,6 +161,9 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
   TraitQueryGuard guard (trait_id);
   TyTy::BaseType *self = nullptr;
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
+
+  // FIXME
+  // this should use the resolve_generic_params like everywhere else
   for (auto &generic_param : trait_reference->get_generic_params ())
     {
       switch (generic_param.get ()->get_kind ())
@@ -182,7 +185,11 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference)
 
            if (typaram.get_type_representation ().compare ("Self") == 0)
              {
-               self = param_type;
+               rust_assert (param_type->get_kind () == TyTy::TypeKind::PARAM);
+               TyTy::ParamType *p
+                 = static_cast<TyTy::ParamType *> (param_type);
+               p->set_implicit_self_trait ();
+               self = p;
              }
          }
          break;
@@ -365,7 +372,7 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
 }
 
 void
-TraitItemReference::associated_type_reset () const
+TraitItemReference::associated_type_reset (bool only_projections) const
 {
   rust_assert (get_trait_item_type () == TraitItemType::TYPE);
 
@@ -374,7 +381,21 @@ TraitItemReference::associated_type_reset () const
   TyTy::PlaceholderType *placeholder
     = static_cast<TyTy::PlaceholderType *> (item_ty);
 
-  placeholder->clear_associated_type ();
+  if (!only_projections)
+    {
+      placeholder->clear_associated_type ();
+    }
+  else
+    {
+      if (!placeholder->can_resolve ())
+       return;
+
+      const TyTy::BaseType *r = placeholder->resolve ();
+      if (r->get_kind () == TyTy::TypeKind::PROJECTION)
+       {
+         placeholder->clear_associated_type ();
+       }
+    }
 }
 
 TyTy::BaseType *
index 4e8c58344de9b5da1a53b59cfc33aa6dc38584d5..628bba5da20b14ca2f09c5c5299cb410f3e39a3c 100644 (file)
@@ -30,42 +30,18 @@ class TypeBoundsProbe : public TypeCheckBase
 {
 public:
   static std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
-  Probe (const TyTy::BaseType *receiver)
-  {
-    TypeBoundsProbe probe (receiver);
-    probe.scan ();
-    return probe.trait_references;
-  }
+  Probe (const TyTy::BaseType *receiver);
 
   static bool is_bound_satisfied_for_type (TyTy::BaseType *receiver,
-                                          TraitReference *ref)
-  {
-    for (auto &bound : receiver->get_specified_bounds ())
-      {
-       const TraitReference *b = bound.get ();
-       if (b->is_equal (*ref))
-         return true;
-      }
-
-    std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
-      = Probe (receiver);
-    for (auto &bound : bounds)
-      {
-       const TraitReference *b = bound.first;
-       if (b->is_equal (*ref))
-         return true;
-      }
-
-    return false;
-  }
+                                          TraitReference *ref);
 
 private:
   void scan ();
+  void assemble_sized_builtin ();
+  void assemble_builtin_candidate (Analysis::RustLangItem::ItemType item);
 
 private:
-  TypeBoundsProbe (const TyTy::BaseType *receiver)
-    : TypeCheckBase (), receiver (receiver)
-  {}
+  TypeBoundsProbe (const TyTy::BaseType *receiver);
 
   const TyTy::BaseType *receiver;
   std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> trait_references;
index 46a14eb6e92f00a68b87efdfe3e8097325c7a6de..d4eea7ae954e708d39dc0a045529cf2d594feb0c 100644 (file)
@@ -1095,6 +1095,7 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
       return;
     }
 
+  fn->prepare_higher_ranked_bounds ();
   auto root = receiver_tyty->get_root ();
   if (root->get_kind () == TyTy::TypeKind::ADT)
     {
@@ -1659,6 +1660,11 @@ TypeCheckExpr::resolve_operator_overload (
   TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
   rust_assert (fn->is_method ());
 
+  fn->prepare_higher_ranked_bounds ();
+  rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
+                 candidate.candidate.ty->get_ref (),
+                 candidate.candidate.ty->debug_str ().c_str ());
+
   auto root = lhs->get_root ();
   if (root->get_kind () == TyTy::TypeKind::ADT)
     {
index b14e0c68e5ab0e2c787b3995b72ff42d70cdd079..76d2eeff8ef5f9c70dd7b2f1a50bf7a7d526812b 100644 (file)
 namespace Rust {
 namespace Resolver {
 
+TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver)
+  : TypeCheckBase (), receiver (receiver)
+{}
+
+std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
+TypeBoundsProbe::Probe (const TyTy::BaseType *receiver)
+{
+  TypeBoundsProbe probe (receiver);
+  probe.scan ();
+  return probe.trait_references;
+}
+
+bool
+TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver,
+                                             TraitReference *ref)
+{
+  for (auto &bound : receiver->get_specified_bounds ())
+    {
+      const TraitReference *b = bound.get ();
+      if (b->is_equal (*ref))
+       return true;
+    }
+
+  std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
+    = Probe (receiver);
+  for (auto &bound : bounds)
+    {
+      const TraitReference *b = bound.first;
+      if (b->is_equal (*ref))
+       return true;
+    }
+
+  return false;
+}
+
 void
 TypeBoundsProbe::scan ()
 {
@@ -57,6 +92,75 @@ TypeBoundsProbe::scan ()
       if (!trait_ref->is_error ())
        trait_references.push_back ({trait_ref, path.second});
     }
+
+  // marker traits...
+  assemble_sized_builtin ();
+}
+
+void
+TypeBoundsProbe::assemble_sized_builtin ()
+{
+  const TyTy::BaseType *raw = receiver->destructure ();
+
+  // does this thing actually implement sized?
+  switch (raw->get_kind ())
+    {
+    case TyTy::ADT:
+    case TyTy::STR:
+    case TyTy::REF:
+    case TyTy::POINTER:
+    case TyTy::PARAM:
+    case TyTy::ARRAY:
+    case TyTy::SLICE:
+    case TyTy::FNDEF:
+    case TyTy::FNPTR:
+    case TyTy::TUPLE:
+    case TyTy::BOOL:
+    case TyTy::CHAR:
+    case TyTy::INT:
+    case TyTy::UINT:
+    case TyTy::FLOAT:
+    case TyTy::USIZE:
+    case TyTy::ISIZE:
+      assemble_builtin_candidate (Analysis::RustLangItem::SIZED);
+      break;
+
+      // not-sure about this.... FIXME
+    case TyTy::INFER:
+    case TyTy::NEVER:
+    case TyTy::PLACEHOLDER:
+    case TyTy::PROJECTION:
+    case TyTy::DYNAMIC:
+    case TyTy::CLOSURE:
+    case TyTy::ERROR:
+      break;
+    }
+}
+
+void
+TypeBoundsProbe::assemble_builtin_candidate (
+  Analysis::RustLangItem::ItemType lang_item)
+{
+  DefId id;
+  bool found_lang_item = mappings->lookup_lang_item (lang_item, &id);
+  if (!found_lang_item)
+    return;
+
+  HIR::Item *item = mappings->lookup_defid (id);
+  if (item == nullptr)
+    return;
+
+  rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
+  HIR::Trait *trait = static_cast<HIR::Trait *> (item);
+  const TyTy::BaseType *raw = receiver->destructure ();
+
+  // assemble the reference
+  TraitReference *trait_ref = TraitResolver::Resolve (*trait);
+  trait_references.push_back ({trait_ref, mappings->lookup_builtin_marker ()});
+
+  rust_debug ("Added builtin lang_item: %s for %s",
+             Analysis::RustLangItem::ToString (lang_item).c_str (),
+             raw->get_name ().c_str ());
 }
 
 TraitReference *
@@ -101,7 +205,8 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
          = static_cast<HIR::TypePathSegmentFunction *> (final_seg.get ());
        auto &fn = final_function_seg->get_function_path ();
 
-       // we need to make implicit generic args which must be an implicit Tuple
+       // we need to make implicit generic args which must be an implicit
+       // Tuple
        auto crate_num = mappings->get_current_crate ();
        HirId implicit_args_id = mappings->get_next_hir_id ();
        Analysis::NodeMapping mapping (crate_num,
@@ -514,8 +619,8 @@ TypeBoundPredicate::lookup_associated_type (const std::string &search)
 {
   TypeBoundPredicateItem item = lookup_associated_item (search);
 
-  // only need to check that it is infact an associated type because other wise
-  // if it was not found it will just be an error node anyway
+  // only need to check that it is infact an associated type because other
+  // wise if it was not found it will just be an error node anyway
   if (!item.is_error ())
     {
       const auto raw = item.get_raw_item ();
index e4fe30e00ea78564900e674a2f3cfe7468eb83cf..d2f6cf607d1481ed4270c1ee25deca69fea50228 100644 (file)
@@ -119,11 +119,6 @@ SubstitutionParamMapping::fill_param_ty (
     {
       type.inherit_bounds (*param);
     }
-  else
-    {
-      if (!param->bounds_compatible (type, locus, true))
-       return false;
-    }
 
   if (type.get_kind () == TypeKind::PARAM)
     {
@@ -133,8 +128,15 @@ SubstitutionParamMapping::fill_param_ty (
   else
     {
       // check the substitution is compatible with bounds
-      if (!param->bounds_compatible (type, locus, true))
-       return false;
+      rust_debug_loc (locus,
+                     "fill_param_ty bounds_compatible: param %s type %s",
+                     param->get_name ().c_str (), type.get_name ().c_str ());
+
+      if (!param->is_implicit_self_trait ())
+       {
+         if (!param->bounds_compatible (type, locus, true))
+           return false;
+       }
 
       // recursively pass this down to all HRTB's
       for (auto &bound : param->get_specified_bounds ())
@@ -870,10 +872,149 @@ SubstitutionRef::solve_missing_mappings_from_this (SubstitutionRef &ref,
   return SubstitutionArgumentMappings (resolved_mappings, {}, 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 ()
+{
+  for (const auto &subst : get_substs ())
+    {
+      const TyTy::ParamType *pty = subst.get_param_ty ();
+      for (const auto &bound : pty->get_specified_bounds ())
+       {
+         const auto ref = bound.get ();
+         ref->clear_associated_type_projections ();
+       }
+    }
+}
+
 bool
 SubstitutionRef::monomorphize ()
 {
-  auto context = Resolver::TypeCheckContext::get ();
   for (const auto &subst : get_substs ())
     {
       const TyTy::ParamType *pty = subst.get_param_ty ();
@@ -887,136 +1028,16 @@ SubstitutionRef::monomorphize ()
 
       for (const auto &bound : pty->get_specified_bounds ())
        {
-         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)
+         bool error_flag = false;
+         auto associated
+           = lookup_associated_impl (subst, bound, binding, &error_flag);
+         if (associated != nullptr)
            {
-             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);
-                   }
-               }
+             associated->setup_associated_types (binding, bound);
            }
 
-         if (!associated_impl_traits.empty ())
-           {
-             // 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 (associated_impl_traits.size () == 1)
-               {
-                 Resolver::AssociatedImplTrait *associate_impl_trait
-                   = associated_impl_traits.at (0);
-                 associate_impl_trait->setup_associated_types (binding, bound);
-               }
-             else
-               {
-                 // 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 (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 ());
-
-                     return false;
-                   }
-
-                 associate_impl_trait->setup_associated_types (binding, bound);
-               }
-           }
+         if (error_flag)
+           return false;
        }
     }
 
index fd5826102b34d9975d5c6e4923a651d9a87fd7d7..365fdb6c042ea22c2bc7dca17b3cdcd1c46425e4 100644 (file)
@@ -298,7 +298,13 @@ public:
   // TODO comment
   BaseType *infer_substitions (Location locus);
 
-  // TODO comment
+  // this clears any possible projections from higher ranked trait bounds which
+  // could be hanging around from a previous resolution
+  void prepare_higher_ranked_bounds ();
+
+  // FIXME
+  // this is bad name for this, i think it should be something like
+  // compute-higher-ranked-bounds
   bool monomorphize ();
 
   // TODO comment
@@ -308,6 +314,10 @@ 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 fe5aa2b059c0cdf9710c9b23228571242f0ad7f0..d0d36ac0a11d4847681955ad4f5171002ce72c1b 100644 (file)
@@ -31,6 +31,7 @@
 #include "rust-hir-type-bounds.h"
 #include "rust-hir-trait-resolve.h"
 #include "rust-tyty-cmp.h"
+#include "rust-type-util.h"
 
 #include "options.h"
 
@@ -266,6 +267,7 @@ BaseType::get_locus () const
   return ident.locus;
 }
 
+// FIXME this is missing locus
 bool
 BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
 {
@@ -277,12 +279,67 @@ BaseType::satisfies_bound (const TypeBoundPredicate &predicate) const
        return true;
     }
 
+  bool satisfied = false;
   auto probed = Resolver::TypeBoundsProbe::Probe (this);
   for (const auto &b : probed)
     {
       const Resolver::TraitReference *bound = b.first;
       if (bound->satisfies_bound (*query))
+       {
+         satisfied = true;
+         break;
+       }
+    }
+
+  if (!satisfied)
+    return false;
+
+  for (const auto &b : probed)
+    {
+      const Resolver::TraitReference *bound = b.first;
+      if (!bound->is_equal (*query))
+       continue;
+
+      // builtin ones have no impl-block this needs fixed and use a builtin node
+      // of somekind
+      if (b.second == nullptr)
        return true;
+
+      // need to check that associated types can match as well
+      const HIR::ImplBlock &impl = *(b.second);
+      for (const auto &item : impl.get_impl_items ())
+       {
+         TyTy::BaseType *impl_item_ty = nullptr;
+         Analysis::NodeMapping i = item->get_impl_mappings ();
+         bool query_ok = Resolver::query_type (i.get_hirid (), &impl_item_ty);
+         if (!query_ok)
+           return false;
+
+         std::string item_name = item->get_impl_item_name ();
+         TypeBoundPredicateItem lookup
+           = predicate.lookup_associated_item (item_name);
+         if (lookup.is_error ())
+           return false;
+
+         const auto *item_ref = lookup.get_raw_item ();
+         TyTy::BaseType *bound_ty = item_ref->get_tyty ();
+
+         // compare the types
+         if (!bound_ty->can_eq (impl_item_ty, false))
+           {
+             RichLocation r (mappings->lookup_location (get_ref ()));
+             r.add_range (predicate.get_locus ());
+             r.add_range (mappings->lookup_location (i.get_hirid ()));
+
+             rust_error_at (
+               r, "expected %<%s%> got %<%s%>",
+               bound_ty->destructure ()->get_name ().c_str (),
+               impl_item_ty->destructure ()->get_name ().c_str ());
+             return false;
+           }
+       }
+
+      return true;
     }
 
   return false;
@@ -2827,18 +2884,18 @@ ParamType::ParamType (std::string symbol, Location locus, HirId ref,
              {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
               locus},
              specified_bounds, refs),
-    symbol (symbol), param (param)
+    is_trait_self (false), symbol (symbol), param (param)
 {}
 
-ParamType::ParamType (std::string symbol, Location locus, HirId ref,
-                     HirId ty_ref, HIR::GenericParam &param,
+ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus,
+                     HirId ref, HirId ty_ref, HIR::GenericParam &param,
                      std::vector<TypeBoundPredicate> specified_bounds,
                      std::set<HirId> refs)
   : BaseType (ref, ty_ref, TypeKind::PARAM,
              {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol),
               locus},
              specified_bounds, refs),
-    symbol (symbol), param (param)
+    is_trait_self (is_trait_self), symbol (symbol), param (param)
 {}
 
 HIR::GenericParam &
@@ -2906,8 +2963,9 @@ ParamType::can_eq (const BaseType *other, bool emit_errors) const
 BaseType *
 ParamType::clone () const
 {
-  return new ParamType (get_symbol (), ident.locus, get_ref (), get_ty_ref (),
-                       param, get_specified_bounds (), get_combined_refs ());
+  return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (),
+                       get_ty_ref (), param, get_specified_bounds (),
+                       get_combined_refs ());
 }
 
 BaseType *
@@ -2997,6 +3055,18 @@ ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
   return p;
 }
 
+void
+ParamType::set_implicit_self_trait ()
+{
+  is_trait_self = true;
+}
+
+bool
+ParamType::is_implicit_self_trait () const
+{
+  return is_trait_self;
+}
+
 // StrType
 
 StrType::StrType (HirId ref, std::set<HirId> refs)
index d2cf5b07fc155d2db9904d6eee9d8fea20a26947..64b9379a1c07b95392ee708a5f2f1f8d26e4840b 100644 (file)
@@ -267,8 +267,8 @@ public:
             std::vector<TypeBoundPredicate> specified_bounds,
             std::set<HirId> refs = std::set<HirId> ());
 
-  ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref,
-            HIR::GenericParam &param,
+  ParamType (bool is_trait_self, std::string symbol, Location locus, HirId ref,
+            HirId ty_ref, HIR::GenericParam &param,
             std::vector<TypeBoundPredicate> specified_bounds,
             std::set<HirId> refs = std::set<HirId> ());
 
@@ -298,7 +298,11 @@ public:
 
   ParamType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
+  void set_implicit_self_trait ();
+  bool is_implicit_self_trait () const;
+
 private:
+  bool is_trait_self;
   std::string symbol;
   HIR::GenericParam &param;
 };
index 1fc32038d19a17c7bdf6013f0a6e16858bd802ab..a968704014432d1d0f30d12b1235a3b6abcc44af 100644 (file)
@@ -96,9 +96,16 @@ static const HirId kDefaultCrateNumBegin = 0;
 Mappings::Mappings ()
   : crateNumItr (kDefaultCrateNumBegin), currentCrateNum (UNKNOWN_CREATENUM),
     hirIdIter (kDefaultHirIdBegin), nodeIdIter (kDefaultNodeIdBegin)
-{}
+{
+  Analysis::NodeMapping node (0, 0, 0, 0);
+  builtinMarker
+    = new HIR::ImplBlock (node, {}, {}, nullptr, nullptr, HIR::WhereClause ({}),
+                         Positive,
+                         HIR::Visibility (HIR::Visibility::VisType::PUBLIC),
+                         {}, {}, Location ());
+}
 
-Mappings::~Mappings () {}
+Mappings::~Mappings () { delete builtinMarker; }
 
 Mappings *
 Mappings::get ()
@@ -1035,5 +1042,11 @@ Mappings::lookup_ast_item (NodeId id, AST::Item **result)
   return true;
 }
 
+HIR::ImplBlock *
+Mappings::lookup_builtin_marker ()
+{
+  return builtinMarker;
+}
+
 } // namespace Analysis
 } // namespace Rust
index 13cae717031a92e47df7bdc1edf71705deb6c65f..9d6affa27e03309cb6143b651170fb56238ad9ff 100644 (file)
@@ -296,6 +296,8 @@ public:
   void insert_ast_item (AST::Item *item);
   bool lookup_ast_item (NodeId id, AST::Item **result);
 
+  HIR::ImplBlock *lookup_builtin_marker ();
+
 private:
   Mappings ();
 
@@ -304,6 +306,7 @@ private:
   HirId hirIdIter;
   NodeId nodeIdIter;
   std::map<CrateNum, LocalDefId> localIdIter;
+  HIR::ImplBlock *builtinMarker;
 
   std::map<NodeId, CrateNum> crate_node_to_crate_num;
   std::map<CrateNum, AST::Crate *> ast_crate_mappings;
diff --git a/gcc/testsuite/rust/compile/issue-1725-1.rs b/gcc/testsuite/rust/compile/issue-1725-1.rs
new file mode 100644 (file)
index 0000000..1ace9fb
--- /dev/null
@@ -0,0 +1,19 @@
+mod core {
+    mod ops {
+        #[lang = "add"]
+        pub trait Add<Rhs = Self> {
+            type Output;
+
+            fn add(self, rhs: Rhs) -> Self::Output;
+        }
+    }
+}
+
+pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
+    a + a
+}
+
+pub fn main() {
+    foo(123f32);
+    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-1725-2.rs b/gcc/testsuite/rust/compile/issue-1725-2.rs
new file mode 100644 (file)
index 0000000..8bfd0bb
--- /dev/null
@@ -0,0 +1,28 @@
+mod core {
+    mod ops {
+        #[lang = "add"]
+        pub trait Add<Rhs = Self> {
+            type Output;
+
+            fn add(self, rhs: Rhs) -> Self::Output;
+        }
+    }
+}
+
+impl core::ops::Add for f32 {
+    type Output = f32;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        self + rhs
+    }
+}
+
+pub fn foo<T: core::ops::Add<Output = i32>>(a: T) -> i32 {
+    a + a
+}
+
+pub fn main() {
+    foo(123f32);
+    // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
+    // { dg-error "bounds not satisfied for f32 .Add. is not satisfied" "" { target *-*-* } .-2 }
+}