Runtime taint and T?unknown
This chapter documents the runtime layer of the unknown value: how
is unknown lowers, how the callee-return-summary path infers taint
without an annotation, and how the declared T?unknown return-flow
marker opts a function into the same contract explicitly.
All three sub-features landed in the v0.31.9.x sub-cycle:
| Slice | Lands |
|---|---|
| v0.31.9.1 | Real is unknown taint fold (PHASE3-DEC-002/003/004). |
| v0.31.9.2 | Callee return-taint summary; TBB_UNKNOWN_AT_USE reservation. |
| v0.31.9.3 | Reject assignment to a fixed struct field (ARIA-056) — see |
| ../types/fixed_field.md. | |
| v0.31.9.4 | Declared return-flow marker T?unknown (D-17a / PHASE3-DEC-011). |
| v0.31.9.5 | K-semantics runtime layer locked (PHASE3-DEC-010). |
The is unknown test
Given a binding of any ordinary type, x is unknown evaluates to a
bool that is true when the binding's value originated from the
unknown literal (directly or transitively through propagation), and
false otherwise.
func:main = int32() {
int32:x = unknown;
pick (x is unknown) {
(true) { exit 0i32; },
(false) { exit 1i32; }
}
};
The compiler folds x is unknown to a constant true / false at
each use site by consulting the per-binding Symbol::mayBeUnknown
flag. When the flag cannot be statically resolved (e.g. the binding
came from an arithmetic mix of tainted and clean sources), the test
conservatively folds to true — callers always learn "yes, this may
be unknown".
The callee return-taint summary
A function body that contains pass unknown (directly, or through a
folded constant) automatically gets returnMayBeUnknown = true set
on its declaration. Callers then treat the bound result as tainted
without any annotation:
func:maker = int32() {
pass unknown;
};
func:main = int32() {
int32:x = raw maker(); // x is now flagged tainted
pick (x is unknown) {
(true) { exit 0i32; }, // taken
(false) { exit 1i32; }
}
};
The summary is body-discovered. A caller never needs to write any
qualifier on the binding — Symbol::mayBeUnknown is set at
initialization time from the callee's flag.
The declared T?unknown marker
When you want to opt a function into the same contract without
having pass unknown in its body (for instance, the body is a stub
or an extern shim that may surface unknown values from C), write
the return type as T?unknown:
func:maker = int32?unknown() {
pass 42i32;
};
func:main = int32() {
int32?:x = raw maker();
pick (x is unknown) {
(true) { exit 0i32; }, // conservatively taken
(false) { exit 1i32; }
}
};
The trailing unknown is opt-in. A bare T? retains the original
optional-type semantics from earlier slices and does not taint
caller bindings. Both paths — body-inferred and declared — write into
the same FuncDeclStmt::returnMayBeUnknown flag, and both are
consumed by the same caller-side hook
(initializerTaintsBinding's CALL arm), so the caller-visible
contract is identical regardless of which path opted the callee in.
Stripping the taint with ok(...)
A tainted binding stays tainted until you wrap a read with ok(...):
func:main = int32() {
int32?:x = raw maker();
int32:y = ok(x); // y is clean
pick (y is unknown) {
(true) { exit 1i32; },
(false) { exit 0i32; } // taken
}
};
ok(...) is the only way to convert from a taint-carrying binding to
a clean one. The compiler folds ok(x) is unknown to false at the
declaration site of y.
Arithmetic propagation
unknown is a propagating bottom for arithmetic: unknown + 5,
unknown * 0, unknown - unknown all stay unknown. The K
semantics models this directly (see nitpick.k lines around 2112 for
the Unknown propagation rules, and tests 158–161 in
k-semantics/tests/core/ for the runtime regressions).
Cross-references
unknownandok(...)— the compile-time taxonomy and the originalSymbol::mayBeUnknownintroduction.pickexhaustiveness for special values —pick (e is unknown) { ... }is just aboolpick with literaltrue/falsearms.fixedstruct fields — companion feature landed in the same sub-cycle.- ARIA codes touched in this surface: none new for the runtime layer (D-17a / D-18 / callee-summary are all contracts, not diagnostics).