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