mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
2043 lines
65 KiB
C
2043 lines
65 KiB
C
// Copyright (c) 2019-2023 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the GNU LGPLv3.0 license
|
|
// a copy of which can be found in the LICENSE file.
|
|
//
|
|
// This source file contains functions related to both explicit and
|
|
// implicit conversions. C3 has a fairly complex set of rules,
|
|
// which makes this code somewhat lengthy.
|
|
|
|
#include "sema_internal.h"
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma ide diagnostic ignored "ConstantFunctionResult"
|
|
|
|
static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool silent, bool may_not_be_optional);
|
|
static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent);
|
|
static bool cast_from_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent);
|
|
static bool cast_from_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent);
|
|
static bool cast_from_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent);
|
|
static bool cast_from_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent);
|
|
|
|
static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type);
|
|
static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type);
|
|
static Expr *recursive_may_narrow(Expr *expr, Type *type);
|
|
static void expr_recursively_rewrite_untyped_list(Expr *expr, Expr **list);
|
|
static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee);
|
|
static inline bool cast_to_array_is_valid(Type *from, Type *to);
|
|
static inline bool insert_cast(Expr *expr, CastKind kind, Type *type);
|
|
static bool pointer_to_integer(Expr *expr, Type *type);
|
|
static bool pointer_to_bool(Expr *expr, Type *type);
|
|
static bool pointer_to_pointer(Expr* expr, Type *type);
|
|
static bool bool_to_int(Expr *expr, Type *canonical, Type *type);
|
|
static bool bool_to_float(Expr *expr, Type *canonical, Type *type);
|
|
static bool integer_to_bool(Expr *expr, Type *type);
|
|
static bool integer_to_enum(Expr *expr, Type *canonical, Type *type);
|
|
static bool integer_to_integer(Expr *expr, Type *canonical, Type *type);
|
|
static bool integer_to_pointer(Expr *expr, Type *type);
|
|
static bool integer_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type);
|
|
static bool float_to_bool(Expr *expr, Type *type);
|
|
static bool float_to_float(Expr* expr, Type *canonical, Type *type);
|
|
static bool float_to_integer(Expr *expr, Type *canonical, Type *type);
|
|
static bool float_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type);
|
|
static bool array_to_vector(Expr *expr, Type *to_type);
|
|
static bool vector_to_array(Expr *expr, Type *to_type);
|
|
static bool vector_to_vector(Expr *expr, Type *to_type);
|
|
INLINE bool subarray_to_subarray(Expr *expr, Type *to_type);
|
|
static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type);
|
|
static bool cast_vector_element_may_implicitly_convert(Expr *expr, Type *from, Type *to);
|
|
static void enum_to_int_lowering(Expr* expr);
|
|
static bool voidfail_to_error(Expr *expr, Type *type);
|
|
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type);
|
|
INLINE bool cast_with_optional(Expr *expr, Type *to_type, bool add_optional);
|
|
static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent);
|
|
|
|
/**
|
|
* Insert a cast. This will assume that the cast is valid. No typeinfo will be registered.
|
|
*/
|
|
static inline bool insert_cast(Expr *expr, CastKind kind, Type *type)
|
|
{
|
|
assert(expr->resolve_status == RESOLVE_DONE);
|
|
assert(expr->type);
|
|
Expr *inner = expr_copy(expr);
|
|
expr->expr_kind = EXPR_CAST;
|
|
expr->cast_expr.kind = kind;
|
|
expr->cast_expr.expr = exprid(inner);
|
|
expr->cast_expr.type_info = 0;
|
|
expr->type = type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* General error due to casts.
|
|
*/
|
|
bool sema_error_failed_cast(Expr *expr, Type *from, Type *to)
|
|
{
|
|
SEMA_ERROR(expr, "The cast %s to %s is not allowed.", type_quoted_error_string(from), type_quoted_error_string(to));
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a type by inferring the length.
|
|
*/
|
|
Type *type_infer_len_from_actual_type(Type *to_infer, Type *actual_type)
|
|
{
|
|
// This may be called on types not inferrable,
|
|
// if so we assume the original type
|
|
if (!type_len_is_inferred(to_infer)) return to_infer;
|
|
|
|
// Handle int[*]! a = { ... } by stripping the optional.
|
|
bool is_optional = type_is_optional(to_infer);
|
|
|
|
assert((is_optional || !type_is_optional(actual_type)) && "int[*] x = { may_fail } should have been caught.");
|
|
|
|
// Strip the optional
|
|
if (is_optional) to_infer = to_infer->optional;
|
|
|
|
// And from the actual type.
|
|
actual_type = type_no_optional(actual_type);
|
|
|
|
// Grab the underlying indexed type,
|
|
// because we can only have [*] [] [<*>] [<>] * here
|
|
Type *indexed = type_get_indexed_type(to_infer);
|
|
Type *actual = type_get_indexed_type(actual_type);
|
|
|
|
// We should always have indexed types.
|
|
assert(indexed && actual);
|
|
|
|
// The underlying type may also be inferred.
|
|
// In this case, infer it.
|
|
if (type_len_is_inferred(indexed))
|
|
{
|
|
// if we have int[*][*] => the inner is int[*], we cast it here.
|
|
indexed = type_infer_len_from_actual_type(indexed, actual);
|
|
}
|
|
|
|
// Construct the real type
|
|
switch (to_infer->type_kind)
|
|
{
|
|
case TYPE_POINTER:
|
|
// The case of int[*]* x = ...
|
|
return type_add_optional(type_get_ptr(indexed), is_optional);
|
|
case TYPE_ARRAY:
|
|
// The case of int[*][2] x = ...
|
|
return type_add_optional(type_get_array(indexed, to_infer->array.len), is_optional);
|
|
case TYPE_INFERRED_ARRAY:
|
|
assert(type_is_arraylike(type_flatten(actual_type)));
|
|
return type_add_optional(type_get_array(indexed, type_flatten(actual_type)->array.len), is_optional);
|
|
case TYPE_INFERRED_VECTOR:
|
|
assert(type_is_arraylike(type_flatten(actual_type)));
|
|
return type_add_optional(type_get_vector(indexed, type_flatten(actual_type)->array.len), is_optional);
|
|
case TYPE_VECTOR:
|
|
// This is unreachable, because unlike arrays, there is no inner type that may be
|
|
// the inferred part.
|
|
UNREACHABLE
|
|
case TYPE_SUBARRAY:
|
|
// The case of int[*][] y = ... is disallowed
|
|
UNREACHABLE
|
|
default:
|
|
UNREACHABLE
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Insert a cast on non-const only
|
|
*/
|
|
INLINE bool insert_runtime_cast_unless_const(Expr *expr, CastKind kind, Type *type)
|
|
{
|
|
if (expr->expr_kind == EXPR_CONST) return false;
|
|
return insert_cast(expr, kind, type);
|
|
}
|
|
|
|
/**
|
|
* Insert the PTRXI cast, or on const do a rewrite.
|
|
*/
|
|
static bool pointer_to_integer(Expr *expr, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_PTRINT, type)) return true;
|
|
|
|
// Revisit this to support pointers > 64 bits.
|
|
expr_rewrite_const_int(expr, type, expr->const_expr.ptr);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Insert the PTRBOOL cast or on const do a rewrite.
|
|
*/
|
|
static bool pointer_to_bool(Expr *expr, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return true;
|
|
|
|
// It may be a pointer
|
|
if (expr->const_expr.const_kind == CONST_POINTER)
|
|
{
|
|
expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0);
|
|
return true;
|
|
}
|
|
|
|
// Or it's a string, in which case it is always true.
|
|
assert(expr->const_expr.const_kind == CONST_STRING);
|
|
expr_rewrite_const_bool(expr, type, true);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Insert a PTRPTR cast or update the pointer type
|
|
*/
|
|
static bool pointer_to_pointer(Expr* expr, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_PTRPTR, type)) return true;
|
|
|
|
// Strings cannot be compile-time folded, so insert a runtime cast.
|
|
if (expr->const_expr.const_kind == CONST_STRING)
|
|
{
|
|
return insert_cast(expr, CAST_PTRPTR, type);
|
|
}
|
|
|
|
// Insert the cast, this removes the ability to narrow it.
|
|
expr->type = type;
|
|
expr->const_expr.is_hex = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Bool into a signed or unsigned int using CAST_BOOLINT
|
|
* or rewrite to 0 / 1 for false / true.
|
|
*/
|
|
static bool bool_to_int(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return true;
|
|
|
|
expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0);
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast bool to float using CAST_BOOLFP
|
|
* or rewrite to 0.0 / 1.0 for false / true
|
|
*/
|
|
static bool bool_to_float(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return true;
|
|
|
|
assert(expr->const_expr.const_kind == CONST_BOOL);
|
|
expr_rewrite_const_float(expr, type, expr->const_expr.b ? 1.0 : 0.0);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Insert a cast from `void!` to some fault type by inserting a `catch`,
|
|
* so "anyerr a = returns_voidfail()" => "anyerr a = catch(returns_voidfail())"
|
|
*/
|
|
static bool voidfail_to_error(Expr *expr, Type *type)
|
|
{
|
|
assert(type->canonical->type_kind == TYPE_FAULTTYPE || type == type_anyerr);
|
|
Expr *inner = expr_copy(expr);
|
|
expr->expr_kind = EXPR_CATCH;
|
|
expr->inner_expr = inner;
|
|
expr->type = type;
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast int to bool using CAST_INTBOOL
|
|
* or rewrite 0 => false, any other value => true
|
|
*/
|
|
static bool integer_to_bool(Expr *expr, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_INTBOOL, type)) return true;
|
|
|
|
expr_rewrite_const_bool(expr, type, !int_is_zero(expr->const_expr.ixx));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Cast any float to bool using CAST_FPBOOL
|
|
* or rewrite 0.0 => false, any other value => true
|
|
*/
|
|
static bool float_to_bool(Expr *expr, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_FPBOOL, type)) return true;
|
|
|
|
expr_rewrite_const_bool(expr, type, expr->const_expr.fxx.f != 0.0);
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert any fp to another fp type using CAST_FPFP
|
|
*/
|
|
static bool float_to_float(Expr* expr, Type *canonical, Type *type)
|
|
{
|
|
// Change to same type should never enter here.
|
|
assert(type_flatten(canonical) != type_flatten(expr->type));
|
|
|
|
// Insert runtime cast if needed.
|
|
if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return true;
|
|
|
|
// Otherwise rewrite the const, which may cause rounding.
|
|
expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert from any floating point to int using CAST_FPINT
|
|
* Const conversion will disable narrowable and hex.
|
|
*/
|
|
static bool float_to_integer(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_FPINT, type)) return true;
|
|
|
|
// Run the int->real to and rewrite.
|
|
assert(type_is_integer(canonical));
|
|
Real d = expr->const_expr.fxx.f;
|
|
expr->const_expr.ixx = int_from_real(d, canonical->type_kind);
|
|
expr->const_expr.const_kind = CONST_INTEGER;
|
|
expr->type = type;
|
|
expr->const_expr.is_hex = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert from integer to enum using CAST_INTENUM / or do a const conversion.
|
|
* This will ensure that the conversion is valid (i.e. in the range 0 .. enumcount - 1)
|
|
*/
|
|
static bool integer_to_enum(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
assert(canonical->type_kind == TYPE_ENUM);
|
|
Decl *enum_decl = canonical->decl;
|
|
|
|
if (insert_runtime_cast_unless_const(expr, CAST_INTENUM, type)) return true;
|
|
|
|
// Check that the type is within limits.
|
|
unsigned max_enums = vec_size(enum_decl->enums.values);
|
|
Int to_convert = expr->const_expr.ixx;
|
|
|
|
// Negative numbers are always wrong.
|
|
if (int_is_neg(to_convert))
|
|
{
|
|
SEMA_ERROR(expr, "A negative number cannot be converted to an enum.");
|
|
return false;
|
|
}
|
|
|
|
// Check the max, we don't support more than 4 billion,
|
|
// so we can safely use TYPE_U32.
|
|
Int max = { .i.low = max_enums, .type = TYPE_U32 };
|
|
if (int_comp(to_convert, max, BINARYOP_GE))
|
|
{
|
|
SEMA_ERROR(expr, "This value exceeds the number of enums in %s.", canonical->decl->name);
|
|
return false;
|
|
}
|
|
|
|
// Fold the const into the actual enum.
|
|
Decl *decl = enum_decl->enums.values[to_convert.i.low];
|
|
expr->const_expr = (ExprConst) {
|
|
.enum_err_val = decl,
|
|
.const_kind = CONST_ENUM
|
|
};
|
|
expr->type = type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert between integers: CAST_INTINT
|
|
*/
|
|
static bool integer_to_integer(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
// Fold pointer casts if narrowing
|
|
// So (int)(uptr)&x => (int)&x in the backend.
|
|
if (expr->expr_kind == EXPR_CAST && expr->cast_expr.kind == CAST_PTRINT
|
|
&& type_size(type) <= type_size(expr->type))
|
|
{
|
|
expr->type = type;
|
|
return true;
|
|
}
|
|
|
|
// Insert runtime casts on non-const.
|
|
if (insert_runtime_cast_unless_const(expr, CAST_INTINT, type)) return true;
|
|
|
|
// Hand this off to the int conversion.
|
|
expr->const_expr.ixx = int_conv(expr->const_expr.ixx, canonical->type_kind);
|
|
expr->const_expr.const_kind = CONST_INTEGER;
|
|
expr->type = type;
|
|
expr->const_expr.is_hex = false;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert 1 => { 1, 1, 1, 1 } using CAST_NUMVEC
|
|
*/
|
|
static bool integer_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
// Fold pointer casts if narrowing
|
|
Type *base = type_get_indexed_type(type);
|
|
cast(expr, base);
|
|
return insert_cast(expr, CAST_NUMVEC, type);
|
|
}
|
|
|
|
/**
|
|
* Convert 1.0 => { 1, 1, 1, 1 } using CAST_NUMVEC
|
|
*/
|
|
static bool float_expand_to_vector_conversion(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
// Fold pointer casts if narrowing
|
|
Type *base = type_get_indexed_type(type);
|
|
cast(expr, base);
|
|
return insert_cast(expr, CAST_NUMVEC, type);
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast a signed or unsigned integer -> floating point, using CAST_INTFP
|
|
* for runtime, otherwise do const transformation.
|
|
*/
|
|
static bool integer_to_float(Expr *expr, Type *canonical, Type *type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_INTFP, type)) return true;
|
|
|
|
Real f = int_to_real(expr->const_expr.ixx);
|
|
expr_rewrite_const_float(expr, type, f);
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast any int to a pointer, will use CAST_INTPTR after a conversion to uptr for runtime.
|
|
* Compile time it will check that the value fits the pointer size.
|
|
*/
|
|
static bool integer_to_pointer(Expr *expr, Type *type)
|
|
{
|
|
assert(type_bit_size(type_uptr) <= 64 && "For > 64 bit pointers, this code needs updating.");
|
|
|
|
// Handle const:
|
|
if (expr->expr_kind == EXPR_CONST)
|
|
{
|
|
// For if the type doesn't fit, insert an error.
|
|
if (!int_fits(expr->const_expr.ixx, type_uptr->canonical->type_kind))
|
|
{
|
|
SEMA_ERROR(expr, "'0x%s' does not fit in a pointer.", int_to_str(expr->const_expr.ixx, 16));
|
|
return false;
|
|
}
|
|
// Otherwise just update.
|
|
expr->type = type;
|
|
expr->const_expr.ptr = expr->const_expr.ixx.i.low;
|
|
expr->const_expr.const_kind = CONST_POINTER;
|
|
return true;
|
|
}
|
|
// Insert widening or narrowing cast as needed.
|
|
cast(expr, type_uptr);
|
|
return insert_cast(expr, CAST_INTPTR, type);
|
|
}
|
|
|
|
/**
|
|
* Convert an enum to its underlying integer. Is a no-op on for enum expressions.
|
|
*/
|
|
static void enum_to_int_lowering(Expr* expr)
|
|
{
|
|
assert(type_flatten(expr->type)->type_kind == TYPE_ENUM);
|
|
Type *underlying_type = type_base(expr->type);
|
|
if (expr->expr_kind == EXPR_CONST)
|
|
{
|
|
assert(expr->const_expr.const_kind == CONST_ENUM);
|
|
expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal);
|
|
|
|
}
|
|
expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr));
|
|
}
|
|
|
|
/**
|
|
* Cast using CAST_ARRVEC, casting an array to a vector. For the constant, this
|
|
* is a simple type change.
|
|
*/
|
|
static bool array_to_vector(Expr *expr, Type *to_type)
|
|
{
|
|
// Runtime cast
|
|
if (insert_runtime_cast_unless_const(expr, CAST_ARRVEC, to_type)) return true;
|
|
|
|
// For the array -> vector this is always a simple rewrite of type.
|
|
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
|
|
ConstInitializer *list = expr->const_expr.initializer;
|
|
list->type = to_type;
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* We have two cases:
|
|
* 1. int[] -> Foo[] where Foo is a distinct or typedef OR it is a constant. Then we can just redefine
|
|
* 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast using CAST_SASA.
|
|
*/
|
|
INLINE bool subarray_to_subarray(Expr *expr, Type *to_type)
|
|
{
|
|
if (expr_is_const(expr) || type_flatten(type_flatten(to_type)->array.base) == type_flatten(type_flatten(expr->type)->array.base))
|
|
{
|
|
// Here we assume int[] -> float[] can't happen.
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
return insert_cast(expr, CAST_SASA, to_type);
|
|
}
|
|
|
|
/**
|
|
* Bitstruct casts go from its base type to any integer or char array of the same size.
|
|
*/
|
|
static bool bitstruct_cast(Expr *expr, Type *bitstruct_type, Type *to, Type *to_type)
|
|
{
|
|
assert(type_size(to) == type_size(bitstruct_type) && "Only casts to the same width expected.");
|
|
|
|
// The case where the bitstruct is backed by an integer
|
|
if (type_is_integer(bitstruct_type))
|
|
{
|
|
// The same size integer, this is the simple case.
|
|
if (type_is_integer(to))
|
|
{
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
// Now we expect a char array of the same size. This
|
|
// is runtime only.
|
|
assert(to->type_kind == TYPE_ARRAY);
|
|
return insert_cast(expr, CAST_BSARRY, to_type);
|
|
}
|
|
|
|
// Converting from a char array.
|
|
assert(bitstruct_type->type_kind == TYPE_ARRAY);
|
|
|
|
// Converting to a char array is the simple case, just change the type.
|
|
if (to->type_kind == TYPE_ARRAY)
|
|
{
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
// Converting to an integer, this is a runtime cast.
|
|
assert(type_is_integer(to));
|
|
return insert_cast(expr, CAST_BSINT, to_type);
|
|
}
|
|
|
|
/**
|
|
* Cast using CAST_VECARR, casting an array to a vector. For the constant, this
|
|
* is a simple type change, see array_to_vector.
|
|
*/
|
|
static bool vector_to_array(Expr *expr, Type *to_type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_VECARR, to_type)) return true;
|
|
|
|
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
|
|
ConstInitializer *list = expr->const_expr.initializer;
|
|
list->type = to_type;
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert vector -> vector. This is somewhat complex as there are various functions
|
|
* we need to invoke depending on the underlying type.
|
|
*/
|
|
static bool vector_to_vector(Expr *expr, Type *to_type)
|
|
{
|
|
//
|
|
if (expr->expr_kind != EXPR_CONST)
|
|
{
|
|
// Extract indexed types.
|
|
Type *from_type = type_flatten(expr->type);
|
|
Type *from_element = from_type->array.base;
|
|
to_type = type_flatten(to_type);
|
|
Type *to_element = to_type->array.base;
|
|
|
|
// float vec -> float/int/bool vec
|
|
if (type_is_float(from_element))
|
|
{
|
|
switch (to_element->type_kind)
|
|
{
|
|
case ALL_FLOATS: return insert_cast(expr, CAST_FPFP, to_type);
|
|
case TYPE_BOOL: return insert_cast(expr, CAST_FPBOOL, to_type);
|
|
case ALL_INTS: return insert_cast(expr, CAST_FPINT, to_type);
|
|
default: UNREACHABLE;
|
|
}
|
|
}
|
|
|
|
// bool vec -> float vec
|
|
if (from_element == type_bool)
|
|
{
|
|
// Special conversion to retain the sign.
|
|
if (type_is_integer(to_element)) return insert_cast(expr, CAST_BOOLVECINT, to_type);
|
|
if (type_is_float(to_element)) return insert_cast(expr, CAST_BOOLFP, to_type);
|
|
UNREACHABLE;
|
|
}
|
|
|
|
// The last possibility is int -> bool/int/fp
|
|
assert(type_is_integer(from_element));
|
|
switch (to_element->type_kind)
|
|
{
|
|
case ALL_FLOATS: return insert_cast(expr, CAST_INTFP, to_type);
|
|
case TYPE_BOOL: return insert_cast(expr, CAST_INTBOOL, to_type);
|
|
case ALL_INTS: return insert_cast(expr, CAST_INTINT, to_type);
|
|
default: UNREACHABLE;
|
|
}
|
|
}
|
|
|
|
assert(expr->const_expr.const_kind == CONST_INITIALIZER);
|
|
|
|
// For the const initializer we need to change the internal type
|
|
ConstInitializer *list = expr->const_expr.initializer;
|
|
vector_const_initializer_convert_to_type(list, to_type);
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Perform vararg promotions typical for C style varargs:
|
|
* 1. Widen int and bool to C int size
|
|
* 2. Widen float and smaller to double
|
|
* 3. Turn subarrays into pointers
|
|
*/
|
|
bool cast_promote_vararg(Expr *arg)
|
|
{
|
|
// Remove things like distinct, optional, enum etc.
|
|
Type *arg_type = type_flatten(arg->type);
|
|
|
|
// 1. Promote any integer or bool to at least CInt
|
|
if (type_is_promotable_int_bool(arg_type)) return cast(arg, type_cint);
|
|
|
|
// 2. Promote any float to at least double
|
|
if (type_is_promotable_float(arg_type)) return cast(arg, type_double);
|
|
|
|
// 3. Turn subarrays into pointers
|
|
if (arg_type->type_kind == TYPE_SUBARRAY) return cast(arg, type_get_ptr(arg_type->array.base));
|
|
|
|
return true;
|
|
}
|
|
/**
|
|
* Cast an untyped list to a particular type.
|
|
*/
|
|
bool cast_untyped_to_type(SemaContext *context, Expr *expr, Type *to_type)
|
|
{
|
|
// Recursively set the type of all ConstInitializer inside.
|
|
expr_recursively_rewrite_untyped_list(expr, expr->const_expr.untyped_list);
|
|
// We can now analyse the list (this is where the actual check happens)
|
|
if (!sema_expr_analyse_initializer_list(context, type_flatten(to_type), expr)) return false;
|
|
// And set the type.
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Given lhs and rhs, promote to the maximum bit size, this will retain
|
|
* signed/unsigned type of each side.
|
|
*/
|
|
void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type)
|
|
{
|
|
unsigned bit_size_left = left_type->builtin.bitsize;
|
|
unsigned bit_size_right = right_type->builtin.bitsize;
|
|
|
|
assert(bit_size_left && bit_size_right);
|
|
|
|
// Simple case they are the same size, just return.
|
|
if (bit_size_left == bit_size_right) return;
|
|
|
|
// Lhs is smaller than rhs, so widen it using the right type
|
|
if (bit_size_left < bit_size_right)
|
|
{
|
|
Type *to = lhs->type->type_kind < TYPE_U8
|
|
? type_int_signed_by_bitsize(bit_size_right)
|
|
: type_int_unsigned_by_bitsize(bit_size_right);
|
|
bool success = cast(lhs, to);
|
|
assert(success);
|
|
return;
|
|
}
|
|
|
|
// Rhs is smaller, do the same thing as above but with the rhs.
|
|
Type *to = rhs->type->type_kind < TYPE_U8
|
|
? type_int_signed_by_bitsize(bit_size_left)
|
|
: type_int_unsigned_by_bitsize(bit_size_left);
|
|
bool success = cast(rhs, to);
|
|
assert(success);
|
|
}
|
|
|
|
/**
|
|
* For implicit casts to bool, in a conditional, return the type of cast to
|
|
* insert.
|
|
*/
|
|
CastKind cast_to_bool_kind(Type *type)
|
|
{
|
|
switch (type_flatten(type)->type_kind)
|
|
{
|
|
case TYPE_BOOL:
|
|
return CAST_BOOLBOOL;
|
|
case TYPE_ANYERR:
|
|
return CAST_EUBOOL;
|
|
case TYPE_SUBARRAY:
|
|
return CAST_SABOOL;
|
|
case ALL_INTS:
|
|
return CAST_INTBOOL;
|
|
case ALL_FLOATS:
|
|
return CAST_FPBOOL;
|
|
case TYPE_POINTER:
|
|
return CAST_PTRBOOL;
|
|
case TYPE_FAULTTYPE:
|
|
return CAST_ERBOOL;
|
|
case TYPE_TYPEDEF:
|
|
case TYPE_DISTINCT:
|
|
case TYPE_OPTIONAL:
|
|
case TYPE_OPTIONAL_ANY:
|
|
case TYPE_ENUM:
|
|
// These are not possible due to flattening.
|
|
UNREACHABLE
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_INFERRED_VECTOR:
|
|
// These should never be here, type should already be known.
|
|
UNREACHABLE
|
|
case TYPE_POISONED:
|
|
case TYPE_VOID:
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_FUNC:
|
|
case TYPE_ARRAY:
|
|
case TYPE_TYPEID:
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_VECTOR:
|
|
case TYPE_BITSTRUCT:
|
|
case TYPE_UNTYPED_LIST:
|
|
case TYPE_ANY:
|
|
case TYPE_FLEXIBLE_ARRAY:
|
|
case TYPE_SCALED_VECTOR:
|
|
case TYPE_MEMBER:
|
|
// Everything else is an error
|
|
return CAST_ERROR;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
|
|
/**
|
|
* Check whether an expression may narrow.
|
|
* 1. If it has an intrinsic type, then compare it against the type. If the bitwidth is smaller or same => ok
|
|
* 2. If it is a constant, then if it fits in the type it is ok.
|
|
* 3. If it has sub expressions, recursively check those if they affect the type.
|
|
* 4. Widening casts are ignored, all other casts are opaque.
|
|
*/
|
|
Expr *recursive_may_narrow(Expr *expr, Type *type)
|
|
{
|
|
RETRY:
|
|
switch (expr->expr_kind)
|
|
{
|
|
case EXPR_BITASSIGN:
|
|
case EXPR_BINARY:
|
|
switch (expr->binary_expr.operator)
|
|
{
|
|
case BINARYOP_ERROR:
|
|
UNREACHABLE
|
|
case BINARYOP_MULT:
|
|
case BINARYOP_SUB:
|
|
case BINARYOP_ADD:
|
|
case BINARYOP_DIV:
|
|
case BINARYOP_MOD:
|
|
case BINARYOP_BIT_OR:
|
|
case BINARYOP_BIT_XOR:
|
|
case BINARYOP_BIT_AND:
|
|
case BINARYOP_ELSE:
|
|
{
|
|
// *, -, +, /, %, |, ^, &, ?? -> check both sides.
|
|
Expr *res = recursive_may_narrow(exprptr(expr->binary_expr.left), type);
|
|
if (res) return res;
|
|
expr = exprptr(expr->binary_expr.right);
|
|
goto RETRY;
|
|
}
|
|
case BINARYOP_SHR:
|
|
case BINARYOP_SHL:
|
|
case BINARYOP_ASSIGN:
|
|
case BINARYOP_ADD_ASSIGN:
|
|
case BINARYOP_BIT_AND_ASSIGN:
|
|
case BINARYOP_BIT_OR_ASSIGN:
|
|
case BINARYOP_BIT_XOR_ASSIGN:
|
|
case BINARYOP_DIV_ASSIGN:
|
|
case BINARYOP_MOD_ASSIGN:
|
|
case BINARYOP_MULT_ASSIGN:
|
|
case BINARYOP_SHR_ASSIGN:
|
|
case BINARYOP_SHL_ASSIGN:
|
|
case BINARYOP_SUB_ASSIGN:
|
|
// For shifts and assignment, ignore the right hand side.
|
|
expr = exprptr(expr->binary_expr.left);
|
|
goto RETRY;
|
|
case BINARYOP_AND:
|
|
case BINARYOP_OR:
|
|
case BINARYOP_GT:
|
|
case BINARYOP_GE:
|
|
case BINARYOP_LT:
|
|
case BINARYOP_LE:
|
|
case BINARYOP_NE:
|
|
case BINARYOP_EQ:
|
|
// This type is bool, so check should never happen.
|
|
UNREACHABLE
|
|
}
|
|
UNREACHABLE
|
|
case EXPR_BUILTIN_ACCESS:
|
|
switch (expr->builtin_access_expr.kind)
|
|
{
|
|
case ACCESS_LEN:
|
|
// Special: we may resize this, but not smaller than cint.
|
|
if (type_size(type) < type_size(type_cint)) return expr;
|
|
return NULL;
|
|
case ACCESS_PTR:
|
|
case ACCESS_TYPEOFANY:
|
|
case ACCESS_ENUMNAME:
|
|
case ACCESS_FAULTNAME:
|
|
// For the rest, just check size.
|
|
goto CHECK_SIZE;
|
|
}
|
|
UNREACHABLE;
|
|
case EXPR_EXPRESSION_LIST:
|
|
// Only the last expression counts for narrowing.
|
|
// It's unclear if this can happen.
|
|
expr = VECLAST(expr->expression_list);
|
|
goto RETRY;
|
|
case EXPR_TERNARY:
|
|
{
|
|
// In the case a ?: b -> check a and b
|
|
// In the case a ? b : c -> check b and c
|
|
Expr *res = recursive_may_narrow(exprptr(expr->ternary_expr.then_expr
|
|
? expr->ternary_expr.then_expr
|
|
: expr->ternary_expr.cond), type);
|
|
if (res) return res;
|
|
expr = exprptr(expr->ternary_expr.else_expr);
|
|
goto RETRY;
|
|
}
|
|
case EXPR_CAST:
|
|
switch (expr->cast_expr.kind)
|
|
{
|
|
case CAST_INTINT:
|
|
case CAST_FPFP:
|
|
// If this is a narrowing cast that makes it smaller that then target type
|
|
// we're done.
|
|
if (type_size(type) >= type_size(expr->type))
|
|
{
|
|
return NULL;
|
|
}
|
|
// Otherwise just look through it.
|
|
expr = exprptr(expr->cast_expr.expr);
|
|
goto RETRY;
|
|
default:
|
|
// For all other casts we regard them as opaque.
|
|
goto CHECK_SIZE;
|
|
}
|
|
case EXPR_CONST:
|
|
// For constants, just check that they will fit.
|
|
if (type_is_integer(type))
|
|
{
|
|
assert(expr->const_expr.const_kind == CONST_INTEGER || expr->const_expr.const_kind == CONST_ENUM);
|
|
if (expr_const_will_overflow(&expr->const_expr, type_flatten(type)->type_kind))
|
|
{
|
|
return expr;
|
|
}
|
|
return NULL;
|
|
}
|
|
assert(type_is_float(type));
|
|
assert(expr->const_expr.const_kind == CONST_FLOAT);
|
|
if (!expr_const_float_fits_type(&expr->const_expr, type_flatten(type)->type_kind))
|
|
{
|
|
return expr;
|
|
}
|
|
return NULL;
|
|
case EXPR_POST_UNARY:
|
|
expr = expr->unary_expr.expr;
|
|
goto RETRY;
|
|
case EXPR_GROUP:
|
|
case EXPR_FORCE_UNWRAP:
|
|
expr = expr->inner_expr;
|
|
goto RETRY;
|
|
case EXPR_RETHROW:
|
|
expr = expr->rethrow_expr.inner;
|
|
goto RETRY;
|
|
case EXPR_UNARY:
|
|
{
|
|
switch (expr->unary_expr.operator)
|
|
{
|
|
case UNARYOP_ERROR:
|
|
case UNARYOP_ADDR:
|
|
case UNARYOP_NOT:
|
|
case UNARYOP_TADDR:
|
|
UNREACHABLE
|
|
case UNARYOP_DEREF:
|
|
// Check sizes.
|
|
goto CHECK_SIZE;
|
|
case UNARYOP_NEG:
|
|
case UNARYOP_BITNEG:
|
|
case UNARYOP_INC:
|
|
case UNARYOP_DEC:
|
|
expr = expr->unary_expr.expr;
|
|
goto RETRY;
|
|
}
|
|
}
|
|
default:
|
|
// Check type sizes
|
|
goto CHECK_SIZE;
|
|
}
|
|
CHECK_SIZE:
|
|
if (type_size(expr->type) > type_size(type)) return expr;
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Cast to a given type, making it an optional type as needed.
|
|
*
|
|
*/
|
|
INLINE bool cast_with_optional(Expr *expr, Type *to_type, bool add_optional)
|
|
{
|
|
if (!cast(expr, to_type)) return false;
|
|
if (add_optional) expr->type = type_add_optional(expr->type, true);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Cast a subarray to some other type:
|
|
* 1. To another subarray => works if the array elements are equivalent.
|
|
* 2. To another pointer => works if the pointer is void* or the array element and pointee is equivalent.
|
|
* 3. To bool => explicit cast is ok.
|
|
*/
|
|
static bool cast_from_subarray(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
switch (to->type_kind)
|
|
{
|
|
case TYPE_SUBARRAY:
|
|
// Casting to another subarray works if the elements are equivalent.
|
|
if (!type_array_element_is_equivalent(from->array.base, to->array.base, is_explicit))
|
|
{
|
|
return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true), silent);
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
case TYPE_POINTER:
|
|
// Casting to another pointer works if either the pointer is void* or the element and pointee are equivalent.
|
|
if (to != type_voidptr && !type_array_element_is_equivalent(from->array.base, to->pointer, is_explicit))
|
|
{
|
|
return sema_error_cannot_convert(expr, to, !is_explicit && type_array_element_is_equivalent(from->array.base, to->pointer, true), silent);
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
case TYPE_BOOL:
|
|
// Only explicit bool casts are allowed.
|
|
if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, silent);
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
default:
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
/**
|
|
* Try casting to a pointer.
|
|
* 1. Any pointer -> variant, any pointer -> void*, void* -> any pointer - always works.
|
|
* 2. Pointer -> integer must be explicit and type size >= uptr
|
|
* 3. Pointer -> subarray if the pointer points to a vector or array, allow void*[2]* -> int*[2]* (pointer equivalence).
|
|
* 4. Pointer -> bool must be explicit (conditionals are treated as a special case.
|
|
* 5. Pointer -> pointer explicit always works, otherwise they must have pointer equivalence.
|
|
*/
|
|
static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
// pointer -> any, void* -> pointer pointer -> void*
|
|
if (to == type_any || to == type_voidptr || (from == type_voidptr && type_is_pointer(to))) return cast_with_optional(expr, to_type, add_optional);
|
|
|
|
Type *pointee = from->pointer;
|
|
pointee = is_explicit ? type_flatten(pointee) : pointee->canonical;
|
|
TypeKind pointee_kind = pointee->type_kind;
|
|
switch (to->type_kind)
|
|
{
|
|
case ALL_INTS:
|
|
// Only explicit cast
|
|
if (!is_explicit) return sema_error_cannot_convert(expr, to_type, true, silent);
|
|
// The type must be uptr or bigger.
|
|
if (type_size(to_type) < type_size(type_uptr))
|
|
{
|
|
SEMA_ERROR(expr, "Casting %s to %s is not allowed because '%s' is smaller than a pointer. "
|
|
"Use (%s)(iptr) if you want this lossy cast.",
|
|
type_quoted_error_string(expr->type), type_quoted_error_string(to_type),
|
|
type_to_error_string(to_type), type_to_error_string(to_type));
|
|
return false;
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
case TYPE_SUBARRAY:
|
|
// int[<2>]*, int[2]*
|
|
if (pointee_kind == TYPE_ARRAY || pointee_kind == TYPE_VECTOR)
|
|
{
|
|
Type *subarray_base = to->array.base->canonical;
|
|
Type *from_base = pointee->array.base;
|
|
if (is_explicit)
|
|
{
|
|
subarray_base = type_flatten(subarray_base);
|
|
from_base = type_flatten(from_base);
|
|
}
|
|
// Same base type? E.g. int[2]* -> int[], then we're done.
|
|
if (subarray_base == from_base) return cast_with_optional(expr, to_type, add_optional);
|
|
|
|
// Otherwise we might have int*[2]* -> void*[], use pointer equivalence.
|
|
if (subarray_base->type_kind == TYPE_POINTER && from_base->type_kind == TYPE_POINTER)
|
|
{
|
|
if (type_is_pointer_equivalent(subarray_base, from_base, is_explicit)) return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
// Silent? Then we're done.
|
|
if (silent) return false;
|
|
// Check if this would work if explicit for a good error message:
|
|
bool would_work_explicit = false;
|
|
if (!is_explicit)
|
|
{
|
|
would_work_explicit = cast_from_pointer(context, expr_copy(expr),
|
|
from, to, to_type, add_optional, true, true);
|
|
}
|
|
return sema_error_cannot_convert(expr, to_type, would_work_explicit, false);
|
|
}
|
|
// All other fails.
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
case TYPE_BOOL:
|
|
// Only explicit conversion allowed.
|
|
if (is_explicit) return cast_with_optional(expr, to_type, add_optional);
|
|
return sema_error_cannot_convert(expr, to_type, true, silent);
|
|
case TYPE_POINTER:
|
|
// Explicit conversion always works.
|
|
if (is_explicit) return cast_with_optional(expr, to_type, add_optional);
|
|
// See if the pointee is equivalent.
|
|
if (type_is_pointer_equivalent(from, to, false))
|
|
{
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
return sema_error_cannot_convert(expr, to_type, true, silent);
|
|
case TYPE_OPTIONAL_ANY:
|
|
case TYPE_OPTIONAL:
|
|
UNREACHABLE
|
|
default:
|
|
// All other types are forbidden.
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
}
|
|
}
|
|
|
|
static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type)
|
|
{
|
|
assert(expr->expr_kind == EXPR_CONST);
|
|
if (expr->const_expr.is_character)
|
|
{
|
|
SEMA_ERROR(problem, "The unicode character U+%04x cannot fit in a %s.", (uint32_t)expr->const_expr.ixx.i.low, type_quoted_error_string(to_type));
|
|
return;
|
|
}
|
|
if (expr->const_expr.const_kind == CONST_ENUM)
|
|
{
|
|
SEMA_ERROR(problem, "The ordinal '%d' is out of range for %s, so you need an explicit cast to truncate the value.",
|
|
expr->const_expr.enum_err_val->var.index,
|
|
type_quoted_error_string(to_type));
|
|
return;
|
|
}
|
|
const char *error_value = expr->const_expr.is_hex ? int_to_str(expr->const_expr.ixx, 16) : expr_const_to_error_string(&expr->const_expr);
|
|
SEMA_ERROR(problem, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", error_value,
|
|
type_quoted_error_string(to_type));
|
|
}
|
|
|
|
|
|
static inline bool cast_maybe_string_lit(Expr *expr, Type *to_canonical, Type *to_original)
|
|
{
|
|
if (expr->expr_kind != EXPR_CONST || expr->const_expr.const_kind != CONST_STRING || expr->type != type_string) return false;
|
|
Type *flat = type_flatten(to_canonical);
|
|
Type *indexed_type = type_get_indexed_type(flat);
|
|
if (indexed_type) indexed_type = type_flatten(indexed_type);
|
|
switch (flat->type_kind)
|
|
{
|
|
case TYPE_SUBARRAY:
|
|
case TYPE_POINTER:
|
|
if (indexed_type != type_char && indexed_type != type_ichar) return false;
|
|
expr->type = to_original;
|
|
case TYPE_INFERRED_ARRAY:
|
|
if (indexed_type != type_char && indexed_type != type_ichar) return false;
|
|
expr->type = type_infer_len_from_actual_type(to_original, type_get_array(indexed_type, expr->const_expr.string.len));
|
|
return true;
|
|
break;
|
|
case TYPE_ARRAY:
|
|
if (indexed_type != type_char && indexed_type != type_ichar) return false;
|
|
{
|
|
ArraySize len = expr->const_expr.string.len;
|
|
ArraySize to_len = flat->array.len;
|
|
if (len > to_len) return false;
|
|
expr->type = to_original;
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Recursively change a const list to an initializer list.
|
|
*/
|
|
static void expr_recursively_rewrite_untyped_list(Expr *expr, Expr **list)
|
|
{
|
|
expr->expr_kind = EXPR_INITIALIZER_LIST;
|
|
expr->initializer_list = list;
|
|
expr->resolve_status = RESOLVE_NOT_DONE;
|
|
FOREACH_BEGIN(Expr *inner, list)
|
|
if (expr_is_const_untyped_list(inner))
|
|
{
|
|
expr_recursively_rewrite_untyped_list(inner, inner->const_expr.untyped_list);
|
|
}
|
|
FOREACH_END();
|
|
}
|
|
|
|
/**
|
|
* Try to make an implicit cast. Optional types are allowed.
|
|
*/
|
|
bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type)
|
|
{
|
|
return cast_expr_inner(context, expr, to_type, false, false, false);
|
|
}
|
|
|
|
/**
|
|
* Try to make an explicit cast, Optional types are allowed.
|
|
*/
|
|
bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type)
|
|
{
|
|
return cast_expr_inner(context, expr, to_type, true, false, false);
|
|
}
|
|
|
|
/**
|
|
* Try to make an implicit cast. If optional is allowed or not depends on the parameter.
|
|
* This is mostly used with assignment.
|
|
*/
|
|
bool cast_implicit_maybe_optional(SemaContext *context, Expr *expr, Type *to_type, bool may_be_optional)
|
|
{
|
|
return cast_expr_inner(context, expr, to_type, false, false, !may_be_optional);
|
|
}
|
|
|
|
/**
|
|
* Silent implicit casting will attempt a cast, but will silently back out if it fails.
|
|
*/
|
|
bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type)
|
|
{
|
|
return cast_expr_inner(context, expr, to_type, false, true, false);
|
|
}
|
|
|
|
/**
|
|
* Common error reporting for casts.
|
|
*/
|
|
static inline bool sema_error_cannot_convert(Expr *expr, Type *to, bool may_cast_explicit, bool silent)
|
|
{
|
|
if (silent) return false;
|
|
if (may_cast_explicit)
|
|
{
|
|
SEMA_ERROR(expr,
|
|
"Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.",
|
|
type_quoted_error_string(type_no_optional(expr->type)),
|
|
type_quoted_error_string(to),
|
|
type_to_error_string(type_no_optional(to)));
|
|
}
|
|
else
|
|
{
|
|
SEMA_ERROR(expr,
|
|
"It is not possible to convert %s to %s.",
|
|
type_quoted_error_string(type_no_optional(expr->type)), type_quoted_error_string(to));
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
/**
|
|
* Attempt casting an array.
|
|
* 1. Inferred array / vector => infer type
|
|
* 2. Array / vector => ok if len matches.
|
|
* 3. Check for array element equivalence.
|
|
*/
|
|
static bool cast_from_array(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
switch (to->type_kind)
|
|
{
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_INFERRED_VECTOR:
|
|
// We infer the target type (note that to and to_type are now of different kinds.
|
|
to_type = type_infer_len_from_actual_type(to_type, from);
|
|
break;
|
|
case TYPE_VECTOR:
|
|
case TYPE_ARRAY:
|
|
// Len must be checked.
|
|
if (to->array.len != from->array.len) return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
break;
|
|
default:
|
|
// No other conversions are allowed.
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
}
|
|
// Check array element equivalence.
|
|
if (!type_array_element_is_equivalent(from->array.base, to->array.base, is_explicit))
|
|
{
|
|
if (silent) return false;
|
|
// Create a good error message, so we can give a hint that maybe you can do an explicit cast.
|
|
bool explicit_would_work = !is_explicit && type_array_element_is_equivalent(from->array.base, to->array.base, true);
|
|
return sema_error_cannot_convert(expr, to_type, explicit_would_work, silent);
|
|
}
|
|
// Insert the cast.
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
|
|
/**
|
|
* Check a vector element and see if it may implicitly convert to the other type.
|
|
*/
|
|
static bool cast_vector_element_may_implicitly_convert(Expr *expr, Type *from, Type *to)
|
|
{
|
|
from = from->canonical;
|
|
to = to->canonical;
|
|
|
|
// Same type - we're fine.
|
|
if (from == to) return true;
|
|
|
|
// If any of the elements are distinct we know it doesn't work,
|
|
if (from->type_kind == TYPE_DISTINCT || to->type_kind == TYPE_DISTINCT) return false;
|
|
|
|
// Casting from bool always works (for int, float)
|
|
if (from == type_bool) return true;
|
|
|
|
// Casting to bool never works (for int, float)
|
|
if (to == type_bool) return false;
|
|
|
|
// Handle floats
|
|
if (type_is_float(to))
|
|
{
|
|
// Any integer may convert to a float.
|
|
if (type_is_integer(from)) return true;
|
|
|
|
if (type_is_float(from))
|
|
{
|
|
// Explict casts always work
|
|
ByteSize to_size = type_size(to);
|
|
ByteSize from_size = type_size(from);
|
|
// Same size is ok
|
|
if (to_size == from_size) return true;
|
|
// Widening is ok if the expression is simple.
|
|
return to_size > from_size && expr_is_simple(expr);
|
|
}
|
|
// No other possibility
|
|
UNREACHABLE;
|
|
}
|
|
|
|
// Last case is integer.
|
|
assert(type_is_integer(to));
|
|
|
|
// float -> int can't be done implicitly
|
|
if (type_is_float(from)) return false;
|
|
|
|
assert(type_is_integer(from));
|
|
|
|
ByteSize to_size = type_size(to);
|
|
ByteSize from_size = type_size(from);
|
|
// Same size is ok
|
|
if (to_size == from_size) return true;
|
|
// Widening is ok if expression is simple. Narrowing is prohibited.
|
|
return to_size > from_size && expr_is_simple(expr);
|
|
}
|
|
|
|
/**
|
|
* Check all casts from vectors:
|
|
* 1. To arrays and inferred arrays -> if the array type matches, eg int[<2>] to int[2]
|
|
* 2. To vectors and inferred vectors -> if the vector type can be promoted, e.g. int[<2>] to long[<2>]
|
|
*/
|
|
static bool cast_from_vector(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
bool not_to_vector = !type_kind_is_any_vector(to->type_kind);
|
|
switch (to->type_kind)
|
|
{
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_INFERRED_VECTOR:
|
|
// Update the to_type (but not to!)
|
|
to_type = type_infer_len_from_actual_type(to_type, from);
|
|
break;
|
|
case TYPE_ARRAY:
|
|
case TYPE_VECTOR:
|
|
// Len must match.
|
|
if (to->array.len != from->array.len) return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
break;
|
|
default:
|
|
// All other conversions fail
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
}
|
|
Type *from_base = from->array.base;
|
|
Type *to_base = to->array.base;
|
|
// vector -> array cast.
|
|
if (not_to_vector)
|
|
{
|
|
// Here we do simple array element equivalence, that is int[<2>] -> int[2] is ok, but not int[<2>] -> float[2]
|
|
if (!type_array_element_is_equivalent(from_base, to_base, is_explicit))
|
|
{
|
|
// Give us a nice hint in case an explicit conversion would work.
|
|
if (silent) return false;
|
|
bool may_explicit = !is_explicit && type_array_element_is_equivalent(from_base, to_base, true);
|
|
return sema_error_cannot_convert(expr, to, may_explicit, true);
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
// Vector -> vector cast
|
|
// This allows for things like int[<2>] -> float[<2>] conversions.
|
|
if (!is_explicit && !cast_vector_element_may_implicitly_convert(expr, from_base, to_base))
|
|
{
|
|
if (silent) return false;
|
|
// Give us a nice hint that explicit conversion would work.
|
|
return sema_error_cannot_convert(expr, to, true, true);
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
|
|
|
|
/**
|
|
* Cast from an enum to other types.
|
|
* 1. Only explicit casts are allowed.
|
|
* 2. Casting to any integer is valid for the explicit cast.
|
|
*/
|
|
static bool cast_from_enum(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
if (!is_explicit)
|
|
{
|
|
bool may_cast = type_is_integer(type_flatten(to));
|
|
sema_error_cannot_convert(expr, to_type, may_cast, silent);
|
|
return false;
|
|
}
|
|
if (!type_is_integer(to))
|
|
{
|
|
sema_error_cannot_convert(expr, to_type, false, silent);
|
|
return false;
|
|
}
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
|
|
/**
|
|
* Cast an integer. Note here that "from" may be an enum.
|
|
* 1. Floats -> always works
|
|
* 2. Bools -> explicit only
|
|
* 3. Vector -> check if the underlying type can be converted.
|
|
* 4. Enum -> if from is an enum, then fails, otherwise follow int conversions.
|
|
* 5. Int -> any int is ok if explicit or same width, if const, check fits, wider -> only simple, narrow -> check narrowing.
|
|
* 6. Distinct -> expr is const, then try as if it was the base type, otherwise fail.
|
|
*/
|
|
static bool cast_from_integer(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
RETRY:
|
|
switch (to->type_kind)
|
|
{
|
|
case ALL_FLOATS:
|
|
// All floats are ok.
|
|
goto CAST;
|
|
case TYPE_BOOL:
|
|
// Explicit only
|
|
if (is_explicit) goto CAST;
|
|
goto REQUIRE_CAST;
|
|
case TYPE_VECTOR:
|
|
// Check underlying type
|
|
to = to->array.base->canonical;
|
|
goto RETRY;
|
|
case TYPE_ENUM:
|
|
if (is_explicit) goto CAST;
|
|
goto REQUIRE_CAST;
|
|
case ALL_INTS:
|
|
{
|
|
// All explicit casts work.
|
|
if (is_explicit) goto CAST;
|
|
ByteSize to_size = type_size(to);
|
|
ByteSize from_size = type_size(from);
|
|
// If widening, require simple.
|
|
if (to_size > from_size) goto ONLY_SIMPLE;
|
|
// If const, check in range.
|
|
if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind))
|
|
{
|
|
sema_error_const_int_out_of_range(expr, expr, to_type);
|
|
return false;
|
|
}
|
|
// Same size => ok
|
|
if (to_size == from_size) goto CAST;
|
|
assert(to == type_flatten(to));
|
|
// Check if narrowing works
|
|
Expr *problem = recursive_may_narrow(expr, to);
|
|
if (problem)
|
|
{
|
|
if (silent) return false;
|
|
expr = problem;
|
|
// Otherwise require a cast.
|
|
goto REQUIRE_CAST;
|
|
}
|
|
goto CAST;
|
|
}
|
|
case TYPE_DISTINCT:
|
|
// The only conversion works if the expr is const.
|
|
if (expr_is_const(expr) && type_is_integer(from))
|
|
{
|
|
to = type_flatten(to);
|
|
goto RETRY;
|
|
}
|
|
// Failure
|
|
if (silent) return false;
|
|
bool may_explicit = cast_expr_inner(context, expr_copy(expr), to_type, true, true, false);
|
|
if (may_explicit) goto REQUIRE_CAST;
|
|
break;
|
|
case TYPE_POINTER:
|
|
{
|
|
if (from->type_kind == TYPE_ENUM) break;
|
|
bool may_cast = expr_is_const(expr) || type_size(from) >= type_size(type_voidptr);
|
|
if (!is_explicit)
|
|
{
|
|
if (may_cast) goto REQUIRE_CAST;
|
|
break;
|
|
}
|
|
if (!may_cast)
|
|
{
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "You cannot cast from a type smaller than %s.",
|
|
type_quoted_error_string(type_iptr));
|
|
return false;
|
|
}
|
|
goto CAST;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
ONLY_SIMPLE:
|
|
if (expr_is_simple(expr)) goto CAST;
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "This conversion requires an explicit cast to %s, because the widening of the expression may be done in more than one way.", type_quoted_error_string(to_type));
|
|
return false;
|
|
REQUIRE_CAST:
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type));
|
|
return false;
|
|
CAST:
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
|
|
/**
|
|
* Casting from a float
|
|
* 1. To ints and bools -> valid with explicit casts.
|
|
* 2. To vectors -> valid if the it can cast to vector element type.
|
|
* 3. To floats -> narrowing if sub expression can be narrowed. Widening if the expr is simple.
|
|
* 4. To distinct -> try as if it was the base type if const, otherwise fail.
|
|
*/
|
|
static inline bool cast_from_float(SemaContext *context, Expr *expr, Type *from, Type *to, Type *to_type, bool add_optional, bool is_explicit, bool silent)
|
|
{
|
|
RETRY:
|
|
switch (to->type_kind)
|
|
{
|
|
case ALL_INTS:
|
|
case TYPE_BOOL:
|
|
// Bool and ints? Explicit casts only.
|
|
if (is_explicit) goto CAST;
|
|
goto REQUIRE_CAST;
|
|
case TYPE_VECTOR:
|
|
// Check if the underlying element may be cast.
|
|
to = to->array.base->canonical;
|
|
goto RETRY;
|
|
case ALL_FLOATS:
|
|
{
|
|
// All explicit casts just work.
|
|
if (is_explicit) goto CAST;
|
|
// If widening, only allow simple expressions.
|
|
ByteSize to_size = type_size(to);
|
|
ByteSize from_size = type_size(from);
|
|
if (to_size > from_size) goto ONLY_SIMPLE;
|
|
// If same size, just cast.
|
|
if (to_size == from_size) goto CAST;
|
|
// If const, check it fits.
|
|
if (expr_is_const(expr) && expr_const_will_overflow(&expr->const_expr, type_flatten(to)->type_kind))
|
|
{
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "The value '%s' is out of range for %s, so you need an explicit cast to truncate the value.", expr_const_to_error_string(&expr->const_expr),
|
|
type_quoted_error_string(to_type));
|
|
return false;
|
|
}
|
|
// Otherwise, check if the underlying code may narrow.
|
|
Expr *problem = recursive_may_narrow(expr, to);
|
|
if (problem)
|
|
{
|
|
if (silent) return false;
|
|
expr = problem;
|
|
goto REQUIRE_CAST;
|
|
}
|
|
// If no problem -> cast.
|
|
goto CAST;
|
|
}
|
|
case TYPE_DISTINCT:
|
|
// Ignore distinct if casting from a const.
|
|
if (expr_is_const(expr))
|
|
{
|
|
to = type_flatten(to);
|
|
goto RETRY;
|
|
}
|
|
else
|
|
{
|
|
if (silent) return false;
|
|
// Give a good error message, suggesting a cast if the cast had worked
|
|
bool may_explicit = cast_from_float(context, expr_copy(expr), from, type_flatten(to), to_type, add_optional, true, true);
|
|
if (may_explicit) goto REQUIRE_CAST;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return sema_error_cannot_convert(expr, to_type, false, silent);
|
|
ONLY_SIMPLE:
|
|
if (expr_is_simple(expr)) goto CAST;
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "This conversion requires an explicit cast to %s, because the widening of the expression may be done in more than one way.", type_quoted_error_string(to_type));
|
|
return false;
|
|
REQUIRE_CAST:
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type));
|
|
return false;
|
|
CAST:
|
|
return cast_with_optional(expr, to_type, add_optional);
|
|
}
|
|
|
|
/**
|
|
* Do the following:
|
|
* 1. Special optional conversions.
|
|
* 2. String literal conversions
|
|
* 3. Constant pointer conversions
|
|
*/
|
|
static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, bool is_explicit, bool silent,
|
|
bool may_not_be_optional)
|
|
{
|
|
Type *from_type = expr->type;
|
|
|
|
assert(!type_is_optional(to_type) || may_not_be_optional);
|
|
|
|
// Allow (void)foo
|
|
if (is_explicit && to_type == type_void)
|
|
{
|
|
return cast(expr, to_type);
|
|
}
|
|
|
|
Type *to = is_explicit ? type_flatten(to_type) : type_no_optional(to_type)->canonical;
|
|
|
|
// Step one, cast from optional.
|
|
// This handles:
|
|
// 1. *! -> any type
|
|
// 2. void! -> anyerr
|
|
// 3. void! -> SomeFault (explicit)
|
|
if (type_is_optional(from_type))
|
|
{
|
|
// *! -> int => ok, gives int!
|
|
if (from_type == type_anyfail)
|
|
{
|
|
if (may_not_be_optional)
|
|
{
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "An optional value cannot be converted to a non-optional %s.", type_quoted_error_string(to_type));
|
|
return false;
|
|
}
|
|
// Just add the optional.
|
|
expr->type = type_add_optional(to_type, true);
|
|
return true;
|
|
}
|
|
|
|
// Here we have something like int!
|
|
assert(from_type->type_kind == TYPE_OPTIONAL);
|
|
|
|
// If it is void!, then there are special rules:
|
|
if (from_type->optional == type_void)
|
|
{
|
|
// void! x; anyerr y = x;
|
|
if (!type_is_optional(to_type) && to == type_anyerr)
|
|
{
|
|
cast(expr, to_type);
|
|
return true;
|
|
}
|
|
|
|
// void! x; FooFault y = (FooFault)x;
|
|
// Only allowed if explicit.
|
|
if (to->type_kind == TYPE_FAULTTYPE)
|
|
{
|
|
if (!is_explicit)
|
|
{
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr, "A 'void!' can only be cast into %s using an explicit cast. You can try using (%s)",
|
|
type_quoted_error_string(to_type), type_to_error_string(to_type));
|
|
return false;
|
|
}
|
|
cast(expr, to_type);
|
|
return true;
|
|
}
|
|
}
|
|
if (may_not_be_optional)
|
|
{
|
|
if (silent) return false;
|
|
char *format = is_explicit ? "Cannot cast an optional %s to %s." : "Cannot convert an optional %s to %s.";
|
|
SEMA_ERROR(expr, format, type_quoted_error_string(from_type), type_quoted_error_string(to_type));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// We're now done and can remove the optional
|
|
bool add_optional = type_is_optional(to_type) || type_is_optional(from_type);
|
|
to_type = type_no_optional(to_type);
|
|
from_type = type_no_optional(from_type);
|
|
|
|
// Grab the underlying expression type.
|
|
Type *from = is_explicit ? type_flatten(from_type) : from_type->canonical;
|
|
|
|
// We may already be done.
|
|
if (from == to)
|
|
{
|
|
expr->type = type_add_optional(to_type, add_optional);
|
|
return true;
|
|
}
|
|
|
|
|
|
// Handle strings, these don't actually mess with the underlying data,
|
|
// just the type.
|
|
if (cast_maybe_string_lit(expr, to, to_type)) return true;
|
|
|
|
// For constant pointers cast into anything pointer-like:
|
|
if (expr_is_const_pointer(expr) && from == type_voidptr && type_flatten(to)->type_kind == TYPE_POINTER)
|
|
{
|
|
assert(!add_optional);
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
switch (from->type_kind)
|
|
{
|
|
case TYPE_UNTYPED_LIST:
|
|
if (!cast_untyped_to_type(context, expr, to_type)) return false;
|
|
if (add_optional) expr->type = type_add_optional(expr->type, true);
|
|
return true;
|
|
case TYPE_FAULTTYPE:
|
|
// Allow MyError.A -> error, to an integer or to bool
|
|
if (to == type_anyerr) return cast(expr, to_type);
|
|
if (type_is_integer(to) || to == type_bool) goto CAST_IF_EXPLICIT;
|
|
goto CAST_FAILED;
|
|
case TYPE_ANYERR:
|
|
if (to_type == type_bool || to->type_kind == TYPE_FAULTTYPE || type_is_integer(to))
|
|
{
|
|
goto CAST_IF_EXPLICIT;
|
|
}
|
|
goto CAST_FAILED;
|
|
case TYPE_POINTER:
|
|
return cast_from_pointer(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case TYPE_SUBARRAY:
|
|
return cast_from_subarray(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case TYPE_BOOL:
|
|
// Bool may convert into integers and floats but only explicitly.
|
|
if (type_is_integer(to) || type_is_float(to)) goto CAST_IF_EXPLICIT;
|
|
goto CAST_FAILED;
|
|
case TYPE_VECTOR:
|
|
case TYPE_SCALED_VECTOR:
|
|
return cast_from_vector(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case TYPE_ARRAY:
|
|
return cast_from_array(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case TYPE_ENUM:
|
|
return cast_from_enum(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case ALL_INTS:
|
|
return cast_from_integer(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case ALL_FLOATS:
|
|
return cast_from_float(context, expr, from, to, to_type, add_optional, is_explicit, silent);
|
|
case TYPE_POISONED:
|
|
return false;
|
|
case TYPE_VOID:
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_FUNC:
|
|
case TYPE_FLEXIBLE_ARRAY:
|
|
case TYPE_INFERRED_VECTOR:
|
|
case TYPE_MEMBER:
|
|
goto CAST_FAILED;
|
|
case TYPE_TYPEID:
|
|
if (!type_is_pointer_sized_or_more(to_type)) goto CAST_FAILED;
|
|
goto CAST_IF_EXPLICIT;
|
|
case TYPE_OPTIONAL:
|
|
case TYPE_OPTIONAL_ANY:
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE;
|
|
case TYPE_ANY:
|
|
if (to->type_kind != TYPE_POINTER) goto CAST_FAILED;
|
|
goto CAST_IF_EXPLICIT;
|
|
case TYPE_STRUCT:
|
|
if (type_is_substruct(from))
|
|
{
|
|
Type *type;
|
|
Expr *access = expr_access_inline_member(expr_copy(expr), from->decl);
|
|
while (1)
|
|
{
|
|
type = access->type->canonical;
|
|
if (type == to) break;
|
|
if (!type_is_substruct(type)) goto CAST_FAILED;
|
|
}
|
|
expr_replace(expr, access);
|
|
return true;
|
|
}
|
|
goto CAST_FAILED;
|
|
case TYPE_UNION:
|
|
goto CAST_FAILED;
|
|
case TYPE_BITSTRUCT:
|
|
// A bitstruct can convert to:
|
|
// 1. An int of the same length
|
|
// 2. An integer array of the same length
|
|
if (type_size(to_type) != type_size(from_type)) goto CAST_FAILED;
|
|
if (type_is_integer(to_type)) goto CAST_IF_EXPLICIT;
|
|
if (to_type->type_kind == TYPE_ARRAY && type_is_integer(to_type->array.base)) goto CAST_IF_EXPLICIT;
|
|
goto CAST_FAILED;
|
|
UNREACHABLE
|
|
case TYPE_DISTINCT:
|
|
assert(!is_explicit);
|
|
if (cast_expr_inner(context, expr, to_type, true, true, false))
|
|
{
|
|
goto CAST_IF_EXPLICIT;
|
|
}
|
|
goto CAST_FAILED;
|
|
}
|
|
UNREACHABLE
|
|
|
|
CAST_IF_EXPLICIT:
|
|
if (!is_explicit)
|
|
{
|
|
if (silent) return false;
|
|
SEMA_ERROR(expr,
|
|
"Implicitly casting %s to %s is not permitted, but you can do an explicit cast by placing '(%s)' before the expression.",
|
|
type_quoted_error_string(type_no_optional(from_type)),
|
|
type_quoted_error_string(type_no_optional(to_type)),
|
|
type_to_error_string(to_type));
|
|
return false;
|
|
}
|
|
return cast(expr, to_type);
|
|
CAST_FAILED:
|
|
if (!silent)
|
|
{
|
|
if (!is_explicit)
|
|
{
|
|
SEMA_ERROR(expr, "You cannot cast %s into %s even with an explicit cast, so this looks like an error.", type_quoted_error_string(expr->type), type_quoted_error_string(to_type));
|
|
return false;
|
|
}
|
|
return sema_error_failed_cast(expr, expr->type, to_type);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void vector_const_initializer_convert_to_type(ConstInitializer *initializer, Type *to_type)
|
|
{
|
|
switch (initializer->kind)
|
|
{
|
|
case CONST_INIT_ARRAY:
|
|
{
|
|
Type *element_type = type_flatten(to_type)->array.base;
|
|
FOREACH_BEGIN(ConstInitializer *element, initializer->init_array.elements)
|
|
vector_const_initializer_convert_to_type(element, element_type);
|
|
FOREACH_END();
|
|
break;
|
|
}
|
|
case CONST_INIT_ARRAY_FULL:
|
|
{
|
|
Type *element_type = type_flatten(to_type)->array.base;
|
|
FOREACH_BEGIN(ConstInitializer *element, initializer->init_array_full)
|
|
vector_const_initializer_convert_to_type(element, element_type);
|
|
FOREACH_END();
|
|
break;
|
|
}
|
|
case CONST_INIT_VALUE:
|
|
{
|
|
Type *to_flat = type_flatten(to_type);
|
|
bool is_neg_conversion = to_flat && type_flatten(initializer->type) == type_bool;
|
|
if (is_neg_conversion)
|
|
{
|
|
bool is_true = initializer->init_value->const_expr.b;
|
|
initializer->init_value->const_expr.ixx = (Int)
|
|
{ .i = is_true ? (Int128) { UINT64_MAX, UINT64_MAX } : (Int128) { 0, 0 },
|
|
.type = to_flat->type_kind };
|
|
initializer->init_value->type = to_type;
|
|
}
|
|
else
|
|
{
|
|
cast(initializer->init_value, to_type);
|
|
}
|
|
break;
|
|
}
|
|
case CONST_INIT_ZERO:
|
|
break;
|
|
case CONST_INIT_UNION:
|
|
case CONST_INIT_STRUCT:
|
|
UNREACHABLE
|
|
case CONST_INIT_ARRAY_VALUE:
|
|
vector_const_initializer_convert_to_type(initializer->init_array_value.element, to_type);
|
|
break;
|
|
}
|
|
initializer->type = to_type;
|
|
}
|
|
|
|
|
|
static bool err_to_anyerr(Expr *expr, Type *to_type)
|
|
{
|
|
expr->type = to_type;
|
|
return true;
|
|
}
|
|
|
|
static bool err_to_bool(Expr *expr, Type *to_type)
|
|
{
|
|
if (insert_runtime_cast_unless_const(expr, CAST_ERBOOL, to_type)) return true;
|
|
|
|
assert(expr->const_expr.const_kind == CONST_ERR);
|
|
|
|
expr_rewrite_const_bool(expr, type_bool, expr->const_expr.enum_err_val != NULL);
|
|
return true;
|
|
}
|
|
|
|
static inline bool subarray_to_bool(Expr *expr, Type *type)
|
|
{
|
|
if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER)
|
|
{
|
|
ConstInitializer *list = expr->const_expr.initializer;
|
|
switch (list->kind)
|
|
{
|
|
case CONST_INIT_ZERO:
|
|
expr_rewrite_const_bool(expr, type, false);
|
|
return true;
|
|
case CONST_INIT_ARRAY:
|
|
expr_rewrite_const_bool(expr, type, vec_size(list->init_array.elements) > 0);
|
|
return true;
|
|
case CONST_INIT_ARRAY_FULL:
|
|
expr_rewrite_const_bool(expr, type, vec_size(list->init_array_full) > 0);
|
|
return true;
|
|
case CONST_INIT_STRUCT:
|
|
case CONST_INIT_UNION:
|
|
case CONST_INIT_VALUE:
|
|
case CONST_INIT_ARRAY_VALUE:
|
|
break;
|
|
}
|
|
}
|
|
return insert_cast(expr, CAST_SABOOL, type);
|
|
}
|
|
|
|
static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
|
|
{
|
|
switch (from_type->type_kind)
|
|
{
|
|
case TYPE_OPTIONAL_ANY:
|
|
case TYPE_OPTIONAL:
|
|
case TYPE_VOID:
|
|
UNREACHABLE
|
|
case TYPE_DISTINCT:
|
|
case TYPE_FUNC:
|
|
case TYPE_TYPEDEF:
|
|
case CT_TYPES:
|
|
UNREACHABLE
|
|
case TYPE_BITSTRUCT:
|
|
return bitstruct_cast(expr, type_flatten(from_type->decl->bitstruct.base_type->type), to, to_type);
|
|
case TYPE_BOOL:
|
|
// Bool may convert into integers and floats but only explicitly.
|
|
if (type_is_integer(to)) return bool_to_int(expr, to, to_type);
|
|
if (type_is_float(to)) return bool_to_float(expr, to, to_type);
|
|
break;
|
|
case TYPE_ANYERR:
|
|
if (to->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type);
|
|
if (to->type_kind == TYPE_FAULTTYPE)
|
|
{
|
|
REMINDER("Improve anyerr -> fault conversion.");
|
|
return insert_cast(expr, CAST_EUER, to_type);
|
|
}
|
|
if (type_is_integer(to)) return insert_cast(expr, CAST_EUINT, to_type);
|
|
break;
|
|
case ALL_SIGNED_INTS:
|
|
if (type_is_integer(to)) return integer_to_integer(expr, to, to_type);
|
|
if (type_is_float(to)) return integer_to_float(expr, to, to_type);
|
|
if (to == type_bool) return integer_to_bool(expr, to_type);
|
|
if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type);
|
|
if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type);
|
|
if (type_kind_is_any_vector(to->type_kind)) return integer_expand_to_vector_conversion(expr, to, to_type);
|
|
break;
|
|
case ALL_UNSIGNED_INTS:
|
|
if (type_is_integer(to)) return integer_to_integer(expr, to, to_type);
|
|
if (type_is_float(to)) return integer_to_float(expr, to, to_type);
|
|
if (to == type_bool) return integer_to_bool(expr, to_type);
|
|
if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type);
|
|
if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type);
|
|
if (type_kind_is_any_vector(to->type_kind)) return integer_expand_to_vector_conversion(expr, to, to_type);
|
|
break;
|
|
case ALL_FLOATS:
|
|
if (type_is_integer(to)) return float_to_integer(expr, to, to_type);
|
|
if (to == type_bool) return float_to_bool(expr, to_type);
|
|
if (type_is_float(to)) return float_to_float(expr, to, to_type);
|
|
if (type_kind_is_any_vector(to->type_kind)) return float_expand_to_vector_conversion(expr, to, to_type);
|
|
break;
|
|
case TYPE_TYPEID:
|
|
case TYPE_POINTER:
|
|
if (type_is_integer(to)) return pointer_to_integer(expr, to_type);
|
|
if (to->type_kind == TYPE_BOOL) return pointer_to_bool(expr, to_type);
|
|
if (to->type_kind == TYPE_POINTER) return pointer_to_pointer(expr, to_type);
|
|
if (to->type_kind == TYPE_SUBARRAY) return insert_cast(expr, CAST_APTSA, to_type);
|
|
if (to->type_kind == TYPE_ANY) return insert_cast(expr, CAST_PTRANY, to_type);
|
|
break;
|
|
case TYPE_ANY:
|
|
if (to->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_ANYPTR, to_type);
|
|
break;
|
|
case TYPE_ENUM:
|
|
enum_to_int_lowering(expr);
|
|
if (type_is_integer(to)) return integer_to_integer(expr, to, to_type);
|
|
if (type_is_float(to)) return integer_to_float(expr, to, to_type);
|
|
if (to == type_bool) return integer_to_bool(expr, to_type);
|
|
if (to->type_kind == TYPE_POINTER) return integer_to_pointer(expr, to_type);
|
|
if (to->type_kind == TYPE_ENUM) return integer_to_enum(expr, to, to_type);
|
|
break;
|
|
case TYPE_FAULTTYPE:
|
|
if (to->type_kind == TYPE_ANYERR) return err_to_anyerr(expr, to_type);
|
|
if (to == type_bool) return err_to_bool(expr, to_type);
|
|
if (type_is_integer(to)) return insert_cast(expr, CAST_ERINT, to_type);
|
|
break;
|
|
case TYPE_FLEXIBLE_ARRAY:
|
|
case TYPE_SCALED_VECTOR:
|
|
return false;
|
|
case TYPE_ARRAY:
|
|
if (to->type_kind == TYPE_VECTOR) return array_to_vector(expr, to_type);
|
|
FALLTHROUGH;
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
|
|
if (to->type_kind == TYPE_ARRAY || to->type_kind == TYPE_STRUCT || to->type_kind == TYPE_UNION)
|
|
{
|
|
return insert_cast(expr, CAST_STST, to_type);
|
|
} // Starting in a little while...
|
|
break;
|
|
case TYPE_SUBARRAY:
|
|
if (to->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_SAPTR, to_type);
|
|
if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr, to_type);
|
|
if (to->type_kind == TYPE_SUBARRAY) return subarray_to_subarray(expr, to_type);
|
|
break;
|
|
case TYPE_VECTOR:
|
|
if (to->type_kind == TYPE_ARRAY) return vector_to_array(expr, to_type);
|
|
if (to->type_kind == TYPE_VECTOR) return vector_to_vector(expr, to_type);
|
|
break;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
|
|
bool cast(Expr *expr, Type *to_type)
|
|
{
|
|
if (to_type == type_void)
|
|
{
|
|
insert_cast(expr, CAST_VOID, type_void);
|
|
return true;
|
|
}
|
|
|
|
assert(!type_is_optional(to_type));
|
|
Type *from_type = expr->type;
|
|
bool from_is_optional = false;
|
|
Type *to = type_flatten(to_type);
|
|
|
|
// Special case *! => error
|
|
if (to == type_anyerr || to->type_kind == TYPE_FAULTTYPE)
|
|
{
|
|
if (type_is_optional(from_type)) return voidfail_to_error(expr, to_type);
|
|
}
|
|
|
|
if (type_is_optional_any(from_type))
|
|
{
|
|
expr->type = type_get_optional(to_type);
|
|
return true;
|
|
}
|
|
|
|
if (type_is_optional_type(from_type))
|
|
{
|
|
from_type = from_type->optional;
|
|
from_is_optional = true;
|
|
}
|
|
from_type = type_flatten(from_type);
|
|
if (type_len_is_inferred(to_type))
|
|
{
|
|
to_type = from_type;
|
|
to = type_flatten(from_type);
|
|
}
|
|
if (from_type == to)
|
|
{
|
|
expr->type = type_add_optional(to_type, from_is_optional);
|
|
if (expr->expr_kind == EXPR_CONST)
|
|
{
|
|
expr->const_expr.is_hex = false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (!cast_inner(expr, from_type, to, to_type)) return false;
|
|
|
|
Type *result_type = expr->type;
|
|
if (from_is_optional && !type_is_optional(result_type))
|
|
{
|
|
expr->type = type_get_optional(result_type);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool cast_to_index(Expr *index)
|
|
{
|
|
Type *type = index->type->canonical;
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_I8:
|
|
case TYPE_I16:
|
|
case TYPE_I32:
|
|
case TYPE_I64:
|
|
return cast(index, type_isz);
|
|
case TYPE_U8:
|
|
case TYPE_U16:
|
|
case TYPE_U32:
|
|
case TYPE_U64:
|
|
return cast(index, type_usz);
|
|
case TYPE_U128:
|
|
SEMA_ERROR(index, "You need to explicitly cast this to a uint or ulong.");
|
|
return false;
|
|
case TYPE_I128:
|
|
SEMA_ERROR(index, "index->type->canonical this to an int or long.");
|
|
return false;
|
|
case TYPE_ENUM:
|
|
type = type->decl->enums.type_info->type->canonical;
|
|
goto RETRY;
|
|
default:
|
|
SEMA_ERROR(index, "Cannot implicitly convert '%s' to an index.", type_to_error_string(index->type));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type)
|
|
{
|
|
Type *to = type_no_optional(type);
|
|
Type *from = type_no_optional(expr->type);
|
|
RETRY:
|
|
if (type_is_integer(from) && type_is_integer(to)) goto CONVERT_IF_BIGGER;
|
|
if (type_is_float(from) && type_is_float(to)) goto CONVERT_IF_BIGGER;
|
|
if (type_is_integer(from) && type_is_float(to)) goto CONVERT;
|
|
if (type_flat_is_vector(from) && type_flat_is_vector(to))
|
|
{
|
|
to = type_vector_type(to);
|
|
from = type_vector_type(from);
|
|
goto RETRY;
|
|
}
|
|
return true;
|
|
CONVERT_IF_BIGGER:
|
|
if (type_size(to) <= type_size(from)) return true;
|
|
CONVERT:
|
|
return cast_implicit(context, expr, type);
|
|
}
|
|
|
|
|
|
Type *cast_numeric_arithmetic_promotion(Type *type)
|
|
{
|
|
if (!type) return NULL;
|
|
switch (type->type_kind)
|
|
{
|
|
case ALL_SIGNED_INTS:
|
|
if (type->builtin.bitsize < platform_target.width_c_int) return type_cint;
|
|
return type;
|
|
case ALL_UNSIGNED_INTS:
|
|
if (type->builtin.bitsize < platform_target.width_c_int) return type_cuint;
|
|
return type;
|
|
case TYPE_F16:
|
|
// Promote F16 to a real type.
|
|
return type_float;
|
|
case TYPE_OPTIONAL:
|
|
UNREACHABLE
|
|
default:
|
|
return type;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma clang diagnostic pop |