diff options
| -rw-r--r-- | src/parser/parser_stmt.c | 44 | ||||
| -rw-r--r-- | tests/features/test_match_composition.zc | 112 |
2 files changed, 154 insertions, 2 deletions
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 7873d51..4577405 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -339,8 +339,48 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) enter_scope(ctx); if (binding) { - // If ref binding, mark as pointer type so auto-deref (->) works - add_symbol(ctx, binding, is_ref ? "void*" : "unknown", NULL); + // Try to infer binding type from enum variant payload + char *binding_type = is_ref ? "void*" : "unknown"; + Type *binding_type_info = NULL; + + // Look up the enum variant to get its payload type + EnumVariantReg *vreg = find_enum_variant(ctx, pattern); + if (vreg) + { + // Find the enum definition + ASTNode *enum_def = find_struct_def(ctx, vreg->enum_name); + if (enum_def && enum_def->type == NODE_ENUM) + { + // Find the specific variant + ASTNode *v = enum_def->enm.variants; + while (v) + { + // Match by variant name (pattern suffix after last _) + char *v_full = + xmalloc(strlen(vreg->enum_name) + strlen(v->variant.name) + 2); + sprintf(v_full, "%s_%s", vreg->enum_name, v->variant.name); + if (strcmp(v_full, pattern) == 0 && v->variant.payload) + { + // Found the variant, extract payload type + binding_type_info = v->variant.payload; + binding_type = type_to_string(v->variant.payload); + if (is_ref) + { + // For ref bindings, make it a pointer to the payload type + char *ptr_type = xmalloc(strlen(binding_type) + 2); + sprintf(ptr_type, "%s*", binding_type); + binding_type = ptr_type; + } + free(v_full); + break; + } + free(v_full); + v = v->next; + } + } + } + + add_symbol(ctx, binding, binding_type, binding_type_info); } ASTNode *body; diff --git a/tests/features/test_match_composition.zc b/tests/features/test_match_composition.zc new file mode 100644 index 0000000..f25b90f --- /dev/null +++ b/tests/features/test_match_composition.zc @@ -0,0 +1,112 @@ + +struct Inner { + value: int; +} + +// Named composition (struct has nested field) +struct NamedWrapper { + use inner: Inner; +} + +// Mixin composition (fields are flattened) +struct MixinWrapper { + use Inner; +} + +enum NamedResult { + Ok(NamedWrapper), + Err(int) +} + +enum MixinResult { + Ok(MixinWrapper), + Err(int) +} + +// Test match binding with named composition - field access +test "match_binding_named_composition" { + var inner = Inner { value: 42 }; + var wrapper = NamedWrapper { inner: inner }; + var result = NamedResult::Ok(wrapper); + + match result { + NamedResult::Ok(w) => { + var val = w.inner.value; + assert(val == 42, "Named composition field access failed"); + }, + NamedResult::Err(e) => assert(false, "Should not be Err") + } +} + +// Test match binding with mixin composition - field access +test "match_binding_mixin_composition" { + var wrapper = MixinWrapper { value: 77 }; + var result = MixinResult::Ok(wrapper); + + match result { + MixinResult::Ok(w) => { + var val = w.value; + assert(val == 77, "Mixin composition field access failed"); + }, + MixinResult::Err(e) => assert(false, "Should not be Err") + } +} + +// Test match binding with mixin - f-string interpolation +test "match_binding_mixin_fstring" { + var wrapper = MixinWrapper { value: 88 }; + var result = MixinResult::Ok(wrapper); + + match result { + MixinResult::Ok(w) => { + println "{w.value}"; + assert(w.value == 88, "F-string with mixin failed"); + }, + MixinResult::Err(e) => assert(false, "Should not be Err") + } +} + +// Test match binding with ref - mixin composition +test "match_binding_ref_mixin" { + var wrapper = MixinWrapper { value: 33 }; + var result = MixinResult::Ok(wrapper); + + match result { + MixinResult::Ok(ref w) => { + assert(w.value == 33, "Ref binding with mixin failed"); + w.value = 44; + }, + MixinResult::Err(e) => assert(false, "Should not be Err") + } + + // Verify modification persisted + match result { + MixinResult::Ok(w) => { + assert(w.value == 44, "Ref modification did not persist"); + }, + MixinResult::Err(e) => {} + } +} + +// Test match binding with ref - named composition +test "match_binding_ref_named" { + var inner = Inner { value: 55 }; + var wrapper = NamedWrapper { inner: inner }; + var result = NamedResult::Ok(wrapper); + + match result { + NamedResult::Ok(ref w) => { + assert(w.inner.value == 55, "Ref binding with named composition failed"); + w.inner.value = 66; + }, + NamedResult::Err(e) => assert(false, "Should not be Err") + } + + // Verify modification persisted + match result { + NamedResult::Ok(w) => { + assert(w.inner.value == 66, "Named composition ref modification did not persist"); + }, + NamedResult::Err(e) => {} + } +} |
