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