Rule 8.19
Chapter 8, Functions and entry points Test
A function that writes no return type returns what its body does, as TypeScript infers it: a function of the file or of a namespace, a local function (Rule 8.17), each instance of a generic function (Rule 8.9) and of a function that takes a function (Rule 8.18), a method, a getter and a field that holds a function (Rule 8.16) take the type of their first return with a value, the returns after it are typed against that type as against a written one, and one with no such return returns nothing.
An arrow function whose body is an expression returns its value, unless the expression is an assignment, ++, -- or a call of a function that returns nothing, which runs as a statement, and the function returns nothing; a method whose every return is return this returns its object, as one written this does (Rule 8.10).
A call that needs the type before the body’s turn lowers that body first, so a function may be called above its declaration and from any body.
A setter’s value that writes no type takes the type its getter returns, written or said by the getter’s body, as TypeScript types it; an assignment that needs the type before the getter’s body is lowered lowers it first.
A call back into a body still being lowered is a call cycle, and must be refused as one (Rule 8.4); so must returns of two types, a bare return beside one with a value, a default parameter value that calls such a function, since every default is lowered before any body, and a setter’s value with no type and no getter, or beside a getter that returns nothing.
An entry point writes its return type, which is its output (Rule 8.2).
return g() where g returns nothing calls g and returns nothing, in any function.
The rule text and the parts under it are the compiler's own English, as the design document writes them.
Rationale
TypeScript code leaves return types off as often as it writes them, most of all on a helper and on a local arrow function (const f = (x: f32) => x * k), and the body saying the type is the ordinary TypeScript experience.
Before this rule a function with none returned void beside a TS8021 warning, so one that returned a value was a type mismatch at every call, and an arrow function whose body is an expression, a getter and a field that holds a function with none were refused.
The front end has no checker to ask, but it lowers every body, and the type of the first return with a value is the one TypeScript infers whenever the program has a shader meaning: a union of two types, or undefined beside a value, has none, and those are refused.
Lowering a body when a call first needs it, rather than in declaration order, is what lets a function be called above its declaration, as TypeScript hoists it; a type that waits on itself only arises in a call cycle, which is refused anyway.
An assignment’s value is what an arrow function written to run it is never for, so it runs as a statement, the one divergence here, which Rule 7.2 records.
No call says a setter’s value type, and the getter does: TypeScript types the property from the getter’s return, inferred or written, and a setter with no getter is its implicit any (TS7006), which a shader has no word for.
Derives from
TypeScript’s return type inference (the type of the returned expressions; TS7023 for one that waits on itself); ECMAScript return (return g() evaluates the call and returns its value, undefined for a function that returns nothing); Rule 8.2; Rule 8.4; Rule 8.9; Rule 8.10; Rule 8.11; Rule 8.16; Rule 8.17; Rule 8.18; surface §14 and §26.
How it is verified
Checked by a test. A test, a gate script or a CI workflow names this rule, and the traceability check fails when a file listed below stops naming it.
Where the rule says the compiler enforces it:
TS8031 RECURSION for a cycle (Recursive call: "a" -> "b" -> "a". WGSL has no call stack, so a function must not take part in a call cycle.), TS8003 TYPE_MISMATCH for two types (Function "f" returns f32 at its first "return" and vec2 at another; a function returns one type (Rule 8.19): make them agree, or write the return type.), TS8021 RETURN_SHAPE for a bare return beside a value and for an entry that returns a value with no return type, TS8020 FUNCTION_SHAPE for a default ("h" says what it returns in its body, and a default is lowered before any body: write the return type on "h" (Rule 8.19).) and TS8002 UNKNOWN_TYPE for a setter’s value with nothing to take a type from (The setter "A.x" needs a type for "v": write "set x(v: T)"., The getter "A.x" returns nothing, so the setter has no type for "v": write "set x(v: T)".); pinned by src/compiler/ts/return-inference.test.ts, which holds WGSL, GLSL ES 3.00, the CPU oracle, the codegen and the debugger to one value for each form, compares each with the program that writes its return types, and holds the multi-file path and the editor’s silence; examples/inferred-returns.shade.ts in the compile gate.
The files that verify it at commit 26de7be8, each at the first line that names the rule:
Explained in
The sections of the surface document that explain this rule, at commit 26de7be8:
Error codes that enforce it
The diagnostic codes the rule names under Enforced by, or whose registry text names the rule:
-
TS8002UNKNOWN_TYPE - A type name nothing declares, said once for the file wherever it is written (a parameter, a claim, a type argument,
B<vec3<Foo>>included, an alias, animplementsclause, the base a class or an interface extends, a body no call lowers), a type the library declares for TypeScript alone (Number) where the file declares none of its name, or a type this surface does not take in a position the mapper reads (Rule 2.1). -
TS8003TYPE_MISMATCH - Two types that do not fit where they meet (an operator, a condition, a declaration, a return or an argument), or a constant the compiler folds that WGSL refuses: a shift amount past 31, a divisor of 0, clamp bounds that cross or an f32 past its range.
-
TS8020FUNCTION_SHAPE - A function declaration or parameter shape TypeShade does not support (missing name or body, optional/rest/destructured parameter).
-
TS8021RETURN_SHAPE - A
returnshape problem: barereturnwhere a value is required, or an entry function with no return type annotation that returns a value. -
TS8031RECURSION - A call cycle: a function that reaches itself, directly or through other functions.
See also
Source
The rule at commit 26de7be8:
docs/language-design.md:816(the design document)reqs/rules/RULE-0819.md(its traceability item)