test: audit M6-M9 fixtures for v0.1.8
This commit is contained in:
@@ -8,4 +8,4 @@ These fixtures pin the M6 ownership/borrow rules before implementation.
|
|||||||
- When M6 starts, wire this directory into the DOS/QEMU gate without changing the expected result of any fixture.
|
- 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.
|
- 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.
|
Coverage: R4 storage restrictions, R5 scope, R6 shared/exclusive liveness, root-local field/index conflicts, call-only `&mut -> &` reborrows, branch/loop `MaybeMoved` and initialization-state merging, R7 invalidation, R8 derived-return provenance joins, defer lifetime extension, and global borrow restrictions.
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:9:initialized
|
||||||
|
unit badbinit;
|
||||||
|
|
||||||
|
fn bad(assign: bool) -> i32 {
|
||||||
|
var value: i32;
|
||||||
|
if assign {
|
||||||
|
value = 1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:9:move
|
||||||
|
unit badbrmov;
|
||||||
|
|
||||||
|
fn bad(p: ^i32, consume: bool) -> void {
|
||||||
|
if consume {
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:8:move
|
||||||
|
unit badloop;
|
||||||
|
|
||||||
|
fn bad(p: ^i32, again: bool) -> void {
|
||||||
|
while again {
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
|
mem.destroy(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// ERROR:9:borrow
|
||||||
|
unit badrfld;
|
||||||
|
|
||||||
|
struct Pair { a: i32, b: i32, }
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var p = Pair{ a: 1, b: 2 };
|
||||||
|
let left = &mut p.a;
|
||||||
|
p.b = 3;
|
||||||
|
left.^ = 4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// ERROR:7:borrow
|
||||||
|
unit badridx;
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var xs: [2]i32 = [1, 2];
|
||||||
|
let a = &mut xs[0];
|
||||||
|
let b = &mut xs[1];
|
||||||
|
a.^ = 3;
|
||||||
|
b.^ = 4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ERROR:7:mut
|
||||||
|
unit badweak;
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
var x: i32 = 0;
|
||||||
|
let m = &mut x;
|
||||||
|
let s: &i32 = m;
|
||||||
|
let v = s.^;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
unit okr8join;
|
||||||
|
|
||||||
|
fn select(s: str, from_param: bool) -> str {
|
||||||
|
if from_param { return s; }
|
||||||
|
return "static";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> u8 {
|
||||||
|
var bytes: [1]u8 = [7 as u8];
|
||||||
|
let view = select(bytes[..], true);
|
||||||
|
let value = view[0];
|
||||||
|
bytes[0] = 8 as u8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okrtlast;
|
||||||
|
|
||||||
|
struct Pair { a: i32, b: i32, }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var p = Pair{ a: 1, b: 2 };
|
||||||
|
let left = &mut p.a;
|
||||||
|
left.^ = 3;
|
||||||
|
p.b = 4;
|
||||||
|
return p.a + p.b;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okwcall;
|
||||||
|
|
||||||
|
fn read(r: &i32) -> i32 { return r.^; }
|
||||||
|
|
||||||
|
fn test() -> i32 {
|
||||||
|
var x: i32 = 5;
|
||||||
|
let m = &mut x;
|
||||||
|
let value = read(m);
|
||||||
|
m.^ = value + 1;
|
||||||
|
return m.^;
|
||||||
|
}
|
||||||
@@ -5,4 +5,4 @@ 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.
|
`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.
|
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.
|
Coverage: contextual `null`, `?T`, `.?`, `Some`/`None` pattern-only non-destructive views, `mem.replace` extraction, lazy `orelse`/`catch`, nominal error unions, `try`, block/short `catch`, and error code/name uniqueness, plus R4/R7 interactions with optional references/owners.
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:duplicate
|
||||||
|
unit badercod;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
One = 1,
|
||||||
|
Two = 1,
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// ERROR:6:duplicate
|
||||||
|
unit badernam;
|
||||||
|
|
||||||
|
error E {
|
||||||
|
One = 1,
|
||||||
|
One = 2,
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:5:null
|
||||||
|
unit badnull;
|
||||||
|
|
||||||
|
fn bad() -> void {
|
||||||
|
let p = null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit okcatmov;
|
||||||
|
|
||||||
|
error E { Bad = 1, }
|
||||||
|
struct Node { value: i32, }
|
||||||
|
|
||||||
|
fn recover(result: E!^Node, fallback: ^Node) -> ^Node {
|
||||||
|
return result catch fallback;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
unit oknull;
|
||||||
|
|
||||||
|
struct Node { value: i32, }
|
||||||
|
|
||||||
|
fn accepts(p: ?^Node) -> bool { return p == null; }
|
||||||
|
|
||||||
|
fn test() -> bool {
|
||||||
|
let p: ?^Node = null;
|
||||||
|
return accepts(p);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
unit okpatvw;
|
||||||
|
|
||||||
|
struct Node { value: i32, }
|
||||||
|
|
||||||
|
fn keep(p: ?^Node) -> void {
|
||||||
|
var slot = p;
|
||||||
|
if let Some(node) = slot {
|
||||||
|
let value = node.value;
|
||||||
|
}
|
||||||
|
let owned = mem.replace(&mut slot, null).?;
|
||||||
|
mem.destroy(owned);
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ M8 is the first multi-unit milestone, so cases live in subdirectories. Each case
|
|||||||
Pass cases:
|
Pass cases:
|
||||||
- `basic`: public function across units.
|
- `basic`: public function across units.
|
||||||
- `pubfld`: public type and public field across units.
|
- `pubfld`: public type and public field across units.
|
||||||
|
- `dotted` and `alias`: canonical dotted unit paths, last-segment binding, and explicit import aliases.
|
||||||
|
- `dotpriv`: a dotted unit prefix does not grant access to another unit's private declarations.
|
||||||
- `errsame`: two units use the same anonymous `error.Name`; the driver must assign one deterministic `core.Error` code.
|
- `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.
|
- `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.
|
||||||
|
|
||||||
@@ -14,6 +16,11 @@ Fail cases:
|
|||||||
- `missing`: unresolved import.
|
- `missing`: unresolved import.
|
||||||
- `cycle`: cyclic imports.
|
- `cycle`: cyclic imports.
|
||||||
- `unitbad`: filename/unit-name mismatch.
|
- `unitbad`: filename/unit-name mismatch.
|
||||||
|
- `badupper` and `badlong`: DOS-safe lowercase, eight-character unit-segment limit.
|
||||||
|
- `bindconf`: two imports with the same last-segment binding require an alias.
|
||||||
|
- `pubpriv`: a public signature cannot expose a private nominal type.
|
||||||
- `errnom`: nominal error cannot flow into `core.Error` via `try`.
|
- `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.
|
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.
|
||||||
|
|
||||||
|
The M8 DOS gate must additionally construct two separate `-I` roots containing the same canonical unit and require an ambiguity error; repeat the case with two paths to the same canonical file and require deduplication. It must also verify that `std.*` resolves only from the built-in std root, ordinary user units never do, and that changing a private non-generic implementation preserves the dependent interface-cache hit. Those checks need temporary roots/cache inspection and deliberately remain procedural rather than encoding host paths in fixtures.
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
unit acme.math;
|
||||||
|
|
||||||
|
pub fn answer() -> i32 { return 42; }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
unit main;
|
||||||
|
import acme.math as calc;
|
||||||
|
|
||||||
|
fn main() -> i32 { return calc.answer(); }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// ERROR:2:unit
|
||||||
|
unit toolonggg;
|
||||||
|
|
||||||
|
fn main() -> void {}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// ERROR:2:unit
|
||||||
|
unit Upper;
|
||||||
|
|
||||||
|
fn main() -> void {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
unit alpha.net;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
unit beta.net;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// ERROR:4:binding
|
||||||
|
unit main;
|
||||||
|
import alpha.net;
|
||||||
|
import beta.net;
|
||||||
|
|
||||||
|
fn main() -> void {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// ERROR:5:private
|
||||||
|
unit game.bar;
|
||||||
|
import game.foo;
|
||||||
|
|
||||||
|
pub fn read() -> i32 { return foo.hidden(); }
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
unit game.foo;
|
||||||
|
|
||||||
|
fn hidden() -> i32 { return 1; }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
unit main;
|
||||||
|
import game.bar;
|
||||||
|
|
||||||
|
fn main() -> i32 { return bar.read(); }
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
unit acme.math;
|
||||||
|
|
||||||
|
pub fn answer() -> i32 { return 42; }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
unit main;
|
||||||
|
import acme.math;
|
||||||
|
|
||||||
|
fn main() -> i32 { return math.answer(); }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
unit lib;
|
||||||
|
|
||||||
|
struct Hidden { value: i32, }
|
||||||
|
// ERROR:4:private
|
||||||
|
pub fn make() -> Hidden { return Hidden{ value: 1 }; }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
unit main;
|
||||||
|
import lib;
|
||||||
|
|
||||||
|
fn main() -> void { let value = lib.make(); }
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
M9 adds comptime type parameters and monomorphization.
|
M9 adds comptime type parameters and monomorphization.
|
||||||
|
|
||||||
`ok*.fe` must compile; `bad*.fe` must fail according to the first-line marker.
|
`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.
|
`defscope/` and `okscope/` are multi-unit definition-scope tests and require M8 imports. `okscope/` verifies that an exported generic may use its definition unit's private helper through `.fei` support metadata.
|
||||||
|
|
||||||
Coverage:
|
Coverage:
|
||||||
- generic functions and structs,
|
- generic functions and structs,
|
||||||
@@ -15,5 +15,7 @@ Coverage:
|
|||||||
- runtime `type` values forbidden,
|
- runtime `type` values forbidden,
|
||||||
- definition-unit name lookup,
|
- definition-unit name lookup,
|
||||||
- recursive instantiation depth limit.
|
- recursive instantiation depth limit.
|
||||||
|
- rejection of user value generics and generic type inference,
|
||||||
|
- same-instance recursive request reuse and selected-out `comptime if` semantic skipping.
|
||||||
|
|
||||||
M9's DOS gate should additionally inspect generated `fe_generics.c`: `okdedup.fe` must emit one body for the repeated `(id, i32)` instantiation.
|
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:7:depth
|
||||||
|
unit baddist;
|
||||||
|
|
||||||
|
struct Box(T) { value: T, }
|
||||||
|
|
||||||
|
fn grow(comptime T: type) -> void {
|
||||||
|
grow(Box(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> void { grow(i32); }
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// ERROR:7:generic
|
||||||
|
unit badinfer;
|
||||||
|
|
||||||
|
fn id(comptime T: type, value: T) -> T { return value; }
|
||||||
|
|
||||||
|
fn bad() -> i32 {
|
||||||
|
return id(7);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// ERROR:4:comptime
|
||||||
|
unit badvalue;
|
||||||
|
|
||||||
|
fn id(comptime N: usize, value: i32) -> i32 { return value; }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
unit oksamrec;
|
||||||
|
|
||||||
|
fn repeat(comptime T: type, value: T) -> T {
|
||||||
|
return repeat(T, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 { return repeat(i32, 1); }
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// ERROR:5:helper
|
|
||||||
unit lib;
|
unit lib;
|
||||||
|
|
||||||
pub fn call(comptime T: type, v: T) -> T {
|
pub fn call(comptime T: type, v: T) -> T {
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
unit okskip;
|
||||||
|
|
||||||
|
fn select(comptime T: type, value: T) -> T {
|
||||||
|
comptime if T == i32 {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return unknown(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() -> i32 { return select(i32, 1); }
|
||||||
Reference in New Issue
Block a user