From 4b25fc15b925f87a20bb15fe5ffcfd33fca6fd32 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 13 Feb 2023 17:51:19 +0000 Subject: [PATCH] gccrs: Support for Sized builtin marker trait 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 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. --- gcc/rust/typecheck/rust-hir-trait-reference.cc | 18 +- gcc/rust/typecheck/rust-hir-trait-reference.h | 6 +- gcc/rust/typecheck/rust-hir-trait-resolve.cc | 27 ++- gcc/rust/typecheck/rust-hir-type-bounds.h | 34 +-- gcc/rust/typecheck/rust-hir-type-check-expr.cc | 6 + gcc/rust/typecheck/rust-tyty-bounds.cc | 111 +++++++++- gcc/rust/typecheck/rust-tyty-subst.cc | 291 +++++++++++++------------ gcc/rust/typecheck/rust-tyty-subst.h | 12 +- gcc/rust/typecheck/rust-tyty.cc | 82 ++++++- gcc/rust/typecheck/rust-tyty.h | 8 +- gcc/rust/util/rust-hir-map.cc | 17 +- gcc/rust/util/rust-hir-map.h | 3 + gcc/testsuite/rust/compile/issue-1725-1.rs | 19 ++ gcc/testsuite/rust/compile/issue-1725-2.rs | 28 +++ 14 files changed, 476 insertions(+), 186 deletions(-) create mode 100644 gcc/testsuite/rust/compile/issue-1725-1.rs create mode 100644 gcc/testsuite/rust/compile/issue-1725-2.rs diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc index 8574988..a1229ad 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.cc +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -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); } } diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h index f3703ef..d20b295 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.h +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -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; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 6e23093..2d79857 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -161,6 +161,9 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) TraitQueryGuard guard (trait_id); TyTy::BaseType *self = nullptr; std::vector 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 (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 (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 * diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index 4e8c583..628bba5 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -30,42 +30,18 @@ class TypeBoundsProbe : public TypeCheckBase { public: static std::vector> - 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> 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> trait_references; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 46a14eb..d4eea7a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -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 (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) { diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index b14e0c6..76d2eef 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -23,6 +23,41 @@ namespace Rust { namespace Resolver { +TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver) + : TypeCheckBase (), receiver (receiver) +{} + +std::vector> +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> 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 (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 (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 (); diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index e4fe30e..d2f6cf6 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -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 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 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 (binding)->get_infer_kind () + == TyTy::InferType::InferTypeKind::INTEGRAL; + bool is_float_infervar + = is_infer_var + && static_cast (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 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 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 (binding) - ->get_infer_kind () - == TyTy::InferType::InferTypeKind::INTEGRAL; - bool is_float_infervar - = is_infer_var - && static_cast (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; } } diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index fd58261..365fdb6 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -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 substitutions; SubstitutionArgumentMappings used_arguments; }; diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index fe5aa2b..d0d36ac 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -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 ¶m, +ParamType::ParamType (bool is_trait_self, std::string symbol, Location locus, + HirId ref, HirId ty_ref, HIR::GenericParam ¶m, std::vector specified_bounds, std::set 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 refs) diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index d2cf5b0..64b9379 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -267,8 +267,8 @@ public: std::vector specified_bounds, std::set refs = std::set ()); - ParamType (std::string symbol, Location locus, HirId ref, HirId ty_ref, - HIR::GenericParam ¶m, + ParamType (bool is_trait_self, std::string symbol, Location locus, HirId ref, + HirId ty_ref, HIR::GenericParam ¶m, std::vector specified_bounds, std::set refs = std::set ()); @@ -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 ¶m; }; diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 1fc3203..a968704 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -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 diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 13cae71..9d6affa 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -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 localIdIter; + HIR::ImplBlock *builtinMarker; std::map crate_node_to_crate_num; std::map 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 index 0000000..1ace9fb --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1725-1.rs @@ -0,0 +1,19 @@ +mod core { + mod ops { + #[lang = "add"] + pub trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; + } + } +} + +pub fn foo>(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 index 0000000..8bfd0bb --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1725-2.rs @@ -0,0 +1,28 @@ +mod core { + mod ops { + #[lang = "add"] + pub trait Add { + 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>(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 } +} -- 2.7.4