shape_vm/compiler/mod.rs
1//! Bytecode compiler - translates AST to bytecode
2
3use shape_ast::error::{Result, ShapeError, SourceLocation};
4use std::collections::{HashMap, HashSet};
5use std::sync::Arc;
6
7use crate::blob_cache_v2::BlobCache;
8/// Borrow mode for reference parameters - Shared (&) or Exclusive (&mut).
9/// Kept for codegen even though the lexical borrow checker has been removed.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum BorrowMode {
12 Shared,
13 Exclusive,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub(crate) enum ExprResultMode {
18 Value,
19 PreserveRef,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
23pub(crate) struct ExprReferenceResult {
24 pub raw_mode: Option<BorrowMode>,
25 pub auto_deref_mode: Option<BorrowMode>,
26}
27
28/// A borrow place key used for encoding borrow targets in codegen.
29pub type BorrowPlace = u32;
30use crate::bytecode::{
31 BuiltinFunction, BytecodeProgram, Constant, FunctionBlob, FunctionHash, Instruction, OpCode,
32 Operand, Program as ContentAddressedProgram,
33};
34use crate::type_tracking::{TypeTracker, VariableTypeInfo};
35use shape_ast::ast::{FunctionDef, Program, Span, TypeAnnotation};
36use shape_runtime::type_schema::SchemaId;
37use shape_runtime::type_system::{
38 Type, TypeAnalysisMode, TypeError, TypeErrorWithLocation, analyze_program_with_mode,
39 checking::MethodTable,
40};
41
42// Sub-modules
43pub(crate) mod comptime;
44pub(crate) mod comptime_builtins;
45pub(crate) mod comptime_concrete;
46pub(crate) mod comptime_target;
47mod control_flow;
48mod expressions;
49mod functions;
50mod functions_annotations;
51mod functions_foreign;
52mod helpers;
53mod helpers_binding;
54mod helpers_reference;
55mod literals;
56mod loops;
57pub(crate) mod mir_schema_threading;
58pub(crate) mod monomorphization;
59mod patterns;
60pub(crate) mod post_inference_verify;
61mod statements;
62pub mod string_interpolation;
63mod trait_object_emission;
64
65/// Loop compilation context
66pub(crate) struct LoopContext {
67 /// Break jump targets
68 pub(crate) break_jumps: Vec<usize>,
69 /// Continue jump target (usize::MAX = deferred, use continue_jumps)
70 pub(crate) continue_target: usize,
71 /// Optional local to store break values for expression loops
72 pub(crate) break_value_local: Option<u16>,
73 /// Whether a for-in iterator is on the stack (break must pop it)
74 pub(crate) iterator_on_stack: bool,
75 /// Drop scope depth when the loop was entered (for break/continue early exit drops)
76 pub(crate) drop_scope_depth: usize,
77 /// Forward-patched continue jumps for range counter loops where the
78 /// increment block is after the body (so continue must forward-jump).
79 pub(crate) continue_jumps: Vec<usize>,
80}
81
82/// Information about an imported symbol (fields used for diagnostics/LSP)
83#[derive(Debug, Clone)]
84#[allow(dead_code)]
85pub(crate) struct ImportedSymbol {
86 /// Original name in the source module
87 pub original_name: String,
88 /// Module path the symbol was imported from
89 pub module_path: String,
90 /// High-level kind of the imported symbol (function, type, etc.)
91 /// `None` for legacy inlining path where kind is not tracked.
92 pub kind: Option<shape_ast::module_utils::ModuleExportKind>,
93}
94
95/// Imported annotation binding routed through a hidden synthetic module.
96#[derive(Debug, Clone)]
97pub(crate) struct ImportedAnnotationSymbol {
98 /// Original annotation name in the source module.
99 pub original_name: String,
100 /// Source module path the annotation was imported from.
101 pub _module_path: String,
102 /// Hidden synthetic module name that owns the compiled annotation scope.
103 pub hidden_module_name: String,
104}
105
106/// Module-scoped builtin function declaration with a runtime source module.
107#[derive(Debug, Clone)]
108pub(crate) struct ModuleBuiltinFunction {
109 /// The callable name as exported by the runtime/native module.
110 pub export_name: String,
111 /// Original source module path that provides the runtime implementation.
112 pub source_module_path: String,
113}
114
115/// Compiler-internal scope taxonomy for name resolution.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[allow(dead_code)]
118pub(crate) enum ResolutionScope {
119 Local,
120 ModuleBinding,
121 NamedImport,
122 NamespaceImport,
123 TypeAssociated,
124 Prelude,
125 SyntaxReserved,
126 InternalIntrinsic,
127}
128
129impl ResolutionScope {
130 pub(crate) const fn label(self) -> &'static str {
131 match self {
132 Self::Local => "local scope",
133 Self::ModuleBinding => "module scope",
134 Self::NamedImport => "named import scope",
135 Self::NamespaceImport => "namespace import scope",
136 Self::TypeAssociated => "type-associated scope",
137 Self::Prelude => "implicit prelude scope",
138 Self::SyntaxReserved => "syntax-reserved scope",
139 Self::InternalIntrinsic => "internal intrinsic scope",
140 }
141 }
142}
143
144/// Builtin lookup result annotated with the scope class it currently belongs to.
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub(crate) enum BuiltinNameResolution {
147 Surface {
148 builtin: BuiltinFunction,
149 scope: ResolutionScope,
150 },
151 InternalOnly {
152 builtin: BuiltinFunction,
153 scope: ResolutionScope,
154 },
155}
156
157impl BuiltinNameResolution {
158 pub(crate) const fn scope(self) -> ResolutionScope {
159 match self {
160 Self::Surface { scope, .. } | Self::InternalOnly { scope, .. } => scope,
161 }
162 }
163}
164
165#[derive(Debug, Clone)]
166pub(crate) struct StructGenericInfo {
167 pub type_params: Vec<shape_ast::ast::TypeParam>,
168 pub runtime_field_types: HashMap<String, shape_ast::ast::TypeAnnotation>,
169}
170
171/// Whether a type's Drop impl is sync-only, async-only, or both.
172#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub(crate) enum DropKind {
174 SyncOnly,
175 AsyncOnly,
176 Both,
177}
178
179/// Canonical compile-time parameter passing contract.
180///
181/// This is the single source of truth used by compiler lowering and LSP rendering.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183pub enum ParamPassMode {
184 ByValue,
185 ByRefShared,
186 ByRefExclusive,
187}
188
189impl ParamPassMode {
190 pub const fn is_reference(self) -> bool {
191 !matches!(self, Self::ByValue)
192 }
193
194 pub const fn is_exclusive(self) -> bool {
195 matches!(self, Self::ByRefExclusive)
196 }
197}
198
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub(crate) struct FunctionReturnReferenceSummary {
201 pub param_index: usize,
202 pub mode: BorrowMode,
203 pub projection: Option<Vec<crate::mir::types::ProjectionStep>>,
204}
205
206impl From<crate::mir::analysis::ReturnReferenceSummary> for FunctionReturnReferenceSummary {
207 fn from(value: crate::mir::analysis::ReturnReferenceSummary) -> Self {
208 Self {
209 param_index: value.param_index,
210 mode: match value.kind {
211 crate::mir::types::BorrowKind::Shared => BorrowMode::Shared,
212 crate::mir::types::BorrowKind::Exclusive => BorrowMode::Exclusive,
213 },
214 projection: value.projection,
215 }
216 }
217}
218
219/// Per-function blob builder for content-addressed compilation.
220///
221/// Uses a **snapshot** strategy: records the global instruction/constant/string
222/// pool sizes at the start of function compilation, then at finalization
223/// extracts the delta and remaps global indices to blob-local indices.
224pub(crate) struct FunctionBlobBuilder {
225 /// Function name.
226 pub name: String,
227 /// Global instruction index where this function's code starts.
228 pub instr_start: usize,
229 /// Global constant pool size when this function started compiling.
230 #[allow(dead_code)]
231 pub const_start: usize,
232 /// Global string pool size when this function started compiling.
233 #[allow(dead_code)]
234 pub string_start: usize,
235 /// Names of functions called by this function (for dependency tracking).
236 pub called_functions: Vec<String>,
237 /// Type schema names this function constructs.
238 pub type_schemas: Vec<String>,
239 /// Accumulated permissions required by this function's direct calls.
240 pub required_permissions: shape_abi_v1::PermissionSet,
241}
242
243impl FunctionBlobBuilder {
244 pub fn new(name: String, instr_start: usize, const_start: usize, string_start: usize) -> Self {
245 Self {
246 name,
247 instr_start,
248 const_start,
249 string_start,
250 called_functions: Vec::new(),
251 type_schemas: Vec::new(),
252 required_permissions: shape_abi_v1::PermissionSet::pure(),
253 }
254 }
255
256 /// Record that this function calls another function by name.
257 pub fn record_call(&mut self, callee_name: &str) {
258 if !self.called_functions.iter().any(|n| n == callee_name) {
259 self.called_functions.push(callee_name.to_owned());
260 }
261 }
262
263 /// Record that this function requires the given permissions
264 /// (e.g., from a stdlib module call identified by capability_tags).
265 pub fn record_permissions(&mut self, perms: &shape_abi_v1::PermissionSet) {
266 self.required_permissions = self.required_permissions.union(perms);
267 }
268
269 /// Finalize this builder into a FunctionBlob by extracting the delta from
270 /// the global program pools and remapping indices to blob-local ones.
271 pub fn finalize(
272 &self,
273 program: &crate::bytecode::BytecodeProgram,
274 func: &crate::bytecode::Function,
275 blob_name_to_hash: &HashMap<String, FunctionHash>,
276 instr_end: usize,
277 ) -> FunctionBlob {
278 use crate::bytecode::Operand;
279
280 // Extract global-indexed instructions for this function.
281 let global_instructions = &program.instructions[self.instr_start..instr_end];
282
283 // Build constant remap: global index -> local index.
284 let mut const_remap: HashMap<u16, u16> = HashMap::new();
285 let mut local_constants: Vec<Constant> = Vec::new();
286 // Build string remap similarly.
287 let mut string_remap: HashMap<u16, u16> = HashMap::new();
288 let mut local_strings: Vec<String> = Vec::new();
289 // Build function operand remap: global function index -> dependency-local index.
290 let mut func_remap: HashMap<u16, u16> = HashMap::new();
291 // Start from explicitly recorded call dependencies, then augment with
292 // function-value references found in constants/operands.
293 let mut called_functions = self.called_functions.clone();
294
295 let mut ensure_called = |callee_name: &str| -> u16 {
296 if let Some(dep_idx) = called_functions.iter().position(|n| n == callee_name) {
297 dep_idx as u16
298 } else {
299 called_functions.push(callee_name.to_owned());
300 (called_functions.len() - 1) as u16
301 }
302 };
303
304 // Scan instructions for all constant/string references and build
305 // blob-local pools with remapped indices.
306 for instr in global_instructions {
307 if let Some(ref operand) = instr.operand {
308 match operand {
309 Operand::Const(idx) => {
310 if !const_remap.contains_key(idx) {
311 let local_idx = local_constants.len() as u16;
312 const_remap.insert(*idx, local_idx);
313 let mut constant = program.constants[*idx as usize].clone();
314 if let Constant::Function(fid) = constant {
315 let global_idx = fid as usize;
316 if let Some(callee) = program.functions.get(global_idx) {
317 let dep_idx = ensure_called(&callee.name);
318 constant = Constant::Function(dep_idx);
319 }
320 }
321 local_constants.push(constant);
322 }
323 }
324 Operand::Property(idx) => {
325 if !string_remap.contains_key(idx) {
326 let local_idx = local_strings.len() as u16;
327 string_remap.insert(*idx, local_idx);
328 local_strings.push(program.strings[*idx as usize].clone());
329 }
330 }
331 Operand::Name(sid) => {
332 let gidx = sid.0 as u16;
333 if !string_remap.contains_key(&gidx) {
334 let local_idx = local_strings.len() as u16;
335 string_remap.insert(gidx, local_idx);
336 local_strings.push(program.strings[gidx as usize].clone());
337 }
338 }
339 Operand::TypedMethodCall { string_id, .. } => {
340 let gidx = *string_id;
341 if !string_remap.contains_key(&gidx) {
342 let local_idx = local_strings.len() as u16;
343 string_remap.insert(gidx, local_idx);
344 local_strings.push(program.strings[gidx as usize].clone());
345 }
346 }
347 Operand::Function(fid) => {
348 let global_idx = fid.0 as usize;
349 if !func_remap.contains_key(&fid.0) {
350 // Map global function index -> dependency-local index.
351 // If this call target was not explicitly recorded (e.g. emitted via
352 // function-valued constants), add it so content-addressed linking can
353 // remap stable function IDs correctly.
354 if let Some(callee) = program.functions.get(global_idx) {
355 let dep_idx = ensure_called(&callee.name);
356 func_remap.insert(fid.0, dep_idx);
357 }
358 }
359 }
360 // Closure spec H5: `MakeClosure` now carries the function id
361 // (plus the escape flag) in a `ClosureAlloc` operand when the
362 // closure escapes. Treat it exactly like `Operand::Function`
363 // for dependency tracking — the content-addressed blob must
364 // record the closure's compiled body as a dependency.
365 Operand::ClosureAlloc { fid, .. } => {
366 let global_idx = fid.0 as usize;
367 if !func_remap.contains_key(&fid.0) {
368 if let Some(callee) = program.functions.get(global_idx) {
369 let dep_idx = ensure_called(&callee.name);
370 func_remap.insert(fid.0, dep_idx);
371 }
372 }
373 }
374 _ => {}
375 }
376 }
377 }
378
379 // Remap instructions to use local indices.
380 let local_instructions: Vec<Instruction> = global_instructions
381 .iter()
382 .map(|instr| {
383 let mut remapped = instr.clone();
384 if let Some(operand) = &mut remapped.operand {
385 match operand {
386 Operand::Const(idx) => {
387 if let Some(&local) = const_remap.get(idx) {
388 *idx = local;
389 }
390 }
391 Operand::Property(idx) => {
392 if let Some(&local) = string_remap.get(idx) {
393 *idx = local;
394 }
395 }
396 Operand::Name(sid) => {
397 if let Some(&local) = string_remap.get(&(sid.0 as u16)) {
398 sid.0 = local as u32;
399 }
400 }
401 Operand::TypedMethodCall { string_id, .. } => {
402 if let Some(&local) = string_remap.get(string_id) {
403 *string_id = local;
404 }
405 }
406 Operand::Function(fid) => {
407 if let Some(&local) = func_remap.get(&fid.0) {
408 fid.0 = local;
409 }
410 }
411 // Closure spec H5: parallel remap for `ClosureAlloc`.
412 Operand::ClosureAlloc { fid, .. } => {
413 if let Some(&local) = func_remap.get(&fid.0) {
414 fid.0 = local;
415 }
416 }
417 _ => {}
418 }
419 }
420 remapped
421 })
422 .collect();
423
424 // Build dependency list from called function names.
425 // Use FunctionHash::ZERO as sentinel for forward references (not yet compiled).
426 let dependencies: Vec<FunctionHash> = called_functions
427 .iter()
428 .map(|callee| {
429 blob_name_to_hash
430 .get(callee)
431 .copied()
432 .unwrap_or(FunctionHash::ZERO)
433 })
434 .collect();
435
436 // Build source map from global debug info.
437 let source_map: Vec<(usize, u32, u32)> = program
438 .debug_info
439 .line_numbers
440 .iter()
441 .filter(|(idx, _, _)| *idx >= self.instr_start && *idx < instr_end)
442 .map(|(idx, fid, line)| (idx - self.instr_start, *fid as u32, *line))
443 .collect();
444
445 // Scan instructions for CallForeign operands and collect content hashes
446 // from the program's foreign_functions table.
447 let mut foreign_deps: Vec<[u8; 32]> = Vec::new();
448 for instr in &local_instructions {
449 if instr.opcode == crate::bytecode::OpCode::CallForeign {
450 if let Some(Operand::ForeignFunction(idx)) = instr.operand {
451 if let Some(entry) = program.foreign_functions.get(idx as usize) {
452 if let Some(hash) = entry.content_hash {
453 foreign_deps.push(hash);
454 }
455 }
456 }
457 }
458 }
459 foreign_deps.sort();
460 foreign_deps.dedup();
461
462 let mut blob = FunctionBlob {
463 content_hash: FunctionHash::ZERO,
464 name: self.name.clone(),
465 arity: func.arity,
466 param_names: func.param_names.clone(),
467 locals_count: func.locals_count,
468 is_closure: func.is_closure,
469 captures_count: func.captures_count,
470 is_async: func.is_async,
471 ref_params: func.ref_params.clone(),
472 ref_mutates: func.ref_mutates.clone(),
473 mutable_captures: func.mutable_captures.clone(),
474 frame_descriptor: func.frame_descriptor.clone(),
475 required_permissions: self.required_permissions.clone(),
476 instructions: local_instructions,
477 constants: local_constants,
478 strings: local_strings,
479 dependencies,
480 callee_names: called_functions,
481 type_schemas: self.type_schemas.clone(),
482 foreign_dependencies: foreign_deps,
483 source_map,
484 };
485 blob.finalize();
486 blob
487 }
488}
489
490#[derive(Debug, Clone, Copy, PartialEq, Eq)]
491pub enum TypeDiagnosticMode {
492 ReliableOnly,
493 Strict,
494 RecoverAll,
495}
496
497#[derive(Debug, Clone, Copy, PartialEq, Eq)]
498pub enum CompileDiagnosticMode {
499 FailFast,
500 RecoverAll,
501}
502
503/// cluster-2-cw-IB-class-b (2026-05-16, supervisor R3 binding-ratified):
504/// retained closure-literal peek used to re-run body return-type
505/// inference at the value-call site with caller-context arg type hints.
506/// Stored per-local-slot in `BytecodeCompiler.local_callable_closure_bodies`
507/// at let-binding time (`update_callable_binding_from_expr` /
508/// `FunctionExpr` arm). The body is the AST `Vec<Statement>` clone — no
509/// bytecode-lowering happens at lookup time; the inference walker only
510/// inspects AST shape.
511#[derive(Debug, Clone)]
512pub struct ClosureBodyPeek {
513 /// Formal parameters of the closure literal (`|inner|` →
514 /// `[FunctionParameter { pattern: Identifier("inner"), .. }]`).
515 pub params: Vec<shape_ast::ast::FunctionParameter>,
516 /// Closure literal body statements.
517 pub body: Vec<shape_ast::ast::Statement>,
518 /// Explicit `-> T` return annotation, if any.
519 pub return_type: Option<shape_ast::ast::TypeAnnotation>,
520 /// Compiled-function index assigned to the closure body by
521 /// `compile_expr_closure`. `None` until the closure literal is
522 /// actually lowered (the peek is built from the AST; the function
523 /// index is assigned at compile-emission time). Used by the value-
524 /// call propagation path to retroactively patch
525 /// `mir.local_typed_array_element_types` for the closure body's
526 /// MIR-side typed-array param seed.
527 pub function_index: Option<usize>,
528}
529
530/// Phase 4b Round 6 WS-1b W16.2-C residual (2026-05-21) — identifies the
531/// binding slot that holds a bare empty-array accumulator awaiting a
532/// downstream-`.push()`-resolved element kind.
533///
534/// A `let mut out = []` either lands in a function-body local slot or a
535/// top-level module binding; both are keyed by their `u16` index. The push
536/// site (`compile_expr_method_call`) resolves the receiver to the same key,
537/// patches the placeholder allocator, and promotes the binding.
538#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
539pub(crate) enum EmptyArrayAccumulatorKey {
540 /// Function-body local slot index.
541 Local(u16),
542 /// Top-level module-binding index.
543 ModuleBinding(u16),
544}
545
546/// Phase 4b Round 6 WS-1b W16.2-C residual — a pending bare empty-array
547/// accumulator. Carries the placeholder `NewArray(0)` instruction index so
548/// the first `.push()` (or the end-of-compilation finalizer) can patch it.
549#[derive(Debug, Clone)]
550pub(crate) struct EmptyArrayAccumulator {
551 /// Instruction index of the placeholder `OpCode::NewArray` emitted at the
552 /// empty-array literal site. Patched in-place to `kind.new_opcode()` once
553 /// the element kind is proven.
554 pub alloc_instr_idx: usize,
555 /// Source location of the empty-array literal — used for the clean
556 /// "element type un-resolvable" diagnostic if no push ever resolves it.
557 pub literal_loc: Option<SourceLocation>,
558 /// The accumulator variable's source name (for diagnostics).
559 pub var_name: String,
560}
561
562/// Compiler state
563pub struct BytecodeCompiler {
564 /// The program being built
565 pub(crate) program: BytecodeProgram,
566
567 /// Current function being compiled
568 pub(crate) current_function: Option<usize>,
569
570 /// Local variable mappings (name -> index)
571 pub(crate) locals: Vec<HashMap<String, u16>>,
572
573 /// ModuleBinding variable mappings (name -> index)
574 pub(crate) module_bindings: HashMap<String, u16>,
575
576 /// Next local variable index
577 pub(crate) next_local: u16,
578
579 /// Next module_binding variable index
580 pub(crate) next_global: u16,
581
582 /// Loop context stack for break/continue
583 pub(crate) loop_stack: Vec<LoopContext>,
584
585 /// Counter for synthetic closure function names
586 pub(crate) closure_counter: u64,
587
588 /// Closure function indices discovered during bytecode compilation of the
589 /// current function. Each entry is (closure_function_name, function_index).
590 /// Used to back-patch MIR ClosurePlaceholder/ClosureCapture after compilation.
591 pub(crate) closure_function_ids: Vec<(String, u16)>,
592
593 /// Registry of closure capture layouts (v2 closure specialization Phase A).
594 ///
595 /// Keyed on capture signature (`Vec<ConcreteType>`): two closures with
596 /// identical capture signatures share a `ClosureTypeId`. Phase C will
597 /// consume this to extend the monomorphization cache key.
598 pub(crate) closure_registry: shape_value::v2::closure_layout::ClosureRegistry,
599
600 /// Mapping from closure function index to its `ClosureTypeId`.
601 /// Populated alongside `closure_function_ids` as each closure literal is
602 /// lowered. Phase C reads this to key monomorphization on the closure type.
603 pub(crate) closure_type_ids: Vec<(u16, shape_value::v2::concrete_type::ClosureTypeId)>,
604
605 /// Track A.1C — per-closure `CaptureKind` vector, one entry per capture
606 /// in declaration order. Populated alongside `closure_type_ids` so that
607 /// `compiler_impl_reference_model::build_closure_function_layouts` can
608 /// construct the per-function `ClosureLayout` with the correct
609 /// `CaptureKind` per capture (rather than defaulting to the
610 /// `ClosureRegistry::intern`'d all-`Immutable` shape). A missing entry
611 /// (closure registered via the legacy path, e.g. test helpers) falls
612 /// back to all-`Immutable`, matching the pre-A.1C layout.
613 pub(crate) closure_capture_kinds: Vec<(u16, Vec<shape_value::v2::closure_layout::CaptureKind>)>,
614
615 /// Registry of `Function<A, R>` signatures (v2 closure specialization
616 /// Phase F). `FunctionTypeId`s assigned here are written into
617 /// `TypedClosureHeader.type_id` in the JIT path and consumed by
618 /// `CallFunctionIndirect` to pick a Cranelift `call_indirect` signature.
619 pub(crate) function_type_registry:
620 shape_value::v2::function_type_registry::FunctionTypeRegistry,
621
622 /// Mapping from closure function index to the `FunctionTypeId` of its
623 /// callable signature (params + return). Populated alongside
624 /// `closure_type_ids` when a closure literal is lowered. The JIT reads
625 /// this to emit the per-`ClosureTypeId` direct-call signature and the
626 /// polymorphic `CallFunctionIndirect` signature.
627 pub(crate) function_type_ids: Vec<(u16, shape_value::v2::concrete_type::FunctionTypeId)>,
628
629 /// Phase F one-shot: if set, the next closure-literal emission uses
630 /// `MakeClosureHeap` instead of the legacy `MakeClosure`. The flag is
631 /// consumed (reset to false) as soon as `compile_expr_closure`
632 /// finishes emitting the opcode. Callers that want to force the heap
633 /// ABI (e.g. the return-statement compiler when the returned value is
634 /// a closure literal) set this right before lowering the closure.
635 pub(crate) emit_make_closure_heap_next: bool,
636
637 /// Wave E+5-cleanup task #108 side-channel: native-kind hint for
638 /// `GetProp` emit sites where the producer-flip in `op_get_prop`
639 /// pushes raw native bits (I64 / Timestamp / F64 / Bool field tags
640 /// against non-heap slots). Keyed by emitted-instruction index;
641 /// consumed by `last_emitted_native_kind`'s `GetProp` arm so the
642 /// host-boundary synthesizer re-tags raw bits per the recorded
643 /// kind. `GetProp` is `Instruction::simple` (no operand) so neither
644 /// operand-decode nor walk-back recovers the field tag — the
645 /// compiler must record the resolved kind at the emit site
646 /// (`compile_expr_property_access`).
647 pub(crate) get_prop_native_kinds: HashMap<usize, crate::type_tracking::StorageHint>,
648
649 /// When compiling a DataTable closure method (e.g. dt.filter(row => ...)),
650 /// this holds the (schema_id, type_name) to tag the closure's row parameter as RowView.
651 pub(crate) closure_row_schema: Option<(u32, String)>,
652
653 /// Strict-typing-sweep (Cluster 3): bidirectional closure inference for
654 /// HOF method calls. When the next compiled closure literal is the
655 /// argument to `arr.map(|x| …)` / `.filter` / `.reduce` / etc., the
656 /// outer `compile_expr_method_call` resolves the receiver's element
657 /// type and stashes per-user-param `TypeAnnotation` hints here. The
658 /// closure compile reads these hints and attaches them to params with
659 /// no explicit annotation, then clears the field. The vector indexes
660 /// USER params only (excludes synthesized capture-params).
661 pub(crate) pending_closure_param_types: Option<Vec<Option<shape_ast::ast::TypeAnnotation>>>,
662
663 /// Unified type metadata for the last compiled expression.
664 ///
665 /// This is the single source for relational/value kind propagation
666 /// (Table<T>, Indexed<T>, known object schema, etc.).
667 pub(crate) last_expr_type_info: Option<VariableTypeInfo>,
668
669 /// Type tracker for optimized field access
670 pub(crate) type_tracker: TypeTracker,
671
672 /// Schema ID of the last compiled expression (if it's a TypedObject).
673 /// Used for compile-time typed merge optimization.
674 pub(crate) last_expr_schema: Option<SchemaId>,
675
676 /// Numeric type of the last compiled expression (for typed opcode emission).
677 /// Set by literal compilation, variable loads, and other expression compilers.
678 /// Read by binary op compilation to emit typed opcodes (e.g., MulInt).
679 pub(crate) last_expr_numeric_type: Option<crate::type_tracking::NumericType>,
680
681 /// E+5.5 Unit C step 2: captured top-level program return-kind, snapshotted
682 /// right after the last item compiles (before drop-scope emission and
683 /// Halt overwrite `last_expr_*`). Consumed by
684 /// `populate_program_storage_hints` to populate
685 /// `top_level_frame.return_kind` so the host boundary reads the kind
686 /// off the parallel-kind track (per ADR-006 §2.7.7 — the deleted
687 /// ValueWord-tagged synthesis is gone).
688 ///
689 /// Per ADR-006 §2.7.5.1 (compiler-tier intermediate state policy),
690 /// "kind not yet stamped" is carried as `Option<StorageHint>` —
691 /// `None` is the post-bulldozer replacement for the deleted
692 /// `StorageHint::Unknown` sentinel.
693 pub(crate) top_level_program_return_kind: Option<crate::type_tracking::StorageHint>,
694
695 /// Result mode for the expression currently being compiled.
696 pub(crate) current_expr_result_mode: ExprResultMode,
697
698 /// Whether the last compiled expression left a raw reference on the stack.
699 ///
700 /// `auto_deref_mode` is only set for propagated ref results (identifier loads,
701 /// ref-returning calls) that should implicitly dereference in value contexts.
702 /// Explicit `&expr` results keep `raw_mode` without enabling auto-deref.
703 pub(crate) last_expr_reference_result: ExprReferenceResult,
704
705 /// Known pass modes for local callable bindings (closures / function aliases).
706 pub(crate) local_callable_pass_modes: HashMap<u16, Vec<ParamPassMode>>,
707
708 /// Known safe return-reference summaries for local callable bindings.
709 pub(crate) local_callable_return_reference_summaries:
710 HashMap<u16, FunctionReturnReferenceSummary>,
711
712 /// Known pass modes for module-binding callable values.
713 pub(crate) module_binding_callable_pass_modes: HashMap<u16, Vec<ParamPassMode>>,
714
715 /// Known safe return-reference summaries for module-binding callable values.
716 pub(crate) module_binding_callable_return_reference_summaries:
717 HashMap<u16, FunctionReturnReferenceSummary>,
718
719 /// Sweep phase 3c.1: inferred return-type names for closures stored in
720 /// local slots. Populated when `update_callable_binding_from_expr`
721 /// observes a `FunctionExpr` initializer; consumed by `infer_expr_type`
722 /// so a `FunctionCall { name: f, .. }` against `let f = |…| body` can
723 /// recover the body's return type for strict-typing binop dispatch.
724 pub(crate) local_callable_return_types: HashMap<u16, String>,
725
726 /// Sweep phase 3c.1: inferred return-type names for closures stored in
727 /// module-binding slots (top-level / REPL `let f = |…|` style).
728 pub(crate) module_binding_callable_return_types: HashMap<u16, String>,
729
730 /// Sweep phase 3c.x: inferred return-type names for arrays whose elements
731 /// are closure literals with a homogeneous return type. Keyed by the
732 /// local slot holding the array. Consumed by `infer_expr_type` for the
733 /// `arr[i](args...)` callsite (which the parser models as
734 /// `MethodCall { method: "__call__", receiver: IndexAccess { .. } }`).
735 /// Without this lookup, `arr[0](1) + arr[1](1)` fails strict-typing as
736 /// `unknown + unknown`.
737 pub(crate) local_array_callable_return_types: HashMap<u16, String>,
738
739 /// Sweep phase 3c.x: inferred return-type names for arrays of closures
740 /// stored in module-binding slots (top-level `let arr = [|x| ..., ...]`).
741 pub(crate) module_binding_array_callable_return_types: HashMap<u16, String>,
742
743 /// cluster-2-cw-IB-class-b (2026-05-16, supervisor R3 binding-
744 /// ratified): retained closure-literal body for local `let f = |..|
745 /// ..` bindings. Populated at let-binding time by
746 /// `update_callable_binding_from_expr`'s `FunctionExpr` arm;
747 /// consumed at `compile_expr_function_call`'s value-call branch when
748 /// re-running closure-body return-type inference with caller-context
749 /// arg types.
750 ///
751 /// The retained body is the AST `Vec<Statement>` clone (no lowering
752 /// occurs at lookup time — the inference walker only inspects AST
753 /// shape, never emits bytecode for the body). Released on
754 /// `clear_callable_binding` and on per-function compilation
755 /// snapshot/restore alongside the existing `local_callable_*`
756 /// maps (`functions.rs:1148-1151` / `:1496-1499` / `:1607-1608`).
757 ///
758 /// Memory cost: bounded by the number of local closure bindings in
759 /// the active function frame; the body is the same AST already held
760 /// by the parent `Statement::VariableDecl` initializer, just held
761 /// for the lifetime of the enclosing function-compile pass to avoid
762 /// re-walking the AST at every value-call site. Released when the
763 /// enclosing function compile completes.
764 pub(crate) local_callable_closure_bodies:
765 HashMap<u16, ClosureBodyPeek>,
766
767 /// cluster-2-cw-IB-class-b: module-binding variant of the closure
768 /// body peek. Covers top-level / REPL `let f = |..|` bindings whose
769 /// slots live in the module-binding space (not the local-slot
770 /// space). Populated/cleared alongside the existing
771 /// `module_binding_callable_return_types` map at the
772 /// `update_callable_binding_from_expr` `FunctionExpr` arm.
773 pub(crate) module_binding_callable_closure_bodies:
774 HashMap<u16, ClosureBodyPeek>,
775
776 /// ADR-006 §2.7.24 Q25.C trait-object emission (Wave 2.6 round-2):
777 /// per-local-slot trait name for `let a: dyn Animal = ...` bindings.
778 /// Consumed by `compile_expr_method_call` (`expressions/function_calls.rs`)
779 /// to route method dispatch through `OpCode::DynMethodCall` instead
780 /// of the standard `OpCode::CallMethod` path. Empty for non-dyn
781 /// locals.
782 pub(crate) dyn_locals: HashMap<u16, String>,
783
784 /// ADR-006 §2.7.24 Q25.C trait-object emission: per-module-binding
785 /// trait name for top-level `let a: dyn Animal = ...` declarations.
786 /// Same role as `dyn_locals` but for the module-binding slot space.
787 pub(crate) dyn_module_bindings: HashMap<u16, String>,
788
789 /// Named functions that safely return one reference parameter unchanged.
790 pub(crate) function_return_reference_summaries: HashMap<String, FunctionReturnReferenceSummary>,
791
792 /// The return-reference summary of the function currently being compiled, if any.
793 pub(crate) current_function_return_reference_summary: Option<FunctionReturnReferenceSummary>,
794
795 /// Type inference engine for match exhaustiveness and type checking
796 pub(crate) type_inference: shape_runtime::type_system::inference::TypeInferenceEngine,
797
798 /// Track type aliases defined in the program
799 /// Maps alias name -> target type (for type validation)
800 pub(crate) type_aliases: HashMap<String, String>,
801
802 /// Current source line being compiled (for debug info)
803 pub(crate) current_line: u32,
804
805 /// Current source file ID (for multi-file debug info)
806 pub(crate) current_file_id: u16,
807
808 /// Source text (for error messages)
809 pub(crate) source_text: Option<String>,
810
811 /// Source lines (split from source_text for quick access)
812 pub(crate) source_lines: Vec<String>,
813
814 /// Imported symbols: local_name -> ImportedSymbol
815 pub(crate) imported_names: HashMap<String, ImportedSymbol>,
816 /// Imported annotations: local_name -> ImportedAnnotationSymbol
817 pub(crate) imported_annotations: HashMap<String, ImportedAnnotationSymbol>,
818 /// R8 W8 Cluster A (2026-05-24): imported `pub const NAME = expr`
819 /// initializers, keyed by the local binding name (alias-respecting).
820 /// At identifier-load time, references to these names compile to an
821 /// inlined `PushConst(<comptime-value>)` rather than a
822 /// `LoadModuleBinding` — the dispatch's "use the existing
823 /// comptime-evaluated-constant mechanism (the `Constant` pool); NOT a
824 /// new opcode, NOT a deferred init runtime computation" binding.
825 /// ADR-006 §2.7.5 stamp-at-compile-time invariant preserved: the
826 /// constant's kind is stamped from the literal's shape at compile time.
827 pub(crate) imported_consts: HashMap<String, shape_ast::ast::Expr>,
828 /// Qualified builtin function declarations available as module-scoped callables.
829 pub(crate) module_builtin_functions: HashMap<String, ModuleBuiltinFunction>,
830 /// Module namespace bindings introduced by `use module.path`.
831 /// Used to avoid UFCS rewrites for module calls like `duckdb.connect(...)`.
832 pub(crate) module_namespace_bindings: HashSet<String>,
833 /// Imported synthetic/local module path -> original source module path.
834 /// Used when code inside a wrapper module needs to dispatch to native exports
835 /// from the underlying source module.
836 pub(crate) module_scope_sources: HashMap<String, String>,
837 /// Active lexical module scope stack while compiling `mod Name { ... }`.
838 pub(crate) module_scope_stack: Vec<String>,
839
840 /// Known exports for import suggestions: function_name -> module_path
841 /// Used to provide helpful error messages like "Did you mean to import from...?"
842 pub(crate) known_exports: HashMap<String, String>,
843 /// Function arity bounds keyed by function name: (required_params, total_params).
844 /// Required params are non-default parameters. Defaults are only allowed
845 /// in trailing positions.
846 pub(crate) function_arity_bounds: HashMap<String, (usize, usize)>,
847 /// Function const parameter indices keyed by function name.
848 /// Const parameters must receive compile-time constant arguments at call sites.
849 pub(crate) function_const_params: HashMap<String, Vec<usize>>,
850 /// Original function definitions keyed by function name.
851 /// Used for const-template specialization at call sites.
852 pub(crate) function_defs: HashMap<String, FunctionDef>,
853 /// Foreign function definitions keyed by function name.
854 /// Used to resolve the effective (Result-wrapped) return type at call sites.
855 pub(crate) foreign_function_defs: HashMap<String, shape_ast::ast::ForeignFunctionDef>,
856 /// Sweep phase 3c.x: per-(enum, variant) struct-variant field
857 /// annotations. The schema-level `EnumVariantInfo` only carries field
858 /// counts (`payload_fields`) and uses `__payload_N` field names with
859 /// `FieldType::Any`, so the named-field types of `enum E { V { x: int,
860 /// y: int } }` are otherwise lost at pattern compile time. Populated
861 /// by `register_enum`; consumed by `compile_typed_enum_binding` (struct
862 /// arm) so `match m::E::V { x, y } => x + y` propagates int onto x and
863 /// y.
864 pub(crate) enum_struct_variant_fields:
865 HashMap<(String, String), Vec<(String, shape_ast::ast::TypeAnnotation)>>,
866 /// R8 W7: per-(enum, variant) tuple-payload positional type
867 /// annotations. Symmetric to `enum_struct_variant_fields` for
868 /// tuple variants. The runtime schema collapses tuple payloads
869 /// into `__payload_N: Any`, so per-position types of
870 /// `enum E { V(string) }` are otherwise lost at pattern-compile
871 /// time. Populated by `register_enum`; consumed by
872 /// `compile_typed_enum_binding` (tuple arm) so `match E::V(id) =>
873 /// id + "!"` propagates `string` onto `id`.
874 pub(crate) enum_tuple_variant_fields:
875 HashMap<(String, String), Vec<shape_ast::ast::TypeAnnotation>>,
876 /// Cached const specializations keyed by `(base_name + const-arg fingerprint)`.
877 pub(crate) const_specializations: HashMap<String, usize>,
878 /// Monotonic counter for unique specialization symbol names.
879 pub(crate) next_const_specialization_id: u64,
880 /// Const-parameter bindings for specialized function symbols.
881 /// These bindings are exposed to comptime handlers as typed module_bindings.
882 /// Kinded carrier per ADR-006 §2.7 / Q7 (`KindedSlot`); the prior
883 /// `shape_value::ValueWord` shape was deleted by the strict-typing
884 /// bulldozer and the comptime ABI in
885 /// `compiler/comptime.rs:execute_comptime_with_annotation_handler`
886 /// already migrated to `(String, KindedSlot)` pairs.
887 pub(crate) specialization_const_bindings:
888 HashMap<String, Vec<(String, shape_value::KindedSlot)>>,
889
890 /// Struct type definitions: type_name -> (field_names in order, definition span)
891 pub(crate) struct_types: HashMap<String, (Vec<String>, shape_ast::ast::Span)>,
892 /// Generic metadata for struct types used to instantiate runtime type names
893 /// (e.g. `MyType<number>`) at struct-literal construction sites.
894 pub(crate) struct_generic_info: HashMap<String, StructGenericInfo>,
895 /// Names of `type C` declarations with native layout metadata.
896 pub(crate) native_layout_types: HashSet<String>,
897 /// Generated conversion pair cache keys: `c_type::object_type`.
898 pub(crate) generated_native_conversion_pairs: HashSet<String>,
899
900 /// Whether the current function being compiled is async
901 pub(crate) current_function_is_async: bool,
902
903 /// Directory of the source file being compiled (for resolving relative source paths)
904 pub(crate) source_dir: Option<std::path::PathBuf>,
905
906 /// Collected compilation errors (for multi-error reporting)
907 pub(crate) errors: Vec<shape_ast::error::ShapeError>,
908
909 /// Hoisted fields from optimistic hoisting pre-pass.
910 /// Maps variable name → list of property names assigned later (e.g., a.y = 2 → "a" → ["y"]).
911 /// Used to include future property assignments in inline object schemas at compile time.
912 pub(crate) hoisted_fields: HashMap<String, Vec<String>>,
913
914 /// Phase 3e: inferred FieldType for hoisted fields, when the assigned
915 /// RHS is a simple literal whose primitive type is statically known.
916 /// Maps variable name → property name → inferred FieldType.
917 ///
918 /// Used by `compile_typed_object_literal` to register the schema with
919 /// concrete primitive types (I64, F64, Bool, String) instead of falling
920 /// back to FieldType::Any. Without this, `let mut a = { x: 10 }; a.y =
921 /// 20; a.x + a.y` types `a.y` as Any in the schema, so the binary-op
922 /// numeric path declines and trait dispatch fires (which has no runtime
923 /// handler for `int.add`).
924 pub(crate) hoisted_field_types:
925 HashMap<String, HashMap<String, shape_runtime::type_schema::FieldType>>,
926
927 /// When compiling a variable initializer, the name of the variable being assigned to.
928 /// Used by compile_typed_object_literal to include hoisted fields in the schema.
929 pub(crate) pending_variable_name: Option<String>,
930
931 /// v2 Phase 3.1: when the enclosing `let arr: Array<T> = [...]` declares
932 /// an explicit `Array<T>` annotation whose element type maps to a
933 /// [`v2_typed_emission::TypedArrayKind`], stash the kind here so
934 /// `compile_expr_array` can lower the literal to a v2 typed-array
935 /// allocation. The statement-binding code path resets this to `None`
936 /// before each new initializer.
937 pub(crate) pending_variable_typed_array_kind:
938 Option<crate::compiler::v2_typed_emission::TypedArrayKind>,
939
940 /// R5.4B: nested-array-literal depth.
941 ///
942 /// Incremented while `compile_expr_array` compiles the elements of an
943 /// array literal, decremented after. When `> 0`, the compiler is inside
944 /// a nested array-literal context (e.g. the inner `[1.0, 2.0]` of
945 /// `[[1.0, 2.0], [3.0, 4.0]]`) and MUST refuse the typed-array fast
946 /// path (`NewTypedArrayF64`/etc.) regardless of annotation or
947 /// inference.
948 ///
949 /// Why: the v2 typed-array opcodes store the allocation as a raw
950 /// native pointer on the kinded VM stack with
951 /// `NativeKind::Ptr(HeapKind::TypedArray)` declared on the parallel-
952 /// kind track (ADR-006 §2.7.7), not as a generic heap-tagged value.
953 /// Downstream consumers that expect a generic `Array` via
954 /// `slot.as_heap_value()` cannot decode a typed-array native pointer
955 /// back into a generic Array (the deleted `as_heap_ref()` /
956 /// `as_any_array()` carrier accessors are gone), so e.g.
957 /// `intrinsic_matmul_mat` fails with "row 0 must be an array of
958 /// numeric values". Refusing typed emission for inner rows forces
959 /// them onto the legacy `NewArray` path, which produces a generic
960 /// `HeapValue::Array` that round-trips correctly through a generic
961 /// outer `Array`.
962 pub(crate) nested_array_literal_depth: u32,
963
964 /// v2 Phase 3.1: per-local-slot record of which locals hold a v2
965 /// typed array (allocated via `NewTypedArrayF64/I64/I32/Bool` rather
966 /// than the legacy v1 `NewTypedArray`/`NewArray`). Populated by the
967 /// statement-binding code path when an `Array<T>` annotation
968 /// successfully picks a typed kind. Consumed by
969 /// `resolve_receiver_typed_array_kind` so the typed Get/Set/Push/Len
970 /// opcodes are only emitted for receivers that were ALSO allocated
971 /// as v2 typed arrays — never for legacy NaN-boxed arrays.
972 pub(crate) v2_typed_array_locals:
973 HashMap<u16, crate::compiler::v2_typed_emission::TypedArrayKind>,
974 /// v2 Phase 3.1: per-module-binding record of v2 typed arrays.
975 /// Mirrors [`v2_typed_array_locals`] for top-level bindings.
976 pub(crate) v2_typed_array_module_bindings:
977 HashMap<u16, crate::compiler::v2_typed_emission::TypedArrayKind>,
978
979 /// Phase 4b Round 6 WS-1 W16.2-C (2026-05-21) — list-comprehension
980 /// element-kind capture.
981 ///
982 /// `compile_list_comprehension` emits the result accumulator's
983 /// `NewTypedArray*` allocator BEFORE the comprehension body is compiled,
984 /// but the element-expression's proven scalar kind is only known AFTER
985 /// the body compiles. `compile_comprehension_clauses` writes the proven
986 /// [`TypedArrayKind`] here at the innermost (clause-empty) base case,
987 /// reading the bytecode compiler's `last_expr_numeric_type` /
988 /// `last_expr_type_info` right after the element expression compiles —
989 /// per ADR-006 §2.7.5 the kind is proven at the producer site, never
990 /// fabricated. `compile_list_comprehension` then patches the recorded
991 /// allocator instruction with the matching typed opcode. `None` means
992 /// the element kind was not statically provable — a clean compile error.
993 pub(crate) comprehension_element_kind:
994 Option<crate::compiler::v2_typed_emission::TypedArrayKind>,
995
996 /// Phase 4b Round 6 WS-1 W16.2-C (2026-05-21) — instruction indices of
997 /// the placeholder `ArrayPush` opcodes emitted at list-comprehension
998 /// element-push sites. `compile_comprehension_clauses` records each
999 /// base-case push here; `compile_list_comprehension` patches them all
1000 /// to the resolved `TypedArrayPush*` opcode once the element kind is
1001 /// known — so the typed accumulator receives a typed push that the JIT
1002 /// and VM both dispatch unambiguously (no generic-carrier path).
1003 pub(crate) comprehension_push_sites: Vec<usize>,
1004
1005 /// Phase 4b Round 6 WS-1b W16.2-C residual (2026-05-21) — bare
1006 /// empty-array accumulator deferred-kind capture.
1007 ///
1008 /// A bare `let mut out = []` (empty array literal, no `Array<T>`
1009 /// annotation, no elements) cannot resolve its `TypedArrayKind` at the
1010 /// literal site — the element type is determined only by downstream
1011 /// `out.push(x)` calls. `compile_expr_array` emits a placeholder
1012 /// `NewArray(0)` and records its instruction index here against the
1013 /// binding (local slot or module binding). The FIRST `arr.push(v)` on
1014 /// that binding resolves the element kind from the compiled argument's
1015 /// proven type (ADR-006 §2.7.5 producer-side stamp — read from the
1016 /// type-tracker at the push site, never decoded from runtime bits, never
1017 /// Bool-defaulted), patches the placeholder to the matching typed
1018 /// `NewTypedArray*` allocator, and promotes the binding into
1019 /// `v2_typed_array_locals` / `v2_typed_array_module_bindings` so every
1020 /// subsequent push is a typed `TypedArrayPush*`. A bare empty array that
1021 /// is never pushed to and never annotated has a genuinely un-resolvable
1022 /// element type — `finalize_unresolved_empty_array_accumulators`
1023 /// surface-and-stops with a clean structured compile error.
1024 pub(crate) empty_array_accumulators: HashMap<EmptyArrayAccumulatorKey, EmptyArrayAccumulator>,
1025
1026 /// Phase 4b Round 6 WS-1b — instruction index of the placeholder
1027 /// `NewArray(0)` emitted by the most recent `compile_expr_array` call for
1028 /// a bare empty array literal. The enclosing `Statement::VariableDecl` /
1029 /// `Item::VariableDecl` reads this immediately after the initializer
1030 /// compiles and re-keys it into [`empty_array_accumulators`] against the
1031 /// resolved binding. `None` when the last array literal was non-empty,
1032 /// annotated, or otherwise resolved a kind directly.
1033 pub(crate) pending_empty_array_alloc_idx: Option<usize>,
1034
1035 /// v2 Phase 3.2: when the enclosing `let m: HashMap<K, V> = HashMap()`
1036 /// declares an explicit `HashMap<K, V>` annotation whose key/value pair
1037 /// maps to a [`v2_typed_map_emission::TypedMapKind`], stash the kind here
1038 /// so `compile_expr_function_call` (HashMap ctor path) can lower the
1039 /// allocation to a v2 typed-map opcode. The statement-binding code path
1040 /// resets this to `None` before each new initializer.
1041 pub(crate) pending_variable_typed_map_kind:
1042 Option<crate::compiler::v2_typed_map_emission::TypedMapKind>,
1043
1044 /// v2 Phase 3.2: per-local-slot record of which locals hold a v2 typed
1045 /// HashMap (allocated via `NewTypedMap*` rather than the legacy
1046 /// `BuiltinCall(HashMapCtor)`). Populated by the statement-binding code
1047 /// path. Consumed by HashMap method dispatch (`m.set/.get/.has/.delete`)
1048 /// so the typed Set/Get/Has/Delete opcodes are only emitted for receivers
1049 /// that were ALSO allocated as v2 typed maps — never for legacy NaN-boxed
1050 /// HashMapData.
1051 pub(crate) v2_typed_map_locals:
1052 HashMap<u16, crate::compiler::v2_typed_map_emission::TypedMapKind>,
1053
1054 /// v2 Phase 3.2: per-module-binding record of v2 typed maps. Mirrors
1055 /// [`v2_typed_map_locals`] for top-level bindings.
1056 pub(crate) v2_typed_map_module_bindings:
1057 HashMap<u16, crate::compiler::v2_typed_map_emission::TypedMapKind>,
1058
1059 /// ADR-006 §2.7.27 / Item 4 ruling (W17-mutation-writeback, 2026-05-12):
1060 /// per-local-slot record of locals known to hold a Copy-on-Write
1061 /// collection (HashSet / HashMap / Deque / PriorityQueue / Array of
1062 /// generic carrier). Populated at let-binding time when the initializer
1063 /// is one of `Set()` / `HashMap()` / `Deque()` / `PriorityQueue()` /
1064 /// `[…]`, or when the binding has an explicit type annotation that
1065 /// names the container kind.
1066 ///
1067 /// Consumed by `compile_expr_method_call`'s `&mut self` writeback
1068 /// emission gate: for an identifier-receiver method call where
1069 /// `(container_kind, method_name)` matches a `MUT_SELF_*` entry, the
1070 /// compiler emits `Dup; StoreLocal recv` after `CallMethod` so the
1071 /// new (possibly Arc-cloned) receiver Arc updates the binding slot.
1072 pub(crate) mut_self_container_locals:
1073 HashMap<u16, crate::compiler::mutation_writeback::ContainerKind>,
1074
1075 /// ADR-006 §2.7.27 / Item 4 ruling: per-module-binding record of
1076 /// mutating-container module bindings. Mirrors
1077 /// [`mut_self_container_locals`] for top-level bindings.
1078 pub(crate) mut_self_container_bindings:
1079 HashMap<u16, crate::compiler::mutation_writeback::ContainerKind>,
1080
1081 /// ADR-006 §2.7.27 / Item 4 ruling: signal raised by container-ctor
1082 /// builtin call emitters (`SetCtor`, `DequeCtor`,
1083 /// `PriorityQueueCtor`, `HashMapCtor`) so the surrounding statement-
1084 /// binding code path can transfer the kind onto the target local
1085 /// / module binding. Mirrors the existing
1086 /// [`pending_variable_typed_array_kind`] convention.
1087 pub(crate) pending_variable_container_kind:
1088 Option<crate::compiler::mutation_writeback::ContainerKind>,
1089
1090 /// v2 Phase 3.2: per-AST-node side table mapping a HashMap-shaped
1091 /// expression to its key/value `ConcreteType` pair. Populated by the
1092 /// `let m: HashMap<K, V> = ...` annotation path AND by inference helpers
1093 /// (`infer_hashmap_kv_from_context`).
1094 pub(crate) map_key_value_types: HashMap<
1095 shape_ast::ast::Span,
1096 (shape_value::v2::ConcreteType, shape_value::v2::ConcreteType),
1097 >,
1098
1099 /// v2 Phase 3.2: per-local-slot side table for HashMap key/value pairs.
1100 pub(crate) local_map_key_value_types:
1101 HashMap<u16, (shape_value::v2::ConcreteType, shape_value::v2::ConcreteType)>,
1102
1103 /// v2 Phase 3.2: per-module-binding side table for HashMap key/value pairs.
1104 pub(crate) module_binding_map_key_value_types:
1105 HashMap<u16, (shape_value::v2::ConcreteType, shape_value::v2::ConcreteType)>,
1106
1107 /// v2 Phase 3.2: per-AST-span array element type table — used by
1108 /// monomorphization helpers and methods that produce arrays from maps.
1109 pub(crate) array_element_types: HashMap<shape_ast::ast::Span, shape_value::v2::ConcreteType>,
1110
1111 /// v2 Phase 3.2: per-local-slot array element type table.
1112 pub(crate) local_array_element_types: HashMap<u16, shape_value::v2::ConcreteType>,
1113
1114 /// v2 Phase 3.2: per-module-binding array element type table.
1115 pub(crate) module_binding_array_element_types: HashMap<u16, shape_value::v2::ConcreteType>,
1116 /// Lexical names that will later need their binding value to remain a raw reference.
1117 /// This is only used to choose `Value` vs `PreserveRef` lowering for bindings; MIR
1118 /// remains the sole authority for borrow legality.
1119 pub(crate) future_reference_use_name_scopes: Vec<HashSet<String>>,
1120
1121 /// Known trait names (populated in the first pass so meta definitions can reference traits)
1122 pub(crate) known_traits: std::collections::HashSet<String>,
1123
1124 /// Full trait definitions keyed by trait name.
1125 /// Used to install default method implementations for impl blocks that omit them.
1126 pub(crate) trait_defs: HashMap<String, shape_ast::ast::types::TraitDef>,
1127
1128 /// J-CT.2 (2026-05-23) — comptime impl blocks deferred for in-mini-VM
1129 /// registration. The outer compiler does NOT desugar/register/compile
1130 /// methods of `comptime impl Trait for Type { ... }` blocks into the
1131 /// runtime program; they are skipped from runtime processing and stored
1132 /// here so the comptime-evaluator mini-VM (`execute_comptime` in
1133 /// `compiler/comptime.rs`) can prepend them as `Item::Impl` items, where
1134 /// the in-comptime-mode compiler then desugars + compiles them normally.
1135 /// Method dispatch from `instance.method()` inside a `comptime { }` block
1136 /// then routes through the standard UFCS / `Type::method` resolution
1137 /// path without a new dispatch shape (audit §2.D carve-out).
1138 pub(crate) comptime_impl_blocks: Vec<shape_ast::ast::types::ImplBlock>,
1139
1140 /// J-CT.2 (2026-05-23) — original struct definitions captured during
1141 /// the first pass. The outer compiler only retains field NAMES in
1142 /// `struct_types`; the comptime-evaluator mini-VM needs full AST
1143 /// (typed annotations, generic info, annotations) to compile
1144 /// struct-literal constructions and field accesses inside `comptime { }`
1145 /// blocks that interact with `comptime_impl_blocks`. Populated in the
1146 /// first-pass `Item::StructType` arm.
1147 pub(crate) comptime_context_struct_defs:
1148 HashMap<String, shape_ast::ast::types::StructTypeDef>,
1149
1150 /// Extension registry for comptime execution
1151 pub(crate) extension_registry: Option<Arc<Vec<shape_runtime::module_exports::ModuleExports>>>,
1152
1153 /// Comptime field values per type: type_name -> (field_name -> bake-time
1154 /// constant). These are type-level constants baked at compile time
1155 /// with zero runtime cost. Inner map releases heap-backed comptime
1156 /// values (strings via `Arc<String>`, etc.) when a type's entry is
1157 /// removed or the compiler is dropped.
1158 ///
1159 /// Kinded carrier per ADR-006 §2.7 / Q7 (`KindedSlot`); the prior
1160 /// `shape_value::ValueMap` shape was deleted by the strict-typing
1161 /// bulldozer along with `ValueWord`. Mirrors the
1162 /// `comptime_builtins::ComptimeDirective::SetParamValue { value:
1163 /// KindedSlot }` migration already landed in
1164 /// `compiler/comptime_builtins.rs`.
1165 pub(crate) comptime_fields:
1166 HashMap<String, HashMap<String, shape_value::KindedSlot>>,
1167 /// Type diagnostic mode for shared analyzer diagnostics.
1168 pub(crate) type_diagnostic_mode: TypeDiagnosticMode,
1169 /// Expression compilation diagnostic mode.
1170 pub(crate) compile_diagnostic_mode: CompileDiagnosticMode,
1171 /// Whether this compiler instance is compiling code for comptime execution.
1172 /// Enables comptime-only builtins and comptime-specific statement semantics.
1173 pub(crate) comptime_mode: bool,
1174 /// Functions removed by comptime annotation handlers (`remove target`).
1175 /// These are still present in `program.functions` (registered in the first pass)
1176 /// but must produce a clear compile-time error when called instead of jumping
1177 /// to an invalid entry point.
1178 pub(crate) removed_functions: HashSet<String>,
1179 /// Internal guard for compiler-synthesized `__comptime__` helper calls.
1180 /// User source must never access `__comptime__` directly.
1181 pub(crate) allow_internal_comptime_namespace: bool,
1182 /// Method table for data-driven method signature queries.
1183 /// Used to replace hardcoded heuristics (e.g., is_type_preserving_table_method)
1184 /// with MethodTable lookups (is_self_returning, takes_closure_with_receiver_param).
1185 pub(crate) method_table: MethodTable,
1186 /// Locals that are reference-typed in the current function.
1187 pub(crate) ref_locals: HashSet<u16>,
1188 /// Subset of ref_locals that hold exclusive (`&mut`) borrows.
1189 /// Used to enforce the three concurrency rules at task boundaries.
1190 pub(crate) exclusive_ref_locals: HashSet<u16>,
1191 /// Subset of ref_locals that were INFERRED as by-reference (not explicitly declared `&`).
1192 /// Inferred-ref params are owned values passed by reference for performance;
1193 /// closures may capture them (the value is dereferenced at capture time).
1194 pub(crate) inferred_ref_locals: HashSet<u16>,
1195 /// Locals whose binding value is itself a first-class reference (`let r = &x`).
1196 /// Reads auto-deref; writes still rebind the local.
1197 pub(crate) reference_value_locals: HashSet<u16>,
1198 /// Subset of reference_value_locals that hold exclusive (`&mut`) references.
1199 pub(crate) exclusive_reference_value_locals: HashSet<u16>,
1200 /// Local variable indices declared as `const` (immutable binding).
1201 pub(crate) const_locals: HashSet<u16>,
1202 /// Module binding indices declared as `const` (immutable binding).
1203 pub(crate) const_module_bindings: HashSet<u16>,
1204 /// Local variable indices declared as immutable `let` (not `let mut` or `var`).
1205 pub(crate) immutable_locals: HashSet<u16>,
1206 /// Local variable indices that are function parameters (first N locals in a function).
1207 /// Used to avoid trusting inferred type hints for params with no explicit annotation.
1208 pub(crate) param_locals: HashSet<u16>,
1209 /// Module binding indices declared as immutable `let`.
1210 pub(crate) immutable_module_bindings: HashSet<u16>,
1211 /// Module bindings whose value is itself a first-class reference.
1212 pub(crate) reference_value_module_bindings: HashSet<u16>,
1213 /// Subset of reference_value_module_bindings that hold exclusive (`&mut`) references.
1214 pub(crate) exclusive_reference_value_module_bindings: HashSet<u16>,
1215 /// ModuleBinding-ref writebacks collected while compiling current call args.
1216 pub(crate) call_arg_module_binding_ref_writebacks: Vec<Vec<(u16, u16)>>,
1217 /// Inferred reference parameters for untyped params: function -> per-param flag.
1218 pub(crate) inferred_ref_params: HashMap<String, Vec<bool>>,
1219 /// Inferred mutating-reference params: function -> per-param flag.
1220 pub(crate) inferred_ref_mutates: HashMap<String, Vec<bool>>,
1221 /// Effective per-parameter pass mode (explicit + inferred), by function name.
1222 pub(crate) inferred_param_pass_modes: HashMap<String, Vec<ParamPassMode>>,
1223 /// Inferred parameter type hints for unannotated params.
1224 /// Keyed by function name; each entry is a per-param optional type string.
1225 pub(crate) inferred_param_type_hints: HashMap<String, Vec<Option<String>>>,
1226 /// v0.3 WS-7: inference-resolved per-parameter `ConcreteType` for
1227 /// UNANNOTATED params. Keyed by function name; each entry is a per-param
1228 /// optional `ConcreteType` projected from the program-wide type-inference
1229 /// engine's result. Annotated params keep `None` here (their
1230 /// `ConcreteType` is stamped directly from the annotation in the
1231 /// `function_local_concrete_types` per-fn seeding pass). This is the
1232 /// proof source that lets the JIT take the v2 typed-array fast path for
1233 /// `fn get(xs, i) { xs[i] }`-style unannotated array parameters — without
1234 /// it the slot stays `ConcreteType::Void`, the JIT mis-classifies the v2
1235 /// `TypedArray` pointer as a NaN-boxed v1 array, and the inline index
1236 /// load reads garbage / SIGSEGVs.
1237 pub(crate) inferred_param_concrete_types:
1238 HashMap<String, Vec<Option<shape_value::v2::ConcreteType>>>,
1239 /// WS-9b: inference-resolved per-parameter ANONYMOUS-OBJECT field
1240 /// definitions for UNANNOTATED params. Keyed by function name; each
1241 /// entry is a per-param optional `Vec<(field_name, FieldType)>`.
1242 ///
1243 /// A *named* struct parameter (`type Box`) resolves through the schema
1244 /// registry — `set_local_type_info` already stamps its `schema_id` from
1245 /// the `"Box"` hint name. But an *anonymous* object parameter (the shape
1246 /// `fn aabb(...) { { min_x: ..., ... } }` produces) has no named schema:
1247 /// its inference hint is the structural string `"{min_x: number, ...}"`,
1248 /// which matches no registered schema. `compile_function_body` consumes
1249 /// this map to register an inline `__inline_obj_*` schema for such a
1250 /// parameter and stamp the slot's `schema_id`, so `param.field` resolves
1251 /// to the proven field type the same way a named-struct field does. The
1252 /// field types are projected from inference's resolved param `Type` —
1253 /// proven, never fabricated; an unresolved field yields `None`.
1254 pub(crate) inferred_param_object_fields: HashMap<
1255 String,
1256 Vec<Option<Vec<(String, shape_runtime::type_schema::FieldType)>>>,
1257 >,
1258 /// WS-9c: per-function inferred RETURN type projected to a
1259 /// `Vec<(field_name, FieldType)>` when that return type is an anonymous
1260 /// structural object (an unannotated object-literal factory such as
1261 /// `fn aabb(lo, hi) { {min: lo, max: hi} }`). `compile_expr_function_call`
1262 /// consumes this to register an inline anonymous schema for the call's
1263 /// result so `aabb(...).field` / `let a = aabb(...); a.field` resolves to
1264 /// the proven field type — the same resolution a named-struct return type
1265 /// already receives. Only unannotated functions appear here (annotated
1266 /// returns resolve through the annotation path). Field types are projected
1267 /// from inference's resolved return `Type` — proven, never fabricated.
1268 pub(crate) inferred_return_object_fields:
1269 HashMap<String, Vec<(String, shape_runtime::type_schema::FieldType)>>,
1270 /// WS-9c: function name → registered inline anonymous schema id for an
1271 /// unannotated function whose inferred return type is an anonymous
1272 /// object. Populated once, up-front, by
1273 /// `register_inferred_return_object_schemas`. Consulted by
1274 /// `compile_expr_function_call` (to stamp `last_expr_schema`) and by the
1275 /// read-only `infer_expr_type` property-access path (to resolve
1276 /// `f(...).field` directly, with no `let` binding).
1277 pub(crate) function_return_schema_ids: HashMap<String, u32>,
1278 /// Stack of scopes, each containing locals that need Drop calls at scope exit.
1279 /// Each entry is (local_index, is_async).
1280 pub(crate) drop_locals: Vec<Vec<(u16, bool)>>,
1281 /// Phase V1.1C: parallel scope stack tracking locals whose storage class
1282 /// is `UniqueHeap` and therefore (when the ownership-moves flag is on)
1283 /// need an ownership-aware `DropLocal` opcode emitted at scope exit to
1284 /// release the owned heap allocation. Orthogonal to `drop_locals` (which
1285 /// drives user-facing `Drop` trait calls via `DropCall`). Populated and
1286 /// consumed only when `ownership_moves_enabled()` is true; otherwise the
1287 /// scope stack is pushed/popped in lockstep with `drop_locals` but kept
1288 /// empty, so the compiler's emission path is byte-identical to
1289 /// pre-V1.1C.
1290 pub(crate) ownership_drop_locals: Vec<Vec<u16>>,
1291 /// Per-type drop kind: tracks whether each type has sync, async, or both drop impls.
1292 /// Populated during the first-pass registration of impl blocks.
1293 pub(crate) drop_type_info: HashMap<String, DropKind>,
1294 /// Module bindings that need Drop calls at program exit.
1295 /// Each entry is (binding_index, is_async).
1296 pub(crate) drop_module_bindings: Vec<(u16, bool)>,
1297 /// Mutable closure captures in the current function being compiled.
1298 /// Maps captured variable name -> upvalue index (for LoadClosure/StoreClosure).
1299 /// Only populated while compiling a closure body that has mutable captures.
1300 pub(crate) mutable_closure_captures: HashMap<String, u16>,
1301
1302 /// Track A.1C.2: subset of `mutable_closure_captures` whose source
1303 /// binding classifies as `CaptureKind::Shared` (a `var` binding
1304 /// mutably captured through a closure). Maps captured variable name
1305 /// → capture index. When the identifier lookup finds a name in this
1306 /// map, the closure body emits `LoadSharedCapture` /
1307 /// `StoreSharedCapture` (A.1B) instead of the legacy `LoadClosure`
1308 /// / `StoreClosure`. Populated while compiling a closure body.
1309 pub(crate) shared_closure_captures: HashMap<String, u16>,
1310
1311 /// Track A.1C.2b: subset of `mutable_closure_captures` whose source
1312 /// binding classifies as `CaptureKind::OwnedMutable` (a `let mut`
1313 /// binding captured by move into a single closure). Maps captured
1314 /// variable name → capture index. When the identifier lookup finds
1315 /// a name in this map, the closure body emits
1316 /// `LoadOwnedMutableCapture` / `StoreOwnedMutableCapture` (A.1B)
1317 /// instead of the legacy `LoadClosure` / `StoreClosure`. Populated
1318 /// while compiling a closure body.
1319 pub(crate) owned_mutable_closure_captures: HashMap<String, u16>,
1320
1321 /// Wave E: parallel to `owned_mutable_closure_captures`, records
1322 /// the interior `FieldKind` of each OwnedMutable capture cell. The
1323 /// inner kind is derived from the captured binding's resolved
1324 /// `ConcreteType` (`concrete_type_for_expr → ConcreteType::to_field_kind`)
1325 /// at the point of closure construction. The closure body uses
1326 /// this map to dispatch to the typed Wave D.1 opcodes
1327 /// (`LoadOwnedMutableCapture<Kind>` / `StoreOwnedMutableCapture<Kind>`,
1328 /// codes 0x140-0x155) instead of the legacy untyped `0x132`/`0x133`
1329 /// opcodes (kind-erased pre-strict-typing — ADR-006 §2.7.7).
1330 /// Populated alongside `owned_mutable_closure_captures`,
1331 /// saved/restored across nested closure-body compilations.
1332 pub(crate) owned_mutable_capture_inner_kinds:
1333 HashMap<String, shape_value::v2::struct_layout::FieldKind>,
1334
1335 /// A2-refined / task #17: parallel to `shared_closure_captures`,
1336 /// records the interior `FieldKind` of each Shared (`var`) capture
1337 /// cell. Derived from the captured binding's resolved `ConcreteType`
1338 /// at closure-construction time, mirroring
1339 /// `owned_mutable_capture_inner_kinds`. The closure body uses this
1340 /// map to dispatch to the typed Wave D.2 opcodes
1341 /// (`LoadSharedCapture<Kind>` / `StoreSharedCapture<Kind>`, codes
1342 /// 0x156-0x16B) instead of the legacy untyped `0x134`/`0x135`
1343 /// opcodes (kind-erased pre-strict-typing — ADR-006 §2.7.7).
1344 /// Saved/restored across nested closure-body compilations.
1345 pub(crate) shared_capture_inner_kinds:
1346 HashMap<String, shape_value::v2::struct_layout::FieldKind>,
1347
1348 /// Variables in the current scope that have been boxed into SharedCells
1349 /// by a mutable closure capture. When a subsequent closure captures one
1350 /// of these variables (even immutably), it must use the SharedCell path
1351 /// so it shares the same mutable cell.
1352 pub(crate) boxed_locals: HashSet<String>,
1353
1354 /// Track A.1C.2: local slots that have been promoted to
1355 /// `Arc<parking_lot::Mutex<u64>>` via the `AllocSharedLocal`
1356 /// opcode (with the matching `NativeKind` declared on the cell's
1357 /// parallel-kind track per ADR-006 §2.7.8). After promotion, every
1358 /// outer-scope read/write of the slot
1359 /// must go through `LoadSharedLocal` / `StoreSharedLocal` (never plain
1360 /// `LoadLocal` / `StoreLocal`), and scope exit must emit
1361 /// `DropSharedLocal` so the Arc strong count is released exactly once
1362 /// per owning frame.
1363 ///
1364 /// Keyed by the binding *name* (mirroring `boxed_locals`). Populated
1365 /// by `compile_expr_closure` when a `var` capture escapes into a
1366 /// closure and gets classified as `CaptureKind::Shared`.
1367 pub(crate) shared_locals: HashSet<String>,
1368
1369 /// Track A.1C.3: local names that have been classified as
1370 /// `CaptureKind::OwnedMutable` by at least one closure in the
1371 /// current function scope. Needed because `binding_semantics_for_name`
1372 /// can return `None` after an inner closure's `compile_function`
1373 /// wipes the type-tracker local semantics, and we need the
1374 /// classification to be stable across sibling closures (otherwise
1375 /// a second closure capturing a different `let mut` local could
1376 /// fall back to `Immutable`, nulling the layout's OwnedMutable mask
1377 /// bit and triggering a layout mismatch in `op_make_closure`).
1378 pub(crate) owned_mutable_locals: HashSet<String>,
1379
1380 /// Session 1 (Rust-move semantics for `let mut`): names of `let mut`
1381 /// local bindings that have been **moved by value into a closure
1382 /// capture** (i.e. classified as `CaptureKind::OwnedMutable` and
1383 /// emitted at `op_make_closure` time as `Box::into_raw(Box::new(bits))`).
1384 /// After the move, the outer slot holds only a stale snapshot of the
1385 /// initial value — every subsequent outer-scope read or write of the
1386 /// same binding is a compile error ("use-after-move").
1387 ///
1388 /// Stored as `name → span-of-the-capturing-closure` so the diagnostic
1389 /// can point the user at the exact capture site that consumed the
1390 /// binding. Populated in `compile_expr_closure`, consulted in
1391 /// `compile_expr_identifier` and `compile_expr_assign`. Saved /
1392 /// restored across nested `compile_function` calls, mirroring the
1393 /// `shared_locals` / `owned_mutable_locals` discipline.
1394 pub(crate) captured_let_mut_moved: HashMap<String, Span>,
1395
1396 /// Track A.1C.3: module-binding slots that have been promoted to
1397 /// `Arc<parking_lot::Mutex<u64>>` via `AllocSharedModuleBinding`
1398 /// (with the matching `NativeKind` declared on the cell's
1399 /// parallel-kind track per ADR-006 §2.7.8).
1400 /// After promotion, every outer-scope read/write of the binding must
1401 /// go through `LoadSharedModuleBinding` / `StoreSharedModuleBinding`
1402 /// (never plain `LoadModuleBinding` / `StoreModuleBinding`). Keyed
1403 /// by the binding's **scoped name** — the same key used by
1404 /// `resolve_scoped_module_binding_name` and the `module_bindings`
1405 /// index map. Populated by `compile_expr_closure` when a
1406 /// module-scope `var` is captured mutably.
1407 pub(crate) shared_module_bindings: HashSet<String>,
1408
1409 /// Track A.1C.2: per-scope stack of slot indices that need a
1410 /// `DropSharedLocal` opcode at scope exit, mirroring the
1411 /// `ownership_drop_locals` discipline. Push in lockstep with
1412 /// `push_drop_scope`; pop and emit in lockstep with `pop_drop_scope`.
1413 pub(crate) shared_drop_locals: Vec<Vec<u16>>,
1414
1415 /// Active permission set for capability checking.
1416 ///
1417 /// When set, imported stdlib functions are checked against capability_tags.
1418 /// If a function requires a permission not in this set, a compile error is
1419 /// emitted and the function never enters bytecode.
1420 ///
1421 /// `None` means no checking (backwards-compatible default).
1422 pub(crate) permission_set: Option<shape_abi_v1::PermissionSet>,
1423
1424 // -- Content-addressed blob tracking --
1425 /// Active blob builder (set while compiling a function body).
1426 pub(crate) current_blob_builder: Option<FunctionBlobBuilder>,
1427 /// Completed function blobs (finalized with content hash).
1428 pub(crate) completed_blobs: Vec<FunctionBlob>,
1429 /// Map from function name to content hash (populated after finalization).
1430 pub(crate) blob_name_to_hash: HashMap<String, FunctionHash>,
1431 /// The content-addressed program produced alongside BytecodeProgram.
1432 pub(crate) content_addressed_program: Option<ContentAddressedProgram>,
1433 /// Content hash per compiled function index (function_id -> blob hash).
1434 /// This is the stable identity bridge for the flat runtime format.
1435 pub(crate) function_hashes_by_id: Vec<Option<FunctionHash>>,
1436
1437 /// Optional blob-level cache for incremental compilation.
1438 /// When set, compiled blobs are stored after finalization and looked up
1439 /// by content hash to avoid redundant work across compilations.
1440 pub(crate) blob_cache: Option<BlobCache>,
1441
1442 /// Temporary function name aliases for comptime replace body.
1443 /// Maps alias (e.g., `__original__`) to actual function name (e.g., `__original__myFunc`).
1444 /// Set before compiling a replacement body and cleared after.
1445 pub(crate) function_aliases: HashMap<String, String>,
1446
1447 /// Parameters of the function currently being compiled.
1448 /// Used by match exhaustiveness checking to fall back to type annotations
1449 /// when the type inference engine cannot resolve a parameter's type.
1450 pub(crate) current_function_params: Vec<shape_ast::ast::FunctionParameter>,
1451
1452 /// Legacy cache of function names collected from stdlib-loaded modules.
1453 ///
1454 /// Internal builtin access is now gated by per-definition declaring-module
1455 /// provenance, not by membership in this set.
1456 pub stdlib_function_names: HashSet<String>,
1457
1458 /// Per-function flag: when true, `get_builtin_function` resolves `__*` names.
1459 /// Toggled during compilation for definitions originating from `std::*`.
1460 pub(crate) allow_internal_builtins: bool,
1461
1462 /// Package-scoped native library resolutions for the current host.
1463 pub(crate) native_resolution_context:
1464 Option<shape_runtime::native_resolution::NativeResolutionSet>,
1465
1466 /// Active synthetic MIR context while compiling non-function code.
1467 pub(crate) non_function_mir_context_stack: Vec<String>,
1468
1469 /// MIR lowered for compiled functions and synthetic non-function contexts.
1470 pub(crate) mir_functions: HashMap<String, crate::mir::types::MirFunction>,
1471
1472 /// Borrow analyses produced from lowered MIR for compiled functions and
1473 /// synthetic non-function contexts.
1474 pub(crate) mir_borrow_analyses: HashMap<String, crate::mir::BorrowAnalysis>,
1475
1476 /// Storage plans produced by the storage planning pass for each function.
1477 /// Maps function name to the plan mapping each MIR slot to a `BindingStorageClass`.
1478 pub(crate) mir_storage_plans: HashMap<String, crate::mir::StoragePlan>,
1479
1480 /// Per-function borrow summaries for interprocedural alias checking.
1481 /// Describes which parameters conflict and must not alias at call sites.
1482 pub(crate) function_borrow_summaries: HashMap<String, crate::mir::FunctionBorrowSummary>,
1483
1484 /// Per-function mapping from AST spans to MIR program points.
1485 /// Used to bridge the bytecode compiler (which knows AST spans) to
1486 /// MIR ownership decisions (which are keyed by `Point`).
1487 pub(crate) mir_span_to_point:
1488 HashMap<String, HashMap<shape_ast::ast::Span, crate::mir::types::Point>>,
1489
1490 /// Field-level definite-initialization and liveness analyses for compiled functions.
1491 pub(crate) mir_field_analyses: HashMap<String, crate::mir::FieldAnalysis>,
1492
1493 /// Graph-compiled namespace map: local namespace name -> canonical module path.
1494 /// Populated during graph-driven compilation to resolve qualified names.
1495 pub(crate) graph_namespace_map: HashMap<String, String>,
1496
1497 /// Module dependency graph (set during graph-driven compilation).
1498 pub(crate) module_graph: Option<std::sync::Arc<crate::module_graph::ModuleGraph>>,
1499
1500 /// Per-local-slot concrete type table for the function currently being compiled.
1501 pub(crate) current_function_local_concrete_types: HashMap<u16, shape_value::v2::ConcreteType>,
1502
1503 /// v0.3 WS-6 — per-module-binding concrete type table, populated at
1504 /// let-binding time from the binding's explicit `TypeAnnotation`.
1505 ///
1506 /// Consumed by the monomorphization call-site resolver
1507 /// (`identifier_concrete_type`) so a generic free-function call whose
1508 /// argument is a variable with an explicit struct / enum / `Option<T>` /
1509 /// `Result<T, E>` / `HashMap<K, V>` annotation can bind its type
1510 /// parameter — `let n: Option<int> = ...; id(n)`. The array / map
1511 /// element side-tables (`module_binding_array_element_types`,
1512 /// `module_binding_map_key_value_types`) already cover the
1513 /// container-element cases; this table covers the remaining
1514 /// fully-annotated shapes.
1515 pub(crate) module_binding_concrete_types: HashMap<u16, shape_value::v2::ConcreteType>,
1516
1517 /// Monomorphization cache for generic function specialization.
1518 pub(crate) monomorphization_cache: monomorphization::cache::MonomorphizationCache,
1519
1520 /// BUG3 — cycle detector for generic method / free-function monomorphization.
1521 ///
1522 /// Holds the set of `mono_key`s whose specialization is currently being
1523 /// compiled further down the call stack. If `ensure_monomorphic_function`
1524 /// is (re-)entered for a key that is already in-progress, it means the
1525 /// specialized body is transitively trying to resolve itself before its
1526 /// own `compile_function` has finished — without the guard this would
1527 /// overflow the compiler stack or cache the wrong index. The entry is
1528 /// inserted BEFORE the inner `compile_function` call and removed right
1529 /// after, whether compilation succeeded or failed.
1530 ///
1531 /// Note: direct self-recursion in the body is already handled by the
1532 /// cache-insert-before-compile behaviour; this guard only fires on the
1533 /// pathological transitive-resolution cycle.
1534 pub(crate) monomorphization_in_progress: std::collections::HashSet<String>,
1535
1536 /// Monotonic counter for monomorphization specialization IDs.
1537 pub(crate) next_monomorphization_id: u64,
1538
1539 /// Phase C — running count of closure-aware specializations emitted in
1540 /// the current module. When this exceeds
1541 /// [`monomorphization::cache::DEFAULT_CLOSURE_SPECIALIZATION_BUDGET`],
1542 /// further closure-aware specializations bail back to the generic
1543 /// (non-inlined) dispatch path.
1544 pub(crate) closure_specialization_count: u32,
1545}
1546
1547impl Default for BytecodeCompiler {
1548 fn default() -> Self {
1549 Self::new()
1550 }
1551}
1552
1553mod compiler_impl_initialization;
1554mod compiler_impl_reference_model;
1555
1556/// Infer effective reference parameters and mutation behavior without compiling bytecode.
1557///
1558/// Returns `(inferred_ref_params, inferred_ref_mutates)` keyed by function name.
1559/// - `inferred_ref_params[f][i] == true` means parameter `i` of `f` is inferred/treated as ref.
1560/// - `inferred_ref_mutates[f][i] == true` means that reference parameter is mutating (`&mut`).
1561pub fn infer_reference_model(
1562 program: &Program,
1563) -> (HashMap<String, Vec<bool>>, HashMap<String, Vec<bool>>) {
1564 let (inferred_ref_params, inferred_ref_mutates, _, _, _, _, _) =
1565 BytecodeCompiler::infer_reference_model(program);
1566 (inferred_ref_params, inferred_ref_mutates)
1567}
1568
1569/// Infer effective parameter pass modes (`ByValue` / `ByRefShared` / `ByRefExclusive`)
1570/// keyed by function name.
1571pub fn infer_param_pass_modes(program: &Program) -> HashMap<String, Vec<ParamPassMode>> {
1572 let (inferred_ref_params, inferred_ref_mutates, _, _, _, _, _) =
1573 BytecodeCompiler::infer_reference_model(program);
1574 BytecodeCompiler::build_param_pass_mode_map(
1575 program,
1576 &inferred_ref_params,
1577 &inferred_ref_mutates,
1578 )
1579}
1580
1581// ADR-006 §2.7.4 / §2.7.7 — Phase 2c deferral.
1582//
1583// `compiler_tests.rs` is a deep test harness that uses `eval()`-style
1584// helpers returning the deleted `shape_value::ValueWord`. Per playbook
1585// §7 REVISED #4, the correct surface for a non-migratable test site is
1586// `cfg(any())`-gating rather than reintroducing the §2.7.7 forbidden
1587// carrier. Re-enabling is Phase 2c work tracked in playbook §10's
1588// Wave-β B12 deferral pattern.
1589#[cfg(any())]
1590#[path = "compiler_tests.rs"]
1591mod compiler_deep;
1592pub(crate) mod v2_array_emission;
1593pub(crate) mod v2_map_emission;
1594pub(crate) mod v2_typed_emission;
1595pub(crate) mod v2_typed_map_emission;
1596
1597// ADR-006 §2.7.27 / Item 4 ruling (W17-mutation-writeback, 2026-05-12):
1598// compile-time write-back emission for `&mut self` opt-in methods on
1599// COW container receivers (HashSet / HashMap / Array / Deque /
1600// PriorityQueue / TypedArray).
1601pub(crate) mod mutation_writeback;