From 50134378cb8a132b8c1666e47e6ae35189f77c46 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 30 May 2023 18:24:15 -0500 Subject: [PATCH] added: field accessing on unions results in optional --- compiler/include/astnodes.h | 2 ++ compiler/include/types.h | 2 ++ compiler/src/checker.c | 25 ++++++++++++++++++++ compiler/src/types.c | 10 ++++++++ compiler/src/wasm_emit.c | 46 ++++++++++++++++++++++++++++++++---- core/container/optional.onyx | 27 ++++++++++++++------- tests/tagged_unions | 1 + tests/tagged_unions.onyx | 14 +++++++++++ 8 files changed, 114 insertions(+), 13 deletions(-) diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 787e9a3c..e1453471 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -710,6 +710,8 @@ struct AstFieldAccess { u32 offset; u32 idx; char* field; // If token is null, defer to field + + b32 is_union_variant_access : 1; }; struct AstFileContents { AstTyped_base; diff --git a/compiler/include/types.h b/compiler/include/types.h index ce8c773b..3df4e5d1 100644 --- a/compiler/include/types.h +++ b/compiler/include/types.h @@ -244,6 +244,7 @@ Type* type_make_array(bh_allocator alloc, Type* to, u32 count); Type* type_make_slice(bh_allocator alloc, Type* of); Type* type_make_dynarray(bh_allocator alloc, Type* of); Type* type_make_varargs(bh_allocator alloc, Type* of); +Type* type_make_optional(bh_allocator alloc, Type* of); void build_linear_types_with_offset(Type* type, bh_arr(TypeWithOffset)* pdest, u32 offset); b32 type_struct_member_apply_use(bh_allocator alloc, Type *s_type, StructMember *smem); @@ -285,5 +286,6 @@ b32 type_constructed_from_poly(Type* base, struct AstType* from); Type* type_struct_is_just_one_basic_value(Type *type); u32 type_union_get_variant_count(Type *type); UnionVariant* type_lookup_union_variant_by_idx(Type* type, i32 idx); +UnionVariant* type_lookup_union_variant_by_name(Type* type, char *name); #endif // #ifndef ONYX_TYPES diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 6bad112f..2abf59de 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -2046,6 +2046,31 @@ CheckStatus check_field_access(AstFieldAccess** pfield) { } } + if (type_union_get_variant_count(field->expr->type) > 0) { + UnionVariant *uv = type_lookup_union_variant_by_name(field->expr->type, field->field); + if (uv) { + field->is_union_variant_access = 1; + field->idx = uv->tag_value; + + // HACK make a function for this. + if (!field->type_node) { + AstPolyCallType* pctype = onyx_ast_node_new(context.ast_alloc, sizeof(AstPolyCallType), Ast_Kind_Poly_Call_Type); + pctype->token = field->token; + pctype->callee = builtin_optional_type; + bh_arr_new(context.ast_alloc, pctype->params, 1); + bh_arr_push(pctype->params, (AstNode *) uv->type->ast_type); + + field->type_node = (AstType *) pctype; + } + + field->type = type_build_from_ast(context.ast_alloc, field->type_node); + if (!field->type) YIELD(field->token->pos, "Waiting for field access type to be constructed."); + + field->flags |= Ast_Flag_Has_Been_Checked; + return Check_Success; + } + } + goto try_resolve_from_type; } diff --git a/compiler/src/types.c b/compiler/src/types.c index aed11dde..1121b7a3 100644 --- a/compiler/src/types.c +++ b/compiler/src/types.c @@ -1841,3 +1841,13 @@ UnionVariant* type_lookup_union_variant_by_idx(Type* type, i32 idx) { return type->Union.variants_ordered[idx]; } +UnionVariant* type_lookup_union_variant_by_name(Type* type, char *name) { + if (!type) return NULL; + if (type->kind == Type_Kind_Pointer) type = type->Pointer.elem; + if (type->kind != Type_Kind_Union) return NULL; + + i32 index = shgeti(type->Union.variants, name); + if (index == -1) return NULL; + return type->Union.variants[index].value; +} + diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index 4c6b1124..a1fdec28 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -162,6 +162,14 @@ static u64 local_allocate_type_in_memory(LocalAllocator* la, Type *type) { return la->curr_stack - size; } +static void local_free_type_in_memory(LocalAllocator* la, Type* type) { + u32 size = type_size_of(type); + u32 alignment = type_alignment_of(type); + bh_align(size, alignment); + + la->curr_stack -= size; +} + static u64 local_allocate(LocalAllocator* la, AstTyped* local) { if (local_is_wasm_local(local)) { WasmType wt = onyx_type_to_wasm_type(local->type); @@ -178,11 +186,7 @@ static void local_free(LocalAllocator* la, AstTyped* local) { local_raw_free(la, wt); } else { - u32 size = type_size_of(local->type); - u32 alignment = type_alignment_of(local->type); - bh_align(size, alignment); - - la->curr_stack -= size; + local_free_type_in_memory(la, local->type); } } @@ -3552,6 +3556,38 @@ EMIT_FUNC(expression, AstTyped* expr) { WIL(NULL, WI_LOCAL_GET, localidx); } + else if (field->is_union_variant_access) { + u64 intermediate_local = emit_local_allocation(mod, &code, (AstTyped *) field); + assert((intermediate_local & LOCAL_IS_WASM) == 0); + + emit_expression(mod, &code, field->expr); + u64 source_base_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); + WIL(NULL, WI_LOCAL_TEE, source_base_ptr); + emit_load_instruction(mod, &code, &basic_types[Basic_Kind_U32], 0); + WIL(NULL, WI_I32_CONST, field->idx); + WI(NULL, WI_I32_EQ); + emit_enter_structured_block(mod, &code, SBT_Basic_If, field->token); + emit_stack_address(mod, &code, intermediate_local, field->token); + WIL(NULL, WI_I32_CONST, 2); // 2 is Some + emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], 0); + + emit_stack_address(mod, &code, intermediate_local + type_alignment_of(field->type), field->token); + WIL(NULL, WI_LOCAL_GET, source_base_ptr); + WIL(NULL, WI_I32_CONST, type_alignment_of(field->expr->type)); + WI(NULL, WI_I32_ADD); + WIL(NULL, WI_I32_CONST, type_size_of(field->type->Union.variants_ordered[1]->type)); + emit_wasm_copy(mod, &code, NULL); + + WI(NULL, WI_ELSE); + emit_stack_address(mod, &code, intermediate_local, field->token); + WIL(NULL, WI_I32_CONST, 1); // 1 is None + emit_store_instruction(mod, &code, &basic_types[Basic_Kind_I32], 0); + emit_leave_structured_block(mod, &code); + + local_raw_free(mod->local_alloc, WASM_TYPE_PTR); + emit_stack_address(mod, &code, intermediate_local, field->token); + } + else if (is_lval((AstNode *) field->expr) || type_is_pointer(field->expr->type)) { u64 offset = 0; emit_field_access_location(mod, &code, field, &offset); diff --git a/core/container/optional.onyx b/core/container/optional.onyx index ca40195d..6acb33e5 100644 --- a/core/container/optional.onyx +++ b/core/container/optional.onyx @@ -118,21 +118,32 @@ use core } } - or_return :: macro (o: ?$T) -> T { - switch value := o; value { - case .Some => v do return v; - case #default { - return return .{}; + or_return :: #match { + macro (o: ?$T) -> T { + switch value := o; value { + case .Some => v do return v; + case #default { + return return .{}; + } } - } + }, + macro (o: ?$T, return_value: $R) -> T { + switch value := o; value { + case .Some => v do return v; + case #default { + return return return_value; + } + } + }, } catch :: macro (o: ?$T, body: Code) -> T { switch value := o; value { case .Some => v do return v; + case .None { + #unquote body; + } } - - #unquote body; } #doc """ diff --git a/tests/tagged_unions b/tests/tagged_unions index f1d76f21..a3ee253c 100644 --- a/tests/tagged_unions +++ b/tests/tagged_unions @@ -6,3 +6,4 @@ This is an integer: 9876 123 456 Error(Process_Error("bad data")) +A wrapped value diff --git a/tests/tagged_unions.onyx b/tests/tagged_unions.onyx index 7592db53..ececc1c8 100644 --- a/tests/tagged_unions.onyx +++ b/tests/tagged_unions.onyx @@ -143,6 +143,19 @@ polymorphic_example :: () { println(v); } +direct_access_is_an_optional :: () { + Methoded :: union { + int: i32; + float: f32; + string: str; + } + + v := Methoded.{ string = "A wrapped value" }; + + the_string := v.string->unwrap(); + println(the_string); +} + main :: () { simple_example(); @@ -150,4 +163,5 @@ main :: () { method_example(); linked_list_example(); polymorphic_example(); + direct_access_is_an_optional(); } -- 2.25.1