diff --git a/examples/issue-0003.sx b/examples/issue-0003.sx new file mode 100644 index 0000000..f09f301 --- /dev/null +++ b/examples/issue-0003.sx @@ -0,0 +1,25 @@ +// Issue: enum literal inference in match expression used as assignment RHS +// When a match expression is assigned to a field with a known enum type, +// the enum literals in case arms should infer their type from the assignment target. + +Color :: enum { + red; + green; + blue; + none; +} + +Thing :: struct { + color: Color; +} + +main :: () { + t : Thing = ---; + value : u8 = 1; + t.color = if value == { + case 1: .red; // error: cannot infer enum type for literal + case 2: .green; + case 3: .blue; + else: .none; + }; +} diff --git a/examples/issue-0004-defs.sx b/examples/issue-0004-defs.sx new file mode 100644 index 0000000..a217eb3 --- /dev/null +++ b/examples/issue-0004-defs.sx @@ -0,0 +1,18 @@ +#import "modules/std.sx"; + +Color :: struct { + r, g, b, a: u8; +} + +COLOR_WHITE :: Color.{ r = 255, g = 255, b = 255, a = 255 }; + +// Additional case: struct constant with enum-typed fields +HAlign :: enum { leading; center; trailing; } +VAlign :: enum { top; center; bottom; } + +Alignment :: struct { + h: HAlign; + v: VAlign; +} + +ALIGN_CENTER :: Alignment.{ h = .center, v = .center }; diff --git a/examples/issue-0004.sx b/examples/issue-0004.sx new file mode 100644 index 0000000..0cdcf9c --- /dev/null +++ b/examples/issue-0004.sx @@ -0,0 +1,20 @@ +// Issue: top-level constants from imported files are not visible +// COLOR_WHITE works after fix, but ALIGN_CENTER (struct with enum fields) does not. +// Error: undefined identifier 'ALIGN_CENTER' + +#import "modules/std.sx"; +#import "examples/issue-0004-defs.sx"; + +Thing :: struct { + color: Color; + alignment: Alignment; + + make :: () -> Thing { + Thing.{ color = COLOR_WHITE, alignment = ALIGN_CENTER }; + } +} + +main :: () { + t := Thing.make(); + print("{}\n", t.color.r); +} diff --git a/src/codegen.zig b/src/codegen.zig index e877d53..f43de02 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2694,6 +2694,17 @@ pub const CodeGen = struct { .struct_literal => |sl| { return self.evalConstantStruct(sl, target_ty); }, + .enum_literal => |el| { + if (target_ty.isEnum()) { + const variants = self.lookupEnumVariants(target_ty.enum_type) orelse return null; + for (variants, 0..) |vname, i| { + if (std.mem.eql(u8, vname, el.name)) { + return c.LLVMConstInt(llvm_ty, @intCast(i), 0); + } + } + } + return null; + }, else => return null, } } @@ -2730,8 +2741,10 @@ pub const CodeGen = struct { /// Register a top-level value constant (e.g., `SPECIAL_VALUE :u8: 42;`) as an LLVM global. fn registerTopLevelConstant(self: *CodeGen, cd: ast.ConstDecl) !void { - const ta = cd.type_annotation orelse return; // need explicit type for top-level constants - const sx_ty = self.resolveType(ta); + const sx_ty = if (cd.type_annotation) |ta| + self.resolveType(ta) + else + self.inferType(cd.value); if (sx_ty == .void_type) return; const const_val = self.evalConstant(cd.value, sx_ty) orelse return; @@ -6106,6 +6119,18 @@ pub const CodeGen = struct { return self.wrapOptional(val, target_ty); } + // Match/if expression with enum/union target: propagate type context into arms + // so enum literals like .red can resolve their type from the assignment target + if ((node.data == .match_expr or node.data == .if_expr) and + (target_ty.isEnum() or target_ty.isUnion())) + { + const saved = self.current_return_type; + self.current_return_type = target_ty; + const val = try self.genExpr(node); + self.current_return_type = saved; + return val; + } + // Enum literal assigned to enum type: resolve variant value if (node.data == .enum_literal and target_ty.isEnum()) { return self.genEnumLiteral(node.data.enum_literal.name, target_ty.enum_type);