From 0925010c07912c447b98dfd9c28de38b8ac9c15a Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 3 Mar 2025 15:02:25 +0100 Subject: [PATCH] Removal of any-switches --- lib/std/io/formatter.c3 | 3 +- lib/std/io/formatter_private.c3 | 56 ++--- releasenotes.md | 1 + src/compiler/compiler_internal.h | 18 -- src/compiler/copying.c | 1 - src/compiler/enums.h | 3 +- src/compiler/expr.c | 3 - src/compiler/sema_expr.c | 5 - src/compiler/sema_stmts.c | 126 +--------- test/test_suite/any/variant_assign.c3t | 320 +++---------------------- test/test_suite/any/variant_switch.c3t | 78 +++--- test/unit/regression/any.c3 | 2 +- test/unit/regression/subtype.c3 | 6 +- 13 files changed, 101 insertions(+), 521 deletions(-) diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index 9ce3f29ae..86b4dc35a 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -479,10 +479,9 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys) nextcase; case 'h': char[] out @noinit; - switch (current) + switch (current.type) { case char[]: - out = *current; case ichar[]: out = *(char[]*)current; default: diff --git a/lib/std/io/formatter_private.c3 b/lib/std/io/formatter_private.c3 index 503519371..52d364f81 100644 --- a/lib/std/io/formatter_private.c3 +++ b/lib/std/io/formatter_private.c3 @@ -52,40 +52,40 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private break; } *is_neg = false; - switch (arg) + switch (arg.type) { case bool: - return (uint128)*arg; + return *(uint128*)arg; case ichar: - int val = *arg; + int val = *(ichar*)arg; return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case short: - int val = *arg; + int val = *(short*)arg; return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case int: - int val = *arg; + int val = *(int*)arg; return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case long: - long val = *arg; + long val = *(long*)arg; return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case int128: - int128 val = *arg; + int128 val = *(int128*)arg; return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case char: - return *arg; + return *(char*)arg; case ushort: - return *arg; + return *(ushort*)arg; case uint: - return *arg; + return *(uint*)arg; case ulong: - return *arg; + return *(ulong*)arg; case uint128: - return *arg; + return *(uint128*)arg; case float: - float f = *arg; + float f = *(float*)arg; return (uint128)((*is_neg = f < 0) ? -f : f); case double: - double d = *arg; + double d = *(double*)arg; return (uint128)((*is_neg = d < 0) ? -d : d); default: return FormattingFault.BAD_FORMAT?; @@ -101,34 +101,34 @@ fn FloatType! float_from_any(any arg) @private { return float_from_any(arg.as_inner()); } - switch (arg) + switch (arg.type) { case bool: - return (FloatType)*arg; + return (FloatType)*(bool*)arg; case ichar: - return *arg; + return *(ichar*)arg; case short: - return *arg; + return *(short*)arg; case int: - return *arg; + return *(int*)arg; case long: - return *arg; + return *(long*)arg; case int128: - return *arg; + return *(int128*)arg; case char: - return *arg; + return *(char*)arg; case ushort: - return *arg; + return *(ushort*)arg; case uint: - return *arg; + return *(uint*)arg; case ulong: - return *arg; + return *(ulong*)arg; case uint128: - return *arg; + return *(uint128*)arg; case float: - return (FloatType)*arg; + return (FloatType)*(float*)arg; case double: - return (FloatType)*arg; + return (FloatType)*(double*)arg; default: return FormattingFault.BAD_FORMAT?; } diff --git a/releasenotes.md b/releasenotes.md index 26d431086..cc6553ed1 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -15,6 +15,7 @@ - Disallow inline use of nested generics (e.g. `List{List{int}}`. - Remove `.allocator = allocator` syntax for functions. - Remove `@operator(construct)`. +- Removal of "any-switch". ### Fixes - Fix address sanitizer to work on MachO targets (e.g. MacOS). diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 15e0fb59d..c2d341b72 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1057,22 +1057,6 @@ typedef struct BuiltinFunction builtin; } ExprBuiltin; -typedef struct -{ - bool is_assign : 1; - bool is_deref : 1; - union - { - struct - { - const char *new_ident; - SourceSpan span; - Expr *any_expr; - }; - Decl *variable; - }; -} ExprAnySwitch; - typedef struct { ExprId parent; @@ -1132,7 +1116,6 @@ struct Expr_ union { ExprResolvedAccess access_resolved_expr; ExprUnresolvedAccess access_unresolved_expr;// 16 - ExprAnySwitch any_switch; // 32 ExprBinary binary_expr; // 12 ExprBinary veccomp_expr; ExprBodyExpansion body_expansion_expr; // 24 @@ -3486,7 +3469,6 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc) case EXPR_TYPEINFO: case EXPR_UNARY: case EXPR_UNRESOLVED_IDENTIFIER: - case EXPR_ANYSWITCH: case EXPR_VASPLAT: case EXPR_MACRO_BODY: case EXPR_DEFAULT_ARG: diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 9e2a5a769..7838e585f 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -295,7 +295,6 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) switch (source_expr->expr_kind) { case EXPR_TYPECALL: - case EXPR_ANYSWITCH: case EXPR_CT_SUBSCRIPT: UNREACHABLE case EXPR_OTHER_CONTEXT: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index a82c20e67..0a26a9a23 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -716,7 +716,6 @@ typedef enum { EXPR_ACCESS_RESOLVED, EXPR_ACCESS_UNRESOLVED, - EXPR_ANYSWITCH, EXPR_ASM, EXPR_BENCHMARK_HOOK, EXPR_BINARY, @@ -1601,7 +1600,7 @@ typedef enum case EXPR_CT_CASTABLE: case EXPR_CT_IS_CONST: \ case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \ case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \ - case EXPR_SPLAT: case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_TYPECALL: \ + case EXPR_SPLAT: case EXPR_STRINGIFY: case EXPR_TYPECALL: \ case EXPR_CT_EVAL static_assert(EXPR_LAST < 128, "Too many expression types"); diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 7851d0e2c..018d515bb 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -14,7 +14,6 @@ const char *expr_kind_to_string(ExprKind kind) { case EXPR_ACCESS_UNRESOLVED: return "access_unresolved"; case EXPR_ACCESS_RESOLVED: return "access_resolved"; - case EXPR_ANYSWITCH: return "anyswitch"; case EXPR_ASM: return "asm"; case EXPR_BENCHMARK_HOOK: return "benchmark_hook"; case EXPR_BINARY: return "binary"; @@ -307,7 +306,6 @@ bool expr_is_runtime_const(Expr *expr) case EXPR_CT_EVAL: case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: - case EXPR_ANYSWITCH: case EXPR_BITASSIGN: case EXPR_TYPECALL: case EXPR_BINARY: @@ -816,7 +814,6 @@ bool expr_is_pure(Expr *expr) case EXPR_MEMBER_GET: return true; case EXPR_BITASSIGN: - case EXPR_ANYSWITCH: return false; case EXPR_BINARY: // Anything with assignment is impure, otherwise true if sub expr are pure. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index caa7719d7..954edbd13 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -551,7 +551,6 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp case EXPR_HASH_IDENT: case EXPR_POISONED: case EXPR_ADDR_CONVERSION: - case EXPR_ANYSWITCH: case EXPR_ASM: case EXPR_BENCHMARK_HOOK: case EXPR_BINARY: @@ -708,7 +707,6 @@ static bool expr_may_ref(Expr *expr) case EXPR_EXPRESSION_LIST: if (!vec_size(expr->expression_list)) return false; return expr_may_ref(VECLAST(expr->expression_list)); - case EXPR_ANYSWITCH: case EXPR_ASM: case EXPR_BENCHMARK_HOOK: case EXPR_BINARY: @@ -9158,7 +9156,6 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr case EXPR_TRY_UNRESOLVED: case EXPR_TRY: case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_ANYSWITCH: case EXPR_OPERATOR_CHARS: case EXPR_MACRO_BODY_EXPANSION: case EXPR_BUILTIN_ACCESS: @@ -9530,7 +9527,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, { switch (expr->expr_kind) { - case EXPR_ANYSWITCH: case EXPR_ASM: case EXPR_BENCHMARK_HOOK: case EXPR_CATCH_UNRESOLVED: @@ -10051,7 +10047,6 @@ IDENT_CHECK:; case EXPR_INT_TO_BOOL: case EXPR_DISCARD: case EXPR_ADDR_CONVERSION: - case EXPR_ANYSWITCH: case EXPR_ASM: case EXPR_BENCHMARK_HOOK: case EXPR_BINARY: diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index a65a38568..4d57b1fb6 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -46,7 +46,7 @@ static inline bool sema_check_type_case(SemaContext *context, Ast *case_stmt, As static inline bool sema_check_value_case(SemaContext *context, Type *switch_type, Ast *case_stmt, Ast **cases, unsigned index, bool *if_chained, bool *max_ranged, uint64_t *actual_cases_ref, Int *low, Int *high); -static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprAnySwitch *any_switch, Decl *var_holder); +static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases); static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *statement); static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **asserts, SourceSpan source); @@ -773,7 +773,6 @@ static inline bool sema_expr_valid_try_expression(Expr *expr) case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TYPEID_INFO: case EXPR_TYPEINFO: - case EXPR_ANYSWITCH: case EXPR_ACCESS_RESOLVED: case EXPR_ASM: case EXPR_DEFAULT_ARG: @@ -1017,63 +1016,6 @@ static inline bool sema_analyse_last_cond(SemaContext *context, Expr *expr, Cond default: break; } - - if (cond_type != COND_TYPE_EVALTYPE_VALUE) goto NORMAL_EXPR; - - // Now we're analysing the last expression in a switch. - // Case 1: switch (var = variant_expr) - if (expr->expr_kind == EXPR_BINARY && expr->binary_expr.operator == BINARYOP_ASSIGN) - { - // No variable on the lhs? Then it can't be an any unwrap. - Expr *left = exprptr(expr->binary_expr.left); - if (left->resolve_status == RESOLVE_DONE || left->expr_kind != EXPR_UNRESOLVED_IDENTIFIER || left->unresolved_ident_expr.path) goto NORMAL_EXPR; - - // Does the identifier exist in the parent scope? - // then again it can't be an any unwrap. - BoolErr defined_in_scope = sema_symbol_is_defined_in_scope(context, left->unresolved_ident_expr.ident); - if (defined_in_scope == BOOL_ERR) return false; - if (defined_in_scope == BOOL_TRUE) goto NORMAL_EXPR; - - Expr *right = exprptr(expr->binary_expr.right); - bool is_deref = right->expr_kind == EXPR_UNARY && right->unary_expr.operator == UNARYOP_DEREF; - if (is_deref) right = right->unary_expr.expr; - if (!sema_analyse_expr_rhs(context, NULL, right, false, NULL, false)) return false; - Type *type = right->type->canonical; - if (type == type_get_ptr(type_any) && is_deref) - { - is_deref = false; - right = exprptr(expr->binary_expr.right); - if (!sema_analyse_expr_rhs(context, NULL, right, false, NULL, false)) return false; - } - if (type != type_any) goto NORMAL_EXPR; - // Found an expansion here - expr->expr_kind = EXPR_ANYSWITCH; - expr->any_switch.new_ident = left->unresolved_ident_expr.ident; - expr->any_switch.span = left->span; - expr->any_switch.any_expr = right; - expr->any_switch.is_deref = is_deref; - expr->any_switch.is_assign = true; - expr->resolve_status = RESOLVE_DONE; - expr->type = type_typeid; - return true; - } - if (!sema_analyse_expr(context, expr)) return false; - Type *type = expr->type->canonical; - if (type != type_any) return true; - if (expr->expr_kind == EXPR_IDENTIFIER) - { - Decl *decl = expr->ident_expr; - expr->expr_kind = EXPR_ANYSWITCH; - expr->any_switch.is_deref = false; - expr->any_switch.is_assign = false; - expr->any_switch.variable = decl; - expr->type = type_typeid; - expr->resolve_status = RESOLVE_DONE; - return true; - } - return true; - -NORMAL_EXPR:; return sema_analyse_expr(context, expr); } /** @@ -2400,7 +2342,7 @@ DONE:; scratch_buffer_append(" - either add them or use 'default'."); return scratch_buffer_to_string(); } -static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprAnySwitch *any_switch, Decl *var_holder) +static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases) { if (!type_is_comparable(switch_type)) { @@ -2476,42 +2418,6 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL; PUSH_NEXT(next, statement); Ast *body = stmt->case_stmt.body; - if (stmt->ast_kind == AST_CASE_STMT && body && type_switch && var_holder && sema_cast_const(exprptr(stmt->case_stmt.expr))) - { - if (any_switch->is_assign) - { - Type *real_type = type_get_ptr(exprptr(stmt->case_stmt.expr)->const_expr.typeid); - Decl *new_var = decl_new_var(any_switch->new_ident, any_switch->span, - type_info_new_base(any_switch->is_deref - ? real_type->pointer : real_type, any_switch->span), - VARDECL_LOCAL); - Expr *var_result = expr_variable(var_holder); - if (!cast_explicit(context, var_result, real_type)) return false; - if (any_switch->is_deref) - { - expr_rewrite_insert_deref(var_result); - } - new_var->var.init_expr = var_result; - Ast *decl_ast = new_ast(AST_DECLARE_STMT, new_var->span); - decl_ast->declare_stmt = new_var; - ast_prepend(&body->compound_stmt.first_stmt, decl_ast); - } - else - { - Expr *expr = exprptr(stmt->case_stmt.expr); - Type *type = type_get_ptr(expr->const_expr.typeid); - Decl *alias = decl_new_var(var_holder->name, var_holder->span, - type_info_new_base(type, expr->span), - VARDECL_LOCAL); - Expr *ident_converted = expr_variable(var_holder); - if (!cast_explicit(context, ident_converted, type)) return false; - alias->var.init_expr = ident_converted; - alias->var.shadow = true; - Ast *decl_ast = new_ast(AST_DECLARE_STMT, alias->span); - decl_ast->declare_stmt = alias; - ast_prepend(&body->compound_stmt.first_stmt, decl_ast); - } - } success = success && (!body || sema_analyse_compound_statement_no_scope(context, body)); POP_BREAK(); POP_NEXT(); @@ -2859,38 +2765,12 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement Expr *cond = exprptrzero(statement->switch_stmt.cond); Type *switch_type; - ExprAnySwitch var_switch; - Decl *any_decl = NULL; if (statement->ast_kind == AST_SWITCH_STMT) { CondResult res = COND_MISSING; if (cond && !sema_analyse_cond(context, cond, COND_TYPE_EVALTYPE_VALUE, &res)) return false; Expr *last = cond ? VECLAST(cond->cond_expr) : NULL; switch_type = last ? last->type->canonical : type_bool; - if (last && last->expr_kind == EXPR_ANYSWITCH) - { - var_switch = last->any_switch; - Expr *inner; - if (var_switch.is_assign) - { - inner = expr_new(EXPR_DECL, last->span); - any_decl = decl_new_generated_var(type_any, VARDECL_LOCAL, last->span); - any_decl->var.init_expr = var_switch.any_expr; - inner->decl_expr = any_decl; - if (!sema_analyse_expr(context, inner)) return false; - } - else - { - inner = expr_new(EXPR_IDENTIFIER, last->span); - any_decl = var_switch.variable; - expr_resolve_ident(inner, any_decl); - inner->type = type_any; - } - expr_rewrite_to_builtin_access(last, inner, ACCESS_TYPEOFANY, type_typeid); - switch_type = type_typeid; - cond->type = type_typeid; - } - } else { @@ -2900,7 +2780,7 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement statement->switch_stmt.defer = context->active_scope.defer_last; if (!sema_analyse_switch_body(context, statement, cond ? cond->span : statement->span, switch_type->canonical, - statement->switch_stmt.cases, any_decl ? &var_switch : NULL, any_decl)) + statement->switch_stmt.cases)) { return SCOPE_POP_ERROR(); } diff --git a/test/test_suite/any/variant_assign.c3t b/test/test_suite/any/variant_assign.c3t index 6e1aab1fa..8433c617b 100644 --- a/test/test_suite/any/variant_assign.c3t +++ b/test/test_suite/any/variant_assign.c3t @@ -5,38 +5,12 @@ extern fn void printf(char*, ...); fn void test(any z) { - switch (z) + switch (z.type) { case int: - printf("int: %d\n", *z); + printf("int: %d\n", *(int*)z); case double: - printf("double %f\n", *z); - default: - printf("Unknown type.\n"); - } -} -fn void test2(any y) -{ - switch (z = y) - { - case int: - y = &&12; - printf("int: %d\n", *z); - case double: - printf("double %f\n", *z); - default: - printf("Unknown type.\n"); - } -} - -fn void test3(any y) -{ - switch (z = *y) - { - case int: - printf("int: %d\n", z); - case double: - printf("double %f\n", z); + printf("double %f\n", *(double*)z); default: printf("Unknown type.\n"); } @@ -47,12 +21,6 @@ fn int main() test(&&123.0); test(&&1); test(&&true); - test2(&&123.5); - test2(&&1); - test2(&&true); - test3(&&124.0); - test3(&&2); - test3(&&true); return 0; } @@ -66,8 +34,6 @@ define void @foo.test(i64 %0, ptr %1) #0 { entry: %z = alloca %any, align 8 %switch = alloca i64, align 8 - %z3 = alloca ptr, align 8 - %z11 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptradd = getelementptr inbounds i8, ptr %z, i64 8 store ptr %1, ptr %ptradd, align 8 @@ -98,218 +64,46 @@ result_block: ; preds = %parent_type_block, switch.case: ; preds = %result_block %8 = load ptr, ptr %z, align 8 - store ptr %8, ptr %z3, align 8 - %9 = load ptr, ptr %z3, align 8 - %10 = load i32, ptr %9, align 4 - call void (ptr, ...) @printf(ptr @.str, i32 %10) + %9 = load i32, ptr %8, align 4 + call void (ptr, ...) @printf(ptr @.str, i32 %9) br label %switch.exit next_if: ; preds = %result_block - br label %check_subtype4 + br label %check_subtype3 -check_subtype4: ; preds = %parent_type_block6, %next_if - %11 = phi i64 [ %3, %next_if ], [ %typeid.parent8, %parent_type_block6 ] - %eq5 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %11 - br i1 %eq5, label %result_block9, label %parent_type_block6 +check_subtype3: ; preds = %parent_type_block5, %next_if + %10 = phi i64 [ %3, %next_if ], [ %typeid.parent7, %parent_type_block5 ] + %eq4 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %10 + br i1 %eq4, label %result_block8, label %parent_type_block5 -parent_type_block6: ; preds = %check_subtype4 - %12 = inttoptr i64 %11 to ptr - %ptradd7 = getelementptr inbounds i8, ptr %12, i64 8 - %typeid.parent8 = load i64, ptr %ptradd7, align 8 - %13 = icmp eq i64 %typeid.parent8, 0 - br i1 %13, label %result_block9, label %check_subtype4 +parent_type_block5: ; preds = %check_subtype3 + %11 = inttoptr i64 %10 to ptr + %ptradd6 = getelementptr inbounds i8, ptr %11, i64 8 + %typeid.parent7 = load i64, ptr %ptradd6, align 8 + %12 = icmp eq i64 %typeid.parent7, 0 + br i1 %12, label %result_block8, label %check_subtype3 -result_block9: ; preds = %parent_type_block6, %check_subtype4 - %14 = phi i1 [ false, %parent_type_block6 ], [ true, %check_subtype4 ] - br i1 %14, label %switch.case10, label %next_if12 +result_block8: ; preds = %parent_type_block5, %check_subtype3 + %13 = phi i1 [ false, %parent_type_block5 ], [ true, %check_subtype3 ] + br i1 %13, label %switch.case9, label %next_if10 -switch.case10: ; preds = %result_block9 - %15 = load ptr, ptr %z, align 8 - store ptr %15, ptr %z11, align 8 - %16 = load ptr, ptr %z11, align 8 - %17 = load double, ptr %16, align 8 - call void (ptr, ...) @printf(ptr @.str.1, double %17) +switch.case9: ; preds = %result_block8 + %14 = load ptr, ptr %z, align 8 + %15 = load double, ptr %14, align 8 + call void (ptr, ...) @printf(ptr @.str.1, double %15) br label %switch.exit -next_if12: ; preds = %result_block9 +next_if10: ; preds = %result_block8 br label %switch.default -switch.default: ; preds = %next_if12 +switch.default: ; preds = %next_if10 call void (ptr, ...) @printf(ptr @.str.2) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case10, %switch.case +switch.exit: ; preds = %switch.default, %switch.case9, %switch.case ret void } -; Function Attrs: -define void @foo.test2(i64 %0, ptr %1) #0 { -entry: - %y = alloca %any, align 8 - %switch = alloca i64, align 8 - %z = alloca ptr, align 8 - %taddr = alloca i32, align 4 - %z9 = alloca ptr, align 8 - store i64 %0, ptr %y, align 8 - %ptradd = getelementptr inbounds i8, ptr %y, i64 8 - store ptr %1, ptr %ptradd, align 8 - %2 = load %any, ptr %y, align 8 - %3 = extractvalue %any %2, 1 - store i64 %3, ptr %switch, align 8 - br label %switch.entry - -switch.entry: ; preds = %entry - %4 = load i64, ptr %switch, align 8 - br label %check_subtype - -check_subtype: ; preds = %parent_type_block, %switch.entry - %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 - br i1 %eq, label %result_block, label %parent_type_block - -parent_type_block: ; preds = %check_subtype - %6 = inttoptr i64 %5 to ptr - %ptradd1 = getelementptr inbounds i8, ptr %6, i64 8 - %typeid.parent = load i64, ptr %ptradd1, align 8 - %7 = icmp eq i64 %typeid.parent, 0 - br i1 %7, label %result_block, label %check_subtype - -result_block: ; preds = %parent_type_block, %check_subtype - %8 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] - br i1 %8, label %switch.case, label %next_if - -switch.case: ; preds = %result_block - %9 = extractvalue %any %2, 0 - store ptr %9, ptr %z, align 8 - store i32 12, ptr %taddr, align 4 - %10 = insertvalue %any undef, ptr %taddr, 0 - %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %any %11, ptr %y, align 8 - %12 = load ptr, ptr %z, align 8 - %13 = load i32, ptr %12, align 4 - call void (ptr, ...) @printf(ptr @.str.3, i32 %13) - br label %switch.exit - -next_if: ; preds = %result_block - br label %check_subtype2 - -check_subtype2: ; preds = %parent_type_block4, %next_if - %14 = phi i64 [ %4, %next_if ], [ %typeid.parent6, %parent_type_block4 ] - %eq3 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %14 - br i1 %eq3, label %result_block7, label %parent_type_block4 - -parent_type_block4: ; preds = %check_subtype2 - %15 = inttoptr i64 %14 to ptr - %ptradd5 = getelementptr inbounds i8, ptr %15, i64 8 - %typeid.parent6 = load i64, ptr %ptradd5, align 8 - %16 = icmp eq i64 %typeid.parent6, 0 - br i1 %16, label %result_block7, label %check_subtype2 - -result_block7: ; preds = %parent_type_block4, %check_subtype2 - %17 = phi i1 [ false, %parent_type_block4 ], [ true, %check_subtype2 ] - br i1 %17, label %switch.case8, label %next_if10 - -switch.case8: ; preds = %result_block7 - %18 = extractvalue %any %2, 0 - store ptr %18, ptr %z9, align 8 - %19 = load ptr, ptr %z9, align 8 - %20 = load double, ptr %19, align 8 - call void (ptr, ...) @printf(ptr @.str.4, double %20) - br label %switch.exit - -next_if10: ; preds = %result_block7 - br label %switch.default - -switch.default: ; preds = %next_if10 - call void (ptr, ...) @printf(ptr @.str.5) - br label %switch.exit - -switch.exit: ; preds = %switch.default, %switch.case8, %switch.case - ret void -} - -; Function Attrs: -define void @foo.test3(i64 %0, ptr %1) #0 { -entry: - %y = alloca %any, align 8 - %switch = alloca i64, align 8 - %z = alloca i32, align 4 - %z9 = alloca double, align 8 - store i64 %0, ptr %y, align 8 - %ptradd = getelementptr inbounds i8, ptr %y, i64 8 - store ptr %1, ptr %ptradd, align 8 - %2 = load %any, ptr %y, align 8 - %3 = extractvalue %any %2, 1 - store i64 %3, ptr %switch, align 8 - br label %switch.entry - -switch.entry: ; preds = %entry - %4 = load i64, ptr %switch, align 8 - br label %check_subtype - -check_subtype: ; preds = %parent_type_block, %switch.entry - %5 = phi i64 [ %4, %switch.entry ], [ %typeid.parent, %parent_type_block ] - %eq = icmp eq i64 ptrtoint (ptr @"$ct.int" to i64), %5 - br i1 %eq, label %result_block, label %parent_type_block - -parent_type_block: ; preds = %check_subtype - %6 = inttoptr i64 %5 to ptr - %ptradd1 = getelementptr inbounds i8, ptr %6, i64 8 - %typeid.parent = load i64, ptr %ptradd1, align 8 - %7 = icmp eq i64 %typeid.parent, 0 - br i1 %7, label %result_block, label %check_subtype - -result_block: ; preds = %parent_type_block, %check_subtype - %8 = phi i1 [ false, %parent_type_block ], [ true, %check_subtype ] - br i1 %8, label %switch.case, label %next_if - -switch.case: ; preds = %result_block - %9 = extractvalue %any %2, 0 - %10 = load i32, ptr %9, align 4 - store i32 %10, ptr %z, align 4 - %11 = load i32, ptr %z, align 4 - call void (ptr, ...) @printf(ptr @.str.6, i32 %11) - br label %switch.exit - -next_if: ; preds = %result_block - br label %check_subtype2 - -check_subtype2: ; preds = %parent_type_block4, %next_if - %12 = phi i64 [ %4, %next_if ], [ %typeid.parent6, %parent_type_block4 ] - %eq3 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %12 - br i1 %eq3, label %result_block7, label %parent_type_block4 - -parent_type_block4: ; preds = %check_subtype2 - %13 = inttoptr i64 %12 to ptr - %ptradd5 = getelementptr inbounds i8, ptr %13, i64 8 - %typeid.parent6 = load i64, ptr %ptradd5, align 8 - %14 = icmp eq i64 %typeid.parent6, 0 - br i1 %14, label %result_block7, label %check_subtype2 - -result_block7: ; preds = %parent_type_block4, %check_subtype2 - %15 = phi i1 [ false, %parent_type_block4 ], [ true, %check_subtype2 ] - br i1 %15, label %switch.case8, label %next_if10 - -switch.case8: ; preds = %result_block7 - %16 = extractvalue %any %2, 0 - %17 = load double, ptr %16, align 8 - store double %17, ptr %z9, align 8 - %18 = load double, ptr %z9, align 8 - call void (ptr, ...) @printf(ptr @.str.7, double %18) - br label %switch.exit - -next_if10: ; preds = %result_block7 - br label %switch.default - -switch.default: ; preds = %next_if10 - call void (ptr, ...) @printf(ptr @.str.8) - br label %switch.exit - -switch.exit: ; preds = %switch.default, %switch.case8, %switch.case - ret void -} - -; Function Attrs: define i32 @main() #0 { entry: %taddr = alloca double, align 8 @@ -318,18 +112,6 @@ entry: %taddr3 = alloca %any, align 8 %taddr7 = alloca i8, align 1 %taddr8 = alloca %any, align 8 - %taddr12 = alloca double, align 8 - %taddr13 = alloca %any, align 8 - %taddr17 = alloca i32, align 4 - %taddr18 = alloca %any, align 8 - %taddr22 = alloca i8, align 1 - %taddr23 = alloca %any, align 8 - %taddr27 = alloca double, align 8 - %taddr28 = alloca %any, align 8 - %taddr32 = alloca i32, align 4 - %taddr33 = alloca %any, align 8 - %taddr37 = alloca i8, align 1 - %taddr38 = alloca %any, align 8 store double 1.230000e+02, ptr %taddr, align 8 %0 = insertvalue %any undef, ptr %taddr, 0 %1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.double" to i64), 1 @@ -354,53 +136,5 @@ entry: %ptradd10 = getelementptr inbounds i8, ptr %taddr8, i64 8 %hi11 = load ptr, ptr %ptradd10, align 8 call void @foo.test(i64 %lo9, ptr %hi11) - store double 1.235000e+02, ptr %taddr12, align 8 - %6 = insertvalue %any undef, ptr %taddr12, 0 - %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %any %7, ptr %taddr13, align 8 - %lo14 = load i64, ptr %taddr13, align 8 - %ptradd15 = getelementptr inbounds i8, ptr %taddr13, i64 8 - %hi16 = load ptr, ptr %ptradd15, align 8 - call void @foo.test2(i64 %lo14, ptr %hi16) - store i32 1, ptr %taddr17, align 4 - %8 = insertvalue %any undef, ptr %taddr17, 0 - %9 = insertvalue %any %8, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %any %9, ptr %taddr18, align 8 - %lo19 = load i64, ptr %taddr18, align 8 - %ptradd20 = getelementptr inbounds i8, ptr %taddr18, i64 8 - %hi21 = load ptr, ptr %ptradd20, align 8 - call void @foo.test2(i64 %lo19, ptr %hi21) - store i8 1, ptr %taddr22, align 1 - %10 = insertvalue %any undef, ptr %taddr22, 0 - %11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %any %11, ptr %taddr23, align 8 - %lo24 = load i64, ptr %taddr23, align 8 - %ptradd25 = getelementptr inbounds i8, ptr %taddr23, i64 8 - %hi26 = load ptr, ptr %ptradd25, align 8 - call void @foo.test2(i64 %lo24, ptr %hi26) - store double 1.240000e+02, ptr %taddr27, align 8 - %12 = insertvalue %any undef, ptr %taddr27, 0 - %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.double" to i64), 1 - store %any %13, ptr %taddr28, align 8 - %lo29 = load i64, ptr %taddr28, align 8 - %ptradd30 = getelementptr inbounds i8, ptr %taddr28, i64 8 - %hi31 = load ptr, ptr %ptradd30, align 8 - call void @foo.test3(i64 %lo29, ptr %hi31) - store i32 2, ptr %taddr32, align 4 - %14 = insertvalue %any undef, ptr %taddr32, 0 - %15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - store %any %15, ptr %taddr33, align 8 - %lo34 = load i64, ptr %taddr33, align 8 - %ptradd35 = getelementptr inbounds i8, ptr %taddr33, i64 8 - %hi36 = load ptr, ptr %ptradd35, align 8 - call void @foo.test3(i64 %lo34, ptr %hi36) - store i8 1, ptr %taddr37, align 1 - %16 = insertvalue %any undef, ptr %taddr37, 0 - %17 = insertvalue %any %16, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - store %any %17, ptr %taddr38, align 8 - %lo39 = load i64, ptr %taddr38, align 8 - %ptradd40 = getelementptr inbounds i8, ptr %taddr38, i64 8 - %hi41 = load ptr, ptr %ptradd40, align 8 - call void @foo.test3(i64 %lo39, ptr %hi41) ret i32 0 -} +} \ No newline at end of file diff --git a/test/test_suite/any/variant_switch.c3t b/test/test_suite/any/variant_switch.c3t index 7496d4d2d..d7a23074d 100644 --- a/test/test_suite/any/variant_switch.c3t +++ b/test/test_suite/any/variant_switch.c3t @@ -5,13 +5,13 @@ extern fn void printf(char*, ...); fn void test(any z) { - switch (z) + switch (z.type) { case int: - printf("int: %d\n", *z); - *z = 3; + printf("int: %d\n", *(int*)z); + *(int*)z = 3; case double: - printf("double %f\n", *z); + printf("double %f\n", *(double*)z); default: printf("Unknown type.\n"); } @@ -38,8 +38,6 @@ define void @foo.test(i64 %0, ptr %1) #0 { entry: %z = alloca %any, align 8 %switch = alloca i64, align 8 - %z3 = alloca ptr, align 8 - %z11 = alloca ptr, align 8 store i64 %0, ptr %z, align 8 %ptradd = getelementptr inbounds i8, ptr %z, i64 8 store ptr %1, ptr %ptradd, align 8 @@ -70,58 +68,54 @@ result_block: ; preds = %parent_type_block, switch.case: ; preds = %result_block %8 = load ptr, ptr %z, align 8 - store ptr %8, ptr %z3, align 8 - %9 = load ptr, ptr %z3, align 8 - %10 = load i32, ptr %9, align 4 - call void (ptr, ...) @printf(ptr @.str, i32 %10) - %11 = load ptr, ptr %z3, align 8 - store i32 3, ptr %11, align 4 + %9 = load i32, ptr %8, align 4 + call void (ptr, ...) @printf(ptr @.str, i32 %9) + %10 = load ptr, ptr %z, align 8 + store i32 3, ptr %10, align 4 br label %switch.exit next_if: ; preds = %result_block - br label %check_subtype4 + br label %check_subtype3 -check_subtype4: ; preds = %parent_type_block6, %next_if - %12 = phi i64 [ %3, %next_if ], [ %typeid.parent8, %parent_type_block6 ] - %eq5 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %12 - br i1 %eq5, label %result_block9, label %parent_type_block6 +check_subtype3: ; preds = %parent_type_block5, %next_if + %11 = phi i64 [ %3, %next_if ], [ %typeid.parent7, %parent_type_block5 ] + %eq4 = icmp eq i64 ptrtoint (ptr @"$ct.double" to i64), %11 + br i1 %eq4, label %result_block8, label %parent_type_block5 -parent_type_block6: ; preds = %check_subtype4 - %13 = inttoptr i64 %12 to ptr - %ptradd7 = getelementptr inbounds i8, ptr %13, i64 8 - %typeid.parent8 = load i64, ptr %ptradd7, align 8 - %14 = icmp eq i64 %typeid.parent8, 0 - br i1 %14, label %result_block9, label %check_subtype4 +parent_type_block5: ; preds = %check_subtype3 + %12 = inttoptr i64 %11 to ptr + %ptradd6 = getelementptr inbounds i8, ptr %12, i64 8 + %typeid.parent7 = load i64, ptr %ptradd6, align 8 + %13 = icmp eq i64 %typeid.parent7, 0 + br i1 %13, label %result_block8, label %check_subtype3 -result_block9: ; preds = %parent_type_block6, %check_subtype4 - %15 = phi i1 [ false, %parent_type_block6 ], [ true, %check_subtype4 ] - br i1 %15, label %switch.case10, label %next_if12 +result_block8: ; preds = %parent_type_block5, %check_subtype3 + %14 = phi i1 [ false, %parent_type_block5 ], [ true, %check_subtype3 ] + br i1 %14, label %switch.case9, label %next_if10 -switch.case10: ; preds = %result_block9 - %16 = load ptr, ptr %z, align 8 - store ptr %16, ptr %z11, align 8 - %17 = load ptr, ptr %z11, align 8 - %18 = load double, ptr %17, align 8 - call void (ptr, ...) @printf(ptr @.str.1, double %18) +switch.case9: ; preds = %result_block8 + %15 = load ptr, ptr %z, align 8 + %16 = load double, ptr %15, align 8 + call void (ptr, ...) @printf(ptr @.str.1, double %16) br label %switch.exit -next_if12: ; preds = %result_block9 +next_if10: ; preds = %result_block8 br label %switch.default -switch.default: ; preds = %next_if12 +switch.default: ; preds = %next_if10 call void (ptr, ...) @printf(ptr @.str.2) br label %switch.exit -switch.exit: ; preds = %switch.default, %switch.case10, %switch.case - %ptradd13 = getelementptr inbounds i8, ptr %z, i64 8 - %19 = load i64, ptr %ptradd13, align 8 - %eq14 = icmp eq i64 %19, ptrtoint (ptr @"$ct.int" to i64) - br i1 %eq14, label %if.then, label %if.exit +switch.exit: ; preds = %switch.default, %switch.case9, %switch.case + %ptradd11 = getelementptr inbounds i8, ptr %z, i64 8 + %17 = load i64, ptr %ptradd11, align 8 + %eq12 = icmp eq i64 %17, ptrtoint (ptr @"$ct.int" to i64) + br i1 %eq12, label %if.then, label %if.exit if.then: ; preds = %switch.exit - %20 = load ptr, ptr %z, align 8 - %21 = load i32, ptr %20, align 4 - call void (ptr, ...) @printf(ptr @.str.3, i32 %21) + %18 = load ptr, ptr %z, align 8 + %19 = load i32, ptr %18, align 4 + call void (ptr, ...) @printf(ptr @.str.3, i32 %19) br label %if.exit if.exit: ; preds = %if.then, %switch.exit diff --git a/test/unit/regression/any.c3 b/test/unit/regression/any.c3 index f3324bec7..60904e09f 100644 --- a/test/unit/regression/any.c3 +++ b/test/unit/regression/any.c3 @@ -15,7 +15,7 @@ fn void test_aliasing() { int x; AnyAlias z = &x; - switch (z) + switch (z.type) { case int: assert(true); diff --git a/test/unit/regression/subtype.c3 b/test/unit/regression/subtype.c3 index a73c1ac17..75d403a65 100644 --- a/test/unit/regression/subtype.c3 +++ b/test/unit/regression/subtype.c3 @@ -18,7 +18,7 @@ fn void switch_subtyping() Foo f = {}; f.z = 123; any x = &f; - switch (x) + switch (x.type) { case int: assert(false); @@ -27,7 +27,7 @@ fn void switch_subtyping() default: assert(false); } - switch (x) + switch (x.type) { case int: assert(false); @@ -36,7 +36,7 @@ fn void switch_subtyping() default: assert(false); } - switch (x) + switch (x.type) { case int: assert(false);