diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index 4f039d2328ea..a8f8f2d50dd1 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -40,11 +40,11 @@ class HIRCompileBase protected: Context *get_context () { return ctx; } - tree coercion_site (HirId id, tree rvalue, const TyTy::BaseType *actual, - const TyTy::BaseType *expected, Location lvalue_locus, + tree coercion_site (HirId id, tree rvalue, TyTy::BaseType *actual, + TyTy::BaseType *expected, Location lvalue_locus, Location rvalue_locus); - tree coercion_site1 (tree rvalue, const TyTy::BaseType *actual, - const TyTy::BaseType *expected, Location lvalue_locus, + tree coercion_site1 (tree rvalue, TyTy::BaseType *actual, + TyTy::BaseType *expected, Location lvalue_locus, Location rvalue_locus); tree coerce_to_dyn_object (tree compiled_ref, const TyTy::BaseType *actual, diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index d7945dbf26b5..200f3a2a07e4 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -26,7 +26,7 @@ #include "rust-compile-block.h" #include "rust-compile-implitem.h" #include "rust-constexpr.h" -#include "rust-unify.h" +#include "rust-type-util.h" #include "rust-gcc.h" #include "fold-const.h" @@ -2007,10 +2007,9 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, { TyTy::BaseType *infer_impl_call = candidate_call->infer_substitions (expr_locus); - monomorphized = Resolver::UnifyRules::Resolve ( - TyTy::TyWithLocation (infer_impl_call), - TyTy::TyWithLocation (fntype), expr_locus, true /* commit */, - true /* emit_errors */); + monomorphized + = Resolver::unify_site (ref, TyTy::TyWithLocation (infer_impl_call), + TyTy::TyWithLocation (fntype), expr_locus); } return CompileInherentImplItem::Compile (impl_item, ctx, monomorphized); diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index db08b3d595b4..321790108558 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -54,10 +54,9 @@ CompileCrate::go () // Shared methods in compilation tree -HIRCompileBase::coercion_site (HirId id, tree rvalue, - const TyTy::BaseType *rval, - const TyTy::BaseType *lval, - Location lvalue_locus, Location rvalue_locus) +HIRCompileBase::coercion_site (HirId id, tree rvalue, TyTy::BaseType *rval, + TyTy::BaseType *lval, Location lvalue_locus, + Location rvalue_locus) { std::vector *adjustments = nullptr; bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments); @@ -70,15 +69,15 @@ HIRCompileBase::coercion_site (HirId id, tree rvalue, } tree -HIRCompileBase::coercion_site1 (tree rvalue, const TyTy::BaseType *rval, - const TyTy::BaseType *lval, - Location lvalue_locus, Location rvalue_locus) +HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval, + TyTy::BaseType *lval, Location lvalue_locus, + Location rvalue_locus) { if (rvalue == error_mark_node) return error_mark_node; - const TyTy::BaseType *actual = rval->destructure (); - const TyTy::BaseType *expected = lval->destructure (); + TyTy::BaseType *actual = rval->destructure (); + TyTy::BaseType *expected = lval->destructure (); if (expected->get_kind () == TyTy::TypeKind::REF) { diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index 658ddd7c2e9c..b2cddb3f6b06 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -26,7 +26,7 @@ namespace Resolver { static bool resolve_operator_overload_fn ( - Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty, + Analysis::RustLangItem::ItemType lang_item_type, TyTy::BaseType *ty, TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item, Adjustment::AdjustmentType *requires_ref_adjustment); @@ -40,7 +40,7 @@ Adjuster::adjust_type (const std::vector &adjustments) } Adjustment -Adjuster::try_deref_type (const TyTy::BaseType *ty, +Adjuster::try_deref_type (TyTy::BaseType *ty, Analysis::RustLangItem::ItemType deref_lang_item) { HIR::ImplItem *impl_item = nullptr; @@ -85,7 +85,7 @@ Adjuster::try_deref_type (const TyTy::BaseType *ty, } Adjustment -Adjuster::try_raw_deref_type (const TyTy::BaseType *ty) +Adjuster::try_raw_deref_type (TyTy::BaseType *ty) { bool is_valid_type = ty->get_kind () == TyTy::TypeKind::REF; if (!is_valid_type) @@ -99,7 +99,7 @@ Adjuster::try_raw_deref_type (const TyTy::BaseType *ty) } Adjustment -Adjuster::try_unsize_type (const TyTy::BaseType *ty) +Adjuster::try_unsize_type (TyTy::BaseType *ty) { bool is_valid_type = ty->get_kind () == TyTy::TypeKind::ARRAY; if (!is_valid_type) @@ -121,7 +121,7 @@ Adjuster::try_unsize_type (const TyTy::BaseType *ty) static bool resolve_operator_overload_fn ( - Analysis::RustLangItem::ItemType lang_item_type, const TyTy::BaseType *ty, + Analysis::RustLangItem::ItemType lang_item_type, TyTy::BaseType *ty, TyTy::FnType **resolved_fn, HIR::ImplItem **impl_item, Adjustment::AdjustmentType *requires_ref_adjustment) { @@ -292,9 +292,9 @@ AutoderefCycle::try_hook (const TyTy::BaseType &) {} bool -AutoderefCycle::cycle (const TyTy::BaseType *receiver) +AutoderefCycle::cycle (TyTy::BaseType *receiver) { - const TyTy::BaseType *r = receiver; + TyTy::BaseType *r = receiver; while (true) { rust_debug ("autoderef try 1: {%s}", r->debug_str ().c_str ()); @@ -382,7 +382,7 @@ AutoderefCycle::cycle (const TyTy::BaseType *receiver) } bool -AutoderefCycle::try_autoderefed (const TyTy::BaseType *r) +AutoderefCycle::try_autoderefed (TyTy::BaseType *r) { try_hook (*r); diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h index 5f05c0489d1e..1d5dacfc55dd 100644 --- a/gcc/rust/typecheck/rust-autoderef.h +++ b/gcc/rust/typecheck/rust-autoderef.h @@ -40,15 +40,15 @@ class Adjustment }; // ctor for all adjustments except derefs - Adjustment (AdjustmentType type, const TyTy::BaseType *actual, - const TyTy::BaseType *expected) + Adjustment (AdjustmentType type, TyTy::BaseType *actual, + TyTy::BaseType *expected) : Adjustment (type, actual, expected, nullptr, nullptr, AdjustmentType::ERROR) {} static Adjustment get_op_overload_deref_adjustment ( - AdjustmentType type, const TyTy::BaseType *actual, - const TyTy::BaseType *expected, TyTy::FnType *fn, HIR::ImplItem *deref_item, + AdjustmentType type, TyTy::BaseType *actual, TyTy::BaseType *expected, + TyTy::FnType *fn, HIR::ImplItem *deref_item, Adjustment::AdjustmentType requires_ref_adjustment) { rust_assert (type == DEREF || type == DEREF_MUT); @@ -58,8 +58,8 @@ class Adjustment AdjustmentType get_type () const { return type; } - const TyTy::BaseType *get_actual () const { return actual; } - const TyTy::BaseType *get_expected () const { return expected; } + TyTy::BaseType *get_actual () const { return actual; } + TyTy::BaseType *get_expected () const { return expected; } std::string as_string () const { @@ -110,8 +110,8 @@ class Adjustment HIR::ImplItem *get_deref_hir_item () const { return deref_item; } private: - Adjustment (AdjustmentType type, const TyTy::BaseType *actual, - const TyTy::BaseType *expected, TyTy::FnType *deref_operator_fn, + Adjustment (AdjustmentType type, TyTy::BaseType *actual, + TyTy::BaseType *expected, TyTy::FnType *deref_operator_fn, HIR::ImplItem *deref_item, Adjustment::AdjustmentType requires_ref_adjustment) : type (type), actual (actual), expected (expected), @@ -120,8 +120,8 @@ class Adjustment {} AdjustmentType type; - const TyTy::BaseType *actual; - const TyTy::BaseType *expected; + TyTy::BaseType *actual; + TyTy::BaseType *expected; // - only used for deref operator_overloads // @@ -140,12 +140,12 @@ class Adjuster TyTy::BaseType *adjust_type (const std::vector &adjustments); static Adjustment - try_deref_type (const TyTy::BaseType *ty, + try_deref_type (TyTy::BaseType *ty, Analysis::RustLangItem::ItemType deref_lang_item); - static Adjustment try_raw_deref_type (const TyTy::BaseType *ty); + static Adjustment try_raw_deref_type (TyTy::BaseType *ty); - static Adjustment try_unsize_type (const TyTy::BaseType *ty); + static Adjustment try_unsize_type (TyTy::BaseType *ty); private: const TyTy::BaseType *base; @@ -158,15 +158,15 @@ class AutoderefCycle virtual ~AutoderefCycle (); - virtual bool select (const TyTy::BaseType &autoderefed) = 0; + virtual bool select (TyTy::BaseType &autoderefed) = 0; // optional: this is a chance to hook in to grab predicate items on the raw // type virtual void try_hook (const TyTy::BaseType &); - virtual bool cycle (const TyTy::BaseType *receiver); + virtual bool cycle (TyTy::BaseType *receiver); - bool try_autoderefed (const TyTy::BaseType *r); + bool try_autoderefed (TyTy::BaseType *r); bool autoderef_flag; std::vector adjustments; diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc index 987542e59c47..0ecb50f7d1d7 100644 --- a/gcc/rust/typecheck/rust-casts.cc +++ b/gcc/rust/typecheck/rust-casts.cc @@ -39,7 +39,8 @@ TypeCastRules::check () { // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582 auto possible_coercion - = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus); + = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus, + true /*allow-autoderef*/); if (!possible_coercion.is_error ()) return possible_coercion; diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index bea40840fbff..9831e77cdd08 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -18,34 +18,37 @@ #include "rust-hir-type-check-base.h" #include "rust-coercion.h" -#include "rust-unify.h" +#include "rust-type-util.h" namespace Rust { namespace Resolver { TypeCoercionRules::CoercionResult TypeCoercionRules::Coerce (TyTy::BaseType *receiver, TyTy::BaseType *expected, - Location locus) + Location locus, bool allow_autoderef) { - TypeCoercionRules resolver (expected, locus, true); + TypeCoercionRules resolver (expected, locus, true, allow_autoderef, false); bool ok = resolver.do_coercion (receiver); return ok ? resolver.try_result : CoercionResult::get_error (); } TypeCoercionRules::CoercionResult TypeCoercionRules::TryCoerce (TyTy::BaseType *receiver, - TyTy::BaseType *expected, Location locus) + TyTy::BaseType *expected, Location locus, + bool allow_autoderef) { - TypeCoercionRules resolver (expected, locus, false); + TypeCoercionRules resolver (expected, locus, false, allow_autoderef, true); bool ok = resolver.do_coercion (receiver); return ok ? resolver.try_result : CoercionResult::get_error (); } TypeCoercionRules::TypeCoercionRules (TyTy::BaseType *expected, Location locus, - bool emit_errors) - : AutoderefCycle (false), mappings (Analysis::Mappings::get ()), + bool emit_errors, bool allow_autoderef, + bool try_flag) + : AutoderefCycle (!allow_autoderef), mappings (Analysis::Mappings::get ()), context (TypeCheckContext::get ()), expected (expected), locus (locus), - try_result (CoercionResult::get_error ()), emit_errors (emit_errors) + try_result (CoercionResult::get_error ()), emit_errors (emit_errors), + try_flag (try_flag) {} bool @@ -138,6 +141,31 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver) break; } + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210 + switch (receiver->get_kind ()) + { + default: { + rust_debug ( + "do_coercion default unify and infer expected: %s receiver %s", + receiver->debug_str ().c_str (), expected->debug_str ().c_str ()); + TyTy::BaseType *result + = unify_site_and (receiver->get_ref (), + TyTy::TyWithLocation (expected), + TyTy::TyWithLocation (receiver), + locus /*unify_locus*/, false /*emit_errors*/, + !try_flag /*commit_if_ok*/, true /*infer*/, + try_flag /*cleanup on error*/); + rust_debug ("result"); + result->debug (); + if (result->get_kind () != TyTy::TypeKind::ERROR) + { + try_result = CoercionResult{{}, result}; + return true; + } + } + break; + } + return !try_result.is_error (); } @@ -146,7 +174,7 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, TyTy::PointerType *expected, Mutability to_mutbl) { - rust_debug ("coerce_unsafe_ptr(a={%s}, b={%s})", + rust_debug ("coerce_unsafe_ptr(receiver={%s}, expected={%s})", receiver->debug_str ().c_str (), expected->debug_str ().c_str ()); Mutability from_mutbl = Mutability::Imm; @@ -169,6 +197,7 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, break; default: { + // FIXME this can probably turn into a unify_and if (receiver->can_eq (expected, false)) return CoercionResult{{}, expected->clone ()}; @@ -176,6 +205,13 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, } } + bool receiver_is_non_ptr = receiver->get_kind () != TyTy::TypeKind::POINTER; + if (autoderef_flag && receiver_is_non_ptr) + { + // it is unsafe to autoderef to raw pointers + return CoercionResult::get_error (); + } + if (!coerceable_mutability (from_mutbl, to_mutbl)) { Location lhs = mappings->lookup_location (receiver->get_ref ()); @@ -184,13 +220,21 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, return TypeCoercionRules::CoercionResult::get_error (); } - TyTy::PointerType *result + TyTy::PointerType *coerced_mutability = new TyTy::PointerType (receiver->get_ref (), TyTy::TyVar (element->get_ref ()), to_mutbl); - if (!result->can_eq (expected, false)) - return CoercionResult::get_error (); - return CoercionResult{{}, result}; + TyTy::BaseType *result + = unify_site_and (receiver->get_ref (), TyTy::TyWithLocation (expected), + TyTy::TyWithLocation (coerced_mutability), + locus /*unify_locus*/, false /*emit_errors*/, + !try_flag /*commit_if_ok*/, true /*infer*/, + try_flag /*cleanup on error*/); + bool unsafe_ptr_coerceion_ok = result->get_kind () != TyTy::TypeKind::ERROR; + if (unsafe_ptr_coerceion_ok) + return CoercionResult{{}, result}; + + return TypeCoercionRules::CoercionResult::get_error (); } /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. @@ -220,9 +264,12 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, // back to a final unity anyway rust_debug ("coerce_borrowed_pointer -- unify"); TyTy::BaseType *result - = UnifyRules::Resolve (TyTy::TyWithLocation (receiver), - TyTy::TyWithLocation (expected), locus, - true /* commit */, true /* emit_errors */); + = unify_site_and (receiver->get_ref (), + TyTy::TyWithLocation (receiver), + TyTy::TyWithLocation (expected), locus, + false /*emit_errors*/, true /*commit_if_ok*/, + false /* FIXME infer do we want to allow this?? */, + true /*cleanup_on_failure*/); return CoercionResult{{}, result}; } } @@ -365,7 +412,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, } bool -TypeCoercionRules::select (const TyTy::BaseType &autoderefed) +TypeCoercionRules::select (TyTy::BaseType &autoderefed) { rust_debug ( "autoderef type-coercion select autoderefed={%s} can_eq expected={%s}", diff --git a/gcc/rust/typecheck/rust-coercion.h b/gcc/rust/typecheck/rust-coercion.h index d0fc0f97079e..5a6dc64b3fcc 100644 --- a/gcc/rust/typecheck/rust-coercion.h +++ b/gcc/rust/typecheck/rust-coercion.h @@ -42,10 +42,12 @@ class TypeCoercionRules : protected AutoderefCycle }; static CoercionResult Coerce (TyTy::BaseType *receiver, - TyTy::BaseType *expected, Location locus); + TyTy::BaseType *expected, Location locus, + bool allow_autoderef); static CoercionResult TryCoerce (TyTy::BaseType *receiver, - TyTy::BaseType *expected, Location locus); + TyTy::BaseType *expected, Location locus, + bool allow_autoderef); CoercionResult coerce_unsafe_ptr (TyTy::BaseType *receiver, TyTy::PointerType *expected, @@ -66,10 +68,10 @@ class TypeCoercionRules : protected AutoderefCycle void object_unsafe_error (Location expr_locus, Location lhs, Location rhs); protected: - TypeCoercionRules (TyTy::BaseType *expected, Location locus, - bool emit_errors); + TypeCoercionRules (TyTy::BaseType *expected, Location locus, bool emit_errors, + bool allow_autoderef, bool try_flag); - bool select (const TyTy::BaseType &autoderefed) override; + bool select (TyTy::BaseType &autoderefed) override; bool do_coercion (TyTy::BaseType *receiver); @@ -85,6 +87,7 @@ class TypeCoercionRules : protected AutoderefCycle // mutable fields CoercionResult try_result; bool emit_errors; + bool try_flag; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc index 84fa8d4f08b6..6e5ab7d7a90c 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.cc +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -19,6 +19,8 @@ #include "rust-hir-dot-operator.h" #include "rust-hir-path-probe.h" #include "rust-hir-trait-resolve.h" +#include "rust-hir-type-check-item.h" +#include "rust-coercion.h" namespace Rust { namespace Resolver { @@ -29,7 +31,7 @@ MethodResolver::MethodResolver (bool autoderef_flag, {} std::set -MethodResolver::Probe (const TyTy::BaseType *receiver, +MethodResolver::Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, bool autoderef_flag) { @@ -46,7 +48,7 @@ MethodResolver::try_hook (const TyTy::BaseType &r) } bool -MethodResolver::select (const TyTy::BaseType &receiver) +MethodResolver::select (TyTy::BaseType &receiver) { struct impl_item_candidate { @@ -55,6 +57,10 @@ MethodResolver::select (const TyTy::BaseType &receiver) TyTy::FnType *ty; }; + const TyTy::BaseType *raw = receiver.destructure (); + bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER; + bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF; + // assemble inherent impl items std::vector inherent_impl_fns; mappings->iterate_impl_items ( @@ -86,6 +92,38 @@ MethodResolver::select (const TyTy::BaseType &receiver) rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *fnty = static_cast (ty); + const TyTy::BaseType *impl_self + = TypeCheckItem::ResolveImplBlockSelf (*impl); + + // see: + // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280 + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660 + bool impl_self_is_ptr = impl_self->get_kind () == TyTy::TypeKind::POINTER; + bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF; + if (receiver_is_raw_ptr && impl_self_is_ptr) + { + const TyTy::PointerType &sptr + = *static_cast (impl_self); + const TyTy::PointerType &ptr + = *static_cast (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + return true; + } + else if (receiver_is_ref && impl_self_is_ref) + { + const TyTy::ReferenceType &sptr + = *static_cast (impl_self); + const TyTy::ReferenceType &ptr + = *static_cast (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + return true; + } inherent_impl_fns.push_back ({func, impl, fnty}); @@ -133,6 +171,39 @@ MethodResolver::select (const TyTy::BaseType &receiver) rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *fnty = static_cast (ty); + const TyTy::BaseType *impl_self + = TypeCheckItem::ResolveImplBlockSelf (*impl); + + // see: + // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280 + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660 + bool impl_self_is_ptr + = impl_self->get_kind () == TyTy::TypeKind::POINTER; + bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF; + if (receiver_is_raw_ptr && impl_self_is_ptr) + { + const TyTy::PointerType &sptr + = *static_cast (impl_self); + const TyTy::PointerType &ptr + = *static_cast (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + continue; + } + else if (receiver_is_ref && impl_self_is_ref) + { + const TyTy::ReferenceType &sptr + = *static_cast (impl_self); + const TyTy::ReferenceType &ptr + = *static_cast (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + continue; + } inherent_impl_fns.push_back ({func, impl, fnty}); return true; @@ -170,18 +241,51 @@ MethodResolver::select (const TyTy::BaseType &receiver) TyTy::FnType *fntype; }; + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 + rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, " "predicate_items found {%lu}", (unsigned long) inherent_impl_fns.size (), (unsigned long) trait_fns.size (), (unsigned long) predicate_items.size ()); - // see the follow for the proper fix to get rid of this we need to assemble - // candidates based on a match expression gathering the relevant impl blocks - // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 - TyTy::set_cmp_autoderef_mode (); - bool found_possible_candidate = false; + for (const auto &predicate : predicate_items) + { + const TyTy::FnType *fn = predicate.fntype; + rust_assert (fn->is_method ()); + + TyTy::BaseType *fn_self = fn->get_self_type (); + rust_debug ("dot-operator predicate fn_self={%s} can_eq receiver={%s}", + fn_self->debug_str ().c_str (), + receiver.debug_str ().c_str ()); + + auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, Location (), + false /*allow-autoderef*/); + bool ok = !res.is_error (); + if (ok) + { + std::vector adjs = append_adjustments (res.adjustments); + const TraitReference *trait_ref + = predicate.lookup.get_parent ()->get (); + const TraitItemReference *trait_item + = predicate.lookup.get_raw_item (); + + PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item, + nullptr}; + auto try_result = MethodCandidate{ + PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC, + fn->clone (), trait_item->get_locus (), c), + adjs}; + result.insert (std::move (try_result)); + found_possible_candidate = true; + } + } + if (found_possible_candidate) + { + return true; + } + for (auto &impl_item : inherent_impl_fns) { bool is_trait_impl_block = impl_item.impl_block->has_trait_ref (); @@ -195,21 +299,25 @@ MethodResolver::select (const TyTy::BaseType &receiver) rust_debug ("dot-operator impl_item fn_self={%s} can_eq receiver={%s}", fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ()); - if (fn_self->can_eq (&receiver, false)) + + auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, Location (), + false /*allow-autoderef*/); + bool ok = !res.is_error (); + if (ok) { + std::vector adjs = append_adjustments (res.adjustments); PathProbeCandidate::ImplItemCandidate c{impl_item.item, impl_item.impl_block}; auto try_result = MethodCandidate{ PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC, fn, impl_item.item->get_locus (), c), - adjustments}; + adjs}; result.insert (std::move (try_result)); found_possible_candidate = true; } } if (found_possible_candidate) { - TyTy::reset_cmp_autoderef_mode (); return true; } @@ -226,21 +334,25 @@ MethodResolver::select (const TyTy::BaseType &receiver) rust_debug ( "dot-operator trait_impl_item fn_self={%s} can_eq receiver={%s}", fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ()); - if (fn_self->can_eq (&receiver, false)) + + auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, Location (), + false /*allow-autoderef*/); + bool ok = !res.is_error (); + if (ok) { + std::vector adjs = append_adjustments (res.adjustments); PathProbeCandidate::ImplItemCandidate c{impl_item.item, impl_item.impl_block}; auto try_result = MethodCandidate{ PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC, fn, impl_item.item->get_locus (), c), - adjustments}; + adjs}; result.insert (std::move (try_result)); found_possible_candidate = true; } } if (found_possible_candidate) { - TyTy::reset_cmp_autoderef_mode (); return true; } @@ -253,53 +365,25 @@ MethodResolver::select (const TyTy::BaseType &receiver) rust_debug ("dot-operator trait_item fn_self={%s} can_eq receiver={%s}", fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ()); - if (fn_self->can_eq (&receiver, false)) + + auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, Location (), + false /*allow-autoderef*/); + bool ok = !res.is_error (); + if (ok) { + std::vector adjs = append_adjustments (res.adjustments); PathProbeCandidate::TraitItemCandidate c{trait_item.reference, trait_item.item_ref, nullptr}; auto try_result = MethodCandidate{ PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC, fn, trait_item.item->get_locus (), c), - adjustments}; - result.insert (std::move (try_result)); - found_possible_candidate = true; - } - } - if (found_possible_candidate) - { - TyTy::reset_cmp_autoderef_mode (); - return true; - } - - for (const auto &predicate : predicate_items) - { - const TyTy::FnType *fn = predicate.fntype; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - rust_debug ("dot-operator predicate fn_self={%s} can_eq receiver={%s}", - fn_self->debug_str ().c_str (), - receiver.debug_str ().c_str ()); - 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 (); - - PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item, - nullptr}; - auto try_result = MethodCandidate{ - PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC, - fn->clone (), trait_item->get_locus (), c), - adjustments}; + adjs}; result.insert (std::move (try_result)); found_possible_candidate = true; } } - TyTy::reset_cmp_autoderef_mode (); return found_possible_candidate; } @@ -328,5 +412,19 @@ MethodResolver::get_predicate_items ( return predicate_items; } +std::vector +MethodResolver::append_adjustments (const std::vector &adjs) const +{ + std::vector combined; + combined.reserve (adjustments.size () + adjs.size ()); + + for (const auto &a : adjustments) + combined.push_back (a); + for (const auto &a : adjs) + combined.push_back (a); + + return combined; +} + } // 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 e14baf3f87d0..db04ad8a56fb 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.h +++ b/gcc/rust/typecheck/rust-hir-dot-operator.h @@ -54,8 +54,7 @@ class MethodResolver : private TypeCheckBase, protected AutoderefCycle }; static std::set - Probe (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &segment_name, + Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, bool autoderef_flag = false); static std::vector get_predicate_items ( @@ -68,7 +67,11 @@ class MethodResolver : private TypeCheckBase, protected AutoderefCycle void try_hook (const TyTy::BaseType &r) override; - bool select (const TyTy::BaseType &receiver) override; + bool select (TyTy::BaseType &receiver) override; + +private: + std::vector + append_adjustments (const std::vector &adjustments) const; private: // search diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index d4eea7ae954e..a4098682668a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -1027,6 +1027,8 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty); + rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s", + receiver_tyty->debug_str ().c_str ()); auto candidates = MethodResolver::Probe (receiver_tyty, expr.get_method_name ().get_segment ()); @@ -1053,13 +1055,17 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) auto candidate = *candidates.begin (); rust_debug_loc (expr.get_method_name ().get_locus (), - "resolved method to: {%u} {%s}", + "resolved method to: {%u} {%s} with [%zu] adjustments", candidate.candidate.ty->get_ref (), - candidate.candidate.ty->debug_str ().c_str ()); + candidate.candidate.ty->debug_str ().c_str (), + candidate.adjustments.size ()); // Get the adjusted self Adjuster adj (receiver_tyty); TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); + rust_debug ("receiver: %s adjusted self %s", + receiver_tyty->debug_str ().c_str (), + adjusted_self->debug_str ().c_str ()); // store the adjustments for code-generation to know what to do which must be // stored onto the receiver to so as we don't trigger duplicate deref mappings @@ -1331,6 +1337,7 @@ TypeCheckExpr::visit (HIR::DereferenceExpr &expr) TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + rust_debug_loc (expr.get_locus (), "attempting deref operator overload"); auto lang_item_type = Analysis::RustLangItem::ItemType::DEREF; bool operator_overloaded = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr); diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 6d4b9b8a62f5..5c5623a0bf69 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -84,6 +84,7 @@ class TypeCheckContext TyTy::BaseType *type); void insert_implicit_type (TyTy::BaseType *type); bool lookup_type (HirId id, TyTy::BaseType **type) const; + void clear_type (TyTy::BaseType *ty); void insert_implicit_type (HirId id, TyTy::BaseType *type); diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index dbd10366fd72..da9a724aca81 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -117,8 +117,57 @@ unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id, expected->debug_str ().c_str (), expr->debug_str ().c_str ()); + std::vector commits; + std::vector infers; return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/, - true /*emit_error*/); + true /*emit_error*/, false /*infer*/, commits, + infers); +} + +TyTy::BaseType * +unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location unify_locus, bool emit_errors, bool commit_if_ok, + bool implicit_infer_vars, bool cleanup) +{ + TypeCheckContext &context = *TypeCheckContext::get (); + + TyTy::BaseType *expected = lhs.get_ty (); + TyTy::BaseType *expr = rhs.get_ty (); + + rust_debug ( + "unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}", + commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false", id, + expected->debug_str ().c_str (), expr->debug_str ().c_str ()); + + std::vector commits; + std::vector infers; + TyTy::BaseType *result + = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/, + emit_errors, implicit_infer_vars, commits, infers); + bool ok = result->get_kind () != TyTy::TypeKind::ERROR; + if (ok && commit_if_ok) + { + for (auto &c : commits) + { + UnifyRules::commit (c.lhs, c.rhs, c.resolved); + } + } + else if (cleanup) + { + // FIXME + // reset the get_next_hir_id + + for (auto &i : infers) + { + i.param->set_ref (i.pref); + i.param->set_ty_ref (i.ptyref); + + // remove the inference variable + context.clear_type (i.infer); + delete i.infer; + } + } + return result; } TyTy::BaseType * @@ -137,7 +186,8 @@ coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, return expr; // can we autoderef it? - auto result = TypeCoercionRules::Coerce (expr, expected, locus); + auto result = TypeCoercionRules::Coerce (expr, expected, locus, + true /*allow-autodref*/); // the result needs to be unified TyTy::BaseType *receiver = expr; diff --git a/gcc/rust/typecheck/rust-type-util.h b/gcc/rust/typecheck/rust-type-util.h index 01333d8b984c..8ecba738ff44 100644 --- a/gcc/rust/typecheck/rust-type-util.h +++ b/gcc/rust/typecheck/rust-type-util.h @@ -30,13 +30,18 @@ class BaseType; namespace Resolver { -extern bool +bool query_type (HirId reference, TyTy::BaseType **result); TyTy::BaseType * unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, Location unify_locus); +TyTy::BaseType * +unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + Location unify_locus, bool emit_errors, bool commit_if_ok, + bool implicit_infer_vars, bool cleanup); + TyTy::BaseType * coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, Location coercion_locus); diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 27ff96986dcd..096ce26f1fa1 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -108,6 +108,16 @@ TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const return true; } +void +TypeCheckContext::clear_type (TyTy::BaseType *ty) +{ + auto it = resolved.find (ty->get_ref ()); + if (it == resolved.end ()) + return; + + resolved.erase (it); +} + void TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id) { diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index 293c8bfa6411..9006eb1b954f 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -28,10 +28,6 @@ namespace Rust { namespace TyTy { -// we need to fix this properly by implementing the match for assembling -// candidates -extern bool autoderef_cmp_flag; - class BaseCmp : public TyConstVisitor { public: @@ -1271,9 +1267,6 @@ class ReferenceCmp : public BaseCmp auto other_base_type = type.get_base (); bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (autoderef_cmp_flag) - mutability_ok = base->mutability () == type.mutability (); - if (!mutability_ok) { BaseCmp::visit (type); @@ -1320,9 +1313,6 @@ class PointerCmp : public BaseCmp auto other_base_type = type.get_base (); bool mutability_ok = base->is_mutable () ? type.is_mutable () : true; - if (autoderef_cmp_flag) - mutability_ok = base->mutability () == type.mutability (); - if (!mutability_ok) { BaseCmp::visit (type); @@ -1401,7 +1391,7 @@ class ParamCmp : public BaseCmp void visit (const ArrayType &) override { ok = true; } - void visit (const SliceType &) override { ok = !autoderef_cmp_flag; } + void visit (const SliceType &) override { ok = true; } void visit (const BoolType &) override { ok = true; } diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index d0d36ac0a11d..110f59266f36 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -38,19 +38,6 @@ namespace Rust { namespace TyTy { -bool autoderef_cmp_flag = false; - -void -set_cmp_autoderef_mode () -{ - autoderef_cmp_flag = true; -} -void -reset_cmp_autoderef_mode () -{ - autoderef_cmp_flag = false; -} - std::string TypeKindFormat::to_string (TypeKind kind) { @@ -1110,6 +1097,30 @@ ADTType::as_string () const return identifier + subst_as_string () + "{" + variants_buffer + "}"; } +bool +ADTType::is_concrete () const +{ + if (is_unit ()) + { + return !needs_substitution (); + } + + for (auto &variant : variants) + { + bool is_num_variant + = variant->get_variant_type () == VariantDef::VariantType::NUM; + if (is_num_variant) + continue; + + for (auto &field : variant->get_fields ()) + { + if (!field->is_concrete ()) + return false; + } + } + return true; +} + bool ADTType::can_eq (const BaseType *other, bool emit_errors) const { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 64b9379a1c07..b729437f73dc 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -77,11 +77,6 @@ class TypeKindFormat static std::string to_string (TypeKind kind); }; -extern void -set_cmp_autoderef_mode (); -extern void -reset_cmp_autoderef_mode (); - class TyVisitor; class TyConstVisitor; class BaseType : public TypeBoundsMappings @@ -604,23 +599,7 @@ class ADTType : public BaseType, public SubstitutionRef return identifier + subst_as_string (); } - bool is_concrete () const override final - { - if (is_unit ()) - { - return !needs_substitution (); - } - - for (auto &variant : variants) - { - for (auto &field : variant->get_fields ()) - { - if (!field->is_concrete ()) - return false; - } - } - return true; - } + bool is_concrete () const override final; BaseType *clone () const final override; BaseType *monomorphized_clone () const final override; diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index cbbff8c44204..fb7b5d4bd6f0 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -22,21 +22,28 @@ namespace Rust { namespace Resolver { UnifyRules::UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - Location locus, bool commit_flag, bool emit_error) + Location locus, bool commit_flag, bool emit_error, + bool infer, std::vector &commits, + std::vector &infers) : lhs (lhs), rhs (rhs), locus (locus), commit_flag (commit_flag), - emit_error (emit_error), mappings (*Analysis::Mappings::get ()), + emit_error (emit_error), infer_flag (infer), commits (commits), + infers (infers), mappings (*Analysis::Mappings::get ()), context (*TypeCheckContext::get ()) {} TyTy::BaseType * UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - Location locus, bool commit_flag, bool emit_error) + Location locus, bool commit_flag, bool emit_error, + bool infer, std::vector &commits, + std::vector &infers) { - UnifyRules r (lhs, rhs, locus, commit_flag, emit_error); - TyTy::BaseType *result = r.go (); + UnifyRules r (lhs, rhs, locus, commit_flag, emit_error, infer, commits, + infers); + TyTy::BaseType *result = r.go (); + commits.push_back ({lhs.get_ty (), rhs.get_ty (), result}); if (r.commit_flag) - r.commit (result); + UnifyRules::commit (lhs.get_ty (), rhs.get_ty (), result); bool failed = result->get_kind () == TyTy::TypeKind::ERROR; if (failed && r.emit_error) @@ -58,19 +65,26 @@ UnifyRules::get_other () } void -UnifyRules::commit (TyTy::BaseType *resolved) +UnifyRules::commit (TyTy::BaseType *base, TyTy::BaseType *other, + TyTy::BaseType *resolved) { - resolved->append_reference (get_base ()->get_ref ()); - resolved->append_reference (get_other ()->get_ref ()); - for (auto ref : get_base ()->get_combined_refs ()) + TypeCheckContext &context = *TypeCheckContext::get (); + Analysis::Mappings &mappings = *Analysis::Mappings::get (); + + TyTy::BaseType *b = base->destructure (); + TyTy::BaseType *o = other->destructure (); + + resolved->append_reference (b->get_ref ()); + resolved->append_reference (o->get_ref ()); + for (auto ref : b->get_combined_refs ()) resolved->append_reference (ref); - for (auto ref : get_other ()->get_combined_refs ()) + for (auto ref : o->get_combined_refs ()) resolved->append_reference (ref); - get_other ()->append_reference (resolved->get_ref ()); - get_other ()->append_reference (get_base ()->get_ref ()); - get_base ()->append_reference (resolved->get_ref ()); - get_base ()->append_reference (get_other ()->get_ref ()); + o->append_reference (resolved->get_ref ()); + o->append_reference (b->get_ref ()); + b->append_reference (resolved->get_ref ()); + b->append_reference (o->get_ref ()); bool result_resolved = resolved->get_kind () != TyTy::TypeKind::INFER; bool result_is_infer_var = resolved->get_kind () == TyTy::TypeKind::INFER; @@ -127,7 +141,7 @@ UnifyRules::go () // check bounds if (ltype->num_specified_bounds () > 0) { - if (!ltype->bounds_compatible (*rtype, locus, true)) + if (!ltype->bounds_compatible (*rtype, locus, emit_error)) { // already emitted an error emit_error = false; @@ -135,6 +149,64 @@ UnifyRules::go () } } + if (infer_flag) + { + bool rgot_param = rtype->get_kind () == TyTy::TypeKind::PARAM; + bool lhs_is_infer_var = ltype->get_kind () == TyTy::TypeKind::INFER; + bool lhs_is_general_infer_var + = lhs_is_infer_var + && static_cast (ltype)->get_infer_kind () + == TyTy::InferType::GENERAL; + bool expected_is_concrete + = ltype->is_concrete () && !lhs_is_general_infer_var; + bool rneeds_infer = expected_is_concrete && rgot_param; + + bool lgot_param = ltype->get_kind () == TyTy::TypeKind::PARAM; + bool rhs_is_infer_var = rtype->get_kind () == TyTy::TypeKind::INFER; + bool rhs_is_general_infer_var + = rhs_is_infer_var + && static_cast (rtype)->get_infer_kind () + == TyTy::InferType::GENERAL; + bool receiver_is_concrete + = rtype->is_concrete () && !rhs_is_general_infer_var; + bool lneeds_infer = receiver_is_concrete && lgot_param; + + if (rneeds_infer) + { + TyTy::ParamType *p = static_cast (rtype); + TyTy::TyVar iv + = TyTy::TyVar::get_implicit_infer_var (rhs.get_locus ()); + rust_assert (iv.get_tyty ()->get_kind () == TyTy::TypeKind::INFER); + TyTy::InferType *i = static_cast (iv.get_tyty ()); + + infers.push_back ({p->get_ref (), p->get_ty_ref (), p, i}); + + // FIXME + // this is hacky to set the implicit param lets make this a function + p->set_ty_ref (i->get_ref ()); + + // set the rtype now to the new inference var + rtype = i; + } + else if (lneeds_infer) + { + TyTy::ParamType *p = static_cast (ltype); + TyTy::TyVar iv + = TyTy::TyVar::get_implicit_infer_var (lhs.get_locus ()); + rust_assert (iv.get_tyty ()->get_kind () == TyTy::TypeKind::INFER); + TyTy::InferType *i = static_cast (iv.get_tyty ()); + + infers.push_back ({p->get_ref (), p->get_ty_ref (), p, i}); + + // FIXME + // this is hacky to set the implicit param lets make this a function + p->set_ty_ref (i->get_ref ()); + + // set the rtype now to the new inference var + ltype = i; + } + } + switch (ltype->get_kind ()) { case TyTy::INFER: @@ -360,7 +432,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty), TyTy::TyWithLocation (other_field_ty), locus, commit_flag, - false /* emit_error */); + false /* emit_error */, infer_flag, + commits, infers); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -385,7 +458,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) auto res = UnifyRules::Resolve (TyTy::TyWithLocation (pa), TyTy::TyWithLocation (pb), locus, - commit_flag, false /* emit_error */); + commit_flag, false /* emit_error */, + infer_flag, commits, infers); if (res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -490,7 +564,8 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *base_resolved = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */); + commit_flag, false /* emit_error */, + infer_flag, commits, infers); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -559,7 +634,8 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *base_resolved = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */); + commit_flag, false /* emit_error */, + infer_flag, commits, infers); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -686,7 +762,7 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *element_unify = UnifyRules::Resolve ( TyTy::TyWithLocation (ltype->get_element_type ()), TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/); + false /* emit_error*/, infer_flag, commits, infers); if (element_unify->get_kind () != TyTy::TypeKind::ERROR) { @@ -745,7 +821,7 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *element_unify = UnifyRules::Resolve ( TyTy::TyWithLocation (ltype->get_element_type ()), TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/); + false /* emit_error*/, infer_flag, commits, infers); if (element_unify->get_kind () != TyTy::TypeKind::ERROR) { @@ -813,18 +889,18 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) auto unified_param = UnifyRules::Resolve (TyTy::TyWithLocation (a), TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */); + commit_flag, false /* emit_errors */, + infer_flag, commits, infers); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return - = UnifyRules::Resolve (TyTy::TyWithLocation ( - ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), - locus, commit_flag, false /* emit_errors */); + auto unified_return = UnifyRules::Resolve ( + TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, + false /* emit_errors */, infer_flag, commits, infers); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -890,18 +966,18 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto unified_param = UnifyRules::Resolve (TyTy::TyWithLocation (a), TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */); + commit_flag, false /* emit_errors */, + infer_flag, commits, infers); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return - = UnifyRules::Resolve (TyTy::TyWithLocation ( - ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), - locus, commit_flag, false /* emit_errors */); + auto unified_return = UnifyRules::Resolve ( + TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, + false /* emit_errors */, infer_flag, commits, infers); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -919,7 +995,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto unified_result = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type), TyTy::TyWithLocation (other_ret_type), locus, - commit_flag, false /*emit_errors*/); + commit_flag, false /*emit_errors*/, infer_flag, + commits, infers); if (unified_result->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -938,7 +1015,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto unified_param = UnifyRules::Resolve (TyTy::TyWithLocation (this_param), TyTy::TyWithLocation (other_param), locus, - commit_flag, false /* emit_errors */); + commit_flag, false /* emit_errors */, + infer_flag, commits, infers); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1005,7 +1083,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *unified_ty = UnifyRules::Resolve (TyTy::TyWithLocation (bo), TyTy::TyWithLocation (fo), locus, - commit_flag, false /* emit_errors */); + commit_flag, false /* emit_errors */, + infer_flag, commits, infers); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); @@ -1597,11 +1676,10 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) return new TyTy::ErrorType (0); } - TyTy::BaseType *args_res - = UnifyRules::Resolve (TyTy::TyWithLocation ( - <ype->get_parameters ()), - TyTy::TyWithLocation (&type.get_parameters ()), - locus, commit_flag, false /* emit_error */); + TyTy::BaseType *args_res = UnifyRules::Resolve ( + TyTy::TyWithLocation (<ype->get_parameters ()), + TyTy::TyWithLocation (&type.get_parameters ()), locus, commit_flag, + false /* emit_error */, infer_flag, commits, infers); if (args_res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1610,7 +1688,7 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *res = UnifyRules::Resolve ( TyTy::TyWithLocation (<ype->get_result_type ()), TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag, - false /* emit_error */); + false /* emit_error */, infer_flag, commits, infers); if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index 75fb884385ef..53acf21c7d4c 100644 --- a/gcc/rust/typecheck/rust-unify.h +++ b/gcc/rust/typecheck/rust-unify.h @@ -28,9 +28,28 @@ namespace Resolver { class UnifyRules { public: + struct InferenceSite + { + HirId pref; + HirId ptyref; + TyTy::ParamType *param; + TyTy::InferType *infer; + }; + struct CommitSite + { + TyTy::BaseType *lhs; + TyTy::BaseType *rhs; + TyTy::BaseType *resolved; + }; + static TyTy::BaseType *Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, Location locus, - bool commit_flag, bool emit_error); + bool commit_flag, bool emit_error, bool infer, + std::vector &commits, + std::vector &infers); + + static void commit (TyTy::BaseType *base, TyTy::BaseType *other, + TyTy::BaseType *resolved); protected: TyTy::BaseType *expect_inference_variable (TyTy::InferType *ltype, @@ -66,10 +85,12 @@ class UnifyRules private: UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - Location locus, bool commit_flag, bool emit_error); + Location locus, bool commit_flag, bool emit_error, bool infer, + std::vector &commits, + std::vector &infers); void emit_type_mismatch () const; - void commit (TyTy::BaseType *resolved); + TyTy::BaseType *go (); TyTy::BaseType *get_base (); @@ -80,6 +101,9 @@ class UnifyRules Location locus; bool commit_flag; bool emit_error; + bool infer_flag; + std::vector &commits; + std::vector &infers; Analysis::Mappings &mappings; TypeCheckContext &context; diff --git a/gcc/testsuite/rust/compile/issue-1901.rs b/gcc/testsuite/rust/compile/issue-1901.rs new file mode 100644 index 000000000000..b2a70805e758 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1901.rs @@ -0,0 +1,33 @@ +mod intrinsics { + extern "rust-intrinsic" { + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +mod ptr { + #[lang = "const_ptr"] + impl *const T { + pub unsafe fn offset(self, count: isize) -> *const T { + intrinsics::offset(self, count) + } + } + + #[lang = "mut_ptr"] + impl *mut T { + pub unsafe fn offset(self, count: isize) -> *mut T { + intrinsics::offset(self, count) as *mut T + } + } +} + +pub fn test_const(x: *const u8) { + unsafe { + x.offset(1); + } +} + +pub fn test_mut(x: *mut u8) { + unsafe { + x.offset(1); + } +} diff --git a/gcc/testsuite/rust/compile/issue-1930.rs b/gcc/testsuite/rust/compile/issue-1930.rs new file mode 100644 index 000000000000..ab30ccc7da43 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1930.rs @@ -0,0 +1,4 @@ +// { dg-options "-w" } +fn test(x: *mut T) { + let x = x as *mut u8; +}