add M6-M9 specification tests (#3)
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
# M6 fixtures
|
||||||
|
|
||||||
|
These fixtures pin the M6 ownership/borrow rules before implementation.
|
||||||
|
|
||||||
|
- `ok*.fe` must compile with `--target=bits32 --emit-c`.
|
||||||
|
- `bad*.fe` must fail compilation; the first line follows the `// ERROR:<line>:<substring>` convention from SPEC §12.
|
||||||
|
- They are intentionally not wired into `TEST-DOS.BAT` while `master` is M5, so adding these fixtures does not make the current milestone red.
|
||||||
|
- When M6 starts, wire this directory into the DOS/QEMU gate without changing the expected result of any fixture.
|
||||||
|
- M6 also owns the general-global borrow restriction from R10 because AGENTS.md explicitly groups that change with the `own.c` state-machine work.
|
||||||
|
|
||||||
|
Coverage: R4 storage restrictions, R5 scope, R6 shared/exclusive liveness and reborrows, R7 invalidation, R8 derived returns, defer lifetime extension, and global borrow restrictions.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:8:self
|
||||||
|
unit badarg;
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
value: i32,
|
||||||
|
|
||||||
|
fn bad(self: &Self, other: &i32) -> &i32 {
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ERROR:10:borrow
|
||||||
|
unit baddefer;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let r = &x;
|
||||||
|
defer { let y = read(r); }
|
||||||
|
x = 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:reference
|
||||||
|
unit badfld;
|
||||||
|
|
||||||
|
struct Bad {
|
||||||
|
value: &i32,
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:7:global
|
||||||
|
unit badglob;
|
||||||
|
|
||||||
|
var VALUE: i32 = 0;
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
let r = &VALUE;
|
||||||
|
return r.^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:7:global
|
||||||
|
unit badgmut;
|
||||||
|
|
||||||
|
var VALUE: i32 = 0;
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
let r = &mut VALUE;
|
||||||
|
r.^ = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:6:borrow
|
||||||
|
unit badinv;
|
||||||
|
|
||||||
|
fn bad(p: ^i32, q: ^i32) -> void {
|
||||||
|
let r = &p;
|
||||||
|
p = q;
|
||||||
|
let keep = r;
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:reference
|
||||||
|
unit badlocsl;
|
||||||
|
|
||||||
|
fn bad() -> []u8 {
|
||||||
|
let a: [2]u8 = [1 as u8, 2 as u8];
|
||||||
|
return a[..];
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:8:borrow
|
||||||
|
unit badmove;
|
||||||
|
|
||||||
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
|
fn bad(p: ^i32) -> void {
|
||||||
|
let r = &p;
|
||||||
|
take(p);
|
||||||
|
let q = r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:7:borrow
|
||||||
|
unit badmut;
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let r = &mut x;
|
||||||
|
x = 1;
|
||||||
|
r.^ = 2;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ERROR:7:borrow
|
||||||
|
unit badmut2;
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let a = &mut x;
|
||||||
|
let b = &mut x;
|
||||||
|
a.^ = 1;
|
||||||
|
b.^ = 2;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:4:reference
|
||||||
|
unit badptr;
|
||||||
|
|
||||||
|
fn bad(p: *&i32) -> void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:reference
|
||||||
|
unit badret;
|
||||||
|
|
||||||
|
fn bad() -> &i32 {
|
||||||
|
let x: i32 = 1;
|
||||||
|
return &x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// ERROR:9:reference
|
||||||
|
unit badscop;
|
||||||
|
|
||||||
|
fn bad(cond: bool) -> i32 {
|
||||||
|
let outer: i32 = 0;
|
||||||
|
var r: &i32 = &outer;
|
||||||
|
if cond {
|
||||||
|
let inner: i32 = 3;
|
||||||
|
r = &inner;
|
||||||
|
}
|
||||||
|
return r.^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:8:self
|
||||||
|
unit badself;
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
value: i32,
|
||||||
|
|
||||||
|
fn bad(self: Self) -> &i32 {
|
||||||
|
return &self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ERROR:9:borrow
|
||||||
|
unit badshwr;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let r = &x;
|
||||||
|
x = 1;
|
||||||
|
return read(r);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:reference
|
||||||
|
unit badslfld;
|
||||||
|
|
||||||
|
struct Bad {
|
||||||
|
bytes: []u8,
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:reference
|
||||||
|
unit badtwo;
|
||||||
|
|
||||||
|
fn choose(a: &i32, b: &i32) -> &i32 {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:8:mut
|
||||||
|
unit badup;
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
value: i32,
|
||||||
|
|
||||||
|
fn bad(self: &Self) -> &mut i32 {
|
||||||
|
return &mut self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
unit okbranch;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test(cond: bool) -> i32 {
|
||||||
|
var x: i32 = 3;
|
||||||
|
let r = &x;
|
||||||
|
if cond {
|
||||||
|
let a = read(r);
|
||||||
|
} else {
|
||||||
|
let b = read(r);
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit okdefer;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var x: i32 = 3;
|
||||||
|
if true {
|
||||||
|
let r = &x;
|
||||||
|
defer { let y = read(r); }
|
||||||
|
}
|
||||||
|
x += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
unit okglobcp;
|
||||||
|
|
||||||
|
var VALUE: i32 = 7;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let local = VALUE;
|
||||||
|
return read(&local);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
unit oklast;
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let r = &mut x;
|
||||||
|
r.^ = 1;
|
||||||
|
x += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit okr8free;
|
||||||
|
|
||||||
|
fn head(s: []u8) -> &u8 {
|
||||||
|
return &s[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> u8 {
|
||||||
|
var a: [2]u8 = [1 as u8, 2 as u8];
|
||||||
|
let r = head(a[..]);
|
||||||
|
let v = r.^;
|
||||||
|
a[0] = 7 as u8;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
unit okr8meth;
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
value: i32,
|
||||||
|
|
||||||
|
pub fn get(self: &Self) -> &i32 {
|
||||||
|
return &self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var b = Box{ value: 4 };
|
||||||
|
let r = b.get();
|
||||||
|
let v = r.^;
|
||||||
|
b.value = 5;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit okr8stat;
|
||||||
|
|
||||||
|
fn name() -> str {
|
||||||
|
return "main";
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okrebor;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var x: i32 = 1;
|
||||||
|
let r = &mut x;
|
||||||
|
let v = read(r);
|
||||||
|
r.^ = v + 1;
|
||||||
|
return r.^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
unit okshare;
|
||||||
|
|
||||||
|
fn add(a: &i32, b: &i32) -> i32 {
|
||||||
|
return a.^ + b.^;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let x: i32 = 4;
|
||||||
|
let a = &x;
|
||||||
|
let b = &x;
|
||||||
|
return add(a, b);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okslreb;
|
||||||
|
|
||||||
|
fn first(s: []u8) -> u8 { return s[0]; }
|
||||||
|
|
||||||
|
fn test() -> u8 {
|
||||||
|
var a: [2]u8 = [1 as u8, 2 as u8];
|
||||||
|
var s = a[..];
|
||||||
|
let v = first(s);
|
||||||
|
s[0] = 9 as u8;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okstatic;
|
||||||
|
|
||||||
|
static VALUE: i32 = 7;
|
||||||
|
|
||||||
|
fn get() -> &i32 {
|
||||||
|
return &VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
return get().^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
unit oktemp;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var x: i32 = 1;
|
||||||
|
let v = read(&x);
|
||||||
|
x += 1;
|
||||||
|
return v + x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit oktrim;
|
||||||
|
|
||||||
|
fn trimmed(line: str) -> str {
|
||||||
|
return line.trim();
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# M7 fixtures
|
||||||
|
|
||||||
|
M7 adds optionals and error unions on top of the M6 ownership model.
|
||||||
|
|
||||||
|
`ok*.fe` must compile. `bad*.fe` must fail according to the first-line error marker.
|
||||||
|
The files are not wired into `TEST-DOS.BAT` until M7 work begins.
|
||||||
|
|
||||||
|
Coverage: `?T`, `.?`, `Some`/`None` pattern-only destructuring, `mem.replace` extraction, `orelse`, nominal error unions, `try`, block/short `catch`, error code zero rejection, and R4/R7 interactions with optional references/owners.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// ERROR:14:catch
|
||||||
|
unit badcatch;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
let v = leaf() catch |e| {
|
||||||
|
let ignored: i32 = 1;
|
||||||
|
};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// ERROR:13:type
|
||||||
|
unit baddef;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
return leaf() catch false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:optional
|
||||||
|
unit baddir;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad(p: ?^Node) -> i32 {
|
||||||
|
return p.^.value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// ERROR:17:error
|
||||||
|
unit badetype;
|
||||||
|
|
||||||
|
error A {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
error B {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> A!i32 {
|
||||||
|
return A.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> B!i32 {
|
||||||
|
return try leaf();
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:reference
|
||||||
|
unit badoref;
|
||||||
|
|
||||||
|
struct Bad {
|
||||||
|
value: ?&i32,
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:non-Copy
|
||||||
|
unit badorel;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
next: ?^Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad(p: ^Node, fallback: ^Node) -> ^Node {
|
||||||
|
return p.next orelse fallback;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ERROR:9:mem.replace
|
||||||
|
unit badproj;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
next: ?^Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad(p: ^Node) -> void {
|
||||||
|
let q = p.next;
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:optional
|
||||||
|
unit badqmark;
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
let x: i32 = 1;
|
||||||
|
return x.?;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// ERROR:13:error
|
||||||
|
unit badret;
|
||||||
|
|
||||||
|
error A {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
error B {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> B!i32 {
|
||||||
|
return A.Bad;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:5:Some
|
||||||
|
unit badsome;
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
let x = Some(1);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// ERROR:13:try
|
||||||
|
unit badtry;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
return try leaf();
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:0
|
||||||
|
unit badzero;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Zero = 0,
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
unit okcatch;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top() -> E!i32 {
|
||||||
|
let v = leaf() catch |e| {
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
unit okcvoid;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!void {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top() -> void {
|
||||||
|
leaf() catch |e| {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit okdeflt;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top() -> i32 {
|
||||||
|
return leaf() catch 11;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit okiflet;
|
||||||
|
|
||||||
|
fn value(p: ?i32) -> i32 {
|
||||||
|
if let Some(v) = p {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit okmatch;
|
||||||
|
|
||||||
|
fn value(p: ?i32) -> i32 {
|
||||||
|
match p {
|
||||||
|
Some(v) => { return v; }
|
||||||
|
None => { return 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit okorelse;
|
||||||
|
|
||||||
|
fn value(p: ?i32) -> i32 {
|
||||||
|
return p orelse 9;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
unit okproj;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn touch(p: ?&mut Node) -> void {
|
||||||
|
p.?.value = 7;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okrepl;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take(p: ?^Node) -> void {
|
||||||
|
var q: ?^Node = p;
|
||||||
|
let n = mem.replace(&mut q, null).?;
|
||||||
|
mem.destroy(n);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
unit oktrdef;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf() -> E!i32 {
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top() -> E!i32 {
|
||||||
|
defer { let x: i32 = 1; }
|
||||||
|
return try leaf();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
unit oktry;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf(ok: bool) -> E!i32 {
|
||||||
|
if ok { return 7; }
|
||||||
|
return E.Bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top() -> E!i32 {
|
||||||
|
return try leaf(true);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# M8 fixtures
|
||||||
|
|
||||||
|
M8 is the first multi-unit milestone, so cases live in subdirectories. Each case is compiled separately with that directory on the import path.
|
||||||
|
|
||||||
|
Pass cases:
|
||||||
|
- `basic`: public function across units.
|
||||||
|
- `pubfld`: public type and public field across units.
|
||||||
|
- `errsame`: two units use the same anonymous `error.Name`; the driver must assign one deterministic `core.Error` code.
|
||||||
|
- `errdet`: the same anonymous error-name set appears in a different source/import order; generated `fe_errors.h` must be byte-identical to `errsame` modulo the intentionally different unit graph.
|
||||||
|
|
||||||
|
Fail cases:
|
||||||
|
- `privfn`: private declaration access.
|
||||||
|
- `privfld`: private field access.
|
||||||
|
- `missing`: unresolved import.
|
||||||
|
- `cycle`: cyclic imports.
|
||||||
|
- `unitbad`: filename/unit-name mismatch.
|
||||||
|
- `errnom`: nominal error cannot flow into `core.Error` via `try`.
|
||||||
|
|
||||||
|
The current M5 `TEST-DOS.BAT` is intentionally unchanged. M8 should add procedural checks for `.fei` creation/hash invalidation and deterministic `fe_errors.h` using these fixtures.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
unit main;
|
||||||
|
import util;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
return util.answer();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit util;
|
||||||
|
|
||||||
|
pub fn answer() -> i32 {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
unit a;
|
||||||
|
import b;
|
||||||
|
|
||||||
|
pub fn a_value() -> i32 { return b.b_value(); }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// ERROR:3:cycle
|
||||||
|
unit b;
|
||||||
|
import a;
|
||||||
|
|
||||||
|
pub fn b_value() -> i32 { return 1; }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit alpha;
|
||||||
|
|
||||||
|
pub fn fail() -> !void {
|
||||||
|
return error.Busy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit beta;
|
||||||
|
|
||||||
|
pub fn fail() -> !void {
|
||||||
|
return error.Busy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
unit main;
|
||||||
|
import beta;
|
||||||
|
import alpha;
|
||||||
|
|
||||||
|
fn one() -> !void { return beta.fail(); }
|
||||||
|
fn two() -> !void { return alpha.fail(); }
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
unit lib;
|
||||||
|
|
||||||
|
pub error LibError {
|
||||||
|
Bad = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value() -> LibError!i32 {
|
||||||
|
return LibError.Bad;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:error
|
||||||
|
unit main;
|
||||||
|
import lib;
|
||||||
|
|
||||||
|
fn bad() -> !i32 {
|
||||||
|
return try lib.value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit alpha;
|
||||||
|
|
||||||
|
pub fn fail() -> !void {
|
||||||
|
return error.Busy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit beta;
|
||||||
|
|
||||||
|
pub fn fail() -> !void {
|
||||||
|
return error.Busy;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
unit main;
|
||||||
|
import alpha;
|
||||||
|
import beta;
|
||||||
|
|
||||||
|
fn one() -> !void { return alpha.fail(); }
|
||||||
|
fn two() -> !void { return beta.fail(); }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// ERROR:3:import
|
||||||
|
unit main;
|
||||||
|
import absent;
|
||||||
|
|
||||||
|
fn main() -> void {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit data;
|
||||||
|
|
||||||
|
pub struct Record {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// ERROR:6:private
|
||||||
|
unit main;
|
||||||
|
import data;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
let r = data.Record{ value: 7 };
|
||||||
|
return r.value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:private
|
||||||
|
unit main;
|
||||||
|
import util;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
return util.hidden();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit util;
|
||||||
|
|
||||||
|
fn hidden() -> i32 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit data;
|
||||||
|
|
||||||
|
pub struct Record {
|
||||||
|
pub value: i32,
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
unit main;
|
||||||
|
import data;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
let r = data.Record{ value: 7 };
|
||||||
|
return r.value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// ERROR:2:unit
|
||||||
|
unit other;
|
||||||
|
|
||||||
|
fn main() -> void {}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# M9 fixtures
|
||||||
|
|
||||||
|
M9 adds comptime type parameters and monomorphization.
|
||||||
|
|
||||||
|
`ok*.fe` must compile; `bad*.fe` must fail according to the first-line marker.
|
||||||
|
`defscope/` is a multi-unit definition-scope test and requires M8 imports.
|
||||||
|
|
||||||
|
Coverage:
|
||||||
|
- generic functions and structs,
|
||||||
|
- multiple and duplicate instantiations,
|
||||||
|
- type aliases as comptime type values,
|
||||||
|
- `T == U` and `@is_int(T)` in comptime,
|
||||||
|
- instantiation-time operation errors,
|
||||||
|
- arity/type-argument errors,
|
||||||
|
- runtime `type` values forbidden,
|
||||||
|
- definition-unit name lookup,
|
||||||
|
- recursive instantiation depth limit.
|
||||||
|
|
||||||
|
M9's DOS gate should additionally inspect generated `fe_generics.c`: `okdedup.fe` must emit one body for the repeated `(id, i32)` instantiation.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:comptime
|
||||||
|
unit badarg;
|
||||||
|
|
||||||
|
fn id(comptime T: type, v: T) -> T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
return id(7, 8);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:argument
|
||||||
|
unit badarity;
|
||||||
|
|
||||||
|
struct Box(T) {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var x: Box(i32, u8);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:instantiation
|
||||||
|
unit badbody;
|
||||||
|
|
||||||
|
fn add(comptime T: type, a: T, b: T) -> T {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> bool {
|
||||||
|
return add(bool, true, false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:depth
|
||||||
|
unit baddepth;
|
||||||
|
|
||||||
|
struct Box(T) {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var x: Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(Box(i32)))))))))))))))))))))))))))))))));
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:generic
|
||||||
|
unit badfew;
|
||||||
|
|
||||||
|
struct Box(T) {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var x: Box;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// ERROR:16:instantiation
|
||||||
|
unit badop;
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max(comptime T: type, a: T, b: T) -> T {
|
||||||
|
if a > b { return a; }
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> Token {
|
||||||
|
let a = Token{ value: 1 };
|
||||||
|
let b = Token{ value: 2 };
|
||||||
|
return max(Token, a, b);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:helper
|
||||||
|
unit lib;
|
||||||
|
|
||||||
|
pub fn call(comptime T: type, v: T) -> T {
|
||||||
|
return helper(v);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit main;
|
||||||
|
import lib;
|
||||||
|
|
||||||
|
fn helper(v: i32) -> i32 { return v + 10; }
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
return lib.call(i32, 1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:type
|
||||||
|
unit badtype;
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
let t = i32;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit lib;
|
||||||
|
|
||||||
|
fn bump_i32(v: i32) -> i32 {
|
||||||
|
return v + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bump(comptime T: type, v: T) -> T {
|
||||||
|
comptime if T == i32 {
|
||||||
|
return bump_i32(v);
|
||||||
|
} else {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
unit main;
|
||||||
|
import lib;
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
return lib.bump(i32, 4);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okalias;
|
||||||
|
|
||||||
|
const Word = i32;
|
||||||
|
|
||||||
|
fn id(comptime T: type, v: T) -> T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> Word {
|
||||||
|
return id(Word, 12);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
unit okbox;
|
||||||
|
|
||||||
|
struct Box(T) {
|
||||||
|
value: T,
|
||||||
|
|
||||||
|
pub fn new(v: T) -> Self {
|
||||||
|
return Self{ value: v };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: &Self) -> &T {
|
||||||
|
return &self.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var b: Box(i32) = Box(i32).new(7);
|
||||||
|
return b.get().^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit okdedup;
|
||||||
|
|
||||||
|
fn id(comptime T: type, v: T) -> T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() -> i32 { return id(i32, 1); }
|
||||||
|
fn b() -> i32 { return id(i32, 2); }
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
unit okid;
|
||||||
|
|
||||||
|
fn id(comptime T: type, v: T) -> T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
return id(i32, 7);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit okisint;
|
||||||
|
|
||||||
|
fn is_integer(comptime T: type) -> bool {
|
||||||
|
comptime if @is_int(T) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> bool {
|
||||||
|
return is_integer(u16);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okmulti;
|
||||||
|
|
||||||
|
fn id(comptime T: type, v: T) -> T {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let a: i32 = id(i32, 7);
|
||||||
|
let b: u8 = id(u8, 9 as u8);
|
||||||
|
return a + (b as i32);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
unit oknested;
|
||||||
|
|
||||||
|
struct Box(T) {
|
||||||
|
value: T,
|
||||||
|
|
||||||
|
pub fn new(v: T) -> Self {
|
||||||
|
return Self{ value: v };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let inner: Box(i32) = Box(i32).new(3);
|
||||||
|
let outer: Box(Box(i32)) = Box(Box(i32)).new(inner);
|
||||||
|
return outer.value.value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
unit okpair;
|
||||||
|
|
||||||
|
struct Pair(A, B) {
|
||||||
|
first: A,
|
||||||
|
second: B,
|
||||||
|
|
||||||
|
pub fn new(a: A, b: B) -> Self {
|
||||||
|
return Self{ first: a, second: b };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
let p: Pair(i32, u8) = Pair(i32, u8).new(4, 5 as u8);
|
||||||
|
return p.first + (p.second as i32);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit oktypeeq;
|
||||||
|
|
||||||
|
fn kind(comptime T: type) -> i32 {
|
||||||
|
comptime if T == i32 {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
return kind(i32);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user