fix(metatype): reject declare() never completed by define()

A bare declare("X") with no define left a zero-field nominal slot that
panicked at codegen (verifySizes: llvm_size != ir_size). evalComptimeType
now detects a zero-variant tagged_union result and emits a clean
build-gating diagnostic naming the type — a zero-variant enum is never a
legitimate construction result (defineEnum rejects empty variant lists
too). Self-reference (a declared slot completed by define) is unaffected.
This commit is contained in:
agra
2026-06-17 06:29:23 +03:00
parent c573e4befb
commit 14f30f341c

View File

@@ -473,7 +473,21 @@ pub fn evalComptimeType(self: *Lowering, expr: *const Node) ?TypeId {
} }
return null; return null;
}; };
return result.asTypeId(); const tid = result.asTypeId() orelse return null;
// A bare `declare("X")` that is never completed by a `define(handle, …)`
// leaves a zero-FIELD nominal slot (an undefined enum). Sizing / constructing
// / emitting it panics at codegen (`verifySizes`: llvm_size != ir_size).
// Reject it loudly here — a zero-variant enum is never a legitimate result
// (`defineEnum` rejects an empty variant list too).
if (!tid.isBuiltin()) {
const info = self.module.types.get(tid);
if (info == .tagged_union and info.tagged_union.fields.len == 0) {
if (self.diagnostics) |d|
d.addFmt(.err, expr.span, "type '{s}' is declared but never defined — complete it with define(handle, info)", .{self.module.types.getString(info.tagged_union.name)});
return null;
}
}
return tid;
} }
/// Rename a nominal type to a new name, re-keying `intern_map` so /// Rename a nominal type to a new name, re-keying `intern_map` so