From f2119ac101f730c90a3124c2533c3eac6b405bf7 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 23 May 2023 19:03:46 -0500 Subject: [PATCH] added: switching over pointer to union --- CHANGELOG | 3 +++ compiler/src/checker.c | 17 ++++++++++++----- compiler/src/wasm_emit.c | 18 ++++++++++++++---- core/container/optional.onyx | 2 +- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a140f9cc..582e2715 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Release v0.1.2 Unreleased Additions: +* Tagged unions (`union` type) * String literals can have unicode code points. - '\uXXXX' for small code points (less than U+FFFF) - '\UXXXXXX' for large code points @@ -14,6 +15,8 @@ Additions: Removals: Changes: +* `Optional` is now a tagged-union +* `Result` is now a tagged-union * `iter.single` can take a `dispose` function, which is called on close of the iterator, with the single value yielded. * `io.write_escaped_str` supports escaping "\\" now. diff --git a/compiler/src/checker.c b/compiler/src/checker.c index c6318ad2..c590c122 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -440,7 +440,8 @@ CheckStatus check_switch(AstSwitch* switchnode) { if (!type_is_integer(switchnode->expr->type) && switchnode->expr->type->kind != Type_Kind_Enum) { switchnode->switch_kind = Switch_Kind_Use_Equals; } - if (switchnode->expr->type->kind == Type_Kind_Union) { + if (switchnode->expr->type->kind == Type_Kind_Union + || (switchnode->expr->type->kind == Type_Kind_Pointer && switchnode->expr->type->Pointer.elem->kind == Type_Kind_Union)) { switchnode->switch_kind = Switch_Kind_Union; } @@ -488,7 +489,8 @@ CheckStatus check_switch(AstSwitch* switchnode) { } if (sc->capture && switchnode->switch_kind != Switch_Kind_Union) { - ERROR(sc->capture->token->pos, "Captures in switch cases are only allowed when switching over a union type."); + ERROR_(sc->capture->token->pos, "Captures in switch cases are only allowed when switching over a union type. Switching over '%s' here.", + type_get_name(switchnode->expr->type)); } if (sc->flags & Ast_Flag_Has_Been_Checked) goto check_switch_case_block; @@ -522,16 +524,21 @@ CheckStatus check_switch(AstSwitch* switchnode) { } if (switchnode->switch_kind == Switch_Kind_Union) { - TYPE_CHECK(value, resolved_expr_type->Union.tag_type) { + Type *union_expr_type = resolved_expr_type; + if (union_expr_type->kind == Type_Kind_Pointer) { + union_expr_type = union_expr_type->Pointer.elem; + } + + TYPE_CHECK(value, union_expr_type->Union.tag_type) { OnyxToken* tkn = sc->block->token; if ((*value)->token) tkn = (*value)->token; ERROR_(tkn->pos, "'%b' is not a variant of '%s'.", - (*value)->token->text, (*value)->token->length, type_get_name(resolved_expr_type)); + (*value)->token->text, (*value)->token->length, type_get_name(union_expr_type)); } // nocheckin Explain the -1 - UnionVariant *union_variant = resolved_expr_type->Union.variants_ordered[get_expression_integer_value(*value, NULL) - 1]; + UnionVariant *union_variant = union_expr_type->Union.variants_ordered[get_expression_integer_value(*value, NULL) - 1]; if (sc->capture) { if (sc->capture_is_by_pointer) { sc->capture->type = type_make_pointer(context.ast_alloc, union_variant->type); diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index 5de1db7c..4c6b1124 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -1656,10 +1656,15 @@ EMIT_FUNC(switch, AstSwitch* switch_node) { emit_expression(mod, &code, switch_node->expr); if (switch_node->switch_kind == Switch_Kind_Union) { - assert(switch_node->expr->type->kind == Type_Kind_Union); + Type *union_expr_type = switch_node->expr->type; + if (union_expr_type->kind == Type_Kind_Pointer) { + union_expr_type = union_expr_type->Pointer.elem; + } + assert(union_expr_type->kind == Type_Kind_Union); + union_capture_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); WIL(NULL, WI_LOCAL_TEE, union_capture_idx); - emit_load_instruction(mod, &code, switch_node->expr->type->Union.tag_type, 0); + emit_load_instruction(mod, &code, union_expr_type->Union.tag_type, 0); } if (switch_node->min_case != 0) { @@ -1702,11 +1707,16 @@ EMIT_FUNC(switch, AstSwitch* switch_node) { if (sc->capture) { assert(union_capture_idx != 0); + Type *union_expr_type = switch_node->expr->type; + if (union_expr_type->kind == Type_Kind_Pointer) { + union_expr_type = union_expr_type->Pointer.elem; + } + if (sc->capture_is_by_pointer) { u64 capture_pointer_local = emit_local_allocation(mod, &code, (AstTyped *) sc->capture); WIL(NULL, WI_LOCAL_GET, union_capture_idx); - WIL(NULL, WI_PTR_CONST, switch_node->expr->type->Union.alignment); + WIL(NULL, WI_PTR_CONST, union_expr_type->Union.alignment); WI(NULL, WI_PTR_ADD); WIL(NULL, WI_LOCAL_SET, capture_pointer_local); @@ -1719,7 +1729,7 @@ EMIT_FUNC(switch, AstSwitch* switch_node) { emit_location(mod, &code, (AstTyped *) sc->capture); WIL(NULL, WI_LOCAL_GET, union_capture_idx); - WIL(NULL, WI_PTR_CONST, switch_node->expr->type->Union.alignment); + WIL(NULL, WI_PTR_CONST, union_expr_type->Union.alignment); WI(NULL, WI_PTR_ADD); WIL(NULL, WI_I32_CONST, type_size_of(sc->capture->type)); diff --git a/core/container/optional.onyx b/core/container/optional.onyx index f049a70b..ca40195d 100644 --- a/core/container/optional.onyx +++ b/core/container/optional.onyx @@ -109,7 +109,7 @@ use core If not, an assertion is thrown and the context's assert handler must take care of it. """ - unwrap_ptr :: (o: ?$T) -> &T { + unwrap_ptr :: (o: & ?$T) -> &T { switch o { case .Some => &v do return v; case #default { -- 2.25.1