diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-base.h | 3 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.cc | 39 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-autoderef.cc | 69 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-autoderef.h | 29 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-dot-operator.cc | 359 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-dot-operator.h | 270 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/method3.rs | 78 | ||||
-rw-r--r-- | 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 4f76216..5d02f06 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 a52886c..54116da 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 a592e35..65f159e 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 fd2f7d3..2862252 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<Adjustment> &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<Adjustment> &adjustments) { @@ -59,23 +40,22 @@ Adjuster::adjust_type (const std::vector<Adjustment> &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<TyTy::ReferenceType *> (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<const TyTy::ReferenceType *> (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 a6c9d08..f389aff 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<Adjustment> &adjustments); - static bool needs_address (const std::vector<Adjustment> &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 0000000..84bbc0c --- /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 +// <http://www.gnu.org/licenses/>. + +#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<Adjustment> 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<Adjustment> &adjustments) +{ + PathProbeCandidate c = PathProbeCandidate::get_error (); + const std::vector<TyTy::TypeBoundPredicate> &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<impl_item_candidate> 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<HIR::Function *> (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<TyTy::FnType *> (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_item_candidate> 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<HIR::Function *> (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<TyTy::FnType *> (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<HIR::TraitItemFunc *> (item); + + TyTy::BaseType *ty = item_ref->get_tyty (); + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast<TyTy::FnType *> (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<precdicate_candidate> 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<TyTy::FnType *> (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 f48211b..f14300a 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<Adjustment> adjustments; - while (true) - { - PathProbeCandidate c = PathProbeCandidate::get_error (); - const std::vector<TyTy::TypeBoundPredicate> &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<impl_item_candidate> 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<HIR::Function *> (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<TyTy::FnType *> (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_item_candidate> 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<HIR::Function *> (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<Adjustment> &adjustments); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast<TyTy::FnType *> (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<HIR::TraitItemFunc *> (item); - - TyTy::BaseType *ty = item_ref->get_tyty (); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast<TyTy::FnType *> (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<precdicate_candidate> 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<TyTy::FnType *> (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 2cb4461..a4b8f0a 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 0000000..0e9e8ff --- /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<T> Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl<T> 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>(T); +impl<T> Deref for Foo<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T> DerefMut for Foo<T> { + 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<Bar> = 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 0000000..5c6fdfe --- /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<T> Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl<T> 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>(T); +impl<T> Deref for Foo<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T> DerefMut for Foo<T> { + 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 +} |