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, Statement,
7    TypeAnnotation, VarKind,
8};
9use shape_ast::error::{Result, ShapeError};
10use shape_runtime::type_schema::{EnumVariantInfo, FieldType};
11
12use super::{BytecodeCompiler, DropKind, ImportedSymbol, ParamPassMode, StructGenericInfo};
13
14#[derive(Debug, Clone)]
15struct NativeFieldLayoutSpec {
16    c_type: String,
17    size: u64,
18    align: u64,
19}
20
21impl BytecodeCompiler {
22    fn emit_comptime_internal_call(
23        &mut self,
24        method: &str,
25        args: Vec<Expr>,
26        span: Span,
27    ) -> Result<()> {
28        let call = Expr::MethodCall {
29            receiver: Box::new(Expr::Identifier("__comptime__".to_string(), span)),
30            method: method.to_string(),
31            args,
32            named_args: Vec::new(),
33            span,
34        };
35        let prev = self.allow_internal_comptime_namespace;
36        self.allow_internal_comptime_namespace = true;
37        let compile_result = self.compile_expr(&call);
38        self.allow_internal_comptime_namespace = prev;
39        compile_result?;
40        self.emit(Instruction::simple(OpCode::Pop));
41        Ok(())
42    }
43
44    fn emit_comptime_extend_directive(
45        &mut self,
46        extend: &shape_ast::ast::ExtendStatement,
47        span: Span,
48    ) -> Result<()> {
49        let payload = serde_json::to_string(extend).map_err(|e| ShapeError::RuntimeError {
50            message: format!("Failed to serialize comptime extend directive: {}", e),
51            location: Some(self.span_to_source_location(span)),
52        })?;
53        self.emit_comptime_internal_call(
54            "__emit_extend",
55            vec![Expr::Literal(Literal::String(payload), span)],
56            span,
57        )
58    }
59
60    fn emit_comptime_remove_directive(&mut self, span: Span) -> Result<()> {
61        self.emit_comptime_internal_call("__emit_remove", Vec::new(), span)
62    }
63
64    fn emit_comptime_set_param_type_directive(
65        &mut self,
66        param_name: &str,
67        type_annotation: &TypeAnnotation,
68        span: Span,
69    ) -> Result<()> {
70        let payload =
71            serde_json::to_string(type_annotation).map_err(|e| ShapeError::RuntimeError {
72                message: format!("Failed to serialize comptime param type directive: {}", e),
73                location: Some(self.span_to_source_location(span)),
74            })?;
75        self.emit_comptime_internal_call(
76            "__emit_set_param_type",
77            vec![
78                Expr::Literal(Literal::String(param_name.to_string()), span),
79                Expr::Literal(Literal::String(payload), span),
80            ],
81            span,
82        )
83    }
84
85    fn emit_comptime_set_return_type_directive(
86        &mut self,
87        type_annotation: &TypeAnnotation,
88        span: Span,
89    ) -> Result<()> {
90        let payload =
91            serde_json::to_string(type_annotation).map_err(|e| ShapeError::RuntimeError {
92                message: format!("Failed to serialize comptime return type directive: {}", e),
93                location: Some(self.span_to_source_location(span)),
94            })?;
95        self.emit_comptime_internal_call(
96            "__emit_set_return_type",
97            vec![Expr::Literal(Literal::String(payload), span)],
98            span,
99        )
100    }
101
102    fn emit_comptime_set_return_expr_directive(
103        &mut self,
104        expression: &Expr,
105        span: Span,
106    ) -> Result<()> {
107        self.emit_comptime_internal_call("__emit_set_return_type", vec![expression.clone()], span)
108    }
109
110    fn emit_comptime_replace_body_directive(
111        &mut self,
112        body: &[Statement],
113        span: Span,
114    ) -> Result<()> {
115        let payload = serde_json::to_string(body).map_err(|e| ShapeError::RuntimeError {
116            message: format!("Failed to serialize comptime replace-body directive: {}", e),
117            location: Some(self.span_to_source_location(span)),
118        })?;
119        self.emit_comptime_internal_call(
120            "__emit_replace_body",
121            vec![Expr::Literal(Literal::String(payload), span)],
122            span,
123        )
124    }
125
126    fn emit_comptime_replace_body_expr_directive(
127        &mut self,
128        expression: &Expr,
129        span: Span,
130    ) -> Result<()> {
131        self.emit_comptime_internal_call("__emit_replace_body", vec![expression.clone()], span)
132    }
133
134    fn emit_comptime_replace_module_expr_directive(
135        &mut self,
136        expression: &Expr,
137        span: Span,
138    ) -> Result<()> {
139        self.emit_comptime_internal_call("__emit_replace_module", vec![expression.clone()], span)
140    }
141
142    pub(super) fn register_item_functions(&mut self, item: &Item) -> Result<()> {
143        match item {
144            Item::Function(func_def, _) => self.register_function(func_def),
145            Item::Module(module_def, _) => {
146                let module_path = self.current_module_path_for(module_def.name.as_str());
147                self.module_scope_stack.push(module_path.clone());
148                let register_result = (|| -> Result<()> {
149                    for inner in &module_def.items {
150                        let qualified = self.qualify_module_item(inner, &module_path)?;
151                        self.register_item_functions(&qualified)?;
152                    }
153                    Ok(())
154                })();
155                self.module_scope_stack.pop();
156                register_result
157            }
158            Item::Trait(trait_def, _) => {
159                self.known_traits.insert(trait_def.name.clone());
160                self.trait_defs
161                    .insert(trait_def.name.clone(), trait_def.clone());
162                Ok(())
163            }
164            Item::ForeignFunction(def, _) => {
165                // Register as a normal function so call sites resolve the name
166                let total_params = def.params.len();
167                self.function_arity_bounds
168                    .insert(def.name.clone(), (total_params, total_params));
169                self.function_const_params
170                    .insert(def.name.clone(), Vec::new());
171                let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
172
173                let func = crate::bytecode::Function {
174                    name: def.name.clone(),
175                    arity: def.params.len() as u16,
176                    param_names: def
177                        .params
178                        .iter()
179                        .flat_map(|p| p.get_identifiers())
180                        .collect(),
181                    locals_count: 0,
182                    entry_point: 0,
183                    body_length: 0,
184                    is_closure: false,
185                    captures_count: 0,
186                    is_async: def.is_async,
187                    ref_params,
188                    ref_mutates,
189                    mutable_captures: Vec::new(),
190                    frame_descriptor: None,
191                    osr_entry_points: Vec::new(),
192                };
193                self.program.functions.push(func);
194
195                // Store the foreign function def so call sites can resolve
196                // the declared return type (must be Result<T> for dynamic languages).
197                self.foreign_function_defs
198                    .insert(def.name.clone(), def.clone());
199
200                Ok(())
201            }
202            Item::Export(export, _) => match &export.item {
203                ExportItem::Function(func_def) => self.register_function(func_def),
204                ExportItem::Trait(trait_def) => {
205                    self.known_traits.insert(trait_def.name.clone());
206                    self.trait_defs
207                        .insert(trait_def.name.clone(), trait_def.clone());
208                    Ok(())
209                }
210                ExportItem::ForeignFunction(def) => {
211                    // Same registration as Item::ForeignFunction
212                    let total_params = def.params.len();
213                    self.function_arity_bounds
214                        .insert(def.name.clone(), (total_params, total_params));
215                    self.function_const_params
216                        .insert(def.name.clone(), Vec::new());
217                    let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
218
219                    let func = crate::bytecode::Function {
220                        name: def.name.clone(),
221                        arity: def.params.len() as u16,
222                        param_names: def
223                            .params
224                            .iter()
225                            .flat_map(|p| p.get_identifiers())
226                            .collect(),
227                        locals_count: 0,
228                        entry_point: 0,
229                        body_length: 0,
230                        is_closure: false,
231                        captures_count: 0,
232                        is_async: def.is_async,
233                        ref_params,
234                        ref_mutates,
235                        mutable_captures: Vec::new(),
236                        frame_descriptor: None,
237                        osr_entry_points: Vec::new(),
238                    };
239                    self.program.functions.push(func);
240
241                    self.foreign_function_defs
242                        .insert(def.name.clone(), def.clone());
243
244                    Ok(())
245                }
246                _ => Ok(()),
247            },
248            Item::Extend(extend, _) => {
249                // Desugar extend methods to functions with implicit `self` receiver param.
250                for method in &extend.methods {
251                    let func_def = self.desugar_extend_method(method, &extend.type_name)?;
252                    self.register_function(&func_def)?;
253                }
254                Ok(())
255            }
256            Item::Impl(impl_block, _) => {
257                // Impl blocks use scoped UFCS names.
258                // - default impl: "Type::method" (legacy compatibility)
259                // - named impl: "Trait::Type::ImplName::method"
260                // This prevents conflicts when multiple named impls exist.
261                let trait_name = match &impl_block.trait_name {
262                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
263                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
264                };
265                let type_name = match &impl_block.target_type {
266                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
267                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
268                };
269                let impl_name = impl_block.impl_name.as_deref();
270
271                // From/TryFrom impls use reverse-conversion desugaring:
272                // the method takes an explicit `value` param (no implicit self),
273                // and we auto-derive Into/TryInto trait symbols on the source type.
274                if trait_name == "From" || trait_name == "TryFrom" {
275                    return self.compile_from_impl(impl_block, trait_name, type_name);
276                }
277
278                // Collect names of methods explicitly provided in the impl block
279                let overridden: std::collections::HashSet<&str> =
280                    impl_block.methods.iter().map(|m| m.name.as_str()).collect();
281
282                for method in &impl_block.methods {
283                    let func_def = self.desugar_impl_method(
284                        method,
285                        trait_name,
286                        type_name,
287                        impl_name,
288                        &impl_block.target_type,
289                    )?;
290                    self.program.register_trait_method_symbol(
291                        trait_name,
292                        type_name,
293                        impl_name,
294                        &method.name,
295                        &func_def.name,
296                    );
297                    self.register_function(&func_def)?;
298
299                    // Track drop kind per type (sync, async, or both)
300                    if trait_name == "Drop" && method.name == "drop" {
301                        let type_key = type_name.to_string();
302                        let existing = self.drop_type_info.get(&type_key).copied();
303                        let new_kind = if method.is_async {
304                            match existing {
305                                Some(DropKind::SyncOnly) | Some(DropKind::Both) => DropKind::Both,
306                                _ => DropKind::AsyncOnly,
307                            }
308                        } else {
309                            match existing {
310                                Some(DropKind::AsyncOnly) | Some(DropKind::Both) => DropKind::Both,
311                                _ => DropKind::SyncOnly,
312                            }
313                        };
314                        self.drop_type_info.insert(type_key, new_kind);
315                    }
316                }
317
318                // Install default methods from the trait definition that were not overridden
319                if let Some(trait_def) = self.trait_defs.get(trait_name).cloned() {
320                    for member in &trait_def.members {
321                        if let shape_ast::ast::types::TraitMember::Default(default_method) = member
322                        {
323                            if !overridden.contains(default_method.name.as_str()) {
324                                let func_def = self.desugar_impl_method(
325                                    default_method,
326                                    trait_name,
327                                    type_name,
328                                    impl_name,
329                                    &impl_block.target_type,
330                                )?;
331                                self.program.register_trait_method_symbol(
332                                    trait_name,
333                                    type_name,
334                                    impl_name,
335                                    &default_method.name,
336                                    &func_def.name,
337                                );
338                                self.register_function(&func_def)?;
339                            }
340                        }
341                    }
342                }
343
344                // BUG-4.6 fix: Register the trait impl in the type inference
345                // environment so that `implements()` can see it at comptime.
346                let all_method_names: Vec<String> =
347                    impl_block.methods.iter().map(|m| m.name.clone()).collect();
348                if let Some(selector) = impl_name {
349                    let _ = self.type_inference.env.register_trait_impl_named(
350                        trait_name,
351                        type_name,
352                        selector,
353                        all_method_names,
354                    );
355                } else {
356                    let _ = self.type_inference.env.register_trait_impl(
357                        trait_name,
358                        type_name,
359                        all_method_names,
360                    );
361                }
362
363                Ok(())
364            }
365            _ => Ok(()),
366        }
367    }
368
369    /// Register a function definition
370    pub(super) fn register_function(&mut self, func_def: &FunctionDef) -> Result<()> {
371        // Detect duplicate function definitions (Shape does not support overloading).
372        // Skip names containing "::" (trait impl methods) or "." (extend methods)
373        // — those are type-qualified and live in separate namespaces.
374        if !func_def.name.contains("::")
375            && !func_def.name.contains('.')
376        {
377            if let Some(existing) = self.program.functions.iter().find(|f| f.name == func_def.name) {
378                // Allow idempotent re-registration from module inlining: when the
379                // prelude and an explicitly imported module both define the same helper
380                // function (e.g., `percentile`), silently keep the first definition
381                // if arities match. Different arities indicate a genuine conflict.
382                if existing.arity == func_def.params.len() as u16 {
383                    return Ok(());
384                }
385                return Err(ShapeError::SemanticError {
386                    message: format!(
387                        "Duplicate function definition: '{}' is already defined",
388                        func_def.name
389                    ),
390                    location: Some(self.span_to_source_location(func_def.name_span)),
391                });
392            }
393        }
394
395        self.function_defs
396            .insert(func_def.name.clone(), func_def.clone());
397
398        let total_params = func_def.params.len();
399        let mut required_params = total_params;
400        let mut saw_default = false;
401        let mut const_params = Vec::new();
402        for (idx, param) in func_def.params.iter().enumerate() {
403            if param.is_const {
404                const_params.push(idx);
405            }
406            if param.default_value.is_some() {
407                if !saw_default {
408                    required_params = idx;
409                    saw_default = true;
410                }
411            } else if saw_default {
412                return Err(ShapeError::SemanticError {
413                    message: "Required parameter cannot follow a parameter with a default value"
414                        .to_string(),
415                    location: Some(self.span_to_source_location(param.span())),
416                });
417            }
418        }
419
420        self.function_arity_bounds
421            .insert(func_def.name.clone(), (required_params, total_params));
422        self.function_const_params
423            .insert(func_def.name.clone(), const_params);
424
425        let inferred_param_modes = self
426            .inferred_param_pass_modes
427            .get(&func_def.name)
428            .cloned()
429            .unwrap_or_default();
430        let mut ref_params: Vec<bool> = Vec::with_capacity(func_def.params.len());
431        let mut ref_mutates: Vec<bool> = Vec::with_capacity(func_def.params.len());
432        for (idx, param) in func_def.params.iter().enumerate() {
433            let fallback = if param.is_reference {
434                ParamPassMode::ByRefShared
435            } else {
436                ParamPassMode::ByValue
437            };
438            let mode = inferred_param_modes.get(idx).copied().unwrap_or(fallback);
439            ref_params.push(mode.is_reference());
440            ref_mutates.push(mode.is_exclusive());
441        }
442
443        let func = Function {
444            name: func_def.name.clone(),
445            arity: func_def.params.len() as u16,
446            param_names: func_def
447                .params
448                .iter()
449                .flat_map(|p| p.get_identifiers())
450                .collect(),
451            locals_count: 0, // Will be updated during compilation
452            entry_point: 0,  // Will be updated during compilation
453            body_length: 0,  // Will be updated during compilation
454            is_closure: false,
455            captures_count: 0,
456            is_async: func_def.is_async,
457            ref_params,
458            ref_mutates,
459            mutable_captures: Vec::new(),
460            frame_descriptor: None,
461            osr_entry_points: Vec::new(),
462        };
463
464        self.program.functions.push(func);
465
466        // Register function return type for typed opcode emission.
467        // When a function has an explicit return type annotation (e.g., `: int`),
468        // record it so that call sites can propagate NumericType through expressions
469        // like `fib(n-1) + fib(n-2)` and emit AddInt instead of generic Add.
470        if let Some(ref return_type) = func_def.return_type {
471            if let Some(type_name) = return_type.as_simple_name() {
472                self.type_tracker
473                    .register_function_return_type(&func_def.name, type_name);
474            }
475        }
476
477        Ok(())
478    }
479
480    /// Compile a top-level item with context about whether it's the last item
481    /// If is_last is true and the item is an expression, keep the result on the stack
482    pub(super) fn compile_item_with_context(&mut self, item: &Item, is_last: bool) -> Result<()> {
483        match item {
484            Item::Function(func_def, _) => self.compile_function(func_def)?,
485            Item::Module(module_def, span) => {
486                self.compile_module_decl(module_def, *span)?;
487            }
488            Item::VariableDecl(var_decl, _) => {
489                // ModuleBinding variable — register the variable even if the initializer fails,
490                // to prevent cascading "Undefined variable" errors on later references.
491                let init_err = if let Some(init_expr) = &var_decl.value {
492                    match self.compile_expr(init_expr) {
493                        Ok(()) => None,
494                        Err(e) => {
495                            // Push null as placeholder so the variable still gets registered
496                            self.emit(Instruction::simple(OpCode::PushNull));
497                            Some(e)
498                        }
499                    }
500                } else {
501                    self.emit(Instruction::simple(OpCode::PushNull));
502                    None
503                };
504
505                if let Some(name) = var_decl.pattern.as_identifier() {
506                    let binding_idx = self.get_or_create_module_binding(name);
507                    self.emit(Instruction::new(
508                        OpCode::StoreModuleBinding,
509                        Some(Operand::ModuleBinding(binding_idx)),
510                    ));
511                } else {
512                    self.compile_destructure_pattern_global(&var_decl.pattern)?;
513                }
514
515                if let Some(e) = init_err {
516                    return Err(e);
517                }
518            }
519            Item::Assignment(assign, _) => {
520                self.compile_statement(&Statement::Assignment(assign.clone(), Span::DUMMY))?;
521            }
522            Item::Expression(expr, _) => {
523                self.compile_expr(expr)?;
524                // Only pop if not the last item - keep last expression result on stack
525                if !is_last {
526                    self.emit(Instruction::simple(OpCode::Pop));
527                }
528            }
529            Item::Statement(stmt, _) => {
530                // For expression statements that are the last item, keep result on stack
531                if is_last {
532                    if let Statement::Expression(expr, _) = stmt {
533                        self.compile_expr(expr)?;
534                        // Don't emit Pop - keep result on stack
535                        return Ok(());
536                    }
537                }
538                self.compile_statement(stmt)?;
539            }
540            Item::Export(export, export_span) => {
541                // If the export has a source variable declaration (pub let/const/var),
542                // compile it so the initialization is actually executed.
543                if let Some(ref var_decl) = export.source_decl {
544                    if let Some(init_expr) = &var_decl.value {
545                        self.compile_expr(init_expr)?;
546                    } else {
547                        self.emit(Instruction::simple(OpCode::PushNull));
548                    }
549                    if let Some(name) = var_decl.pattern.as_identifier() {
550                        let binding_idx = self.get_or_create_module_binding(name);
551                        self.emit(Instruction::new(
552                            OpCode::StoreModuleBinding,
553                            Some(Operand::ModuleBinding(binding_idx)),
554                        ));
555                    }
556                }
557                match &export.item {
558                    ExportItem::Function(func_def) => self.compile_function(func_def)?,
559                    ExportItem::Enum(enum_def) => self.register_enum(enum_def)?,
560                    ExportItem::Struct(struct_def) => {
561                        self.register_struct_type(struct_def, *export_span)?;
562                        if self.struct_types.contains_key(&struct_def.name) {
563                            self.emit_annotation_lifecycle_calls_for_type(
564                                &struct_def.name,
565                                &struct_def.annotations,
566                            )?;
567                        }
568                    }
569                    ExportItem::Interface(_) => {} // no-op for now
570                    ExportItem::Trait(_) => {} // no-op for now (trait registration happens in type system)
571                    ExportItem::ForeignFunction(def) => self.compile_foreign_function(def)?,
572                    _ => {}
573                }
574            }
575            Item::Stream(_stream, _) => {
576                return Err(ShapeError::StreamError {
577                    message: "Streaming functionality has been removed".to_string(),
578                    stream_name: None,
579                });
580            }
581            Item::TypeAlias(type_alias, _) => {
582                // Track type alias for meta validation
583                let base_type_name = match &type_alias.type_annotation {
584                    TypeAnnotation::Reference(name) | TypeAnnotation::Basic(name) => {
585                        Some(name.clone())
586                    }
587                    _ => None,
588                };
589                self.type_aliases.insert(
590                    type_alias.name.clone(),
591                    base_type_name
592                        .clone()
593                        .unwrap_or_else(|| format!("{:?}", type_alias.type_annotation)),
594                );
595
596                // Apply comptime field overrides from type alias
597                // e.g., type EUR = Currency { symbol: "€" } overrides Currency's comptime symbol
598                if let (Some(base_name), Some(overrides)) =
599                    (&base_type_name, &type_alias.meta_param_overrides)
600                {
601                    use shape_ast::ast::Literal;
602                    use shape_value::ValueWord;
603                    use std::sync::Arc;
604
605                    // Start with base type's comptime fields (if any)
606                    let mut alias_comptime = self
607                        .comptime_fields
608                        .get(base_name)
609                        .cloned()
610                        .unwrap_or_default();
611
612                    for (field_name, expr) in overrides {
613                        let value = match expr {
614                            Expr::Literal(Literal::Number(n), _) => ValueWord::from_f64(*n),
615                            Expr::Literal(Literal::Int(n), _) => ValueWord::from_f64(*n as f64),
616                            Expr::Literal(Literal::String(s), _) => {
617                                ValueWord::from_string(Arc::new(s.clone()))
618                            }
619                            Expr::Literal(Literal::Bool(b), _) => ValueWord::from_bool(*b),
620                            Expr::Literal(Literal::None, _) => ValueWord::none(),
621                            _ => {
622                                return Err(ShapeError::SemanticError {
623                                    message: format!(
624                                        "Comptime field override '{}' on type alias '{}' must be a literal",
625                                        field_name, type_alias.name
626                                    ),
627                                    location: None,
628                                });
629                            }
630                        };
631                        alias_comptime.insert(field_name.clone(), value);
632                    }
633
634                    if !alias_comptime.is_empty() {
635                        self.comptime_fields
636                            .insert(type_alias.name.clone(), alias_comptime);
637                    }
638                }
639            }
640            Item::StructType(struct_def, span) => {
641                self.register_struct_type(struct_def, *span)?;
642                if self.struct_types.contains_key(&struct_def.name) {
643                    self.emit_annotation_lifecycle_calls_for_type(
644                        &struct_def.name,
645                        &struct_def.annotations,
646                    )?;
647                }
648            }
649            Item::Enum(enum_def, _) => {
650                self.register_enum(enum_def)?;
651            }
652            // Meta/Format definitions removed — formatting now uses Display trait
653            Item::Import(import_stmt, _) => {
654                // Import handling is now done by executor pre-resolution
655                // via the unified runtime module loader.
656                // Imported module AST items are inlined via prelude injection
657                // before compilation (single-pass, no index remapping).
658                //
659                // At self point in compile_item, imports should already have been
660                // processed by pre-resolution. If we reach here, the import
661                // is either:
662                // 1. Being compiled standalone (no module context) - skip for now
663                // 2. A future extension point for runtime imports
664                //
665                // For now, we register the imported names as known functions
666                // that can be resolved later.
667                self.register_import_names(import_stmt)?;
668            }
669            Item::Extend(extend, _) => {
670                // Compile desugared extend methods
671                for method in &extend.methods {
672                    let func_def = self.desugar_extend_method(method, &extend.type_name)?;
673                    self.compile_function(&func_def)?;
674                }
675            }
676            Item::Impl(impl_block, _) => {
677                // Compile impl block methods with scoped names
678                let trait_name = match &impl_block.trait_name {
679                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
680                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
681                };
682                let type_name = match &impl_block.target_type {
683                    shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
684                    shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
685                };
686                let impl_name = impl_block.impl_name.as_deref();
687
688                // From/TryFrom: compile the from/tryFrom method + synthetic wrapper
689                if trait_name == "From" || trait_name == "TryFrom" {
690                    return self.compile_from_impl_bodies(impl_block, trait_name, type_name);
691                }
692
693                // Collect names of methods explicitly provided in the impl block
694                let overridden: std::collections::HashSet<&str> =
695                    impl_block.methods.iter().map(|m| m.name.as_str()).collect();
696
697                for method in &impl_block.methods {
698                    let func_def = self.desugar_impl_method(
699                        method,
700                        trait_name,
701                        type_name,
702                        impl_name,
703                        &impl_block.target_type,
704                    )?;
705                    self.compile_function(&func_def)?;
706                }
707
708                // Compile default methods from the trait definition that were not overridden
709                if let Some(trait_def) = self.trait_defs.get(trait_name).cloned() {
710                    for member in &trait_def.members {
711                        if let shape_ast::ast::types::TraitMember::Default(default_method) = member
712                        {
713                            if !overridden.contains(default_method.name.as_str()) {
714                                let func_def = self.desugar_impl_method(
715                                    default_method,
716                                    trait_name,
717                                    type_name,
718                                    impl_name,
719                                    &impl_block.target_type,
720                                )?;
721                                self.compile_function(&func_def)?;
722                            }
723                        }
724                    }
725                }
726            }
727            Item::AnnotationDef(ann_def, _) => {
728                self.compile_annotation_def(ann_def)?;
729            }
730            Item::Comptime(stmts, span) => {
731                // Execute comptime block at compile time (side-effects only; result discarded)
732                let extensions: Vec<_> = self
733                    .extension_registry
734                    .as_ref()
735                    .map(|r| r.as_ref().clone())
736                    .unwrap_or_default();
737                let trait_impls = self.type_inference.env.trait_impl_keys();
738                let known_type_symbols: std::collections::HashSet<String> = self
739                    .struct_types
740                    .keys()
741                    .chain(self.type_aliases.keys())
742                    .cloned()
743                    .collect();
744                let comptime_helpers = self.collect_comptime_helpers();
745                let execution = super::comptime::execute_comptime(
746                    stmts,
747                    &comptime_helpers,
748                    &extensions,
749                    trait_impls,
750                    known_type_symbols,
751                )
752                .map_err(|e| ShapeError::RuntimeError {
753                    message: format!(
754                        "Comptime block evaluation failed: {}",
755                        super::helpers::strip_error_prefix(&e)
756                    ),
757                    location: Some(self.span_to_source_location(*span)),
758                })?;
759                self.process_comptime_directives(execution.directives, "")
760                    .map_err(|e| ShapeError::RuntimeError {
761                        message: format!("Comptime block directive processing failed: {}", e),
762                        location: Some(self.span_to_source_location(*span)),
763                    })?;
764            }
765            Item::Query(query, _span) => {
766                self.compile_query(query)?;
767                // Pop the query result unless self is the last item
768                if !is_last {
769                    self.emit(Instruction::simple(OpCode::Pop));
770                }
771            }
772            Item::ForeignFunction(def, _) => self.compile_foreign_function(def)?,
773            _ => {} // Skip other items for now
774        }
775        Ok(())
776    }
777
778    /// Register imported names for symbol resolution
779    ///
780    /// This allows the compiler to recognize imported functions when
781    /// they are called later in the code.
782    fn register_import_names(&mut self, import_stmt: &shape_ast::ast::ImportStmt) -> Result<()> {
783        use shape_ast::ast::ImportItems;
784
785        // Check permissions before registering imports.
786        // Clone to avoid borrow conflict with &mut self in check_import_permissions.
787        if let Some(pset) = self.permission_set.clone() {
788            self.check_import_permissions(import_stmt, &pset)?;
789        }
790
791        match &import_stmt.items {
792            ImportItems::Named(specs) => {
793                for spec in specs {
794                    let local_name = spec.alias.as_ref().unwrap_or(&spec.name);
795                    // Register as a known import - actual function resolution
796                    // happens when the imported module's bytecode is merged
797                    self.imported_names.insert(
798                        local_name.clone(),
799                        ImportedSymbol {
800                            original_name: spec.name.clone(),
801                            module_path: import_stmt.from.clone(),
802                        },
803                    );
804                }
805            }
806            ImportItems::Namespace { name, alias } => {
807                // `use module.path` or `use module.path as alias`
808                // Register the local namespace binding as a module_binding.
809                let local_name = alias.as_ref().unwrap_or(name);
810                let binding_idx = self.get_or_create_module_binding(local_name);
811                self.module_namespace_bindings.insert(local_name.clone());
812                let module_path = if import_stmt.from.is_empty() {
813                    name.as_str()
814                } else {
815                    import_stmt.from.as_str()
816                };
817                // Predeclare module object schema so runtime can instantiate
818                // module module_bindings without synthesizing schemas dynamically.
819                self.register_extension_module_schema(module_path);
820                let module_schema_name = format!("__mod_{}", module_path);
821                if self
822                    .type_tracker
823                    .schema_registry()
824                    .get(&module_schema_name)
825                    .is_some()
826                {
827                    self.set_module_binding_type_info(binding_idx, &module_schema_name);
828                }
829                // The module object will be provided at runtime by the VM
830                let _ = binding_idx;
831            }
832        }
833        Ok(())
834    }
835
836    /// Check whether the imported symbols are allowed by the active permission set.
837    ///
838    /// For named imports (`from "file" import { read_text }`), checks each function
839    /// individually. For namespace imports (`use http`), checks the whole module.
840    fn check_import_permissions(
841        &mut self,
842        import_stmt: &shape_ast::ast::ImportStmt,
843        pset: &shape_abi_v1::PermissionSet,
844    ) -> Result<()> {
845        use shape_ast::ast::ImportItems;
846        use shape_runtime::stdlib::capability_tags;
847
848        // Extract the module name from the import path.
849        // Paths like "std::file", "file", "std/file" all resolve to "file".
850        let module_name = Self::extract_module_name(&import_stmt.from);
851
852        match &import_stmt.items {
853            ImportItems::Named(specs) => {
854                for spec in specs {
855                    let required = capability_tags::required_permissions(module_name, &spec.name);
856                    if !required.is_empty() && !required.is_subset(pset) {
857                        let missing = required.difference(pset);
858                        let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
859                        return Err(ShapeError::SemanticError {
860                            message: format!(
861                                "Permission denied: {module_name}::{} requires {} capability, \
862                                 but the active permission set does not include it. \
863                                 Add the permission to [permissions] in shape.toml or use a less \
864                                 restrictive preset.",
865                                spec.name,
866                                missing_names.join(", "),
867                            ),
868                            location: None,
869                        });
870                    }
871                    self.record_blob_permissions(module_name, &spec.name);
872                }
873            }
874            ImportItems::Namespace { .. } => {
875                // For namespace imports, check the entire module's permission envelope.
876                // If the module requires any permissions not granted, deny the import.
877                let required = capability_tags::module_permissions(module_name);
878                if !required.is_empty() && !required.is_subset(pset) {
879                    let missing = required.difference(pset);
880                    let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
881                    return Err(ShapeError::SemanticError {
882                        message: format!(
883                            "Permission denied: module '{module_name}' requires {} capabilities, \
884                             but the active permission set does not include them. \
885                             Add the permissions to [permissions] in shape.toml or use a less \
886                             restrictive preset.",
887                            missing_names.join(", "),
888                        ),
889                        location: None,
890                    });
891                }
892                // Record module-level permissions for namespace imports in the current blob
893                if let Some(ref mut blob) = self.current_blob_builder {
894                    let module_perms = capability_tags::module_permissions(module_name);
895                    blob.record_permissions(&module_perms);
896                }
897            }
898        }
899        Ok(())
900    }
901
902    /// Extract the leaf module name from an import path.
903    ///
904    /// `"std::file"` → `"file"`, `"file"` → `"file"`, `"std/io"` → `"io"`
905    fn extract_module_name(path: &str) -> &str {
906        path.rsplit(|c| c == ':' || c == '/')
907            .find(|s| !s.is_empty())
908            .unwrap_or(path)
909    }
910
911    pub(super) fn register_extension_module_schema(&mut self, module_path: &str) {
912        let Some(registry) = self.extension_registry.as_ref() else {
913            return;
914        };
915        let Some(module) = registry.iter().rev().find(|m| m.name == module_path) else {
916            return;
917        };
918
919        for schema in &module.type_schemas {
920            if self
921                .type_tracker
922                .schema_registry()
923                .get(&schema.name)
924                .is_none()
925            {
926                self.type_tracker
927                    .schema_registry_mut()
928                    .register(schema.clone());
929            }
930        }
931
932        let schema_name = format!("__mod_{}", module_path);
933        if self
934            .type_tracker
935            .schema_registry()
936            .get(&schema_name)
937            .is_some()
938        {
939            return;
940        }
941
942        let mut export_names: Vec<String> = module
943            .export_names_available(self.comptime_mode)
944            .into_iter()
945            .map(|name| name.to_string())
946            .collect();
947
948        for artifact in &module.module_artifacts {
949            if artifact.module_path != module_path {
950                continue;
951            }
952            let Some(source) = artifact.source.as_deref() else {
953                continue;
954            };
955            if let Ok(names) =
956                shape_runtime::module_loader::collect_exported_function_names_from_source(
957                    &artifact.module_path,
958                    source,
959                )
960            {
961                export_names.extend(names);
962            }
963        }
964
965        export_names.sort();
966        export_names.dedup();
967
968        let fields: Vec<(String, FieldType)> = export_names
969            .into_iter()
970            .map(|name| (name, FieldType::Any))
971            .collect();
972        self.type_tracker
973            .schema_registry_mut()
974            .register_type(schema_name, fields);
975    }
976
977    /// Register an enum definition in the TypeSchemaRegistry
978    fn register_enum(&mut self, enum_def: &EnumDef) -> Result<()> {
979        let variants: Vec<EnumVariantInfo> = enum_def
980            .members
981            .iter()
982            .enumerate()
983            .map(|(id, member)| {
984                let payload_fields = match &member.kind {
985                    EnumMemberKind::Unit { .. } => 0,
986                    EnumMemberKind::Tuple(types) => types.len() as u16,
987                    EnumMemberKind::Struct(fields) => fields.len() as u16,
988                };
989                EnumVariantInfo::new(&member.name, id as u16, payload_fields)
990            })
991            .collect();
992
993        let schema = shape_runtime::type_schema::TypeSchema::new_enum(&enum_def.name, variants);
994        self.type_tracker.schema_registry_mut().register(schema);
995        Ok(())
996    }
997
998    /// Pre-register items from an imported module (enums, struct types, functions).
999    ///
1000    /// Called by the LSP before compilation to make imported enums/types known
1001    /// to the compiler's type tracker. Reuses `register_enum` as single source of truth.
1002    pub fn register_imported_items(&mut self, items: &[Item]) {
1003        for item in items {
1004            match item {
1005                Item::Export(export, _) => {
1006                    match &export.item {
1007                        ExportItem::Enum(enum_def) => {
1008                            let _ = self.register_enum(enum_def);
1009                        }
1010                        ExportItem::Struct(struct_def) => {
1011                            // Register struct type fields so the compiler knows about them
1012                            let _ = self.register_struct_type(struct_def, Span::DUMMY);
1013                        }
1014                        ExportItem::Function(func_def) => {
1015                            // Register function so it's known during compilation
1016                            let _ = self.register_function(func_def);
1017                        }
1018                        _ => {}
1019                    }
1020                }
1021                Item::Enum(enum_def, _) => {
1022                    let _ = self.register_enum(enum_def);
1023                }
1024                _ => {}
1025            }
1026        }
1027    }
1028
1029    /// Register a meta definition in the format registry
1030    ///
1031    // Meta compilation methods removed — formatting now uses Display trait
1032
1033    /// Desugar an extend method to a FunctionDef with implicit `self` first param.
1034    ///
1035    /// `extend Number { method double() { self * 2 } }`
1036    /// becomes: `function double(self) { self * 2 }`
1037    ///
1038    /// UFCS handles the rest: `(5).double()` → `double(5)` → self = 5
1039    pub(super) fn desugar_extend_method(
1040        &self,
1041        method: &shape_ast::ast::types::MethodDef,
1042        target_type: &shape_ast::ast::TypeName,
1043    ) -> Result<FunctionDef> {
1044        let receiver_type = Some(Self::type_name_to_annotation(target_type));
1045        let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1046
1047        // Extend methods use qualified "Type.method" names to avoid collisions
1048        // with free functions (e.g., prelude's `sum` vs extend Point { method sum() }).
1049        let type_str = match target_type {
1050            shape_ast::ast::TypeName::Simple(n) => n.clone(),
1051            shape_ast::ast::TypeName::Generic { name, .. } => name.clone(),
1052        };
1053
1054        Ok(FunctionDef {
1055            name: format!("{}.{}", type_str, method.name),
1056            name_span: Span::DUMMY,
1057            params,
1058            return_type: method.return_type.clone(),
1059            body,
1060            type_params: Some(Vec::new()),
1061            annotations: Vec::new(),
1062            is_async: method.is_async,
1063            is_comptime: false,
1064            where_clause: None,
1065        })
1066    }
1067
1068    /// Desugar an impl method to a scoped FunctionDef.
1069    ///
1070    /// - Default impl:
1071    ///   `impl Queryable for DbTable { method filter(pred) { ... } }`
1072    ///   becomes: `function DbTable::filter(self, pred) { ... }`
1073    /// - Named impl:
1074    ///   `impl Display for User as JsonDisplay { method display() { ... } }`
1075    ///   becomes: `function Display::User::JsonDisplay::display(self) { ... }`
1076    ///
1077    /// Named impls use trait/type/impl prefixes to avoid collisions.
1078    fn desugar_impl_method(
1079        &self,
1080        method: &shape_ast::ast::types::MethodDef,
1081        trait_name: &str,
1082        type_name: &str,
1083        impl_name: Option<&str>,
1084        target_type: &shape_ast::ast::TypeName,
1085    ) -> Result<FunctionDef> {
1086        let receiver_type = Some(Self::type_name_to_annotation(target_type));
1087        let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1088
1089        // Async drop methods are named "drop_async" so both sync and async
1090        // variants can coexist in the function name index.
1091        let method_name = if trait_name == "Drop" && method.name == "drop" && method.is_async {
1092            "drop_async".to_string()
1093        } else {
1094            method.name.clone()
1095        };
1096        let fn_name = if let Some(name) = impl_name {
1097            format!("{}::{}::{}::{}", trait_name, type_name, name, method_name)
1098        } else {
1099            format!("{}::{}", type_name, method_name)
1100        };
1101
1102        Ok(FunctionDef {
1103            name: fn_name,
1104            name_span: Span::DUMMY,
1105            params,
1106            return_type: method.return_type.clone(),
1107            body,
1108            type_params: Some(Vec::new()),
1109            annotations: Vec::new(),
1110            is_async: method.is_async,
1111            is_comptime: false,
1112            where_clause: None,
1113        })
1114    }
1115
1116    /// Build desugared method params/body with implicit receiver handling.
1117    ///
1118    /// Canonical receiver is `self`.
1119    fn desugar_method_signature_and_body(
1120        &self,
1121        method: &shape_ast::ast::types::MethodDef,
1122        receiver_type: Option<shape_ast::ast::TypeAnnotation>,
1123    ) -> Result<(Vec<FunctionParameter>, Vec<Statement>)> {
1124        if let Some(receiver) = method
1125            .params
1126            .first()
1127            .and_then(|p| p.pattern.as_identifier())
1128        {
1129            if receiver == "self" {
1130                let location = method
1131                    .params
1132                    .first()
1133                    .map(|p| self.span_to_source_location(p.span()));
1134                return Err(ShapeError::SemanticError {
1135                    message: format!(
1136                        "Method '{}' has an explicit `self` parameter, but method receivers are implicit. Use `method {}(...)` without `self`.",
1137                        method.name, method.name
1138                    ),
1139                    location,
1140                });
1141            }
1142        }
1143
1144        let mut params = vec![FunctionParameter {
1145            pattern: shape_ast::ast::DestructurePattern::Identifier(
1146                "self".to_string(),
1147                Span::DUMMY,
1148            ),
1149            is_const: false,
1150            is_reference: false,
1151            is_mut_reference: false,
1152            type_annotation: receiver_type,
1153            default_value: None,
1154        }];
1155        params.extend(method.params.clone());
1156
1157        Ok((params, method.body.clone()))
1158    }
1159
1160    /// Compile a `From` or `TryFrom` impl block.
1161    ///
1162    /// Unlike normal impl methods (which inject implicit `self`), From/TryFrom
1163    /// methods are constructors: `from(value: Source) -> Target`. The value
1164    /// parameter sits at local slot 0 with no receiver.
1165    ///
1166    /// Auto-derives:
1167    /// - `impl From<S> for T`  → `Into<T>::into` on S (direct alias)
1168    ///                          + `TryInto<T>::tryInto` on S (wrapper → Ok())
1169    /// - `impl TryFrom<S> for T` → `TryInto<T>::tryInto` on S (direct alias)
1170    fn compile_from_impl(
1171        &mut self,
1172        impl_block: &shape_ast::ast::types::ImplBlock,
1173        trait_name: &str,
1174        target_type: &str,
1175    ) -> Result<()> {
1176        // Extract source type from generic args: From<Source> → Source
1177        let source_type = match &impl_block.trait_name {
1178            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1179                match &type_args[0] {
1180                    TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => name.clone(),
1181                    other => {
1182                        return Err(ShapeError::SemanticError {
1183                            message: format!(
1184                                "{} impl requires a simple source type, found {:?}",
1185                                trait_name, other
1186                            ),
1187                            location: None,
1188                        });
1189                    }
1190                }
1191            }
1192            _ => {
1193                return Err(ShapeError::SemanticError {
1194                    message: format!(
1195                        "{} impl requires a generic type argument, e.g., {}<string>",
1196                        trait_name, trait_name
1197                    ),
1198                    location: None,
1199                });
1200            }
1201        };
1202
1203        // Named impl selector defaults to the source type name
1204        let selector = impl_block.impl_name.as_deref().unwrap_or(&source_type);
1205
1206        for method in &impl_block.methods {
1207            let func_def =
1208                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1209            let from_fn_name = func_def.name.clone();
1210
1211            // Register From/TryFrom trait method symbol on the target type
1212            self.program.register_trait_method_symbol(
1213                trait_name,
1214                target_type,
1215                Some(&source_type),
1216                &method.name,
1217                &from_fn_name,
1218            );
1219            self.register_function(&func_def)?;
1220
1221            // Auto-derive Into/TryInto on the source type
1222            if trait_name == "From" {
1223                // From<S> for T → Into<T>::into on S = direct alias (same fn)
1224                self.program.register_trait_method_symbol(
1225                    "Into",
1226                    &source_type,
1227                    Some(selector),
1228                    "into",
1229                    &from_fn_name,
1230                );
1231
1232                // From<S> for T → TryInto<T>::tryInto on S = wrapper (from + Ok)
1233                let wrapper_name =
1234                    self.emit_from_to_tryinto_wrapper(&from_fn_name, &source_type, target_type)?;
1235                self.program.register_trait_method_symbol(
1236                    "TryInto",
1237                    &source_type,
1238                    Some(selector),
1239                    "tryInto",
1240                    &wrapper_name,
1241                );
1242
1243                // Register trait impls in type inference environment
1244                let _ = self.type_inference.env.register_trait_impl_named(
1245                    "Into",
1246                    &source_type,
1247                    selector,
1248                    vec!["into".to_string()],
1249                );
1250                let _ = self.type_inference.env.register_trait_impl_named(
1251                    "TryInto",
1252                    &source_type,
1253                    selector,
1254                    vec!["tryInto".to_string()],
1255                );
1256            } else {
1257                // TryFrom<S> for T → TryInto<T>::tryInto on S = direct alias
1258                self.program.register_trait_method_symbol(
1259                    "TryInto",
1260                    &source_type,
1261                    Some(selector),
1262                    "tryInto",
1263                    &from_fn_name,
1264                );
1265
1266                // Register TryInto trait impl in type inference environment
1267                let _ = self.type_inference.env.register_trait_impl_named(
1268                    "TryInto",
1269                    &source_type,
1270                    selector,
1271                    vec!["tryInto".to_string()],
1272                );
1273            }
1274        }
1275
1276        // Register From/TryFrom trait impl on target type
1277        let all_method_names: Vec<String> =
1278            impl_block.methods.iter().map(|m| m.name.clone()).collect();
1279        let _ = self.type_inference.env.register_trait_impl_named(
1280            trait_name,
1281            target_type,
1282            &source_type,
1283            all_method_names,
1284        );
1285
1286        Ok(())
1287    }
1288
1289    /// Compile From/TryFrom impl method bodies (and the synthetic TryInto wrapper).
1290    ///
1291    /// Called from `compile_item_with_context` — the registration pass already
1292    /// happened in `compile_from_impl` / `register_item_functions`.
1293    fn compile_from_impl_bodies(
1294        &mut self,
1295        impl_block: &shape_ast::ast::types::ImplBlock,
1296        trait_name: &str,
1297        target_type: &str,
1298    ) -> Result<()> {
1299        let source_type = match &impl_block.trait_name {
1300            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1301                match &type_args[0] {
1302                    TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => name.clone(),
1303                    _ => return Ok(()), // error already reported in registration
1304                }
1305            }
1306            _ => return Ok(()),
1307        };
1308
1309        for method in &impl_block.methods {
1310            let func_def =
1311                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1312            self.compile_function(&func_def)?;
1313        }
1314
1315        // Also compile the synthetic TryInto wrapper for From impls
1316        if trait_name == "From" {
1317            for method in &impl_block.methods {
1318                let from_fn_name = format!(
1319                    "{}::{}::{}::{}",
1320                    trait_name, target_type, source_type, method.name
1321                );
1322                let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1323                // The wrapper was already registered; now compile its body
1324                if let Some(func_def) = self.function_defs.get(&wrapper_name).cloned() {
1325                    let _ = self.compile_function(&func_def);
1326                    // Suppress errors: if Ok() or the from fn is not yet available, it
1327                    // will be resolved at link time.
1328                    let _ = from_fn_name; // used above in the format
1329                }
1330            }
1331        }
1332
1333        Ok(())
1334    }
1335
1336    /// Desugar a From/TryFrom method WITHOUT implicit self injection.
1337    ///
1338    /// `From::from(value: S)` is a constructor — `value` sits at local slot 0.
1339    /// Function name: `"From::TargetType::SourceType::method_name"`
1340    fn desugar_from_method(
1341        &self,
1342        method: &shape_ast::ast::types::MethodDef,
1343        trait_name: &str,
1344        target_type: &str,
1345        source_type: &str,
1346    ) -> Result<FunctionDef> {
1347        // Verify no explicit `self` parameter
1348        if let Some(first) = method
1349            .params
1350            .first()
1351            .and_then(|p| p.pattern.as_identifier())
1352        {
1353            if first == "self" {
1354                return Err(ShapeError::SemanticError {
1355                    message: format!(
1356                        "{}::{} methods are constructors and must not have a `self` parameter",
1357                        trait_name, method.name
1358                    ),
1359                    location: None,
1360                });
1361            }
1362        }
1363
1364        let fn_name = format!(
1365            "{}::{}::{}::{}",
1366            trait_name, target_type, source_type, method.name
1367        );
1368
1369        Ok(FunctionDef {
1370            name: fn_name,
1371            name_span: Span::DUMMY,
1372            params: method.params.clone(),
1373            return_type: method.return_type.clone(),
1374            body: method.body.clone(),
1375            type_params: Some(Vec::new()),
1376            annotations: Vec::new(),
1377            is_async: method.is_async,
1378            is_comptime: false,
1379            where_clause: None,
1380        })
1381    }
1382
1383    /// Emit a synthetic wrapper function that calls a From::from function
1384    /// and wraps its result in Ok() for TryInto compatibility.
1385    ///
1386    /// Generated function: `__from_tryinto_{source}_{target}(value) -> Ok(from(value))`
1387    fn emit_from_to_tryinto_wrapper(
1388        &mut self,
1389        from_fn_name: &str,
1390        source_type: &str,
1391        target_type: &str,
1392    ) -> Result<String> {
1393        let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1394
1395        // Create a synthetic FunctionDef whose body calls from() and wraps in Ok()
1396        let span = Span::DUMMY;
1397        let body = vec![Statement::Return(
1398            Some(Expr::FunctionCall {
1399                name: "Ok".to_string(),
1400                args: vec![Expr::FunctionCall {
1401                    name: from_fn_name.to_string(),
1402                    args: vec![Expr::Identifier("value".to_string(), span)],
1403                    named_args: Vec::new(),
1404                    span,
1405                }],
1406                named_args: Vec::new(),
1407                span,
1408            }),
1409            span,
1410        )];
1411
1412        let func_def = FunctionDef {
1413            name: wrapper_name.clone(),
1414            name_span: span,
1415            params: vec![FunctionParameter {
1416                pattern: DestructurePattern::Identifier("value".to_string(), span),
1417                is_const: false,
1418                is_reference: false,
1419                is_mut_reference: false,
1420                type_annotation: None,
1421                default_value: None,
1422            }],
1423            return_type: None,
1424            body,
1425            type_params: Some(Vec::new()),
1426            annotations: Vec::new(),
1427            is_async: false,
1428            is_comptime: false,
1429            where_clause: None,
1430        };
1431
1432        self.register_function(&func_def)?;
1433
1434        Ok(wrapper_name)
1435    }
1436
1437    fn type_name_to_annotation(
1438        type_name: &shape_ast::ast::TypeName,
1439    ) -> shape_ast::ast::TypeAnnotation {
1440        match type_name {
1441            shape_ast::ast::TypeName::Simple(name) => {
1442                shape_ast::ast::TypeAnnotation::Basic(name.clone())
1443            }
1444            shape_ast::ast::TypeName::Generic { name, type_args } => {
1445                shape_ast::ast::TypeAnnotation::Generic {
1446                    name: name.clone(),
1447                    args: type_args.clone(),
1448                }
1449            }
1450        }
1451    }
1452
1453    /// Compile an annotation definition.
1454    ///
1455    /// Each handler is compiled as an internal function:
1456    /// - before(args, ctx) → `{name}___before(self, period, args, ctx)`
1457    /// - after(args, result, ctx) → `{name}___after(self, period, args, result, ctx)`
1458    ///
1459    /// `self` is the annotated item (function/method/property).
1460    /// Annotation params (e.g., `period`) are prepended after `self`.
1461    fn compile_annotation_def(&mut self, ann_def: &shape_ast::ast::AnnotationDef) -> Result<()> {
1462        use crate::bytecode::CompiledAnnotation;
1463        use shape_ast::ast::AnnotationHandlerType;
1464
1465        let mut compiled = CompiledAnnotation {
1466            name: ann_def.name.clone(),
1467            param_names: ann_def
1468                .params
1469                .iter()
1470                .flat_map(|p| p.get_identifiers())
1471                .collect(),
1472            before_handler: None,
1473            after_handler: None,
1474            on_define_handler: None,
1475            metadata_handler: None,
1476            comptime_pre_handler: None,
1477            comptime_post_handler: None,
1478            allowed_targets: Vec::new(),
1479        };
1480
1481        for handler in &ann_def.handlers {
1482            // Comptime handlers are stored as AST (not compiled to bytecode).
1483            // They are executed at compile time when the annotation is applied.
1484            match handler.handler_type {
1485                AnnotationHandlerType::ComptimePre => {
1486                    compiled.comptime_pre_handler = Some(handler.clone());
1487                    continue;
1488                }
1489                AnnotationHandlerType::ComptimePost => {
1490                    compiled.comptime_post_handler = Some(handler.clone());
1491                    continue;
1492                }
1493                _ => {}
1494            }
1495
1496            if handler.params.iter().any(|p| p.is_variadic) {
1497                return Err(ShapeError::SemanticError {
1498                    message:
1499                        "Variadic annotation handler params (`...args`) are only supported on comptime handlers"
1500                            .to_string(),
1501                    location: Some(self.span_to_source_location(handler.span)),
1502                });
1503            }
1504
1505            let handler_type_str = match handler.handler_type {
1506                AnnotationHandlerType::Before => "before",
1507                AnnotationHandlerType::After => "after",
1508                AnnotationHandlerType::OnDefine => "on_define",
1509                AnnotationHandlerType::Metadata => "metadata",
1510                AnnotationHandlerType::ComptimePre => unreachable!(),
1511                AnnotationHandlerType::ComptimePost => unreachable!(),
1512            };
1513
1514            let func_name = format!("{}___{}", ann_def.name, handler_type_str);
1515
1516            // Build function params: self + annotation_params + handler_params
1517            let mut params = vec![FunctionParameter {
1518                pattern: shape_ast::ast::DestructurePattern::Identifier(
1519                    "self".to_string(),
1520                    Span::DUMMY,
1521                ),
1522                is_const: false,
1523                is_reference: false,
1524                is_mut_reference: false,
1525                type_annotation: None,
1526                default_value: None,
1527            }];
1528            // Add annotation params (e.g., period)
1529            for ann_param in &ann_def.params {
1530                params.push(ann_param.clone());
1531            }
1532            // Add handler params (e.g., args, ctx)
1533            for param in &handler.params {
1534                let inferred_type = if param.name == "ctx" {
1535                    Some(TypeAnnotation::Object(vec![
1536                        shape_ast::ast::ObjectTypeField {
1537                            name: "state".to_string(),
1538                            optional: false,
1539                            type_annotation: TypeAnnotation::Any,
1540                            annotations: vec![],
1541                        },
1542                        shape_ast::ast::ObjectTypeField {
1543                            name: "event_log".to_string(),
1544                            optional: false,
1545                            type_annotation: TypeAnnotation::Array(Box::new(TypeAnnotation::Any)),
1546                            annotations: vec![],
1547                        },
1548                    ]))
1549                } else if matches!(
1550                    handler.handler_type,
1551                    AnnotationHandlerType::OnDefine | AnnotationHandlerType::Metadata
1552                ) && (param.name == "fn" || param.name == "target")
1553                {
1554                    Some(TypeAnnotation::Object(vec![
1555                        shape_ast::ast::ObjectTypeField {
1556                            name: "name".to_string(),
1557                            optional: false,
1558                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1559                            annotations: vec![],
1560                        },
1561                        shape_ast::ast::ObjectTypeField {
1562                            name: "kind".to_string(),
1563                            optional: false,
1564                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1565                            annotations: vec![],
1566                        },
1567                        shape_ast::ast::ObjectTypeField {
1568                            name: "id".to_string(),
1569                            optional: false,
1570                            type_annotation: TypeAnnotation::Basic("int".to_string()),
1571                            annotations: vec![],
1572                        },
1573                    ]))
1574                } else {
1575                    None
1576                };
1577
1578                params.push(FunctionParameter {
1579                    pattern: shape_ast::ast::DestructurePattern::Identifier(
1580                        param.name.clone(),
1581                        Span::DUMMY,
1582                    ),
1583                    is_const: false,
1584                    is_reference: false,
1585                    is_mut_reference: false,
1586                    type_annotation: inferred_type,
1587                    default_value: None,
1588                });
1589            }
1590
1591            // Convert handler body (Expr) to function body (Vec<Statement>)
1592            let body = vec![Statement::Return(Some(handler.body.clone()), Span::DUMMY)];
1593
1594            let func_def = FunctionDef {
1595                name: func_name,
1596                name_span: Span::DUMMY,
1597                params,
1598                return_type: handler.return_type.clone(),
1599                body,
1600                type_params: Some(Vec::new()),
1601                annotations: Vec::new(),
1602                is_async: false,
1603                is_comptime: false,
1604                where_clause: None,
1605            };
1606
1607            self.register_function(&func_def)?;
1608            self.compile_function(&func_def)?;
1609
1610            let func_id = (self.program.functions.len() - 1) as u16;
1611
1612            match handler.handler_type {
1613                AnnotationHandlerType::Before => compiled.before_handler = Some(func_id),
1614                AnnotationHandlerType::After => compiled.after_handler = Some(func_id),
1615                AnnotationHandlerType::OnDefine => compiled.on_define_handler = Some(func_id),
1616                AnnotationHandlerType::Metadata => compiled.metadata_handler = Some(func_id),
1617                AnnotationHandlerType::ComptimePre => {} // handled above
1618                AnnotationHandlerType::ComptimePost => {} // handled above
1619            }
1620        }
1621
1622        // Resolve allowed target kinds.
1623        // Explicit `targets: [...]` in the annotation definition has priority.
1624        // Otherwise infer from handlers:
1625        // before/after handlers only make sense on functions (they wrap calls),
1626        // lifecycle handlers (on_define/metadata) are definition-time only.
1627        if let Some(explicit) = &ann_def.allowed_targets {
1628            compiled.allowed_targets = explicit.clone();
1629        } else if compiled.before_handler.is_some()
1630            || compiled.after_handler.is_some()
1631            || compiled.comptime_pre_handler.is_some()
1632            || compiled.comptime_post_handler.is_some()
1633        {
1634            compiled.allowed_targets =
1635                vec![shape_ast::ast::functions::AnnotationTargetKind::Function];
1636        } else if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
1637            compiled.allowed_targets = vec![
1638                shape_ast::ast::functions::AnnotationTargetKind::Function,
1639                shape_ast::ast::functions::AnnotationTargetKind::Type,
1640                shape_ast::ast::functions::AnnotationTargetKind::Module,
1641            ];
1642        }
1643
1644        // Enforce that definition-time lifecycle hooks only target definition
1645        // sites (`function` / `type`).
1646        if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
1647            if compiled.allowed_targets.is_empty() {
1648                return Err(ShapeError::SemanticError {
1649                    message: format!(
1650                        "Annotation '{}' uses `on_define`/`metadata` and cannot have unrestricted targets. Allowed targets are: function, type, module",
1651                        ann_def.name
1652                    ),
1653                    location: Some(self.span_to_source_location(ann_def.span)),
1654                });
1655            }
1656            if let Some(invalid) = compiled
1657                .allowed_targets
1658                .iter()
1659                .find(|kind| !Self::is_definition_annotation_target(**kind))
1660            {
1661                let invalid_label = format!("{:?}", invalid).to_lowercase();
1662                return Err(ShapeError::SemanticError {
1663                    message: format!(
1664                        "Annotation '{}' uses `on_define`/`metadata`, but target '{}' is not a definition target. Allowed targets are: function, type, module",
1665                        ann_def.name, invalid_label
1666                    ),
1667                    location: Some(self.span_to_source_location(ann_def.span)),
1668                });
1669            }
1670        }
1671
1672        self.program
1673            .compiled_annotations
1674            .insert(ann_def.name.clone(), compiled);
1675        Ok(())
1676    }
1677
1678    /// Register a struct type definition.
1679    ///
1680    /// Comptime fields are baked at compile time and excluded from the runtime TypeSchema.
1681    /// Their values are stored in `self.comptime_fields` for constant-folded access.
1682    fn register_struct_type(
1683        &mut self,
1684        struct_def: &shape_ast::ast::StructTypeDef,
1685        span: shape_ast::ast::Span,
1686    ) -> Result<()> {
1687        use shape_ast::ast::Literal;
1688        use shape_runtime::type_schema::{FieldAnnotation, TypeSchemaBuilder};
1689
1690        // Validate annotation target kinds before type registration.
1691        for ann in &struct_def.annotations {
1692            self.validate_annotation_target_usage(
1693                ann,
1694                shape_ast::ast::functions::AnnotationTargetKind::Type,
1695                span,
1696            )?;
1697        }
1698
1699        if struct_def.native_layout.is_some() {
1700            self.native_layout_types.insert(struct_def.name.clone());
1701        } else {
1702            self.native_layout_types.remove(&struct_def.name);
1703        }
1704
1705        // Pre-register runtime field layout so comptime-generated methods on
1706        // `extend target { ... }` can resolve `self.field` statically.
1707        // If the target is later removed by comptime directives, these
1708        // placeholders are rolled back below.
1709        let runtime_field_names: Vec<String> = struct_def
1710            .fields
1711            .iter()
1712            .filter(|f| !f.is_comptime)
1713            .map(|f| f.name.clone())
1714            .collect();
1715        let runtime_field_types = struct_def
1716            .fields
1717            .iter()
1718            .filter(|f| !f.is_comptime)
1719            .map(|f| (f.name.clone(), f.type_annotation.clone()))
1720            .collect::<std::collections::HashMap<_, _>>();
1721        self.struct_types
1722            .insert(struct_def.name.clone(), (runtime_field_names, span));
1723        self.struct_generic_info.insert(
1724            struct_def.name.clone(),
1725            StructGenericInfo {
1726                type_params: struct_def.type_params.clone().unwrap_or_default(),
1727                runtime_field_types,
1728            },
1729        );
1730        if self
1731            .type_tracker
1732            .schema_registry()
1733            .get(&struct_def.name)
1734            .is_none()
1735        {
1736            let runtime_fields: Vec<(String, shape_runtime::type_schema::FieldType)> = struct_def
1737                .fields
1738                .iter()
1739                .filter(|f| !f.is_comptime)
1740                .map(|f| {
1741                    (
1742                        f.name.clone(),
1743                        Self::type_annotation_to_field_type(&f.type_annotation),
1744                    )
1745                })
1746                .collect();
1747            self.type_tracker
1748                .schema_registry_mut()
1749                .register_type(struct_def.name.clone(), runtime_fields);
1750        }
1751
1752        // Execute comptime annotation handlers before registration so
1753        // `remove target` can suppress type emission entirely.
1754        if self.execute_struct_comptime_handlers(struct_def)? {
1755            self.struct_types.remove(&struct_def.name);
1756            self.struct_generic_info.remove(&struct_def.name);
1757            return Ok(());
1758        }
1759
1760        if struct_def.native_layout.is_some() {
1761            self.register_native_struct_layout(struct_def, span)?;
1762        }
1763
1764        // Build TypeSchema for runtime fields only
1765        if self
1766            .type_tracker
1767            .schema_registry()
1768            .get(&struct_def.name)
1769            .is_none()
1770        {
1771            let mut builder = TypeSchemaBuilder::new(struct_def.name.clone());
1772            for field in &struct_def.fields {
1773                if field.is_comptime {
1774                    continue;
1775                }
1776                let field_type = Self::type_annotation_to_field_type(&field.type_annotation);
1777                let mut annotations = Vec::new();
1778                for ann in &field.annotations {
1779                    let args: Vec<String> = ann
1780                        .args
1781                        .iter()
1782                        .filter_map(Self::eval_annotation_arg)
1783                        .collect();
1784                    annotations.push(FieldAnnotation {
1785                        name: ann.name.clone(),
1786                        args,
1787                    });
1788                }
1789                builder = builder.field_with_meta(field.name.clone(), field_type, annotations);
1790            }
1791            builder.register(self.type_tracker.schema_registry_mut());
1792        }
1793
1794        // Bake comptime field values
1795        let mut comptime_values = std::collections::HashMap::new();
1796        for field in &struct_def.fields {
1797            if !field.is_comptime {
1798                continue;
1799            }
1800            if let Some(ref default_expr) = field.default_value {
1801                let value = match default_expr {
1802                    Expr::Literal(Literal::Number(n), _) => shape_value::ValueWord::from_f64(*n),
1803                    Expr::Literal(Literal::Int(n), _) => {
1804                        shape_value::ValueWord::from_f64(*n as f64)
1805                    }
1806                    Expr::Literal(Literal::String(s), _) => {
1807                        shape_value::ValueWord::from_string(std::sync::Arc::new(s.clone()))
1808                    }
1809                    Expr::Literal(Literal::Bool(b), _) => shape_value::ValueWord::from_bool(*b),
1810                    Expr::Literal(Literal::None, _) => shape_value::ValueWord::none(),
1811                    _ => {
1812                        return Err(ShapeError::SemanticError {
1813                            message: format!(
1814                                "Comptime field '{}' on type '{}' must have a literal default value",
1815                                field.name, struct_def.name
1816                            ),
1817                            location: None,
1818                        });
1819                    }
1820                };
1821                comptime_values.insert(field.name.clone(), value);
1822            }
1823            // Comptime fields without a default are allowed — they must be
1824            // provided via type alias overrides (e.g., type EUR = Currency { symbol: "€" })
1825        }
1826
1827        if !comptime_values.is_empty() {
1828            self.comptime_fields
1829                .insert(struct_def.name.clone(), comptime_values);
1830        }
1831
1832        self.maybe_generate_native_type_conversions(&struct_def.name, span)?;
1833
1834        Ok(())
1835    }
1836
1837    fn register_native_struct_layout(
1838        &mut self,
1839        struct_def: &shape_ast::ast::StructTypeDef,
1840        span: shape_ast::ast::Span,
1841    ) -> Result<()> {
1842        if struct_def.type_params.is_some() {
1843            return Err(ShapeError::SemanticError {
1844                message: format!(
1845                    "type C '{}' cannot be generic in this version",
1846                    struct_def.name
1847                ),
1848                location: Some(self.span_to_source_location(span)),
1849            });
1850        }
1851
1852        if struct_def.fields.iter().any(|f| f.is_comptime) {
1853            return Err(ShapeError::SemanticError {
1854                message: format!(
1855                    "type C '{}' cannot contain comptime fields",
1856                    struct_def.name
1857                ),
1858                location: Some(self.span_to_source_location(span)),
1859            });
1860        }
1861
1862        let abi = struct_def
1863            .native_layout
1864            .as_ref()
1865            .map(|b| b.abi.clone())
1866            .unwrap_or_else(|| "C".to_string());
1867        if abi != "C" {
1868            return Err(ShapeError::SemanticError {
1869                message: format!(
1870                    "type '{}' uses unsupported native ABI '{}'; only C is supported",
1871                    struct_def.name, abi
1872                ),
1873                location: Some(self.span_to_source_location(span)),
1874            });
1875        }
1876
1877        let mut struct_align: u64 = 1;
1878        let mut offset: u64 = 0;
1879        let mut field_layouts = Vec::with_capacity(struct_def.fields.len());
1880
1881        for field in &struct_def.fields {
1882            let field_spec =
1883                self.native_field_layout_spec(&field.type_annotation, span, &struct_def.name)?;
1884            struct_align = struct_align.max(field_spec.align);
1885            offset = Self::align_to(offset, field_spec.align);
1886            if offset > u32::MAX as u64
1887                || field_spec.size > u32::MAX as u64
1888                || field_spec.align > u32::MAX as u64
1889            {
1890                return Err(ShapeError::SemanticError {
1891                    message: format!(
1892                        "type C '{}' layout exceeds supported size/alignment limits",
1893                        struct_def.name
1894                    ),
1895                    location: Some(self.span_to_source_location(span)),
1896                });
1897            }
1898            field_layouts.push(crate::bytecode::NativeStructFieldLayout {
1899                name: field.name.clone(),
1900                c_type: field_spec.c_type,
1901                offset: offset as u32,
1902                size: field_spec.size as u32,
1903                align: field_spec.align as u32,
1904            });
1905            offset = offset.saturating_add(field_spec.size);
1906        }
1907
1908        let size = Self::align_to(offset, struct_align);
1909        if size > u32::MAX as u64 || struct_align > u32::MAX as u64 {
1910            return Err(ShapeError::SemanticError {
1911                message: format!(
1912                    "type C '{}' layout exceeds supported size/alignment limits",
1913                    struct_def.name
1914                ),
1915                location: Some(self.span_to_source_location(span)),
1916            });
1917        }
1918
1919        let entry = crate::bytecode::NativeStructLayoutEntry {
1920            name: struct_def.name.clone(),
1921            abi,
1922            size: size as u32,
1923            align: struct_align as u32,
1924            fields: field_layouts,
1925        };
1926
1927        if let Some(existing) = self
1928            .program
1929            .native_struct_layouts
1930            .iter_mut()
1931            .find(|existing| existing.name == entry.name)
1932        {
1933            *existing = entry;
1934        } else {
1935            self.program.native_struct_layouts.push(entry);
1936        }
1937
1938        Ok(())
1939    }
1940
1941    fn align_to(value: u64, align: u64) -> u64 {
1942        debug_assert!(align > 0);
1943        let mask = align - 1;
1944        (value + mask) & !mask
1945    }
1946
1947    fn native_field_layout_spec(
1948        &self,
1949        ann: &shape_ast::ast::TypeAnnotation,
1950        span: shape_ast::ast::Span,
1951        struct_name: &str,
1952    ) -> Result<NativeFieldLayoutSpec> {
1953        use shape_ast::ast::TypeAnnotation;
1954
1955        let pointer = std::mem::size_of::<usize>() as u64;
1956
1957        let fail = || -> Result<NativeFieldLayoutSpec> {
1958            Err(ShapeError::SemanticError {
1959                message: format!(
1960                    "unsupported type C field type '{}' in '{}'",
1961                    ann.to_type_string(),
1962                    struct_name
1963                ),
1964                location: Some(self.span_to_source_location(span)),
1965            })
1966        };
1967
1968        match ann {
1969            TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => {
1970                if let Some(existing) = self
1971                    .program
1972                    .native_struct_layouts
1973                    .iter()
1974                    .find(|layout| &layout.name == name)
1975                {
1976                    return Ok(NativeFieldLayoutSpec {
1977                        c_type: name.clone(),
1978                        size: existing.size as u64,
1979                        align: existing.align as u64,
1980                    });
1981                }
1982
1983                let spec = match name.as_str() {
1984                    "f64" | "number" | "Number" | "float" => ("f64", 8, 8),
1985                    "f32" => ("f32", 4, 4),
1986                    "i64" | "int" | "integer" | "Int" | "Integer" => ("i64", 8, 8),
1987                    "i32" => ("i32", 4, 4),
1988                    "i16" => ("i16", 2, 2),
1989                    "i8" | "char" => ("i8", 1, 1),
1990                    "u64" => ("u64", 8, 8),
1991                    "u32" => ("u32", 4, 4),
1992                    "u16" => ("u16", 2, 2),
1993                    "u8" | "byte" => ("u8", 1, 1),
1994                    "bool" | "boolean" => ("bool", 1, 1),
1995                    "isize" => ("isize", pointer, pointer),
1996                    "usize" | "ptr" | "pointer" => ("ptr", pointer, pointer),
1997                    "string" | "str" | "cstring" => ("cstring", pointer, pointer),
1998                    _ => return fail(),
1999                };
2000                Ok(NativeFieldLayoutSpec {
2001                    c_type: spec.0.to_string(),
2002                    size: spec.1,
2003                    align: spec.2,
2004                })
2005            }
2006            TypeAnnotation::Optional(inner) => {
2007                let inner = self.native_field_layout_spec(inner, span, struct_name)?;
2008                if inner.c_type == "cstring" {
2009                    Ok(NativeFieldLayoutSpec {
2010                        c_type: "cstring?".to_string(),
2011                        size: pointer,
2012                        align: pointer,
2013                    })
2014                } else {
2015                    fail()
2016                }
2017            }
2018            _ => fail(),
2019        }
2020    }
2021
2022    fn maybe_generate_native_type_conversions(
2023        &mut self,
2024        type_name: &str,
2025        span: shape_ast::ast::Span,
2026    ) -> Result<()> {
2027        let pair = if self.native_layout_types.contains(type_name) {
2028            let Some(object_type) = Self::object_type_name_for_native_layout(type_name) else {
2029                return Ok(());
2030            };
2031            if !self.struct_types.contains_key(&object_type)
2032                || self.native_layout_types.contains(&object_type)
2033            {
2034                return Ok(());
2035            }
2036            (type_name.to_string(), object_type)
2037        } else {
2038            let candidates: Vec<String> = Self::native_layout_name_candidates_for_object(type_name)
2039                .into_iter()
2040                .filter(|candidate| self.native_layout_types.contains(candidate))
2041                .collect();
2042            if candidates.is_empty() {
2043                return Ok(());
2044            }
2045            if candidates.len() > 1 {
2046                return Err(ShapeError::SemanticError {
2047                    message: format!(
2048                        "type '{}' matches multiple `type C` companions ({}) - use one canonical name",
2049                        type_name,
2050                        candidates.join(", ")
2051                    ),
2052                    location: Some(self.span_to_source_location(span)),
2053                });
2054            }
2055            (candidates[0].clone(), type_name.to_string())
2056        };
2057
2058        let pair_key = format!("{}::{}", pair.0, pair.1);
2059        if self.generated_native_conversion_pairs.contains(&pair_key) {
2060            return Ok(());
2061        }
2062
2063        self.validate_native_conversion_pair(&pair.0, &pair.1, span)?;
2064        self.generate_native_conversion_direction(&pair.0, &pair.1, span)?;
2065        self.generate_native_conversion_direction(&pair.1, &pair.0, span)?;
2066        self.generated_native_conversion_pairs.insert(pair_key);
2067        Ok(())
2068    }
2069
2070    fn object_type_name_for_native_layout(name: &str) -> Option<String> {
2071        if let Some(base) = name.strip_suffix("Layout")
2072            && !base.is_empty()
2073        {
2074            return Some(base.to_string());
2075        }
2076        if let Some(base) = name.strip_suffix('C')
2077            && !base.is_empty()
2078        {
2079            return Some(base.to_string());
2080        }
2081        if let Some(base) = name.strip_prefix('C')
2082            && !base.is_empty()
2083            && base
2084                .chars()
2085                .next()
2086                .map(|ch| ch.is_ascii_uppercase())
2087                .unwrap_or(false)
2088        {
2089            return Some(base.to_string());
2090        }
2091        None
2092    }
2093
2094    fn native_layout_name_candidates_for_object(name: &str) -> Vec<String> {
2095        vec![
2096            format!("{}Layout", name),
2097            format!("{}C", name),
2098            format!("C{}", name),
2099        ]
2100    }
2101
2102    fn validate_native_conversion_pair(
2103        &self,
2104        c_type: &str,
2105        object_type: &str,
2106        span: shape_ast::ast::Span,
2107    ) -> Result<()> {
2108        if !self.native_layout_types.contains(c_type) {
2109            return Err(ShapeError::SemanticError {
2110                message: format!("'{}' is not declared as `type C`", c_type),
2111                location: Some(self.span_to_source_location(span)),
2112            });
2113        }
2114        if self.native_layout_types.contains(object_type) {
2115            return Err(ShapeError::SemanticError {
2116                message: format!(
2117                    "auto conversion target '{}' cannot also be declared as `type C`",
2118                    object_type
2119                ),
2120                location: Some(self.span_to_source_location(span)),
2121            });
2122        }
2123
2124        let c_type_info =
2125            self.struct_generic_info
2126                .get(c_type)
2127                .ok_or_else(|| ShapeError::SemanticError {
2128                    message: format!("missing compiler metadata for `type C {}`", c_type),
2129                    location: Some(self.span_to_source_location(span)),
2130                })?;
2131        let object_type_info =
2132            self.struct_generic_info
2133                .get(object_type)
2134                .ok_or_else(|| ShapeError::SemanticError {
2135                    message: format!(
2136                        "missing compiler metadata for companion type '{}'",
2137                        object_type
2138                    ),
2139                    location: Some(self.span_to_source_location(span)),
2140                })?;
2141
2142        if !c_type_info.type_params.is_empty() || !object_type_info.type_params.is_empty() {
2143            return Err(ShapeError::SemanticError {
2144                message: format!(
2145                    "auto `type C` conversions currently require non-generic types (`{}` <-> `{}`)",
2146                    c_type, object_type
2147                ),
2148                location: Some(self.span_to_source_location(span)),
2149            });
2150        }
2151
2152        let c_fields = self
2153            .struct_types
2154            .get(c_type)
2155            .map(|(fields, _)| fields)
2156            .ok_or_else(|| ShapeError::SemanticError {
2157                message: format!("missing field metadata for `type C {}`", c_type),
2158                location: Some(self.span_to_source_location(span)),
2159            })?;
2160        let object_fields = self
2161            .struct_types
2162            .get(object_type)
2163            .map(|(fields, _)| fields)
2164            .ok_or_else(|| ShapeError::SemanticError {
2165                message: format!(
2166                    "missing field metadata for companion type '{}'",
2167                    object_type
2168                ),
2169                location: Some(self.span_to_source_location(span)),
2170            })?;
2171
2172        let c_field_set: std::collections::HashSet<&str> =
2173            c_fields.iter().map(String::as_str).collect();
2174        let object_field_set: std::collections::HashSet<&str> =
2175            object_fields.iter().map(String::as_str).collect();
2176        if c_field_set != object_field_set {
2177            return Err(ShapeError::SemanticError {
2178                message: format!(
2179                    "auto conversion pair '{}' <-> '{}' must have identical runtime fields",
2180                    c_type, object_type
2181                ),
2182                location: Some(self.span_to_source_location(span)),
2183            });
2184        }
2185
2186        for field_name in c_field_set {
2187            let c_ann = c_type_info
2188                .runtime_field_types
2189                .get(field_name)
2190                .ok_or_else(|| ShapeError::SemanticError {
2191                    message: format!(
2192                        "missing type metadata for field '{}.{}'",
2193                        c_type, field_name
2194                    ),
2195                    location: Some(self.span_to_source_location(span)),
2196                })?;
2197            let object_ann = object_type_info
2198                .runtime_field_types
2199                .get(field_name)
2200                .ok_or_else(|| ShapeError::SemanticError {
2201                    message: format!(
2202                        "missing type metadata for field '{}.{}'",
2203                        object_type, field_name
2204                    ),
2205                    location: Some(self.span_to_source_location(span)),
2206                })?;
2207            if c_ann != object_ann {
2208                return Err(ShapeError::SemanticError {
2209                    message: format!(
2210                        "field type mismatch for auto conversion '{}.{}' (`{}`) vs '{}.{}' (`{}`)",
2211                        c_type,
2212                        field_name,
2213                        c_ann.to_type_string(),
2214                        object_type,
2215                        field_name,
2216                        object_ann.to_type_string()
2217                    ),
2218                    location: Some(self.span_to_source_location(span)),
2219                });
2220            }
2221        }
2222
2223        Ok(())
2224    }
2225
2226    fn generate_native_conversion_direction(
2227        &mut self,
2228        source_type: &str,
2229        target_type: &str,
2230        span: shape_ast::ast::Span,
2231    ) -> Result<()> {
2232        let fn_name = format!(
2233            "__auto_native_from_{}_to_{}",
2234            Self::sanitize_auto_symbol(source_type),
2235            Self::sanitize_auto_symbol(target_type)
2236        );
2237        if self.function_defs.contains_key(&fn_name) {
2238            return Ok(());
2239        }
2240
2241        let target_fields = self
2242            .struct_types
2243            .get(target_type)
2244            .map(|(fields, _)| fields.clone())
2245            .ok_or_else(|| ShapeError::SemanticError {
2246                message: format!(
2247                    "missing target type metadata for auto conversion '{}'",
2248                    target_type
2249                ),
2250                location: Some(self.span_to_source_location(span)),
2251            })?;
2252
2253        let source_expr = Expr::Identifier("value".to_string(), span);
2254        let struct_fields = target_fields
2255            .iter()
2256            .map(|field| {
2257                (
2258                    field.clone(),
2259                    Expr::PropertyAccess {
2260                        object: Box::new(source_expr.clone()),
2261                        property: field.clone(),
2262                        optional: false,
2263                        span,
2264                    },
2265                )
2266            })
2267            .collect::<Vec<_>>();
2268        let body = vec![Statement::Return(
2269            Some(Expr::StructLiteral {
2270                type_name: target_type.to_string(),
2271                fields: struct_fields,
2272                span,
2273            }),
2274            span,
2275        )];
2276        let fn_def = FunctionDef {
2277            name: fn_name.clone(),
2278            name_span: span,
2279            params: vec![FunctionParameter {
2280                pattern: DestructurePattern::Identifier("value".to_string(), span),
2281                is_const: false,
2282                is_reference: false,
2283                is_mut_reference: false,
2284                type_annotation: Some(TypeAnnotation::Reference(source_type.to_string())),
2285                default_value: None,
2286            }],
2287            return_type: Some(TypeAnnotation::Reference(target_type.to_string())),
2288            body,
2289            type_params: Some(Vec::new()),
2290            annotations: Vec::new(),
2291            is_async: false,
2292            is_comptime: false,
2293            where_clause: None,
2294        };
2295        self.register_function(&fn_def)?;
2296        self.compile_function(&fn_def)?;
2297
2298        self.program.register_trait_method_symbol(
2299            "From",
2300            target_type,
2301            Some(source_type),
2302            "from",
2303            &fn_name,
2304        );
2305        self.program.register_trait_method_symbol(
2306            "Into",
2307            source_type,
2308            Some(target_type),
2309            "into",
2310            &fn_name,
2311        );
2312        let _ = self.type_inference.env.register_trait_impl_named(
2313            "From",
2314            target_type,
2315            source_type,
2316            vec!["from".to_string()],
2317        );
2318        let _ = self.type_inference.env.register_trait_impl_named(
2319            "Into",
2320            source_type,
2321            target_type,
2322            vec!["into".to_string()],
2323        );
2324        Ok(())
2325    }
2326
2327    fn sanitize_auto_symbol(name: &str) -> String {
2328        let mut out = String::with_capacity(name.len());
2329        for ch in name.chars() {
2330            if ch.is_ascii_alphanumeric() {
2331                out.push(ch);
2332            } else {
2333                out.push('_');
2334            }
2335        }
2336        out
2337    }
2338
2339    /// Execute comptime annotation handlers for a struct type definition.
2340    ///
2341    /// Mirrors `execute_comptime_handlers` in functions.rs but uses
2342    /// `ComptimeTarget::from_type()` to build the target from struct fields.
2343    fn execute_struct_comptime_handlers(
2344        &mut self,
2345        struct_def: &shape_ast::ast::StructTypeDef,
2346    ) -> Result<bool> {
2347        let mut removed = false;
2348        for ann in &struct_def.annotations {
2349            let compiled = self.program.compiled_annotations.get(&ann.name).cloned();
2350            if let Some(compiled) = compiled {
2351                let handlers = [
2352                    compiled.comptime_pre_handler,
2353                    compiled.comptime_post_handler,
2354                ];
2355                for handler in handlers.into_iter().flatten() {
2356                    // Build field info for ComptimeTarget::from_type()
2357                    let fields: Vec<(String, Option<shape_ast::ast::TypeAnnotation>)> = struct_def
2358                        .fields
2359                        .iter()
2360                        .map(|f| (f.name.clone(), Some(f.type_annotation.clone())))
2361                        .collect();
2362
2363                    let target = super::comptime_target::ComptimeTarget::from_type(
2364                        &struct_def.name,
2365                        &fields,
2366                    );
2367                    let target_value = target.to_nanboxed();
2368                    let target_name = struct_def.name.clone();
2369                    let handler_span = handler.span;
2370                    let execution =
2371                        self.execute_comptime_annotation_handler(ann, &handler, target_value, &[])?;
2372
2373                    if self
2374                        .process_comptime_directives(execution.directives, &target_name)
2375                        .map_err(|e| ShapeError::RuntimeError {
2376                            message: format!(
2377                                "Comptime handler '{}' directive processing failed: {}",
2378                                ann.name, e
2379                            ),
2380                            location: Some(self.span_to_source_location(handler_span)),
2381                        })?
2382                    {
2383                        removed = true;
2384                        break;
2385                    }
2386                }
2387            }
2388            if removed {
2389                break;
2390            }
2391        }
2392        Ok(removed)
2393    }
2394
2395    fn current_module_path_for(&self, module_name: &str) -> String {
2396        if let Some(parent) = self.module_scope_stack.last() {
2397            format!("{}::{}", parent, module_name)
2398        } else {
2399            module_name.to_string()
2400        }
2401    }
2402
2403    fn qualify_module_symbol(module_path: &str, name: &str) -> String {
2404        format!("{}::{}", module_path, name)
2405    }
2406
2407    fn qualify_module_item(&self, item: &Item, module_path: &str) -> Result<Item> {
2408        match item {
2409            Item::Function(func, span) => {
2410                let mut qualified = func.clone();
2411                qualified.name = Self::qualify_module_symbol(module_path, &func.name);
2412                Ok(Item::Function(qualified, *span))
2413            }
2414            Item::VariableDecl(decl, span) => {
2415                if decl.kind != VarKind::Const {
2416                    return Err(ShapeError::SemanticError {
2417                        message: "module-level variable declarations currently require `const`"
2418                            .to_string(),
2419                        location: Some(self.span_to_source_location(*span)),
2420                    });
2421                }
2422                let mut qualified = decl.clone();
2423                let Some(name) = decl.pattern.as_identifier() else {
2424                    return Err(ShapeError::SemanticError {
2425                        message:
2426                            "module-level constants currently require a simple identifier binding"
2427                                .to_string(),
2428                        location: Some(self.span_to_source_location(*span)),
2429                    });
2430                };
2431                qualified.pattern = DestructurePattern::Identifier(
2432                    Self::qualify_module_symbol(module_path, name),
2433                    *span,
2434                );
2435                Ok(Item::VariableDecl(qualified, *span))
2436            }
2437            Item::Statement(Statement::VariableDecl(decl, stmt_span), item_span) => {
2438                if decl.kind != VarKind::Const {
2439                    return Err(ShapeError::SemanticError {
2440                        message: "module-level variable declarations currently require `const`"
2441                            .to_string(),
2442                        location: Some(self.span_to_source_location(*stmt_span)),
2443                    });
2444                }
2445                let mut qualified = decl.clone();
2446                let Some(name) = decl.pattern.as_identifier() else {
2447                    return Err(ShapeError::SemanticError {
2448                        message:
2449                            "module-level constants currently require a simple identifier binding"
2450                                .to_string(),
2451                        location: Some(self.span_to_source_location(*stmt_span)),
2452                    });
2453                };
2454                qualified.pattern = DestructurePattern::Identifier(
2455                    Self::qualify_module_symbol(module_path, name),
2456                    *stmt_span,
2457                );
2458                Ok(Item::Statement(
2459                    Statement::VariableDecl(qualified, *stmt_span),
2460                    *item_span,
2461                ))
2462            }
2463            Item::Statement(Statement::Assignment(assign, stmt_span), item_span) => {
2464                let mut qualified = assign.clone();
2465                if let Some(name) = assign.pattern.as_identifier() {
2466                    qualified.pattern = DestructurePattern::Identifier(
2467                        Self::qualify_module_symbol(module_path, name),
2468                        *stmt_span,
2469                    );
2470                }
2471                Ok(Item::Statement(
2472                    Statement::Assignment(qualified, *stmt_span),
2473                    *item_span,
2474                ))
2475            }
2476            Item::Export(export, span) if export.source_decl.is_some() => {
2477                // pub const/let/var: unwrap the source_decl and qualify it as a VariableDecl
2478                let decl = export.source_decl.as_ref().unwrap();
2479                if decl.kind != VarKind::Const {
2480                    return Err(ShapeError::SemanticError {
2481                        message: "module-level variable declarations currently require `const`"
2482                            .to_string(),
2483                        location: Some(self.span_to_source_location(*span)),
2484                    });
2485                }
2486                let mut qualified = decl.clone();
2487                let Some(name) = decl.pattern.as_identifier() else {
2488                    return Err(ShapeError::SemanticError {
2489                        message:
2490                            "module-level constants currently require a simple identifier binding"
2491                                .to_string(),
2492                        location: Some(self.span_to_source_location(*span)),
2493                    });
2494                };
2495                qualified.pattern = DestructurePattern::Identifier(
2496                    Self::qualify_module_symbol(module_path, name),
2497                    *span,
2498                );
2499                Ok(Item::VariableDecl(qualified, *span))
2500            }
2501            _ => Ok(item.clone()),
2502        }
2503    }
2504
2505    fn collect_module_runtime_exports(
2506        &self,
2507        items: &[Item],
2508        module_path: &str,
2509    ) -> Vec<(String, String)> {
2510        let mut exports = Vec::new();
2511        for item in items {
2512            match item {
2513                Item::Function(func, _) => {
2514                    exports.push((
2515                        func.name.clone(),
2516                        Self::qualify_module_symbol(module_path, &func.name),
2517                    ));
2518                }
2519                Item::VariableDecl(decl, _) => {
2520                    if decl.kind == VarKind::Const
2521                        && let Some(name) = decl.pattern.as_identifier()
2522                    {
2523                        exports.push((
2524                            name.to_string(),
2525                            Self::qualify_module_symbol(module_path, name),
2526                        ));
2527                    }
2528                }
2529                Item::Statement(Statement::VariableDecl(decl, _), _) => {
2530                    if decl.kind == VarKind::Const
2531                        && let Some(name) = decl.pattern.as_identifier()
2532                    {
2533                        exports.push((
2534                            name.to_string(),
2535                            Self::qualify_module_symbol(module_path, name),
2536                        ));
2537                    }
2538                }
2539                Item::Export(export, _) => {
2540                    if let Some(ref decl) = export.source_decl {
2541                        if let Some(name) = decl.pattern.as_identifier() {
2542                            exports.push((
2543                                name.to_string(),
2544                                Self::qualify_module_symbol(module_path, name),
2545                            ));
2546                        }
2547                    }
2548                }
2549                Item::Module(module, _) => {
2550                    exports.push((
2551                        module.name.clone(),
2552                        Self::qualify_module_symbol(module_path, &module.name),
2553                    ));
2554                }
2555                _ => {}
2556            }
2557        }
2558        exports.sort_by(|a, b| a.0.cmp(&b.0));
2559        exports.dedup_by(|a, b| a.0 == b.0);
2560        exports
2561    }
2562
2563    fn module_target_fields(items: &[Item]) -> Vec<(String, String)> {
2564        let mut fields = Vec::new();
2565        for item in items {
2566            match item {
2567                Item::Function(func, _) => fields.push((func.name.clone(), "function".to_string())),
2568                Item::VariableDecl(decl, _) => {
2569                    if let Some(name) = decl.pattern.as_identifier() {
2570                        let type_name = decl
2571                            .type_annotation
2572                            .as_ref()
2573                            .and_then(TypeAnnotation::as_simple_name)
2574                            .unwrap_or("any")
2575                            .to_string();
2576                        fields.push((name.to_string(), type_name));
2577                    }
2578                }
2579                Item::Statement(Statement::VariableDecl(decl, _), _) => {
2580                    if let Some(name) = decl.pattern.as_identifier() {
2581                        let type_name = decl
2582                            .type_annotation
2583                            .as_ref()
2584                            .and_then(TypeAnnotation::as_simple_name)
2585                            .unwrap_or("any")
2586                            .to_string();
2587                        fields.push((name.to_string(), type_name));
2588                    }
2589                }
2590                Item::Export(export, _) => {
2591                    if let Some(ref decl) = export.source_decl {
2592                        if let Some(name) = decl.pattern.as_identifier() {
2593                            let type_name = decl
2594                                .type_annotation
2595                                .as_ref()
2596                                .and_then(TypeAnnotation::as_simple_name)
2597                                .unwrap_or("any")
2598                                .to_string();
2599                            fields.push((name.to_string(), type_name));
2600                        }
2601                    }
2602                }
2603                Item::StructType(def, _) => fields.push((def.name.clone(), "type".to_string())),
2604                Item::Enum(def, _) => fields.push((def.name.clone(), "type".to_string())),
2605                Item::TypeAlias(def, _) => fields.push((def.name.clone(), "type".to_string())),
2606                Item::Module(def, _) => fields.push((def.name.clone(), "module".to_string())),
2607                _ => {}
2608            }
2609        }
2610        fields
2611    }
2612
2613    fn process_comptime_directives_for_module(
2614        &mut self,
2615        directives: Vec<super::comptime_builtins::ComptimeDirective>,
2616        module_name: &str,
2617        module_items: &mut Vec<Item>,
2618    ) -> std::result::Result<bool, String> {
2619        let mut removed = false;
2620        for directive in directives {
2621            match directive {
2622                super::comptime_builtins::ComptimeDirective::Extend(extend) => {
2623                    self.apply_comptime_extend(extend, module_name)
2624                        .map_err(|e| e.to_string())?;
2625                }
2626                super::comptime_builtins::ComptimeDirective::RemoveTarget => {
2627                    removed = true;
2628                    break;
2629                }
2630                super::comptime_builtins::ComptimeDirective::ReplaceModule { items } => {
2631                    *module_items = items;
2632                }
2633                super::comptime_builtins::ComptimeDirective::SetParamType { .. } => {
2634                    return Err(
2635                        "`set param` directives are only valid when compiling function targets"
2636                            .to_string(),
2637                    );
2638                }
2639                super::comptime_builtins::ComptimeDirective::SetReturnType { .. } => {
2640                    return Err(
2641                        "`set return` directives are only valid when compiling function targets"
2642                            .to_string(),
2643                    );
2644                }
2645                super::comptime_builtins::ComptimeDirective::ReplaceBody { .. } => {
2646                    return Err(
2647                        "`replace body` directives are only valid when compiling function targets"
2648                            .to_string(),
2649                    );
2650                }
2651            }
2652        }
2653        Ok(removed)
2654    }
2655
2656    fn execute_module_comptime_handlers(
2657        &mut self,
2658        module_def: &ModuleDecl,
2659        module_path: &str,
2660        module_items: &mut Vec<Item>,
2661    ) -> Result<bool> {
2662        let mut removed = false;
2663        for ann in &module_def.annotations {
2664            let compiled = self.program.compiled_annotations.get(&ann.name).cloned();
2665            if let Some(compiled) = compiled {
2666                let handlers = [
2667                    compiled.comptime_pre_handler,
2668                    compiled.comptime_post_handler,
2669                ];
2670                for handler in handlers.into_iter().flatten() {
2671                    let target = super::comptime_target::ComptimeTarget::from_module(
2672                        module_path,
2673                        &Self::module_target_fields(module_items),
2674                    );
2675                    let target_value = target.to_nanboxed();
2676                    let handler_span = handler.span;
2677                    let execution =
2678                        self.execute_comptime_annotation_handler(ann, &handler, target_value, &[])?;
2679                    if self
2680                        .process_comptime_directives_for_module(
2681                            execution.directives,
2682                            module_path,
2683                            module_items,
2684                        )
2685                        .map_err(|e| ShapeError::RuntimeError {
2686                            message: format!(
2687                                "Comptime handler '{}' directive processing failed: {}",
2688                                ann.name, e
2689                            ),
2690                            location: Some(self.span_to_source_location(handler_span)),
2691                        })?
2692                    {
2693                        removed = true;
2694                        break;
2695                    }
2696                }
2697            }
2698            if removed {
2699                break;
2700            }
2701        }
2702        Ok(removed)
2703    }
2704
2705    fn inject_module_local_comptime_helper_aliases(
2706        &self,
2707        module_path: &str,
2708        helpers: &mut Vec<FunctionDef>,
2709    ) {
2710        let module_prefix = format!("{}::", module_path);
2711        let mut seen: std::collections::HashSet<String> =
2712            helpers.iter().map(|h| h.name.clone()).collect();
2713        let mut aliases = Vec::new();
2714
2715        for helper in helpers.iter() {
2716            let Some(local_name) = helper.name.strip_prefix(&module_prefix) else {
2717                continue;
2718            };
2719            if local_name.contains("::") || !seen.insert(local_name.to_string()) {
2720                continue;
2721            }
2722            let mut alias = helper.clone();
2723            alias.name = local_name.to_string();
2724            aliases.push(alias);
2725        }
2726
2727        helpers.extend(aliases);
2728    }
2729
2730    fn execute_module_inline_comptime_blocks(
2731        &mut self,
2732        module_path: &str,
2733        module_items: &mut Vec<Item>,
2734    ) -> Result<bool> {
2735        loop {
2736            let Some(idx) = module_items
2737                .iter()
2738                .position(|item| matches!(item, Item::Comptime(_, _)))
2739            else {
2740                break;
2741            };
2742
2743            let (stmts, span) = match module_items[idx].clone() {
2744                Item::Comptime(stmts, span) => (stmts, span),
2745                _ => unreachable!("index is guarded by position() matcher"),
2746            };
2747
2748            let extensions: Vec<_> = self
2749                .extension_registry
2750                .as_ref()
2751                .map(|r| r.as_ref().clone())
2752                .unwrap_or_default();
2753            let trait_impls = self.type_inference.env.trait_impl_keys();
2754            let known_type_symbols: std::collections::HashSet<String> = self
2755                .struct_types
2756                .keys()
2757                .chain(self.type_aliases.keys())
2758                .cloned()
2759                .collect();
2760            let mut comptime_helpers = self.collect_comptime_helpers();
2761            self.inject_module_local_comptime_helper_aliases(module_path, &mut comptime_helpers);
2762
2763            let execution = super::comptime::execute_comptime(
2764                &stmts,
2765                &comptime_helpers,
2766                &extensions,
2767                trait_impls,
2768                known_type_symbols,
2769            )
2770            .map_err(|e| ShapeError::RuntimeError {
2771                message: format!(
2772                    "Comptime block evaluation failed: {}",
2773                    super::helpers::strip_error_prefix(&e)
2774                ),
2775                location: Some(self.span_to_source_location(span)),
2776            })?;
2777
2778            if self
2779                .process_comptime_directives_for_module(
2780                    execution.directives,
2781                    module_path,
2782                    module_items,
2783                )
2784                .map_err(|e| ShapeError::RuntimeError {
2785                    message: format!("Comptime block directive processing failed: {}", e),
2786                    location: Some(self.span_to_source_location(span)),
2787                })?
2788            {
2789                return Ok(true);
2790            }
2791
2792            if idx < module_items.len() && matches!(module_items[idx], Item::Comptime(_, _)) {
2793                module_items.remove(idx);
2794            }
2795        }
2796
2797        Ok(false)
2798    }
2799
2800    fn register_missing_module_functions(&mut self, item: &Item) -> Result<()> {
2801        match item {
2802            Item::Function(func, _) => {
2803                if !self.function_defs.contains_key(&func.name) {
2804                    self.register_function(func)?;
2805                }
2806                Ok(())
2807            }
2808            Item::Export(export, _) => match &export.item {
2809                ExportItem::Function(func) => {
2810                    if !self.function_defs.contains_key(&func.name) {
2811                        self.register_function(func)?;
2812                    }
2813                    Ok(())
2814                }
2815                _ => Ok(()),
2816            },
2817            Item::Module(module, _) => {
2818                let module_path = self.current_module_path_for(module.name.as_str());
2819                self.module_scope_stack.push(module_path.clone());
2820                let register_result = (|| -> Result<()> {
2821                    for inner in &module.items {
2822                        let qualified = self.qualify_module_item(inner, &module_path)?;
2823                        self.register_missing_module_functions(&qualified)?;
2824                    }
2825                    Ok(())
2826                })();
2827                self.module_scope_stack.pop();
2828                register_result
2829            }
2830            _ => Ok(()),
2831        }
2832    }
2833
2834    fn compile_module_decl(&mut self, module_def: &ModuleDecl, span: Span) -> Result<()> {
2835        for ann in &module_def.annotations {
2836            self.validate_annotation_target_usage(ann, AnnotationTargetKind::Module, span)?;
2837        }
2838
2839        let module_path = self.current_module_path_for(&module_def.name);
2840        self.module_scope_stack.push(module_path.clone());
2841
2842        let mut module_items = module_def.items.clone();
2843        if self.execute_module_comptime_handlers(module_def, &module_path, &mut module_items)? {
2844            self.module_scope_stack.pop();
2845            return Ok(());
2846        }
2847        if self.execute_module_inline_comptime_blocks(&module_path, &mut module_items)? {
2848            self.module_scope_stack.pop();
2849            return Ok(());
2850        }
2851
2852        let mut qualified_items = Vec::with_capacity(module_items.len());
2853        for inner in &module_items {
2854            qualified_items.push(self.qualify_module_item(inner, &module_path)?);
2855        }
2856
2857        for qualified in &qualified_items {
2858            self.register_missing_module_functions(qualified)?;
2859        }
2860
2861        for qualified in &qualified_items {
2862            self.compile_item_with_context(qualified, false)?;
2863        }
2864
2865        let exports = self.collect_module_runtime_exports(&module_items, &module_path);
2866        let entries: Vec<ObjectEntry> = exports
2867            .into_iter()
2868            .map(|(name, value_ident)| ObjectEntry::Field {
2869                key: name,
2870                value: Expr::Identifier(value_ident, span),
2871                type_annotation: None,
2872            })
2873            .collect();
2874        let module_object = Expr::Object(entries, span);
2875        self.compile_expr(&module_object)?;
2876
2877        let binding_idx = self.get_or_create_module_binding(&module_path);
2878        self.emit(Instruction::new(
2879            OpCode::StoreModuleBinding,
2880            Some(Operand::ModuleBinding(binding_idx)),
2881        ));
2882        self.propagate_initializer_type_to_slot(binding_idx, false, false);
2883
2884        if self.module_scope_stack.len() == 1 {
2885            self.module_namespace_bindings
2886                .insert(module_def.name.clone());
2887        }
2888
2889        self.emit_annotation_lifecycle_calls_for_module(
2890            &module_path,
2891            &module_def.annotations,
2892            Some(binding_idx),
2893        )?;
2894
2895        self.module_scope_stack.pop();
2896        Ok(())
2897    }
2898
2899    /// Compile a query (Backtest, Alert, or With/CTE).
2900    ///
2901    /// For CTE (WITH) queries:
2902    /// 1. Compile each CTE subquery and store the result in a named module_binding variable.
2903    /// 2. Compile the main query (which can reference CTEs by name as variables).
2904    ///
2905    /// For Backtest and Alert queries, emit a stub for now.
2906    fn compile_query(&mut self, query: &Query) -> Result<()> {
2907        match query {
2908            Query::With(with_query) => {
2909                // Compile each CTE: evaluate its subquery and store as a named variable
2910                for cte in &with_query.ctes {
2911                    // Recursively compile the CTE's subquery
2912                    self.compile_query(&cte.query)?;
2913
2914                    // Store the result in a module_binding variable with the CTE's name
2915                    let binding_idx = self.get_or_create_module_binding(&cte.name);
2916                    self.emit(Instruction::new(
2917                        OpCode::StoreModuleBinding,
2918                        Some(Operand::ModuleBinding(binding_idx)),
2919                    ));
2920                }
2921
2922                // Compile the main query
2923                self.compile_query(&with_query.query)?;
2924            }
2925            Query::Backtest(_backtest) => {
2926                // Backtest queries require runtime context to evaluate.
2927                // Push null as placeholder — the runtime executor handles backtest
2928                // execution when given a full ExecutionContext.
2929                self.emit(Instruction::simple(OpCode::PushNull));
2930            }
2931            Query::Alert(alert) => {
2932                // Compile alert condition
2933                self.compile_expr(&alert.condition)?;
2934                // Push null as placeholder (alert evaluation requires runtime context)
2935                self.emit(Instruction::simple(OpCode::Pop));
2936                self.emit(Instruction::simple(OpCode::PushNull));
2937            }
2938        }
2939        Ok(())
2940    }
2941
2942    pub(super) fn propagate_initializer_type_to_slot(&mut self, slot: u16, is_local: bool, _is_mutable: bool) {
2943        self.propagate_assignment_type_to_slot(slot, is_local, true);
2944    }
2945
2946    /// Compile a statement
2947    pub(super) fn compile_statement(&mut self, stmt: &Statement) -> Result<()> {
2948        match stmt {
2949            Statement::Return(expr_opt, _span) => {
2950                // Prevent returning references — refs are scoped borrows
2951                // that cannot escape the function (would create dangling refs).
2952                if let Some(expr) = expr_opt {
2953                    if let Expr::Reference { span: ref_span, .. } = expr {
2954                        return Err(ShapeError::SemanticError {
2955                            message: "cannot return a reference — references are scoped borrows that cannot escape the function. Return an owned value instead".to_string(),
2956                            location: Some(self.span_to_source_location(*ref_span)),
2957                        });
2958                    }
2959                    // Note: returning a ref_local identifier is allowed — compile_expr
2960                    // emits DerefLoad which returns the dereferenced *value*, not the
2961                    // reference itself. Only returning `&x` (Expr::Reference) is blocked.
2962                    self.compile_expr(expr)?;
2963                } else {
2964                    self.emit(Instruction::simple(OpCode::PushNull));
2965                }
2966                // Emit drops for all active drop scopes before returning
2967                let total_scopes = self.drop_locals.len();
2968                if total_scopes > 0 {
2969                    self.emit_drops_for_early_exit(total_scopes)?;
2970                }
2971                self.emit(Instruction::simple(OpCode::ReturnValue));
2972            }
2973
2974            Statement::Break(_) => {
2975                let in_loop = !self.loop_stack.is_empty();
2976                if in_loop {
2977                    // Emit drops for drop scopes inside the loop before breaking
2978                    let scopes_to_exit = self
2979                        .loop_stack
2980                        .last()
2981                        .map(|ctx| self.drop_locals.len().saturating_sub(ctx.drop_scope_depth))
2982                        .unwrap_or(0);
2983                    if scopes_to_exit > 0 {
2984                        self.emit_drops_for_early_exit(scopes_to_exit)?;
2985                    }
2986                    let jump_idx = self.emit_jump(OpCode::Jump, 0);
2987                    if let Some(loop_ctx) = self.loop_stack.last_mut() {
2988                        loop_ctx.break_jumps.push(jump_idx);
2989                    }
2990                } else {
2991                    return Err(ShapeError::RuntimeError {
2992                        message: "break statement outside of loop".to_string(),
2993                        location: None,
2994                    });
2995                }
2996            }
2997
2998            Statement::Continue(_) => {
2999                if let Some(loop_ctx) = self.loop_stack.last() {
3000                    // Copy values we need before mutable borrow
3001                    let scopes_to_exit = self
3002                        .drop_locals
3003                        .len()
3004                        .saturating_sub(loop_ctx.drop_scope_depth);
3005                    let continue_target = loop_ctx.continue_target;
3006                    // Emit drops for drop scopes inside the loop before continuing
3007                    if scopes_to_exit > 0 {
3008                        self.emit_drops_for_early_exit(scopes_to_exit)?;
3009                    }
3010                    let offset = continue_target as i32 - self.program.current_offset() as i32 - 1;
3011                    self.emit(Instruction::new(
3012                        OpCode::Jump,
3013                        Some(Operand::Offset(offset)),
3014                    ));
3015                } else {
3016                    return Err(ShapeError::RuntimeError {
3017                        message: "continue statement outside of loop".to_string(),
3018                        location: None,
3019                    });
3020                }
3021            }
3022
3023            Statement::VariableDecl(var_decl, _) => {
3024                // Set pending variable name for hoisting integration.
3025                // compile_typed_object_literal uses self to include hoisted fields in the schema.
3026                self.pending_variable_name =
3027                    var_decl.pattern.as_identifier().map(|s| s.to_string());
3028
3029                // Compile-time range check: if the type annotation is a width type
3030                // (i8, u8, i16, etc.) and the initializer is a constant expression,
3031                // verify the value fits in the declared width.
3032                if let (Some(type_ann), Some(init_expr)) =
3033                    (&var_decl.type_annotation, &var_decl.value)
3034                {
3035                    if let shape_ast::ast::TypeAnnotation::Basic(type_name) = type_ann {
3036                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
3037                            if let Some(const_val) =
3038                                crate::compiler::expressions::function_calls::eval_const_expr_to_nanboxed(init_expr)
3039                            {
3040                                let in_range = if let Some(i) = const_val.as_i64() {
3041                                    w.in_range_i64(i)
3042                                } else if let Some(f) = const_val.as_f64() {
3043                                    // Float → int truncation check
3044                                    let i = f as i64;
3045                                    (i as f64 == f) && w.in_range_i64(i)
3046                                } else {
3047                                    true // non-numeric, let runtime handle it
3048                                };
3049                                if !in_range {
3050                                    return Err(shape_ast::error::ShapeError::SemanticError {
3051                                        message: format!(
3052                                            "value does not fit in `{}` (range {}..={})",
3053                                            type_name,
3054                                            w.min_value(),
3055                                            w.max_value()
3056                                        ),
3057                                        location: Some(self.span_to_source_location(shape_ast::ast::Spanned::span(init_expr))),
3058                                    });
3059                                }
3060                            }
3061                        }
3062                    }
3063                }
3064
3065                // Compile initializer — register the variable even if the initializer fails,
3066                // to prevent cascading "Undefined variable" errors on later references.
3067                let init_err = if let Some(init_expr) = &var_decl.value {
3068                    // Special handling: Table row literal syntax
3069                    // `let t: Table<T> = [a, b], [c, d]` → compile as table construction
3070                    if let Expr::TableRows(rows, tr_span) = init_expr {
3071                        match self.compile_table_rows(rows, &var_decl.type_annotation, *tr_span) {
3072                            Ok(()) => None,
3073                            Err(e) => {
3074                                self.emit(Instruction::simple(OpCode::PushNull));
3075                                Some(e)
3076                            }
3077                        }
3078                    } else {
3079                        match self.compile_expr(init_expr) {
3080                            Ok(()) => None,
3081                            Err(e) => {
3082                                self.emit(Instruction::simple(OpCode::PushNull));
3083                                Some(e)
3084                            }
3085                        }
3086                    }
3087                } else {
3088                    self.emit(Instruction::simple(OpCode::PushNull));
3089                    None
3090                };
3091
3092                // Clear pending variable name after init expression is compiled
3093                self.pending_variable_name = None;
3094
3095                // Emit BindSchema for Table<T> annotations (runtime safety net)
3096                if let Some(ref type_ann) = var_decl.type_annotation {
3097                    if let Some(schema_id) = self.get_table_schema_id(type_ann) {
3098                        self.emit(Instruction::new(
3099                            OpCode::BindSchema,
3100                            Some(Operand::Count(schema_id)),
3101                        ));
3102                    }
3103                }
3104
3105                // At top-level (no current function), create module_bindings; otherwise create locals
3106                if self.current_function.is_none() {
3107                    // Top-level: create module_binding variable
3108                    if let Some(name) = var_decl.pattern.as_identifier() {
3109                        let binding_idx = self.get_or_create_module_binding(name);
3110                        self.emit(Instruction::new(
3111                            OpCode::StoreModuleBinding,
3112                            Some(Operand::ModuleBinding(binding_idx)),
3113                        ));
3114
3115                        // Track const module bindings for reassignment checks
3116                        if var_decl.kind == VarKind::Const {
3117                            self.const_module_bindings.insert(binding_idx);
3118                        }
3119
3120                        // Track immutable `let` bindings at module level
3121                        if var_decl.kind == VarKind::Let && !var_decl.is_mut {
3122                            self.immutable_module_bindings.insert(binding_idx);
3123                        }
3124
3125                        // Track type annotation if present (for type checker)
3126                        if let Some(ref type_ann) = var_decl.type_annotation {
3127                            if let Some(type_name) =
3128                                Self::tracked_type_name_from_annotation(type_ann)
3129                            {
3130                                self.set_module_binding_type_info(binding_idx, &type_name);
3131                            }
3132                            // Handle Table<T> generic annotation
3133                            self.try_track_datatable_type(type_ann, binding_idx, false)?;
3134                        } else {
3135                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
3136                            self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
3137                        }
3138                    } else {
3139                        self.compile_destructure_pattern_global(&var_decl.pattern)?;
3140                    }
3141                } else {
3142                    // Inside function: create local variable
3143                    self.compile_destructure_pattern(&var_decl.pattern)?;
3144
3145                    // Patch StoreLocal → StoreLocalTyped for width-typed simple bindings.
3146                    // compile_destructure_pattern emits StoreLocal(idx) for Identifier patterns;
3147                    // we upgrade it here when the type annotation is a width type.
3148                    if let (Some(name), Some(TypeAnnotation::Basic(type_name))) = (
3149                        var_decl.pattern.as_identifier(),
3150                        var_decl.type_annotation.as_ref(),
3151                    ) {
3152                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
3153                            if let Some(local_idx) = self.resolve_local(name) {
3154                                if let Some(last) = self.program.instructions.last_mut() {
3155                                    if last.opcode == OpCode::StoreLocal {
3156                                        last.opcode = OpCode::StoreLocalTyped;
3157                                        last.operand = Some(Operand::TypedLocal(
3158                                            local_idx,
3159                                            crate::bytecode::NumericWidth::from_int_width(w),
3160                                        ));
3161                                    }
3162                                }
3163                            }
3164                        }
3165                    }
3166
3167                    // Track const locals for reassignment checks
3168                    if var_decl.kind == VarKind::Const {
3169                        if let Some(name) = var_decl.pattern.as_identifier() {
3170                            if let Some(local_idx) = self.resolve_local(name) {
3171                                self.const_locals.insert(local_idx);
3172                            }
3173                        }
3174                    }
3175
3176                    // Track immutable `let` bindings (not `let mut` and not `var`)
3177                    // `let` without `mut` is immutable by default.
3178                    // `var` is always mutable (inferred from usage).
3179                    // `let mut` is explicitly mutable.
3180                    if var_decl.kind == VarKind::Let && !var_decl.is_mut {
3181                        if let Some(name) = var_decl.pattern.as_identifier() {
3182                            if let Some(local_idx) = self.resolve_local(name) {
3183                                self.immutable_locals.insert(local_idx);
3184                            }
3185                        }
3186                    }
3187
3188                    // Track type annotation first (so drop tracking can resolve the type)
3189                    if let Some(name) = var_decl.pattern.as_identifier() {
3190                        if let Some(ref type_ann) = var_decl.type_annotation {
3191                            if let Some(type_name) =
3192                                Self::tracked_type_name_from_annotation(type_ann)
3193                            {
3194                                // Get the local index for self variable
3195                                if let Some(local_idx) = self.resolve_local(name) {
3196                                    self.set_local_type_info(local_idx, &type_name);
3197                                }
3198                            }
3199                            // Handle Table<T> generic annotation
3200                            if let Some(local_idx) = self.resolve_local(name) {
3201                                self.try_track_datatable_type(type_ann, local_idx, true)?;
3202                            }
3203                        } else if let Some(local_idx) = self.resolve_local(name) {
3204                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
3205                            self.propagate_initializer_type_to_slot(local_idx, true, is_mutable);
3206                        }
3207                    }
3208
3209                    // Track for auto-drop at scope exit (DropCall silently skips non-Drop types).
3210                    // Select sync vs async opcode based on the type's DropKind.
3211                    if let Some(name) = var_decl.pattern.as_identifier() {
3212                        if let Some(local_idx) = self.resolve_local(name) {
3213                            let drop_kind = self.local_drop_kind(local_idx).or_else(|| {
3214                                var_decl
3215                                    .type_annotation
3216                                    .as_ref()
3217                                    .and_then(|ann| self.annotation_drop_kind(ann))
3218                            });
3219
3220                            let is_async = match drop_kind {
3221                                Some(DropKind::AsyncOnly) => {
3222                                    if !self.current_function_is_async {
3223                                        let tn = self
3224                                            .type_tracker
3225                                            .get_local_type(local_idx)
3226                                            .and_then(|info| info.type_name.clone())
3227                                            .unwrap_or_else(|| name.to_string());
3228                                        return Err(ShapeError::SemanticError {
3229                                            message: format!(
3230                                                "type '{}' has only an async drop() and cannot be used in a sync context; \
3231                                                 add a sync method drop(self) or use it inside an async function",
3232                                                tn
3233                                            ),
3234                                            location: None,
3235                                        });
3236                                    }
3237                                    true
3238                                }
3239                                Some(DropKind::Both) => self.current_function_is_async,
3240                                Some(DropKind::SyncOnly) | None => false,
3241                            };
3242                            self.track_drop_local(local_idx, is_async);
3243                        }
3244                    }
3245                }
3246
3247                if let Some(e) = init_err {
3248                    return Err(e);
3249                }
3250            }
3251
3252            Statement::Assignment(assign, _) => 'assign: {
3253                // Check for const reassignment
3254                if let Some(name) = assign.pattern.as_identifier() {
3255                    if let Some(local_idx) = self.resolve_local(name) {
3256                        if self.const_locals.contains(&local_idx) {
3257                            return Err(ShapeError::SemanticError {
3258                                message: format!("Cannot reassign const variable '{}'", name),
3259                                location: None,
3260                            });
3261                        }
3262                        // Check for immutable `let` reassignment
3263                        if self.immutable_locals.contains(&local_idx) {
3264                            return Err(ShapeError::SemanticError {
3265                                message: format!(
3266                                    "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
3267                                    name
3268                                ),
3269                                location: None,
3270                            });
3271                        }
3272                    } else {
3273                        let scoped_name = self
3274                            .resolve_scoped_module_binding_name(name)
3275                            .unwrap_or_else(|| name.to_string());
3276                        if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
3277                            if self.const_module_bindings.contains(&binding_idx) {
3278                                return Err(ShapeError::SemanticError {
3279                                    message: format!("Cannot reassign const variable '{}'", name),
3280                                    location: None,
3281                                });
3282                            }
3283                            // Check for immutable `let` reassignment at module level
3284                            if self.immutable_module_bindings.contains(&binding_idx) {
3285                                return Err(ShapeError::SemanticError {
3286                                    message: format!(
3287                                        "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
3288                                        name
3289                                    ),
3290                                    location: None,
3291                                });
3292                            }
3293                        }
3294                    }
3295                }
3296
3297                // Optimization: x = x.push(val) → ArrayPushLocal (O(1) in-place mutation)
3298                if let Some(name) = assign.pattern.as_identifier() {
3299                    if let Expr::MethodCall {
3300                        receiver,
3301                        method,
3302                        args,
3303                        ..
3304                    } = &assign.value
3305                    {
3306                        if method == "push" && args.len() == 1 {
3307                            if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
3308                                if recv_name == name {
3309                                    if let Some(local_idx) = self.resolve_local(name) {
3310                                        if !self.ref_locals.contains(&local_idx) {
3311                                            self.compile_expr(&args[0])?;
3312                                            let pushed_numeric = self.last_expr_numeric_type;
3313                                            self.emit(Instruction::new(
3314                                                OpCode::ArrayPushLocal,
3315                                                Some(Operand::Local(local_idx)),
3316                                            ));
3317                                            if let Some(numeric_type) = pushed_numeric {
3318                                                self.mark_slot_as_numeric_array(
3319                                                    local_idx,
3320                                                    true,
3321                                                    numeric_type,
3322                                                );
3323                                            }
3324                                            break 'assign;
3325                                        }
3326                                    } else {
3327                                        let binding_idx = self.get_or_create_module_binding(name);
3328                                        self.compile_expr(&args[0])?;
3329                                        let pushed_numeric = self.last_expr_numeric_type;
3330                                        self.emit(Instruction::new(
3331                                            OpCode::ArrayPushLocal,
3332                                            Some(Operand::ModuleBinding(binding_idx)),
3333                                        ));
3334                                        if let Some(numeric_type) = pushed_numeric {
3335                                            self.mark_slot_as_numeric_array(
3336                                                binding_idx,
3337                                                false,
3338                                                numeric_type,
3339                                            );
3340                                        }
3341                                        break 'assign;
3342                                    }
3343                                }
3344                            }
3345                        }
3346                    }
3347                }
3348
3349                // Compile value
3350                self.compile_expr(&assign.value)?;
3351                let assigned_ident = assign.pattern.as_identifier().map(str::to_string);
3352
3353                // Store in variable
3354                self.compile_destructure_assignment(&assign.pattern)?;
3355                if let Some(name) = assigned_ident.as_deref() {
3356                    self.propagate_assignment_type_to_identifier(name);
3357                }
3358            }
3359
3360            Statement::Expression(expr, _) => {
3361                // Fast path: arr.push(val) as standalone statement → in-place mutation
3362                // (avoids the LoadLocal+Pop overhead from the expression-level optimization)
3363                if let Expr::MethodCall {
3364                    receiver,
3365                    method,
3366                    args,
3367                    ..
3368                } = expr
3369                {
3370                    if method == "push" && args.len() == 1 {
3371                        if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
3372                            if let Some(local_idx) = self.resolve_local(recv_name) {
3373                                if !self.ref_locals.contains(&local_idx) {
3374                                    self.compile_expr(&args[0])?;
3375                                    let pushed_numeric = self.last_expr_numeric_type;
3376                                    self.emit(Instruction::new(
3377                                        OpCode::ArrayPushLocal,
3378                                        Some(Operand::Local(local_idx)),
3379                                    ));
3380                                    if let Some(numeric_type) = pushed_numeric {
3381                                        self.mark_slot_as_numeric_array(
3382                                            local_idx,
3383                                            true,
3384                                            numeric_type,
3385                                        );
3386                                    }
3387                                    return Ok(());
3388                                }
3389                            } else if !self
3390                                .mutable_closure_captures
3391                                .contains_key(recv_name.as_str())
3392                            {
3393                                let binding_idx = self.get_or_create_module_binding(recv_name);
3394                                self.compile_expr(&args[0])?;
3395                                self.emit(Instruction::new(
3396                                    OpCode::ArrayPushLocal,
3397                                    Some(Operand::ModuleBinding(binding_idx)),
3398                                ));
3399                                return Ok(());
3400                            }
3401                        }
3402                    }
3403                }
3404                self.compile_expr(expr)?;
3405                self.emit(Instruction::simple(OpCode::Pop));
3406            }
3407
3408            Statement::For(for_loop, _) => {
3409                self.compile_for_loop(for_loop)?;
3410            }
3411
3412            Statement::While(while_loop, _) => {
3413                self.compile_while_loop(while_loop)?;
3414            }
3415
3416            Statement::If(if_stmt, _) => {
3417                self.compile_if_statement(if_stmt)?;
3418            }
3419            Statement::Extend(extend, span) => {
3420                if !self.comptime_mode {
3421                    return Err(ShapeError::SemanticError {
3422                        message:
3423                            "`extend` as a statement is only valid inside `comptime { }` context"
3424                                .to_string(),
3425                        location: Some(self.span_to_source_location(*span)),
3426                    });
3427                }
3428                self.emit_comptime_extend_directive(extend, *span)?;
3429            }
3430            Statement::RemoveTarget(span) => {
3431                if !self.comptime_mode {
3432                    return Err(ShapeError::SemanticError {
3433                        message: "`remove target` is only valid inside `comptime { }` context"
3434                            .to_string(),
3435                        location: Some(self.span_to_source_location(*span)),
3436                    });
3437                }
3438                self.emit_comptime_remove_directive(*span)?;
3439            }
3440            Statement::SetParamType {
3441                param_name,
3442                type_annotation,
3443                span,
3444            } => {
3445                if !self.comptime_mode {
3446                    return Err(ShapeError::SemanticError {
3447                        message: "`set param` is only valid inside `comptime { }` context"
3448                            .to_string(),
3449                        location: Some(self.span_to_source_location(*span)),
3450                    });
3451                }
3452                self.emit_comptime_set_param_type_directive(param_name, type_annotation, *span)?;
3453            }
3454            Statement::SetReturnType {
3455                type_annotation,
3456                span,
3457            } => {
3458                if !self.comptime_mode {
3459                    return Err(ShapeError::SemanticError {
3460                        message: "`set return` is only valid inside `comptime { }` context"
3461                            .to_string(),
3462                        location: Some(self.span_to_source_location(*span)),
3463                    });
3464                }
3465                self.emit_comptime_set_return_type_directive(type_annotation, *span)?;
3466            }
3467            Statement::SetReturnExpr { expression, span } => {
3468                if !self.comptime_mode {
3469                    return Err(ShapeError::SemanticError {
3470                        message: "`set return` is only valid inside `comptime { }` context"
3471                            .to_string(),
3472                        location: Some(self.span_to_source_location(*span)),
3473                    });
3474                }
3475                self.emit_comptime_set_return_expr_directive(expression, *span)?;
3476            }
3477            Statement::ReplaceBody { body, span } => {
3478                if !self.comptime_mode {
3479                    return Err(ShapeError::SemanticError {
3480                        message: "`replace body` is only valid inside `comptime { }` context"
3481                            .to_string(),
3482                        location: Some(self.span_to_source_location(*span)),
3483                    });
3484                }
3485                self.emit_comptime_replace_body_directive(body, *span)?;
3486            }
3487            Statement::ReplaceBodyExpr { expression, span } => {
3488                if !self.comptime_mode {
3489                    return Err(ShapeError::SemanticError {
3490                        message: "`replace body` is only valid inside `comptime { }` context"
3491                            .to_string(),
3492                        location: Some(self.span_to_source_location(*span)),
3493                    });
3494                }
3495                self.emit_comptime_replace_body_expr_directive(expression, *span)?;
3496            }
3497            Statement::ReplaceModuleExpr { expression, span } => {
3498                if !self.comptime_mode {
3499                    return Err(ShapeError::SemanticError {
3500                        message: "`replace module` is only valid inside `comptime { }` context"
3501                            .to_string(),
3502                        location: Some(self.span_to_source_location(*span)),
3503                    });
3504                }
3505                self.emit_comptime_replace_module_expr_directive(expression, *span)?;
3506            }
3507        }
3508        Ok(())
3509    }
3510}
3511
3512#[cfg(test)]
3513mod tests {
3514    use crate::compiler::BytecodeCompiler;
3515    use crate::executor::{VMConfig, VirtualMachine};
3516    use shape_ast::parser::parse_program;
3517
3518    #[test]
3519    fn test_module_decl_function_resolves_module_const() {
3520        let code = r#"
3521            mod math {
3522                const BASE = 21
3523                fn twice() {
3524                    BASE * 2
3525                }
3526            }
3527            math.twice()
3528        "#;
3529
3530        let program = parse_program(code).expect("Failed to parse");
3531        let bytecode = BytecodeCompiler::new()
3532            .compile(&program)
3533            .expect("Failed to compile");
3534
3535        let mut vm = VirtualMachine::new(VMConfig::default());
3536        vm.load_program(bytecode);
3537        vm.populate_module_objects();
3538        let result = vm.execute(None).expect("Failed to execute");
3539        assert_eq!(
3540            result
3541                .as_number_coerce()
3542                .expect("module call should return number"),
3543            42.0
3544        );
3545    }
3546
3547    #[test]
3548    fn test_module_annotation_can_replace_module_items() {
3549        let code = r#"
3550            annotation synth_module() {
3551                targets: [module]
3552                comptime post(target, ctx) {
3553                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
3554                }
3555            }
3556
3557            @synth_module()
3558            mod demo {}
3559
3560            demo.plus_two()
3561        "#;
3562
3563        let program = parse_program(code).expect("Failed to parse");
3564        let bytecode = BytecodeCompiler::new()
3565            .compile(&program)
3566            .expect("Failed to compile");
3567
3568        let mut vm = VirtualMachine::new(VMConfig::default());
3569        vm.load_program(bytecode);
3570        vm.populate_module_objects();
3571        let result = vm.execute(None).expect("Failed to execute");
3572        assert_eq!(
3573            result
3574                .as_number_coerce()
3575                .expect("module call should return number"),
3576            42.0
3577        );
3578    }
3579
3580    #[test]
3581    fn test_module_inline_comptime_can_replace_module_items() {
3582        let code = r#"
3583            mod demo {
3584                comptime {
3585                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
3586                }
3587            }
3588
3589            demo.plus_two()
3590        "#;
3591
3592        let program = parse_program(code).expect("Failed to parse");
3593        let bytecode = BytecodeCompiler::new()
3594            .compile(&program)
3595            .expect("Failed to compile");
3596
3597        let mut vm = VirtualMachine::new(VMConfig::default());
3598        vm.load_program(bytecode);
3599        vm.populate_module_objects();
3600        let result = vm.execute(None).expect("Failed to execute");
3601        assert_eq!(
3602            result
3603                .as_number_coerce()
3604                .expect("module call should return number"),
3605            42.0
3606        );
3607    }
3608
3609    #[test]
3610    fn test_module_inline_comptime_can_use_module_local_comptime_helper() {
3611        let code = r#"
3612            mod demo {
3613                comptime fn synth() {
3614                    "const ANSWER = 40; fn plus_two() { ANSWER + 2 }"
3615                }
3616
3617                comptime {
3618                    replace module (synth())
3619                }
3620            }
3621
3622            demo.plus_two()
3623        "#;
3624
3625        let program = parse_program(code).expect("Failed to parse");
3626        let bytecode = BytecodeCompiler::new()
3627            .compile(&program)
3628            .expect("Failed to compile");
3629
3630        let mut vm = VirtualMachine::new(VMConfig::default());
3631        vm.load_program(bytecode);
3632        vm.populate_module_objects();
3633        let result = vm.execute(None).expect("Failed to execute");
3634        assert_eq!(
3635            result
3636                .as_number_coerce()
3637                .expect("module call should return number"),
3638            42.0
3639        );
3640    }
3641
3642    #[test]
3643    fn test_type_annotated_variable_no_wrapping() {
3644        // BUG-1/BUG-2 fix: variable declarations must NOT emit WrapTypeAnnotation
3645        // (the wrapper broke arithmetic and comparisons)
3646        let code = r#"
3647            type Currency = Number
3648            let x: Currency = 123
3649        "#;
3650        let program = parse_program(code).expect("Failed to parse");
3651        let bytecode = BytecodeCompiler::new()
3652            .compile(&program)
3653            .expect("Failed to compile");
3654
3655        // WrapTypeAnnotation should NOT be emitted for variable declarations
3656        let has_wrap_instruction = bytecode
3657            .instructions
3658            .iter()
3659            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
3660        assert!(
3661            !has_wrap_instruction,
3662            "Should NOT emit WrapTypeAnnotation for type-annotated variable"
3663        );
3664    }
3665
3666    #[test]
3667    fn test_untyped_variable_no_wrapping() {
3668        // Variables without type annotations should NOT emit WrapTypeAnnotation
3669        let code = r#"
3670            let x = 123
3671        "#;
3672        let program = parse_program(code).expect("Failed to parse");
3673        let bytecode = BytecodeCompiler::new()
3674            .compile(&program)
3675            .expect("Failed to compile");
3676
3677        // Check that WrapTypeAnnotation instruction was NOT emitted
3678        let has_wrap_instruction = bytecode
3679            .instructions
3680            .iter()
3681            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
3682        assert!(
3683            !has_wrap_instruction,
3684            "Should NOT emit WrapTypeAnnotation for untyped variable"
3685        );
3686    }
3687
3688    // ===== Phase 2: Extend Block Compilation Tests =====
3689
3690    #[test]
3691    fn test_extend_block_compiles() {
3692        let code = r#"
3693            extend Number {
3694                method double() {
3695                    return self * 2
3696                }
3697            }
3698        "#;
3699        let program = parse_program(code).expect("Failed to parse extend block");
3700        let bytecode = BytecodeCompiler::new().compile(&program);
3701        assert!(
3702            bytecode.is_ok(),
3703            "Extend block should compile: {:?}",
3704            bytecode.err()
3705        );
3706
3707        // Verify a function named "Number.double" was generated (qualified extend name).
3708        let bytecode = bytecode.unwrap();
3709        let has_double = bytecode.functions.iter().any(|f| f.name == "Number.double");
3710        assert!(
3711            has_double,
3712            "Should generate 'Number.double' function from extend block"
3713        );
3714    }
3715
3716    #[test]
3717    fn test_extend_method_has_self_param() {
3718        let code = r#"
3719            extend Number {
3720                method add(n) {
3721                    return self + n
3722                }
3723            }
3724        "#;
3725        let program = parse_program(code).expect("Failed to parse");
3726        let bytecode = BytecodeCompiler::new()
3727            .compile(&program)
3728            .expect("Failed to compile");
3729
3730        let func = bytecode.functions.iter().find(|f| f.name == "Number.add");
3731        assert!(func.is_some(), "Should have 'Number.add' function");
3732        // The function should have 2 params: self + n
3733        assert_eq!(
3734            func.unwrap().arity,
3735            2,
3736            "add() should have arity 2 (self + n)"
3737        );
3738    }
3739
3740    #[test]
3741    fn test_extend_method_rejects_explicit_self_param() {
3742        let code = r#"
3743            extend Number {
3744                method add(self, n) {
3745                    return self + n
3746                }
3747            }
3748        "#;
3749        let program = parse_program(code).expect("Failed to parse");
3750        let err = BytecodeCompiler::new()
3751            .compile(&program)
3752            .expect_err("Compiler should reject explicit self receiver param in methods");
3753        let msg = format!("{err}");
3754        assert!(
3755            msg.contains("explicit `self` parameter"),
3756            "Expected explicit self error, got: {msg}"
3757        );
3758    }
3759
3760    // ===== Phase 3: Annotation Handler Compilation Tests =====
3761
3762    #[test]
3763    fn test_annotation_def_compiles_handlers() {
3764        let code = r#"
3765            annotation warmup(period) {
3766                before(args, ctx) {
3767                    args
3768                }
3769                after(args, result, ctx) {
3770                    result
3771                }
3772            }
3773            function test() { return 42; }
3774        "#;
3775        let program = parse_program(code).expect("Failed to parse annotation def");
3776        let bytecode = BytecodeCompiler::new().compile(&program);
3777        assert!(
3778            bytecode.is_ok(),
3779            "Annotation def should compile: {:?}",
3780            bytecode.err()
3781        );
3782
3783        let bytecode = bytecode.unwrap();
3784        // Verify CompiledAnnotation was registered
3785        assert!(
3786            bytecode.compiled_annotations.contains_key("warmup"),
3787            "Should have compiled 'warmup' annotation"
3788        );
3789
3790        let compiled = bytecode.compiled_annotations.get("warmup").unwrap();
3791        assert!(
3792            compiled.before_handler.is_some(),
3793            "Should have before handler"
3794        );
3795        assert!(
3796            compiled.after_handler.is_some(),
3797            "Should have after handler"
3798        );
3799    }
3800
3801    #[test]
3802    fn test_annotation_handler_function_names() {
3803        let code = r#"
3804            annotation my_ann(x) {
3805                before(args, ctx) {
3806                    args
3807                }
3808            }
3809            function test() { return 1; }
3810        "#;
3811        let program = parse_program(code).expect("Failed to parse");
3812        let bytecode = BytecodeCompiler::new()
3813            .compile(&program)
3814            .expect("Failed to compile");
3815
3816        // Handler should be compiled as an internal function
3817        let compiled = bytecode.compiled_annotations.get("my_ann").unwrap();
3818        let handler_id = compiled.before_handler.unwrap() as usize;
3819        assert!(
3820            handler_id < bytecode.functions.len(),
3821            "Handler function ID should be valid"
3822        );
3823
3824        let handler_fn = &bytecode.functions[handler_id];
3825        assert_eq!(
3826            handler_fn.name, "my_ann___before",
3827            "Handler function should be named my_ann___before"
3828        );
3829    }
3830
3831    // ===== Phase 4: Compile-Time Function Wrapping Tests =====
3832
3833    #[test]
3834    fn test_annotated_function_generates_wrapper() {
3835        let code = r#"
3836            annotation tracked(label) {
3837                before(args, ctx) {
3838                    args
3839                }
3840            }
3841            @tracked("my_func")
3842            function compute(x) {
3843                return x * 2
3844            }
3845            function test() { return 1; }
3846        "#;
3847        let program = parse_program(code).expect("Failed to parse");
3848        let bytecode = BytecodeCompiler::new().compile(&program);
3849        assert!(
3850            bytecode.is_ok(),
3851            "Annotated function should compile: {:?}",
3852            bytecode.err()
3853        );
3854
3855        let bytecode = bytecode.unwrap();
3856        // Should have the original function (wrapper) and the impl
3857        let has_impl = bytecode
3858            .functions
3859            .iter()
3860            .any(|f| f.name == "compute___impl");
3861        assert!(has_impl, "Should generate compute___impl function");
3862
3863        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
3864        assert!(has_wrapper, "Should keep compute as wrapper");
3865    }
3866
3867    #[test]
3868    fn test_unannotated_function_no_wrapper() {
3869        let code = r#"
3870            function plain(x) {
3871                return x + 1
3872            }
3873        "#;
3874        let program = parse_program(code).expect("Failed to parse");
3875        let bytecode = BytecodeCompiler::new()
3876            .compile(&program)
3877            .expect("Failed to compile");
3878
3879        // Should NOT have an ___impl function
3880        let has_impl = bytecode
3881            .functions
3882            .iter()
3883            .any(|f| f.name.ends_with("___impl"));
3884        assert!(
3885            !has_impl,
3886            "Non-annotated function should not generate ___impl"
3887        );
3888    }
3889
3890    // ===== Sprint 10: Annotation chaining and target validation =====
3891
3892    #[test]
3893    fn test_annotation_chaining_generates_chain() {
3894        // Two annotations on the same function should generate chained wrappers
3895        let code = r#"
3896            annotation first() {
3897                before(args, ctx) {
3898                    return args
3899                }
3900            }
3901
3902            annotation second() {
3903                before(args, ctx) {
3904                    return args
3905                }
3906            }
3907
3908            @first
3909            @second
3910            function compute(x) {
3911                return x * 2
3912            }
3913        "#;
3914        let program = parse_program(code).expect("Failed to parse");
3915        let bytecode = BytecodeCompiler::new().compile(&program);
3916        assert!(
3917            bytecode.is_ok(),
3918            "Chained annotations should compile: {:?}",
3919            bytecode.err()
3920        );
3921        let bytecode = bytecode.unwrap();
3922
3923        // Should have: compute (outermost wrapper), compute___impl (body), compute___second (intermediate)
3924        let has_impl = bytecode
3925            .functions
3926            .iter()
3927            .any(|f| f.name == "compute___impl");
3928        assert!(has_impl, "Should generate compute___impl function");
3929        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
3930        assert!(has_wrapper, "Should keep compute as outermost wrapper");
3931        let has_intermediate = bytecode
3932            .functions
3933            .iter()
3934            .any(|f| f.name == "compute___second");
3935        assert!(
3936            has_intermediate,
3937            "Should generate compute___second intermediate wrapper"
3938        );
3939    }
3940
3941    #[test]
3942    fn test_annotation_allowed_targets_inferred() {
3943        // An annotation with before/after should have allowed_targets = [Function]
3944        let code = r#"
3945            annotation traced() {
3946                before(args, ctx) {
3947                    return args
3948                }
3949            }
3950        "#;
3951        let program = parse_program(code).expect("Failed to parse");
3952        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
3953        let ann = bytecode
3954            .compiled_annotations
3955            .get("traced")
3956            .expect("traced annotation");
3957        assert!(
3958            !ann.allowed_targets.is_empty(),
3959            "before handler should restrict targets"
3960        );
3961        assert!(
3962            ann.allowed_targets
3963                .contains(&shape_ast::ast::functions::AnnotationTargetKind::Function),
3964            "before handler should allow Function target"
3965        );
3966    }
3967
3968    #[test]
3969    fn test_annotation_allowed_targets_explicit_override() {
3970        // Explicit `targets: [...]` should override inferred defaults.
3971        let code = r#"
3972            annotation traced() {
3973                targets: [type]
3974                before(args, ctx) {
3975                    return args
3976                }
3977            }
3978        "#;
3979        let program = parse_program(code).expect("Failed to parse");
3980        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
3981        let ann = bytecode
3982            .compiled_annotations
3983            .get("traced")
3984            .expect("traced annotation");
3985        assert_eq!(
3986            ann.allowed_targets,
3987            vec![shape_ast::ast::functions::AnnotationTargetKind::Type]
3988        );
3989    }
3990
3991    #[test]
3992    fn test_metadata_only_annotation_defaults_to_definition_targets() {
3993        // An annotation with only metadata handler should default to definition targets.
3994        let code = r#"
3995            annotation info() {
3996                metadata() {
3997                    return { version: 1 }
3998                }
3999            }
4000        "#;
4001        let program = parse_program(code).expect("Failed to parse");
4002        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
4003        let ann = bytecode
4004            .compiled_annotations
4005            .get("info")
4006            .expect("info annotation");
4007        assert_eq!(
4008            ann.allowed_targets,
4009            vec![
4010                shape_ast::ast::functions::AnnotationTargetKind::Function,
4011                shape_ast::ast::functions::AnnotationTargetKind::Type,
4012                shape_ast::ast::functions::AnnotationTargetKind::Module
4013            ],
4014            "metadata-only annotation should default to definition targets"
4015        );
4016    }
4017
4018    #[test]
4019    fn test_definition_lifecycle_targets_reject_expression_target() {
4020        let code = r#"
4021            annotation info() {
4022                targets: [expression]
4023                metadata(target, ctx) {
4024                    target.name
4025                }
4026            }
4027        "#;
4028        let program = parse_program(code).expect("Failed to parse");
4029        let err = BytecodeCompiler::new()
4030            .compile(&program)
4031            .expect_err("metadata hooks on expression targets should fail");
4032        let msg = format!("{}", err);
4033        assert!(
4034            msg.contains("not a definition target"),
4035            "expected definition-target restriction error, got: {}",
4036            msg
4037        );
4038    }
4039
4040    #[test]
4041    fn test_annotation_target_validation_on_struct_type() {
4042        // Function-only annotation applied to a type should fail.
4043        let code = r#"
4044            annotation traced() {
4045                before(args, ctx) { return args }
4046            }
4047
4048            @traced()
4049            type Point { x: int }
4050        "#;
4051        let program = parse_program(code).expect("Failed to parse");
4052        let err = BytecodeCompiler::new()
4053            .compile(&program)
4054            .expect_err("function-only annotation on type should fail");
4055        let msg = format!("{}", err);
4056        assert!(
4057            msg.contains("cannot be applied to a type"),
4058            "expected type target validation error, got: {}",
4059            msg
4060        );
4061    }
4062
4063    #[test]
4064    fn test_type_c_emits_native_layout_metadata() {
4065        let bytecode = compiles_to(
4066            r#"
4067            type C Pair32 {
4068                left: i32,
4069                right: i32,
4070            }
4071            "#,
4072        );
4073
4074        assert_eq!(bytecode.native_struct_layouts.len(), 1);
4075        let layout = &bytecode.native_struct_layouts[0];
4076        assert_eq!(layout.name, "Pair32");
4077        assert_eq!(layout.abi, "C");
4078        assert_eq!(layout.size, 8);
4079        assert_eq!(layout.align, 4);
4080        assert_eq!(layout.fields.len(), 2);
4081        assert_eq!(layout.fields[0].name, "left");
4082        assert_eq!(layout.fields[0].offset, 0);
4083        assert_eq!(layout.fields[0].size, 4);
4084        assert_eq!(layout.fields[1].name, "right");
4085        assert_eq!(layout.fields[1].offset, 4);
4086        assert_eq!(layout.fields[1].size, 4);
4087    }
4088
4089    #[test]
4090    fn test_type_c_auto_generates_into_from_traits() {
4091        let bytecode = compiles_to(
4092            r#"
4093            type C QuoteC {
4094                bid: i64,
4095                ask: i64,
4096            }
4097
4098            type Quote {
4099                bid: i64,
4100                ask: i64,
4101            }
4102            "#,
4103        );
4104
4105        let c_to_shape =
4106            bytecode.lookup_trait_method_symbol("Into", "QuoteC", Some("Quote"), "into");
4107        let shape_to_c =
4108            bytecode.lookup_trait_method_symbol("Into", "Quote", Some("QuoteC"), "into");
4109        let from_c = bytecode.lookup_trait_method_symbol("From", "Quote", Some("QuoteC"), "from");
4110        let from_shape =
4111            bytecode.lookup_trait_method_symbol("From", "QuoteC", Some("Quote"), "from");
4112
4113        assert!(c_to_shape.is_some(), "expected Into<Quote> for QuoteC");
4114        assert!(shape_to_c.is_some(), "expected Into<QuoteC> for Quote");
4115        assert!(from_c.is_some(), "expected From<QuoteC> for Quote");
4116        assert!(from_shape.is_some(), "expected From<Quote> for QuoteC");
4117    }
4118
4119    #[test]
4120    fn test_type_c_auto_conversion_function_compiles() {
4121        let _ = compiles_to(
4122            r#"
4123            type Quote {
4124                bid: i64,
4125                ask: i64,
4126            }
4127
4128            type C QuoteC {
4129                bid: i64,
4130                ask: i64,
4131            }
4132
4133            fn spread(q: QuoteC) -> i64 {
4134                let q_shape = __auto_native_from_QuoteC_to_Quote(q);
4135                q_shape.ask - q_shape.bid
4136            }
4137
4138            spread(QuoteC { bid: 10, ask: 13 })
4139            "#,
4140        );
4141    }
4142
4143    #[test]
4144    fn test_type_c_auto_conversion_rejects_incompatible_fields() {
4145        let program = parse_program(
4146            r#"
4147            type Price {
4148                value: i64,
4149            }
4150
4151            type C PriceC {
4152                value: u64,
4153            }
4154            "#,
4155        )
4156        .expect("parse failed");
4157        let err = BytecodeCompiler::new()
4158            .compile(&program)
4159            .expect_err("incompatible type C conversion pair should fail");
4160        let msg = format!("{}", err);
4161        assert!(
4162            msg.contains("field type mismatch for auto conversion"),
4163            "expected type mismatch error, got: {}",
4164            msg
4165        );
4166    }
4167
4168    // ===== Task 1: Meta on traits =====
4169
4170    // ===== Drop Track: Sprint 2 Tests =====
4171
4172    fn compiles_to(code: &str) -> crate::bytecode::BytecodeProgram {
4173        let program = parse_program(code).expect("parse failed");
4174        let compiler = BytecodeCompiler::new();
4175        compiler.compile(&program).expect("compile failed")
4176    }
4177
4178    // --- Permission checking tests ---
4179
4180    #[test]
4181    fn test_extract_module_name() {
4182        assert_eq!(BytecodeCompiler::extract_module_name("file"), "file");
4183        assert_eq!(BytecodeCompiler::extract_module_name("std::file"), "file");
4184        assert_eq!(BytecodeCompiler::extract_module_name("std/io"), "io");
4185        assert_eq!(BytecodeCompiler::extract_module_name("a::b::c"), "c");
4186        assert_eq!(BytecodeCompiler::extract_module_name(""), "");
4187    }
4188
4189    #[test]
4190    fn test_permission_check_allows_pure_module_imports() {
4191        // json is a pure module — should compile even with empty permissions
4192        let code = "from json use { parse }";
4193        let program = parse_program(code).expect("parse failed");
4194        let mut compiler = BytecodeCompiler::new();
4195        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4196        // Should not fail — json requires no permissions
4197        let _result = compiler.compile(&program);
4198    }
4199
4200    #[test]
4201    fn test_permission_check_blocks_file_import_under_pure() {
4202        let code = "from file use { read_text }";
4203        let program = parse_program(code).expect("parse failed");
4204        let mut compiler = BytecodeCompiler::new();
4205        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4206        let result = compiler.compile(&program);
4207        assert!(
4208            result.is_err(),
4209            "Expected permission error for file::read_text under pure"
4210        );
4211        let err_msg = format!("{}", result.unwrap_err());
4212        assert!(
4213            err_msg.contains("Permission denied"),
4214            "Error should mention permission denied: {err_msg}"
4215        );
4216        assert!(
4217            err_msg.contains("fs.read"),
4218            "Error should mention fs.read: {err_msg}"
4219        );
4220    }
4221
4222    #[test]
4223    fn test_permission_check_allows_file_import_with_fs_read() {
4224        let code = "from file use { read_text }";
4225        let program = parse_program(code).expect("parse failed");
4226        let mut compiler = BytecodeCompiler::new();
4227        let pset = shape_abi_v1::PermissionSet::from_iter([shape_abi_v1::Permission::FsRead]);
4228        compiler.set_permission_set(Some(pset));
4229        // Should not fail
4230        let _result = compiler.compile(&program);
4231    }
4232
4233    #[test]
4234    fn test_permission_check_no_permission_set_allows_everything() {
4235        // When permission_set is None (default), no checking is done
4236        let code = "from file use { read_text }";
4237        let program = parse_program(code).expect("parse failed");
4238        let compiler = BytecodeCompiler::new();
4239        // permission_set is None by default — should compile fine
4240        let _result = compiler.compile(&program);
4241    }
4242
4243    #[test]
4244    fn test_permission_check_namespace_import_blocked() {
4245        let code = "use http";
4246        let program = parse_program(code).expect("parse failed");
4247        let mut compiler = BytecodeCompiler::new();
4248        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4249        let result = compiler.compile(&program);
4250        assert!(
4251            result.is_err(),
4252            "Expected permission error for `use http` under pure"
4253        );
4254        let err_msg = format!("{}", result.unwrap_err());
4255        assert!(
4256            err_msg.contains("Permission denied"),
4257            "Error should mention permission denied: {err_msg}"
4258        );
4259    }
4260
4261    #[test]
4262    fn test_permission_check_namespace_import_allowed() {
4263        let code = "use http";
4264        let program = parse_program(code).expect("parse failed");
4265        let mut compiler = BytecodeCompiler::new();
4266        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::full()));
4267        // Should not fail
4268        let _result = compiler.compile(&program);
4269    }
4270}