mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Improve inference on ?? #1943.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
- Distinct inline void causes unexpected error if used in slice #1946.
|
||||
- Allow `fn int test() => @pool() { return 1; }` short function syntax usage #1906.
|
||||
- Test runner will also check for leaks.
|
||||
- Improve inference on `??` #1943.
|
||||
|
||||
### Fixes
|
||||
- Fix issue requiring prefix on a generic interface declaration.
|
||||
|
||||
@@ -55,14 +55,14 @@ static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bo
|
||||
bool lvalue);
|
||||
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr);
|
||||
static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error);
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr, bool *failed_ref);
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Type *infer_type, Expr *expr, bool *failed_ref);
|
||||
static inline bool sema_expr_resolve_ct_eval(SemaContext *context, Expr *expr);
|
||||
static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr);
|
||||
static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr);
|
||||
|
||||
static inline bool sema_expr_analyse_ternary(SemaContext *context, Type *infer_type, Expr *expr);
|
||||
static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool *invalid_cast_ref);
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right);
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right, Type *infer_type);
|
||||
static inline bool sema_expr_analyse_unary(SemaContext *context, Expr *expr, bool *failed_ref, CheckType check);
|
||||
static inline bool sema_expr_analyse_embed(SemaContext *context, Expr *expr, bool allow_fail);
|
||||
|
||||
@@ -6007,7 +6007,7 @@ static bool sema_binary_analyse_ct_op_assign(SemaContext *context, Expr *expr, E
|
||||
}
|
||||
expr->binary_expr.operator = binaryop_assign_base_op(expr->binary_expr.operator);
|
||||
|
||||
if (!sema_expr_analyse_binary(context, expr, NULL)) return false;
|
||||
if (!sema_expr_analyse_binary(context, NULL, expr, NULL)) return false;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
|
||||
if (!sema_cast_const(expr))
|
||||
@@ -6041,7 +6041,7 @@ static bool sema_binary_analyse_ct_subscript_op_assign(SemaContext *context, Exp
|
||||
|
||||
BinaryOp op = binaryop_assign_base_op(expr->binary_expr.operator);
|
||||
expr->binary_expr = (ExprBinary) { .left = exprid(value), .right = expr->binary_expr.right, .operator = op };
|
||||
if (!sema_expr_analyse_binary(context, expr, NULL)) return false;
|
||||
if (!sema_expr_analyse_binary(context, NULL, expr, NULL)) return false;
|
||||
if (!sema_expr_analyse_ct_subscript_set_value(context, left, left_var, expr)) return false;
|
||||
return true;
|
||||
|
||||
@@ -7862,13 +7862,12 @@ INLINE bool expr_is_ungrouped_ternary(Expr *expr)
|
||||
return expr->expr_kind == EXPR_TERNARY && !expr->ternary_expr.grouped;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right)
|
||||
static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right, Type *infer_type)
|
||||
{
|
||||
bool lhs_is_embed = left->expr_kind == EXPR_EMBED;
|
||||
if (expr_is_ungrouped_ternary(left) || expr_is_ungrouped_ternary(right))
|
||||
{
|
||||
SEMA_ERROR(expr, "Unclear precedence using ternary with ??, please use () to remove ambiguity.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(expr, "Unclear precedence using ternary with ??, please use () to remove ambiguity.");
|
||||
}
|
||||
if (lhs_is_embed)
|
||||
{
|
||||
@@ -7876,7 +7875,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr(context, left)) return false;
|
||||
if (!sema_analyse_inferred_expr(context, infer_type, left)) return false;
|
||||
}
|
||||
|
||||
Type *type = left->type;
|
||||
@@ -7888,13 +7887,12 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
|
||||
return true;
|
||||
}
|
||||
RETURN_SEMA_ERROR(left, "No optional to use '\?\?' with, please remove the '\?\?'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool active_scope_jump = context->active_scope.jump_end;
|
||||
|
||||
// First we analyse the "else" and try to implictly cast.
|
||||
if (!sema_analyse_expr(context, right)) return false;
|
||||
if (!sema_analyse_inferred_expr(context, infer_type, right)) return false;
|
||||
|
||||
if (left->expr_kind == EXPR_OPTIONAL)
|
||||
{
|
||||
@@ -7916,9 +7914,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr,
|
||||
Type *common = type_find_max_type(type, else_type);
|
||||
if (!common)
|
||||
{
|
||||
SEMA_ERROR(right, "Cannot find a common type for %s and %s.", type_quoted_error_string(type),
|
||||
type_quoted_error_string(else_type));
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(right, "Cannot find a common type for %s and %s.", type_quoted_error_string(type), type_quoted_error_string(else_type));
|
||||
}
|
||||
if (!cast_implicit(context, left, common, false)) return false;
|
||||
if (!cast_implicit(context, right, common, false)) return false;
|
||||
@@ -7943,7 +7939,7 @@ static inline bool sema_expr_analyse_ct_and_or(SemaContext *context, Expr *expr,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr, bool *failed_ref)
|
||||
static inline bool sema_expr_analyse_binary(SemaContext *context, Type *infer_type, Expr *expr, bool *failed_ref)
|
||||
{
|
||||
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING);
|
||||
Expr *left = exprptr(expr->binary_expr.left);
|
||||
@@ -7958,7 +7954,7 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr, bo
|
||||
switch (operator)
|
||||
{
|
||||
case BINARYOP_ELSE:
|
||||
return sema_expr_analyse_or_error(context, expr, left, right);
|
||||
return sema_expr_analyse_or_error(context, expr, left, right, infer_type);
|
||||
case BINARYOP_CT_CONCAT:
|
||||
return sema_expr_analyse_ct_concat(context, expr, left, right);
|
||||
case BINARYOP_CT_OR:
|
||||
@@ -9340,7 +9336,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
UNREACHABLE
|
||||
case EXPR_BINARY:
|
||||
main_expr->resolve_status = RESOLVE_RUNNING;
|
||||
if (!sema_expr_analyse_binary(context, main_expr, &failed))
|
||||
if (!sema_expr_analyse_binary(context, NULL, main_expr, &failed))
|
||||
{
|
||||
if (!failed) goto FAIL;
|
||||
success = false;
|
||||
@@ -9942,7 +9938,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
|
||||
if (!sema_expr_resolve_ct_eval(context, expr)) return false;
|
||||
return sema_analyse_expr_dispatch(context, expr, check);
|
||||
case EXPR_BINARY:
|
||||
return sema_expr_analyse_binary(context, expr, NULL);
|
||||
return sema_expr_analyse_binary(context, NULL, expr, NULL);
|
||||
case EXPR_TERNARY:
|
||||
return sema_expr_analyse_ternary(context, NULL, expr);
|
||||
case EXPR_UNARY:
|
||||
@@ -10591,6 +10587,9 @@ RETRY:
|
||||
case EXPR_LAMBDA:
|
||||
if (!sema_expr_analyse_lambda(context, to, expr)) return expr_poison(expr);
|
||||
break;
|
||||
case EXPR_BINARY:
|
||||
if (!sema_expr_analyse_binary(context, to, expr, NULL)) return expr_poison(expr);
|
||||
break;
|
||||
case EXPR_TERNARY:
|
||||
if (!sema_expr_analyse_ternary(context, to, expr)) return expr_poison(expr);
|
||||
break;
|
||||
|
||||
@@ -82,14 +82,17 @@ entry:
|
||||
%not_err = icmp eq i64 %optval, 0
|
||||
%18 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %18, label %after_check, label %else_block
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%19 = load i32, ptr %w, align 4
|
||||
%sext13 = sext i32 %19 to i64
|
||||
br label %phi_block
|
||||
|
||||
else_block: ; preds = %entry
|
||||
br label %phi_block
|
||||
|
||||
phi_block: ; preds = %else_block, %after_check
|
||||
%val = phi i32 [ %19, %after_check ], [ 1, %else_block ]
|
||||
%sext13 = sext i32 %val to i64
|
||||
store i64 %sext13, ptr %z, align 8
|
||||
%val = phi i64 [ %sext13, %after_check ], [ 1, %else_block ]
|
||||
store i64 %val, ptr %z, align 8
|
||||
ret void
|
||||
}
|
||||
@@ -57,45 +57,45 @@ phi_block: ; preds = %else_block, %after_
|
||||
%6 = call i64 @testError(ptr %retparam5)
|
||||
%not_err6 = icmp eq i64 %6, 0
|
||||
%7 = call i1 @llvm.expect.i1(i1 %not_err6, i1 true)
|
||||
br i1 %7, label %after_check7, label %else_block8
|
||||
br i1 %7, label %after_check7, label %else_block9
|
||||
|
||||
after_check7: ; preds = %phi_block
|
||||
%8 = load i32, ptr %retparam5, align 4
|
||||
%shl = shl i32 1, %8
|
||||
%9 = freeze i32 %shl
|
||||
br label %phi_block9
|
||||
%sifp8 = sitofp i32 %9 to double
|
||||
br label %phi_block10
|
||||
|
||||
else_block8: ; preds = %phi_block
|
||||
br label %phi_block9
|
||||
else_block9: ; preds = %phi_block
|
||||
br label %phi_block10
|
||||
|
||||
phi_block9: ; preds = %else_block8, %after_check7
|
||||
%val10 = phi i32 [ %9, %after_check7 ], [ 100, %else_block8 ]
|
||||
%sifp11 = sitofp i32 %val10 to double
|
||||
store double %sifp11, ptr %y, align 8
|
||||
phi_block10: ; preds = %else_block9, %after_check7
|
||||
%val11 = phi double [ %sifp8, %after_check7 ], [ 1.000000e+02, %else_block9 ]
|
||||
store double %val11, ptr %y, align 8
|
||||
%10 = call i64 @testError(ptr %retparam12)
|
||||
%not_err13 = icmp eq i64 %10, 0
|
||||
%11 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true)
|
||||
br i1 %11, label %after_check14, label %else_block15
|
||||
br i1 %11, label %after_check14, label %else_block16
|
||||
|
||||
after_check14: ; preds = %phi_block9
|
||||
after_check14: ; preds = %phi_block10
|
||||
%12 = load i32, ptr %retparam12, align 4
|
||||
%ashr = ashr i32 %12, 1
|
||||
%13 = freeze i32 %ashr
|
||||
br label %phi_block16
|
||||
%sifp15 = sitofp i32 %13 to double
|
||||
br label %phi_block17
|
||||
|
||||
else_block15: ; preds = %phi_block9
|
||||
br label %phi_block16
|
||||
else_block16: ; preds = %phi_block10
|
||||
br label %phi_block17
|
||||
|
||||
phi_block16: ; preds = %else_block15, %after_check14
|
||||
%val17 = phi i32 [ %13, %after_check14 ], [ 100, %else_block15 ]
|
||||
%sifp18 = sitofp i32 %val17 to double
|
||||
store double %sifp18, ptr %z, align 8
|
||||
phi_block17: ; preds = %else_block16, %after_check14
|
||||
%val18 = phi double [ %sifp15, %after_check14 ], [ 1.000000e+02, %else_block16 ]
|
||||
store double %val18, ptr %z, align 8
|
||||
%14 = call i64 @testError(ptr %retparam19)
|
||||
%not_err20 = icmp eq i64 %14, 0
|
||||
%15 = call i1 @llvm.expect.i1(i1 %not_err20, i1 true)
|
||||
br i1 %15, label %after_check21, label %else_block27
|
||||
|
||||
after_check21: ; preds = %phi_block16
|
||||
after_check21: ; preds = %phi_block17
|
||||
%16 = load i32, ptr %retparam19, align 4
|
||||
%sifp22 = sitofp i32 %16 to double
|
||||
%17 = call i64 @testError(ptr %retparam23)
|
||||
@@ -109,7 +109,7 @@ after_check25: ; preds = %after_check21
|
||||
%fmul = fmul double %sifp22, %sifp26
|
||||
br label %phi_block28
|
||||
|
||||
else_block27: ; preds = %after_check21, %phi_block16
|
||||
else_block27: ; preds = %after_check21, %phi_block17
|
||||
br label %phi_block28
|
||||
|
||||
phi_block28: ; preds = %else_block27, %after_check25
|
||||
|
||||
96
test/test_suite/errors/or_err_infer.c3t
Normal file
96
test/test_suite/errors/or_err_infer.c3t
Normal file
@@ -0,0 +1,96 @@
|
||||
// #target: macos-x64
|
||||
enum Foo
|
||||
{
|
||||
ABC,
|
||||
DEF
|
||||
}
|
||||
|
||||
fn int main()
|
||||
{
|
||||
int a;
|
||||
Foo! x = ABC;
|
||||
Foo f = x ?? DEF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* expect: test.ll
|
||||
|
||||
define void @top_down_casts.test() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
%z = alloca i64, align 8
|
||||
%w = alloca i32, align 4
|
||||
%w.f = alloca i64, align 8
|
||||
store i32 0, ptr %x, align 4
|
||||
store i32 0, ptr %y, align 4
|
||||
%0 = load i32, ptr %x, align 4
|
||||
%sext = sext i32 %0 to i64
|
||||
%1 = load i32, ptr %y, align 4
|
||||
%sext1 = sext i32 %1 to i64
|
||||
%mul = mul i64 %sext, %sext1
|
||||
store i64 %mul, ptr %z, align 8
|
||||
%2 = load i32, ptr %x, align 4
|
||||
%3 = load i32, ptr %y, align 4
|
||||
%sdiv = sdiv i32 %2, %3
|
||||
%sext2 = sext i32 %sdiv to i64
|
||||
store i64 %sext2, ptr %z, align 8
|
||||
%4 = load i32, ptr %x, align 4
|
||||
%sext3 = sext i32 %4 to i64
|
||||
%5 = load i32, ptr %y, align 4
|
||||
%sext4 = sext i32 %5 to i64
|
||||
%add = add i64 %sext3, %sext4
|
||||
store i64 %add, ptr %z, align 8
|
||||
%6 = load i32, ptr %x, align 4
|
||||
%sext5 = sext i32 %6 to i64
|
||||
%7 = load i32, ptr %y, align 4
|
||||
%sext6 = sext i32 %7 to i64
|
||||
%sub = sub i64 %sext5, %sext6
|
||||
store i64 %sub, ptr %z, align 8
|
||||
%8 = load i32, ptr %x, align 4
|
||||
%9 = load i32, ptr %y, align 4
|
||||
%smod = srem i32 %8, %9
|
||||
%sext7 = sext i32 %smod to i64
|
||||
store i64 %sext7, ptr %z, align 8
|
||||
%10 = load i32, ptr %x, align 4
|
||||
%sext8 = sext i32 %10 to i64
|
||||
%11 = load i32, ptr %y, align 4
|
||||
%zext = zext i32 %11 to i64
|
||||
%shl = shl i64 %sext8, %zext
|
||||
%12 = freeze i64 %shl
|
||||
store i64 %12, ptr %z, align 8
|
||||
%13 = load i32, ptr %x, align 4
|
||||
%sext9 = sext i32 %13 to i64
|
||||
%14 = load i32, ptr %y, align 4
|
||||
%zext10 = zext i32 %14 to i64
|
||||
%ashr = ashr i64 %sext9, %zext10
|
||||
%15 = freeze i64 %ashr
|
||||
store i64 %15, ptr %z, align 8
|
||||
%16 = load i32, ptr %x, align 4
|
||||
%bnot = xor i32 %16, -1
|
||||
%sext11 = sext i32 %bnot to i64
|
||||
store i64 %sext11, ptr %z, align 8
|
||||
%17 = load i32, ptr %x, align 4
|
||||
%neg = sub i32 0, %17
|
||||
%sext12 = sext i32 %neg to i64
|
||||
store i64 %sext12, ptr %z, align 8
|
||||
store i64 0, ptr %w.f, align 8
|
||||
store i32 0, ptr %w, align 4
|
||||
%optval = load i64, ptr %w.f, align 8
|
||||
%not_err = icmp eq i64 %optval, 0
|
||||
%18 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %18, label %after_check, label %else_block
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%19 = load i32, ptr %w, align 4
|
||||
%sext13 = sext i32 %19 to i64
|
||||
br label %phi_block
|
||||
|
||||
else_block: ; preds = %entry
|
||||
br label %phi_block
|
||||
|
||||
phi_block: ; preds = %else_block, %after_check
|
||||
%val = phi i64 [ %sext13, %after_check ], [ 1, %else_block ]
|
||||
store i64 %val, ptr %z, align 8
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user