Repository navigation
self-host P3 slice 4: values known at compile time fit their types, in Zig and in C (E_UNSOUND) #8100
Description
Part of #5980 (phase P3, the type checker). This is the fourth P3 slice: literal widths, or more exactly every value Zig knows at compile time.
t27c's typecheck reads a constant's width only in a module const whose value is a decimal literal (check_const_widths; #8035 covers the separated, hex and binary forms it skips). Nowhere else does a constant meet its type (see #8098). So these all pass typecheck, and gen-c writes C that converts, wraps or traps, where Zig refuses:
var x: u8 = 300;h(300)with a u8 parameterreturn -1;from a u32 functionx + 300withx: u8300 as u8G - 9withconst G: u32 = 1xs[4]on a[4]u8x << 40on a u32x / 0
gen-c also writes constant expressions as C text, so C computes them in the type of their literals: 100000 * 100000, 1 << 40, G * G with a #define G, 0xFFFFFFFF + 1 (see #8099). And a negative constant compared with a u32 is converted (see #8076).
This slice
The core works out every value Zig knows at compile time, both in Zig's type and in the C type gen-c's text gives it. It refuses with E_UNSOUND (17):
- a value that does not fit the type it meets: as a whole at an initializer, argument, return, field, item or assignment; an untyped one in the type of the runtime operand it meets;
- a step that overflows a typed operand or the C type;
- a cast that does not hold its value;
- an index past a one-dimension array;
- a shift amount at or past the shifted width;
- a zero divisor;
- a negative constant compared with an unsigned int or wider.
It accepts what both backends compute alike, as the accept fixture shows. Fixtures, core tests and the DDC repin, as in earlier slices.
User Scenarios
- Given a module with
var x: u8 = 300;When the typechecker runs Then it reports E_UNSOUND because 300 does not fit u8. - Given a function
fn h(p: u8) void {}called ash(300)When the typechecker runs Then it reports E_UNSOUND because the argument 300 does not fit the u8 parameter. - Given a function
fn f() u32 { return -1; }When the typechecker runs Then it reports E_UNSOUND because -1 does not fit u32.
Requirements
- FR-001: The typechecker MUST compute every value Zig knows at compile time in both the Zig type and the C type that gen-c emits.
- FR-002: The typechecker MUST reject with E_UNSOUND (17) any value that does not fit the type it meets at an initializer, argument, return, field, item, or assignment.
- FR-003: The typechecker MUST reject with E_UNSOUND any untyped value that does not fit the type of the runtime operand it meets.
- FR-004: The typechecker MUST reject with E_UNSOUND any step that overflows a typed operand or the C type.
- FR-005: The typechecker MUST reject with E_UNSOUND any cast that does not hold its value.
- FR-006: The typechecker MUST reject with E_UNSOUND any index past a one-dimension array bound.
- FR-007: The typechecker MUST reject with E_UNSOUND any shift amount at or past the shifted type's width.
- FR-008: The typechecker MUST reject with E_UNSOUND any zero divisor.
- FR-009: The typechecker MUST reject with E_UNSOUND any negative constant compared with an unsigned int or wider type.
- FR-010: The typechecker MUST accept programs where both backends compute the same result, as demonstrated by the accept fixture.
Success Criteria
t27c check fixtures/p3/slice4/reject.t27exits with code 17 and prints E_UNSOUND for each rejecting case.t27c check fixtures/p3/slice4/accept.t27exits with code 0.cargo test -p t27c -- typecheck::p3_slice4runs 5 tests and exits 0.- The DDC repin command
./scripts/ddc-repin.shexits 0.
Boundary
- specs/base/types.t27
- specs/tools/tri/types.t27
- specs/memory/tmem/types.t27
- specs/memory/graph/types.t27
- specs/tri/utils/time.t27
- cli/tri/src/depin/types.rs
Activity