From patchwork Wed Apr 5 14:03:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 67388 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C217539449C1 for ; Wed, 5 Apr 2023 14:22:27 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by sourceware.org (Postfix) with ESMTPS id EDCF03857008 for ; Wed, 5 Apr 2023 14:06:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EDCF03857008 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x329.google.com with SMTP id d11-20020a05600c3acb00b003ef6e6754c5so18372585wms.5 for ; Wed, 05 Apr 2023 07:06:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; t=1680703581; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=nd4LBzR7/WMT6jIjUOgFhfMAMTK0EPcYfwEIqXgyk0g=; b=euTDJBZD+y4mkoV3bavIkPqx3QqEh15iaPwGOLShKDQxZMExJ0pHsokyXF++s+cX5J gQvcHyGBgQshpIWkFeIGO8PXmJXGioWbw9plVdhJAog+qBHiDmWeWlX2Qe+/RAbFoI9v BB+V9P/xsBBiTF/vH8xSPwtKMT3hXlTuWvpnV2kJY46lXiAyC8n6B53kskJFC5C3shzW Dqd82iLH+2TZVhPVRDHdNCnnOo5UYS7kc1rZiXFGnPoJ/c5VaDCSJFqVRGf8+pqPJOao hctIPma5+bA0saRCeSOyMlfjPsfzjhPuMEomlifIQQUWhzTb3ihVrMOjxIXg4T0YkuWy N1sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680703581; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=nd4LBzR7/WMT6jIjUOgFhfMAMTK0EPcYfwEIqXgyk0g=; b=czwUBf8e0jJglncnzcnJKtUljqtc9PAs1tE8uJ5l4tQ8QFz8BcYmaYne8qmbjObk6J ND93hAZxadFfiaEFb9/uwRO4t/b76vAQgVL3r0ukJddg3ZGCmwfjfk9zQclHWASbRqIe pUzJ2Inv8WeXOTqzDiSNZvAXP+xELDbKxcBzY/qYWbjFUho0rFl66prVQgR56fPCs1Ix WlPgwoZuclTRiylm3ylOkCfUgg2YENTZb86KiYXmVRaLjmOkQ1PRKoGEQ0bo+yESGJrN SgdGODJDZ5EyMHzN6KSS7dDq0eaTJYsFIKh9XX3zdWNRr2siU69OcttyqGGnUCt5p8Vy iHIA== X-Gm-Message-State: AAQBX9fs/sQJRCVhyXRCimYJsuFINeT0pEuyBio8CezVJAhSkRSwhgpr 2iYLn2Rn4mlD7Uh2pB791IrH69ywMOENRDLI+w== X-Google-Smtp-Source: AKy350ZPvkFhRvFitIYgnRyCPexnmnUASKV77cbyjPkoorJxkWqQ1hMvOYmbcAdGSjWFCYpjuXHgEw== X-Received: by 2002:a05:600c:2216:b0:3e2:1dac:b071 with SMTP id z22-20020a05600c221600b003e21dacb071mr1909965wml.13.1680703581025; Wed, 05 Apr 2023 07:06:21 -0700 (PDT) Received: from platypus.localdomain ([62.23.166.218]) by smtp.gmail.com with ESMTPSA id ay8-20020a05600c1e0800b003edddae1068sm2330150wmb.9.2023.04.05.07.06.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 07:06:20 -0700 (PDT) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [committed 75/88] gccrs: Support for Sized builtin marker trait Date: Wed, 5 Apr 2023 16:03:59 +0200 Message-Id: <20230405140411.3016563-76-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230405140411.3016563-1-arthur.cohen@embecosm.com> References: <20230405140411.3016563-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-14.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron 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. --- .../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 +- .../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 8574988fb0b..a1229adc06c 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 f3703efcced..d20b2952e5b 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 6e23093eceb..2d7985703cf 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 4e8c58344de..628bba5da20 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 46a14eb6e92..d4eea7ae954 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 b14e0c68e5a..76d2eeff8ef 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 e4fe30e00ea..d2f6cf607d1 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 fd5826102b3..365fdb6c042 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 fe5aa2b059c..d0d36ac0a11 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 d2cf5b07fc1..64b9379a1c0 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 1fc32038d19..a9687040144 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 13cae717031..9d6affa27e0 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 00000000000..1ace9fbbf30 --- /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 00000000000..8bfd0bbd924 --- /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 } +}