pub enum TypedStmtKind {
Show 21 variants
Let {
name: Ident,
ty: Type,
value: ExprId,
boxed: bool,
doc: Option<DocComment>,
},
ReboxLocal {
ident: Ident,
ty: Type,
},
Const {
name: Ident,
ty: Type,
value: ExprId,
doc: Option<DocComment>,
},
If {
condition: ExprId,
then_block: StmtId,
else_block: Option<StmtId>,
},
While {
condition: ExprId,
body: StmtId,
},
For {
init: Option<StmtId>,
condition: Option<ExprId>,
update: Option<StmtId>,
body: StmtId,
},
ForOf {
binding_kind: BindingKind,
name: Ident,
element_ty: Type,
iter: ExprId,
body: StmtId,
kind: ForOfKind,
},
DoWhile {
body: StmtId,
condition: ExprId,
},
Switch {
discriminant: ExprId,
discriminant_ty: Type,
cases: Vec<TypedSwitchCase>,
default: Option<StmtId>,
},
Break,
Continue,
Return(Option<ExprId>),
Throw {
value: ExprId,
},
Try {
body: StmtId,
catches: Vec<TypedCatchClause>,
finally: Option<StmtId>,
},
Expr(ExprId),
Block(Vec<StmtId>),
AssignLocal {
ident: Ident,
target_ty: Type,
value: ExprId,
boxed: bool,
narrowed_shadow_ty: Option<Type>,
},
AssignGlobal {
ident: Ident,
mangled: MangledName,
target_ty: Type,
value: ExprId,
},
AssignField {
receiver: ExprId,
name: Ident,
value: ExprId,
},
AssignIndex {
receiver: ExprId,
index: ExprId,
value: ExprId,
elem_ty: Type,
},
NarrowRegion {
path: ReferencePath,
source: ExprId,
binding: Ident,
cast_info: CastInfo,
body: StmtId,
},
}Variants§
Let
Function-local only; top-level let is in TypedAst::globals.
ty is the annotation when present, else the inferred type — annotation wins on mismatch.
ReboxLocal
Replace the box in ident’s slot with a fresh one holding the same value,
so closures created from here on capture a cell nothing before them shares.
Only the for lowering emits this, for the per-iteration binding a let
head has in JS (ECMA-262 §14.7.4.4 CreatePerIterationEnvironment): each
pass gets its own copy, which is why for (let i …) fns.push(() => i)
yields 0,1,2 rather than three views of one slot. ident must name a
boxed binding — an unboxed one is captured by value, so there is
nothing to separate.
Const
Captured const bindings are copied into the closure env (no boxed field).
Function-local only — see Let.
If
While
For
Pre-desugar; codegen never sees this variant.
ForOf
Pre-desugar; codegen never sees this variant. kind lets desugar dispatch
without re-running assignability.
Fields
binding_kind: BindingKindDoWhile
Pre-desugar; lowers to a while-true whose head tests cond on every
pass but the first, so a continue still reaches the test.
Switch
Not lowered to if/else — first-class through desugar and codegen.
discriminant_ty drives dispatch strategy. Case bodies are wrapped in
NarrowRegion by the inferer for discriminated-union narrowing.
Fields
cases: Vec<TypedSwitchCase>Break
Continue
Desugar injects the update step before the jump in for/for-of.
A switch frame on the loop-contexts stack is skipped so continue inside
switch reaches the enclosing loop.
Return(Option<ExprId>)
Throw
throw <expr>. Value must be Error; diverges in control-flow analysis.
Try
catches dispatch in declaration order on the thrown value’s nominal
class; an unmatched error re-raises. Codegen duplicates finally on
normal/caught/uncaught paths.
Expr(ExprId)
Block(Vec<StmtId>)
AssignLocal
Function-scope binding assignment. target_ty is the slot’s declared type;
codegen coerces primitives into ref-typed slots (e.g. number | null boxes f64).
Fields
AssignGlobal
const and function targets are rejected. target_ty mirrors AssignLocal.target_ty for codegen coercion.
AssignField
AssignIndex
elem_ty is carried so codegen picks the boxing path without re-walking
the receiver’s Type.
NarrowRegion
Wraps then/else blocks and switch case bodies. path is for diagnostics; codegen
consults only source, cast_info, binding, and body.