Updated casts (#684)

Cast code rework. Remove llvm_set_bool and friends.
This commit is contained in:
Christoffer Lerno
2022-12-27 14:16:47 +01:00
committed by GitHub
parent e2b4a19c81
commit f46697bc54
72 changed files with 1074 additions and 674 deletions

View File

@@ -961,7 +961,6 @@ typedef struct
typedef struct
{
CastKind kind : 8;
bool implicit : 1;
ExprId expr;
TypeInfoId type_info;
} ExprCast;
@@ -2027,10 +2026,14 @@ INLINE AsmRegister *asm_reg_by_index(unsigned index);
AsmRegister *asm_reg_by_index(unsigned index);
bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type);
bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type);
bool cast_implicit_maybe_failable(SemaContext *context, Expr *expr, Type *to_type, bool may_be_failable);
bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type);
bool cast(Expr *expr, Type *to_type);
bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option);
bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, bool is_const);
bool cast_may_bool_convert(Type *type);
Type *cast_infer_len(Type *to_infer, Type *actual_type);
bool cast_to_index(Expr *index);
@@ -2312,6 +2315,9 @@ bool type_flat_is_boolintlike(Type *type);
bool type_flat_is_numlike(Type *type);
bool type_may_have_sub_elements(Type *type);
bool type_may_have_method(Type *type);
bool type_is_pointer_equivalent(Type *pointer1, Type *pointer2, bool flatten_distinct);
bool type_array_element_is_equivalent(Type *element1, Type *element2, bool is_explicit);
const char *type_to_error_string(Type *type);
const char *type_quoted_error_string(Type *type);
INLINE bool type_may_negate(Type *type);
@@ -3214,6 +3220,11 @@ INLINE bool expr_is_const_string(Expr *expr)
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_STRING;
}
INLINE bool expr_is_const_pointer(Expr *expr)
{
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER;
}
INLINE bool expr_is_const_initializer(Expr *expr)
{
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER;

View File

@@ -125,9 +125,14 @@ typedef enum
{
CAST_OPTION_NONE = 0x00,
CAST_OPTION_SIMPLE_EXPR = 0x01,
CAST_OPTION_ALLOW_OPTIONAL = 0x02,
} CastOption;
typedef enum
{
CAST_TYPE_NO_ERROR_REPORT = 0x08,
CAST_TYPE_NO_OPTIONAL = 0x02,
} CastType;
typedef enum
{

View File

@@ -774,22 +774,6 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
}
void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
{
value->value = llvm_value;
value->alignment = type_abi_alignment(type_bool);
value->kind = BE_BOOLEAN;
value->type = type_bool;
}
void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type)
{
value->value = llvm_value;
value->alignment = type_abi_alignment(type);
value->kind = BE_BOOLVECTOR;
value->type = type;
}
void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i)
{
llvm_value_set(value, llvm_const_int(c, type, i), type);

View File

@@ -384,7 +384,7 @@ static void llvm_emit_overflow_builtin(GenContext *c, BEValue *be_value, Expr *e
LLVMValueRef failed = llvm_emit_extract_value(c, result, 1);
LLVMValueRef value = llvm_emit_extract_value(c, result, 0);
llvm_store_raw(c, &ref, value);
llvm_value_set_bool(be_value, failed);
llvm_value_set(be_value, failed, type_bool);
}
static void llvm_emit_wrap_builtin(GenContext *c, BEValue *result_value, Expr *expr, BuiltinFunction func)
@@ -508,7 +508,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin
UNREACHABLE
}
}
llvm_value_set_bool_vector(value, res, expr->type);
llvm_value_set(value, res, expr->type);
return;
}

View File

@@ -189,7 +189,7 @@ static void llvm_convert_vector_comparison(GenContext *c, BEValue *be_value, LLV
}
unsigned intrinsic = is_equals ? intrinsic_id.vector_reduce_and : intrinsic_id.vector_reduce_or;
LLVMValueRef result = llvm_emit_call_intrinsic(c, intrinsic, &llvm_type, 1, &val, 1);
llvm_value_set_bool(be_value, result);
llvm_value_set(be_value, result, type_bool);
}
static LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTypeRef coerce_type, AlignSize target_alignment, AlignSize *resulting_alignment)
@@ -776,7 +776,7 @@ static inline void llvm_extract_bool_bit_from_array(GenContext *c, BEValue *be_v
// Truncate to i1.
element = LLVMBuildTrunc(c->builder, element, c->bool_type, "");
// Done!
llvm_value_set_bool(be_value, element);
llvm_value_set(be_value, element, type_bool);
}
static inline LLVMValueRef llvm_bswap_non_integral(GenContext *c, LLVMValueRef value, unsigned bitsize)
@@ -2383,7 +2383,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type));
UNREACHABLE
}
llvm_value_set_bool(value, llvm_value);
llvm_value_set(value, llvm_value, type_bool);
return;
case UNARYOP_BITNEG:
llvm_emit_expr(c, value, inner);
@@ -2897,7 +2897,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp
if (!lhs_end_block)
{
// Just set any value.
llvm_value_set_bool(be_value, result_on_skip);
llvm_value_set(be_value, result_on_skip, type_bool);
return;
}
@@ -2932,7 +2932,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp
// One possibility here is that a return happens inside of the expression.
if (!rhs_end_block)
{
llvm_value_set_bool(be_value, result_on_skip);
llvm_value_set(be_value, result_on_skip, type_bool);
return;
}
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
@@ -2940,7 +2940,7 @@ static void llvm_emit_logical_and_or(GenContext *c, BEValue *be_value, Expr *exp
LLVMBasicBlockRef blocks[2] = { lhs_end_block, rhs_end_block };
LLVMAddIncoming(phi, logic_values, blocks, 2);
llvm_value_set_bool(be_value, phi);
llvm_value_set(be_value, phi, type_bool);
}
void llvm_emit_int_comp_zero(GenContext *c, BEValue *result, BEValue *lhs, BinaryOp binary_op)
@@ -3060,7 +3060,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type
llvm_convert_vector_comparison(c, result, value, lhs_type, binary_op == BINARYOP_EQ);
return;
}
llvm_value_set_bool(result, value);
llvm_value_set(result, value, type_bool);
return;
}
@@ -3101,7 +3101,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type
llvm_convert_vector_comparison(c, result, comp_value, lhs_type, binary_op == BINARYOP_EQ);
return;
}
llvm_value_set_bool(result, comp_value);
llvm_value_set(result, comp_value, type_bool);
return;
}
@@ -3147,7 +3147,7 @@ void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type
llvm_convert_vector_comparison(c, result, comp_value, lhs_type, BINARYOP_EQ == binary_op);
return;
}
llvm_value_set_bool(result, comp_value);
llvm_value_set(result, comp_value, type_bool);
}
static void llvm_emit_ptr_comparison(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
@@ -3180,7 +3180,7 @@ static void llvm_emit_ptr_comparison(GenContext *c, BEValue *result, BEValue *lh
default:
UNREACHABLE
}
llvm_value_set_bool(result, val);
llvm_value_set(result, val, type_bool);
}
static inline LLVMValueRef llvm_emit_mult_int(GenContext *c, Type *type, LLVMValueRef left, LLVMValueRef right, SourceSpan loc)
@@ -3282,9 +3282,13 @@ static void llvm_emit_subarray_comp(GenContext *c, BEValue *be_value, BEValue *l
LLVMBasicBlockRef blocks[3] = { all_match_block, no_match_block, match_fail_block };
LLVMAddIncoming(phi, logic_values, blocks, 3);
llvm_value_set_bool(be_value, phi);
llvm_value_set(be_value, phi, type_bool);
}
static void llvm_emit_array_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
{
TODO
}
static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs, BEValue *rhs, BinaryOp binary_op, Type *vector_type)
@@ -3324,7 +3328,7 @@ static void llvm_emit_float_comp(GenContext *c, BEValue *be_value, BEValue *lhs,
llvm_convert_vector_comparison(c, be_value, val, vector_type, BINARYOP_EQ == binary_op);
return;
}
llvm_value_set_bool(be_value, val);
llvm_value_set(be_value, val, type_bool);
}
void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
@@ -3365,6 +3369,11 @@ void llvm_emit_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs,
}
return;
}
if (lhs->type->type_kind == TYPE_ARRAY)
{
llvm_emit_array_comp(c, result, lhs, rhs, binary_op);
return;
}
TODO
}
@@ -3432,7 +3441,7 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr)
{
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->bool_type, "val");
LLVMAddIncoming(phi, logic_values, blocks, 2);
llvm_value_set_bool(be_value, phi);
llvm_value_set(be_value, phi, type_bool);
return;
}
LLVMValueRef phi = LLVMBuildPhi(c->builder, llvm_get_type(c, expr->type), "val");
@@ -3703,16 +3712,6 @@ void llvm_emit_binary(GenContext *c, BEValue *be_value, Expr *expr, BEValue *lhs
UNREACHABLE
}
assert(val);
if (lhs.type == type_bool)
{
llvm_value_set_bool(be_value, val);
return;
}
if (lhs.kind == BE_BOOLVECTOR)
{
llvm_value_set_bool_vector(be_value, val, expr->type);
return;
}
llvm_value_set(be_value, val, expr->type);
}
@@ -3787,7 +3786,7 @@ void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_valu
LLVMBasicBlockRef blocks[2] = { success_block, catch_block };
LLVMAddIncoming(phi, logic_values, blocks, 2);
llvm_value_set_bool(be_value, phi);
llvm_value_set(be_value, phi, type_bool);
}
@@ -4078,14 +4077,7 @@ static inline void llvm_emit_elvis_expr(GenContext *c, BEValue *value, Expr *exp
llvm_emit_expr(c, &right, else_expr);
llvm_value_rvalue(c, &right);
LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs, right.value, "elvis");
if (right.type == type_bool)
{
llvm_value_set_bool(value, val);
}
else
{
llvm_value_set(value, val, right.type);
}
llvm_value_set(value, val, right.type);
return;
}
@@ -4176,14 +4168,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_expr(c, &right, else_expr);
llvm_value_rvalue(c, &right);
LLVMValueRef val = LLVMBuildSelect(c->builder, value->value, lhs_value, right.value, "ternary");
if (right.type == type_bool)
{
llvm_value_set_bool(value, val);
}
else
{
llvm_value_set(value, val, right.type);
}
llvm_value_set(value, val, right.type);
return;
}
@@ -4228,24 +4213,14 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
if (!rhs_exit)
{
if (!lhs_value) lhs_value = LLVMGetUndef(llvm_get_type(c, expr->type));
if (LLVMTypeOf(lhs_value) == c->bool_type)
{
llvm_value_set_bool(value, lhs_value);
return;
}
llvm_value_set(value, lhs_value, type_flatten(expr->type));
llvm_value_set(value, lhs_value, expr->type);
return;
}
if (!lhs_exit)
{
if (!rhs_value) rhs_value = LLVMGetUndef(llvm_get_type(c, expr->type));
if (LLVMTypeOf(rhs_value) == c->bool_type)
{
llvm_value_set_bool(value, rhs_value);
return;
}
llvm_value_set(value, rhs_value, type_flatten(expr->type));
llvm_value_set(value, rhs_value, expr->type);
return;
}
@@ -4255,11 +4230,6 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
LLVMValueRef logic_values[2] = { lhs_value, rhs_value };
LLVMBasicBlockRef blocks[2] = { lhs_exit, rhs_exit };
LLVMAddIncoming(phi, logic_values, blocks, 2);
if (expr_type == type_bool)
{
llvm_value_set_bool(value, phi);
return;
}
llvm_value_set(value, phi, expr_type);
}
static LLVMValueRef llvm_emit_real(LLVMTypeRef type, Float f)
@@ -4346,7 +4316,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
}
return;
case CONST_BOOL:
llvm_value_set_bool(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0));
llvm_value_set(be_value, LLVMConstInt(c->bool_type, expr->const_expr.b ? 1 : 0, 0), type_bool);
return;
case CONST_STRING:
{
@@ -5672,7 +5642,7 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp
LLVMValueRef fail_ref = decl_optional_ref(expr->try_unwrap_expr.decl);
LLVMValueRef errv = llvm_load(c, llvm_get_type(c, type_anyerr), fail_ref, type_abi_alignment(type_anyerr), "load.err");
LLVMValueRef result = LLVMBuildICmp(c->builder, LLVMIntEQ, errv, llvm_get_zero(c, type_anyerr), "result");
llvm_value_set_bool(value, result);
llvm_value_set(value, result, type_bool);
return;
}
BEValue addr;
@@ -5914,7 +5884,7 @@ void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr)
LLVMBasicBlockRef blocks[2] = { next_block, fail_block };
LLVMAddIncoming(chain_result, logic_values, blocks, 2);
llvm_value_set_bool(value, chain_result);
llvm_value_set(value, chain_result, type_bool);
}
@@ -5958,7 +5928,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp
// Check if zero:
BEValue cond;
llvm_value_set_bool(&cond, LLVMBuildICmp(c->builder, LLVMIntEQ, count, llvm_get_zero(c, argc_value.type), ""));
llvm_value_set(&cond, LLVMBuildICmp(c->builder, LLVMIntEQ, count, llvm_get_zero(c, argc_value.type), ""), type_bool);
LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "exit_loop");
LLVMBasicBlockRef pre_loop_block = llvm_basic_block_new(c, "pre_loop");
@@ -6006,7 +5976,7 @@ static inline void llvm_emit_argv_to_subarray(GenContext *c, BEValue *value, Exp
// Add index
LLVMValueRef index_plus = LLVMBuildNUWAdd(c->builder, index_var, llvm_const_int(c, type_usize, 1), "");
llvm_value_set_bool(&cond, LLVMBuildICmp(c->builder, LLVMIntULT, index_plus, size, ""));
llvm_value_set(&cond, LLVMBuildICmp(c->builder, LLVMIntULT, index_plus, size, ""), type_bool);
llvm_emit_cond_br(c, &cond, body_block, exit_block);
LLVMValueRef values[2] = { index_plus, zero };
LLVMBasicBlockRef blocks[2] = { body_block, pre_loop_block };

View File

@@ -258,8 +258,6 @@ static inline bool llvm_value_is_addr(BEValue *value) { return value->kind == BE
static inline bool llvm_value_is_bool(BEValue *value) { return value->kind == BE_BOOLEAN; }
bool llvm_value_is_const(BEValue *value);
void llvm_value_rvalue(GenContext *context, BEValue *value);
void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value);
void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type);
void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type);
void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i);
void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment);

View File

@@ -141,7 +141,7 @@ void llvm_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr *expr
LLVMValueRef decl_value = llvm_get_ref(context, last->decl_expr);
if (bool_cast && last->decl_expr->var.unwrap)
{
llvm_value_set_bool(be_value, LLVMConstInt(context->bool_type, 1, false));
llvm_value_set(be_value, LLVMConstInt(context->bool_type, 1, false), type_bool);
return;
}
llvm_value_set_address_abi_aligned(be_value, decl_value, type);
@@ -638,7 +638,7 @@ static void llvm_emit_switch_body_if_chain(GenContext *c,
llvm_emit_comp(c, &le, &be_value, switch_value, BINARYOP_LE);
BEValue ge;
llvm_emit_comp(c, &ge, &to_value, switch_value, BINARYOP_GE);
llvm_value_set_bool(&equals, llvm_emit_and(c, &le, &ge));
llvm_value_set(&equals, llvm_emit_and(c, &le, &ge), type_bool);
}
else
{
@@ -1344,7 +1344,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani
LLVMBasicBlockRef panic_block = llvm_basic_block_new(c, "panic");
LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "checkok");
BEValue be_value;
llvm_value_set_bool(&be_value, value);
llvm_value_set(&be_value, value, type_bool);
llvm_emit_cond_br(c, &be_value, panic_block, ok_block);
llvm_emit_block(c, panic_block);
llvm_emit_panic(c, panic_name, loc);

View File

@@ -8,6 +8,26 @@ void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type)
value->alignment = type_abi_alignment(type);
value->kind = BE_VALUE;
value->type = type;
if (type == type_bool)
{
LLVMTypeRef llvm_type = LLVMTypeOf(llvm_value);
LLVMContextRef context = LLVMGetTypeContext(llvm_type);
if (llvm_type == LLVMIntTypeInContext(context, 1))
{
value->kind = BE_BOOLEAN;
}
}
if (type_kind_is_any_vector(type->type_kind) && type->array.base == type_bool)
{
LLVMTypeRef llvm_type = LLVMTypeOf(llvm_value);
LLVMTypeRef element = LLVMGetElementType(llvm_type);
LLVMContextRef context = LLVMGetTypeContext(llvm_type);
if (element == LLVMIntTypeInContext(context, 1))
{
value->kind = BE_BOOLVECTOR;
}
}
}
void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment)

View File

@@ -171,20 +171,30 @@ bool expr_const_float_fits_type(const ExprConst *expr_const, TypeKind kind)
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind)
{
switch (kind)
switch (expr->const_kind)
{
case ALL_INTS:
return !int_fits(expr->ixx, kind);
case TYPE_F16:
case TYPE_F32:
case TYPE_F64:
case TYPE_F128:
case CONST_FLOAT:
return !expr_const_float_fits_type(expr, kind);
case TYPE_BOOL:
case CONST_INTEGER:
return !int_fits(expr->ixx, kind);
case CONST_BOOL:
return false;
default:
UNREACHABLE
case CONST_ENUM:
{
Int i = { .i = { .low = expr->enum_err_val->var.index }, .type = type_flatten(expr->enum_err_val->type)->type_kind };
return !int_fits(i, kind);
}
case CONST_ERR:
case CONST_BYTES:
case CONST_STRING:
case CONST_POINTER:
case CONST_TYPEID:
case CONST_INITIALIZER:
case CONST_UNTYPED_LIST:
case CONST_MEMBER:
UNREACHABLE;
}
UNREACHABLE;
}
const char *expr_const_to_error_string(const ExprConst *expr)

File diff suppressed because it is too large Load Diff

View File

@@ -910,7 +910,25 @@ static inline bool sema_binary_promote_top_down(SemaContext *context, Expr *bina
static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *binary, Expr *left, Expr *right)
{
return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right);
if (right->expr_kind == EXPR_INITIALIZER_LIST)
{
if (!sema_analyse_expr(context, left)) return false;
if (type_kind_is_any_vector(type_flatten(left->type)->type_kind))
{
return sema_analyse_inferred_expr(context, left->type, right);
}
return sema_analyse_expr(context, right);
}
if (left->expr_kind == EXPR_INITIALIZER_LIST)
{
if (!sema_analyse_expr(context, right)) return false;
if (type_kind_is_any_vector(type_flatten(right->type)->type_kind))
{
return sema_analyse_inferred_expr(context, right->type, right);
}
return sema_analyse_expr(context, left);
}
return sema_analyse_expr(context, left) && sema_analyse_expr(context, right);
}
static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed)
@@ -1804,14 +1822,13 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
inferred_len = false;
}
}
if (!cast_may_implicit(type, rtype, CAST_OPTION_SIMPLE_EXPR | (may_failable ? CAST_OPTION_ALLOW_OPTIONAL : 0)) || inferred_len)
bool success = cast_implicit_silent(context, ret_expr, rtype);
if (inferred_len || (!may_failable && IS_OPTIONAL(ret_expr)) || !success)
{
SEMA_ERROR(ret_expr, "Expected %s, not %s.", type_quoted_error_string(rtype),
type_quoted_error_string(type));
return SCOPE_POP_ERROR();
}
bool success = cast_implicit(context, ret_expr, rtype);
assert(success);
if (may_failable) ret_expr->type = type_add_optional(ret_expr->type, may_failable);
}
call_expr->type = type_add_optional(rtype, failable);
@@ -2523,7 +2540,12 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr)
if (end && end->type != start->type)
{
Type *common = type_find_max_type(start->type, end->type);
if (!common || !cast_implicit(context, start, common) || !cast_implicit(context, end, common)) return false;
if (!common)
{
SEMA_ERROR(expr, "No common type can be found between start and end index.");
return false;
}
if (!cast_implicit(context, start, common) || !cast_implicit(context, end, common)) return false;
}
bool start_from_end = expr->subscript_expr.range.start_from_end;
@@ -3816,14 +3838,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr)
expr_replace(expr, inner);
return true;
}
if (!cast_may_explicit(inner->type, target_type, true, inner->expr_kind == EXPR_CONST))
{
return sema_error_failed_cast(expr, type_no_optional(inner->type), target_type);
}
if (!cast(inner, target_type))
{
return expr_poison(expr);
}
if (!cast_explicit(context, inner, target_type)) return expr_poison(expr);
expr_replace(expr, inner);
return true;
}
@@ -3853,8 +3868,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ
Range *left_range = &left->subscript_expr.range;
Range *right_range = &right->subscript_expr.range;
if (!sema_analyse_expr(context, right)) return false;
if (cast_may_implicit(right->type, base, CAST_OPTION_SIMPLE_EXPR)) goto ASSIGN;
if (!cast_implicit(context, right, left_type)) return false;
if (!cast_implicit_silent(context, right, left_type)) goto ASSIGN;
IndexDiff left_len = range_const_len(left_range);
IndexDiff right_len = range_const_len(right_range);
if (left_len >= 0 && right_len >= 0 && left_len != right_len)
@@ -3885,8 +3899,9 @@ bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type
}
// 1. Evaluate right side to required type.
if (!sema_analyse_expr_rhs(context, left_type, right, true)) return false;
if (IS_OPTIONAL(right) && !type_is_optional(left_type))
bool to_optional = left_type && type_is_optional(left_type);
if (!sema_analyse_expr_rhs(context, left_type, right, is_unwrapped || to_optional)) return false;
if (IS_OPTIONAL(right) && !to_optional)
{
if (is_unwrapped)
{
@@ -4112,12 +4127,7 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *
// 5. Cast the right hand side to the one on the left
if (!sema_analyse_expr(context, right)) return false;
if (!cast_implicit(context, right, no_fail)) return false;
if (IS_OPTIONAL(right) && !IS_OPTIONAL(left))
{
SEMA_ERROR(right, "This expression cannot be failable, since the assigned variable isn't.");
return false;
}
if (!cast_implicit_maybe_failable(context, right, no_fail, IS_OPTIONAL(left))) return false;
// 6. Check for zero in case of div or mod.
if (right->expr_kind == EXPR_CONST)
{
@@ -4252,7 +4262,8 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E
SEMA_ERROR(parent, error_message, type_quoted_error_string(left->type), type_quoted_error_string(right->type));
return false;
}
return cast_implicit(context, left, max) && cast_implicit(context, right, max);
return cast_implicit(context, left, max) &&
cast_implicit(context, right, max);
}
static void sema_binary_unify_voidptr(Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref)
@@ -4276,8 +4287,7 @@ static Type *defer_iptr_cast(Expr *maybe_pointer, Expr *maybe_diff)
// (iptr)((char*)(ptr) +- 1)
if (maybe_pointer->expr_kind == EXPR_CAST
&& maybe_pointer->cast_expr.kind == CAST_PTRXI
&& type_flatten(maybe_pointer->type) == type_flatten(type_iptr)
&& cast_may_implicit(maybe_diff->type, maybe_diff->type, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL))
&& type_flatten(maybe_pointer->type) == type_flatten(type_iptr))
{
Type *cast_to_iptr = maybe_pointer->type;
maybe_pointer->cast_expr.kind = CAST_PTRPTR;
@@ -4858,7 +4868,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp
static bool sema_expr_analyse_and_or(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{
if (!sema_binary_analyse_subexpr(context, expr, left, right)) return false;
if (!cast_implicit(context, left, type_bool) || !cast_implicit(context, right, type_bool)) return false;
if (!cast_explicit(context, left, type_bool) || !cast_explicit(context, right, type_bool)) return false;
if (expr_both_const(left, right))
{
@@ -5330,17 +5340,35 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr)
// 2. Check whether the type is a vector
Type *type = type_no_optional(inner->type);
if (type_flat_is_vector(type))
Type *flat = type_flatten_distinct(type);
if (type_kind_is_any_vector(flat->type_kind))
{
// 3. This always works, so we're done.
expr->type = type_add_optional(type_get_vector_bool(type), IS_OPTIONAL(inner));
return true;
// This may be some form of bool vector.
if (type_flatten(flat->array.base) == type_bool)
{
// If so then we're done.
expr->type = type;
return true;
}
Type *canonical = type->canonical;
switch (canonical->type_kind)
{
case TYPE_VECTOR:
expr->type = type_get_vector(type_bool, canonical->array.len);
return true;
case TYPE_SCALED_VECTOR:
expr->type = type_get_scaled_vector(type_bool);
return true;
case TYPE_INFERRED_VECTOR:
UNREACHABLE;
default:
break;
}
}
// 4. Let's see if it's possible to cast it implicitly
if (!cast_may_implicit(type, type_bool, CAST_OPTION_SIMPLE_EXPR | CAST_OPTION_ALLOW_OPTIONAL))
if (!cast_may_bool_convert(type))
{
SEMA_ERROR(expr, "The use of '!' on %s is not allowed as it can't be converted to a boolean value.", type_quoted_error_string(inner->type));
SEMA_ERROR(expr, "The %s can't be converted to a boolean value.", type_quoted_error_string(inner->type));
return false;
}
@@ -5348,7 +5376,7 @@ static inline bool sema_expr_analyse_not(SemaContext *context, Expr *expr)
if (inner->expr_kind == EXPR_CONST)
{
bool success = cast_implicit(context, inner, expr->type);
bool success = cast_explicit(context, inner, expr->type);
assert(success);
assert(inner->const_expr.const_kind == CONST_BOOL);
expr->const_expr.const_kind = CONST_BOOL;
@@ -6856,7 +6884,7 @@ bool sema_analyse_cond_expr(SemaContext *context, Expr *expr)
type_quoted_error_string(expr->type));
return false;
}
return cast_implicit(context, expr, type_bool);
return cast_explicit(context, expr, type_bool);
}
@@ -6877,7 +6905,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo
return false;
}
}
if (to && !cast_implicit(context, expr, to)) return false;
if (to && !cast_implicit_maybe_failable(context, expr, to, allow_failable)) return false;
if (!allow_failable && IS_OPTIONAL(expr))
{
SEMA_ERROR(expr, "You cannot have a failable here.");

View File

@@ -27,6 +27,12 @@
#define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK()
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
typedef enum
{
REPORT_ERROR,
REPORT_NONE,
} ReportType;
typedef enum
{
SPLIT_PATH_IDENT,

View File

@@ -898,21 +898,16 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
}
return true;
}
// 3a. Check for failables in case of an expression.
// 3a. Check for optional in case of an expression.
if (IS_OPTIONAL(last))
{
if (!cast_to_bool || cast_may_implicit(type_no_optional(last->type), type_bool, CAST_OPTION_NONE))
{
SEMA_ERROR(last, "The expression may not be a failable, but was %s.", type_quoted_error_string(last->type));
return false;
}
sema_error_failed_cast(last, type_no_optional(last->type), type_bool);
SEMA_ERROR(last, "The expression may not be an optional, but was %s.", type_quoted_error_string(last->type));
return false;
}
// 3b. Cast to bool if that is needed
if (cast_to_bool)
{
if (!cast_implicit(context, last, type_bool)) return false;
if (!cast_explicit(context, last, type_bool)) return false;
}
return true;
}

View File

@@ -1633,6 +1633,71 @@ Type *type_from_token(TokenType type)
}
}
bool type_array_element_is_equivalent(Type *element1, Type *element2, bool is_explicit)
{
RETRY:
if (is_explicit)
{
element1 = type_flatten_distinct(element1);
element2 = type_flatten_distinct(element2);
}
else
{
element1 = element1->canonical;
element2 = element2->canonical;
}
if (element1 == element2) return true;
switch (element1->type_kind)
{
case TYPE_POINTER:
if (element2->type_kind != TYPE_POINTER) return false;
return type_is_pointer_equivalent(element1, element2, is_explicit);
case TYPE_ARRAY:
if (element2->type_kind != TYPE_INFERRED_ARRAY && element1->array.len != element2->array.len) return false;
element1 = element1->array.base;
element2 = element2->array.base;
goto RETRY;
case TYPE_VECTOR:
if (element2->type_kind != TYPE_INFERRED_VECTOR && element1->array.len != element2->array.len) return false;
element1 = element1->array.base;
element2 = element2->array.base;
goto RETRY;
case TYPE_STRUCT:
if (is_explicit) return type_is_structurally_equivalent(element1, element2);
return false;
default:
return false;
}
}
bool type_is_pointer_equivalent(Type *pointer1, Type *pointer2, bool flatten_distinct)
{
RETRY:
if (flatten_distinct)
{
pointer1 = type_flatten_distinct(pointer1);
pointer2 = type_flatten_distinct(pointer2);
}
if (pointer1 == type_voidptr || pointer2 == type_voidptr) return true;
Type *pointee1 = pointer1->pointer->canonical;
Type *pointee2 = pointer2->pointer->canonical;
if (flatten_distinct)
{
pointee1 = type_flatten_distinct(pointee1);
pointee2 = type_flatten_distinct(pointee2);
}
if (pointee1->type_kind != pointee2->type_kind) return false;
if (pointee1->type_kind == TYPE_POINTER)
{
pointer1 = pointee1;
pointer2 = pointee2;
goto RETRY;
}
if (!type_is_arraylike(pointee1)) return false;
if (pointee1->array.len != pointee2->array.len) return false;
return type_array_element_is_equivalent(pointee1->array.base, pointer2->array.base, flatten_distinct);
}
bool type_may_have_method(Type *type)
{
DECL_TYPE_KIND_REAL(kind, type)