Skip to main content

shape_vm/compiler/
statements.rs

1//! Statement and item compilation
2
3use crate::bytecode::{Function, Instruction, OpCode, Operand};
4use shape_ast::ast::{
5    AnnotationTargetKind, DestructurePattern, EnumDef, EnumMemberKind, ExportItem, Expr,
6    FunctionDef, FunctionParameter, Item, Literal, ModuleDecl, ObjectEntry, Query, Span, Spanned,
7    Statement, TypeAnnotation, VarKind,
8};
9use shape_ast::error::{Result, ShapeError};
10use shape_runtime::type_schema::{EnumVariantInfo, FieldType};
11
12use super::{
13    BytecodeCompiler, DropKind, ImportedAnnotationSymbol, ImportedSymbol, ModuleBuiltinFunction,
14    ParamPassMode, StructGenericInfo,
15};
16
17#[derive(Debug, Clone)]
18struct NativeFieldLayoutSpec {
19    c_type: String,
20    size: u64,
21    align: u64,
22}
23
24impl BytecodeCompiler {
25    fn register_builtin_function_decl(
26        &mut self,
27        def: &shape_ast::ast::BuiltinFunctionDecl,
28    ) -> Result<()> {
29        let export_name = def
30            .name
31            .rsplit("::")
32            .next()
33            .unwrap_or(def.name.as_str())
34            .to_string();
35        let source_module_path = if let Some((owner_module, _)) = def.name.rsplit_once("::") {
36            self.resolve_canonical_module_path(owner_module)
37                .unwrap_or_else(|| owner_module.to_string())
38        } else {
39            return Ok(());
40        };
41
42        self.module_builtin_functions.insert(
43            def.name.clone(),
44            ModuleBuiltinFunction {
45                export_name,
46                source_module_path,
47            },
48        );
49        Ok(())
50    }
51
52    fn emit_comptime_internal_call(
53        &mut self,
54        method: &str,
55        args: Vec<Expr>,
56        span: Span,
57    ) -> Result<()> {
58        let call = Expr::QualifiedFunctionCall {
59            namespace: "__comptime__".to_string(),
60            function: method.to_string(),
61            args,
62            named_args: Vec::new(),
63            span,
64        };
65        let prev = self.allow_internal_comptime_namespace;
66        self.allow_internal_comptime_namespace = true;
67        let compile_result = self.compile_expr(&call);
68        self.allow_internal_comptime_namespace = prev;
69        compile_result?;
70        self.emit(Instruction::simple(OpCode::Pop));
71        Ok(())
72    }
73
74    /// Serialize a value to JSON for comptime directive payloads.
75    ///
76    /// Wraps serde_json serialization errors into ShapeError with the given
77    /// directive label for diagnostics.
78    fn serialize_directive_payload(
79        &self,
80        value: &(impl serde::Serialize + ?Sized),
81        directive_label: &str,
82        span: Span,
83    ) -> Result<String> {
84        serde_json::to_string(value).map_err(|e| ShapeError::RuntimeError {
85            message: format!("Failed to serialize comptime {} directive: {}", directive_label, e),
86            location: Some(self.span_to_source_location(span)),
87        })
88    }
89
90    /// Check that the compiler is in comptime mode, returning an error otherwise.
91    fn require_comptime_mode(&self, directive_name: &str, span: Span) -> Result<()> {
92        if !self.comptime_mode {
93            return Err(ShapeError::SemanticError {
94                message: format!("`{}` is only valid inside `comptime {{}}` context", directive_name),
95                location: Some(self.span_to_source_location(span)),
96            });
97        }
98        Ok(())
99    }
100
101    fn emit_comptime_extend_directive(
102        &mut self,
103        extend: &shape_ast::ast::ExtendStatement,
104        span: Span,
105    ) -> Result<()> {
106        let payload = self.serialize_directive_payload(extend, "extend", span)?;
107        self.emit_comptime_internal_call(
108            "__emit_extend",
109            vec![Expr::Literal(Literal::String(payload), span)],
110            span,
111        )
112    }
113
114    fn emit_comptime_remove_directive(&mut self, span: Span) -> Result<()> {
115        self.emit_comptime_internal_call("__emit_remove", Vec::new(), span)
116    }
117
118    fn emit_comptime_set_param_value_directive(
119        &mut self,
120        param_name: &str,
121        expression: &Expr,
122        span: Span,
123    ) -> Result<()> {
124        self.emit_comptime_internal_call(
125            "__emit_set_param_value",
126            vec![
127                Expr::Literal(Literal::String(param_name.to_string()), span),
128                expression.clone(),
129            ],
130            span,
131        )
132    }
133
134    fn emit_comptime_set_param_type_directive(
135        &mut self,
136        param_name: &str,
137        type_annotation: &TypeAnnotation,
138        span: Span,
139    ) -> Result<()> {
140        let payload = self.serialize_directive_payload(type_annotation, "param type", span)?;
141        self.emit_comptime_internal_call(
142            "__emit_set_param_type",
143            vec![
144                Expr::Literal(Literal::String(param_name.to_string()), span),
145                Expr::Literal(Literal::String(payload), span),
146            ],
147            span,
148        )
149    }
150
151    fn emit_comptime_set_return_type_directive(
152        &mut self,
153        type_annotation: &TypeAnnotation,
154        span: Span,
155    ) -> Result<()> {
156        let payload = self.serialize_directive_payload(type_annotation, "return type", span)?;
157        self.emit_comptime_internal_call(
158            "__emit_set_return_type",
159            vec![Expr::Literal(Literal::String(payload), span)],
160            span,
161        )
162    }
163
164    fn emit_comptime_set_return_expr_directive(
165        &mut self,
166        expression: &Expr,
167        span: Span,
168    ) -> Result<()> {
169        self.emit_comptime_internal_call("__emit_set_return_type", vec![expression.clone()], span)
170    }
171
172    fn emit_comptime_replace_body_directive(
173        &mut self,
174        body: &[Statement],
175        span: Span,
176    ) -> Result<()> {
177        let payload = self.serialize_directive_payload(body, "replace-body", span)?;
178        self.emit_comptime_internal_call(
179            "__emit_replace_body",
180            vec![Expr::Literal(Literal::String(payload), span)],
181            span,
182        )
183    }
184
185    fn emit_comptime_replace_body_expr_directive(
186        &mut self,
187        expression: &Expr,
188        span: Span,
189    ) -> Result<()> {
190        self.emit_comptime_internal_call("__emit_replace_body", vec![expression.clone()], span)
191    }
192
193    fn emit_comptime_replace_module_expr_directive(
194        &mut self,
195        expression: &Expr,
196        span: Span,
197    ) -> Result<()> {
198        self.emit_comptime_internal_call("__emit_replace_module", vec![expression.clone()], span)
199    }
200
201    pub(super) fn register_item_functions(&mut self, item: &Item) -> Result<()> {
202        match item {
203            Item::Function(func_def, _) => self.register_function(func_def),
204            Item::BuiltinFunctionDecl(def, _) => self.register_builtin_function_decl(def),
205            Item::Module(module_def, _) => {
206                let module_path = self.current_module_path_for(module_def.name.as_str());
207                self.module_scope_stack.push(module_path.clone());
208                let register_result = (|| -> Result<()> {
209                    for inner in &module_def.items {
210                        let qualified = self.qualify_module_item(inner, &module_path)?;
211                        self.register_item_functions(&qualified)?;
212                    }
213                    Ok(())
214                })();
215                self.module_scope_stack.pop();
216                register_result
217            }
218            Item::Trait(trait_def, _) => {
219                self.known_traits.insert(trait_def.name.clone());
220                self.trait_defs
221                    .insert(trait_def.name.clone(), trait_def.clone());
222                // Register in type inference environment so supertrait checking works
223                self.type_inference.env.define_trait(trait_def);
224                Ok(())
225            }
226            Item::ForeignFunction(def, _) => {
227                // Register as a normal function so call sites resolve the name.
228                // Caller-visible arity excludes `out` params.
229                let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
230                self.function_arity_bounds
231                    .insert(def.name.clone(), (caller_visible, caller_visible));
232                self.function_const_params
233                    .insert(def.name.clone(), Vec::new());
234                let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
235                let (vis_ref_params, vis_ref_mutates) = if def.params.iter().any(|p| p.is_out) {
236                    let mut vrp = Vec::new();
237                    let mut vrm = Vec::new();
238                    for (i, p) in def.params.iter().enumerate() {
239                        if !p.is_out {
240                            vrp.push(ref_params.get(i).copied().unwrap_or(false));
241                            vrm.push(ref_mutates.get(i).copied().unwrap_or(false));
242                        }
243                    }
244                    (vrp, vrm)
245                } else {
246                    (ref_params, ref_mutates)
247                };
248
249                let func = crate::bytecode::Function {
250                    name: def.name.clone(),
251                    arity: caller_visible as u16,
252                    param_names: def
253                        .params
254                        .iter()
255                        .filter(|p| !p.is_out)
256                        .flat_map(|p| p.get_identifiers())
257                        .collect(),
258                    locals_count: 0,
259                    entry_point: 0,
260                    body_length: 0,
261                    is_closure: false,
262                    captures_count: 0,
263                    is_async: def.is_async,
264                    ref_params: vis_ref_params,
265                    ref_mutates: vis_ref_mutates,
266                    mutable_captures: Vec::new(),
267                    frame_descriptor: None,
268                    osr_entry_points: Vec::new(),
269                };
270                self.program.functions.push(func);
271
272                // Store the foreign function def so call sites can resolve
273                // the declared return type (must be Result<T> for dynamic languages).
274                self.foreign_function_defs
275                    .insert(def.name.clone(), def.clone());
276
277                Ok(())
278            }
279            Item::Export(export, _) => match &export.item {
280                ExportItem::Function(func_def) => self.register_function(func_def),
281                ExportItem::BuiltinFunction(def) => self.register_builtin_function_decl(def),
282                ExportItem::Trait(trait_def) => {
283                    self.known_traits.insert(trait_def.name.clone());
284                    self.trait_defs
285                        .insert(trait_def.name.clone(), trait_def.clone());
286                    // Register in type inference environment so supertrait checking works
287                    self.type_inference.env.define_trait(trait_def);
288                    Ok(())
289                }
290                ExportItem::Annotation(annotation_def) => {
291                    self.compile_annotation_def(annotation_def)
292                }
293                ExportItem::ForeignFunction(def) => {
294                    // Same registration as Item::ForeignFunction
295                    let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
296                    self.function_arity_bounds
297                        .insert(def.name.clone(), (caller_visible, caller_visible));
298                    self.function_const_params
299                        .insert(def.name.clone(), Vec::new());
300                    let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
301                    let (vis_ref_params, vis_ref_mutates) = if def.params.iter().any(|p| p.is_out) {
302                        let mut vrp = Vec::new();
303                        let mut vrm = Vec::new();
304                        for (i, p) in def.params.iter().enumerate() {
305                            if !p.is_out {
306                                vrp.push(ref_params.get(i).copied().unwrap_or(false));
307                                vrm.push(ref_mutates.get(i).copied().unwrap_or(false));
308                            }
309                        }
310                        (vrp, vrm)
311                    } else {
312                        (ref_params, ref_mutates)
313                    };
314
315                    let func = crate::bytecode::Function {
316                        name: def.name.clone(),
317                        arity: caller_visible as u16,
318                        param_names: def
319                            .params
320                            .iter()
321                            .filter(|p| !p.is_out)
322                            .flat_map(|p| p.get_identifiers())
323                            .collect(),
324                        locals_count: 0,
325                        entry_point: 0,
326                        body_length: 0,
327                        is_closure: false,
328                        captures_count: 0,
329                        is_async: def.is_async,
330                        ref_params: vis_ref_params,
331                        ref_mutates: vis_ref_mutates,
332                        mutable_captures: Vec::new(),
333                        frame_descriptor: None,
334                        osr_entry_points: Vec::new(),
335                    };
336                    self.program.functions.push(func);
337
338                    self.foreign_function_defs
339                        .insert(def.name.clone(), def.clone());
340
341                    Ok(())
342                }
343                _ => Ok(()),
344            },
345            Item::Extend(extend, _) => {
346                // Desugar extend methods to functions with implicit `self` receiver param.
347                for method in &extend.methods {
348                    let func_def = self.desugar_extend_method(method, &extend.type_name)?;
349                    self.register_function(&func_def)?;
350                }
351                Ok(())
352            }
353            Item::Impl(impl_block, _) => {
354                // Impl blocks use scoped UFCS names.
355                // - default impl: "Type::method" (legacy compatibility)
356                // - named impl: "Trait::Type::ImplName::method"
357                // This prevents conflicts when multiple named impls exist.
358                let raw_trait_name = match &impl_block.trait_name {
359                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
360                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
361                };
362                let type_name = match &impl_block.target_type {
363                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
364                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
365                };
366                let impl_name = impl_block.impl_name.as_deref();
367
368                // Resolve trait name: canonical for def lookup, basename for dispatch
369                let (canonical_trait, trait_basename) = self.resolve_trait_name(raw_trait_name);
370
371                // From/TryFrom impls use reverse-conversion desugaring:
372                // the method takes an explicit `value` param (no implicit self),
373                // and we auto-derive Into/TryInto trait symbols on the source type.
374                if trait_basename == "From" || trait_basename == "TryFrom" {
375                    return self.compile_from_impl(impl_block, &trait_basename, type_name);
376                }
377
378                // Collect names of methods explicitly provided in the impl block
379                let overridden: std::collections::HashSet<&str> =
380                    impl_block.methods.iter().map(|m| m.name.as_str()).collect();
381
382                for method in &impl_block.methods {
383                    let func_def = self.desugar_impl_method(
384                        method,
385                        &trait_basename,
386                        type_name,
387                        impl_name,
388                        &impl_block.target_type,
389                    )?;
390                    self.program.register_trait_method_symbol(
391                        &trait_basename,
392                        type_name,
393                        impl_name,
394                        &method.name,
395                        &func_def.name,
396                    );
397                    self.register_function(&func_def)?;
398
399                    // Track drop kind per type (sync, async, or both)
400                    if trait_basename == "Drop" && method.name == "drop" {
401                        let type_key = type_name.to_string();
402                        let existing = self.drop_type_info.get(&type_key).copied();
403                        let new_kind = if method.is_async {
404                            match existing {
405                                Some(DropKind::SyncOnly) | Some(DropKind::Both) => DropKind::Both,
406                                _ => DropKind::AsyncOnly,
407                            }
408                        } else {
409                            match existing {
410                                Some(DropKind::AsyncOnly) | Some(DropKind::Both) => DropKind::Both,
411                                _ => DropKind::SyncOnly,
412                            }
413                        };
414                        self.drop_type_info.insert(type_key, new_kind);
415                    }
416                }
417
418                // Install default methods from the trait definition that were not overridden
419                if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
420                    for member in &trait_def.members {
421                        if let shape_ast::ast::types::TraitMember::Default(default_method) = member
422                        {
423                            if !overridden.contains(default_method.name.as_str()) {
424                                let func_def = self.desugar_impl_method(
425                                    default_method,
426                                    &trait_basename,
427                                    type_name,
428                                    impl_name,
429                                    &impl_block.target_type,
430                                )?;
431                                self.program.register_trait_method_symbol(
432                                    &trait_basename,
433                                    type_name,
434                                    impl_name,
435                                    &default_method.name,
436                                    &func_def.name,
437                                );
438                                self.register_function(&func_def)?;
439                            }
440                        }
441                    }
442                }
443
444                // BUG-4.6 fix: Register the trait impl in the type inference
445                // environment so that `implements()` can see it at comptime.
446                let all_method_names: Vec<String> =
447                    impl_block.methods.iter().map(|m| m.name.clone()).collect();
448                if let Some(selector) = impl_name {
449                    let _ = self.type_inference.env.register_trait_impl_named(
450                        &trait_basename,
451                        type_name,
452                        selector,
453                        all_method_names,
454                    );
455                } else {
456                    let _ = self.type_inference.env.register_trait_impl(
457                        &trait_basename,
458                        type_name,
459                        all_method_names,
460                    );
461                }
462
463                // C3: Verify supertrait constraints.
464                // If the trait has supertraits (e.g. `trait Foo: Bar + Baz`),
465                // check that the target type also implements each supertrait.
466                if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
467                    for super_ann in &trait_def.super_traits {
468                        let super_name = match super_ann {
469                            TypeAnnotation::Basic(name) => name.clone(),
470                            TypeAnnotation::Reference(name) => name.to_string(),
471                            TypeAnnotation::Generic { name, .. } => name.to_string(),
472                            _ => continue,
473                        };
474                        let (_canonical_super, super_basename) = self.resolve_trait_name(&super_name);
475                        if !self
476                            .type_inference
477                            .env
478                            .type_implements_trait(type_name, &super_basename)
479                        {
480                            return Err(ShapeError::SemanticError {
481                                message: format!(
482                                    "impl {} for {} requires supertrait '{}' to be implemented first",
483                                    trait_basename, type_name, super_basename
484                                ),
485                                location: None,
486                            });
487                        }
488                    }
489                }
490
491                Ok(())
492            }
493            _ => Ok(()),
494        }
495    }
496
497    /// Register a function definition
498    pub(super) fn register_function(&mut self, func_def: &FunctionDef) -> Result<()> {
499        // Detect duplicate function definitions (Shape does not support overloading).
500        // Skip names containing "::" (trait impl methods) or "." (extend methods)
501        // — those are type-qualified and live in separate namespaces.
502        if !func_def.name.contains("::") && !func_def.name.contains('.') {
503            if let Some(existing) = self
504                .program
505                .functions
506                .iter()
507                .find(|f| f.name == func_def.name)
508            {
509                // Allow idempotent re-registration from module inlining: when the
510                // prelude and an explicitly imported module both define the same helper
511                // function (e.g., `percentile`), silently keep the first definition
512                // if arities match. Different arities indicate a genuine conflict.
513                if existing.arity == func_def.params.len() as u16 {
514                    return Ok(());
515                }
516                return Err(ShapeError::SemanticError {
517                    message: format!(
518                        "Duplicate function definition: '{}' is already defined",
519                        func_def.name
520                    ),
521                    location: Some(self.span_to_source_location(func_def.name_span)),
522                });
523            }
524        }
525
526        self.function_defs
527            .insert(func_def.name.clone(), func_def.clone());
528
529        let total_params = func_def.params.len();
530        let mut required_params = total_params;
531        let mut saw_default = false;
532        let mut const_params = Vec::new();
533        for (idx, param) in func_def.params.iter().enumerate() {
534            if param.is_const {
535                const_params.push(idx);
536            }
537            if param.default_value.is_some() {
538                if !saw_default {
539                    required_params = idx;
540                    saw_default = true;
541                }
542            } else if saw_default {
543                return Err(ShapeError::SemanticError {
544                    message: "Required parameter cannot follow a parameter with a default value"
545                        .to_string(),
546                    location: Some(self.span_to_source_location(param.span())),
547                });
548            }
549        }
550
551        self.function_arity_bounds
552            .insert(func_def.name.clone(), (required_params, total_params));
553        self.function_const_params
554            .insert(func_def.name.clone(), const_params);
555
556        let inferred_param_modes = self
557            .inferred_param_pass_modes
558            .get(&func_def.name)
559            .cloned()
560            .unwrap_or_default();
561        let mut ref_params: Vec<bool> = Vec::with_capacity(func_def.params.len());
562        let mut ref_mutates: Vec<bool> = Vec::with_capacity(func_def.params.len());
563        for (idx, param) in func_def.params.iter().enumerate() {
564            let fallback = if param.is_reference {
565                ParamPassMode::ByRefShared
566            } else {
567                ParamPassMode::ByValue
568            };
569            let mode = inferred_param_modes.get(idx).copied().unwrap_or(fallback);
570            ref_params.push(mode.is_reference());
571            ref_mutates.push(mode.is_exclusive());
572        }
573
574        let func = Function {
575            name: func_def.name.clone(),
576            arity: func_def.params.len() as u16,
577            param_names: func_def
578                .params
579                .iter()
580                .flat_map(|p| p.get_identifiers())
581                .collect(),
582            locals_count: 0, // Will be updated during compilation
583            entry_point: 0,  // Will be updated during compilation
584            body_length: 0,  // Will be updated during compilation
585            is_closure: false,
586            captures_count: 0,
587            is_async: func_def.is_async,
588            ref_params,
589            ref_mutates,
590            mutable_captures: Vec::new(),
591            frame_descriptor: None,
592            osr_entry_points: Vec::new(),
593        };
594
595        self.program.functions.push(func);
596
597        // Register function return type for typed opcode emission.
598        // When a function has an explicit return type annotation (e.g., `: int`),
599        // record it so that call sites can propagate NumericType through expressions
600        // like `fib(n-1) + fib(n-2)` and emit AddInt instead of generic Add.
601        if let Some(ref return_type) = func_def.return_type {
602            if let Some(type_name) = return_type.as_simple_name() {
603                self.type_tracker
604                    .register_function_return_type(&func_def.name, type_name);
605            }
606        }
607
608        Ok(())
609    }
610
611    /// Compile a top-level item with context about whether it's the last item
612    /// If is_last is true and the item is an expression, keep the result on the stack
613    pub(super) fn compile_item_with_context(&mut self, item: &Item, is_last: bool) -> Result<()> {
614        match item {
615            Item::Function(func_def, _) => self.compile_function(func_def)?,
616            Item::Module(module_def, span) => {
617                self.compile_module_decl(module_def, *span)?;
618            }
619            Item::VariableDecl(var_decl, _) => {
620                // ModuleBinding variable — register the variable even if the initializer fails,
621                // to prevent cascading "Undefined variable" errors on later references.
622                let mut ref_borrow = None;
623                let init_err = if let Some(init_expr) = &var_decl.value {
624                    let saved_pending_variable_name = self.pending_variable_name.clone();
625                    self.pending_variable_name = var_decl
626                        .pattern
627                        .as_identifier()
628                        .map(|name| name.to_string());
629                    match self.compile_expr_for_reference_binding(init_expr) {
630                        Ok(tracked_borrow) => {
631                            ref_borrow = tracked_borrow;
632                            self.pending_variable_name = saved_pending_variable_name;
633                            None
634                        }
635                        Err(e) => {
636                            self.pending_variable_name = saved_pending_variable_name;
637                            // Push null as placeholder so the variable still gets registered
638                            self.emit(Instruction::simple(OpCode::PushNull));
639                            Some(e)
640                        }
641                    }
642                } else {
643                    self.emit(Instruction::simple(OpCode::PushNull));
644                    None
645                };
646
647                if let Some(name) = var_decl.pattern.as_identifier() {
648                    if ref_borrow.is_some() {
649                        return Err(ShapeError::SemanticError {
650                            message:
651                                "[B0003] cannot return or store a reference that outlives its owner"
652                                    .to_string(),
653                            location: var_decl
654                                .value
655                                .as_ref()
656                                .map(|expr| self.span_to_source_location(expr.span())),
657                        });
658                    }
659                    let binding_idx = self.get_or_create_module_binding(name);
660                    self.emit(Instruction::new(
661                        OpCode::StoreModuleBinding,
662                        Some(Operand::ModuleBinding(binding_idx)),
663                    ));
664                    if let Some(value) = &var_decl.value {
665                        self.finish_reference_binding_from_expr(
666                            binding_idx,
667                            false,
668                            name,
669                            value,
670                            ref_borrow,
671                        );
672                        self.update_callable_binding_from_expr(binding_idx, false, value);
673                    } else {
674                        self.clear_reference_binding(binding_idx, false);
675                        self.clear_callable_binding(binding_idx, false);
676                    }
677
678                    // Propagate type info from annotation or initializer expression
679                    if let Some(ref type_ann) = var_decl.type_annotation {
680                        if let Some(type_name) = Self::tracked_type_name_from_annotation(type_ann) {
681                            self.set_module_binding_type_info(binding_idx, &type_name);
682                        }
683                    } else {
684                        let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
685                        self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
686                    }
687
688                    // Track for auto-drop at program exit
689                    let binding_type_name = self
690                        .type_tracker
691                        .get_binding_type(binding_idx)
692                        .and_then(|info| info.type_name.clone());
693                    let drop_kind = binding_type_name
694                        .as_ref()
695                        .and_then(|tn| self.drop_type_info.get(tn).copied())
696                        .or_else(|| {
697                            var_decl
698                                .type_annotation
699                                .as_ref()
700                                .and_then(|ann| self.annotation_drop_kind(ann))
701                        });
702                    if drop_kind.is_some() {
703                        let is_async = match drop_kind {
704                            Some(DropKind::AsyncOnly) => true,
705                            Some(DropKind::Both) => false,
706                            Some(DropKind::SyncOnly) | None => false,
707                        };
708                        self.track_drop_module_binding(binding_idx, is_async);
709                    }
710                } else {
711                    self.compile_destructure_pattern_global(&var_decl.pattern)?;
712                }
713
714                if let Some(e) = init_err {
715                    return Err(e);
716                }
717            }
718            Item::Assignment(assign, _) => {
719                self.compile_statement(&Statement::Assignment(assign.clone(), Span::DUMMY))?;
720            }
721            Item::Expression(expr, _) => {
722                self.compile_expr(expr)?;
723                // Only pop if not the last item - keep last expression result on stack
724                if !is_last {
725                    self.emit(Instruction::simple(OpCode::Pop));
726                }
727            }
728            Item::Statement(stmt, _) => {
729                // For expression statements that are the last item, keep result on stack
730                if is_last {
731                    if let Statement::Expression(expr, _) = stmt {
732                        self.compile_expr(expr)?;
733                        // Don't emit Pop - keep result on stack
734                        return Ok(());
735                    }
736                }
737                self.compile_statement(stmt)?;
738            }
739            Item::Export(export, export_span) => {
740                // If the export has a source variable declaration (pub let/const/var),
741                // compile it so the initialization is actually executed.
742                if let Some(ref var_decl) = export.source_decl {
743                    let mut ref_borrow = None;
744                    if let Some(init_expr) = &var_decl.value {
745                        let saved_pending_variable_name = self.pending_variable_name.clone();
746                        self.pending_variable_name = var_decl
747                            .pattern
748                            .as_identifier()
749                            .map(|name| name.to_string());
750                        let compile_result = self.compile_expr_for_reference_binding(init_expr);
751                        self.pending_variable_name = saved_pending_variable_name;
752                        ref_borrow = compile_result?;
753                        if ref_borrow.is_some() {
754                            return Err(ShapeError::SemanticError {
755                                message:
756                                    "[B0003] cannot return or store a reference that outlives its owner"
757                                        .to_string(),
758                                location: Some(self.span_to_source_location(init_expr.span())),
759                            });
760                        }
761                    } else {
762                        self.emit(Instruction::simple(OpCode::PushNull));
763                    }
764                    if let Some(name) = var_decl.pattern.as_identifier() {
765                        let binding_idx = self.get_or_create_module_binding(name);
766                        self.emit(Instruction::new(
767                            OpCode::StoreModuleBinding,
768                            Some(Operand::ModuleBinding(binding_idx)),
769                        ));
770                        if let Some(value) = &var_decl.value {
771                            self.finish_reference_binding_from_expr(
772                                binding_idx,
773                                false,
774                                name,
775                                value,
776                                ref_borrow,
777                            );
778                            self.update_callable_binding_from_expr(binding_idx, false, value);
779                        } else {
780                            self.clear_reference_binding(binding_idx, false);
781                            self.clear_callable_binding(binding_idx, false);
782                        }
783                    }
784                }
785                match &export.item {
786                    ExportItem::Function(func_def) => self.compile_function(func_def)?,
787                    ExportItem::Annotation(annotation_def) => {
788                        self.compile_annotation_def(annotation_def)?;
789                    }
790                    ExportItem::Enum(enum_def) => self.register_enum(enum_def)?,
791                    ExportItem::Struct(struct_def) => {
792                        self.register_struct_type(struct_def, *export_span)?;
793                        if self.struct_types.contains_key(&struct_def.name) {
794                            self.emit_annotation_lifecycle_calls_for_type(
795                                &struct_def.name,
796                                &struct_def.annotations,
797                            )?;
798                        }
799                    }
800                    ExportItem::Interface(_) => {} // no-op for now
801                    ExportItem::Trait(_) => {} // no-op for now (trait registration happens in type system)
802                    ExportItem::ForeignFunction(def) => self.compile_foreign_function(def)?,
803                    _ => {}
804                }
805            }
806            Item::Stream(_stream, _) => {
807                return Err(ShapeError::StreamError {
808                    message: "Streaming functionality has been removed".to_string(),
809                    stream_name: None,
810                });
811            }
812            Item::TypeAlias(type_alias, _) => {
813                // Track type alias for meta validation
814                let base_type_name = match &type_alias.type_annotation {
815                    TypeAnnotation::Basic(name) => Some(name.clone()),
816                    TypeAnnotation::Reference(name) => Some(name.to_string()),
817                    _ => None,
818                };
819                self.type_aliases.insert(
820                    type_alias.name.clone(),
821                    base_type_name
822                        .clone()
823                        .unwrap_or_else(|| format!("{:?}", type_alias.type_annotation)),
824                );
825                // Register in type inference environment so lookup_type_alias works
826                self.type_inference.env.define_type_alias(
827                    &type_alias.name,
828                    &type_alias.type_annotation,
829                    type_alias.meta_param_overrides.clone(),
830                );
831
832                // Apply comptime field overrides from type alias
833                // e.g., type EUR = Currency { symbol: "€" } overrides Currency's comptime symbol
834                if let (Some(base_name), Some(overrides)) =
835                    (&base_type_name, &type_alias.meta_param_overrides)
836                {
837                    use shape_ast::ast::Literal;
838                    use shape_value::ValueWord;
839                    use std::sync::Arc;
840
841                    // Start with base type's comptime fields (if any)
842                    let mut alias_comptime = self
843                        .comptime_fields
844                        .get(base_name)
845                        .cloned()
846                        .unwrap_or_default();
847
848                    for (field_name, expr) in overrides {
849                        let value = match expr {
850                            Expr::Literal(Literal::Number(n), _) => ValueWord::from_f64(*n),
851                            Expr::Literal(Literal::Int(n), _) => ValueWord::from_i64(*n),
852                            Expr::Literal(Literal::String(s), _) => {
853                                ValueWord::from_string(Arc::new(s.clone()))
854                            }
855                            Expr::Literal(Literal::Bool(b), _) => ValueWord::from_bool(*b),
856                            Expr::Literal(Literal::None, _) => ValueWord::none(),
857                            _ => {
858                                return Err(ShapeError::SemanticError {
859                                    message: format!(
860                                        "Comptime field override '{}' on type alias '{}' must be a literal",
861                                        field_name, type_alias.name
862                                    ),
863                                    location: None,
864                                });
865                            }
866                        };
867                        alias_comptime.insert(field_name.clone(), value);
868                    }
869
870                    if !alias_comptime.is_empty() {
871                        self.comptime_fields
872                            .insert(type_alias.name.clone(), alias_comptime);
873                    }
874                }
875            }
876            Item::StructType(struct_def, span) => {
877                self.register_struct_type(struct_def, *span)?;
878                if self.struct_types.contains_key(&struct_def.name) {
879                    self.emit_annotation_lifecycle_calls_for_type(
880                        &struct_def.name,
881                        &struct_def.annotations,
882                    )?;
883                }
884            }
885            Item::Enum(enum_def, _) => {
886                self.register_enum(enum_def)?;
887            }
888            // Meta/Format definitions removed — formatting now uses Display trait
889            Item::Import(import_stmt, _) => {
890                // Import resolution is handled by the module graph pipeline
891                // before compilation. At this point imports should already
892                // have been resolved via `register_graph_imports_for_module`.
893                // If we reach here, the import is either:
894                // 1. Being compiled standalone (no module context) - skip for now
895                // 2. A future extension point for runtime imports
896                //
897                // For now, we register the imported names as known functions
898                // that can be resolved later.
899                self.register_import_names(import_stmt)?;
900            }
901            Item::Extend(extend, _) => {
902                // Compile desugared extend methods
903                for method in &extend.methods {
904                    let func_def = self.desugar_extend_method(method, &extend.type_name)?;
905                    self.compile_function(&func_def)?;
906                }
907            }
908            Item::Impl(impl_block, _) => {
909                // Compile impl block methods with scoped names
910                let raw_trait_name = match &impl_block.trait_name {
911                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
912                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
913                };
914                let type_name = match &impl_block.target_type {
915                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
916                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
917                };
918                let impl_name = impl_block.impl_name.as_deref();
919
920                // Resolve trait name: canonical for def lookup, basename for dispatch
921                let (canonical_trait, trait_basename) = self.resolve_trait_name(raw_trait_name);
922
923                // From/TryFrom: compile the from/tryFrom method + synthetic wrapper
924                if trait_basename == "From" || trait_basename == "TryFrom" {
925                    return self.compile_from_impl_bodies(impl_block, &trait_basename, type_name);
926                }
927
928                // Collect names of methods explicitly provided in the impl block
929                let overridden: std::collections::HashSet<&str> =
930                    impl_block.methods.iter().map(|m| m.name.as_str()).collect();
931
932                for method in &impl_block.methods {
933                    let func_def = self.desugar_impl_method(
934                        method,
935                        &trait_basename,
936                        type_name,
937                        impl_name,
938                        &impl_block.target_type,
939                    )?;
940                    self.compile_function(&func_def)?;
941                }
942
943                // Compile default methods from the trait definition that were not overridden
944                if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
945                    for member in &trait_def.members {
946                        if let shape_ast::ast::types::TraitMember::Default(default_method) = member
947                        {
948                            if !overridden.contains(default_method.name.as_str()) {
949                                let func_def = self.desugar_impl_method(
950                                    default_method,
951                                    &trait_basename,
952                                    type_name,
953                                    impl_name,
954                                    &impl_block.target_type,
955                                )?;
956                                self.compile_function(&func_def)?;
957                            }
958                        }
959                    }
960                }
961            }
962            Item::AnnotationDef(ann_def, _) => {
963                self.compile_annotation_def(ann_def)?;
964            }
965            Item::Comptime(stmts, span) => {
966                // Execute comptime block at compile time (side-effects only; result discarded)
967                let extensions: Vec<_> = self
968                    .extension_registry
969                    .as_ref()
970                    .map(|r| r.as_ref().clone())
971                    .unwrap_or_default();
972                let trait_impls = self.type_inference.env.trait_impl_keys();
973                let known_type_symbols: std::collections::HashSet<String> = self
974                    .struct_types
975                    .keys()
976                    .chain(self.type_aliases.keys())
977                    .cloned()
978                    .collect();
979                let comptime_helpers = self.collect_comptime_helpers();
980                let execution = super::comptime::execute_comptime(
981                    stmts,
982                    &comptime_helpers,
983                    &extensions,
984                    trait_impls,
985                    known_type_symbols,
986                )
987                .map_err(|e| ShapeError::RuntimeError {
988                    message: format!(
989                        "Comptime block evaluation failed: {}",
990                        super::helpers::strip_error_prefix(&e)
991                    ),
992                    location: Some(self.span_to_source_location(*span)),
993                })?;
994                self.process_comptime_directives(execution.directives, "")
995                    .map_err(|e| ShapeError::RuntimeError {
996                        message: format!("Comptime block directive processing failed: {}", e),
997                        location: Some(self.span_to_source_location(*span)),
998                    })?;
999            }
1000            Item::Query(query, _span) => {
1001                self.compile_query(query)?;
1002                // Pop the query result unless self is the last item
1003                if !is_last {
1004                    self.emit(Instruction::simple(OpCode::Pop));
1005                }
1006            }
1007            Item::ForeignFunction(def, _) => self.compile_foreign_function(def)?,
1008            _ => {} // Skip other items for now
1009        }
1010        Ok(())
1011    }
1012
1013    /// Register imported names for symbol resolution
1014    ///
1015    /// This allows the compiler to recognize imported functions when
1016    /// they are called later in the code.
1017    fn register_import_names(&mut self, import_stmt: &shape_ast::ast::ImportStmt) -> Result<()> {
1018        use shape_ast::ast::ImportItems;
1019
1020        // Check permissions before registering imports.
1021        // Clone to avoid borrow conflict with &mut self in check_import_permissions.
1022        if let Some(pset) = self.permission_set.clone() {
1023            self.check_import_permissions(import_stmt, &pset)?;
1024        }
1025
1026        match &import_stmt.items {
1027            ImportItems::Named(specs) => {
1028                for spec in specs {
1029                    if spec.is_annotation {
1030                        let hidden_module_name =
1031                            crate::module_resolution::hidden_annotation_import_module_name(
1032                                &import_stmt.from,
1033                            );
1034                        self.module_scope_sources
1035                            .entry(hidden_module_name.clone())
1036                            .or_insert_with(|| import_stmt.from.clone());
1037                        self.imported_annotations.insert(
1038                            spec.name.clone(),
1039                            ImportedAnnotationSymbol {
1040                                original_name: spec.name.clone(),
1041                                _module_path: import_stmt.from.clone(),
1042                                hidden_module_name,
1043                            },
1044                        );
1045                        continue;
1046                    }
1047                    let local_name = spec.alias.as_ref().unwrap_or(&spec.name);
1048                    // Register as a known import - actual function resolution
1049                    // happens when the imported module's bytecode is merged
1050                    self.imported_names.insert(
1051                        local_name.clone(),
1052                        ImportedSymbol {
1053                            original_name: spec.name.clone(),
1054                            module_path: import_stmt.from.clone(),
1055                            kind: None, // legacy path
1056                        },
1057                    );
1058                }
1059            }
1060            ImportItems::Namespace { name, alias } => {
1061                // `use module.path` or `use module.path as alias`
1062                // Register the local namespace binding as a module_binding.
1063                let local_name = alias.as_ref().unwrap_or(name);
1064                let binding_idx = self.get_or_create_module_binding(local_name);
1065                self.module_namespace_bindings.insert(local_name.clone());
1066                self.module_scope_sources
1067                    .entry(local_name.clone())
1068                    .or_insert_with(|| import_stmt.from.clone());
1069                let module_path = if import_stmt.from.is_empty() {
1070                    name.as_str()
1071                } else {
1072                    import_stmt.from.as_str()
1073                };
1074                // Predeclare module object schema so runtime can instantiate
1075                // module module_bindings without synthesizing schemas dynamically.
1076                self.register_extension_module_schema(module_path);
1077                let module_schema_name = format!("__mod_{}", module_path);
1078                if self
1079                    .type_tracker
1080                    .schema_registry()
1081                    .get(&module_schema_name)
1082                    .is_some()
1083                {
1084                    self.set_module_binding_type_info(binding_idx, &module_schema_name);
1085                }
1086                // The module object will be provided at runtime by the VM
1087                let _ = binding_idx;
1088            }
1089        }
1090        Ok(())
1091    }
1092
1093    /// Check whether the imported symbols are allowed by the active permission set.
1094    ///
1095    /// For named imports (`from std::core::file use { read_text }`), checks each function
1096    /// individually. For namespace imports (`use std::core::http`), checks the whole module.
1097    fn check_import_permissions(
1098        &mut self,
1099        import_stmt: &shape_ast::ast::ImportStmt,
1100        pset: &shape_abi_v1::PermissionSet,
1101    ) -> Result<()> {
1102        use shape_ast::ast::ImportItems;
1103        use shape_runtime::stdlib::capability_tags;
1104
1105        // Pass the full canonical path (e.g. "std::core::file") to capability tags.
1106        let module_name = &import_stmt.from as &str;
1107
1108        match &import_stmt.items {
1109            ImportItems::Named(specs) => {
1110                for spec in specs {
1111                    let required = capability_tags::required_permissions(module_name, &spec.name);
1112                    if !required.is_empty() && !required.is_subset(pset) {
1113                        let missing = required.difference(pset);
1114                        let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
1115                        return Err(ShapeError::SemanticError {
1116                            message: format!(
1117                                "Permission denied: {module_name}::{} requires {} capability, \
1118                                 but the active permission set does not include it. \
1119                                 Add the permission to [permissions] in shape.toml or use a less \
1120                                 restrictive preset.",
1121                                spec.name,
1122                                missing_names.join(", "),
1123                            ),
1124                            location: None,
1125                        });
1126                    }
1127                    self.record_blob_permissions(module_name, &spec.name);
1128                }
1129            }
1130            ImportItems::Namespace { .. } => {
1131                // For namespace imports, check the entire module's permission envelope.
1132                // If the module requires any permissions not granted, deny the import.
1133                let required = capability_tags::module_permissions(module_name);
1134                if !required.is_empty() && !required.is_subset(pset) {
1135                    let missing = required.difference(pset);
1136                    let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
1137                    return Err(ShapeError::SemanticError {
1138                        message: format!(
1139                            "Permission denied: module '{module_name}' requires {} capabilities, \
1140                             but the active permission set does not include them. \
1141                             Add the permissions to [permissions] in shape.toml or use a less \
1142                             restrictive preset.",
1143                            missing_names.join(", "),
1144                        ),
1145                        location: None,
1146                    });
1147                }
1148                // Record module-level permissions for namespace imports in the current blob
1149                if let Some(ref mut blob) = self.current_blob_builder {
1150                    let module_perms = capability_tags::module_permissions(module_name);
1151                    blob.record_permissions(&module_perms);
1152                }
1153            }
1154        }
1155        Ok(())
1156    }
1157
1158    /// Register imports for a module from the module graph.
1159    ///
1160    /// This is the graph-driven replacement for `register_import_names`.
1161    /// For each `ResolvedImport` on the node:
1162    /// - Namespace: creates canonical + alias bindings, registers schemas
1163    /// - Named: populates `imported_names`, `imported_annotations`, `module_builtin_functions`
1164    pub(super) fn register_graph_imports_for_module(
1165        &mut self,
1166        module_id: crate::module_graph::ModuleId,
1167        graph: &crate::module_graph::ModuleGraph,
1168    ) -> Result<()> {
1169        use crate::module_graph::{ModuleSourceKind, ResolvedImport};
1170
1171        let node = graph.node(module_id);
1172        let resolved_imports = node.resolved_imports.clone();
1173
1174        for ri in &resolved_imports {
1175            match ri {
1176                ResolvedImport::Namespace {
1177                    local_name,
1178                    canonical_path,
1179                    module_id: dep_id,
1180                } => {
1181                    let dep_node = graph.node(*dep_id);
1182
1183                    // 1. Ensure canonical binding exists
1184                    let canonical_idx = self.get_or_create_module_binding(canonical_path);
1185
1186                    // Register native schema on canonical binding for NativeModule/Hybrid
1187                    if matches!(
1188                        dep_node.source_kind,
1189                        ModuleSourceKind::NativeModule | ModuleSourceKind::Hybrid
1190                    ) {
1191                        self.register_extension_module_schema(canonical_path);
1192                        let module_schema_name = format!("__mod_{}", canonical_path);
1193                        if self
1194                            .type_tracker
1195                            .schema_registry()
1196                            .get(&module_schema_name)
1197                            .is_some()
1198                        {
1199                            self.set_module_binding_type_info(canonical_idx, &module_schema_name);
1200                        }
1201                    }
1202
1203                    // 2. Create alias binding if local_name != canonical_path
1204                    if local_name != canonical_path {
1205                        let alias_idx = self.get_or_create_module_binding(local_name);
1206
1207                        // Copy type info from canonical to alias
1208                        let module_schema_name = format!("__mod_{}", canonical_path);
1209                        if self
1210                            .type_tracker
1211                            .schema_registry()
1212                            .get(&module_schema_name)
1213                            .is_some()
1214                        {
1215                            self.set_module_binding_type_info(alias_idx, &module_schema_name);
1216                        }
1217
1218                        // Emit runtime binding copy: alias = canonical
1219                        self.emit(Instruction::new(
1220                            OpCode::LoadModuleBinding,
1221                            Some(Operand::ModuleBinding(canonical_idx)),
1222                        ));
1223                        self.emit(Instruction::new(
1224                            OpCode::StoreModuleBinding,
1225                            Some(Operand::ModuleBinding(alias_idx)),
1226                        ));
1227                    }
1228
1229                    // 3. Register namespace
1230                    self.module_namespace_bindings.insert(local_name.clone());
1231                    self.graph_namespace_map
1232                        .insert(local_name.clone(), canonical_path.clone());
1233                }
1234                ResolvedImport::Named {
1235                    canonical_path,
1236                    module_id: dep_id,
1237                    symbols,
1238                } => {
1239                    let dep_node = graph.node(*dep_id);
1240
1241                    for sym in symbols {
1242                        if sym.is_annotation {
1243                            let hidden_module_name =
1244                                crate::module_resolution::hidden_annotation_import_module_name(
1245                                    canonical_path,
1246                                );
1247                            self.module_scope_sources
1248                                .entry(hidden_module_name.clone())
1249                                .or_insert_with(|| canonical_path.clone());
1250                            // Vacant-only: explicit imports win over prelude
1251                            self.imported_annotations
1252                                .entry(sym.local_name.clone())
1253                                .or_insert_with(|| ImportedAnnotationSymbol {
1254                                    original_name: sym.original_name.clone(),
1255                                    _module_path: canonical_path.clone(),
1256                                    hidden_module_name,
1257                                });
1258                            continue;
1259                        }
1260
1261                        // Register as imported name (vacant-only: explicit imports
1262                        // are processed first and win over prelude entries)
1263                        self.imported_names
1264                            .entry(sym.local_name.clone())
1265                            .or_insert_with(|| ImportedSymbol {
1266                                original_name: sym.original_name.clone(),
1267                                module_path: canonical_path.clone(),
1268                                kind: Some(sym.kind),
1269                            });
1270
1271                        // For native exports, register as module builtin function
1272                        if matches!(
1273                            dep_node.source_kind,
1274                            ModuleSourceKind::NativeModule | ModuleSourceKind::Hybrid
1275                        ) && matches!(
1276                            sym.kind,
1277                            shape_ast::module_utils::ModuleExportKind::Function
1278                                | shape_ast::module_utils::ModuleExportKind::BuiltinFunction
1279                        ) {
1280                            self.module_builtin_functions
1281                                .entry(sym.local_name.clone())
1282                                .or_insert_with(|| ModuleBuiltinFunction {
1283                                    export_name: sym.original_name.clone(),
1284                                    source_module_path: canonical_path.clone(),
1285                                });
1286                        }
1287                    }
1288                }
1289            }
1290        }
1291
1292        Ok(())
1293    }
1294
1295    pub(super) fn register_extension_module_schema(&mut self, module_path: &str) {
1296        let Some(registry) = self.extension_registry.as_ref() else {
1297            return;
1298        };
1299        let Some(module) = registry
1300            .iter()
1301            .rev()
1302            .find(|m| m.name == module_path)
1303        else {
1304            return;
1305        };
1306
1307        for schema in &module.type_schemas {
1308            if self
1309                .type_tracker
1310                .schema_registry()
1311                .get(&schema.name)
1312                .is_none()
1313            {
1314                self.type_tracker
1315                    .schema_registry_mut()
1316                    .register(schema.clone());
1317            }
1318        }
1319
1320        let schema_name = format!("__mod_{}", module_path);
1321        if self
1322            .type_tracker
1323            .schema_registry()
1324            .get(&schema_name)
1325            .is_some()
1326        {
1327            return;
1328        }
1329
1330        let mut export_names: Vec<String> = module
1331            .export_names_available(self.comptime_mode)
1332            .into_iter()
1333            .map(|name| name.to_string())
1334            .collect();
1335
1336        for artifact in &module.module_artifacts {
1337            if artifact.module_path != module_path {
1338                continue;
1339            }
1340            let Some(source) = artifact.source.as_deref() else {
1341                continue;
1342            };
1343            if let Ok(names) =
1344                shape_runtime::module_loader::collect_exported_function_names_from_source(
1345                    &artifact.module_path,
1346                    source,
1347                )
1348            {
1349                export_names.extend(names);
1350            }
1351        }
1352
1353        export_names.sort();
1354        export_names.dedup();
1355
1356        let fields: Vec<(String, FieldType)> = export_names
1357            .into_iter()
1358            .map(|name| (name, FieldType::Any))
1359            .collect();
1360        self.type_tracker
1361            .schema_registry_mut()
1362            .register_type(schema_name, fields);
1363    }
1364
1365    /// Register an enum definition in the TypeSchemaRegistry
1366    fn register_enum(&mut self, enum_def: &EnumDef) -> Result<()> {
1367        let variants: Vec<EnumVariantInfo> = enum_def
1368            .members
1369            .iter()
1370            .enumerate()
1371            .map(|(id, member)| {
1372                let payload_fields = match &member.kind {
1373                    EnumMemberKind::Unit { .. } => 0,
1374                    EnumMemberKind::Tuple(types) => types.len() as u16,
1375                    EnumMemberKind::Struct(fields) => fields.len() as u16,
1376                };
1377                EnumVariantInfo::new(&member.name, id as u16, payload_fields)
1378            })
1379            .collect();
1380
1381        let schema = shape_runtime::type_schema::TypeSchema::new_enum(&enum_def.name, variants.clone());
1382        self.type_tracker.schema_registry_mut().register(schema);
1383
1384        // Also register under bare name if the qualified name contains "::"
1385        // so runtime code that uses bare enum names (e.g., "Snapshot") can find the schema.
1386        if let Some(basename) = enum_def.name.rsplit("::").next() {
1387            if basename != enum_def.name
1388                && self
1389                    .type_tracker
1390                    .schema_registry()
1391                    .get(basename)
1392                    .is_none()
1393            {
1394                let alias_schema =
1395                    shape_runtime::type_schema::TypeSchema::new_enum(basename, variants);
1396                self.type_tracker.schema_registry_mut().register(alias_schema);
1397            }
1398        }
1399        Ok(())
1400    }
1401
1402    /// Pre-register items from an imported module (enums, struct types, functions).
1403    ///
1404    /// Called by the LSP before compilation to make imported enums/types known
1405    /// to the compiler's type tracker. Reuses `register_enum` as single source of truth.
1406    pub fn register_imported_items(&mut self, items: &[Item]) {
1407        for item in items {
1408            match item {
1409                Item::Export(export, _) => {
1410                    match &export.item {
1411                        ExportItem::Enum(enum_def) => {
1412                            let _ = self.register_enum(enum_def);
1413                        }
1414                        ExportItem::Struct(struct_def) => {
1415                            // Register struct type fields so the compiler knows about them
1416                            let _ = self.register_struct_type(struct_def, Span::DUMMY);
1417                        }
1418                        ExportItem::Function(func_def) => {
1419                            // Register function so it's known during compilation
1420                            let _ = self.register_function(func_def);
1421                        }
1422                        _ => {}
1423                    }
1424                }
1425                Item::Enum(enum_def, _) => {
1426                    let _ = self.register_enum(enum_def);
1427                }
1428                _ => {}
1429            }
1430        }
1431    }
1432
1433    /// Register a meta definition in the format registry
1434    ///
1435    // Meta compilation methods removed — formatting now uses Display trait
1436
1437    /// Desugar an extend method to a FunctionDef with implicit `self` first param.
1438    ///
1439    /// `extend Number { method double() { self * 2 } }`
1440    /// becomes: `function double(self) { self * 2 }`
1441    ///
1442    /// UFCS handles the rest: `(5).double()` → `double(5)` → self = 5
1443    pub(super) fn desugar_extend_method(
1444        &self,
1445        method: &shape_ast::ast::types::MethodDef,
1446        target_type: &shape_ast::ast::TypeName,
1447    ) -> Result<FunctionDef> {
1448        let receiver_type = Some(Self::type_name_to_annotation(target_type));
1449        let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1450
1451        // Extend methods use qualified "Type.method" names to avoid collisions
1452        // with free functions (e.g., prelude's `sum` vs extend Point { method sum() }).
1453        let type_str = match target_type {
1454            shape_ast::ast::TypeName::Simple(n) => n.clone(),
1455            shape_ast::ast::TypeName::Generic { name, .. } => name.clone(),
1456        };
1457
1458        Ok(FunctionDef {
1459            name: format!("{}.{}", type_str, method.name),
1460            name_span: Span::DUMMY,
1461            declaring_module_path: method.declaring_module_path.clone(),
1462            doc_comment: None,
1463            params,
1464            return_type: method.return_type.clone(),
1465            body,
1466            type_params: Some(Vec::new()),
1467            annotations: method.annotations.clone(),
1468            is_async: method.is_async,
1469            is_comptime: false,
1470            where_clause: None,
1471        })
1472    }
1473
1474    /// Desugar an impl method to a scoped FunctionDef.
1475    ///
1476    /// - Default impl:
1477    ///   `impl Queryable for DbTable { method filter(pred) { ... } }`
1478    ///   becomes: `function DbTable::filter(self, pred) { ... }`
1479    /// - Named impl:
1480    ///   `impl Display for User as JsonDisplay { method display() { ... } }`
1481    ///   becomes: `function Display::User::JsonDisplay::display(self) { ... }`
1482    ///
1483    /// Named impls use trait/type/impl prefixes to avoid collisions.
1484    fn desugar_impl_method(
1485        &self,
1486        method: &shape_ast::ast::types::MethodDef,
1487        trait_name: &str,
1488        type_name: &str,
1489        impl_name: Option<&str>,
1490        target_type: &shape_ast::ast::TypeName,
1491    ) -> Result<FunctionDef> {
1492        let receiver_type = Some(Self::type_name_to_annotation(target_type));
1493        let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1494
1495        // Async drop methods are named "drop_async" so both sync and async
1496        // variants can coexist in the function name index.
1497        let method_name = if trait_name == "Drop" && method.name == "drop" && method.is_async {
1498            "drop_async".to_string()
1499        } else {
1500            method.name.clone()
1501        };
1502        let fn_name = if let Some(name) = impl_name {
1503            format!("{}::{}::{}::{}", trait_name, type_name, name, method_name)
1504        } else {
1505            format!("{}::{}", type_name, method_name)
1506        };
1507
1508        Ok(FunctionDef {
1509            name: fn_name,
1510            name_span: Span::DUMMY,
1511            declaring_module_path: method.declaring_module_path.clone(),
1512            doc_comment: None,
1513            params,
1514            return_type: method.return_type.clone(),
1515            body,
1516            type_params: Some(Vec::new()),
1517            annotations: method.annotations.clone(),
1518            is_async: method.is_async,
1519            is_comptime: false,
1520            where_clause: None,
1521        })
1522    }
1523
1524    /// Build desugared method params/body with implicit receiver handling.
1525    ///
1526    /// Canonical receiver is `self`.
1527    fn desugar_method_signature_and_body(
1528        &self,
1529        method: &shape_ast::ast::types::MethodDef,
1530        receiver_type: Option<shape_ast::ast::TypeAnnotation>,
1531    ) -> Result<(Vec<FunctionParameter>, Vec<Statement>)> {
1532        if let Some(receiver) = method
1533            .params
1534            .first()
1535            .and_then(|p| p.pattern.as_identifier())
1536        {
1537            if receiver == "self" {
1538                let location = method
1539                    .params
1540                    .first()
1541                    .map(|p| self.span_to_source_location(p.span()));
1542                return Err(ShapeError::SemanticError {
1543                    message: format!(
1544                        "Method '{}' has an explicit `self` parameter, but method receivers are implicit. Use `method {}(...)` without `self`.",
1545                        method.name, method.name
1546                    ),
1547                    location,
1548                });
1549            }
1550        }
1551
1552        let mut params = vec![FunctionParameter {
1553            pattern: shape_ast::ast::DestructurePattern::Identifier(
1554                "self".to_string(),
1555                Span::DUMMY,
1556            ),
1557            is_const: false,
1558            is_reference: false,
1559            is_mut_reference: false,
1560            is_out: false,
1561            type_annotation: receiver_type,
1562            default_value: None,
1563        }];
1564        params.extend(method.params.clone());
1565
1566        Ok((params, method.body.clone()))
1567    }
1568
1569    /// Compile a `From` or `TryFrom` impl block.
1570    ///
1571    /// Unlike normal impl methods (which inject implicit `self`), From/TryFrom
1572    /// methods are constructors: `from(value: Source) -> Target`. The value
1573    /// parameter sits at local slot 0 with no receiver.
1574    ///
1575    /// Auto-derives:
1576    /// - `impl From<S> for T`  → `Into<T>::into` on S (direct alias)
1577    ///                          + `TryInto<T>::tryInto` on S (wrapper → Ok())
1578    /// - `impl TryFrom<S> for T` → `TryInto<T>::tryInto` on S (direct alias)
1579    fn compile_from_impl(
1580        &mut self,
1581        impl_block: &shape_ast::ast::types::ImplBlock,
1582        trait_name: &str,
1583        target_type: &str,
1584    ) -> Result<()> {
1585        // Extract source type from generic args: From<Source> → Source
1586        let source_type = match &impl_block.trait_name {
1587            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1588                match &type_args[0] {
1589                    TypeAnnotation::Basic(name) => name.clone(),
1590                    TypeAnnotation::Reference(name) => name.to_string(),
1591                    other => {
1592                        return Err(ShapeError::SemanticError {
1593                            message: format!(
1594                                "{} impl requires a simple source type, found {:?}",
1595                                trait_name, other
1596                            ),
1597                            location: None,
1598                        });
1599                    }
1600                }
1601            }
1602            _ => {
1603                return Err(ShapeError::SemanticError {
1604                    message: format!(
1605                        "{} impl requires a generic type argument, e.g., {}<string>",
1606                        trait_name, trait_name
1607                    ),
1608                    location: None,
1609                });
1610            }
1611        };
1612
1613        // Named impl selector defaults to the target type name so that
1614        // `as TargetType` / `as TargetType?` dispatch finds the right symbol.
1615        let selector = impl_block.impl_name.as_deref().unwrap_or(target_type);
1616
1617        for method in &impl_block.methods {
1618            let func_def =
1619                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1620            let from_fn_name = func_def.name.clone();
1621
1622            // Register From/TryFrom trait method symbol on the target type
1623            self.program.register_trait_method_symbol(
1624                trait_name,
1625                target_type,
1626                Some(&source_type),
1627                &method.name,
1628                &from_fn_name,
1629            );
1630            self.register_function(&func_def)?;
1631
1632            // Auto-derive Into/TryInto on the source type
1633            if trait_name == "From" {
1634                // From<S> for T → Into<T>::into on S = direct alias (same fn)
1635                self.program.register_trait_method_symbol(
1636                    "Into",
1637                    &source_type,
1638                    Some(selector),
1639                    "into",
1640                    &from_fn_name,
1641                );
1642
1643                // From<S> for T → TryInto<T>::tryInto on S = wrapper (from + Ok)
1644                let wrapper_name =
1645                    self.emit_from_to_tryinto_wrapper(&from_fn_name, &source_type, target_type)?;
1646                self.program.register_trait_method_symbol(
1647                    "TryInto",
1648                    &source_type,
1649                    Some(selector),
1650                    "tryInto",
1651                    &wrapper_name,
1652                );
1653
1654                // Register trait impls in type inference environment
1655                let _ = self.type_inference.env.register_trait_impl_named(
1656                    "Into",
1657                    &source_type,
1658                    selector,
1659                    vec!["into".to_string()],
1660                );
1661                let _ = self.type_inference.env.register_trait_impl_named(
1662                    "TryInto",
1663                    &source_type,
1664                    selector,
1665                    vec!["tryInto".to_string()],
1666                );
1667            } else {
1668                // TryFrom<S> for T → TryInto<T>::tryInto on S = direct alias
1669                self.program.register_trait_method_symbol(
1670                    "TryInto",
1671                    &source_type,
1672                    Some(selector),
1673                    "tryInto",
1674                    &from_fn_name,
1675                );
1676
1677                // Register TryInto trait impl in type inference environment
1678                let _ = self.type_inference.env.register_trait_impl_named(
1679                    "TryInto",
1680                    &source_type,
1681                    selector,
1682                    vec!["tryInto".to_string()],
1683                );
1684            }
1685        }
1686
1687        // Register From/TryFrom trait impl on target type
1688        let all_method_names: Vec<String> =
1689            impl_block.methods.iter().map(|m| m.name.clone()).collect();
1690        let _ = self.type_inference.env.register_trait_impl_named(
1691            trait_name,
1692            target_type,
1693            &source_type,
1694            all_method_names,
1695        );
1696
1697        Ok(())
1698    }
1699
1700    /// Compile From/TryFrom impl method bodies (and the synthetic TryInto wrapper).
1701    ///
1702    /// Called from `compile_item_with_context` — the registration pass already
1703    /// happened in `compile_from_impl` / `register_item_functions`.
1704    fn compile_from_impl_bodies(
1705        &mut self,
1706        impl_block: &shape_ast::ast::types::ImplBlock,
1707        trait_name: &str,
1708        target_type: &str,
1709    ) -> Result<()> {
1710        let source_type = match &impl_block.trait_name {
1711            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1712                match &type_args[0] {
1713                    TypeAnnotation::Basic(name) => name.clone(),
1714                    TypeAnnotation::Reference(name) => name.to_string(),
1715                    _ => return Ok(()), // error already reported in registration
1716                }
1717            }
1718            _ => return Ok(()),
1719        };
1720
1721        for method in &impl_block.methods {
1722            let func_def =
1723                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1724            self.compile_function(&func_def)?;
1725        }
1726
1727        // Also compile the synthetic TryInto wrapper for From impls
1728        if trait_name == "From" {
1729            for method in &impl_block.methods {
1730                let from_fn_name = format!(
1731                    "{}::{}::{}::{}",
1732                    trait_name, target_type, source_type, method.name
1733                );
1734                let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1735                // The wrapper was already registered; now compile its body
1736                if let Some(func_def) = self.function_defs.get(&wrapper_name).cloned() {
1737                    let _ = self.compile_function(&func_def);
1738                    // Suppress errors: if Ok() or the from fn is not yet available, it
1739                    // will be resolved at link time.
1740                    let _ = from_fn_name; // used above in the format
1741                }
1742            }
1743        }
1744
1745        Ok(())
1746    }
1747
1748    /// Desugar a From/TryFrom method WITHOUT implicit self injection.
1749    ///
1750    /// `From::from(value: S)` is a constructor — `value` sits at local slot 0.
1751    /// Function name: `"From::TargetType::SourceType::method_name"`
1752    fn desugar_from_method(
1753        &self,
1754        method: &shape_ast::ast::types::MethodDef,
1755        trait_name: &str,
1756        target_type: &str,
1757        source_type: &str,
1758    ) -> Result<FunctionDef> {
1759        // Verify no explicit `self` parameter
1760        if let Some(first) = method
1761            .params
1762            .first()
1763            .and_then(|p| p.pattern.as_identifier())
1764        {
1765            if first == "self" {
1766                return Err(ShapeError::SemanticError {
1767                    message: format!(
1768                        "{}::{} methods are constructors and must not have a `self` parameter",
1769                        trait_name, method.name
1770                    ),
1771                    location: None,
1772                });
1773            }
1774        }
1775
1776        let fn_name = format!(
1777            "{}::{}::{}::{}",
1778            trait_name, target_type, source_type, method.name
1779        );
1780
1781        Ok(FunctionDef {
1782            name: fn_name,
1783            name_span: Span::DUMMY,
1784            declaring_module_path: method.declaring_module_path.clone(),
1785            doc_comment: None,
1786            params: method.params.clone(),
1787            return_type: method.return_type.clone(),
1788            body: method.body.clone(),
1789            type_params: Some(Vec::new()),
1790            annotations: Vec::new(),
1791            is_async: method.is_async,
1792            is_comptime: false,
1793            where_clause: None,
1794        })
1795    }
1796
1797    /// Emit a synthetic wrapper function that calls a From::from function
1798    /// and wraps its result in Ok() for TryInto compatibility.
1799    ///
1800    /// Generated function: `__from_tryinto_{source}_{target}(value) -> Ok(from(value))`
1801    fn emit_from_to_tryinto_wrapper(
1802        &mut self,
1803        from_fn_name: &str,
1804        source_type: &str,
1805        target_type: &str,
1806    ) -> Result<String> {
1807        let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1808
1809        // Create a synthetic FunctionDef whose body calls from() and wraps in Ok()
1810        let span = Span::DUMMY;
1811        let body = vec![Statement::Return(
1812            Some(Expr::FunctionCall {
1813                name: "Ok".to_string(),
1814                args: vec![Expr::FunctionCall {
1815                    name: from_fn_name.to_string(),
1816                    args: vec![Expr::Identifier("value".to_string(), span)],
1817                    named_args: Vec::new(),
1818                    span,
1819                }],
1820                named_args: Vec::new(),
1821                span,
1822            }),
1823            span,
1824        )];
1825
1826        let func_def = FunctionDef {
1827            name: wrapper_name.clone(),
1828            name_span: span,
1829            declaring_module_path: None,
1830            doc_comment: None,
1831            params: vec![FunctionParameter {
1832                pattern: DestructurePattern::Identifier("value".to_string(), span),
1833                is_const: false,
1834                is_reference: false,
1835                is_mut_reference: false,
1836                is_out: false,
1837                type_annotation: None,
1838                default_value: None,
1839            }],
1840            return_type: None,
1841            body,
1842            type_params: Some(Vec::new()),
1843            annotations: Vec::new(),
1844            is_async: false,
1845            is_comptime: false,
1846            where_clause: None,
1847        };
1848
1849        self.register_function(&func_def)?;
1850
1851        Ok(wrapper_name)
1852    }
1853
1854    fn type_name_to_annotation(
1855        type_name: &shape_ast::ast::TypeName,
1856    ) -> shape_ast::ast::TypeAnnotation {
1857        match type_name {
1858            shape_ast::ast::TypeName::Simple(name) => {
1859                shape_ast::ast::TypeAnnotation::Basic(name.to_string())
1860            }
1861            shape_ast::ast::TypeName::Generic { name, type_args } => {
1862                shape_ast::ast::TypeAnnotation::Generic {
1863                    name: name.clone(),
1864                    args: type_args.clone(),
1865                }
1866            }
1867        }
1868    }
1869
1870    /// Compile an annotation definition.
1871    ///
1872    /// Each handler is compiled as an internal function:
1873    /// - before(args, ctx) → `{name}___before(self, period, args, ctx)`
1874    /// - after(args, result, ctx) → `{name}___after(self, period, args, result, ctx)`
1875    ///
1876    /// `self` is the annotated item (function/method/property).
1877    /// Annotation params (e.g., `period`) are prepended after `self`.
1878    fn compile_annotation_def(&mut self, ann_def: &shape_ast::ast::AnnotationDef) -> Result<()> {
1879        use crate::bytecode::CompiledAnnotation;
1880        use shape_ast::ast::AnnotationHandlerType;
1881
1882        let mut compiled = CompiledAnnotation {
1883            name: ann_def.name.clone(),
1884            param_names: ann_def
1885                .params
1886                .iter()
1887                .flat_map(|p| p.get_identifiers())
1888                .collect(),
1889            before_handler: None,
1890            after_handler: None,
1891            on_define_handler: None,
1892            metadata_handler: None,
1893            comptime_pre_handler: None,
1894            comptime_post_handler: None,
1895            allowed_targets: Vec::new(),
1896        };
1897
1898        for handler in &ann_def.handlers {
1899            // Comptime handlers are stored as AST (not compiled to bytecode).
1900            // They are executed at compile time when the annotation is applied.
1901            match handler.handler_type {
1902                AnnotationHandlerType::ComptimePre => {
1903                    compiled.comptime_pre_handler = Some(handler.clone());
1904                    continue;
1905                }
1906                AnnotationHandlerType::ComptimePost => {
1907                    compiled.comptime_post_handler = Some(handler.clone());
1908                    continue;
1909                }
1910                _ => {}
1911            }
1912
1913            if handler.params.iter().any(|p| p.is_variadic) {
1914                return Err(ShapeError::SemanticError {
1915                    message:
1916                        "Variadic annotation handler params (`...args`) are only supported on comptime handlers"
1917                            .to_string(),
1918                    location: Some(self.span_to_source_location(handler.span)),
1919                });
1920            }
1921
1922            let handler_type_str = match handler.handler_type {
1923                AnnotationHandlerType::Before => "before",
1924                AnnotationHandlerType::After => "after",
1925                AnnotationHandlerType::OnDefine => "on_define",
1926                AnnotationHandlerType::Metadata => "metadata",
1927                AnnotationHandlerType::ComptimePre => unreachable!(),
1928                AnnotationHandlerType::ComptimePost => unreachable!(),
1929            };
1930
1931            let func_name = format!("{}___{}", ann_def.name, handler_type_str);
1932
1933            // Build function params: self + annotation_params + handler_params
1934            let mut params = vec![FunctionParameter {
1935                pattern: shape_ast::ast::DestructurePattern::Identifier(
1936                    "self".to_string(),
1937                    Span::DUMMY,
1938                ),
1939                is_const: false,
1940                is_reference: false,
1941                is_mut_reference: false,
1942                is_out: false,
1943                type_annotation: None,
1944                default_value: None,
1945            }];
1946            // Add annotation params (e.g., period)
1947            for ann_param in &ann_def.params {
1948                params.push(ann_param.clone());
1949            }
1950            // Add handler params (e.g., args, ctx)
1951            for param in &handler.params {
1952                let inferred_type = if param.name == "ctx" {
1953                    Some(TypeAnnotation::Object(vec![
1954                        shape_ast::ast::ObjectTypeField {
1955                            name: "state".to_string(),
1956                            optional: false,
1957                            type_annotation: TypeAnnotation::Basic("unknown".to_string()),
1958                            annotations: vec![],
1959                        },
1960                        shape_ast::ast::ObjectTypeField {
1961                            name: "event_log".to_string(),
1962                            optional: false,
1963                            type_annotation: TypeAnnotation::Array(Box::new(
1964                                TypeAnnotation::Basic("unknown".to_string()),
1965                            )),
1966                            annotations: vec![],
1967                        },
1968                    ]))
1969                } else if matches!(
1970                    handler.handler_type,
1971                    AnnotationHandlerType::OnDefine | AnnotationHandlerType::Metadata
1972                ) && (param.name == "fn" || param.name == "target")
1973                {
1974                    Some(TypeAnnotation::Object(vec![
1975                        shape_ast::ast::ObjectTypeField {
1976                            name: "name".to_string(),
1977                            optional: false,
1978                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1979                            annotations: vec![],
1980                        },
1981                        shape_ast::ast::ObjectTypeField {
1982                            name: "kind".to_string(),
1983                            optional: false,
1984                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1985                            annotations: vec![],
1986                        },
1987                        shape_ast::ast::ObjectTypeField {
1988                            name: "id".to_string(),
1989                            optional: false,
1990                            type_annotation: TypeAnnotation::Basic("int".to_string()),
1991                            annotations: vec![],
1992                        },
1993                    ]))
1994                } else {
1995                    None
1996                };
1997
1998                params.push(FunctionParameter {
1999                    pattern: shape_ast::ast::DestructurePattern::Identifier(
2000                        param.name.clone(),
2001                        Span::DUMMY,
2002                    ),
2003                    is_const: false,
2004                    is_reference: false,
2005                    is_mut_reference: false,
2006                    is_out: false,
2007                    type_annotation: inferred_type,
2008                    default_value: None,
2009                });
2010            }
2011
2012            // Convert handler body (Expr) to function body (Vec<Statement>)
2013            let body = vec![Statement::Return(Some(handler.body.clone()), Span::DUMMY)];
2014
2015            let func_def = FunctionDef {
2016                name: func_name,
2017                name_span: Span::DUMMY,
2018                declaring_module_path: None,
2019                doc_comment: None,
2020                params,
2021                return_type: handler.return_type.clone(),
2022                body,
2023                type_params: Some(Vec::new()),
2024                annotations: Vec::new(),
2025                is_async: false,
2026                is_comptime: false,
2027                where_clause: None,
2028            };
2029
2030            self.register_function(&func_def)?;
2031            self.compile_function(&func_def)?;
2032
2033            let func_id = (self.program.functions.len() - 1) as u16;
2034
2035            match handler.handler_type {
2036                AnnotationHandlerType::Before => compiled.before_handler = Some(func_id),
2037                AnnotationHandlerType::After => compiled.after_handler = Some(func_id),
2038                AnnotationHandlerType::OnDefine => compiled.on_define_handler = Some(func_id),
2039                AnnotationHandlerType::Metadata => compiled.metadata_handler = Some(func_id),
2040                AnnotationHandlerType::ComptimePre => {} // handled above
2041                AnnotationHandlerType::ComptimePost => {} // handled above
2042            }
2043        }
2044
2045        // Resolve allowed target kinds.
2046        // Explicit `targets: [...]` in the annotation definition has priority.
2047        // Otherwise infer from handlers:
2048        // before/after handlers only make sense on functions (they wrap calls),
2049        // lifecycle handlers (on_define/metadata) are definition-time only.
2050        if let Some(explicit) = &ann_def.allowed_targets {
2051            compiled.allowed_targets = explicit.clone();
2052        } else if compiled.before_handler.is_some()
2053            || compiled.after_handler.is_some()
2054            || compiled.comptime_pre_handler.is_some()
2055            || compiled.comptime_post_handler.is_some()
2056        {
2057            compiled.allowed_targets =
2058                vec![shape_ast::ast::functions::AnnotationTargetKind::Function];
2059        } else if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
2060            compiled.allowed_targets = vec![
2061                shape_ast::ast::functions::AnnotationTargetKind::Function,
2062                shape_ast::ast::functions::AnnotationTargetKind::Type,
2063                shape_ast::ast::functions::AnnotationTargetKind::Module,
2064            ];
2065        }
2066
2067        // Enforce that definition-time lifecycle hooks only target definition
2068        // sites (`function` / `type`).
2069        if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
2070            if compiled.allowed_targets.is_empty() {
2071                return Err(ShapeError::SemanticError {
2072                    message: format!(
2073                        "Annotation '{}' uses `on_define`/`metadata` and cannot have unrestricted targets. Allowed targets are: function, type, module",
2074                        ann_def.name
2075                    ),
2076                    location: Some(self.span_to_source_location(ann_def.span)),
2077                });
2078            }
2079            if let Some(invalid) = compiled
2080                .allowed_targets
2081                .iter()
2082                .find(|kind| !Self::is_definition_annotation_target(**kind))
2083            {
2084                let invalid_label = format!("{:?}", invalid).to_lowercase();
2085                return Err(ShapeError::SemanticError {
2086                    message: format!(
2087                        "Annotation '{}' uses `on_define`/`metadata`, but target '{}' is not a definition target. Allowed targets are: function, type, module",
2088                        ann_def.name, invalid_label
2089                    ),
2090                    location: Some(self.span_to_source_location(ann_def.span)),
2091                });
2092            }
2093        }
2094
2095        self.program
2096            .compiled_annotations
2097            .insert(ann_def.name.clone(), compiled);
2098        Ok(())
2099    }
2100
2101    /// Register a struct type definition.
2102    ///
2103    /// Comptime fields are baked at compile time and excluded from the runtime TypeSchema.
2104    /// Their values are stored in `self.comptime_fields` for constant-folded access.
2105    fn register_struct_type(
2106        &mut self,
2107        struct_def: &shape_ast::ast::StructTypeDef,
2108        span: shape_ast::ast::Span,
2109    ) -> Result<()> {
2110        use shape_ast::ast::Literal;
2111        use shape_runtime::type_schema::{FieldAnnotation, TypeSchemaBuilder};
2112
2113        // Validate annotation target kinds before type registration.
2114        for ann in &struct_def.annotations {
2115            self.validate_annotation_target_usage(
2116                ann,
2117                shape_ast::ast::functions::AnnotationTargetKind::Type,
2118                span,
2119            )?;
2120        }
2121
2122        if struct_def.native_layout.is_some() {
2123            self.native_layout_types.insert(struct_def.name.clone());
2124        } else {
2125            self.native_layout_types.remove(&struct_def.name);
2126        }
2127
2128        // Pre-register runtime field layout so comptime-generated methods on
2129        // `extend target { ... }` can resolve `self.field` statically.
2130        // If the target is later removed by comptime directives, these
2131        // placeholders are rolled back below.
2132        let runtime_field_names: Vec<String> = struct_def
2133            .fields
2134            .iter()
2135            .filter(|f| !f.is_comptime)
2136            .map(|f| f.name.clone())
2137            .collect();
2138        let runtime_field_types = struct_def
2139            .fields
2140            .iter()
2141            .filter(|f| !f.is_comptime)
2142            .map(|f| (f.name.clone(), f.type_annotation.clone()))
2143            .collect::<std::collections::HashMap<_, _>>();
2144        self.struct_types
2145            .insert(struct_def.name.clone(), (runtime_field_names, span));
2146        self.struct_generic_info.insert(
2147            struct_def.name.clone(),
2148            StructGenericInfo {
2149                type_params: struct_def.type_params.clone().unwrap_or_default(),
2150                runtime_field_types,
2151            },
2152        );
2153        if self
2154            .type_tracker
2155            .schema_registry()
2156            .get(&struct_def.name)
2157            .is_none()
2158        {
2159            let runtime_fields: Vec<(String, shape_runtime::type_schema::FieldType)> = struct_def
2160                .fields
2161                .iter()
2162                .filter(|f| !f.is_comptime)
2163                .map(|f| {
2164                    (
2165                        f.name.clone(),
2166                        Self::type_annotation_to_field_type(&f.type_annotation),
2167                    )
2168                })
2169                .collect();
2170            // Collect field annotations (e.g. @alias) so that JSON
2171            // deserialization can map wire names to field names.
2172            let field_annotations: Vec<Vec<FieldAnnotation>> = struct_def
2173                .fields
2174                .iter()
2175                .filter(|f| !f.is_comptime)
2176                .map(|f| {
2177                    f.annotations
2178                        .iter()
2179                        .map(|ann| FieldAnnotation {
2180                            name: ann.name.clone(),
2181                            args: ann
2182                                .args
2183                                .iter()
2184                                .filter_map(|arg| match arg {
2185                                    Expr::Literal(Literal::String(s), _) => Some(s.clone()),
2186                                    _ => None,
2187                                })
2188                                .collect(),
2189                        })
2190                        .collect()
2191                })
2192                .collect();
2193            self.type_tracker
2194                .schema_registry_mut()
2195                .register_type_with_annotations(
2196                    struct_def.name.clone(),
2197                    runtime_fields,
2198                    field_annotations,
2199                );
2200        }
2201
2202        // Execute comptime annotation handlers before registration so
2203        // `remove target` can suppress type emission entirely.
2204        if self.execute_struct_comptime_handlers(struct_def)? {
2205            self.struct_types.remove(&struct_def.name);
2206            self.struct_generic_info.remove(&struct_def.name);
2207            return Ok(());
2208        }
2209
2210        if struct_def.native_layout.is_some() {
2211            self.register_native_struct_layout(struct_def, span)?;
2212        }
2213
2214        // Build TypeSchema for runtime fields only
2215        if self
2216            .type_tracker
2217            .schema_registry()
2218            .get(&struct_def.name)
2219            .is_none()
2220        {
2221            let mut builder = TypeSchemaBuilder::new(struct_def.name.clone());
2222            for field in &struct_def.fields {
2223                if field.is_comptime {
2224                    continue;
2225                }
2226                let field_type = Self::type_annotation_to_field_type(&field.type_annotation);
2227                let mut annotations = Vec::new();
2228                for ann in &field.annotations {
2229                    let args: Vec<String> = ann
2230                        .args
2231                        .iter()
2232                        .filter_map(Self::eval_annotation_arg)
2233                        .collect();
2234                    annotations.push(FieldAnnotation {
2235                        name: ann.name.clone(),
2236                        args,
2237                    });
2238                }
2239                builder = builder.field_with_meta(field.name.clone(), field_type, annotations);
2240            }
2241            builder.register(self.type_tracker.schema_registry_mut());
2242        }
2243
2244        // Bake comptime field values
2245        let mut comptime_values = std::collections::HashMap::new();
2246        for field in &struct_def.fields {
2247            if !field.is_comptime {
2248                continue;
2249            }
2250            if let Some(ref default_expr) = field.default_value {
2251                let value = match default_expr {
2252                    Expr::Literal(Literal::Number(n), _) => shape_value::ValueWord::from_f64(*n),
2253                    Expr::Literal(Literal::Int(n), _) => {
2254                        shape_value::ValueWord::from_i64(*n)
2255                    }
2256                    Expr::Literal(Literal::String(s), _) => {
2257                        shape_value::ValueWord::from_string(std::sync::Arc::new(s.clone()))
2258                    }
2259                    Expr::Literal(Literal::Bool(b), _) => shape_value::ValueWord::from_bool(*b),
2260                    Expr::Literal(Literal::None, _) => shape_value::ValueWord::none(),
2261                    _ => {
2262                        return Err(ShapeError::SemanticError {
2263                            message: format!(
2264                                "Comptime field '{}' on type '{}' must have a literal default value",
2265                                field.name, struct_def.name
2266                            ),
2267                            location: None,
2268                        });
2269                    }
2270                };
2271                comptime_values.insert(field.name.clone(), value);
2272            }
2273            // Comptime fields without a default are allowed — they must be
2274            // provided via type alias overrides (e.g., type EUR = Currency { symbol: "€" })
2275        }
2276
2277        if !comptime_values.is_empty() {
2278            self.comptime_fields
2279                .insert(struct_def.name.clone(), comptime_values);
2280        }
2281
2282        self.maybe_generate_native_type_conversions(&struct_def.name, span)?;
2283
2284        Ok(())
2285    }
2286
2287    fn register_native_struct_layout(
2288        &mut self,
2289        struct_def: &shape_ast::ast::StructTypeDef,
2290        span: shape_ast::ast::Span,
2291    ) -> Result<()> {
2292        if struct_def.type_params.is_some() {
2293            return Err(ShapeError::SemanticError {
2294                message: format!(
2295                    "type C '{}' cannot be generic in this version",
2296                    struct_def.name
2297                ),
2298                location: Some(self.span_to_source_location(span)),
2299            });
2300        }
2301
2302        if struct_def.fields.iter().any(|f| f.is_comptime) {
2303            return Err(ShapeError::SemanticError {
2304                message: format!(
2305                    "type C '{}' cannot contain comptime fields",
2306                    struct_def.name
2307                ),
2308                location: Some(self.span_to_source_location(span)),
2309            });
2310        }
2311
2312        let abi = struct_def
2313            .native_layout
2314            .as_ref()
2315            .map(|b| b.abi.clone())
2316            .unwrap_or_else(|| "C".to_string());
2317        if abi != "C" {
2318            return Err(ShapeError::SemanticError {
2319                message: format!(
2320                    "type '{}' uses unsupported native ABI '{}'; only C is supported",
2321                    struct_def.name, abi
2322                ),
2323                location: Some(self.span_to_source_location(span)),
2324            });
2325        }
2326
2327        let mut struct_align: u64 = 1;
2328        let mut offset: u64 = 0;
2329        let mut field_layouts = Vec::with_capacity(struct_def.fields.len());
2330
2331        for field in &struct_def.fields {
2332            let field_spec =
2333                self.native_field_layout_spec(&field.type_annotation, span, &struct_def.name)?;
2334            struct_align = struct_align.max(field_spec.align);
2335            offset = Self::align_to(offset, field_spec.align);
2336            if offset > u32::MAX as u64
2337                || field_spec.size > u32::MAX as u64
2338                || field_spec.align > u32::MAX as u64
2339            {
2340                return Err(ShapeError::SemanticError {
2341                    message: format!(
2342                        "type C '{}' layout exceeds supported size/alignment limits",
2343                        struct_def.name
2344                    ),
2345                    location: Some(self.span_to_source_location(span)),
2346                });
2347            }
2348            field_layouts.push(crate::bytecode::NativeStructFieldLayout {
2349                name: field.name.clone(),
2350                c_type: field_spec.c_type,
2351                offset: offset as u32,
2352                size: field_spec.size as u32,
2353                align: field_spec.align as u32,
2354            });
2355            offset = offset.saturating_add(field_spec.size);
2356        }
2357
2358        let size = Self::align_to(offset, struct_align);
2359        if size > u32::MAX as u64 || struct_align > u32::MAX as u64 {
2360            return Err(ShapeError::SemanticError {
2361                message: format!(
2362                    "type C '{}' layout exceeds supported size/alignment limits",
2363                    struct_def.name
2364                ),
2365                location: Some(self.span_to_source_location(span)),
2366            });
2367        }
2368
2369        let entry = crate::bytecode::NativeStructLayoutEntry {
2370            name: struct_def.name.clone(),
2371            abi,
2372            size: size as u32,
2373            align: struct_align as u32,
2374            fields: field_layouts,
2375        };
2376
2377        if let Some(existing) = self
2378            .program
2379            .native_struct_layouts
2380            .iter_mut()
2381            .find(|existing| existing.name == entry.name)
2382        {
2383            *existing = entry;
2384        } else {
2385            self.program.native_struct_layouts.push(entry);
2386        }
2387
2388        Ok(())
2389    }
2390
2391    fn align_to(value: u64, align: u64) -> u64 {
2392        debug_assert!(align > 0);
2393        let mask = align - 1;
2394        (value + mask) & !mask
2395    }
2396
2397    fn native_field_layout_spec(
2398        &self,
2399        ann: &shape_ast::ast::TypeAnnotation,
2400        span: shape_ast::ast::Span,
2401        struct_name: &str,
2402    ) -> Result<NativeFieldLayoutSpec> {
2403        use shape_ast::ast::TypeAnnotation;
2404
2405        let pointer = std::mem::size_of::<usize>() as u64;
2406
2407        let fail = || -> Result<NativeFieldLayoutSpec> {
2408            Err(ShapeError::SemanticError {
2409                message: format!(
2410                    "unsupported type C field type '{}' in '{}'",
2411                    ann.to_type_string(),
2412                    struct_name
2413                ),
2414                location: Some(self.span_to_source_location(span)),
2415            })
2416        };
2417
2418        if let Some(name) = ann.as_type_name_str() {
2419                if let Some(existing) = self
2420                    .program
2421                    .native_struct_layouts
2422                    .iter()
2423                    .find(|layout| layout.name == name)
2424                {
2425                    return Ok(NativeFieldLayoutSpec {
2426                        c_type: name.to_string(),
2427                        size: existing.size as u64,
2428                        align: existing.align as u64,
2429                    });
2430                }
2431
2432                let spec = match name {
2433                    "f64" | "number" | "Number" | "float" => ("f64", 8, 8),
2434                    "f32" => ("f32", 4, 4),
2435                    "i64" | "int" | "integer" | "Int" | "Integer" => ("i64", 8, 8),
2436                    "i32" => ("i32", 4, 4),
2437                    "i16" => ("i16", 2, 2),
2438                    "i8" | "char" => ("i8", 1, 1),
2439                    "u64" => ("u64", 8, 8),
2440                    "u32" => ("u32", 4, 4),
2441                    "u16" => ("u16", 2, 2),
2442                    "u8" | "byte" => ("u8", 1, 1),
2443                    "bool" | "boolean" => ("bool", 1, 1),
2444                    "isize" => ("isize", pointer, pointer),
2445                    "usize" | "ptr" | "pointer" => ("ptr", pointer, pointer),
2446                    "string" | "str" | "cstring" => ("cstring", pointer, pointer),
2447                    _ => return fail(),
2448                };
2449                return Ok(NativeFieldLayoutSpec {
2450                    c_type: spec.0.to_string(),
2451                    size: spec.1,
2452                    align: spec.2,
2453                });
2454        }
2455        match ann {
2456            TypeAnnotation::Generic { name, args } if name == "Option" && args.len() == 1 => {
2457                let inner = self.native_field_layout_spec(&args[0], span, struct_name)?;
2458                if inner.c_type == "cstring" {
2459                    Ok(NativeFieldLayoutSpec {
2460                        c_type: "cstring?".to_string(),
2461                        size: pointer,
2462                        align: pointer,
2463                    })
2464                } else {
2465                    fail()
2466                }
2467            }
2468            _ => fail(),
2469        }
2470    }
2471
2472    fn maybe_generate_native_type_conversions(
2473        &mut self,
2474        type_name: &str,
2475        span: shape_ast::ast::Span,
2476    ) -> Result<()> {
2477        let pair = if self.native_layout_types.contains(type_name) {
2478            let Some(object_type) = Self::object_type_name_for_native_layout(type_name) else {
2479                return Ok(());
2480            };
2481            if !self.struct_types.contains_key(&object_type)
2482                || self.native_layout_types.contains(&object_type)
2483            {
2484                return Ok(());
2485            }
2486            (type_name.to_string(), object_type)
2487        } else {
2488            let candidates: Vec<String> = Self::native_layout_name_candidates_for_object(type_name)
2489                .into_iter()
2490                .filter(|candidate| self.native_layout_types.contains(candidate))
2491                .collect();
2492            if candidates.is_empty() {
2493                return Ok(());
2494            }
2495            if candidates.len() > 1 {
2496                return Err(ShapeError::SemanticError {
2497                    message: format!(
2498                        "type '{}' matches multiple `type C` companions ({}) - use one canonical name",
2499                        type_name,
2500                        candidates.join(", ")
2501                    ),
2502                    location: Some(self.span_to_source_location(span)),
2503                });
2504            }
2505            (candidates[0].clone(), type_name.to_string())
2506        };
2507
2508        let pair_key = format!("{}::{}", pair.0, pair.1);
2509        if self.generated_native_conversion_pairs.contains(&pair_key) {
2510            return Ok(());
2511        }
2512
2513        self.validate_native_conversion_pair(&pair.0, &pair.1, span)?;
2514        self.generate_native_conversion_direction(&pair.0, &pair.1, span)?;
2515        self.generate_native_conversion_direction(&pair.1, &pair.0, span)?;
2516        self.generated_native_conversion_pairs.insert(pair_key);
2517        Ok(())
2518    }
2519
2520    fn object_type_name_for_native_layout(name: &str) -> Option<String> {
2521        if let Some(base) = name.strip_suffix("Layout")
2522            && !base.is_empty()
2523        {
2524            return Some(base.to_string());
2525        }
2526        if let Some(base) = name.strip_suffix('C')
2527            && !base.is_empty()
2528        {
2529            return Some(base.to_string());
2530        }
2531        if let Some(base) = name.strip_prefix('C')
2532            && !base.is_empty()
2533            && base
2534                .chars()
2535                .next()
2536                .map(|ch| ch.is_ascii_uppercase())
2537                .unwrap_or(false)
2538        {
2539            return Some(base.to_string());
2540        }
2541        None
2542    }
2543
2544    fn native_layout_name_candidates_for_object(name: &str) -> Vec<String> {
2545        vec![
2546            format!("{}Layout", name),
2547            format!("{}C", name),
2548            format!("C{}", name),
2549        ]
2550    }
2551
2552    fn validate_native_conversion_pair(
2553        &self,
2554        c_type: &str,
2555        object_type: &str,
2556        span: shape_ast::ast::Span,
2557    ) -> Result<()> {
2558        if !self.native_layout_types.contains(c_type) {
2559            return Err(ShapeError::SemanticError {
2560                message: format!("'{}' is not declared as `type C`", c_type),
2561                location: Some(self.span_to_source_location(span)),
2562            });
2563        }
2564        if self.native_layout_types.contains(object_type) {
2565            return Err(ShapeError::SemanticError {
2566                message: format!(
2567                    "auto conversion target '{}' cannot also be declared as `type C`",
2568                    object_type
2569                ),
2570                location: Some(self.span_to_source_location(span)),
2571            });
2572        }
2573
2574        let c_type_info =
2575            self.struct_generic_info
2576                .get(c_type)
2577                .ok_or_else(|| ShapeError::SemanticError {
2578                    message: format!("missing compiler metadata for `type C {}`", c_type),
2579                    location: Some(self.span_to_source_location(span)),
2580                })?;
2581        let object_type_info =
2582            self.struct_generic_info
2583                .get(object_type)
2584                .ok_or_else(|| ShapeError::SemanticError {
2585                    message: format!(
2586                        "missing compiler metadata for companion type '{}'",
2587                        object_type
2588                    ),
2589                    location: Some(self.span_to_source_location(span)),
2590                })?;
2591
2592        if !c_type_info.type_params.is_empty() || !object_type_info.type_params.is_empty() {
2593            return Err(ShapeError::SemanticError {
2594                message: format!(
2595                    "auto `type C` conversions currently require non-generic types (`{}` <-> `{}`)",
2596                    c_type, object_type
2597                ),
2598                location: Some(self.span_to_source_location(span)),
2599            });
2600        }
2601
2602        let c_fields = self
2603            .struct_types
2604            .get(c_type)
2605            .map(|(fields, _)| fields)
2606            .ok_or_else(|| ShapeError::SemanticError {
2607                message: format!("missing field metadata for `type C {}`", c_type),
2608                location: Some(self.span_to_source_location(span)),
2609            })?;
2610        let object_fields = self
2611            .struct_types
2612            .get(object_type)
2613            .map(|(fields, _)| fields)
2614            .ok_or_else(|| ShapeError::SemanticError {
2615                message: format!(
2616                    "missing field metadata for companion type '{}'",
2617                    object_type
2618                ),
2619                location: Some(self.span_to_source_location(span)),
2620            })?;
2621
2622        let c_field_set: std::collections::HashSet<&str> =
2623            c_fields.iter().map(String::as_str).collect();
2624        let object_field_set: std::collections::HashSet<&str> =
2625            object_fields.iter().map(String::as_str).collect();
2626        if c_field_set != object_field_set {
2627            return Err(ShapeError::SemanticError {
2628                message: format!(
2629                    "auto conversion pair '{}' <-> '{}' must have identical runtime fields",
2630                    c_type, object_type
2631                ),
2632                location: Some(self.span_to_source_location(span)),
2633            });
2634        }
2635
2636        for field_name in c_field_set {
2637            let c_ann = c_type_info
2638                .runtime_field_types
2639                .get(field_name)
2640                .ok_or_else(|| ShapeError::SemanticError {
2641                    message: format!(
2642                        "missing type metadata for field '{}.{}'",
2643                        c_type, field_name
2644                    ),
2645                    location: Some(self.span_to_source_location(span)),
2646                })?;
2647            let object_ann = object_type_info
2648                .runtime_field_types
2649                .get(field_name)
2650                .ok_or_else(|| ShapeError::SemanticError {
2651                    message: format!(
2652                        "missing type metadata for field '{}.{}'",
2653                        object_type, field_name
2654                    ),
2655                    location: Some(self.span_to_source_location(span)),
2656                })?;
2657            if c_ann != object_ann {
2658                return Err(ShapeError::SemanticError {
2659                    message: format!(
2660                        "field type mismatch for auto conversion '{}.{}' (`{}`) vs '{}.{}' (`{}`)",
2661                        c_type,
2662                        field_name,
2663                        c_ann.to_type_string(),
2664                        object_type,
2665                        field_name,
2666                        object_ann.to_type_string()
2667                    ),
2668                    location: Some(self.span_to_source_location(span)),
2669                });
2670            }
2671        }
2672
2673        Ok(())
2674    }
2675
2676    fn generate_native_conversion_direction(
2677        &mut self,
2678        source_type: &str,
2679        target_type: &str,
2680        span: shape_ast::ast::Span,
2681    ) -> Result<()> {
2682        let fn_name = format!(
2683            "__auto_native_from_{}_to_{}",
2684            Self::sanitize_auto_symbol(source_type),
2685            Self::sanitize_auto_symbol(target_type)
2686        );
2687        if self.function_defs.contains_key(&fn_name) {
2688            return Ok(());
2689        }
2690
2691        let target_fields = self
2692            .struct_types
2693            .get(target_type)
2694            .map(|(fields, _)| fields.clone())
2695            .ok_or_else(|| ShapeError::SemanticError {
2696                message: format!(
2697                    "missing target type metadata for auto conversion '{}'",
2698                    target_type
2699                ),
2700                location: Some(self.span_to_source_location(span)),
2701            })?;
2702
2703        let source_expr = Expr::Identifier("value".to_string(), span);
2704        let struct_fields = target_fields
2705            .iter()
2706            .map(|field| {
2707                (
2708                    field.clone(),
2709                    Expr::PropertyAccess {
2710                        object: Box::new(source_expr.clone()),
2711                        property: field.clone(),
2712                        optional: false,
2713                        span,
2714                    },
2715                )
2716            })
2717            .collect::<Vec<_>>();
2718        let body = vec![Statement::Return(
2719            Some(Expr::StructLiteral {
2720                type_name: target_type.into(),
2721                fields: struct_fields,
2722                span,
2723            }),
2724            span,
2725        )];
2726        let fn_def = FunctionDef {
2727            name: fn_name.clone(),
2728            name_span: span,
2729            declaring_module_path: None,
2730            doc_comment: None,
2731            params: vec![FunctionParameter {
2732                pattern: DestructurePattern::Identifier("value".to_string(), span),
2733                is_const: false,
2734                is_reference: false,
2735                is_mut_reference: false,
2736                is_out: false,
2737                type_annotation: Some(TypeAnnotation::Reference(source_type.into())),
2738                default_value: None,
2739            }],
2740            return_type: Some(TypeAnnotation::Reference(target_type.into())),
2741            body,
2742            type_params: Some(Vec::new()),
2743            annotations: Vec::new(),
2744            is_async: false,
2745            is_comptime: false,
2746            where_clause: None,
2747        };
2748        self.register_function(&fn_def)?;
2749        self.compile_function(&fn_def)?;
2750
2751        self.program.register_trait_method_symbol(
2752            "From",
2753            target_type,
2754            Some(source_type),
2755            "from",
2756            &fn_name,
2757        );
2758        self.program.register_trait_method_symbol(
2759            "Into",
2760            source_type,
2761            Some(target_type),
2762            "into",
2763            &fn_name,
2764        );
2765        let _ = self.type_inference.env.register_trait_impl_named(
2766            "From",
2767            target_type,
2768            source_type,
2769            vec!["from".to_string()],
2770        );
2771        let _ = self.type_inference.env.register_trait_impl_named(
2772            "Into",
2773            source_type,
2774            target_type,
2775            vec!["into".to_string()],
2776        );
2777        Ok(())
2778    }
2779
2780    fn sanitize_auto_symbol(name: &str) -> String {
2781        let mut out = String::with_capacity(name.len());
2782        for ch in name.chars() {
2783            if ch.is_ascii_alphanumeric() {
2784                out.push(ch);
2785            } else {
2786                out.push('_');
2787            }
2788        }
2789        out
2790    }
2791
2792    /// Execute comptime annotation handlers for a struct type definition.
2793    ///
2794    /// Mirrors `execute_comptime_handlers` in functions.rs but uses
2795    /// `ComptimeTarget::from_type()` to build the target from struct fields.
2796    fn execute_struct_comptime_handlers(
2797        &mut self,
2798        struct_def: &shape_ast::ast::StructTypeDef,
2799    ) -> Result<bool> {
2800        let mut removed = false;
2801        for ann in &struct_def.annotations {
2802            if let Some((_, compiled)) = self.lookup_compiled_annotation(ann) {
2803                let handlers = [
2804                    compiled.comptime_pre_handler,
2805                    compiled.comptime_post_handler,
2806                ];
2807                for handler in handlers.into_iter().flatten() {
2808                    // Build field info for ComptimeTarget::from_type()
2809                    // Include per-field annotations so comptime handlers can inspect them.
2810                    let fields: Vec<(
2811                        String,
2812                        Option<shape_ast::ast::TypeAnnotation>,
2813                        Vec<shape_ast::ast::functions::Annotation>,
2814                    )> = struct_def
2815                        .fields
2816                        .iter()
2817                        .map(|f| {
2818                            (
2819                                f.name.clone(),
2820                                Some(f.type_annotation.clone()),
2821                                f.annotations.clone(),
2822                            )
2823                        })
2824                        .collect();
2825
2826                    let target = super::comptime_target::ComptimeTarget::from_type(
2827                        &struct_def.name,
2828                        &fields,
2829                    );
2830                    let target_value = target.to_nanboxed();
2831                    let target_name = struct_def.name.clone();
2832                    let handler_span = handler.span;
2833                    let execution = self.execute_comptime_annotation_handler(
2834                        ann,
2835                        &handler,
2836                        target_value,
2837                        &compiled.param_names,
2838                        &[],
2839                    )?;
2840
2841                    if self
2842                        .process_comptime_directives(execution.directives, &target_name)
2843                        .map_err(|e| ShapeError::RuntimeError {
2844                            message: format!(
2845                                "Comptime handler '{}' directive processing failed: {}",
2846                                ann.name, e
2847                            ),
2848                            location: Some(self.span_to_source_location(handler_span)),
2849                        })?
2850                    {
2851                        removed = true;
2852                        break;
2853                    }
2854                }
2855            }
2856            if removed {
2857                break;
2858            }
2859        }
2860        Ok(removed)
2861    }
2862
2863    fn current_module_path_for(&self, module_name: &str) -> String {
2864        if let Some(parent) = self.module_scope_stack.last() {
2865            format!("{}::{}", parent, module_name)
2866        } else {
2867            module_name.to_string()
2868        }
2869    }
2870
2871    pub(super) fn qualify_module_symbol(module_path: &str, name: &str) -> String {
2872        format!("{}::{}", module_path, name)
2873    }
2874
2875    /// Returns true if a name refers to a builtin/primitive type that should
2876    /// not be module-qualified.
2877    fn is_builtin_type_name(name: &str) -> bool {
2878        matches!(
2879            name,
2880            "int" | "number" | "string" | "bool" | "decimal" | "bigint"
2881                | "Array" | "HashMap" | "Option" | "Result" | "DateTime"
2882                | "Content" | "Table" | "DataTable" | "Mat"
2883                | "Json" | "Duration" | "Regex"
2884                | "Vec"
2885                | "int8" | "int16" | "int32" | "int64"
2886                | "uint8" | "uint16" | "uint32" | "uint64"
2887                | "float32" | "float64"
2888                | "IoHandle"
2889        )
2890    }
2891
2892    fn qualify_type_name(
2893        type_name: &shape_ast::ast::TypeName,
2894        module_path: &str,
2895    ) -> shape_ast::ast::TypeName {
2896        match type_name {
2897            shape_ast::ast::TypeName::Simple(path)
2898                if !path.is_qualified() && !Self::is_builtin_type_name(path.as_str()) =>
2899            {
2900                shape_ast::ast::TypeName::Simple(
2901                    Self::qualify_module_symbol(module_path, path.as_str()).into(),
2902                )
2903            }
2904            shape_ast::ast::TypeName::Generic { name, type_args }
2905                if !name.is_qualified() && !Self::is_builtin_type_name(name.as_str()) =>
2906            {
2907                shape_ast::ast::TypeName::Generic {
2908                    name: Self::qualify_module_symbol(module_path, name.as_str()).into(),
2909                    type_args: type_args.clone(),
2910                }
2911            }
2912            _ => type_name.clone(),
2913        }
2914    }
2915
2916    pub(super) fn qualify_module_item(&self, item: &Item, module_path: &str) -> Result<Item> {
2917        match item {
2918            Item::Function(func, span) => {
2919                let mut qualified = func.clone();
2920                qualified.name = Self::qualify_module_symbol(module_path, &func.name);
2921                Ok(Item::Function(qualified, *span))
2922            }
2923            Item::Export(export, span) if export.source_decl.is_none() => {
2924                let mut qualified = export.clone();
2925                match &mut qualified.item {
2926                    ExportItem::Function(func) => {
2927                        func.name = Self::qualify_module_symbol(module_path, &func.name);
2928                    }
2929                    ExportItem::BuiltinFunction(func) => {
2930                        func.name = Self::qualify_module_symbol(module_path, &func.name);
2931                    }
2932                    ExportItem::ForeignFunction(func) => {
2933                        func.name = Self::qualify_module_symbol(module_path, &func.name);
2934                    }
2935                    ExportItem::Annotation(annotation) => {
2936                        annotation.name =
2937                            Self::qualify_module_symbol(module_path, &annotation.name);
2938                    }
2939                    ExportItem::Struct(def) => {
2940                        def.name = Self::qualify_module_symbol(module_path, &def.name);
2941                    }
2942                    ExportItem::Enum(def) => {
2943                        def.name = Self::qualify_module_symbol(module_path, &def.name);
2944                    }
2945                    ExportItem::TypeAlias(def) => {
2946                        def.name = Self::qualify_module_symbol(module_path, &def.name);
2947                    }
2948                    ExportItem::Trait(def) => {
2949                        def.name = Self::qualify_module_symbol(module_path, &def.name);
2950                    }
2951                    ExportItem::Interface(def) => {
2952                        def.name = Self::qualify_module_symbol(module_path, &def.name);
2953                    }
2954                    _ => {}
2955                }
2956                Ok(Item::Export(qualified, *span))
2957            }
2958            Item::BuiltinFunctionDecl(def, span) => {
2959                let mut qualified = def.clone();
2960                qualified.name = Self::qualify_module_symbol(module_path, &def.name);
2961                Ok(Item::BuiltinFunctionDecl(qualified, *span))
2962            }
2963            Item::AnnotationDef(def, span) => {
2964                let mut qualified = def.clone();
2965                qualified.name = Self::qualify_module_symbol(module_path, &def.name);
2966                Ok(Item::AnnotationDef(qualified, *span))
2967            }
2968            Item::VariableDecl(decl, span) => {
2969                if decl.kind != VarKind::Const {
2970                    return Err(ShapeError::SemanticError {
2971                        message: "module-level variable declarations currently require `const`"
2972                            .to_string(),
2973                        location: Some(self.span_to_source_location(*span)),
2974                    });
2975                }
2976                let mut qualified = decl.clone();
2977                let Some(name) = decl.pattern.as_identifier() else {
2978                    return Err(ShapeError::SemanticError {
2979                        message:
2980                            "module-level constants currently require a simple identifier binding"
2981                                .to_string(),
2982                        location: Some(self.span_to_source_location(*span)),
2983                    });
2984                };
2985                qualified.pattern = DestructurePattern::Identifier(
2986                    Self::qualify_module_symbol(module_path, name),
2987                    *span,
2988                );
2989                Ok(Item::VariableDecl(qualified, *span))
2990            }
2991            Item::Statement(Statement::VariableDecl(decl, stmt_span), item_span) => {
2992                if decl.kind != VarKind::Const {
2993                    return Err(ShapeError::SemanticError {
2994                        message: "module-level variable declarations currently require `const`"
2995                            .to_string(),
2996                        location: Some(self.span_to_source_location(*stmt_span)),
2997                    });
2998                }
2999                let mut qualified = decl.clone();
3000                let Some(name) = decl.pattern.as_identifier() else {
3001                    return Err(ShapeError::SemanticError {
3002                        message:
3003                            "module-level constants currently require a simple identifier binding"
3004                                .to_string(),
3005                        location: Some(self.span_to_source_location(*stmt_span)),
3006                    });
3007                };
3008                qualified.pattern = DestructurePattern::Identifier(
3009                    Self::qualify_module_symbol(module_path, name),
3010                    *stmt_span,
3011                );
3012                Ok(Item::Statement(
3013                    Statement::VariableDecl(qualified, *stmt_span),
3014                    *item_span,
3015                ))
3016            }
3017            Item::Statement(Statement::Assignment(assign, stmt_span), item_span) => {
3018                let mut qualified = assign.clone();
3019                if let Some(name) = assign.pattern.as_identifier() {
3020                    qualified.pattern = DestructurePattern::Identifier(
3021                        Self::qualify_module_symbol(module_path, name),
3022                        *stmt_span,
3023                    );
3024                }
3025                Ok(Item::Statement(
3026                    Statement::Assignment(qualified, *stmt_span),
3027                    *item_span,
3028                ))
3029            }
3030            Item::Export(export, span) if export.source_decl.is_some() => {
3031                // pub const/let/var: unwrap the source_decl and qualify it as a VariableDecl
3032                let decl = export.source_decl.as_ref().unwrap();
3033                if decl.kind != VarKind::Const {
3034                    return Err(ShapeError::SemanticError {
3035                        message: "module-level variable declarations currently require `const`"
3036                            .to_string(),
3037                        location: Some(self.span_to_source_location(*span)),
3038                    });
3039                }
3040                let mut qualified = decl.clone();
3041                let Some(name) = decl.pattern.as_identifier() else {
3042                    return Err(ShapeError::SemanticError {
3043                        message:
3044                            "module-level constants currently require a simple identifier binding"
3045                                .to_string(),
3046                        location: Some(self.span_to_source_location(*span)),
3047                    });
3048                };
3049                qualified.pattern = DestructurePattern::Identifier(
3050                    Self::qualify_module_symbol(module_path, name),
3051                    *span,
3052                );
3053                Ok(Item::VariableDecl(qualified, *span))
3054            }
3055            Item::StructType(def, span) => {
3056                let mut q = def.clone();
3057                q.name = Self::qualify_module_symbol(module_path, &def.name);
3058                Ok(Item::StructType(q, *span))
3059            }
3060            Item::Enum(def, span) => {
3061                let mut q = def.clone();
3062                q.name = Self::qualify_module_symbol(module_path, &def.name);
3063                Ok(Item::Enum(q, *span))
3064            }
3065            Item::TypeAlias(def, span) => {
3066                let mut q = def.clone();
3067                q.name = Self::qualify_module_symbol(module_path, &def.name);
3068                Ok(Item::TypeAlias(q, *span))
3069            }
3070            Item::Trait(def, span) => {
3071                let mut q = def.clone();
3072                q.name = Self::qualify_module_symbol(module_path, &def.name);
3073                Ok(Item::Trait(q, *span))
3074            }
3075            Item::Interface(def, span) => {
3076                let mut q = def.clone();
3077                q.name = Self::qualify_module_symbol(module_path, &def.name);
3078                Ok(Item::Interface(q, *span))
3079            }
3080            Item::Extend(extend, span) => {
3081                let mut q = extend.clone();
3082                q.type_name = Self::qualify_type_name(&extend.type_name, module_path);
3083                Ok(Item::Extend(q, *span))
3084            }
3085            Item::Impl(impl_block, span) => {
3086                let mut q = impl_block.clone();
3087                q.target_type = Self::qualify_type_name(&impl_block.target_type, module_path);
3088                // Do NOT qualify trait_name — traits may be imported from other scopes
3089                Ok(Item::Impl(q, *span))
3090            }
3091            _ => Ok(item.clone()),
3092        }
3093    }
3094
3095    pub(super) fn collect_module_runtime_exports(
3096        &self,
3097        items: &[Item],
3098        module_path: &str,
3099    ) -> Vec<(String, String)> {
3100        let mut exports = Vec::new();
3101        let has_explicit_exports = items.iter().any(|item| matches!(item, Item::Export(..)));
3102
3103        if has_explicit_exports {
3104            for item in items {
3105                let Item::Export(export, _) = item else {
3106                    continue;
3107                };
3108                if let Some(ref decl) = export.source_decl {
3109                    if let Some(name) = decl.pattern.as_identifier() {
3110                        exports.push((
3111                            name.to_string(),
3112                            Self::qualify_module_symbol(module_path, name),
3113                        ));
3114                    }
3115                }
3116                match &export.item {
3117                    ExportItem::Function(func) => {
3118                        let exported_name = func
3119                            .name
3120                            .rsplit("::")
3121                            .next()
3122                            .unwrap_or(func.name.as_str())
3123                            .to_string();
3124                        exports.push((
3125                            exported_name.clone(),
3126                            Self::qualify_module_symbol(module_path, &exported_name),
3127                        ));
3128                    }
3129                    ExportItem::ForeignFunction(func) => {
3130                        let exported_name = func
3131                            .name
3132                            .rsplit("::")
3133                            .next()
3134                            .unwrap_or(func.name.as_str())
3135                            .to_string();
3136                        exports.push((
3137                            exported_name.clone(),
3138                            Self::qualify_module_symbol(module_path, &exported_name),
3139                        ));
3140                    }
3141                    ExportItem::Named(specs) => {
3142                        for spec in specs {
3143                            let exported_name =
3144                                spec.alias.clone().unwrap_or_else(|| spec.name.clone());
3145                            exports.push((
3146                                exported_name,
3147                                Self::qualify_module_symbol(module_path, &spec.name),
3148                            ));
3149                        }
3150                    }
3151                    // H4: Include exported annotations as named exports
3152                    ExportItem::Annotation(ann_def) => {
3153                        exports.push((
3154                            ann_def.name.clone(),
3155                            Self::qualify_module_symbol(module_path, &ann_def.name),
3156                        ));
3157                    }
3158                    _ => {}
3159                }
3160            }
3161            exports.sort_by(|a, b| a.0.cmp(&b.0));
3162            exports.dedup_by(|a, b| a.0 == b.0);
3163            return exports;
3164        }
3165
3166        for item in items {
3167            match item {
3168                Item::Function(func, _) => {
3169                    exports.push((
3170                        func.name.clone(),
3171                        Self::qualify_module_symbol(module_path, &func.name),
3172                    ));
3173                }
3174                Item::VariableDecl(decl, _) => {
3175                    if decl.kind == VarKind::Const
3176                        && let Some(name) = decl.pattern.as_identifier()
3177                    {
3178                        exports.push((
3179                            name.to_string(),
3180                            Self::qualify_module_symbol(module_path, name),
3181                        ));
3182                    }
3183                }
3184                Item::Statement(Statement::VariableDecl(decl, _), _) => {
3185                    if decl.kind == VarKind::Const
3186                        && let Some(name) = decl.pattern.as_identifier()
3187                    {
3188                        exports.push((
3189                            name.to_string(),
3190                            Self::qualify_module_symbol(module_path, name),
3191                        ));
3192                    }
3193                }
3194                Item::Export(export, _) => {
3195                    if let Some(ref decl) = export.source_decl {
3196                        if let Some(name) = decl.pattern.as_identifier() {
3197                            exports.push((
3198                                name.to_string(),
3199                                Self::qualify_module_symbol(module_path, name),
3200                            ));
3201                        }
3202                    }
3203                }
3204                Item::Module(module, _) => {
3205                    exports.push((
3206                        module.name.clone(),
3207                        Self::qualify_module_symbol(module_path, &module.name),
3208                    ));
3209                }
3210                // H4: Include annotation definitions as exported names
3211                Item::AnnotationDef(ann_def, _) => {
3212                    exports.push((
3213                        ann_def.name.clone(),
3214                        Self::qualify_module_symbol(module_path, &ann_def.name),
3215                    ));
3216                }
3217                // Note: Type items (StructType, Enum, TypeAlias, Trait, Interface) are NOT
3218                // included as runtime exports. They are resolved through the type system
3219                // (struct_types, schema_registry, type_aliases) via resolve_type_name(),
3220                // not through runtime module bindings.
3221                _ => {}
3222            }
3223        }
3224        exports.sort_by(|a, b| a.0.cmp(&b.0));
3225        exports.dedup_by(|a, b| a.0 == b.0);
3226        exports
3227    }
3228
3229    fn module_target_fields(items: &[Item]) -> Vec<(String, String)> {
3230        let mut fields = Vec::new();
3231        for item in items {
3232            match item {
3233                Item::Function(func, _) => fields.push((func.name.clone(), "function".to_string())),
3234                Item::VariableDecl(decl, _) => {
3235                    if let Some(name) = decl.pattern.as_identifier() {
3236                        let type_name = decl
3237                            .type_annotation
3238                            .as_ref()
3239                            .and_then(TypeAnnotation::as_simple_name)
3240                            .unwrap_or("any")
3241                            .to_string();
3242                        fields.push((name.to_string(), type_name));
3243                    }
3244                }
3245                Item::Statement(Statement::VariableDecl(decl, _), _) => {
3246                    if let Some(name) = decl.pattern.as_identifier() {
3247                        let type_name = decl
3248                            .type_annotation
3249                            .as_ref()
3250                            .and_then(TypeAnnotation::as_simple_name)
3251                            .unwrap_or("any")
3252                            .to_string();
3253                        fields.push((name.to_string(), type_name));
3254                    }
3255                }
3256                Item::Export(export, _) => {
3257                    if let Some(ref decl) = export.source_decl {
3258                        if let Some(name) = decl.pattern.as_identifier() {
3259                            let type_name = decl
3260                                .type_annotation
3261                                .as_ref()
3262                                .and_then(TypeAnnotation::as_simple_name)
3263                                .unwrap_or("any")
3264                                .to_string();
3265                            fields.push((name.to_string(), type_name));
3266                        }
3267                    }
3268                }
3269                Item::StructType(def, _) => fields.push((def.name.clone(), "type".to_string())),
3270                Item::Enum(def, _) => fields.push((def.name.clone(), "type".to_string())),
3271                Item::TypeAlias(def, _) => fields.push((def.name.clone(), "type".to_string())),
3272                Item::Module(def, _) => fields.push((def.name.clone(), "module".to_string())),
3273                // H4: Include annotation definitions in module target fields
3274                Item::AnnotationDef(def, _) => {
3275                    fields.push((def.name.clone(), "annotation".to_string()))
3276                }
3277                _ => {}
3278            }
3279        }
3280        fields
3281    }
3282
3283    fn process_comptime_directives_for_module(
3284        &mut self,
3285        directives: Vec<super::comptime_builtins::ComptimeDirective>,
3286        module_name: &str,
3287        module_items: &mut Vec<Item>,
3288    ) -> std::result::Result<bool, String> {
3289        let mut removed = false;
3290        for directive in directives {
3291            match directive {
3292                super::comptime_builtins::ComptimeDirective::Extend(extend) => {
3293                    self.apply_comptime_extend(extend, module_name)
3294                        .map_err(|e| e.to_string())?;
3295                }
3296                super::comptime_builtins::ComptimeDirective::RemoveTarget => {
3297                    removed = true;
3298                    break;
3299                }
3300                super::comptime_builtins::ComptimeDirective::ReplaceModule { items } => {
3301                    *module_items = items;
3302                }
3303                super::comptime_builtins::ComptimeDirective::SetParamType { .. }
3304                | super::comptime_builtins::ComptimeDirective::SetParamValue { .. } => {
3305                    return Err(
3306                        "`set param` directives are only valid when compiling function targets"
3307                            .to_string(),
3308                    );
3309                }
3310                super::comptime_builtins::ComptimeDirective::SetReturnType { .. } => {
3311                    return Err(
3312                        "`set return` directives are only valid when compiling function targets"
3313                            .to_string(),
3314                    );
3315                }
3316                super::comptime_builtins::ComptimeDirective::ReplaceBody { .. } => {
3317                    return Err(
3318                        "`replace body` directives are only valid when compiling function targets"
3319                            .to_string(),
3320                    );
3321                }
3322            }
3323        }
3324        Ok(removed)
3325    }
3326
3327    fn execute_module_comptime_handlers(
3328        &mut self,
3329        module_def: &ModuleDecl,
3330        module_path: &str,
3331        module_items: &mut Vec<Item>,
3332    ) -> Result<bool> {
3333        let mut removed = false;
3334        for ann in &module_def.annotations {
3335            if let Some((_, compiled)) = self.lookup_compiled_annotation(ann) {
3336                let handlers = [
3337                    compiled.comptime_pre_handler,
3338                    compiled.comptime_post_handler,
3339                ];
3340                for handler in handlers.into_iter().flatten() {
3341                    let target = super::comptime_target::ComptimeTarget::from_module(
3342                        module_path,
3343                        &Self::module_target_fields(module_items),
3344                    );
3345                    let target_value = target.to_nanboxed();
3346                    let handler_span = handler.span;
3347                    let execution = self.execute_comptime_annotation_handler(
3348                        ann,
3349                        &handler,
3350                        target_value,
3351                        &compiled.param_names,
3352                        &[],
3353                    )?;
3354                    if self
3355                        .process_comptime_directives_for_module(
3356                            execution.directives,
3357                            module_path,
3358                            module_items,
3359                        )
3360                        .map_err(|e| ShapeError::RuntimeError {
3361                            message: format!(
3362                                "Comptime handler '{}' directive processing failed: {}",
3363                                ann.name, e
3364                            ),
3365                            location: Some(self.span_to_source_location(handler_span)),
3366                        })?
3367                    {
3368                        removed = true;
3369                        break;
3370                    }
3371                }
3372            }
3373            if removed {
3374                break;
3375            }
3376        }
3377        Ok(removed)
3378    }
3379
3380    fn inject_module_local_comptime_helper_aliases(
3381        &self,
3382        module_path: &str,
3383        helpers: &mut Vec<FunctionDef>,
3384    ) {
3385        let module_prefix = format!("{}::", module_path);
3386        let mut seen: std::collections::HashSet<String> =
3387            helpers.iter().map(|h| h.name.clone()).collect();
3388        let mut aliases = Vec::new();
3389
3390        for helper in helpers.iter() {
3391            let Some(local_name) = helper.name.strip_prefix(&module_prefix) else {
3392                continue;
3393            };
3394            if local_name.contains("::") || !seen.insert(local_name.to_string()) {
3395                continue;
3396            }
3397            let mut alias = helper.clone();
3398            alias.name = local_name.to_string();
3399            aliases.push(alias);
3400        }
3401
3402        helpers.extend(aliases);
3403    }
3404
3405    fn execute_module_inline_comptime_blocks(
3406        &mut self,
3407        module_path: &str,
3408        module_items: &mut Vec<Item>,
3409    ) -> Result<bool> {
3410        loop {
3411            let Some(idx) = module_items
3412                .iter()
3413                .position(|item| matches!(item, Item::Comptime(_, _)))
3414            else {
3415                break;
3416            };
3417
3418            let (stmts, span) = match module_items[idx].clone() {
3419                Item::Comptime(stmts, span) => (stmts, span),
3420                _ => unreachable!("index is guarded by position() matcher"),
3421            };
3422
3423            let extensions: Vec<_> = self
3424                .extension_registry
3425                .as_ref()
3426                .map(|r| r.as_ref().clone())
3427                .unwrap_or_default();
3428            let trait_impls = self.type_inference.env.trait_impl_keys();
3429            let known_type_symbols: std::collections::HashSet<String> = self
3430                .struct_types
3431                .keys()
3432                .chain(self.type_aliases.keys())
3433                .cloned()
3434                .collect();
3435            let mut comptime_helpers = self.collect_comptime_helpers();
3436            self.inject_module_local_comptime_helper_aliases(module_path, &mut comptime_helpers);
3437
3438            let execution = super::comptime::execute_comptime(
3439                &stmts,
3440                &comptime_helpers,
3441                &extensions,
3442                trait_impls,
3443                known_type_symbols,
3444            )
3445            .map_err(|e| ShapeError::RuntimeError {
3446                message: format!(
3447                    "Comptime block evaluation failed: {}",
3448                    super::helpers::strip_error_prefix(&e)
3449                ),
3450                location: Some(self.span_to_source_location(span)),
3451            })?;
3452
3453            if self
3454                .process_comptime_directives_for_module(
3455                    execution.directives,
3456                    module_path,
3457                    module_items,
3458                )
3459                .map_err(|e| ShapeError::RuntimeError {
3460                    message: format!("Comptime block directive processing failed: {}", e),
3461                    location: Some(self.span_to_source_location(span)),
3462                })?
3463            {
3464                return Ok(true);
3465            }
3466
3467            if idx < module_items.len() && matches!(module_items[idx], Item::Comptime(_, _)) {
3468                module_items.remove(idx);
3469            }
3470        }
3471
3472        Ok(false)
3473    }
3474
3475    pub(super) fn register_missing_module_items(&mut self, item: &Item) -> Result<()> {
3476        match item {
3477            Item::Function(func, _) => {
3478                if !self.function_defs.contains_key(&func.name) {
3479                    self.register_function(func)?;
3480                }
3481                Ok(())
3482            }
3483            Item::Trait(trait_def, _) => {
3484                if !self.trait_defs.contains_key(&trait_def.name) {
3485                    self.known_traits.insert(trait_def.name.clone());
3486                    self.trait_defs
3487                        .insert(trait_def.name.clone(), trait_def.clone());
3488                    self.type_inference.env.define_trait(trait_def);
3489                }
3490                Ok(())
3491            }
3492            Item::Enum(enum_def, _) => {
3493                self.register_enum(enum_def)?;
3494                Ok(())
3495            }
3496            Item::StructType(struct_def, span) => {
3497                // Pre-declare struct type layout without running full
3498                // register_struct_type (which does annotation validation,
3499                // comptime handlers, native layout, and schema registration).
3500                // This makes the type name resolvable for forward references
3501                // during first-pass registration.
3502                if !self.struct_types.contains_key(&struct_def.name) {
3503                    let runtime_field_names: Vec<String> = struct_def
3504                        .fields
3505                        .iter()
3506                        .filter(|f| !f.is_comptime)
3507                        .map(|f| f.name.clone())
3508                        .collect();
3509                    let runtime_field_types = struct_def
3510                        .fields
3511                        .iter()
3512                        .filter(|f| !f.is_comptime)
3513                        .map(|f| (f.name.clone(), f.type_annotation.clone()))
3514                        .collect::<std::collections::HashMap<_, _>>();
3515                    self.struct_types.insert(
3516                        struct_def.name.clone(),
3517                        (runtime_field_names, *span),
3518                    );
3519                    self.struct_generic_info.insert(
3520                        struct_def.name.clone(),
3521                        StructGenericInfo {
3522                            type_params: struct_def.type_params.clone().unwrap_or_default(),
3523                            runtime_field_types,
3524                        },
3525                    );
3526                }
3527                Ok(())
3528            }
3529            Item::TypeAlias(type_alias, _) => {
3530                if !self.type_aliases.contains_key(&type_alias.name) {
3531                    let base_type_name = match &type_alias.type_annotation {
3532                        TypeAnnotation::Basic(name) => Some(name.clone()),
3533                        TypeAnnotation::Reference(name) => Some(name.to_string()),
3534                        _ => None,
3535                    };
3536                    self.type_aliases.insert(
3537                        type_alias.name.clone(),
3538                        base_type_name.unwrap_or_else(|| {
3539                            format!("{:?}", type_alias.type_annotation)
3540                        }),
3541                    );
3542                    self.type_inference.env.define_type_alias(
3543                        &type_alias.name,
3544                        &type_alias.type_annotation,
3545                        type_alias.meta_param_overrides.clone(),
3546                    );
3547                }
3548                Ok(())
3549            }
3550            Item::BuiltinFunctionDecl(def, _) => {
3551                self.register_builtin_function_decl(def)
3552            }
3553            Item::ForeignFunction(def, _) => {
3554                if !self.function_defs.contains_key(&def.name) {
3555                    // Register arity + foreign def (same as register_item_functions)
3556                    let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
3557                    self.function_arity_bounds
3558                        .insert(def.name.clone(), (caller_visible, caller_visible));
3559                    self.function_const_params
3560                        .insert(def.name.clone(), Vec::new());
3561                    self.foreign_function_defs
3562                        .insert(def.name.clone(), def.clone());
3563                }
3564                Ok(())
3565            }
3566            Item::Export(export, _) => match &export.item {
3567                ExportItem::Function(func) => {
3568                    if !self.function_defs.contains_key(&func.name) {
3569                        self.register_function(func)?;
3570                    }
3571                    Ok(())
3572                }
3573                ExportItem::Trait(trait_def) => {
3574                    if !self.trait_defs.contains_key(&trait_def.name) {
3575                        self.known_traits.insert(trait_def.name.clone());
3576                        self.trait_defs
3577                            .insert(trait_def.name.clone(), trait_def.clone());
3578                        self.type_inference.env.define_trait(trait_def);
3579                    }
3580                    Ok(())
3581                }
3582                ExportItem::Enum(enum_def) => {
3583                    self.register_enum(enum_def)?;
3584                    Ok(())
3585                }
3586                ExportItem::Struct(struct_def) => {
3587                    // Pre-declare only — full registration happens in second pass
3588                    if !self.struct_types.contains_key(&struct_def.name) {
3589                        let runtime_field_names: Vec<String> = struct_def
3590                            .fields
3591                            .iter()
3592                            .filter(|f| !f.is_comptime)
3593                            .map(|f| f.name.clone())
3594                            .collect();
3595                        let runtime_field_types = struct_def
3596                            .fields
3597                            .iter()
3598                            .filter(|f| !f.is_comptime)
3599                            .map(|f| (f.name.clone(), f.type_annotation.clone()))
3600                            .collect::<std::collections::HashMap<_, _>>();
3601                        self.struct_types.insert(
3602                            struct_def.name.clone(),
3603                            (runtime_field_names, Span::DUMMY),
3604                        );
3605                        self.struct_generic_info.insert(
3606                            struct_def.name.clone(),
3607                            StructGenericInfo {
3608                                type_params: struct_def.type_params.clone().unwrap_or_default(),
3609                                runtime_field_types,
3610                            },
3611                        );
3612                    }
3613                    Ok(())
3614                }
3615                ExportItem::TypeAlias(type_alias) => {
3616                    if !self.type_aliases.contains_key(&type_alias.name) {
3617                        let base_type_name = match &type_alias.type_annotation {
3618                            TypeAnnotation::Basic(name) => Some(name.clone()),
3619                            TypeAnnotation::Reference(name) => Some(name.to_string()),
3620                            _ => None,
3621                        };
3622                        self.type_aliases.insert(
3623                            type_alias.name.clone(),
3624                            base_type_name.unwrap_or_else(|| {
3625                                format!("{:?}", type_alias.type_annotation)
3626                            }),
3627                        );
3628                        self.type_inference.env.define_type_alias(
3629                            &type_alias.name,
3630                            &type_alias.type_annotation,
3631                            type_alias.meta_param_overrides.clone(),
3632                        );
3633                    }
3634                    Ok(())
3635                }
3636                ExportItem::BuiltinFunction(def) => {
3637                    self.register_builtin_function_decl(def)
3638                }
3639                ExportItem::ForeignFunction(def) => {
3640                    if !self.function_defs.contains_key(&def.name) {
3641                        let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
3642                        self.function_arity_bounds
3643                            .insert(def.name.clone(), (caller_visible, caller_visible));
3644                        self.function_const_params
3645                            .insert(def.name.clone(), Vec::new());
3646                        self.foreign_function_defs
3647                            .insert(def.name.clone(), def.clone());
3648                    }
3649                    Ok(())
3650                }
3651                _ => Ok(()),
3652            },
3653            // Impl and Extend blocks: delegate to register_item_functions
3654            // which handles the full registration (desugar methods, trait symbols,
3655            // type inference impls, drop tracking, etc.)
3656            Item::Impl(..) | Item::Extend(..) => {
3657                self.register_item_functions(item)
3658            }
3659            Item::Module(module, _) => {
3660                let module_path = self.current_module_path_for(module.name.as_str());
3661                self.module_scope_stack.push(module_path.clone());
3662                let register_result = (|| -> Result<()> {
3663                    for inner in &module.items {
3664                        let qualified = self.qualify_module_item(inner, &module_path)?;
3665                        self.register_missing_module_items(&qualified)?;
3666                    }
3667                    Ok(())
3668                })();
3669                self.module_scope_stack.pop();
3670                register_result
3671            }
3672            _ => Ok(()),
3673        }
3674    }
3675
3676    fn compile_module_decl(&mut self, module_def: &ModuleDecl, span: Span) -> Result<()> {
3677        for ann in &module_def.annotations {
3678            self.validate_annotation_target_usage(ann, AnnotationTargetKind::Module, span)?;
3679        }
3680
3681        let module_path = self.current_module_path_for(&module_def.name);
3682        if let Some(parent_path) = self.module_scope_stack.last().cloned()
3683            && let Some(parent_source) = self.resolve_canonical_module_path(&parent_path)
3684        {
3685            self.module_scope_sources
3686                .entry(module_path.clone())
3687                .or_insert_with(|| format!("{}::{}", parent_source, module_def.name));
3688        }
3689        self.module_scope_stack.push(module_path.clone());
3690        self.push_module_reference_scope();
3691
3692        let mut module_items = module_def.items.clone();
3693        if self.execute_module_comptime_handlers(module_def, &module_path, &mut module_items)? {
3694            self.pop_module_reference_scope();
3695            self.module_scope_stack.pop();
3696            return Ok(());
3697        }
3698        if self.execute_module_inline_comptime_blocks(&module_path, &mut module_items)? {
3699            self.pop_module_reference_scope();
3700            self.module_scope_stack.pop();
3701            return Ok(());
3702        }
3703
3704        let mut qualified_items = Vec::with_capacity(module_items.len());
3705        for inner in &module_items {
3706            qualified_items.push(self.qualify_module_item(inner, &module_path)?);
3707        }
3708
3709        for qualified in &qualified_items {
3710            self.register_missing_module_items(qualified)?;
3711        }
3712
3713        self.non_function_mir_context_stack
3714            .push(module_path.clone());
3715        let compile_result = (|| -> Result<()> {
3716            for (idx, qualified) in qualified_items.iter().enumerate() {
3717                let future_names = self
3718                    .future_reference_use_names_for_remaining_items(&qualified_items[idx + 1..]);
3719                self.push_future_reference_use_names(future_names);
3720                let compile_result = self.compile_item_with_context(qualified, false);
3721                self.pop_future_reference_use_names();
3722                compile_result?;
3723                self.release_unused_module_reference_borrows_for_remaining_items(
3724                    &qualified_items[idx + 1..],
3725                );
3726            }
3727            Ok(())
3728        })();
3729        self.non_function_mir_context_stack.pop();
3730        compile_result?;
3731
3732        let exports = self.collect_module_runtime_exports(&module_items, &module_path);
3733        let entries: Vec<ObjectEntry> = exports
3734            .into_iter()
3735            .map(|(name, value_ident)| ObjectEntry::Field {
3736                key: name,
3737                value: Expr::Identifier(value_ident, span),
3738                type_annotation: None,
3739            })
3740            .collect();
3741        let module_object = Expr::Object(entries, span);
3742        self.compile_expr(&module_object)?;
3743
3744        let binding_idx = self.get_or_create_module_binding(&module_path);
3745        self.emit(Instruction::new(
3746            OpCode::StoreModuleBinding,
3747            Some(Operand::ModuleBinding(binding_idx)),
3748        ));
3749        self.propagate_initializer_type_to_slot(binding_idx, false, false);
3750
3751        if self.module_scope_stack.len() == 1
3752            && !crate::module_resolution::is_hidden_annotation_import_module_name(&module_def.name)
3753        {
3754            self.module_namespace_bindings
3755                .insert(module_def.name.clone());
3756        }
3757
3758        self.emit_annotation_lifecycle_calls_for_module(
3759            &module_path,
3760            &module_def.annotations,
3761            Some(binding_idx),
3762        )?;
3763
3764        self.pop_module_reference_scope();
3765        self.module_scope_stack.pop();
3766        Ok(())
3767    }
3768
3769    /// Compile a query (Backtest, Alert, or With/CTE).
3770    ///
3771    /// For CTE (WITH) queries:
3772    /// 1. Compile each CTE subquery and store the result in a named module_binding variable.
3773    /// 2. Compile the main query (which can reference CTEs by name as variables).
3774    ///
3775    /// For Backtest and Alert queries, emit a stub for now.
3776    fn compile_query(&mut self, query: &Query) -> Result<()> {
3777        match query {
3778            Query::With(with_query) => {
3779                // Compile each CTE: evaluate its subquery and store as a named variable
3780                for cte in &with_query.ctes {
3781                    // Recursively compile the CTE's subquery
3782                    self.compile_query(&cte.query)?;
3783
3784                    // Store the result in a module_binding variable with the CTE's name
3785                    let binding_idx = self.get_or_create_module_binding(&cte.name);
3786                    self.emit(Instruction::new(
3787                        OpCode::StoreModuleBinding,
3788                        Some(Operand::ModuleBinding(binding_idx)),
3789                    ));
3790                }
3791
3792                // Compile the main query
3793                self.compile_query(&with_query.query)?;
3794            }
3795            Query::Backtest(_backtest) => {
3796                // Backtest queries require runtime context to evaluate.
3797                // Push null as placeholder — the runtime executor handles backtest
3798                // execution when given a full ExecutionContext.
3799                self.emit(Instruction::simple(OpCode::PushNull));
3800            }
3801            Query::Alert(alert) => {
3802                // Compile alert condition
3803                self.compile_expr(&alert.condition)?;
3804                // Push null as placeholder (alert evaluation requires runtime context)
3805                self.emit(Instruction::simple(OpCode::Pop));
3806                self.emit(Instruction::simple(OpCode::PushNull));
3807            }
3808        }
3809        Ok(())
3810    }
3811
3812    pub(super) fn propagate_initializer_type_to_slot(
3813        &mut self,
3814        slot: u16,
3815        is_local: bool,
3816        _is_mutable: bool,
3817    ) {
3818        self.propagate_assignment_type_to_slot(slot, is_local, true);
3819    }
3820
3821    /// Compile a statement
3822    pub(super) fn compile_statement(&mut self, stmt: &Statement) -> Result<()> {
3823        match stmt {
3824            Statement::Return(expr_opt, _span) => {
3825                if let Some(expr) = expr_opt {
3826                    self.plan_flexible_binding_escape_from_expr(expr);
3827                    if self.current_function_return_reference_summary.is_some() {
3828                        self.compile_expr_preserving_refs(expr)?;
3829                    } else {
3830                        self.compile_expr(expr)?;
3831                    }
3832                } else {
3833                    self.emit(Instruction::simple(OpCode::PushNull));
3834                }
3835                // Emit drops for all active drop scopes before returning
3836                let total_scopes = self.drop_locals.len();
3837                if total_scopes > 0 {
3838                    self.emit_drops_for_early_exit(total_scopes)?;
3839                }
3840                self.emit(Instruction::simple(OpCode::ReturnValue));
3841            }
3842
3843            Statement::Break(_) => {
3844                let in_loop = !self.loop_stack.is_empty();
3845                if in_loop {
3846                    // Emit drops for drop scopes inside the loop before breaking
3847                    let scopes_to_exit = self
3848                        .loop_stack
3849                        .last()
3850                        .map(|ctx| self.drop_locals.len().saturating_sub(ctx.drop_scope_depth))
3851                        .unwrap_or(0);
3852                    if scopes_to_exit > 0 {
3853                        self.emit_drops_for_early_exit(scopes_to_exit)?;
3854                    }
3855                    let jump_idx = self.emit_jump(OpCode::Jump, 0);
3856                    if let Some(loop_ctx) = self.loop_stack.last_mut() {
3857                        loop_ctx.break_jumps.push(jump_idx);
3858                    }
3859                } else {
3860                    return Err(ShapeError::RuntimeError {
3861                        message: "break statement outside of loop".to_string(),
3862                        location: None,
3863                    });
3864                }
3865            }
3866
3867            Statement::Continue(_) => {
3868                if let Some(loop_ctx) = self.loop_stack.last() {
3869                    // Copy values we need before mutable borrow
3870                    let scopes_to_exit = self
3871                        .drop_locals
3872                        .len()
3873                        .saturating_sub(loop_ctx.drop_scope_depth);
3874                    let continue_target = loop_ctx.continue_target;
3875                    // Emit drops for drop scopes inside the loop before continuing
3876                    if scopes_to_exit > 0 {
3877                        self.emit_drops_for_early_exit(scopes_to_exit)?;
3878                    }
3879                    if continue_target == usize::MAX {
3880                        // Deferred continue: emit placeholder forward jump
3881                        let jump_idx = self.emit_jump(OpCode::Jump, 0);
3882                        if let Some(loop_ctx) = self.loop_stack.last_mut() {
3883                            loop_ctx.continue_jumps.push(jump_idx);
3884                        }
3885                    } else {
3886                        let offset =
3887                            continue_target as i32 - self.program.current_offset() as i32 - 1;
3888                        self.emit(Instruction::new(
3889                            OpCode::Jump,
3890                            Some(Operand::Offset(offset)),
3891                        ));
3892                    }
3893                } else {
3894                    return Err(ShapeError::RuntimeError {
3895                        message: "continue statement outside of loop".to_string(),
3896                        location: None,
3897                    });
3898                }
3899            }
3900
3901            Statement::VariableDecl(var_decl, _) => {
3902                // Set pending variable name for hoisting integration.
3903                // compile_typed_object_literal uses self to include hoisted fields in the schema.
3904                self.pending_variable_name =
3905                    var_decl.pattern.as_identifier().map(|s| s.to_string());
3906
3907                // Compile-time range check: if the type annotation is a width type
3908                // (i8, u8, i16, etc.) and the initializer is a constant expression,
3909                // verify the value fits in the declared width.
3910                if let (Some(type_ann), Some(init_expr)) =
3911                    (&var_decl.type_annotation, &var_decl.value)
3912                {
3913                    if let shape_ast::ast::TypeAnnotation::Basic(type_name) = type_ann {
3914                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
3915                            if let Some(const_val) =
3916                                crate::compiler::expressions::function_calls::eval_const_expr_to_nanboxed(init_expr)
3917                            {
3918                                let in_range = if let Some(i) = const_val.as_i64() {
3919                                    w.in_range_i64(i)
3920                                } else if let Some(f) = const_val.as_f64() {
3921                                    // Float → int truncation check
3922                                    let i = f as i64;
3923                                    (i as f64 == f) && w.in_range_i64(i)
3924                                } else {
3925                                    true // non-numeric, let runtime handle it
3926                                };
3927                                if !in_range {
3928                                    return Err(shape_ast::error::ShapeError::SemanticError {
3929                                        message: format!(
3930                                            "value does not fit in `{}` (range {}..={})",
3931                                            type_name,
3932                                            w.min_value(),
3933                                            w.max_value()
3934                                        ),
3935                                        location: Some(self.span_to_source_location(shape_ast::ast::Spanned::span(init_expr))),
3936                                    });
3937                                }
3938                            }
3939                        }
3940                    }
3941                }
3942
3943                // Compile initializer — register the variable even if the initializer fails,
3944                // to prevent cascading "Undefined variable" errors on later references.
3945                let mut ref_borrow = None;
3946                let init_err = if let Some(init_expr) = &var_decl.value {
3947                    // Special handling: Table row literal syntax
3948                    // `let t: Table<T> = [a, b], [c, d]` → compile as table construction
3949                    if let Expr::TableRows(rows, tr_span) = init_expr {
3950                        match self.compile_table_rows(rows, &var_decl.type_annotation, *tr_span) {
3951                            Ok(()) => None,
3952                            Err(e) => {
3953                                self.emit(Instruction::simple(OpCode::PushNull));
3954                                Some(e)
3955                            }
3956                        }
3957                    } else if let Expr::Array(items, arr_span) = init_expr {
3958                        // Single-row table literal: `let t: Table<T> = [a, b, c]`
3959                        // When the annotation is Table<T>, treat the array as a single row.
3960                        let is_table_annotated = matches!(
3961                            &var_decl.type_annotation,
3962                            Some(shape_ast::ast::TypeAnnotation::Generic { name, args })
3963                                if name == "Table" && args.len() == 1
3964                        );
3965                        if is_table_annotated {
3966                            let single_row = vec![items.clone()];
3967                            match self.compile_table_rows(
3968                                &single_row,
3969                                &var_decl.type_annotation,
3970                                *arr_span,
3971                            ) {
3972                                Ok(()) => None,
3973                                Err(e) => {
3974                                    self.emit(Instruction::simple(OpCode::PushNull));
3975                                    Some(e)
3976                                }
3977                            }
3978                        } else {
3979                            match self.compile_expr_for_reference_binding(init_expr) {
3980                                Ok(tracked_borrow) => {
3981                                    ref_borrow = tracked_borrow;
3982                                    None
3983                                }
3984                                Err(e) => {
3985                                    self.emit(Instruction::simple(OpCode::PushNull));
3986                                    Some(e)
3987                                }
3988                            }
3989                        }
3990                    } else {
3991                        match self.compile_expr_for_reference_binding(init_expr) {
3992                            Ok(tracked_borrow) => {
3993                                ref_borrow = tracked_borrow;
3994                                None
3995                            }
3996                            Err(e) => {
3997                                self.emit(Instruction::simple(OpCode::PushNull));
3998                                Some(e)
3999                            }
4000                        }
4001                    }
4002                } else {
4003                    self.emit(Instruction::simple(OpCode::PushNull));
4004                    None
4005                };
4006
4007                // Clear pending variable name after init expression is compiled
4008                self.pending_variable_name = None;
4009
4010                // Emit BindSchema for Table<T> annotations (runtime safety net)
4011                if let Some(ref type_ann) = var_decl.type_annotation {
4012                    if let Some(schema_id) = self.get_table_schema_id(type_ann) {
4013                        self.emit(Instruction::new(
4014                            OpCode::BindSchema,
4015                            Some(Operand::Count(schema_id)),
4016                        ));
4017                    }
4018                }
4019
4020                // At top-level (no current function), create module_bindings; otherwise create locals
4021                if self.current_function.is_none() {
4022                    // Top-level: create module_binding variable
4023                    if let Some(name) = var_decl.pattern.as_identifier() {
4024                        if ref_borrow.is_some() {
4025                            return Err(ShapeError::SemanticError {
4026                                message:
4027                                    "[B0003] cannot return or store a reference that outlives its owner"
4028                                        .to_string(),
4029                                location: var_decl.value.as_ref().map(|expr| {
4030                                    self.span_to_source_location(expr.span())
4031                                }),
4032                            });
4033                        }
4034                        let binding_idx = self.get_or_create_module_binding(name);
4035
4036                        // Emit StoreModuleBindingTyped for width-typed bindings,
4037                        // otherwise emit regular StoreModuleBinding.
4038                        let used_typed_store = if let Some(TypeAnnotation::Basic(type_name)) =
4039                            var_decl.type_annotation.as_ref()
4040                        {
4041                            if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
4042                                self.emit(Instruction::new(
4043                                    OpCode::StoreModuleBindingTyped,
4044                                    Some(Operand::TypedModuleBinding(
4045                                        binding_idx,
4046                                        crate::bytecode::NumericWidth::from_int_width(w),
4047                                    )),
4048                                ));
4049                                true
4050                            } else {
4051                                false
4052                            }
4053                        } else {
4054                            false
4055                        };
4056                        if !used_typed_store {
4057                            self.emit(Instruction::new(
4058                                OpCode::StoreModuleBinding,
4059                                Some(Operand::ModuleBinding(binding_idx)),
4060                            ));
4061                        }
4062
4063                        // Track type annotation if present (for type checker)
4064                        if let Some(ref type_ann) = var_decl.type_annotation {
4065                            if let Some(type_name) =
4066                                Self::tracked_type_name_from_annotation(type_ann)
4067                            {
4068                                self.set_module_binding_type_info(binding_idx, &type_name);
4069                            }
4070                            // Handle Table<T> generic annotation
4071                            self.try_track_datatable_type(type_ann, binding_idx, false)?;
4072                        } else {
4073                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
4074                            self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
4075                        }
4076
4077                        // Track for auto-drop at program exit
4078                        let binding_type_name = self
4079                            .type_tracker
4080                            .get_binding_type(binding_idx)
4081                            .and_then(|info| info.type_name.clone());
4082                        let drop_kind = binding_type_name
4083                            .as_ref()
4084                            .and_then(|tn| self.drop_type_info.get(tn).copied())
4085                            .or_else(|| {
4086                                var_decl
4087                                    .type_annotation
4088                                    .as_ref()
4089                                    .and_then(|ann| self.annotation_drop_kind(ann))
4090                            });
4091                        if drop_kind.is_some() {
4092                            let is_async = match drop_kind {
4093                                Some(DropKind::AsyncOnly) => true,
4094                                Some(DropKind::Both) => false,
4095                                Some(DropKind::SyncOnly) | None => false,
4096                            };
4097                            self.track_drop_module_binding(binding_idx, is_async);
4098                        }
4099                        if let Some(value) = &var_decl.value {
4100                            self.finish_reference_binding_from_expr(
4101                                binding_idx,
4102                                false,
4103                                name,
4104                                value,
4105                                ref_borrow,
4106                            );
4107                            self.update_callable_binding_from_expr(binding_idx, false, value);
4108                        } else {
4109                            self.clear_reference_binding(binding_idx, false);
4110                            self.clear_callable_binding(binding_idx, false);
4111                        }
4112                    } else {
4113                        self.compile_destructure_pattern_global(&var_decl.pattern)?;
4114                    }
4115
4116                    for (binding_name, _) in var_decl.pattern.get_bindings() {
4117                        let scoped_name = self
4118                            .resolve_scoped_module_binding_name(&binding_name)
4119                            .unwrap_or(binding_name);
4120                        if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
4121                            if var_decl.kind == VarKind::Const {
4122                                self.const_module_bindings.insert(binding_idx);
4123                            }
4124                            if var_decl.kind == VarKind::Let && !var_decl.is_mut {
4125                                self.immutable_module_bindings.insert(binding_idx);
4126                            }
4127                        }
4128                    }
4129                    self.apply_binding_semantics_to_pattern_bindings(
4130                        &var_decl.pattern,
4131                        false,
4132                        Self::binding_semantics_for_var_decl(var_decl),
4133                    );
4134                    self.plan_flexible_binding_storage_for_pattern_initializer(
4135                        &var_decl.pattern,
4136                        false,
4137                        var_decl.value.as_ref(),
4138                    );
4139                } else {
4140                    // Inside function: create local variable
4141                    self.compile_destructure_pattern(&var_decl.pattern)?;
4142
4143                    // Patch StoreLocal → StoreLocalTyped for width-typed simple bindings.
4144                    // compile_destructure_pattern emits StoreLocal(idx) for Identifier patterns;
4145                    // we upgrade it here when the type annotation is a width type.
4146                    if let (Some(name), Some(TypeAnnotation::Basic(type_name))) = (
4147                        var_decl.pattern.as_identifier(),
4148                        var_decl.type_annotation.as_ref(),
4149                    ) {
4150                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
4151                            if let Some(local_idx) = self.resolve_local(name) {
4152                                if let Some(last) = self.program.instructions.last_mut() {
4153                                    if last.opcode == OpCode::StoreLocal {
4154                                        last.opcode = OpCode::StoreLocalTyped;
4155                                        last.operand = Some(Operand::TypedLocal(
4156                                            local_idx,
4157                                            crate::bytecode::NumericWidth::from_int_width(w),
4158                                        ));
4159                                    }
4160                                }
4161                            }
4162                        }
4163                    }
4164
4165                    for (binding_name, _) in var_decl.pattern.get_bindings() {
4166                        if let Some(local_idx) = self.resolve_local(&binding_name) {
4167                            if var_decl.kind == VarKind::Const {
4168                                self.const_locals.insert(local_idx);
4169                            }
4170                            if var_decl.kind == VarKind::Let && !var_decl.is_mut {
4171                                self.immutable_locals.insert(local_idx);
4172                            }
4173                        }
4174                    }
4175                    self.apply_binding_semantics_to_pattern_bindings(
4176                        &var_decl.pattern,
4177                        true,
4178                        Self::binding_semantics_for_var_decl(var_decl),
4179                    );
4180                    self.plan_flexible_binding_storage_for_pattern_initializer(
4181                        &var_decl.pattern,
4182                        true,
4183                        var_decl.value.as_ref(),
4184                    );
4185
4186                    // Track type annotation first (so drop tracking can resolve the type)
4187                    if let Some(name) = var_decl.pattern.as_identifier() {
4188                        if let Some(ref type_ann) = var_decl.type_annotation {
4189                            if let Some(type_name) =
4190                                Self::tracked_type_name_from_annotation(type_ann)
4191                            {
4192                                // Get the local index for self variable
4193                                if let Some(local_idx) = self.resolve_local(name) {
4194                                    self.set_local_type_info(local_idx, &type_name);
4195                                }
4196                            }
4197                            // Handle Table<T> generic annotation
4198                            if let Some(local_idx) = self.resolve_local(name) {
4199                                self.try_track_datatable_type(type_ann, local_idx, true)?;
4200                            }
4201                        } else if let Some(local_idx) = self.resolve_local(name) {
4202                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
4203                            self.propagate_initializer_type_to_slot(local_idx, true, is_mutable);
4204                        }
4205                    }
4206
4207                    // Track for auto-drop at scope exit (DropCall silently skips non-Drop types).
4208                    // Select sync vs async opcode based on the type's DropKind.
4209                    if let Some(name) = var_decl.pattern.as_identifier() {
4210                        if let Some(local_idx) = self.resolve_local(name) {
4211                            let drop_kind = self.local_drop_kind(local_idx).or_else(|| {
4212                                var_decl
4213                                    .type_annotation
4214                                    .as_ref()
4215                                    .and_then(|ann| self.annotation_drop_kind(ann))
4216                            });
4217
4218                            let is_async = match drop_kind {
4219                                Some(DropKind::AsyncOnly) => {
4220                                    if !self.current_function_is_async {
4221                                        let tn = self
4222                                            .type_tracker
4223                                            .get_local_type(local_idx)
4224                                            .and_then(|info| info.type_name.clone())
4225                                            .unwrap_or_else(|| name.to_string());
4226                                        return Err(ShapeError::SemanticError {
4227                                            message: format!(
4228                                                "type '{}' has only an async drop() and cannot be used in a sync context; \
4229                                                 add a sync method drop(self) or use it inside an async function",
4230                                                tn
4231                                            ),
4232                                            location: None,
4233                                        });
4234                                    }
4235                                    true
4236                                }
4237                                Some(DropKind::Both) => self.current_function_is_async,
4238                                Some(DropKind::SyncOnly) | None => false,
4239                            };
4240                            self.track_drop_local(local_idx, is_async);
4241                            if let Some(value) = &var_decl.value {
4242                                self.finish_reference_binding_from_expr(
4243                                    local_idx, true, name, value, ref_borrow,
4244                                );
4245                                self.update_callable_binding_from_expr(local_idx, true, value);
4246                            } else {
4247                                self.clear_reference_binding(local_idx, true);
4248                                self.clear_callable_binding(local_idx, true);
4249                            }
4250                        }
4251                    }
4252                }
4253
4254                if let Some(e) = init_err {
4255                    return Err(e);
4256                }
4257            }
4258
4259            Statement::Assignment(assign, _) => 'assign: {
4260                // Check for const reassignment
4261                if let Some(name) = assign.pattern.as_identifier() {
4262                    if let Some(local_idx) = self.resolve_local(name) {
4263                        if !self.current_binding_uses_mir_write_authority(true)
4264                            && self.const_locals.contains(&local_idx)
4265                        {
4266                            return Err(ShapeError::SemanticError {
4267                                message: format!("Cannot reassign const variable '{}'", name),
4268                                location: None,
4269                            });
4270                        }
4271                        // Check for immutable `let` reassignment
4272                        if !self.current_binding_uses_mir_write_authority(true)
4273                            && self.immutable_locals.contains(&local_idx)
4274                        {
4275                            return Err(ShapeError::SemanticError {
4276                                message: format!(
4277                                    "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
4278                                    name
4279                                ),
4280                                location: None,
4281                            });
4282                        }
4283                        self.check_write_allowed_in_current_context(
4284                            Self::borrow_key_for_local(local_idx),
4285                            None,
4286                        )
4287                        .map_err(|e| match e {
4288                            ShapeError::SemanticError { message, location } => {
4289                                let user_msg = message.replace(
4290                                    &format!("(slot {})", local_idx),
4291                                    &format!("'{}'", name),
4292                                );
4293                                ShapeError::SemanticError {
4294                                    message: user_msg,
4295                                    location,
4296                                }
4297                            }
4298                            other => other,
4299                        })?;
4300                    } else {
4301                        let scoped_name = self
4302                            .resolve_scoped_module_binding_name(name)
4303                            .unwrap_or_else(|| name.to_string());
4304                        if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
4305                            if !self.current_binding_uses_mir_write_authority(false)
4306                                && self.const_module_bindings.contains(&binding_idx)
4307                            {
4308                                return Err(ShapeError::SemanticError {
4309                                    message: format!("Cannot reassign const variable '{}'", name),
4310                                    location: None,
4311                                });
4312                            }
4313                            // Check for immutable `let` reassignment at module level
4314                            if !self.current_binding_uses_mir_write_authority(false)
4315                                && self.immutable_module_bindings.contains(&binding_idx)
4316                            {
4317                                return Err(ShapeError::SemanticError {
4318                                    message: format!(
4319                                        "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
4320                                        name
4321                                    ),
4322                                    location: None,
4323                                });
4324                            }
4325                            self.check_write_allowed_in_current_context(
4326                                Self::borrow_key_for_module_binding(binding_idx),
4327                                None,
4328                            )
4329                            .map_err(|e| match e {
4330                                ShapeError::SemanticError { message, location } => {
4331                                    let user_msg = message.replace(
4332                                        &format!(
4333                                            "(slot {})",
4334                                            Self::borrow_key_for_module_binding(binding_idx)
4335                                        ),
4336                                        &format!("'{}'", name),
4337                                    );
4338                                    ShapeError::SemanticError {
4339                                        message: user_msg,
4340                                        location,
4341                                    }
4342                                }
4343                                other => other,
4344                            })?;
4345                        }
4346                    }
4347                }
4348
4349                // Optimization: x = x.push(val) → ArrayPushLocal (O(1) in-place mutation)
4350                if let Some(name) = assign.pattern.as_identifier() {
4351                    if let Expr::MethodCall {
4352                        receiver,
4353                        method,
4354                        args,
4355                        ..
4356                    } = &assign.value
4357                    {
4358                        if method == "push" && args.len() == 1 {
4359                            if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
4360                                if recv_name == name {
4361                                    if let Some(local_idx) = self.resolve_local(name) {
4362                                        self.compile_expr(&args[0])?;
4363                                        let pushed_numeric = self.last_expr_numeric_type;
4364                                        self.emit(Instruction::new(
4365                                            OpCode::ArrayPushLocal,
4366                                            Some(Operand::Local(local_idx)),
4367                                        ));
4368                                        if let Some(numeric_type) = pushed_numeric {
4369                                            self.mark_slot_as_numeric_array(
4370                                                local_idx,
4371                                                true,
4372                                                numeric_type,
4373                                            );
4374                                        }
4375                                        self.plan_flexible_binding_storage_from_expr(
4376                                            local_idx,
4377                                            true,
4378                                            &assign.value,
4379                                        );
4380                                        break 'assign;
4381                                    } else {
4382                                        let binding_idx = self.get_or_create_module_binding(name);
4383                                        self.compile_expr(&args[0])?;
4384                                        let pushed_numeric = self.last_expr_numeric_type;
4385                                        self.emit(Instruction::new(
4386                                            OpCode::ArrayPushLocal,
4387                                            Some(Operand::ModuleBinding(binding_idx)),
4388                                        ));
4389                                        if let Some(numeric_type) = pushed_numeric {
4390                                            self.mark_slot_as_numeric_array(
4391                                                binding_idx,
4392                                                false,
4393                                                numeric_type,
4394                                            );
4395                                        }
4396                                        self.plan_flexible_binding_storage_from_expr(
4397                                            binding_idx,
4398                                            false,
4399                                            &assign.value,
4400                                        );
4401                                        break 'assign;
4402                                    }
4403                                }
4404                            }
4405                        }
4406                    }
4407                }
4408
4409                // Compile value
4410                let saved_pending_variable_name = self.pending_variable_name.clone();
4411                self.pending_variable_name =
4412                    assign.pattern.as_identifier().map(|name| name.to_string());
4413                let compile_result = self.compile_expr_for_reference_binding(&assign.value);
4414                self.pending_variable_name = saved_pending_variable_name;
4415                let ref_borrow = compile_result?;
4416                let assigned_ident = assign.pattern.as_identifier().map(str::to_string);
4417
4418                // Store in variable
4419                self.compile_destructure_assignment(&assign.pattern)?;
4420                if let Some(name) = assigned_ident.as_deref() {
4421                    if let Some(local_idx) = self.resolve_local(name) {
4422                        if !self.local_binding_is_reference_value(local_idx) {
4423                            self.finish_reference_binding_from_expr(
4424                                local_idx,
4425                                true,
4426                                name,
4427                                &assign.value,
4428                                ref_borrow,
4429                            );
4430                            self.update_callable_binding_from_expr(local_idx, true, &assign.value);
4431                        }
4432                        self.plan_flexible_binding_storage_from_expr(
4433                            local_idx,
4434                            true,
4435                            &assign.value,
4436                        );
4437                    } else if let Some(scoped_name) = self.resolve_scoped_module_binding_name(name)
4438                    {
4439                        if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
4440                            self.finish_reference_binding_from_expr(
4441                                binding_idx,
4442                                false,
4443                                name,
4444                                &assign.value,
4445                                ref_borrow,
4446                            );
4447                            self.update_callable_binding_from_expr(
4448                                binding_idx,
4449                                false,
4450                                &assign.value,
4451                            );
4452                            self.plan_flexible_binding_storage_from_expr(
4453                                binding_idx,
4454                                false,
4455                                &assign.value,
4456                            );
4457                        }
4458                    }
4459                    self.propagate_assignment_type_to_identifier(name);
4460                }
4461            }
4462
4463            Statement::Expression(expr, _) => {
4464                // Fast path: arr.push(val) as standalone statement → in-place mutation
4465                // (avoids the LoadLocal+Pop overhead from the expression-level optimization)
4466                if let Expr::MethodCall {
4467                    receiver,
4468                    method,
4469                    args,
4470                    ..
4471                } = expr
4472                {
4473                    if method == "push" && args.len() == 1 {
4474                        if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
4475                            let source_loc = self.span_to_source_location(receiver.as_ref().span());
4476                            if let Some(local_idx) = self.resolve_local(recv_name) {
4477                                if !self.ref_locals.contains(&local_idx) {
4478                                    self.check_named_binding_write_allowed(
4479                                        recv_name,
4480                                        Some(source_loc.clone()),
4481                                    )?;
4482                                }
4483                                self.compile_expr(&args[0])?;
4484                                let pushed_numeric = self.last_expr_numeric_type;
4485                                self.emit(Instruction::new(
4486                                    OpCode::ArrayPushLocal,
4487                                    Some(Operand::Local(local_idx)),
4488                                ));
4489                                if let Some(numeric_type) = pushed_numeric {
4490                                    self.mark_slot_as_numeric_array(local_idx, true, numeric_type);
4491                                }
4492                                return Ok(());
4493                            } else if !self
4494                                .mutable_closure_captures
4495                                .contains_key(recv_name.as_str())
4496                            {
4497                                self.check_named_binding_write_allowed(
4498                                    recv_name,
4499                                    Some(source_loc),
4500                                )?;
4501                                let binding_idx = self.get_or_create_module_binding(recv_name);
4502                                self.compile_expr(&args[0])?;
4503                                self.emit(Instruction::new(
4504                                    OpCode::ArrayPushLocal,
4505                                    Some(Operand::ModuleBinding(binding_idx)),
4506                                ));
4507                                return Ok(());
4508                            }
4509                        }
4510                    }
4511                }
4512                self.compile_expr(expr)?;
4513                self.emit(Instruction::simple(OpCode::Pop));
4514            }
4515
4516            Statement::For(for_loop, _) => {
4517                self.compile_for_loop(for_loop)?;
4518            }
4519
4520            Statement::While(while_loop, _) => {
4521                self.compile_while_loop(while_loop)?;
4522            }
4523
4524            Statement::If(if_stmt, _) => {
4525                self.compile_if_statement(if_stmt)?;
4526            }
4527            Statement::Extend(extend, span) => {
4528                self.require_comptime_mode("extend", *span)?;
4529                self.emit_comptime_extend_directive(extend, *span)?;
4530            }
4531            Statement::RemoveTarget(span) => {
4532                self.require_comptime_mode("remove target", *span)?;
4533                self.emit_comptime_remove_directive(*span)?;
4534            }
4535            Statement::SetParamType {
4536                param_name,
4537                type_annotation,
4538                span,
4539            } => {
4540                self.require_comptime_mode("set param", *span)?;
4541                self.emit_comptime_set_param_type_directive(param_name, type_annotation, *span)?;
4542            }
4543            Statement::SetParamValue {
4544                param_name,
4545                expression,
4546                span,
4547            } => {
4548                self.require_comptime_mode("set param", *span)?;
4549                self.emit_comptime_set_param_value_directive(param_name, expression, *span)?;
4550            }
4551            Statement::SetReturnType {
4552                type_annotation,
4553                span,
4554            } => {
4555                self.require_comptime_mode("set return", *span)?;
4556                self.emit_comptime_set_return_type_directive(type_annotation, *span)?;
4557            }
4558            Statement::SetReturnExpr { expression, span } => {
4559                self.require_comptime_mode("set return", *span)?;
4560                self.emit_comptime_set_return_expr_directive(expression, *span)?;
4561            }
4562            Statement::ReplaceBody { body, span } => {
4563                self.require_comptime_mode("replace body", *span)?;
4564                self.emit_comptime_replace_body_directive(body, *span)?;
4565            }
4566            Statement::ReplaceBodyExpr { expression, span } => {
4567                self.require_comptime_mode("replace body", *span)?;
4568                self.emit_comptime_replace_body_expr_directive(expression, *span)?;
4569            }
4570            Statement::ReplaceModuleExpr { expression, span } => {
4571                self.require_comptime_mode("replace module", *span)?;
4572                self.emit_comptime_replace_module_expr_directive(expression, *span)?;
4573            }
4574        }
4575        Ok(())
4576    }
4577}
4578
4579#[cfg(test)]
4580mod tests {
4581    use crate::compiler::BytecodeCompiler;
4582    use crate::executor::{VMConfig, VirtualMachine};
4583    use shape_ast::ast::{Item, Span, Statement};
4584    use shape_ast::parser::parse_program;
4585
4586    #[test]
4587    fn test_module_decl_function_resolves_module_const() {
4588        let code = r#"
4589            mod math {
4590                const BASE = 21
4591                fn twice() {
4592                    BASE * 2
4593                }
4594            }
4595            math::twice()
4596        "#;
4597
4598        let program = parse_program(code).expect("Failed to parse");
4599        let bytecode = BytecodeCompiler::new()
4600            .compile(&program)
4601            .expect("Failed to compile");
4602
4603        let mut vm = VirtualMachine::new(VMConfig::default());
4604        vm.load_program(bytecode);
4605        vm.populate_module_objects();
4606        let result = vm.execute(None).expect("Failed to execute");
4607        assert_eq!(
4608            result
4609                .as_number_coerce()
4610                .expect("module call should return number"),
4611            42.0
4612        );
4613    }
4614
4615    #[test]
4616    fn test_module_annotation_can_replace_module_items() {
4617        let code = r#"
4618            annotation synth_module() {
4619                targets: [module]
4620                comptime post(target, ctx) {
4621                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
4622                }
4623            }
4624
4625            @synth_module()
4626            mod demo {}
4627
4628            demo::plus_two()
4629        "#;
4630
4631        let program = parse_program(code).expect("Failed to parse");
4632        let bytecode = BytecodeCompiler::new()
4633            .compile(&program)
4634            .expect("Failed to compile");
4635
4636        let mut vm = VirtualMachine::new(VMConfig::default());
4637        vm.load_program(bytecode);
4638        vm.populate_module_objects();
4639        let result = vm.execute(None).expect("Failed to execute");
4640        assert_eq!(
4641            result
4642                .as_number_coerce()
4643                .expect("module call should return number"),
4644            42.0
4645        );
4646    }
4647
4648    #[test]
4649    fn test_module_inline_comptime_can_replace_module_items() {
4650        let code = r#"
4651            mod demo {
4652                comptime {
4653                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
4654                }
4655            }
4656
4657            demo::plus_two()
4658        "#;
4659
4660        let program = parse_program(code).expect("Failed to parse");
4661        let bytecode = BytecodeCompiler::new()
4662            .compile(&program)
4663            .expect("Failed to compile");
4664
4665        let mut vm = VirtualMachine::new(VMConfig::default());
4666        vm.load_program(bytecode);
4667        vm.populate_module_objects();
4668        let result = vm.execute(None).expect("Failed to execute");
4669        assert_eq!(
4670            result
4671                .as_number_coerce()
4672                .expect("module call should return number"),
4673            42.0
4674        );
4675    }
4676
4677    #[test]
4678    fn test_module_inline_comptime_can_use_module_local_comptime_helper() {
4679        let code = r#"
4680            mod demo {
4681                comptime fn synth() {
4682                    "const ANSWER = 40; fn plus_two() { ANSWER + 2 }"
4683                }
4684
4685                comptime {
4686                    replace module (synth())
4687                }
4688            }
4689
4690            demo::plus_two()
4691        "#;
4692
4693        let program = parse_program(code).expect("Failed to parse");
4694        let bytecode = BytecodeCompiler::new()
4695            .compile(&program)
4696            .expect("Failed to compile");
4697
4698        let mut vm = VirtualMachine::new(VMConfig::default());
4699        vm.load_program(bytecode);
4700        vm.populate_module_objects();
4701        let result = vm.execute(None).expect("Failed to execute");
4702        assert_eq!(
4703            result
4704                .as_number_coerce()
4705                .expect("module call should return number"),
4706            42.0
4707        );
4708    }
4709
4710    #[test]
4711    fn test_type_annotated_variable_no_wrapping() {
4712        // BUG-1/BUG-2 fix: variable declarations must NOT emit WrapTypeAnnotation
4713        // (the wrapper broke arithmetic and comparisons)
4714        let code = r#"
4715            type Currency = Number
4716            let x: Currency = 123
4717        "#;
4718        let program = parse_program(code).expect("Failed to parse");
4719        let bytecode = BytecodeCompiler::new()
4720            .compile(&program)
4721            .expect("Failed to compile");
4722
4723        // WrapTypeAnnotation should NOT be emitted for variable declarations
4724        let has_wrap_instruction = bytecode
4725            .instructions
4726            .iter()
4727            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
4728        assert!(
4729            !has_wrap_instruction,
4730            "Should NOT emit WrapTypeAnnotation for type-annotated variable"
4731        );
4732    }
4733
4734    #[test]
4735    fn test_untyped_variable_no_wrapping() {
4736        // Variables without type annotations should NOT emit WrapTypeAnnotation
4737        let code = r#"
4738            let x = 123
4739        "#;
4740        let program = parse_program(code).expect("Failed to parse");
4741        let bytecode = BytecodeCompiler::new()
4742            .compile(&program)
4743            .expect("Failed to compile");
4744
4745        // Check that WrapTypeAnnotation instruction was NOT emitted
4746        let has_wrap_instruction = bytecode
4747            .instructions
4748            .iter()
4749            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
4750        assert!(
4751            !has_wrap_instruction,
4752            "Should NOT emit WrapTypeAnnotation for untyped variable"
4753        );
4754    }
4755
4756    // ===== Phase 2: Extend Block Compilation Tests =====
4757
4758    #[test]
4759    fn test_extend_block_compiles() {
4760        let code = r#"
4761            extend Number {
4762                method double() {
4763                    return self * 2
4764                }
4765            }
4766        "#;
4767        let program = parse_program(code).expect("Failed to parse extend block");
4768        let bytecode = BytecodeCompiler::new().compile(&program);
4769        assert!(
4770            bytecode.is_ok(),
4771            "Extend block should compile: {:?}",
4772            bytecode.err()
4773        );
4774
4775        // Verify a function named "Number.double" was generated (qualified extend name).
4776        let bytecode = bytecode.unwrap();
4777        let has_double = bytecode.functions.iter().any(|f| f.name == "Number.double");
4778        assert!(
4779            has_double,
4780            "Should generate 'Number.double' function from extend block"
4781        );
4782    }
4783
4784    #[test]
4785    fn test_extend_method_has_self_param() {
4786        let code = r#"
4787            extend Number {
4788                method add(n) {
4789                    return self + n
4790                }
4791            }
4792        "#;
4793        let program = parse_program(code).expect("Failed to parse");
4794        let bytecode = BytecodeCompiler::new()
4795            .compile(&program)
4796            .expect("Failed to compile");
4797
4798        let func = bytecode.functions.iter().find(|f| f.name == "Number.add");
4799        assert!(func.is_some(), "Should have 'Number.add' function");
4800        // The function should have 2 params: self + n
4801        assert_eq!(
4802            func.unwrap().arity,
4803            2,
4804            "add() should have arity 2 (self + n)"
4805        );
4806    }
4807
4808    #[test]
4809    fn test_extend_method_rejects_explicit_self_param() {
4810        let code = r#"
4811            extend Number {
4812                method add(self, n) {
4813                    return self + n
4814                }
4815            }
4816        "#;
4817        let program = parse_program(code).expect("Failed to parse");
4818        let err = BytecodeCompiler::new()
4819            .compile(&program)
4820            .expect_err("Compiler should reject explicit self receiver param in methods");
4821        let msg = format!("{err}");
4822        assert!(
4823            msg.contains("explicit `self` parameter"),
4824            "Expected explicit self error, got: {msg}"
4825        );
4826    }
4827
4828    // ===== Phase 3: Annotation Handler Compilation Tests =====
4829
4830    #[test]
4831    fn test_annotation_def_compiles_handlers() {
4832        let code = r#"
4833            annotation warmup(period) {
4834                before(args, ctx) {
4835                    args
4836                }
4837                after(args, result, ctx) {
4838                    result
4839                }
4840            }
4841            function test() { return 42; }
4842        "#;
4843        let program = parse_program(code).expect("Failed to parse annotation def");
4844        let bytecode = BytecodeCompiler::new().compile(&program);
4845        assert!(
4846            bytecode.is_ok(),
4847            "Annotation def should compile: {:?}",
4848            bytecode.err()
4849        );
4850
4851        let bytecode = bytecode.unwrap();
4852        // Verify CompiledAnnotation was registered
4853        assert!(
4854            bytecode.compiled_annotations.contains_key("warmup"),
4855            "Should have compiled 'warmup' annotation"
4856        );
4857
4858        let compiled = bytecode.compiled_annotations.get("warmup").unwrap();
4859        assert!(
4860            compiled.before_handler.is_some(),
4861            "Should have before handler"
4862        );
4863        assert!(
4864            compiled.after_handler.is_some(),
4865            "Should have after handler"
4866        );
4867    }
4868
4869    #[test]
4870    fn test_exported_annotation_def_compiles_handlers() {
4871        let code = r#"
4872            pub annotation warmup(period) {
4873                before(args, ctx) {
4874                    args
4875                }
4876            }
4877
4878            @warmup(5)
4879            fn test() { 42 }
4880        "#;
4881        let program = parse_program(code).expect("Failed to parse exported annotation def");
4882        let bytecode = BytecodeCompiler::new().compile(&program);
4883        assert!(
4884            bytecode.is_ok(),
4885            "Exported annotation def should compile: {:?}",
4886            bytecode.err()
4887        );
4888
4889        let bytecode = bytecode.unwrap();
4890        assert!(
4891            bytecode.compiled_annotations.contains_key("warmup"),
4892            "Should have compiled exported 'warmup' annotation"
4893        );
4894    }
4895
4896    #[test]
4897    fn test_annotation_handler_function_names() {
4898        let code = r#"
4899            annotation my_ann(x) {
4900                before(args, ctx) {
4901                    args
4902                }
4903            }
4904            function test() { return 1; }
4905        "#;
4906        let program = parse_program(code).expect("Failed to parse");
4907        let bytecode = BytecodeCompiler::new()
4908            .compile(&program)
4909            .expect("Failed to compile");
4910
4911        // Handler should be compiled as an internal function
4912        let compiled = bytecode.compiled_annotations.get("my_ann").unwrap();
4913        let handler_id = compiled.before_handler.unwrap() as usize;
4914        assert!(
4915            handler_id < bytecode.functions.len(),
4916            "Handler function ID should be valid"
4917        );
4918
4919        let handler_fn = &bytecode.functions[handler_id];
4920        assert_eq!(
4921            handler_fn.name, "my_ann___before",
4922            "Handler function should be named my_ann___before"
4923        );
4924    }
4925
4926    // ===== Phase 4: Compile-Time Function Wrapping Tests =====
4927
4928    #[test]
4929    fn test_annotated_function_generates_wrapper() {
4930        let code = r#"
4931            annotation tracked(label) {
4932                before(args, ctx) {
4933                    args
4934                }
4935            }
4936            @tracked("my_func")
4937            function compute(x) {
4938                return x * 2
4939            }
4940            function test() { return 1; }
4941        "#;
4942        let program = parse_program(code).expect("Failed to parse");
4943        let bytecode = BytecodeCompiler::new().compile(&program);
4944        assert!(
4945            bytecode.is_ok(),
4946            "Annotated function should compile: {:?}",
4947            bytecode.err()
4948        );
4949
4950        let bytecode = bytecode.unwrap();
4951        // Should have the original function (wrapper) and the impl
4952        let has_impl = bytecode
4953            .functions
4954            .iter()
4955            .any(|f| f.name == "compute___impl");
4956        assert!(has_impl, "Should generate compute___impl function");
4957
4958        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
4959        assert!(has_wrapper, "Should keep compute as wrapper");
4960    }
4961
4962    #[test]
4963    fn test_unannotated_function_no_wrapper() {
4964        let code = r#"
4965            function plain(x) {
4966                return x + 1
4967            }
4968        "#;
4969        let program = parse_program(code).expect("Failed to parse");
4970        let bytecode = BytecodeCompiler::new()
4971            .compile(&program)
4972            .expect("Failed to compile");
4973
4974        // Should NOT have an ___impl function
4975        let has_impl = bytecode
4976            .functions
4977            .iter()
4978            .any(|f| f.name.ends_with("___impl"));
4979        assert!(
4980            !has_impl,
4981            "Non-annotated function should not generate ___impl"
4982        );
4983    }
4984
4985    // ===== Sprint 10: Annotation chaining and target validation =====
4986
4987    #[test]
4988    fn test_annotation_chaining_generates_chain() {
4989        // Two annotations on the same function should generate chained wrappers
4990        let code = r#"
4991            annotation first() {
4992                before(args, ctx) {
4993                    return args
4994                }
4995            }
4996
4997            annotation second() {
4998                before(args, ctx) {
4999                    return args
5000                }
5001            }
5002
5003            @first
5004            @second
5005            function compute(x) {
5006                return x * 2
5007            }
5008        "#;
5009        let program = parse_program(code).expect("Failed to parse");
5010        let bytecode = BytecodeCompiler::new().compile(&program);
5011        assert!(
5012            bytecode.is_ok(),
5013            "Chained annotations should compile: {:?}",
5014            bytecode.err()
5015        );
5016        let bytecode = bytecode.unwrap();
5017
5018        // Should have: compute (outermost wrapper), compute___impl (body), compute___second (intermediate)
5019        let has_impl = bytecode
5020            .functions
5021            .iter()
5022            .any(|f| f.name == "compute___impl");
5023        assert!(has_impl, "Should generate compute___impl function");
5024        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
5025        assert!(has_wrapper, "Should keep compute as outermost wrapper");
5026        let has_intermediate = bytecode
5027            .functions
5028            .iter()
5029            .any(|f| f.name == "compute___second");
5030        assert!(
5031            has_intermediate,
5032            "Should generate compute___second intermediate wrapper"
5033        );
5034    }
5035
5036    #[test]
5037    fn test_annotation_allowed_targets_inferred() {
5038        // An annotation with before/after should have allowed_targets = [Function]
5039        let code = r#"
5040            annotation traced() {
5041                before(args, ctx) {
5042                    return args
5043                }
5044            }
5045        "#;
5046        let program = parse_program(code).expect("Failed to parse");
5047        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
5048        let ann = bytecode
5049            .compiled_annotations
5050            .get("traced")
5051            .expect("traced annotation");
5052        assert!(
5053            !ann.allowed_targets.is_empty(),
5054            "before handler should restrict targets"
5055        );
5056        assert!(
5057            ann.allowed_targets
5058                .contains(&shape_ast::ast::functions::AnnotationTargetKind::Function),
5059            "before handler should allow Function target"
5060        );
5061    }
5062
5063    #[test]
5064    fn test_annotation_allowed_targets_explicit_override() {
5065        // Explicit `targets: [...]` should override inferred defaults.
5066        let code = r#"
5067            annotation traced() {
5068                targets: [type]
5069                before(args, ctx) {
5070                    return args
5071                }
5072            }
5073        "#;
5074        let program = parse_program(code).expect("Failed to parse");
5075        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
5076        let ann = bytecode
5077            .compiled_annotations
5078            .get("traced")
5079            .expect("traced annotation");
5080        assert_eq!(
5081            ann.allowed_targets,
5082            vec![shape_ast::ast::functions::AnnotationTargetKind::Type]
5083        );
5084    }
5085
5086    #[test]
5087    fn test_metadata_only_annotation_defaults_to_definition_targets() {
5088        // An annotation with only metadata handler should default to definition targets.
5089        let code = r#"
5090            annotation info() {
5091                metadata() {
5092                    return { version: 1 }
5093                }
5094            }
5095        "#;
5096        let program = parse_program(code).expect("Failed to parse");
5097        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
5098        let ann = bytecode
5099            .compiled_annotations
5100            .get("info")
5101            .expect("info annotation");
5102        assert_eq!(
5103            ann.allowed_targets,
5104            vec![
5105                shape_ast::ast::functions::AnnotationTargetKind::Function,
5106                shape_ast::ast::functions::AnnotationTargetKind::Type,
5107                shape_ast::ast::functions::AnnotationTargetKind::Module
5108            ],
5109            "metadata-only annotation should default to definition targets"
5110        );
5111    }
5112
5113    #[test]
5114    fn test_definition_lifecycle_targets_reject_expression_target() {
5115        let code = r#"
5116            annotation info() {
5117                targets: [expression]
5118                metadata(target, ctx) {
5119                    target.name
5120                }
5121            }
5122        "#;
5123        let program = parse_program(code).expect("Failed to parse");
5124        let err = BytecodeCompiler::new()
5125            .compile(&program)
5126            .expect_err("metadata hooks on expression targets should fail");
5127        let msg = format!("{}", err);
5128        assert!(
5129            msg.contains("not a definition target"),
5130            "expected definition-target restriction error, got: {}",
5131            msg
5132        );
5133    }
5134
5135    #[test]
5136    fn test_annotation_target_validation_on_struct_type() {
5137        // Function-only annotation applied to a type should fail.
5138        let code = r#"
5139            annotation traced() {
5140                before(args, ctx) { return args }
5141            }
5142
5143            @traced()
5144            type Point { x: int }
5145        "#;
5146        let program = parse_program(code).expect("Failed to parse");
5147        let err = BytecodeCompiler::new()
5148            .compile(&program)
5149            .expect_err("function-only annotation on type should fail");
5150        let msg = format!("{}", err);
5151        assert!(
5152            msg.contains("cannot be applied to a type"),
5153            "expected type target validation error, got: {}",
5154            msg
5155        );
5156    }
5157
5158    #[test]
5159    fn test_type_c_emits_native_layout_metadata() {
5160        let bytecode = compiles_to(
5161            r#"
5162            type C Pair32 {
5163                left: i32,
5164                right: i32,
5165            }
5166            "#,
5167        );
5168
5169        assert_eq!(bytecode.native_struct_layouts.len(), 1);
5170        let layout = &bytecode.native_struct_layouts[0];
5171        assert_eq!(layout.name, "Pair32");
5172        assert_eq!(layout.abi, "C");
5173        assert_eq!(layout.size, 8);
5174        assert_eq!(layout.align, 4);
5175        assert_eq!(layout.fields.len(), 2);
5176        assert_eq!(layout.fields[0].name, "left");
5177        assert_eq!(layout.fields[0].offset, 0);
5178        assert_eq!(layout.fields[0].size, 4);
5179        assert_eq!(layout.fields[1].name, "right");
5180        assert_eq!(layout.fields[1].offset, 4);
5181        assert_eq!(layout.fields[1].size, 4);
5182    }
5183
5184    #[test]
5185    fn test_type_c_auto_generates_into_from_traits() {
5186        let bytecode = compiles_to(
5187            r#"
5188            type C QuoteC {
5189                bid: i64,
5190                ask: i64,
5191            }
5192
5193            type Quote {
5194                bid: i64,
5195                ask: i64,
5196            }
5197            "#,
5198        );
5199
5200        let c_to_shape =
5201            bytecode.lookup_trait_method_symbol("Into", "QuoteC", Some("Quote"), "into");
5202        let shape_to_c =
5203            bytecode.lookup_trait_method_symbol("Into", "Quote", Some("QuoteC"), "into");
5204        let from_c = bytecode.lookup_trait_method_symbol("From", "Quote", Some("QuoteC"), "from");
5205        let from_shape =
5206            bytecode.lookup_trait_method_symbol("From", "QuoteC", Some("Quote"), "from");
5207
5208        assert!(c_to_shape.is_some(), "expected Into<Quote> for QuoteC");
5209        assert!(shape_to_c.is_some(), "expected Into<QuoteC> for Quote");
5210        assert!(from_c.is_some(), "expected From<QuoteC> for Quote");
5211        assert!(from_shape.is_some(), "expected From<Quote> for QuoteC");
5212    }
5213
5214    #[test]
5215    fn test_type_c_auto_conversion_function_compiles() {
5216        let _ = compiles_to(
5217            r#"
5218            type Quote {
5219                bid: i64,
5220                ask: i64,
5221            }
5222
5223            type C QuoteC {
5224                bid: i64,
5225                ask: i64,
5226            }
5227
5228            fn spread(q: QuoteC) -> i64 {
5229                let q_shape = __auto_native_from_QuoteC_to_Quote(q);
5230                q_shape.ask - q_shape.bid
5231            }
5232
5233            spread(QuoteC { bid: 10, ask: 13 })
5234            "#,
5235        );
5236    }
5237
5238    #[test]
5239    fn test_type_c_auto_conversion_rejects_incompatible_fields() {
5240        let program = parse_program(
5241            r#"
5242            type Price {
5243                value: i64,
5244            }
5245
5246            type C PriceC {
5247                value: u64,
5248            }
5249            "#,
5250        )
5251        .expect("parse failed");
5252        let err = BytecodeCompiler::new()
5253            .compile(&program)
5254            .expect_err("incompatible type C conversion pair should fail");
5255        let msg = format!("{}", err);
5256        assert!(
5257            msg.contains("field type mismatch for auto conversion"),
5258            "expected type mismatch error, got: {}",
5259            msg
5260        );
5261    }
5262
5263    // ===== Task 1: Meta on traits =====
5264
5265    // ===== Drop Track: Sprint 2 Tests =====
5266
5267    fn compiles_to(code: &str) -> crate::bytecode::BytecodeProgram {
5268        let program = parse_program(code).expect("parse failed");
5269        let compiler = BytecodeCompiler::new();
5270        compiler.compile(&program).expect("compile failed")
5271    }
5272
5273    // --- Permission checking tests ---
5274
5275    #[test]
5276    fn test_permission_check_allows_pure_module_imports() {
5277        // json is a pure module — should compile even with empty permissions
5278        let code = "from std::core::json use { parse }";
5279        let program = parse_program(code).expect("parse failed");
5280        let mut compiler = BytecodeCompiler::new();
5281        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
5282        // Should not fail — json requires no permissions
5283        let _result = compiler.compile(&program);
5284    }
5285
5286    #[test]
5287    fn test_permission_check_blocks_file_import_under_pure() {
5288        let code = "from std::core::file use { read_text }";
5289        let program = parse_program(code).expect("parse failed");
5290        let mut compiler = BytecodeCompiler::new();
5291        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
5292        let result = compiler.compile(&program);
5293        assert!(
5294            result.is_err(),
5295            "Expected permission error for file::read_text under pure"
5296        );
5297        let err_msg = format!("{}", result.unwrap_err());
5298        assert!(
5299            err_msg.contains("Permission denied"),
5300            "Error should mention permission denied: {err_msg}"
5301        );
5302        assert!(
5303            err_msg.contains("fs.read"),
5304            "Error should mention fs.read: {err_msg}"
5305        );
5306    }
5307
5308    #[test]
5309    fn test_permission_check_allows_file_import_with_fs_read() {
5310        let code = "from std::core::file use { read_text }";
5311        let program = parse_program(code).expect("parse failed");
5312        let mut compiler = BytecodeCompiler::new();
5313        let pset = shape_abi_v1::PermissionSet::from_iter([shape_abi_v1::Permission::FsRead]);
5314        compiler.set_permission_set(Some(pset));
5315        // Should not fail
5316        let _result = compiler.compile(&program);
5317    }
5318
5319    #[test]
5320    fn test_permission_check_no_permission_set_allows_everything() {
5321        // When permission_set is None (default), no checking is done
5322        let code = "from std::core::file use { read_text }";
5323        let program = parse_program(code).expect("parse failed");
5324        let compiler = BytecodeCompiler::new();
5325        // permission_set is None by default — should compile fine
5326        let _result = compiler.compile(&program);
5327    }
5328
5329    #[test]
5330    fn test_permission_check_namespace_import_blocked() {
5331        let code = "use std::core::http";
5332        let program = parse_program(code).expect("parse failed");
5333        let mut compiler = BytecodeCompiler::new();
5334        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
5335        let result = compiler.compile(&program);
5336        assert!(
5337            result.is_err(),
5338            "Expected permission error for `use std::core::http` under pure"
5339        );
5340        let err_msg = format!("{}", result.unwrap_err());
5341        assert!(
5342            err_msg.contains("Permission denied"),
5343            "Error should mention permission denied: {err_msg}"
5344        );
5345    }
5346
5347    #[test]
5348    fn test_permission_check_namespace_import_allowed() {
5349        let code = "use std::core::http";
5350        let program = parse_program(code).expect("parse failed");
5351        let mut compiler = BytecodeCompiler::new();
5352        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::full()));
5353        // Should not fail
5354        let _result = compiler.compile(&program);
5355    }
5356
5357    fn test_decl(kind: shape_ast::ast::VarKind, is_mut: bool) -> shape_ast::ast::VariableDecl {
5358        shape_ast::ast::VariableDecl {
5359            kind,
5360            is_mut,
5361            pattern: shape_ast::ast::DestructurePattern::Identifier(
5362                "x".to_string(),
5363                shape_ast::ast::Span::DUMMY,
5364            ),
5365            type_annotation: None,
5366            value: None,
5367            ownership: Default::default(),
5368        }
5369    }
5370
5371    #[test]
5372    fn test_binding_semantics_for_decl_maps_let_var_classes() {
5373        let let_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5374            shape_ast::ast::VarKind::Let,
5375            false,
5376        ));
5377        assert_eq!(
5378            let_semantics.ownership_class,
5379            crate::type_tracking::BindingOwnershipClass::OwnedImmutable
5380        );
5381        assert_eq!(
5382            let_semantics.storage_class,
5383            crate::type_tracking::BindingStorageClass::Direct
5384        );
5385
5386        let let_mut_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5387            shape_ast::ast::VarKind::Let,
5388            true,
5389        ));
5390        assert_eq!(
5391            let_mut_semantics.ownership_class,
5392            crate::type_tracking::BindingOwnershipClass::OwnedMutable
5393        );
5394        assert_eq!(
5395            let_mut_semantics.storage_class,
5396            crate::type_tracking::BindingStorageClass::Direct
5397        );
5398
5399        let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5400            shape_ast::ast::VarKind::Var,
5401            false,
5402        ));
5403        assert_eq!(
5404            var_semantics.ownership_class,
5405            crate::type_tracking::BindingOwnershipClass::Flexible
5406        );
5407        assert_eq!(
5408            var_semantics.storage_class,
5409            crate::type_tracking::BindingStorageClass::Deferred
5410        );
5411    }
5412
5413    #[test]
5414    fn test_destructured_module_bindings_get_binding_semantics() {
5415        let mut compiler = BytecodeCompiler::new();
5416        let pattern = shape_ast::ast::DestructurePattern::Array(vec![
5417            shape_ast::ast::DestructurePattern::Identifier(
5418                "left".to_string(),
5419                shape_ast::ast::Span::DUMMY,
5420            ),
5421            shape_ast::ast::DestructurePattern::Identifier(
5422                "right".to_string(),
5423                shape_ast::ast::Span::DUMMY,
5424            ),
5425        ]);
5426        compiler
5427            .compile_destructure_pattern_global(&pattern)
5428            .expect("destructure should compile");
5429        compiler.apply_binding_semantics_to_pattern_bindings(
5430            &pattern,
5431            false,
5432            BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5433                shape_ast::ast::VarKind::Let,
5434                false,
5435            )),
5436        );
5437
5438        let left_idx = *compiler
5439            .module_bindings
5440            .get("left")
5441            .expect("left binding should exist");
5442        let right_idx = *compiler
5443            .module_bindings
5444            .get("right")
5445            .expect("right binding should exist");
5446
5447        assert_eq!(
5448            compiler
5449                .type_tracker
5450                .get_binding_semantics(left_idx)
5451                .map(|semantics| semantics.ownership_class),
5452            Some(crate::type_tracking::BindingOwnershipClass::OwnedImmutable)
5453        );
5454        assert_eq!(
5455            compiler
5456                .type_tracker
5457                .get_binding_semantics(left_idx)
5458                .map(|semantics| semantics.storage_class),
5459            Some(crate::type_tracking::BindingStorageClass::Direct)
5460        );
5461        assert_eq!(
5462            compiler
5463                .type_tracker
5464                .get_binding_semantics(right_idx)
5465                .map(|semantics| semantics.ownership_class),
5466            Some(crate::type_tracking::BindingOwnershipClass::OwnedImmutable)
5467        );
5468    }
5469
5470    #[test]
5471    fn test_flexible_binding_alias_initializer_marks_shared_storage() {
5472        let mut compiler = BytecodeCompiler::new();
5473        compiler.push_scope();
5474        let source = compiler.declare_local("source").expect("declare source");
5475        let dest = compiler.declare_local("dest").expect("declare dest");
5476        let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5477            shape_ast::ast::VarKind::Var,
5478            false,
5479        ));
5480        compiler
5481            .type_tracker
5482            .set_local_binding_semantics(source, var_semantics);
5483        compiler
5484            .type_tracker
5485            .set_local_binding_semantics(dest, var_semantics);
5486
5487        compiler.plan_flexible_binding_storage_from_expr(
5488            dest,
5489            true,
5490            &shape_ast::ast::Expr::Identifier("source".to_string(), shape_ast::ast::Span::DUMMY),
5491        );
5492
5493        assert_eq!(
5494            compiler
5495                .type_tracker
5496                .get_local_binding_semantics(source)
5497                .map(|semantics| semantics.storage_class),
5498            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5499        );
5500        assert_eq!(
5501            compiler
5502                .type_tracker
5503                .get_local_binding_semantics(dest)
5504                .map(|semantics| semantics.storage_class),
5505            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5506        );
5507    }
5508
5509    #[test]
5510    fn test_flexible_destructure_bindings_finalize_to_direct_storage() {
5511        let mut compiler = BytecodeCompiler::new();
5512        compiler.push_scope();
5513        let left = compiler.declare_local("left").expect("declare left");
5514        let right = compiler.declare_local("right").expect("declare right");
5515        let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
5516            shape_ast::ast::VarKind::Var,
5517            false,
5518        ));
5519        compiler
5520            .type_tracker
5521            .set_local_binding_semantics(left, var_semantics);
5522        compiler
5523            .type_tracker
5524            .set_local_binding_semantics(right, var_semantics);
5525
5526        let pattern = shape_ast::ast::DestructurePattern::Array(vec![
5527            shape_ast::ast::DestructurePattern::Identifier(
5528                "left".to_string(),
5529                shape_ast::ast::Span::DUMMY,
5530            ),
5531            shape_ast::ast::DestructurePattern::Identifier(
5532                "right".to_string(),
5533                shape_ast::ast::Span::DUMMY,
5534            ),
5535        ]);
5536        compiler.plan_flexible_binding_storage_for_pattern_initializer(
5537            &pattern,
5538            true,
5539            Some(&shape_ast::ast::Expr::Identifier(
5540                "source".to_string(),
5541                shape_ast::ast::Span::DUMMY,
5542            )),
5543        );
5544
5545        assert_eq!(
5546            compiler
5547                .type_tracker
5548                .get_local_binding_semantics(left)
5549                .map(|semantics| semantics.storage_class),
5550            Some(crate::type_tracking::BindingStorageClass::Direct)
5551        );
5552        assert_eq!(
5553            compiler
5554                .type_tracker
5555                .get_local_binding_semantics(right)
5556                .map(|semantics| semantics.storage_class),
5557            Some(crate::type_tracking::BindingStorageClass::Direct)
5558        );
5559    }
5560
5561    #[test]
5562    fn test_module_var_alias_decl_marks_shared_storage() {
5563        let program = parse_program(
5564            r#"
5565                var source = [1]
5566                var alias = source
5567            "#,
5568        )
5569        .expect("parse failed");
5570        let mut compiler = BytecodeCompiler::new();
5571        let first_decl = match &program.items[0] {
5572            Item::VariableDecl(var_decl, _) => {
5573                Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
5574            }
5575            Item::Statement(stmt, _) => stmt.clone(),
5576            _ => panic!("expected first variable declaration"),
5577        };
5578        let second_decl = match &program.items[1] {
5579            Item::VariableDecl(var_decl, _) => {
5580                Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
5581            }
5582            Item::Statement(stmt, _) => stmt.clone(),
5583            _ => panic!("expected second variable declaration"),
5584        };
5585        compiler
5586            .compile_statement(&first_decl)
5587            .expect("first decl should compile");
5588        compiler
5589            .compile_statement(&second_decl)
5590            .expect("second decl should compile");
5591
5592        let source_idx = *compiler
5593            .module_bindings
5594            .get("source")
5595            .expect("source binding should exist");
5596        let alias_idx = *compiler
5597            .module_bindings
5598            .get("alias")
5599            .expect("alias binding should exist");
5600
5601        assert_eq!(
5602            compiler
5603                .type_tracker
5604                .get_binding_semantics(source_idx)
5605                .map(|semantics| semantics.storage_class),
5606            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5607        );
5608        assert_eq!(
5609            compiler
5610                .type_tracker
5611                .get_binding_semantics(alias_idx)
5612                .map(|semantics| semantics.storage_class),
5613            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5614        );
5615    }
5616
5617    #[test]
5618    fn test_module_var_fresh_decl_marks_direct_storage() {
5619        let program = parse_program("var values = [1, 2, 3]").expect("parse failed");
5620        let mut compiler = BytecodeCompiler::new();
5621        let decl = match &program.items[0] {
5622            Item::VariableDecl(var_decl, _) => {
5623                Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
5624            }
5625            Item::Statement(stmt, _) => stmt.clone(),
5626            _ => panic!("expected variable declaration"),
5627        };
5628        compiler
5629            .compile_statement(&decl)
5630            .expect("decl should compile");
5631
5632        let values_idx = *compiler
5633            .module_bindings
5634            .get("values")
5635            .expect("values binding should exist");
5636
5637        assert_eq!(
5638            compiler
5639                .type_tracker
5640                .get_binding_semantics(values_idx)
5641                .map(|semantics| semantics.storage_class),
5642            Some(crate::type_tracking::BindingStorageClass::Direct)
5643        );
5644    }
5645
5646    #[test]
5647    fn test_module_var_collection_escape_marks_source_unique_heap() {
5648        let program = parse_program(
5649            r#"
5650                var source = [1]
5651                var wrapped = [source]
5652            "#,
5653        )
5654        .expect("parse failed");
5655        let mut compiler = BytecodeCompiler::new();
5656        for item in &program.items {
5657            let stmt = match item {
5658                Item::VariableDecl(var_decl, _) => {
5659                    Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
5660                }
5661                Item::Statement(stmt, _) => stmt.clone(),
5662                _ => continue,
5663            };
5664            compiler
5665                .compile_statement(&stmt)
5666                .expect("item should compile");
5667        }
5668
5669        let source_idx = *compiler
5670            .module_bindings
5671            .get("source")
5672            .expect("source binding should exist");
5673        let wrapped_idx = *compiler
5674            .module_bindings
5675            .get("wrapped")
5676            .expect("wrapped binding should exist");
5677
5678        assert_eq!(
5679            compiler
5680                .type_tracker
5681                .get_binding_semantics(source_idx)
5682                .map(|semantics| semantics.storage_class),
5683            Some(crate::type_tracking::BindingStorageClass::UniqueHeap)
5684        );
5685        assert_eq!(
5686            compiler
5687                .type_tracker
5688                .get_binding_semantics(wrapped_idx)
5689                .map(|semantics| semantics.storage_class),
5690            Some(crate::type_tracking::BindingStorageClass::Direct)
5691        );
5692    }
5693
5694    #[test]
5695    fn test_module_var_assignment_alias_marks_shared_storage() {
5696        let program = parse_program(
5697            r#"
5698                var source = [1]
5699                var alias = []
5700                alias = source
5701            "#,
5702        )
5703        .expect("parse failed");
5704        let mut compiler = BytecodeCompiler::new();
5705        for item in &program.items {
5706            let stmt = match item {
5707                Item::VariableDecl(var_decl, _) => {
5708                    Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
5709                }
5710                Item::Assignment(assign, _) => Statement::Assignment(assign.clone(), Span::DUMMY),
5711                Item::Statement(stmt, _) => stmt.clone(),
5712                _ => continue,
5713            };
5714            compiler
5715                .compile_statement(&stmt)
5716                .expect("item should compile");
5717        }
5718
5719        let source_idx = *compiler
5720            .module_bindings
5721            .get("source")
5722            .expect("source binding should exist");
5723        let alias_idx = *compiler
5724            .module_bindings
5725            .get("alias")
5726            .expect("alias binding should exist");
5727
5728        assert_eq!(
5729            compiler
5730                .type_tracker
5731                .get_binding_semantics(source_idx)
5732                .map(|semantics| semantics.storage_class),
5733            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5734        );
5735        assert_eq!(
5736            compiler
5737                .type_tracker
5738                .get_binding_semantics(alias_idx)
5739                .map(|semantics| semantics.storage_class),
5740            Some(crate::type_tracking::BindingStorageClass::SharedCow)
5741        );
5742    }
5743}