test(metatype): lock by-value self-ref rejection for constructed enums (1182)
Constructed-type companion to examples/1178 (source form): a declare/
define enum whose variant references itself BY VALUE is rejected by the
same checkInfiniteSize guard ('infinitely sized'). Pins the use-before-
define corner of the validation story — by-value self-reference is the
one self-ref shape that isn't legal; *L (pointer) is fine (see 0618).
No compiler change (locks existing behavior).
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
// Diagnostic: a comptime-CONSTRUCTED enum (declare/define) that contains itself
|
||||
// BY VALUE is infinitely sized and rejected loudly — the same `checkInfiniteSize`
|
||||
// guard that covers source decls (examples/1178) also covers minted types. A
|
||||
// pointer payload (`*L`) breaks the cycle and is the fix the message suggests
|
||||
// (see examples/0618 for the working recursive `*List`).
|
||||
//
|
||||
// This is the constructed-type companion to 1178, and pins the "use-before-
|
||||
// define by value" corner of the metatype validation story: referencing a
|
||||
// declared slot by VALUE in its own definition is the one self-reference shape
|
||||
// that isn't legal (a `*L` pointer needs no layout, so it is).
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/meta.sx";
|
||||
|
||||
make :: () -> Type {
|
||||
h := declare("L");
|
||||
return define(h, .enum(.{ variants = .[
|
||||
EnumVariant.{ name = "cons", payload = L }, // by VALUE, not *L
|
||||
EnumVariant.{ name = "nil", payload = void },
|
||||
] }));
|
||||
}
|
||||
|
||||
L :: make();
|
||||
|
||||
main :: () -> i32 {
|
||||
x : L = .nil;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1 @@
|
||||
error: type 'L' is infinitely sized (it contains itself by value); use a pointer ('*L') to break the cycle
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user