@@ -1172,3 +1172,144 @@ test "compiler: nested field access a.b.c" {
11721172 const result = try runCompiled (allocator , &.{ point_decl , line_decl , p_decl , l_decl }, .{ .field_access = fa_x });
11731173 try std .testing .expect (result .eql (.{ .int = 3 }));
11741174}
1175+
1176+ // ===========================================================================
1177+ // Step 7: Enum variant constructors
1178+ // ===========================================================================
1179+
1180+ test "compiler: enum zero-field variant construction" {
1181+ var arena = std .heap .ArenaAllocator .init (std .testing .allocator );
1182+ defer arena .deinit ();
1183+ const allocator = arena .allocator ();
1184+
1185+ // enum Color { Red, Green }
1186+ const variants = [_ ]ast.Statement.Variant {
1187+ .{ .name = ident ("Red" ), .fields = &.{} },
1188+ .{ .name = ident ("Green" ), .fields = &.{} },
1189+ };
1190+ const enum_decl = ast.Statement { .enum_declaration = .{
1191+ .name = ident ("Color" ),
1192+ .is_error = false ,
1193+ .variants = & variants ,
1194+ } };
1195+
1196+ // Color.Red()
1197+ const fa = try allocator .create (ast .Expression .FieldAccess );
1198+ fa .* = .{ .object = .{ .variable = .{ .token = ident ("Color" ) } }, .name = ident ("Red" ) };
1199+ const call = try allocator .create (ast .Expression .FnCall );
1200+ call .* = .{ .callee = .{ .field_access = fa }, .args = &.{} };
1201+
1202+ const result = try runCompiled (allocator , &.{enum_decl }, .{ .fn_call = call });
1203+ try std .testing .expect (result == .struct_instance );
1204+ try std .testing .expectEqualStrings ("Color.Red" , result .struct_instance .type_name );
1205+ try std .testing .expectEqual (@as (usize , 0 ), result .struct_instance .field_values .len );
1206+ }
1207+
1208+ test "compiler: enum variant with fields" {
1209+ var arena = std .heap .ArenaAllocator .init (std .testing .allocator );
1210+ defer arena .deinit ();
1211+ const allocator = arena .allocator ();
1212+
1213+ // enum Shape { Circle(const radius: Int) }
1214+ const circle_fields = [_ ]ast.Statement.FieldDeclaration {
1215+ .{ .name = ident ("radius" ), .type_annotation = dummyType (), .mutability = .constant , .default_value = null },
1216+ };
1217+ const variants = [_ ]ast.Statement.Variant {
1218+ .{ .name = ident ("Circle" ), .fields = & circle_fields },
1219+ };
1220+ const enum_decl = ast.Statement { .enum_declaration = .{
1221+ .name = ident ("Shape" ),
1222+ .is_error = false ,
1223+ .variants = & variants ,
1224+ } };
1225+
1226+ // Shape.Circle(5)
1227+ const fa = try allocator .create (ast .Expression .FieldAccess );
1228+ fa .* = .{ .object = .{ .variable = .{ .token = ident ("Shape" ) } }, .name = ident ("Circle" ) };
1229+ const args = [_ ]ast.Expression {
1230+ .{ .literal = .{ .token = ident ("5" ), .value = .{ .int = 5 } } },
1231+ };
1232+ const call = try allocator .create (ast .Expression .FnCall );
1233+ call .* = .{ .callee = .{ .field_access = fa }, .args = & args };
1234+
1235+ const result = try runCompiled (allocator , &.{enum_decl }, .{ .fn_call = call });
1236+ try std .testing .expect (result == .struct_instance );
1237+ try std .testing .expectEqualStrings ("Shape.Circle" , result .struct_instance .type_name );
1238+ try std .testing .expectEqual (@as (usize , 1 ), result .struct_instance .field_values .len );
1239+ try std .testing .expect (result .struct_instance .field_values [0 ].eql (.{ .int = 5 }));
1240+ }
1241+
1242+ test "compiler: qualified enum access resolves to correct variant" {
1243+ var arena = std .heap .ArenaAllocator .init (std .testing .allocator );
1244+ defer arena .deinit ();
1245+ const allocator = arena .allocator ();
1246+
1247+ // enum Color { Red, Green }
1248+ const variants = [_ ]ast.Statement.Variant {
1249+ .{ .name = ident ("Red" ), .fields = &.{} },
1250+ .{ .name = ident ("Green" ), .fields = &.{} },
1251+ };
1252+ const enum_decl = ast.Statement { .enum_declaration = .{
1253+ .name = ident ("Color" ),
1254+ .is_error = false ,
1255+ .variants = & variants ,
1256+ } };
1257+
1258+ // Color.Green() — must resolve to Green, not Red
1259+ const fa = try allocator .create (ast .Expression .FieldAccess );
1260+ fa .* = .{ .object = .{ .variable = .{ .token = ident ("Color" ) } }, .name = ident ("Green" ) };
1261+ const call = try allocator .create (ast .Expression .FnCall );
1262+ call .* = .{ .callee = .{ .field_access = fa }, .args = &.{} };
1263+
1264+ const result = try runCompiled (allocator , &.{enum_decl }, .{ .fn_call = call });
1265+ try std .testing .expect (result == .struct_instance );
1266+ try std .testing .expectEqualStrings ("Color.Green" , result .struct_instance .type_name );
1267+ }
1268+
1269+ test "compiler: nested enum coercion" {
1270+ var arena = std .heap .ArenaAllocator .init (std .testing .allocator );
1271+ defer arena .deinit ();
1272+ const allocator = arena .allocator ();
1273+
1274+ // enum Inner { A }
1275+ const inner_variants = [_ ]ast.Statement.Variant {
1276+ .{ .name = ident ("A" ), .fields = &.{} },
1277+ };
1278+ const inner_decl = ast.Statement { .enum_declaration = .{
1279+ .name = ident ("Inner" ),
1280+ .is_error = false ,
1281+ .variants = & inner_variants ,
1282+ } };
1283+
1284+ // enum Outer { Inner, B }
1285+ // "Inner" has zero declared fields but matches a known enum → single-field wrapper
1286+ const outer_variants = [_ ]ast.Statement.Variant {
1287+ .{ .name = ident ("Inner" ), .fields = &.{} },
1288+ .{ .name = ident ("B" ), .fields = &.{} },
1289+ };
1290+ const outer_decl = ast.Statement { .enum_declaration = .{
1291+ .name = ident ("Outer" ),
1292+ .is_error = false ,
1293+ .variants = & outer_variants ,
1294+ } };
1295+
1296+ // Inner.A()
1297+ const inner_fa = try allocator .create (ast .Expression .FieldAccess );
1298+ inner_fa .* = .{ .object = .{ .variable = .{ .token = ident ("Inner" ) } }, .name = ident ("A" ) };
1299+ const inner_call = try allocator .create (ast .Expression .FnCall );
1300+ inner_call .* = .{ .callee = .{ .field_access = inner_fa }, .args = &.{} };
1301+
1302+ // Outer.Inner(Inner.A())
1303+ const outer_fa = try allocator .create (ast .Expression .FieldAccess );
1304+ outer_fa .* = .{ .object = .{ .variable = .{ .token = ident ("Outer" ) } }, .name = ident ("Inner" ) };
1305+ const outer_args = [_ ]ast.Expression {.{ .fn_call = inner_call }};
1306+ const outer_call = try allocator .create (ast .Expression .FnCall );
1307+ outer_call .* = .{ .callee = .{ .field_access = outer_fa }, .args = & outer_args };
1308+
1309+ const result = try runCompiled (allocator , &.{ inner_decl , outer_decl }, .{ .fn_call = outer_call });
1310+ try std .testing .expect (result == .struct_instance );
1311+ try std .testing .expectEqualStrings ("Outer.Inner" , result .struct_instance .type_name );
1312+ try std .testing .expectEqual (@as (usize , 1 ), result .struct_instance .field_values .len );
1313+ try std .testing .expect (result .struct_instance .field_values [0 ] == .struct_instance );
1314+ try std .testing .expectEqualStrings ("Inner.A" , result .struct_instance .field_values [0 ].struct_instance .type_name );
1315+ }
0 commit comments