1431: Incremental refactor for better coercion site support r=philberty a=philberty

This is the major refactor to get our coercion site code closer to Rustc.
It introduced several new pieces most notably a refactor to the autoderef
cycle so this can be reused in method resolution and in coercion sites which
allows us to handle deref coercions. It will eventually allow us to get rid
of our bad implementation in rust-tyty-coercion.h which is just messy now.

Fixes #1198 

Co-authored-by: Philip Herron <philip.herron@embecosm.com>
This commit is contained in:
bors[bot] 2022-08-05 10:09:20 +00:00 committed by GitHub
commit a39108dea1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1122 additions and 767 deletions

View File

@ -106,6 +106,7 @@ GRS_OBJS = \
rust/rust-pub-restricted-visitor.o \
rust/rust-privacy-reporter.o \
rust/rust-tyty.o \
rust/rust-tyty-call.o \
rust/rust-tyctx.o \
rust/rust-tyty-bounds.o \
rust/rust-hir-type-check-util.o \
@ -117,6 +118,7 @@ GRS_OBJS = \
rust/rust-hir-type-check-pattern.o \
rust/rust-hir-type-check-expr.o \
rust/rust-hir-dot-operator.o \
rust/rust-coercion.o \
rust/rust-hir-type-check-base.o \
rust/rust-autoderef.o \
rust/rust-substitution-mapper.o \

View File

@ -411,7 +411,7 @@ HIRCompileBase::mark_addressable (tree exp, Location locus)
}
tree
HIRCompileBase::address_expression (tree expr, tree ptrtype, Location location)
HIRCompileBase::address_expression (tree expr, Location location)
{
if (expr == error_mark_node)
return error_mark_node;
@ -419,8 +419,16 @@ HIRCompileBase::address_expression (tree expr, tree ptrtype, Location location)
if (!mark_addressable (expr, location))
return error_mark_node;
return build_fold_addr_expr_with_type_loc (location.gcc_location (), expr,
ptrtype);
return build_fold_addr_expr_loc (location.gcc_location (), expr);
}
tree
HIRCompileBase::indirect_expression (tree expr, Location locus)
{
if (expr == error_mark_node)
return error_mark_node;
return build_fold_indirect_ref_loc (locus.gcc_location (), expr);
}
std::vector<Bvariable *>

View File

@ -40,9 +40,12 @@ protected:
protected:
Context *get_context () { return ctx; }
tree coercion_site (tree rvalue, const TyTy::BaseType *actual,
tree coercion_site (HirId id, tree rvalue, const TyTy::BaseType *actual,
const 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,
Location rvalue_locus);
tree coerce_to_dyn_object (tree compiled_ref, const TyTy::BaseType *actual,
const TyTy::BaseType *expected,
@ -101,7 +104,9 @@ protected:
static void setup_abi_options (tree fndecl, ABI abi);
static tree address_expression (tree expr, tree ptrtype, Location locus);
static tree address_expression (tree expr, Location locus);
static tree indirect_expression (tree expr, Location locus);
static bool mark_addressable (tree, Location);

View File

@ -134,8 +134,7 @@ CompileExpr::visit (HIR::BorrowExpr &expr)
&tyty))
return;
tree ptrtype = TyTyResolveCompile::compile (ctx, tyty);
translated = address_expression (main_expr, ptrtype, expr.get_locus ());
translated = address_expression (main_expr, expr.get_locus ());
}
void
@ -175,10 +174,7 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
return;
}
bool known_valid = true;
translated
= ctx->get_backend ()->indirect_expression (expected_type, main_expr,
known_valid, expr.get_locus ());
translated = indirect_expression (main_expr, expr.get_locus ());
}
// Helper for sort_tuple_patterns.
@ -857,8 +853,9 @@ CompileExpr::visit (HIR::CallExpr &expr)
Location lvalue_locus
= ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
Location rvalue_locus = argument->get_locus ();
rvalue = coercion_site (rvalue, actual, expected, lvalue_locus,
rvalue_locus);
rvalue
= coercion_site (argument->get_mappings ().get_hirid (), rvalue,
actual, expected, lvalue_locus, rvalue_locus);
// add it to the list
arguments.push_back (rvalue);
@ -955,8 +952,8 @@ CompileExpr::visit (HIR::CallExpr &expr)
Location lvalue_locus
= ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
Location rvalue_locus = argument->get_locus ();
rvalue
= coercion_site (rvalue, actual, expected, lvalue_locus, rvalue_locus);
rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
actual, expected, lvalue_locus, rvalue_locus);
// add it to the list
args.push_back (rvalue);
@ -1039,9 +1036,11 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
}
// lookup the autoderef mappings
HirId autoderef_mappings_id
= expr.get_receiver ()->get_mappings ().get_hirid ();
std::vector<Resolver::Adjustment> *adjustments = nullptr;
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
expr.get_mappings ().get_hirid (), &adjustments);
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id,
&adjustments);
rust_assert (ok);
// apply adjustments for the fn call
@ -1071,8 +1070,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
Location lvalue_locus
= ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
Location rvalue_locus = argument->get_locus ();
rvalue
= coercion_site (rvalue, actual, expected, lvalue_locus, rvalue_locus);
rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue,
actual, expected, lvalue_locus, rvalue_locus);
// add it to the list
args.push_back (rvalue);
@ -1111,15 +1110,7 @@ CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn,
// get any indirection sorted out
if (receiver->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
auto indirect_ty = r->get_base ();
tree indrect_compiled_tyty
= TyTyResolveCompile::compile (ctx, indirect_ty);
tree indirect
= ctx->get_backend ()->indirect_expression (indrect_compiled_tyty,
receiver_ref, true,
expr_locus);
tree indirect = indirect_expression (receiver_ref, expr_locus);
receiver_ref = indirect;
}
@ -1149,17 +1140,8 @@ CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
{
// get any indirection sorted out
if (receiver->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver);
auto indirect_ty = r->get_base ();
tree indrect_compiled_tyty
= TyTyResolveCompile::compile (ctx, indirect_ty);
tree indirect
= ctx->get_backend ()->indirect_expression (indrect_compiled_tyty,
receiver_ref, true,
expr_locus);
tree indirect = indirect_expression (receiver_ref, expr_locus);
receiver_ref = indirect;
}
@ -1179,8 +1161,7 @@ CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref,
tree fn = NULL_TREE;
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
{
return address_expression (fn, build_pointer_type (TREE_TYPE (fn)),
expr_locus);
return address_expression (fn, expr_locus);
}
// Now we can try and resolve the address since this might be a forward
@ -1307,7 +1288,7 @@ CompileExpr::resolve_operator_overload (
// lookup the autoderef mappings
std::vector<Resolver::Adjustment> *adjustments = nullptr;
ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
expr.get_mappings ().get_hirid (), &adjustments);
expr.get_lvalue_mappings ().get_hirid (), &adjustments);
rust_assert (ok);
// apply adjustments for the fn call
@ -1440,8 +1421,7 @@ CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr,
auto base = ctx->get_backend ()->string_constant_expression (
literal_value.as_string ());
tree data = address_expression (base, build_pointer_type (TREE_TYPE (base)),
expr.get_locus ());
tree data = address_expression (base, expr.get_locus ());
TyTy::BaseType *usize = nullptr;
bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
@ -1487,8 +1467,7 @@ CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
vals,
expr.get_locus ());
return address_expression (constructed, build_pointer_type (array_type),
expr.get_locus ());
return address_expression (constructed, expr.get_locus ());
}
tree
@ -1734,10 +1713,7 @@ HIRCompileBase::resolve_adjustements (
case Resolver::Adjustment::AdjustmentType::MUT_REF: {
if (!SLICE_TYPE_P (TREE_TYPE (e)))
{
tree ptrtype
= TyTyResolveCompile::compile (ctx,
adjustment.get_expected ());
e = address_expression (e, ptrtype, locus);
e = address_expression (e, locus);
}
}
break;
@ -1785,10 +1761,7 @@ HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment,
!= Resolver::Adjustment::AdjustmentType::ERROR;
if (needs_borrow)
{
adjusted_argument
= address_expression (expression,
build_reference_type (TREE_TYPE (expression)),
locus);
adjusted_argument = address_expression (expression, locus);
}
// make the call
@ -1800,12 +1773,7 @@ tree
HIRCompileBase::resolve_indirection_adjustment (
Resolver::Adjustment &adjustment, tree expression, Location locus)
{
tree expected_type
= TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
return ctx->get_backend ()->indirect_expression (expected_type, expression,
true, /* known_valid*/
locus);
return indirect_expression (expression, locus);
}
tree
@ -1824,9 +1792,7 @@ HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment,
= TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
// make a constructor for this
tree data
= address_expression (expression,
build_reference_type (TREE_TYPE (expression)), locus);
tree data = address_expression (expression, locus);
// fetch the size from the domain
tree domain = TYPE_DOMAIN (expr_type);
@ -1919,8 +1885,7 @@ CompileExpr::visit (HIR::IdentifierExpr &expr)
else if (ctx->lookup_function_decl (ref, &fn))
{
TREE_USED (fn) = 1;
translated = address_expression (fn, build_pointer_type (TREE_TYPE (fn)),
expr.get_locus ());
translated = address_expression (fn, expr.get_locus ());
}
else if (ctx->lookup_var_decl (ref, &var))
{
@ -2091,20 +2056,10 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr)
return;
}
// lookup the expected type for this expression
TyTy::BaseType *tyty = nullptr;
bool ok
= ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
&tyty);
rust_assert (ok);
tree expected_type = TyTyResolveCompile::compile (ctx, tyty);
// rust deref always returns a reference from this overload then we can
// actually do the indirection
translated
= ctx->get_backend ()->indirect_expression (expected_type,
operator_overload_call,
true, expr.get_locus ());
= indirect_expression (operator_overload_call, expr.get_locus ());
return;
}
@ -2118,14 +2073,8 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr)
// do we need to add an indirect reference
if (array_expr_ty->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r
= static_cast<TyTy::ReferenceType *> (array_expr_ty);
TyTy::BaseType *tuple_type = r->get_base ();
tree array_tyty = TyTyResolveCompile::compile (ctx, tuple_type);
array_reference
= ctx->get_backend ()->indirect_expression (array_tyty, array_reference,
true, expr.get_locus ());
= indirect_expression (array_reference, expr.get_locus ());
}
translated

View File

@ -53,14 +53,7 @@ public:
// do we need to add an indirect reference
if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF)
{
TyTy::ReferenceType *r
= static_cast<TyTy::ReferenceType *> (tuple_expr_ty);
TyTy::BaseType *tuple_type = r->get_base ();
tree tuple_tyty = TyTyResolveCompile::compile (ctx, tuple_type);
tree indirect
= ctx->get_backend ()->indirect_expression (tuple_tyty, receiver_ref,
true, expr.get_locus ());
tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;
}
@ -184,9 +177,9 @@ public:
expr.get_rhs ()->get_mappings ().get_hirid (), &actual);
rust_assert (ok);
rvalue
= coercion_site (rvalue, actual, expected, expr.get_lhs ()->get_locus (),
expr.get_rhs ()->get_locus ());
rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual,
expected, expr.get_lhs ()->get_locus (),
expr.get_rhs ()->get_locus ());
tree assignment
= ctx->get_backend ()->assignment_statement (lvalue, rvalue,
@ -442,8 +435,9 @@ public:
if (ok)
{
rvalue = coercion_site (rvalue, actual, expected, lvalue_locus,
rvalue_locus);
rvalue
= coercion_site (argument->get_mappings ().get_hirid (), rvalue,
actual, expected, lvalue_locus, rvalue_locus);
}
// add it to the list
@ -476,7 +470,8 @@ public:
// compile/torture/struct_base_init_1.rs
if (ok)
{
rvalue = coercion_site (rvalue, actual, expected, lvalue_locus,
rvalue = coercion_site (argument->get_mappings ().get_hirid (),
rvalue, actual, expected, lvalue_locus,
rvalue_locus);
}
@ -552,10 +547,7 @@ public:
&field_index);
rust_assert (ok);
tree adt_tyty = TyTyResolveCompile::compile (ctx, adt);
tree indirect
= ctx->get_backend ()->indirect_expression (adt_tyty, receiver_ref,
true, expr.get_locus ());
tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;
}

View File

@ -110,10 +110,7 @@ public:
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
fntype->get_id (), fntype))
{
reference
= address_expression (lookup, build_pointer_type (TREE_TYPE (lookup)),
ref_locus);
reference = address_expression (lookup, ref_locus);
return;
}
@ -155,9 +152,7 @@ public:
ctx->insert_function_decl (fntype, fndecl);
reference
= address_expression (fndecl, build_pointer_type (TREE_TYPE (fndecl)),
ref_locus);
reference = address_expression (fndecl, ref_locus);
}
private:

View File

@ -67,10 +67,8 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func)
{
ctx->insert_function_decl (fntype, lookup);
}
reference
= address_expression (lookup,
build_pointer_type (TREE_TYPE (lookup)),
ref_locus);
reference = address_expression (lookup, ref_locus);
return;
}
}
@ -96,9 +94,7 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func)
func.get_outer_attrs (), func.get_locus (),
func.get_block_expr ().get (), canonical_path, fntype,
function.has_return_type ());
reference
= address_expression (fndecl, build_pointer_type (TREE_TYPE (fndecl)),
ref_locus);
reference = address_expression (fndecl, ref_locus);
}
} // namespace Compile

View File

@ -144,10 +144,7 @@ CompileItem::visit (HIR::Function &function)
ctx->insert_function_decl (fntype, lookup);
}
reference
= address_expression (lookup,
build_pointer_type (TREE_TYPE (lookup)),
ref_locus);
reference = address_expression (lookup, ref_locus);
return;
}
}
@ -171,9 +168,7 @@ CompileItem::visit (HIR::Function &function)
function.get_outer_attrs (), function.get_locus (),
function.get_definition ().get (), canonical_path,
fntype, function.has_function_return_type ());
reference
= address_expression (fndecl, build_pointer_type (TREE_TYPE (fndecl)),
ref_locus);
reference = address_expression (fndecl, ref_locus);
}
void

View File

@ -129,16 +129,14 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
{
TREE_USED (fn) = 1;
return address_expression (fn, build_pointer_type (TREE_TYPE (fn)),
expr_locus);
return address_expression (fn, expr_locus);
}
else if (fntype->get_abi () == ABI::INTRINSIC)
{
Intrinsics compile (ctx);
fn = compile.compile (fntype);
TREE_USED (fn) = 1;
return address_expression (fn, build_pointer_type (TREE_TYPE (fn)),
expr_locus);
return address_expression (fn, expr_locus);
}
}

View File

@ -87,7 +87,8 @@ public:
Location lvalue_locus = stmt.get_pattern ()->get_locus ();
Location rvalue_locus = stmt.get_init_expr ()->get_locus ();
TyTy::BaseType *expected = ty;
init = coercion_site (init, actual, expected, lvalue_locus, rvalue_locus);
init = coercion_site (stmt.get_mappings ().get_hirid (), init, actual,
expected, lvalue_locus, rvalue_locus);
auto fnctx = ctx->peek_fn ();
if (ty->is_unit ())

View File

@ -198,9 +198,25 @@ CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field)
// Shared methods in compilation
tree
HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval,
HIRCompileBase::coercion_site (HirId id, tree rvalue,
const TyTy::BaseType *rval,
const 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);
if (ok)
{
rvalue = resolve_adjustements (*adjustments, rvalue, rvalue_locus);
}
return coercion_site1 (rvalue, rval, lval, lvalue_locus, rvalue_locus);
}
tree
HIRCompileBase::coercion_site1 (tree rvalue, const TyTy::BaseType *rval,
const TyTy::BaseType *lval,
Location lvalue_locus, Location rvalue_locus)
{
if (rvalue == error_mark_node)
return error_mark_node;
@ -225,20 +241,14 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval,
const TyTy::ReferenceType *act
= static_cast<const TyTy::ReferenceType *> (actual);
tree expected_type = TyTyResolveCompile::compile (ctx, act->get_base ());
tree deref_rvalue
= ctx->get_backend ()->indirect_expression (expected_type, rvalue,
false /*known_valid*/,
rvalue_locus);
tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
tree coerced
= coercion_site (deref_rvalue, act->get_base (), exp->get_base (),
lvalue_locus, rvalue_locus);
= coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (),
lvalue_locus, rvalue_locus);
if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced)))
return coerced;
return address_expression (coerced,
build_reference_type (TREE_TYPE (coerced)),
rvalue_locus);
return address_expression (coerced, rvalue_locus);
}
else if (expected->get_kind () == TyTy::TypeKind::POINTER)
{
@ -258,14 +268,12 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval,
= static_cast<const TyTy::ReferenceType *> (expected);
TyTy::BaseType *actual_base = nullptr;
tree expected_type = error_mark_node;
if (actual->get_kind () == TyTy::TypeKind::REF)
{
const TyTy::ReferenceType *act
= static_cast<const TyTy::ReferenceType *> (actual);
actual_base = act->get_base ();
expected_type = TyTyResolveCompile::compile (ctx, act->get_base ());
}
else if (actual->get_kind () == TyTy::TypeKind::POINTER)
{
@ -273,22 +281,18 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval,
= static_cast<const TyTy::PointerType *> (actual);
actual_base = act->get_base ();
expected_type = TyTyResolveCompile::compile (ctx, act->get_base ());
}
rust_assert (actual_base != nullptr);
tree deref_rvalue
= ctx->get_backend ()->indirect_expression (expected_type, rvalue,
false /*known_valid*/,
rvalue_locus);
tree coerced = coercion_site (deref_rvalue, actual_base, exp->get_base (),
lvalue_locus, rvalue_locus);
tree deref_rvalue = indirect_expression (rvalue, rvalue_locus);
tree coerced
= coercion_site1 (deref_rvalue, actual_base, exp->get_base (),
lvalue_locus, rvalue_locus);
if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced)))
return coerced;
return address_expression (coerced,
build_pointer_type (TREE_TYPE (coerced)),
rvalue_locus);
return address_expression (coerced, rvalue_locus);
}
else if (expected->get_kind () == TyTy::TypeKind::ARRAY)
{
@ -350,10 +354,7 @@ HIRCompileBase::coerce_to_dyn_object (tree compiled_ref,
tree address_of_compiled_ref = null_pointer_node;
if (!actual->is_unit ())
address_of_compiled_ref
= address_expression (compiled_ref,
build_pointer_type (TREE_TYPE (compiled_ref)),
locus);
address_of_compiled_ref = address_expression (compiled_ref, locus);
std::vector<tree> vtable_ctor_elems;
std::vector<unsigned long> vtable_ctor_idx;

View File

@ -4120,31 +4120,47 @@ class OperatorExprMeta
{
public:
OperatorExprMeta (HIR::CompoundAssignmentExpr &expr)
: node_mappings (expr.get_mappings ()), locus (expr.get_locus ())
: node_mappings (expr.get_mappings ()),
lvalue_mappings (expr.get_expr ()->get_mappings ()),
locus (expr.get_locus ())
{}
OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr)
: node_mappings (expr.get_mappings ()), locus (expr.get_locus ())
: node_mappings (expr.get_mappings ()),
lvalue_mappings (expr.get_expr ()->get_mappings ()),
locus (expr.get_locus ())
{}
OperatorExprMeta (HIR::NegationExpr &expr)
: node_mappings (expr.get_mappings ()), locus (expr.get_locus ())
: node_mappings (expr.get_mappings ()),
lvalue_mappings (expr.get_expr ()->get_mappings ()),
locus (expr.get_locus ())
{}
OperatorExprMeta (HIR::DereferenceExpr &expr)
: node_mappings (expr.get_mappings ()), locus (expr.get_locus ())
: node_mappings (expr.get_mappings ()),
lvalue_mappings (expr.get_expr ()->get_mappings ()),
locus (expr.get_locus ())
{}
OperatorExprMeta (HIR::ArrayIndexExpr &expr)
: node_mappings (expr.get_mappings ()), locus (expr.get_locus ())
: node_mappings (expr.get_mappings ()),
lvalue_mappings (expr.get_array_expr ()->get_mappings ()),
locus (expr.get_locus ())
{}
const Analysis::NodeMapping &get_mappings () const { return node_mappings; }
const Analysis::NodeMapping &get_lvalue_mappings () const
{
return lvalue_mappings;
}
Location get_locus () const { return locus; }
private:
const Analysis::NodeMapping node_mappings;
const Analysis::NodeMapping lvalue_mappings;
Location locus;
};

View File

@ -178,14 +178,6 @@ public:
// Create a reference to a variable.
virtual tree var_expression (Bvariable *var, Location) = 0;
// Create an expression that indirects through the pointer expression EXPR
// (i.e., return the expression for *EXPR). KNOWN_VALID is true if the pointer
// is known to point to a valid memory location. BTYPE is the expected type
// of the indirected EXPR.
virtual tree indirect_expression (tree btype, tree expr, bool known_valid,
Location)
= 0;
// Return an expression for the multi-precision integer VAL in BTYPE.
virtual tree integer_constant_expression (tree btype, mpz_t val) = 0;

View File

@ -201,8 +201,6 @@ public:
tree var_expression (Bvariable *var, Location);
tree indirect_expression (tree, tree expr, bool known_valid, Location);
tree integer_constant_expression (tree type, mpz_t val);
tree float_constant_expression (tree type, mpfr_t val);
@ -1053,28 +1051,6 @@ Gcc_backend::var_expression (Bvariable *var, Location location)
return var->get_tree (location);
}
// An expression that indirectly references an expression.
tree
Gcc_backend::indirect_expression (tree type_tree, tree expr_tree,
bool known_valid, Location location)
{
if (expr_tree == error_mark_node || type_tree == error_mark_node)
return error_mark_node;
// If the type of EXPR is a recursive pointer type, then we
// need to insert a cast before indirecting.
tree target_type_tree = TREE_TYPE (TREE_TYPE (expr_tree));
if (VOID_TYPE_P (target_type_tree))
expr_tree = fold_convert_loc (location.gcc_location (),
build_pointer_type (type_tree), expr_tree);
tree ret = build_fold_indirect_ref_loc (location.gcc_location (), expr_tree);
if (known_valid)
TREE_THIS_NOTRAP (ret) = 1;
return ret;
}
// Return a typed value as a constant integer.
tree

View File

@ -268,5 +268,129 @@ resolve_operator_overload_fn (
return true;
}
AutoderefCycle::AutoderefCycle (bool autoderef_flag)
: autoderef_flag (autoderef_flag)
{}
AutoderefCycle::~AutoderefCycle () {}
void
AutoderefCycle::try_hook (const TyTy::BaseType &)
{}
bool
AutoderefCycle::cycle (const TyTy::BaseType *receiver)
{
const TyTy::BaseType *r = receiver;
while (true)
{
if (try_autoderefed (r))
return true;
// 4. deref to to 1, if cannot deref then quit
if (autoderef_flag)
return false;
// try unsize
Adjustment unsize = Adjuster::try_unsize_type (r);
if (!unsize.is_error ())
{
adjustments.push_back (unsize);
auto unsize_r = unsize.get_expected ();
if (try_autoderefed (unsize_r))
return true;
adjustments.pop_back ();
}
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);
if (try_autoderefed (deref_r))
return true;
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);
if (try_autoderefed (deref_r))
return true;
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 ();
if (try_autoderefed (deref_r))
return true;
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 false;
r = raw_deref.get_expected ();
adjustments.push_back (raw_deref);
}
return false;
}
bool
AutoderefCycle::try_autoderefed (const TyTy::BaseType *r)
{
try_hook (*r);
// 1. try raw
if (select (*r))
return true;
// 2. try ref
TyTy::ReferenceType *r1
= new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
Mutability::Imm);
adjustments.push_back (Adjustment (Adjustment::AdjustmentType::IMM_REF, r1));
if (select (*r1))
return true;
adjustments.pop_back ();
// 3. try mut ref
TyTy::ReferenceType *r2
= new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
Mutability::Mut);
adjustments.push_back (Adjustment (Adjustment::AdjustmentType::MUT_REF, r2));
if (select (*r2))
return true;
adjustments.pop_back ();
return false;
}
} // namespace Resolver
} // namespace Rust

View File

@ -144,6 +144,27 @@ private:
const TyTy::BaseType *base;
};
class AutoderefCycle
{
protected:
AutoderefCycle (bool autoderef_flag);
virtual ~AutoderefCycle ();
virtual bool select (const 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);
bool try_autoderefed (const TyTy::BaseType *r);
bool autoderef_flag;
std::vector<Adjustment> adjustments;
};
} // namespace Resolver
} // namespace Rust

View File

@ -0,0 +1,92 @@
// 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-coercion.h"
namespace Rust {
namespace Resolver {
AutoderefTypeCoercion::CoercionResult
AutoderefTypeCoercion::Coerce (const TyTy::BaseType *receiver,
const TyTy::BaseType *expected, Location locus)
{
AutoderefTypeCoercion resolver (expected, locus);
bool ok = resolver.cycle (receiver);
return ok ? resolver.try_result : CoercionResult::get_error ();
}
AutoderefTypeCoercion::AutoderefTypeCoercion (const TyTy::BaseType *expected,
Location locus)
: AutoderefCycle (false), mappings (Analysis::Mappings::get ()),
context (TypeCheckContext::get ()), expected (expected), locus (locus),
try_result (CoercionResult::get_error ())
{}
bool
AutoderefTypeCoercion::cycle (const TyTy::BaseType *receiver)
{
// FIXME this is not finished and might be super simplified
// see:
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs
if (receiver->get_kind () == TyTy::TypeKind::REF
&& expected->get_kind () == TyTy::TypeKind::REF)
{
// if we expect to get a mutable pointer we can't get that from an
// immutable one so we have to be careful
const auto &receiver_ref
= static_cast<const TyTy::ReferenceType &> (*receiver);
const auto &expected_ref
= static_cast<const TyTy::ReferenceType &> (*expected);
// we can allow for mutability changes here by casting down from
// mutability eg: mut vs const, we cant take a mutable reference from a
// const eg: const vs mut we can take a const reference from a mutable
// one
bool mutability_ok
= !expected_ref.is_mutable ()
|| (expected_ref.is_mutable () == receiver_ref.is_mutable ());
if (!mutability_ok)
{
RichLocation r (locus);
r.add_range (mappings->lookup_location (receiver_ref.get_ref ()));
r.add_range (mappings->lookup_location (expected_ref.get_ref ()));
rust_error_at (r, "mismatched mutability");
return false;
}
}
return AutoderefCycle::cycle (receiver);
}
bool
AutoderefTypeCoercion::select (const TyTy::BaseType &autoderefed)
{
if (autoderefed.can_eq (expected, false))
{
try_result = CoercionResult{adjustments, autoderefed.clone ()};
return true;
}
return false;
}
} // namespace Resolver
} // namespace Rust

View File

@ -0,0 +1,70 @@
// 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/>.
#ifndef RUST_COERCION
#define RUST_COERCION
#include "rust-autoderef.h"
#include "rust-hir-type-check.h"
namespace Rust {
namespace Resolver {
class AutoderefTypeCoercion : protected AutoderefCycle
{
public:
struct CoercionResult
{
std::vector<Adjustment> adjustments;
TyTy::BaseType *tyty;
bool is_error ()
{
return tyty == nullptr || tyty->get_kind () == TyTy::TypeKind::ERROR;
}
static CoercionResult get_error () { return CoercionResult{{}, nullptr}; }
};
static CoercionResult Coerce (const TyTy::BaseType *receiver,
const TyTy::BaseType *expected, Location locus);
protected:
AutoderefTypeCoercion (const TyTy::BaseType *expected, Location locus);
bool cycle (const TyTy::BaseType *receiver) override;
bool select (const TyTy::BaseType &autoderefed) override;
private:
// context info
Analysis::Mappings *mappings;
TypeCheckContext *context;
// search
const TyTy::BaseType *expected;
Location locus;
// mutable fields
CoercionResult try_result;
};
} // namespace Resolver
} // namespace Rust
#endif // RUST_COERCION

View File

@ -23,151 +23,32 @@
namespace Rust {
namespace Resolver {
MethodResolver::MethodResolver (bool autoderef_flag,
const HIR::PathIdentSegment &segment_name)
: AutoderefCycle (autoderef_flag), mappings (Analysis::Mappings::get ()),
context (TypeCheckContext::get ()), segment_name (segment_name),
try_result (MethodCandidate::get_error ())
{}
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 ();
// try unsize
Adjustment unsize = Adjuster::try_unsize_type (r);
if (!unsize.is_error ())
{
adjustments.push_back (unsize);
auto unsize_r = unsize.get_expected ();
auto res = Try (unsize_r, segment_name, adjustments);
if (!res.is_error ())
{
return res;
}
adjustments.pop_back ();
}
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 ();
MethodResolver resolver (autoderef_flag, segment_name);
bool ok = resolver.cycle (receiver);
return ok ? resolver.try_result : MethodCandidate::get_error ();
}
MethodCandidate
MethodResolver::Try (const TyTy::BaseType *r,
const HIR::PathIdentSegment &segment_name,
std::vector<Adjustment> &adjustments)
void
MethodResolver::try_hook (const TyTy::BaseType &r)
{
PathProbeCandidate c = PathProbeCandidate::get_error ();
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds
= r->get_specified_bounds ();
const std::vector<MethodResolver::predicate_candidate> predicate_items
= get_predicate_items (segment_name, *r, specified_bounds);
// 1. try raw
MethodResolver raw (*r, segment_name, predicate_items);
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, predicate_items);
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, predicate_items);
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 ();
const auto &specified_bounds = r.get_specified_bounds ();
predicate_items = get_predicate_items (segment_name, r, specified_bounds);
}
PathProbeCandidate
MethodResolver::select ()
bool
MethodResolver::select (const TyTy::BaseType &receiver)
{
struct impl_item_candidate
{
@ -300,9 +181,11 @@ MethodResolver::select ()
{
PathProbeCandidate::ImplItemCandidate c{impl_item.item,
impl_item.impl_block};
return PathProbeCandidate (
PathProbeCandidate::CandidateType::IMPL_FUNC, fn,
impl_item.item->get_locus (), c);
try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
fn, impl_item.item->get_locus (), c),
adjustments};
return true;
}
}
@ -317,9 +200,11 @@ MethodResolver::select ()
PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
trait_item.item_ref,
nullptr};
return PathProbeCandidate (
PathProbeCandidate::CandidateType::TRAIT_FUNC, fn,
trait_item.item->get_locus (), c);
try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
fn, trait_item.item->get_locus (), c),
adjustments};
return true;
}
}
@ -338,13 +223,15 @@ MethodResolver::select ()
PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
nullptr};
return PathProbeCandidate (
PathProbeCandidate::CandidateType::TRAIT_FUNC, fn->clone (),
trait_item->get_locus (), c);
try_result = MethodCandidate{
PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
fn->clone (), trait_item->get_locus (), c),
adjustments};
return true;
}
}
return PathProbeCandidate::get_error ();
return false;
}
std::vector<MethodResolver::predicate_candidate>

View File

@ -37,43 +37,42 @@ struct MethodCandidate
bool is_error () const { return candidate.is_error (); }
};
class MethodResolver : public TypeCheckBase
class MethodResolver : protected AutoderefCycle
{
protected:
using Rust::Resolver::TypeCheckBase::visit;
public:
static MethodCandidate Probe (const TyTy::BaseType *receiver,
const HIR::PathIdentSegment &segment_name,
bool autoderef_flag = false);
protected:
struct predicate_candidate
{
TyTy::TypeBoundPredicateItem lookup;
TyTy::FnType *fntype;
};
static MethodCandidate Try (const TyTy::BaseType *r,
const HIR::PathIdentSegment &segment_name,
std::vector<Adjustment> &adjustments);
static MethodCandidate Probe (const TyTy::BaseType *receiver,
const HIR::PathIdentSegment &segment_name,
bool autoderef_flag = false);
static std::vector<predicate_candidate> get_predicate_items (
const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
PathProbeCandidate select ();
protected:
MethodResolver (bool autoderef_flag,
const HIR::PathIdentSegment &segment_name);
MethodResolver (
const TyTy::BaseType &receiver, const HIR::PathIdentSegment &segment_name,
const std::vector<MethodResolver::predicate_candidate> &predicate_items)
: receiver (receiver), segment_name (segment_name),
predicate_items (predicate_items)
{}
void try_hook (const TyTy::BaseType &r) override;
const TyTy::BaseType &receiver;
bool select (const TyTy::BaseType &receiver) override;
private:
// context info
Analysis::Mappings *mappings;
TypeCheckContext *context;
// search
const HIR::PathIdentSegment &segment_name;
const std::vector<MethodResolver::predicate_candidate> &predicate_items;
std::vector<MethodResolver::predicate_candidate> predicate_items;
// mutable fields
MethodCandidate try_result;
};
} // namespace Resolver

View File

@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-base.h"
#include "rust-coercion.h"
namespace Rust {
namespace Resolver {
@ -327,5 +328,26 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, Location locus)
return repr;
}
TyTy::BaseType *
TypeCheckBase::coercion_site (HirId id, TyTy::BaseType *expected,
TyTy::BaseType *expr, Location locus)
{
auto context = TypeCheckContext::get ();
if (expected->get_kind () == TyTy::TypeKind::ERROR
|| expr->get_kind () == TyTy::TypeKind::ERROR)
return expr;
// can we autoderef it?
auto result = AutoderefTypeCoercion::Coerce (expr, expected, locus);
if (!result.is_error ())
{
// save any adjustments
context->insert_autoderef_mappings (id, std::move (result.adjustments));
return expected->coerce (result.tyty);
}
return expected->coerce (expr);
}
} // namespace Resolver
} // namespace Rust

View File

@ -39,6 +39,9 @@ public:
virtual ~TypeCheckBase () {}
static TyTy::BaseType *coercion_site (HirId id, TyTy::BaseType *lhs,
TyTy::BaseType *rhs, Location locus);
protected:
TypeCheckBase ()
: mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()),

View File

@ -295,6 +295,161 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
infered = array_type->get_element_type ()->clone ();
}
void
TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
{
auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ());
if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_receiver ()->get_locus (),
"failed to resolve receiver in MethodCallExpr");
return;
}
context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
auto candidate
= MethodResolver::Probe (receiver_tyty,
expr.get_method_name ().get_segment ());
if (candidate.is_error ())
{
rust_error_at (
expr.get_method_name ().get_locus (),
"failed to resolve method for %<%s%>",
expr.get_method_name ().get_segment ().as_string ().c_str ());
return;
}
// Get the adjusted self
Adjuster adj (receiver_tyty);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
// 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
// ICE when an argument is a method call
HirId autoderef_mappings_id
= expr.get_receiver ()->get_mappings ().get_hirid ();
context->insert_autoderef_mappings (autoderef_mappings_id,
std::move (candidate.adjustments));
PathProbeCandidate &resolved_candidate = candidate.candidate;
TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
NodeId resolved_node_id
= resolved_candidate.is_impl_candidate ()
? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
.get_nodeid ()
: resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
{
RichLocation r (expr.get_method_name ().get_locus ());
r.add_range (resolved_candidate.locus);
rust_error_at (r, "associated impl item is not a method");
return;
}
TyTy::BaseType *lookup = lookup_tyty;
TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
if (!fn->is_method ())
{
RichLocation r (expr.get_method_name ().get_locus ());
r.add_range (resolved_candidate.locus);
rust_error_at (r, "associated function is not a method");
return;
}
auto root = receiver_tyty->get_root ();
if (root->get_kind () == TyTy::TypeKind::ADT)
{
const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
if (adt->has_substitutions () && fn->needs_substitution ())
{
// consider the case where we have:
//
// struct Foo<X,Y>(X,Y);
//
// impl<T> Foo<T, i32> {
// fn test<X>(self, a:X) -> (T,X) { (self.0, a) }
// }
//
// In this case we end up with an fn type of:
//
// fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X)
//
// This means the instance or self we are calling this method for
// will be substituted such that we can get the inherited type
// arguments but then need to use the turbo fish if available or
// infer the remaining arguments. Luckily rust does not allow for
// default types GenericParams on impl blocks since these must
// always be at the end of the list
auto s = fn->get_self_type ()->get_root ();
rust_assert (s->can_eq (adt, false));
rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
const TyTy::ADTType *self_adt
= static_cast<const TyTy::ADTType *> (s);
// we need to grab the Self substitutions as the inherit type
// parameters for this
if (self_adt->needs_substitution ())
{
rust_assert (adt->was_substituted ());
TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
= GetUsedSubstArgs::From (adt);
TyTy::SubstitutionArgumentMappings inherit_type_args
= self_adt->solve_mappings_from_receiver_for_self (
used_args_in_prev_segment);
// there may or may not be inherited type arguments
if (!inherit_type_args.is_error ())
{
// need to apply the inherited type arguments to the
// function
lookup = fn->handle_substitions (inherit_type_args);
}
}
}
}
// apply any remaining generic arguments
if (expr.get_method_name ().has_generic_args ())
{
HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
lookup
= SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
&args);
if (lookup->get_kind () == TyTy::TypeKind::ERROR)
return;
}
else if (lookup->needs_generic_substitutions ())
{
lookup = SubstMapper::InferSubst (lookup,
expr.get_method_name ().get_locus ());
}
TyTy::BaseType *function_ret_tyty
= TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self, context);
if (function_ret_tyty == nullptr
|| function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_locus (),
"failed to lookup type to MethodCallExpr");
return;
}
// store the expected fntype
context->insert_type (expr.get_method_name ().get_mappings (), lookup);
// set up the resolved name on the path
resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
resolved_node_id);
// return the result of the function back
infered = function_ret_tyty;
}
bool
TypeCheckExpr::resolve_operator_overload (
Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExprMeta expr,
@ -365,7 +520,7 @@ TypeCheckExpr::resolve_operator_overload (
}
// store the adjustments for code-generation to know what to do
context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
std::move (candidate.adjustments));
// now its just like a method-call-expr

View File

@ -220,157 +220,7 @@ public:
= TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
}
void visit (HIR::MethodCallExpr &expr) override
{
auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ());
if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_receiver ()->get_locus (),
"failed to resolve receiver in MethodCallExpr");
return;
}
context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
auto candidate
= MethodResolver::Probe (receiver_tyty,
expr.get_method_name ().get_segment ());
if (candidate.is_error ())
{
rust_error_at (
expr.get_method_name ().get_locus (),
"failed to resolve method for %<%s%>",
expr.get_method_name ().get_segment ().as_string ().c_str ());
return;
}
// Get the adjusted self
Adjuster adj (receiver_tyty);
TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
// store the adjustments for code-generation to know what to do
context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
std::move (candidate.adjustments));
PathProbeCandidate &resolved_candidate = candidate.candidate;
TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
NodeId resolved_node_id
= resolved_candidate.is_impl_candidate ()
? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
.get_nodeid ()
: resolved_candidate.item.trait.item_ref->get_mappings ()
.get_nodeid ();
if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
{
RichLocation r (expr.get_method_name ().get_locus ());
r.add_range (resolved_candidate.locus);
rust_error_at (r, "associated impl item is not a method");
return;
}
TyTy::BaseType *lookup = lookup_tyty;
TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
if (!fn->is_method ())
{
RichLocation r (expr.get_method_name ().get_locus ());
r.add_range (resolved_candidate.locus);
rust_error_at (r, "associated function is not a method");
return;
}
auto root = receiver_tyty->get_root ();
if (root->get_kind () == TyTy::TypeKind::ADT)
{
const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root);
if (adt->has_substitutions () && fn->needs_substitution ())
{
// consider the case where we have:
//
// struct Foo<X,Y>(X,Y);
//
// impl<T> Foo<T, i32> {
// fn test<X>(self, a:X) -> (T,X) { (self.0, a) }
// }
//
// In this case we end up with an fn type of:
//
// fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X)
//
// This means the instance or self we are calling this method for
// will be substituted such that we can get the inherited type
// arguments but then need to use the turbo fish if available or
// infer the remaining arguments. Luckily rust does not allow for
// default types GenericParams on impl blocks since these must
// always be at the end of the list
auto s = fn->get_self_type ()->get_root ();
rust_assert (s->can_eq (adt, false));
rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
const TyTy::ADTType *self_adt
= static_cast<const TyTy::ADTType *> (s);
// we need to grab the Self substitutions as the inherit type
// parameters for this
if (self_adt->needs_substitution ())
{
rust_assert (adt->was_substituted ());
TyTy::SubstitutionArgumentMappings used_args_in_prev_segment
= GetUsedSubstArgs::From (adt);
TyTy::SubstitutionArgumentMappings inherit_type_args
= self_adt->solve_mappings_from_receiver_for_self (
used_args_in_prev_segment);
// there may or may not be inherited type arguments
if (!inherit_type_args.is_error ())
{
// need to apply the inherited type arguments to the
// function
lookup = fn->handle_substitions (inherit_type_args);
}
}
}
}
// apply any remaining generic arguments
if (expr.get_method_name ().has_generic_args ())
{
HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
lookup
= SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
&args);
if (lookup->get_kind () == TyTy::TypeKind::ERROR)
return;
}
else if (lookup->needs_generic_substitutions ())
{
lookup = SubstMapper::InferSubst (lookup,
expr.get_method_name ().get_locus ());
}
TyTy::BaseType *function_ret_tyty
= TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self,
context);
if (function_ret_tyty == nullptr
|| function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_locus (),
"failed to lookup type to MethodCallExpr");
return;
}
// store the expected fntype
context->insert_type (expr.get_method_name ().get_mappings (), lookup);
// set up the resolved name on the path
resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
resolved_node_id);
// return the result of the function back
infered = function_ret_tyty;
}
void visit (HIR::MethodCallExpr &expr) override;
void visit (HIR::AssignmentExpr &expr) override
{
@ -380,7 +230,8 @@ public:
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
lhs->coerce (rhs);
coercion_site (expr.get_mappings ().get_hirid (), lhs, rhs,
expr.get_locus ());
}
void visit (HIR::CompoundAssignmentExpr &expr) override

View File

@ -99,7 +99,8 @@ public:
if (specified_ty != nullptr && init_expr_ty != nullptr)
{
// FIXME use this result and look at the regressions
specified_ty->coerce (init_expr_ty);
coercion_site (stmt.get_mappings ().get_hirid (), specified_ty,
init_expr_ty, stmt.get_locus ());
context->insert_type (stmt_pattern.get_pattern_mappings (),
specified_ty);
}

View File

@ -42,8 +42,8 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
{
TyTy::BaseType *base_resolved
= TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ());
struct_def
= (TyTy::ADTType *) struct_path_resolved->coerce (base_resolved);
struct_def = static_cast<TyTy::ADTType *> (
struct_path_resolved->coerce (base_resolved));
if (struct_def == nullptr)
{
rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (),
@ -221,7 +221,9 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
}
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field.get_mappings ().get_hirid (),
field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{
fields_assigned.insert (field.field_name);
@ -250,7 +252,9 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
}
TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ());
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field.get_mappings ().get_hirid (),
field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{
fields_assigned.insert (field_name);
@ -284,7 +288,9 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field)
field.get_locus ());
TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr);
resolved_field_value_expr = field_type->get_field_type ()->coerce (value);
resolved_field_value_expr
= coercion_site (field.get_mappings ().get_hirid (),
field_type->get_field_type (), value, field.get_locus ());
if (resolved_field_value_expr != nullptr)
{

View File

@ -0,0 +1,269 @@
// 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-tyty-call.h"
#include "rust-hir-type-check-expr.h"
namespace Rust {
namespace TyTy {
void
TypeCheckCallExpr::visit (ADTType &type)
{
rust_assert (!variant.is_error ());
if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
rust_error_at (
call.get_locus (),
"expected function, tuple struct or tuple variant, found struct %<%s%>",
type.get_name ().c_str ());
return;
}
if (call.num_params () != variant.num_fields ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) variant.num_fields ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
StructFieldType *field = variant.get_field_at_index (i);
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
if (arg->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"failed to resolve argument type");
return;
}
auto res = Resolver::TypeCheckBase::coercion_site (
argument->get_mappings ().get_hirid (), field_tyty, arg,
argument->get_locus ());
if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return;
}
delete res;
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.clone ();
}
void
TypeCheckCallExpr::visit (FnType &type)
{
type.monomorphize ();
if (call.num_params () != type.num_params ())
{
if (type.is_varadic ())
{
if (call.num_params () < type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
else
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
// it might be a varadic function
if (i < type.num_params ())
{
auto fnparam = type.param_at (i);
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
argument->get_mappings ().get_hirid (), fnparam.second,
argument_expr_tyty, argument->get_locus ());
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i < call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->clone ();
}
void
TypeCheckCallExpr::visit (FnPtr &type)
{
if (call.num_params () != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
argument->get_mappings ().get_hirid (), fnparam, argument_expr_tyty,
argument->get_locus ());
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.get_return_type ()->monomorphized_clone ();
}
// method call checker
void
TypeCheckMethodCallExpr::visit (FnType &type)
{
type.get_self_type ()->unify (adjusted_self);
// +1 for the receiver self
size_t num_args_to_call = call.num_params () + 1;
if (num_args_to_call != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 1;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = Resolver::TypeCheckBase::coercion_site (
argument->get_mappings ().get_hirid (), fnparam.second,
argument_expr_tyty, argument->get_locus ());
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != num_args_to_call)
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->monomorphized_clone ();
}
} // namespace TyTy
} // namespace Rust

View File

@ -36,12 +36,7 @@ public:
if (other->get_kind () == TypeKind::PARAM)
{
const ParamType *p = static_cast<const ParamType *> (other);
if (p->can_resolve ())
{
const BaseType *resolved = p->resolve ();
resolved->accept_vis (*this);
return ok;
}
other = p->resolve ();
}
if (other->get_kind () == TypeKind::PLACEHOLDER)
{
@ -861,6 +856,17 @@ public:
: BaseCmp (base, emit_errors), base (base)
{}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const ClosureType *base;
@ -889,6 +895,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const ArrayType *base;
@ -917,6 +934,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const SliceType *base;
@ -1074,6 +1102,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const ADTType *base;
@ -1111,6 +1150,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const TupleType *base;
@ -1209,6 +1259,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const ReferenceType *base;
@ -1246,6 +1307,17 @@ public:
ok = true;
}
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const PointerType *base;
@ -1344,6 +1416,17 @@ public:
void visit (const StrType &type) override { ok = true; }
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const StrType *base;
@ -1360,6 +1443,17 @@ public:
void visit (const NeverType &type) override { ok = true; }
void visit (const InferType &type) override
{
if (type.get_infer_kind () != InferType::InferTypeKind::GENERAL)
{
BaseCmp::visit (type);
return;
}
ok = true;
}
private:
const BaseType *get_base () const override { return base; }
const NeverType *base;

View File

@ -3205,243 +3205,5 @@ DynamicObjectType::get_object_items () const
return items;
}
// rust-tyty-call.h
void
TypeCheckCallExpr::visit (ADTType &type)
{
rust_assert (!variant.is_error ());
if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
rust_error_at (
call.get_locus (),
"expected function, tuple struct or tuple variant, found struct %<%s%>",
type.get_name ().c_str ());
return;
}
if (call.num_params () != variant.num_fields ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) variant.num_fields ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
StructFieldType *field = variant.get_field_at_index (i);
BaseType *field_tyty = field->get_field_type ();
BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
if (arg->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"failed to resolve argument type");
return;
}
auto res = field_tyty->coerce (arg);
if (res->get_kind () == TyTy::TypeKind::ERROR)
{
return;
}
delete res;
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.clone ();
}
void
TypeCheckCallExpr::visit (FnType &type)
{
type.monomorphize ();
if (call.num_params () != type.num_params ())
{
if (type.is_varadic ())
{
if (call.num_params () < type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
else
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
// it might be a varadic function
if (i < type.num_params ())
{
auto fnparam = type.param_at (i);
auto resolved_argument_type
= fnparam.second->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i < call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->clone ();
}
void
TypeCheckCallExpr::visit (FnPtr &type)
{
if (call.num_params () != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 0;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = fnparam->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != call.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
resolved = type.get_return_type ()->monomorphized_clone ();
}
// method call checker
void
TypeCheckMethodCallExpr::visit (FnType &type)
{
type.get_self_type ()->unify (adjusted_self);
// +1 for the receiver self
size_t num_args_to_call = call.num_params () + 1;
if (num_args_to_call != type.num_params ())
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) call.num_params (),
(unsigned long) type.num_params ());
return;
}
size_t i = 1;
for (auto &argument : call.get_arguments ())
{
auto fnparam = type.param_at (i);
auto argument_expr_tyty
= Resolver::TypeCheckExpr::Resolve (argument.get ());
if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (
argument->get_locus (),
"failed to resolve type for argument expr in CallExpr");
return;
}
auto resolved_argument_type = fnparam.second->coerce (argument_expr_tyty);
if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (argument->get_locus (),
"Type Resolution failure on parameter");
return;
}
context->insert_type (argument->get_mappings (), argument_expr_tyty);
i++;
}
if (i != num_args_to_call)
{
rust_error_at (call.get_locus (),
"unexpected number of arguments %lu expected %lu",
(unsigned long) i, (unsigned long) call.num_params ());
return;
}
type.monomorphize ();
resolved = type.get_return_type ()->monomorphized_clone ();
}
} // namespace TyTy
} // namespace Rust

View File

@ -3,10 +3,9 @@ struct GenericStruct<T>(T, usize);
fn main() {
let a2;
a2 = GenericStruct::<i8, i32>(1, 456); // { dg-error "generic item takes at most 1 type arguments but 2 were supplied" }
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 }
// { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-2 }
// { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-3 }
// { dg-error {expected \[T\?\] got \[<tyty::error>\]} "" { target *-*-* } .-4 }
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 }
// { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-2 }
// { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-3 }
let b2: i32 = a2.0;
// { dg-error {Expected Tuple or ADT got: T\?} "" { target *-*-* } .-1 }

View File

@ -1,5 +1,6 @@
fn main() {
let a = &123;
let b: &mut i32 = a;
// { dg-error "expected .&mut i32. got .& i32." "" { target *-*-* } .-1 }
// { dg-error "mismatched mutability" "" { target *-*-* } .-1 }
// { dg-error "expected .&mut i32. got .& i32." "" { target *-*-* } .-2 }
}

View File

@ -3,6 +3,5 @@ fn main() {
let mut x;
x = true;
x = x + 2; // { dg-error "cannot apply this operator to types bool and <integer>" }
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 }
// { dg-error {expected \[bool\] got \[<tyty::error>\]} "" { target *-*-* } .-2 }
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 }
}

View File

@ -7,5 +7,4 @@ fn main() {
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 }
// { dg-error {Failed to resolve expression of function call} "" { target *-*-* } .-3 }
// { duplicate _dg-error {failed to type resolve expression} "" { target *-*-* } .-4 }
// { dg-error {expected \[T\?\] got \[<tyty::error>\]} "" { target *-*-* } .-5 }
}

View File

@ -0,0 +1,75 @@
/* { dg-output "foo_deref\nimm_deref\n123\n" } */
extern "C" {
fn printf(s: *const i8, ...);
}
#[lang = "deref"]
pub trait Deref {
type Target;
fn deref(&self) -> &Self::Target;
}
impl<T> Deref for &T {
type Target = T;
fn deref(&self) -> &T {
unsafe {
let a = "imm_deref\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c);
}
*self
}
}
impl<T> Deref for &mut T {
type Target = T;
fn deref(&self) -> &T {
unsafe {
let a = "mut_deref\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c);
}
*self
}
}
struct Foo<T>(T);
impl<T> Deref for Foo<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
let a = "foo_deref\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c);
}
&self.0
}
}
fn main() -> i32 {
let foo: Foo<i32> = Foo(123);
let bar: &i32 = &foo;
unsafe {
let a = "%i\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c, *bar);
}
0
}