From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 24D5A3AAA063; Wed, 8 Jun 2022 12:05:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 24D5A3AAA063 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] Support deref_mut lang item during method resolution X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 9023bb8687347559702340c24cd72301f0656a59 X-Git-Newrev: c0e5ca327ba69655de7eae9628b85ad5a615dd77 Message-Id: <20220608120558.24D5A3AAA063@sourceware.org> Date: Wed, 8 Jun 2022 12:05:58 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 12:05:58 -0000 https://gcc.gnu.org/g:c0e5ca327ba69655de7eae9628b85ad5a615dd77 commit c0e5ca327ba69655de7eae9628b85ad5a615dd77 Author: Philip Herron Date: Fri Feb 11 14:51:22 2022 +0000 Support deref_mut lang item during method resolution When we have method resolution we need to look at any deref lang items for the receiver. The precise rules need to be tested rigorously to ensure this is right. Fixes #890 Diff: --- gcc/rust/Make-lang.in | 1 + gcc/rust/backend/rust-compile-base.h | 3 + gcc/rust/backend/rust-compile-expr.cc | 39 +-- gcc/rust/typecheck/rust-autoderef.cc | 69 ++--- gcc/rust/typecheck/rust-autoderef.h | 29 ++- gcc/rust/typecheck/rust-hir-dot-operator.cc | 359 ++++++++++++++++++++++++++ gcc/rust/typecheck/rust-hir-dot-operator.h | 270 +------------------ gcc/rust/typecheck/rust-hir-type-check-expr.h | 1 + gcc/testsuite/rust/execute/torture/method3.rs | 78 ++++++ gcc/testsuite/rust/execute/torture/method4.rs | 78 ++++++ 10 files changed, 605 insertions(+), 322 deletions(-) diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 4f762160a54..5d02f060d29 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -89,6 +89,7 @@ GRS_OBJS = \ rust/rust-hir-type-check-type.o \ rust/rust-hir-type-check-struct.o \ rust/rust-hir-type-check-pattern.o \ + rust/rust-hir-dot-operator.o \ rust/rust-autoderef.o \ rust/rust-substitution-mapper.o \ rust/rust-lint-marklive.o \ diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index a52886c9676..54116daa37e 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -67,6 +67,9 @@ protected: tree resolve_deref_adjustment (Resolver::Adjustment &adjustment, tree expression, Location locus); + tree resolve_indirection_adjustment (Resolver::Adjustment &adjustment, + tree expression, Location locus); + static void setup_attributes_on_fndecl ( tree fndecl, bool is_main_entry_point, bool has_visibility, const HIR::FunctionQualifiers &qualifiers, const AST::AttrVec &attrs); diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index a592e352c00..65f159ef603 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -1199,9 +1199,14 @@ HIRCompileBase::resolve_adjustements ( e = address_expression (e, locus); break; - case Resolver::Adjustment::AdjustmentType::DEREF_REF: + case Resolver::Adjustment::AdjustmentType::DEREF: + case Resolver::Adjustment::AdjustmentType::DEREF_MUT: e = resolve_deref_adjustment (adjustment, e, locus); break; + + case Resolver::Adjustment::AdjustmentType::INDIRECTION: + e = resolve_indirection_adjustment (adjustment, e, locus); + break; } } @@ -1212,17 +1217,9 @@ tree HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment, tree expression, Location locus) { - rust_assert (adjustment.is_deref_adjustment ()); - - tree expected_type - = TyTyResolveCompile::compile (ctx, adjustment.get_expected ()); - if (!adjustment.has_operator_overload ()) - { - return ctx->get_backend ()->indirect_expression (expected_type, - expression, - true, /* known_valid*/ - locus); - } + rust_assert (adjustment.is_deref_adjustment () + || adjustment.is_deref_mut_adjustment ()); + rust_assert (adjustment.has_operator_overload ()); TyTy::FnType *lookup = adjustment.get_deref_operator_fn (); HIR::ImplItem *resolved_item = adjustment.get_deref_hir_item (); @@ -1246,13 +1243,19 @@ HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment, // make the call auto fncontext = ctx->peek_fn (); - tree deref_call - = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address, - {adjusted_argument}, nullptr, - locus); + return ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address, + {adjusted_argument}, nullptr, + locus); +} + +tree +HIRCompileBase::resolve_indirection_adjustment ( + Resolver::Adjustment &adjustment, tree expression, Location locus) +{ + tree expected_type + = TyTyResolveCompile::compile (ctx, adjustment.get_expected ()); - // do the indirect expression - return ctx->get_backend ()->indirect_expression (expected_type, deref_call, + return ctx->get_backend ()->indirect_expression (expected_type, expression, true, /* known_valid*/ locus); } diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index fd2f7d3a905..286225266a2 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -19,6 +19,7 @@ #include "rust-autoderef.h" #include "rust-hir-path-probe.h" #include "rust-hir-dot-operator.h" +#include "rust-hir-trait-resolve.h" namespace Rust { namespace Resolver { @@ -29,26 +30,6 @@ resolve_operator_overload_fn ( TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item, Adjustment::AdjustmentType *requires_ref_adjustment); -bool -Adjuster::needs_address (const std::vector &adjustments) -{ - for (auto &adjustment : adjustments) - { - switch (adjustment.get_type ()) - { - case Adjustment::AdjustmentType::IMM_REF: - case Adjustment::AdjustmentType::MUT_REF: - case Adjustment::AdjustmentType::DEREF_REF: - return true; - - default: - break; - } - } - - return false; -} - TyTy::BaseType * Adjuster::adjust_type (const std::vector &adjustments) { @@ -59,23 +40,22 @@ Adjuster::adjust_type (const std::vector &adjustments) } Adjustment -Adjuster::try_deref_type (const TyTy::BaseType *ty) +Adjuster::try_deref_type (const TyTy::BaseType *ty, + Analysis::RustLangItem::ItemType deref_lang_item) { - // probe for the lang-item - TyTy::BaseType *resolved_base = ty->clone (); - HIR::ImplItem *impl_item = nullptr; TyTy::FnType *fn = nullptr; Adjustment::AdjustmentType requires_ref_adjustment = Adjustment::AdjustmentType::ERROR; bool operator_overloaded - = resolve_operator_overload_fn (Analysis::RustLangItem::ItemType::DEREF, ty, - &fn, &impl_item, &requires_ref_adjustment); - if (operator_overloaded) + = resolve_operator_overload_fn (deref_lang_item, ty, &fn, &impl_item, + &requires_ref_adjustment); + if (!operator_overloaded) { - resolved_base = fn->get_return_type ()->clone (); + return Adjustment::get_error (); } + auto resolved_base = fn->get_return_type ()->clone (); bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF; if (!is_valid_type) return Adjustment::get_error (); @@ -83,12 +63,41 @@ Adjuster::try_deref_type (const TyTy::BaseType *ty) TyTy::ReferenceType *ref_base = static_cast (resolved_base); - auto infered = ref_base->get_base ()->clone (); + Adjustment::AdjustmentType adjustment_type + = Adjustment::AdjustmentType::ERROR; + switch (deref_lang_item) + { + case Analysis::RustLangItem::ItemType::DEREF: + adjustment_type = Adjustment::AdjustmentType::DEREF; + break; - return Adjustment::get_op_overload_deref_adjustment (infered, fn, impl_item, + case Analysis::RustLangItem::ItemType::DEREF_MUT: + adjustment_type = Adjustment::AdjustmentType::DEREF_MUT; + break; + + default: + break; + } + + return Adjustment::get_op_overload_deref_adjustment (adjustment_type, + ref_base, fn, impl_item, requires_ref_adjustment); } +Adjustment +Adjuster::try_raw_deref_type (const TyTy::BaseType *ty) +{ + bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF; + if (!is_valid_type) + return Adjustment::get_error (); + + const TyTy::ReferenceType *ref_base + = static_cast (ty); + auto infered = ref_base->get_base ()->clone (); + + return Adjustment (Adjustment::AdjustmentType::INDIRECTION, infered); +} + static bool resolve_operator_overload_fn ( Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty, diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h index a6c9d088a89..f389aff62c0 100644 --- a/gcc/rust/typecheck/rust-autoderef.h +++ b/gcc/rust/typecheck/rust-autoderef.h @@ -33,7 +33,9 @@ public: IMM_REF, MUT_REF, - DEREF_REF + DEREF, + DEREF_MUT, + INDIRECTION, }; // ctor for all adjustments except derefs @@ -42,11 +44,12 @@ public: {} static Adjustment get_op_overload_deref_adjustment ( - const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item, + AdjustmentType type, const TyTy::BaseType *expected, TyTy::FnType *fn, + HIR::ImplItem *deref_item, Adjustment::AdjustmentType requires_ref_adjustment) { - return Adjustment (Adjustment::DEREF_REF, expected, fn, deref_item, - requires_ref_adjustment); + rust_assert (type == DEREF || type == DEREF_MUT); + return Adjustment (type, expected, fn, deref_item, requires_ref_adjustment); } AdjustmentType get_type () const { return type; } @@ -69,8 +72,12 @@ public: return "IMM_REF"; case AdjustmentType::MUT_REF: return "MUT_REF"; - case AdjustmentType::DEREF_REF: - return "DEREF_REF"; + case AdjustmentType::DEREF: + return "DEREF"; + case AdjustmentType::DEREF_MUT: + return "DEREF_MUT"; + case AdjustmentType::INDIRECTION: + return "INDIRECTION"; } gcc_unreachable (); return ""; @@ -80,7 +87,9 @@ public: bool is_error () const { return type == ERROR; } - bool is_deref_adjustment () const { return type == DEREF_REF; } + bool is_deref_adjustment () const { return type == DEREF; } + + bool is_deref_mut_adjustment () const { return type == DEREF_MUT; } bool has_operator_overload () const { return deref_operator_fn != nullptr; } @@ -120,9 +129,11 @@ public: TyTy::BaseType *adjust_type (const std::vector &adjustments); - static bool needs_address (const std::vector &adjustments); + static Adjustment + try_deref_type (const TyTy::BaseType *ty, + Analysis::RustLangItem::ItemType deref_lang_item); - static Adjustment try_deref_type (const TyTy::BaseType *ty); + static Adjustment try_raw_deref_type (const TyTy::BaseType *ty); private: const TyTy::BaseType *base; diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc new file mode 100644 index 00000000000..84bbc0c4e0a --- /dev/null +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -0,0 +1,359 @@ +// Copyright (C) 2020-2022 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// . + +#include "rust-hir-dot-operator.h" +#include "rust-hir-path-probe.h" +#include "rust-hir-trait-resolve.h" + +namespace Rust { +namespace Resolver { + +MethodCandidate +MethodResolver::Probe (const TyTy::BaseType *receiver, + const HIR::PathIdentSegment &segment_name, + bool autoderef_flag) +{ + const TyTy::BaseType *r = receiver; + std::vector adjustments; + while (true) + { + auto res = Try (r, segment_name, adjustments); + if (!res.is_error ()) + return res; + + // 4. deref to to 1, if cannot deref then quit + if (autoderef_flag) + return MethodCandidate::get_error (); + + Adjustment deref + = Adjuster::try_deref_type (r, Analysis::RustLangItem::ItemType::DEREF); + if (!deref.is_error ()) + { + auto deref_r = deref.get_expected (); + adjustments.push_back (deref); + auto res = Try (deref_r, segment_name, adjustments); + if (!res.is_error ()) + { + return res; + } + + adjustments.pop_back (); + } + + Adjustment deref_mut = Adjuster::try_deref_type ( + r, Analysis::RustLangItem::ItemType::DEREF_MUT); + if (!deref_mut.is_error ()) + { + auto deref_r = deref_mut.get_expected (); + adjustments.push_back (deref_mut); + auto res = Try (deref_r, segment_name, adjustments); + if (!res.is_error ()) + { + return res; + } + + adjustments.pop_back (); + } + + if (!deref_mut.is_error ()) + { + auto deref_r = deref_mut.get_expected (); + adjustments.push_back (deref_mut); + Adjustment raw_deref = Adjuster::try_raw_deref_type (deref_r); + adjustments.push_back (raw_deref); + deref_r = raw_deref.get_expected (); + + auto res = Try (deref_r, segment_name, adjustments); + if (!res.is_error ()) + { + return res; + } + + adjustments.pop_back (); + adjustments.pop_back (); + } + + if (!deref.is_error ()) + { + r = deref.get_expected (); + adjustments.push_back (deref); + } + Adjustment raw_deref = Adjuster::try_raw_deref_type (r); + if (raw_deref.is_error ()) + return MethodCandidate::get_error (); + + r = raw_deref.get_expected (); + adjustments.push_back (raw_deref); + } + return MethodCandidate::get_error (); +} + +MethodCandidate +MethodResolver::Try (const TyTy::BaseType *r, + const HIR::PathIdentSegment &segment_name, + std::vector &adjustments) +{ + PathProbeCandidate c = PathProbeCandidate::get_error (); + const std::vector &specified_bounds + = r->get_specified_bounds (); + + // 1. try raw + MethodResolver raw (*r, segment_name, specified_bounds); + c = raw.select (); + if (!c.is_error ()) + { + return MethodCandidate{c, adjustments}; + } + + // 2. try ref + TyTy::ReferenceType *r1 + = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), + Mutability::Imm); + MethodResolver imm_ref (*r1, segment_name, specified_bounds); + c = imm_ref.select (); + if (!c.is_error ()) + { + adjustments.push_back ( + Adjustment (Adjustment::AdjustmentType::IMM_REF, r1)); + return MethodCandidate{c, adjustments}; + } + + // 3. try mut ref + TyTy::ReferenceType *r2 + = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), + Mutability::Mut); + MethodResolver mut_ref (*r2, segment_name, specified_bounds); + c = mut_ref.select (); + if (!c.is_error ()) + { + adjustments.push_back ( + Adjustment (Adjustment::AdjustmentType::MUT_REF, r2)); + return MethodCandidate{c, adjustments}; + } + + return MethodCandidate::get_error (); +} + +PathProbeCandidate +MethodResolver::select () +{ + struct impl_item_candidate + { + HIR::Function *item; + HIR::ImplBlock *impl_block; + TyTy::FnType *ty; + }; + + // assemble inherent impl items + std::vector inherent_impl_fns; + mappings->iterate_impl_items ( + [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { + bool is_trait_impl = impl->has_trait_ref (); + if (is_trait_impl) + return true; + + bool is_fn + = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION; + if (!is_fn) + return true; + + HIR::Function *func = static_cast (item); + if (!func->is_method ()) + return true; + + bool name_matches + = func->get_function_name ().compare (segment_name.as_string ()) == 0; + if (!name_matches) + return true; + + TyTy::BaseType *ty = nullptr; + if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty)) + return true; + if (ty->get_kind () == TyTy::TypeKind::ERROR) + return true; + + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast (ty); + + inherent_impl_fns.push_back ({func, impl, fnty}); + + return true; + }); + + struct trait_item_candidate + { + const HIR::TraitItemFunc *item; + const HIR::Trait *trait; + TyTy::FnType *ty; + const TraitReference *reference; + const TraitItemReference *item_ref; + }; + + std::vector trait_fns; + mappings->iterate_impl_blocks ([&] (HirId id, + HIR::ImplBlock *impl) mutable -> bool { + bool is_trait_impl = impl->has_trait_ref (); + if (!is_trait_impl) + return true; + + // look for impl implementation else lookup the associated trait item + for (auto &impl_item : impl->get_impl_items ()) + { + bool is_fn = impl_item->get_impl_item_type () + == HIR::ImplItem::ImplItemType::FUNCTION; + if (!is_fn) + continue; + + HIR::Function *func = static_cast (impl_item.get ()); + if (!func->is_method ()) + continue; + + bool name_matches + = func->get_function_name ().compare (segment_name.as_string ()) == 0; + if (!name_matches) + continue; + + TyTy::BaseType *ty = nullptr; + if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty)) + continue; + if (ty->get_kind () == TyTy::TypeKind::ERROR) + continue; + + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast (ty); + + inherent_impl_fns.push_back ({func, impl, fnty}); + return true; + } + + TraitReference *trait_ref + = TraitResolver::Resolve (*impl->get_trait_ref ().get ()); + rust_assert (!trait_ref->is_error ()); + + auto item_ref + = trait_ref->lookup_trait_item (segment_name.as_string (), + TraitItemReference::TraitItemType::FN); + if (item_ref->is_error ()) + return true; + + const HIR::Trait *trait = trait_ref->get_hir_trait_ref (); + HIR::TraitItem *item = item_ref->get_hir_trait_item (); + rust_assert (item->get_item_kind () == HIR::TraitItem::TraitItemKind::FUNC); + HIR::TraitItemFunc *func = static_cast (item); + + TyTy::BaseType *ty = item_ref->get_tyty (); + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast (ty); + + trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; + trait_fns.push_back (candidate); + + return true; + }); + + // lookup specified bounds for an associated item + struct precdicate_candidate + { + TyTy::TypeBoundPredicateItem lookup; + TyTy::FnType *fntype; + }; + + std::vector predicate_items; + for (auto &bound : specified_bounds) + { + TyTy::TypeBoundPredicateItem lookup + = bound.lookup_associated_item (segment_name.as_string ()); + if (lookup.is_error ()) + continue; + + bool is_fn = lookup.get_raw_item ()->get_trait_item_type () + == TraitItemReference::TraitItemType::FN; + if (!is_fn) + continue; + + TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty (); + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast (ty); + + precdicate_candidate candidate{lookup, fnty}; + predicate_items.push_back (candidate); + } + + for (auto impl_item : inherent_impl_fns) + { + TyTy::FnType *fn = impl_item.ty; + rust_assert (fn->is_method ()); + + TyTy::BaseType *fn_self = fn->get_self_type (); + if (fn_self->can_eq (&receiver, false)) + { + PathProbeCandidate::ImplItemCandidate c{impl_item.item, + impl_item.impl_block}; + return PathProbeCandidate ( + PathProbeCandidate::CandidateType::IMPL_FUNC, fn, + impl_item.item->get_locus (), c); + } + } + + for (auto trait_item : trait_fns) + { + TyTy::FnType *fn = trait_item.ty; + rust_assert (fn->is_method ()); + + TyTy::BaseType *fn_self = fn->get_self_type (); + if (fn_self->can_eq (&receiver, false)) + { + PathProbeCandidate::TraitItemCandidate c{trait_item.reference, + trait_item.item_ref, + nullptr}; + return PathProbeCandidate ( + PathProbeCandidate::CandidateType::TRAIT_FUNC, fn, + trait_item.item->get_locus (), c); + } + } + + for (auto predicate : predicate_items) + { + TyTy::FnType *fn = predicate.fntype; + rust_assert (fn->is_method ()); + + TyTy::BaseType *fn_self = fn->get_self_type (); + if (fn_self->can_eq (&receiver, false)) + { + const TraitReference *trait_ref + = predicate.lookup.get_parent ()->get (); + const TraitItemReference *trait_item + = predicate.lookup.get_raw_item (); + + TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver ( + receiver.get_root (), + predicate.lookup.get_parent ()->get_generic_args ()); + + PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item, + nullptr}; + return PathProbeCandidate ( + PathProbeCandidate::CandidateType::TRAIT_FUNC, subst, + trait_item->get_locus (), c); + } + } + + return PathProbeCandidate::get_error (); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h index f48211bb4f2..f14300a4bfe 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.h +++ b/gcc/rust/typecheck/rust-hir-dot-operator.h @@ -20,7 +20,6 @@ #define RUST_HIR_DOT_OPERATOR #include "rust-hir-path-probe.h" -#include "rust-hir-trait-resolve.h" namespace Rust { namespace Resolver { @@ -46,273 +45,14 @@ protected: public: static MethodCandidate Probe (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, - bool autoderef_flag = false) - { - const TyTy::BaseType *r = receiver; - std::vector adjustments; - while (true) - { - PathProbeCandidate c = PathProbeCandidate::get_error (); - const std::vector &specified_bounds - = r->get_specified_bounds (); - - // 1. try raw - MethodResolver raw (*r, segment_name, specified_bounds); - c = raw.select (); - if (!c.is_error ()) - return MethodCandidate{c, adjustments}; - - // 2. try ref - TyTy::ReferenceType *r1 - = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), - Mutability::Imm); - MethodResolver imm_ref (*r1, segment_name, specified_bounds); - c = imm_ref.select (); - if (!c.is_error ()) - { - adjustments.push_back ( - Adjustment (Adjustment::AdjustmentType::IMM_REF, r1)); - return MethodCandidate{c, adjustments}; - } - - // 3. try mut ref - TyTy::ReferenceType *r2 - = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()), - Mutability::Mut); - MethodResolver mut_ref (*r2, segment_name, specified_bounds); - c = mut_ref.select (); - if (!c.is_error ()) - { - adjustments.push_back ( - Adjustment (Adjustment::AdjustmentType::MUT_REF, r2)); - return MethodCandidate{c, adjustments}; - } - - // 4. deref to to 1, if cannot deref then quit - if (autoderef_flag) - { - return MethodCandidate::get_error (); - } - else - { - Adjustment deref = Adjuster::try_deref_type (r); - if (deref.is_error ()) - return MethodCandidate::get_error (); - - r = deref.get_expected (); - adjustments.push_back (deref); - } - } - return MethodCandidate::get_error (); - } + bool autoderef_flag = false); protected: - PathProbeCandidate select () - { - struct impl_item_candidate - { - HIR::Function *item; - HIR::ImplBlock *impl_block; - TyTy::FnType *ty; - }; - - // assemble inherent impl items - std::vector inherent_impl_fns; - mappings->iterate_impl_items ([&] (HirId id, HIR::ImplItem *item, - HIR::ImplBlock *impl) mutable -> bool { - bool is_trait_impl = impl->has_trait_ref (); - if (is_trait_impl) - return true; - - bool is_fn - = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION; - if (!is_fn) - return true; - - HIR::Function *func = static_cast (item); - if (!func->is_method ()) - return true; - - bool name_matches - = func->get_function_name ().compare (segment_name.as_string ()) == 0; - if (!name_matches) - return true; - - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty)) - return true; - if (ty->get_kind () == TyTy::TypeKind::ERROR) - return true; - - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast (ty); - - inherent_impl_fns.push_back ({func, impl, fnty}); - - return true; - }); - - struct trait_item_candidate - { - const HIR::TraitItemFunc *item; - const HIR::Trait *trait; - TyTy::FnType *ty; - const TraitReference *reference; - const TraitItemReference *item_ref; - }; - - std::vector trait_fns; - mappings->iterate_impl_blocks ([&] (HirId id, - HIR::ImplBlock *impl) mutable -> bool { - bool is_trait_impl = impl->has_trait_ref (); - if (!is_trait_impl) - return true; - - // look for impl implementation else lookup the associated trait item - for (auto &impl_item : impl->get_impl_items ()) - { - bool is_fn = impl_item->get_impl_item_type () - == HIR::ImplItem::ImplItemType::FUNCTION; - if (!is_fn) - continue; - - HIR::Function *func = static_cast (impl_item.get ()); - if (!func->is_method ()) - continue; - - bool name_matches - = func->get_function_name ().compare (segment_name.as_string ()) - == 0; - if (!name_matches) - continue; - - TyTy::BaseType *ty = nullptr; - if (!context->lookup_type (func->get_mappings ().get_hirid (), &ty)) - continue; - if (ty->get_kind () == TyTy::TypeKind::ERROR) - continue; + static MethodCandidate Try (const TyTy::BaseType *r, + const HIR::PathIdentSegment &segment_name, + std::vector &adjustments); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast (ty); - - inherent_impl_fns.push_back ({func, impl, fnty}); - return true; - } - - TraitReference *trait_ref - = TraitResolver::Resolve (*impl->get_trait_ref ().get ()); - rust_assert (!trait_ref->is_error ()); - - auto item_ref - = trait_ref->lookup_trait_item (segment_name.as_string (), - TraitItemReference::TraitItemType::FN); - if (item_ref->is_error ()) - return true; - - const HIR::Trait *trait = trait_ref->get_hir_trait_ref (); - HIR::TraitItem *item = item_ref->get_hir_trait_item (); - rust_assert (item->get_item_kind () - == HIR::TraitItem::TraitItemKind::FUNC); - HIR::TraitItemFunc *func = static_cast (item); - - TyTy::BaseType *ty = item_ref->get_tyty (); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast (ty); - - trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; - trait_fns.push_back (candidate); - - return true; - }); - - // lookup specified bounds for an associated item - struct precdicate_candidate - { - TyTy::TypeBoundPredicateItem lookup; - TyTy::FnType *fntype; - }; - - std::vector predicate_items; - for (auto &bound : specified_bounds) - { - TyTy::TypeBoundPredicateItem lookup - = bound.lookup_associated_item (segment_name.as_string ()); - if (lookup.is_error ()) - continue; - - bool is_fn = lookup.get_raw_item ()->get_trait_item_type () - == TraitItemReference::TraitItemType::FN; - if (!is_fn) - continue; - - TyTy::BaseType *ty = lookup.get_raw_item ()->get_tyty (); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast (ty); - - precdicate_candidate candidate{lookup, fnty}; - predicate_items.push_back (candidate); - } - - for (auto impl_item : inherent_impl_fns) - { - TyTy::FnType *fn = impl_item.ty; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - if (fn_self->can_eq (&receiver, false)) - { - PathProbeCandidate::ImplItemCandidate c{impl_item.item, - impl_item.impl_block}; - return PathProbeCandidate ( - PathProbeCandidate::CandidateType::IMPL_FUNC, fn, - impl_item.item->get_locus (), c); - } - } - - for (auto trait_item : trait_fns) - { - TyTy::FnType *fn = trait_item.ty; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - if (fn_self->can_eq (&receiver, false)) - { - PathProbeCandidate::TraitItemCandidate c{trait_item.reference, - trait_item.item_ref, - nullptr}; - return PathProbeCandidate ( - PathProbeCandidate::CandidateType::TRAIT_FUNC, fn, - trait_item.item->get_locus (), c); - } - } - - for (auto predicate : predicate_items) - { - TyTy::FnType *fn = predicate.fntype; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - if (fn_self->can_eq (&receiver, false)) - { - const TraitReference *trait_ref - = predicate.lookup.get_parent ()->get (); - const TraitItemReference *trait_item - = predicate.lookup.get_raw_item (); - - TyTy::BaseType *subst = predicate.lookup.get_tyty_for_receiver ( - receiver.get_root (), - predicate.lookup.get_parent ()->get_generic_args ()); - - PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item, - nullptr}; - return PathProbeCandidate ( - PathProbeCandidate::CandidateType::TRAIT_FUNC, subst, - trait_item->get_locus (), c); - } - } - - return PathProbeCandidate::get_error (); - } + PathProbeCandidate select (); MethodResolver (const TyTy::BaseType &receiver, const HIR::PathIdentSegment &segment_name, diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2cb4461886e..a4b8f0ac530 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -258,6 +258,7 @@ public: // Get the adjusted self Adjuster adj (receiver_tyty); TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); + adjusted_self->debug (); // store the adjustments for code-generation to know what to do context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (), diff --git a/gcc/testsuite/rust/execute/torture/method3.rs b/gcc/testsuite/rust/execute/torture/method3.rs new file mode 100644 index 00000000000..0e9e8ff42a0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method3.rs @@ -0,0 +1,78 @@ +// { dg-additional-options "-w" } +// { dg-output "mut_deref\nfoobar: 123\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +pub trait DerefMut: Deref { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl Deref for &mut T { + type Target = T; + fn deref(&self) -> &T { + *self + } +} + +pub struct Bar(i32); +impl Bar { + pub fn foobar(&mut self) -> i32 { + self.0 + } +} + +pub struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &mut self.0 + } +} + +pub fn main() -> i32 { + let bar = Bar(123); + let mut foo: Foo = Foo(bar); + let foobar = foo.foobar(); + + unsafe { + let a = "foobar: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, foobar); + } + + foobar - 123 +} diff --git a/gcc/testsuite/rust/execute/torture/method4.rs b/gcc/testsuite/rust/execute/torture/method4.rs new file mode 100644 index 00000000000..5c6fdfe02c3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/method4.rs @@ -0,0 +1,78 @@ +// { dg-additional-options "-w" } +// { dg-output "mut_deref\nfoobar: 123\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "deref"] +pub trait Deref { + type Target; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +pub trait DerefMut: Deref { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +impl Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl Deref for &mut T { + type Target = T; + fn deref(&self) -> &T { + *self + } +} + +pub struct Bar(i32); +impl Bar { + pub fn foobar(&mut self) -> i32 { + self.0 + } +} + +pub struct Foo(T); +impl Deref for Foo { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + let a = "mut_deref\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + &mut self.0 + } +} + +pub fn main() -> i32 { + let mut bar = Bar(123); + let mut foo: Foo<&mut Bar> = Foo(&mut bar); + let foobar = foo.foobar(); + + unsafe { + let a = "foobar: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, foobar); + } + + foobar - 123 +}