Skip to content

Generic pointers coerceable #1931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 28, 2023
Merged
8 changes: 4 additions & 4 deletions gcc/rust/backend/rust-compile-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 4 additions & 5 deletions gcc/rust/backend/rust-compile-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
17 changes: 8 additions & 9 deletions gcc/rust/backend/rust-compile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<Resolver::Adjustment> *adjustments = nullptr;
bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (id, &adjustments);
Expand All @@ -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)
{
Expand Down
16 changes: 8 additions & 8 deletions gcc/rust/typecheck/rust-autoderef.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -40,7 +40,7 @@ Adjuster::adjust_type (const std::vector<Adjustment> &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;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
{
Expand Down Expand Up @@ -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 ());
Expand Down Expand Up @@ -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);

Expand Down
32 changes: 16 additions & 16 deletions gcc/rust/typecheck/rust-autoderef.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
{
Expand Down Expand Up @@ -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),
Expand All @@ -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
//
Expand All @@ -140,12 +140,12 @@ class Adjuster
TyTy::BaseType *adjust_type (const std::vector<Adjustment> &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;
Expand All @@ -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<Adjustment> adjustments;
Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/typecheck/rust-casts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
81 changes: 64 additions & 17 deletions gcc/rust/typecheck/rust-coercion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ();
}

Expand All @@ -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;
Expand All @@ -169,13 +197,21 @@ 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 ()};

return CoercionResult::get_error ();
}
}

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 ();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe as in "this is allowed in unsafe contexts"? Or is it always forbidden?

}

if (!coerceable_mutability (from_mutbl, to_mutbl))
{
Location lhs = mappings->lookup_location (receiver->get_ref ());
Expand All @@ -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`.
Expand Down Expand Up @@ -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};
}
}
Expand Down Expand Up @@ -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}",
Expand Down
Loading