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            declaring_module_path: method.declaring_module_path.clone(),
1139            doc_comment: None,
1140            params,
1141            return_type: method.return_type.clone(),
1142            body,
1143            type_params: Some(Vec::new()),
1144            annotations: method.annotations.clone(),
1145            is_async: method.is_async,
1146            is_comptime: false,
1147            where_clause: None,
1148        })
1149    }
1150
1151    /// Desugar an impl method to a scoped FunctionDef.
1152    ///
1153    /// - Default impl:
1154    ///   `impl Queryable for DbTable { method filter(pred) { ... } }`
1155    ///   becomes: `function DbTable::filter(self, pred) { ... }`
1156    /// - Named impl:
1157    ///   `impl Display for User as JsonDisplay { method display() { ... } }`
1158    ///   becomes: `function Display::User::JsonDisplay::display(self) { ... }`
1159    ///
1160    /// Named impls use trait/type/impl prefixes to avoid collisions.
1161    fn desugar_impl_method(
1162        &self,
1163        method: &shape_ast::ast::types::MethodDef,
1164        trait_name: &str,
1165        type_name: &str,
1166        impl_name: Option<&str>,
1167        target_type: &shape_ast::ast::TypeName,
1168    ) -> Result<FunctionDef> {
1169        let receiver_type = Some(Self::type_name_to_annotation(target_type));
1170        let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1171
1172        // Async drop methods are named "drop_async" so both sync and async
1173        // variants can coexist in the function name index.
1174        let method_name = if trait_name == "Drop" && method.name == "drop" && method.is_async {
1175            "drop_async".to_string()
1176        } else {
1177            method.name.clone()
1178        };
1179        let fn_name = if let Some(name) = impl_name {
1180            format!("{}::{}::{}::{}", trait_name, type_name, name, method_name)
1181        } else {
1182            format!("{}::{}", type_name, method_name)
1183        };
1184
1185        Ok(FunctionDef {
1186            name: fn_name,
1187            name_span: Span::DUMMY,
1188            declaring_module_path: method.declaring_module_path.clone(),
1189            doc_comment: None,
1190            params,
1191            return_type: method.return_type.clone(),
1192            body,
1193            type_params: Some(Vec::new()),
1194            annotations: method.annotations.clone(),
1195            is_async: method.is_async,
1196            is_comptime: false,
1197            where_clause: None,
1198        })
1199    }
1200
1201    /// Build desugared method params/body with implicit receiver handling.
1202    ///
1203    /// Canonical receiver is `self`.
1204    fn desugar_method_signature_and_body(
1205        &self,
1206        method: &shape_ast::ast::types::MethodDef,
1207        receiver_type: Option<shape_ast::ast::TypeAnnotation>,
1208    ) -> Result<(Vec<FunctionParameter>, Vec<Statement>)> {
1209        if let Some(receiver) = method
1210            .params
1211            .first()
1212            .and_then(|p| p.pattern.as_identifier())
1213        {
1214            if receiver == "self" {
1215                let location = method
1216                    .params
1217                    .first()
1218                    .map(|p| self.span_to_source_location(p.span()));
1219                return Err(ShapeError::SemanticError {
1220                    message: format!(
1221                        "Method '{}' has an explicit `self` parameter, but method receivers are implicit. Use `method {}(...)` without `self`.",
1222                        method.name, method.name
1223                    ),
1224                    location,
1225                });
1226            }
1227        }
1228
1229        let mut params = vec![FunctionParameter {
1230            pattern: shape_ast::ast::DestructurePattern::Identifier(
1231                "self".to_string(),
1232                Span::DUMMY,
1233            ),
1234            is_const: false,
1235            is_reference: false,
1236            is_mut_reference: false,
1237            is_out: false,
1238            type_annotation: receiver_type,
1239            default_value: None,
1240        }];
1241        params.extend(method.params.clone());
1242
1243        Ok((params, method.body.clone()))
1244    }
1245
1246    /// Compile a `From` or `TryFrom` impl block.
1247    ///
1248    /// Unlike normal impl methods (which inject implicit `self`), From/TryFrom
1249    /// methods are constructors: `from(value: Source) -> Target`. The value
1250    /// parameter sits at local slot 0 with no receiver.
1251    ///
1252    /// Auto-derives:
1253    /// - `impl From<S> for T`  → `Into<T>::into` on S (direct alias)
1254    ///                          + `TryInto<T>::tryInto` on S (wrapper → Ok())
1255    /// - `impl TryFrom<S> for T` → `TryInto<T>::tryInto` on S (direct alias)
1256    fn compile_from_impl(
1257        &mut self,
1258        impl_block: &shape_ast::ast::types::ImplBlock,
1259        trait_name: &str,
1260        target_type: &str,
1261    ) -> Result<()> {
1262        // Extract source type from generic args: From<Source> → Source
1263        let source_type = match &impl_block.trait_name {
1264            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1265                match &type_args[0] {
1266                    TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => name.clone(),
1267                    other => {
1268                        return Err(ShapeError::SemanticError {
1269                            message: format!(
1270                                "{} impl requires a simple source type, found {:?}",
1271                                trait_name, other
1272                            ),
1273                            location: None,
1274                        });
1275                    }
1276                }
1277            }
1278            _ => {
1279                return Err(ShapeError::SemanticError {
1280                    message: format!(
1281                        "{} impl requires a generic type argument, e.g., {}<string>",
1282                        trait_name, trait_name
1283                    ),
1284                    location: None,
1285                });
1286            }
1287        };
1288
1289        // Named impl selector defaults to the source type name
1290        let selector = impl_block.impl_name.as_deref().unwrap_or(&source_type);
1291
1292        for method in &impl_block.methods {
1293            let func_def =
1294                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1295            let from_fn_name = func_def.name.clone();
1296
1297            // Register From/TryFrom trait method symbol on the target type
1298            self.program.register_trait_method_symbol(
1299                trait_name,
1300                target_type,
1301                Some(&source_type),
1302                &method.name,
1303                &from_fn_name,
1304            );
1305            self.register_function(&func_def)?;
1306
1307            // Auto-derive Into/TryInto on the source type
1308            if trait_name == "From" {
1309                // From<S> for T → Into<T>::into on S = direct alias (same fn)
1310                self.program.register_trait_method_symbol(
1311                    "Into",
1312                    &source_type,
1313                    Some(selector),
1314                    "into",
1315                    &from_fn_name,
1316                );
1317
1318                // From<S> for T → TryInto<T>::tryInto on S = wrapper (from + Ok)
1319                let wrapper_name =
1320                    self.emit_from_to_tryinto_wrapper(&from_fn_name, &source_type, target_type)?;
1321                self.program.register_trait_method_symbol(
1322                    "TryInto",
1323                    &source_type,
1324                    Some(selector),
1325                    "tryInto",
1326                    &wrapper_name,
1327                );
1328
1329                // Register trait impls in type inference environment
1330                let _ = self.type_inference.env.register_trait_impl_named(
1331                    "Into",
1332                    &source_type,
1333                    selector,
1334                    vec!["into".to_string()],
1335                );
1336                let _ = self.type_inference.env.register_trait_impl_named(
1337                    "TryInto",
1338                    &source_type,
1339                    selector,
1340                    vec!["tryInto".to_string()],
1341                );
1342            } else {
1343                // TryFrom<S> for T → TryInto<T>::tryInto on S = direct alias
1344                self.program.register_trait_method_symbol(
1345                    "TryInto",
1346                    &source_type,
1347                    Some(selector),
1348                    "tryInto",
1349                    &from_fn_name,
1350                );
1351
1352                // Register TryInto trait impl in type inference environment
1353                let _ = self.type_inference.env.register_trait_impl_named(
1354                    "TryInto",
1355                    &source_type,
1356                    selector,
1357                    vec!["tryInto".to_string()],
1358                );
1359            }
1360        }
1361
1362        // Register From/TryFrom trait impl on target type
1363        let all_method_names: Vec<String> =
1364            impl_block.methods.iter().map(|m| m.name.clone()).collect();
1365        let _ = self.type_inference.env.register_trait_impl_named(
1366            trait_name,
1367            target_type,
1368            &source_type,
1369            all_method_names,
1370        );
1371
1372        Ok(())
1373    }
1374
1375    /// Compile From/TryFrom impl method bodies (and the synthetic TryInto wrapper).
1376    ///
1377    /// Called from `compile_item_with_context` — the registration pass already
1378    /// happened in `compile_from_impl` / `register_item_functions`.
1379    fn compile_from_impl_bodies(
1380        &mut self,
1381        impl_block: &shape_ast::ast::types::ImplBlock,
1382        trait_name: &str,
1383        target_type: &str,
1384    ) -> Result<()> {
1385        let source_type = match &impl_block.trait_name {
1386            shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
1387                match &type_args[0] {
1388                    TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => name.clone(),
1389                    _ => return Ok(()), // error already reported in registration
1390                }
1391            }
1392            _ => return Ok(()),
1393        };
1394
1395        for method in &impl_block.methods {
1396            let func_def =
1397                self.desugar_from_method(method, trait_name, target_type, &source_type)?;
1398            self.compile_function(&func_def)?;
1399        }
1400
1401        // Also compile the synthetic TryInto wrapper for From impls
1402        if trait_name == "From" {
1403            for method in &impl_block.methods {
1404                let from_fn_name = format!(
1405                    "{}::{}::{}::{}",
1406                    trait_name, target_type, source_type, method.name
1407                );
1408                let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1409                // The wrapper was already registered; now compile its body
1410                if let Some(func_def) = self.function_defs.get(&wrapper_name).cloned() {
1411                    let _ = self.compile_function(&func_def);
1412                    // Suppress errors: if Ok() or the from fn is not yet available, it
1413                    // will be resolved at link time.
1414                    let _ = from_fn_name; // used above in the format
1415                }
1416            }
1417        }
1418
1419        Ok(())
1420    }
1421
1422    /// Desugar a From/TryFrom method WITHOUT implicit self injection.
1423    ///
1424    /// `From::from(value: S)` is a constructor — `value` sits at local slot 0.
1425    /// Function name: `"From::TargetType::SourceType::method_name"`
1426    fn desugar_from_method(
1427        &self,
1428        method: &shape_ast::ast::types::MethodDef,
1429        trait_name: &str,
1430        target_type: &str,
1431        source_type: &str,
1432    ) -> Result<FunctionDef> {
1433        // Verify no explicit `self` parameter
1434        if let Some(first) = method
1435            .params
1436            .first()
1437            .and_then(|p| p.pattern.as_identifier())
1438        {
1439            if first == "self" {
1440                return Err(ShapeError::SemanticError {
1441                    message: format!(
1442                        "{}::{} methods are constructors and must not have a `self` parameter",
1443                        trait_name, method.name
1444                    ),
1445                    location: None,
1446                });
1447            }
1448        }
1449
1450        let fn_name = format!(
1451            "{}::{}::{}::{}",
1452            trait_name, target_type, source_type, method.name
1453        );
1454
1455        Ok(FunctionDef {
1456            name: fn_name,
1457            name_span: Span::DUMMY,
1458            declaring_module_path: method.declaring_module_path.clone(),
1459            doc_comment: None,
1460            params: method.params.clone(),
1461            return_type: method.return_type.clone(),
1462            body: method.body.clone(),
1463            type_params: Some(Vec::new()),
1464            annotations: Vec::new(),
1465            is_async: method.is_async,
1466            is_comptime: false,
1467            where_clause: None,
1468        })
1469    }
1470
1471    /// Emit a synthetic wrapper function that calls a From::from function
1472    /// and wraps its result in Ok() for TryInto compatibility.
1473    ///
1474    /// Generated function: `__from_tryinto_{source}_{target}(value) -> Ok(from(value))`
1475    fn emit_from_to_tryinto_wrapper(
1476        &mut self,
1477        from_fn_name: &str,
1478        source_type: &str,
1479        target_type: &str,
1480    ) -> Result<String> {
1481        let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
1482
1483        // Create a synthetic FunctionDef whose body calls from() and wraps in Ok()
1484        let span = Span::DUMMY;
1485        let body = vec![Statement::Return(
1486            Some(Expr::FunctionCall {
1487                name: "Ok".to_string(),
1488                args: vec![Expr::FunctionCall {
1489                    name: from_fn_name.to_string(),
1490                    args: vec![Expr::Identifier("value".to_string(), span)],
1491                    named_args: Vec::new(),
1492                    span,
1493                }],
1494                named_args: Vec::new(),
1495                span,
1496            }),
1497            span,
1498        )];
1499
1500        let func_def = FunctionDef {
1501            name: wrapper_name.clone(),
1502            name_span: span,
1503            declaring_module_path: None,
1504            doc_comment: None,
1505            params: vec![FunctionParameter {
1506                pattern: DestructurePattern::Identifier("value".to_string(), span),
1507                is_const: false,
1508                is_reference: false,
1509                is_mut_reference: false,
1510                is_out: false,
1511                type_annotation: None,
1512                default_value: None,
1513            }],
1514            return_type: None,
1515            body,
1516            type_params: Some(Vec::new()),
1517            annotations: Vec::new(),
1518            is_async: false,
1519            is_comptime: false,
1520            where_clause: None,
1521        };
1522
1523        self.register_function(&func_def)?;
1524
1525        Ok(wrapper_name)
1526    }
1527
1528    fn type_name_to_annotation(
1529        type_name: &shape_ast::ast::TypeName,
1530    ) -> shape_ast::ast::TypeAnnotation {
1531        match type_name {
1532            shape_ast::ast::TypeName::Simple(name) => {
1533                shape_ast::ast::TypeAnnotation::Basic(name.clone())
1534            }
1535            shape_ast::ast::TypeName::Generic { name, type_args } => {
1536                shape_ast::ast::TypeAnnotation::Generic {
1537                    name: name.clone(),
1538                    args: type_args.clone(),
1539                }
1540            }
1541        }
1542    }
1543
1544    /// Compile an annotation definition.
1545    ///
1546    /// Each handler is compiled as an internal function:
1547    /// - before(args, ctx) → `{name}___before(self, period, args, ctx)`
1548    /// - after(args, result, ctx) → `{name}___after(self, period, args, result, ctx)`
1549    ///
1550    /// `self` is the annotated item (function/method/property).
1551    /// Annotation params (e.g., `period`) are prepended after `self`.
1552    fn compile_annotation_def(&mut self, ann_def: &shape_ast::ast::AnnotationDef) -> Result<()> {
1553        use crate::bytecode::CompiledAnnotation;
1554        use shape_ast::ast::AnnotationHandlerType;
1555
1556        let mut compiled = CompiledAnnotation {
1557            name: ann_def.name.clone(),
1558            param_names: ann_def
1559                .params
1560                .iter()
1561                .flat_map(|p| p.get_identifiers())
1562                .collect(),
1563            before_handler: None,
1564            after_handler: None,
1565            on_define_handler: None,
1566            metadata_handler: None,
1567            comptime_pre_handler: None,
1568            comptime_post_handler: None,
1569            allowed_targets: Vec::new(),
1570        };
1571
1572        for handler in &ann_def.handlers {
1573            // Comptime handlers are stored as AST (not compiled to bytecode).
1574            // They are executed at compile time when the annotation is applied.
1575            match handler.handler_type {
1576                AnnotationHandlerType::ComptimePre => {
1577                    compiled.comptime_pre_handler = Some(handler.clone());
1578                    continue;
1579                }
1580                AnnotationHandlerType::ComptimePost => {
1581                    compiled.comptime_post_handler = Some(handler.clone());
1582                    continue;
1583                }
1584                _ => {}
1585            }
1586
1587            if handler.params.iter().any(|p| p.is_variadic) {
1588                return Err(ShapeError::SemanticError {
1589                    message:
1590                        "Variadic annotation handler params (`...args`) are only supported on comptime handlers"
1591                            .to_string(),
1592                    location: Some(self.span_to_source_location(handler.span)),
1593                });
1594            }
1595
1596            let handler_type_str = match handler.handler_type {
1597                AnnotationHandlerType::Before => "before",
1598                AnnotationHandlerType::After => "after",
1599                AnnotationHandlerType::OnDefine => "on_define",
1600                AnnotationHandlerType::Metadata => "metadata",
1601                AnnotationHandlerType::ComptimePre => unreachable!(),
1602                AnnotationHandlerType::ComptimePost => unreachable!(),
1603            };
1604
1605            let func_name = format!("{}___{}", ann_def.name, handler_type_str);
1606
1607            // Build function params: self + annotation_params + handler_params
1608            let mut params = vec![FunctionParameter {
1609                pattern: shape_ast::ast::DestructurePattern::Identifier(
1610                    "self".to_string(),
1611                    Span::DUMMY,
1612                ),
1613                is_const: false,
1614                is_reference: false,
1615                is_mut_reference: false,
1616                is_out: false,
1617                type_annotation: None,
1618                default_value: None,
1619            }];
1620            // Add annotation params (e.g., period)
1621            for ann_param in &ann_def.params {
1622                params.push(ann_param.clone());
1623            }
1624            // Add handler params (e.g., args, ctx)
1625            for param in &handler.params {
1626                let inferred_type = if param.name == "ctx" {
1627                    Some(TypeAnnotation::Object(vec![
1628                        shape_ast::ast::ObjectTypeField {
1629                            name: "state".to_string(),
1630                            optional: false,
1631                            type_annotation: TypeAnnotation::Basic("unknown".to_string()),
1632                            annotations: vec![],
1633                        },
1634                        shape_ast::ast::ObjectTypeField {
1635                            name: "event_log".to_string(),
1636                            optional: false,
1637                            type_annotation: TypeAnnotation::Array(Box::new(TypeAnnotation::Basic("unknown".to_string()))),
1638                            annotations: vec![],
1639                        },
1640                    ]))
1641                } else if matches!(
1642                    handler.handler_type,
1643                    AnnotationHandlerType::OnDefine | AnnotationHandlerType::Metadata
1644                ) && (param.name == "fn" || param.name == "target")
1645                {
1646                    Some(TypeAnnotation::Object(vec![
1647                        shape_ast::ast::ObjectTypeField {
1648                            name: "name".to_string(),
1649                            optional: false,
1650                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1651                            annotations: vec![],
1652                        },
1653                        shape_ast::ast::ObjectTypeField {
1654                            name: "kind".to_string(),
1655                            optional: false,
1656                            type_annotation: TypeAnnotation::Basic("string".to_string()),
1657                            annotations: vec![],
1658                        },
1659                        shape_ast::ast::ObjectTypeField {
1660                            name: "id".to_string(),
1661                            optional: false,
1662                            type_annotation: TypeAnnotation::Basic("int".to_string()),
1663                            annotations: vec![],
1664                        },
1665                    ]))
1666                } else {
1667                    None
1668                };
1669
1670                params.push(FunctionParameter {
1671                    pattern: shape_ast::ast::DestructurePattern::Identifier(
1672                        param.name.clone(),
1673                        Span::DUMMY,
1674                    ),
1675                    is_const: false,
1676                    is_reference: false,
1677                    is_mut_reference: false,
1678                    is_out: false,
1679                    type_annotation: inferred_type,
1680                    default_value: None,
1681                });
1682            }
1683
1684            // Convert handler body (Expr) to function body (Vec<Statement>)
1685            let body = vec![Statement::Return(Some(handler.body.clone()), Span::DUMMY)];
1686
1687            let func_def = FunctionDef {
1688                name: func_name,
1689                name_span: Span::DUMMY,
1690                declaring_module_path: None,
1691                doc_comment: None,
1692                params,
1693                return_type: handler.return_type.clone(),
1694                body,
1695                type_params: Some(Vec::new()),
1696                annotations: Vec::new(),
1697                is_async: false,
1698                is_comptime: false,
1699                where_clause: None,
1700            };
1701
1702            self.register_function(&func_def)?;
1703            self.compile_function(&func_def)?;
1704
1705            let func_id = (self.program.functions.len() - 1) as u16;
1706
1707            match handler.handler_type {
1708                AnnotationHandlerType::Before => compiled.before_handler = Some(func_id),
1709                AnnotationHandlerType::After => compiled.after_handler = Some(func_id),
1710                AnnotationHandlerType::OnDefine => compiled.on_define_handler = Some(func_id),
1711                AnnotationHandlerType::Metadata => compiled.metadata_handler = Some(func_id),
1712                AnnotationHandlerType::ComptimePre => {} // handled above
1713                AnnotationHandlerType::ComptimePost => {} // handled above
1714            }
1715        }
1716
1717        // Resolve allowed target kinds.
1718        // Explicit `targets: [...]` in the annotation definition has priority.
1719        // Otherwise infer from handlers:
1720        // before/after handlers only make sense on functions (they wrap calls),
1721        // lifecycle handlers (on_define/metadata) are definition-time only.
1722        if let Some(explicit) = &ann_def.allowed_targets {
1723            compiled.allowed_targets = explicit.clone();
1724        } else if compiled.before_handler.is_some()
1725            || compiled.after_handler.is_some()
1726            || compiled.comptime_pre_handler.is_some()
1727            || compiled.comptime_post_handler.is_some()
1728        {
1729            compiled.allowed_targets =
1730                vec![shape_ast::ast::functions::AnnotationTargetKind::Function];
1731        } else if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
1732            compiled.allowed_targets = vec![
1733                shape_ast::ast::functions::AnnotationTargetKind::Function,
1734                shape_ast::ast::functions::AnnotationTargetKind::Type,
1735                shape_ast::ast::functions::AnnotationTargetKind::Module,
1736            ];
1737        }
1738
1739        // Enforce that definition-time lifecycle hooks only target definition
1740        // sites (`function` / `type`).
1741        if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
1742            if compiled.allowed_targets.is_empty() {
1743                return Err(ShapeError::SemanticError {
1744                    message: format!(
1745                        "Annotation '{}' uses `on_define`/`metadata` and cannot have unrestricted targets. Allowed targets are: function, type, module",
1746                        ann_def.name
1747                    ),
1748                    location: Some(self.span_to_source_location(ann_def.span)),
1749                });
1750            }
1751            if let Some(invalid) = compiled
1752                .allowed_targets
1753                .iter()
1754                .find(|kind| !Self::is_definition_annotation_target(**kind))
1755            {
1756                let invalid_label = format!("{:?}", invalid).to_lowercase();
1757                return Err(ShapeError::SemanticError {
1758                    message: format!(
1759                        "Annotation '{}' uses `on_define`/`metadata`, but target '{}' is not a definition target. Allowed targets are: function, type, module",
1760                        ann_def.name, invalid_label
1761                    ),
1762                    location: Some(self.span_to_source_location(ann_def.span)),
1763                });
1764            }
1765        }
1766
1767        self.program
1768            .compiled_annotations
1769            .insert(ann_def.name.clone(), compiled);
1770        Ok(())
1771    }
1772
1773    /// Register a struct type definition.
1774    ///
1775    /// Comptime fields are baked at compile time and excluded from the runtime TypeSchema.
1776    /// Their values are stored in `self.comptime_fields` for constant-folded access.
1777    fn register_struct_type(
1778        &mut self,
1779        struct_def: &shape_ast::ast::StructTypeDef,
1780        span: shape_ast::ast::Span,
1781    ) -> Result<()> {
1782        use shape_ast::ast::Literal;
1783        use shape_runtime::type_schema::{FieldAnnotation, TypeSchemaBuilder};
1784
1785        // Validate annotation target kinds before type registration.
1786        for ann in &struct_def.annotations {
1787            self.validate_annotation_target_usage(
1788                ann,
1789                shape_ast::ast::functions::AnnotationTargetKind::Type,
1790                span,
1791            )?;
1792        }
1793
1794        if struct_def.native_layout.is_some() {
1795            self.native_layout_types.insert(struct_def.name.clone());
1796        } else {
1797            self.native_layout_types.remove(&struct_def.name);
1798        }
1799
1800        // Pre-register runtime field layout so comptime-generated methods on
1801        // `extend target { ... }` can resolve `self.field` statically.
1802        // If the target is later removed by comptime directives, these
1803        // placeholders are rolled back below.
1804        let runtime_field_names: Vec<String> = struct_def
1805            .fields
1806            .iter()
1807            .filter(|f| !f.is_comptime)
1808            .map(|f| f.name.clone())
1809            .collect();
1810        let runtime_field_types = struct_def
1811            .fields
1812            .iter()
1813            .filter(|f| !f.is_comptime)
1814            .map(|f| (f.name.clone(), f.type_annotation.clone()))
1815            .collect::<std::collections::HashMap<_, _>>();
1816        self.struct_types
1817            .insert(struct_def.name.clone(), (runtime_field_names, span));
1818        self.struct_generic_info.insert(
1819            struct_def.name.clone(),
1820            StructGenericInfo {
1821                type_params: struct_def.type_params.clone().unwrap_or_default(),
1822                runtime_field_types,
1823            },
1824        );
1825        if self
1826            .type_tracker
1827            .schema_registry()
1828            .get(&struct_def.name)
1829            .is_none()
1830        {
1831            let runtime_fields: Vec<(String, shape_runtime::type_schema::FieldType)> = struct_def
1832                .fields
1833                .iter()
1834                .filter(|f| !f.is_comptime)
1835                .map(|f| {
1836                    (
1837                        f.name.clone(),
1838                        Self::type_annotation_to_field_type(&f.type_annotation),
1839                    )
1840                })
1841                .collect();
1842            self.type_tracker
1843                .schema_registry_mut()
1844                .register_type(struct_def.name.clone(), runtime_fields);
1845        }
1846
1847        // Execute comptime annotation handlers before registration so
1848        // `remove target` can suppress type emission entirely.
1849        if self.execute_struct_comptime_handlers(struct_def)? {
1850            self.struct_types.remove(&struct_def.name);
1851            self.struct_generic_info.remove(&struct_def.name);
1852            return Ok(());
1853        }
1854
1855        if struct_def.native_layout.is_some() {
1856            self.register_native_struct_layout(struct_def, span)?;
1857        }
1858
1859        // Build TypeSchema for runtime fields only
1860        if self
1861            .type_tracker
1862            .schema_registry()
1863            .get(&struct_def.name)
1864            .is_none()
1865        {
1866            let mut builder = TypeSchemaBuilder::new(struct_def.name.clone());
1867            for field in &struct_def.fields {
1868                if field.is_comptime {
1869                    continue;
1870                }
1871                let field_type = Self::type_annotation_to_field_type(&field.type_annotation);
1872                let mut annotations = Vec::new();
1873                for ann in &field.annotations {
1874                    let args: Vec<String> = ann
1875                        .args
1876                        .iter()
1877                        .filter_map(Self::eval_annotation_arg)
1878                        .collect();
1879                    annotations.push(FieldAnnotation {
1880                        name: ann.name.clone(),
1881                        args,
1882                    });
1883                }
1884                builder = builder.field_with_meta(field.name.clone(), field_type, annotations);
1885            }
1886            builder.register(self.type_tracker.schema_registry_mut());
1887        }
1888
1889        // Bake comptime field values
1890        let mut comptime_values = std::collections::HashMap::new();
1891        for field in &struct_def.fields {
1892            if !field.is_comptime {
1893                continue;
1894            }
1895            if let Some(ref default_expr) = field.default_value {
1896                let value = match default_expr {
1897                    Expr::Literal(Literal::Number(n), _) => shape_value::ValueWord::from_f64(*n),
1898                    Expr::Literal(Literal::Int(n), _) => {
1899                        shape_value::ValueWord::from_f64(*n as f64)
1900                    }
1901                    Expr::Literal(Literal::String(s), _) => {
1902                        shape_value::ValueWord::from_string(std::sync::Arc::new(s.clone()))
1903                    }
1904                    Expr::Literal(Literal::Bool(b), _) => shape_value::ValueWord::from_bool(*b),
1905                    Expr::Literal(Literal::None, _) => shape_value::ValueWord::none(),
1906                    _ => {
1907                        return Err(ShapeError::SemanticError {
1908                            message: format!(
1909                                "Comptime field '{}' on type '{}' must have a literal default value",
1910                                field.name, struct_def.name
1911                            ),
1912                            location: None,
1913                        });
1914                    }
1915                };
1916                comptime_values.insert(field.name.clone(), value);
1917            }
1918            // Comptime fields without a default are allowed — they must be
1919            // provided via type alias overrides (e.g., type EUR = Currency { symbol: "€" })
1920        }
1921
1922        if !comptime_values.is_empty() {
1923            self.comptime_fields
1924                .insert(struct_def.name.clone(), comptime_values);
1925        }
1926
1927        self.maybe_generate_native_type_conversions(&struct_def.name, span)?;
1928
1929        Ok(())
1930    }
1931
1932    fn register_native_struct_layout(
1933        &mut self,
1934        struct_def: &shape_ast::ast::StructTypeDef,
1935        span: shape_ast::ast::Span,
1936    ) -> Result<()> {
1937        if struct_def.type_params.is_some() {
1938            return Err(ShapeError::SemanticError {
1939                message: format!(
1940                    "type C '{}' cannot be generic in this version",
1941                    struct_def.name
1942                ),
1943                location: Some(self.span_to_source_location(span)),
1944            });
1945        }
1946
1947        if struct_def.fields.iter().any(|f| f.is_comptime) {
1948            return Err(ShapeError::SemanticError {
1949                message: format!(
1950                    "type C '{}' cannot contain comptime fields",
1951                    struct_def.name
1952                ),
1953                location: Some(self.span_to_source_location(span)),
1954            });
1955        }
1956
1957        let abi = struct_def
1958            .native_layout
1959            .as_ref()
1960            .map(|b| b.abi.clone())
1961            .unwrap_or_else(|| "C".to_string());
1962        if abi != "C" {
1963            return Err(ShapeError::SemanticError {
1964                message: format!(
1965                    "type '{}' uses unsupported native ABI '{}'; only C is supported",
1966                    struct_def.name, abi
1967                ),
1968                location: Some(self.span_to_source_location(span)),
1969            });
1970        }
1971
1972        let mut struct_align: u64 = 1;
1973        let mut offset: u64 = 0;
1974        let mut field_layouts = Vec::with_capacity(struct_def.fields.len());
1975
1976        for field in &struct_def.fields {
1977            let field_spec =
1978                self.native_field_layout_spec(&field.type_annotation, span, &struct_def.name)?;
1979            struct_align = struct_align.max(field_spec.align);
1980            offset = Self::align_to(offset, field_spec.align);
1981            if offset > u32::MAX as u64
1982                || field_spec.size > u32::MAX as u64
1983                || field_spec.align > u32::MAX as u64
1984            {
1985                return Err(ShapeError::SemanticError {
1986                    message: format!(
1987                        "type C '{}' layout exceeds supported size/alignment limits",
1988                        struct_def.name
1989                    ),
1990                    location: Some(self.span_to_source_location(span)),
1991                });
1992            }
1993            field_layouts.push(crate::bytecode::NativeStructFieldLayout {
1994                name: field.name.clone(),
1995                c_type: field_spec.c_type,
1996                offset: offset as u32,
1997                size: field_spec.size as u32,
1998                align: field_spec.align as u32,
1999            });
2000            offset = offset.saturating_add(field_spec.size);
2001        }
2002
2003        let size = Self::align_to(offset, struct_align);
2004        if size > u32::MAX as u64 || struct_align > u32::MAX as u64 {
2005            return Err(ShapeError::SemanticError {
2006                message: format!(
2007                    "type C '{}' layout exceeds supported size/alignment limits",
2008                    struct_def.name
2009                ),
2010                location: Some(self.span_to_source_location(span)),
2011            });
2012        }
2013
2014        let entry = crate::bytecode::NativeStructLayoutEntry {
2015            name: struct_def.name.clone(),
2016            abi,
2017            size: size as u32,
2018            align: struct_align as u32,
2019            fields: field_layouts,
2020        };
2021
2022        if let Some(existing) = self
2023            .program
2024            .native_struct_layouts
2025            .iter_mut()
2026            .find(|existing| existing.name == entry.name)
2027        {
2028            *existing = entry;
2029        } else {
2030            self.program.native_struct_layouts.push(entry);
2031        }
2032
2033        Ok(())
2034    }
2035
2036    fn align_to(value: u64, align: u64) -> u64 {
2037        debug_assert!(align > 0);
2038        let mask = align - 1;
2039        (value + mask) & !mask
2040    }
2041
2042    fn native_field_layout_spec(
2043        &self,
2044        ann: &shape_ast::ast::TypeAnnotation,
2045        span: shape_ast::ast::Span,
2046        struct_name: &str,
2047    ) -> Result<NativeFieldLayoutSpec> {
2048        use shape_ast::ast::TypeAnnotation;
2049
2050        let pointer = std::mem::size_of::<usize>() as u64;
2051
2052        let fail = || -> Result<NativeFieldLayoutSpec> {
2053            Err(ShapeError::SemanticError {
2054                message: format!(
2055                    "unsupported type C field type '{}' in '{}'",
2056                    ann.to_type_string(),
2057                    struct_name
2058                ),
2059                location: Some(self.span_to_source_location(span)),
2060            })
2061        };
2062
2063        match ann {
2064            TypeAnnotation::Basic(name) | TypeAnnotation::Reference(name) => {
2065                if let Some(existing) = self
2066                    .program
2067                    .native_struct_layouts
2068                    .iter()
2069                    .find(|layout| &layout.name == name)
2070                {
2071                    return Ok(NativeFieldLayoutSpec {
2072                        c_type: name.clone(),
2073                        size: existing.size as u64,
2074                        align: existing.align as u64,
2075                    });
2076                }
2077
2078                let spec = match name.as_str() {
2079                    "f64" | "number" | "Number" | "float" => ("f64", 8, 8),
2080                    "f32" => ("f32", 4, 4),
2081                    "i64" | "int" | "integer" | "Int" | "Integer" => ("i64", 8, 8),
2082                    "i32" => ("i32", 4, 4),
2083                    "i16" => ("i16", 2, 2),
2084                    "i8" | "char" => ("i8", 1, 1),
2085                    "u64" => ("u64", 8, 8),
2086                    "u32" => ("u32", 4, 4),
2087                    "u16" => ("u16", 2, 2),
2088                    "u8" | "byte" => ("u8", 1, 1),
2089                    "bool" | "boolean" => ("bool", 1, 1),
2090                    "isize" => ("isize", pointer, pointer),
2091                    "usize" | "ptr" | "pointer" => ("ptr", pointer, pointer),
2092                    "string" | "str" | "cstring" => ("cstring", pointer, pointer),
2093                    _ => return fail(),
2094                };
2095                Ok(NativeFieldLayoutSpec {
2096                    c_type: spec.0.to_string(),
2097                    size: spec.1,
2098                    align: spec.2,
2099                })
2100            }
2101            TypeAnnotation::Generic { name, args }
2102                if name == "Option" && args.len() == 1 =>
2103            {
2104                let inner = self.native_field_layout_spec(&args[0], span, struct_name)?;
2105                if inner.c_type == "cstring" {
2106                    Ok(NativeFieldLayoutSpec {
2107                        c_type: "cstring?".to_string(),
2108                        size: pointer,
2109                        align: pointer,
2110                    })
2111                } else {
2112                    fail()
2113                }
2114            }
2115            _ => fail(),
2116        }
2117    }
2118
2119    fn maybe_generate_native_type_conversions(
2120        &mut self,
2121        type_name: &str,
2122        span: shape_ast::ast::Span,
2123    ) -> Result<()> {
2124        let pair = if self.native_layout_types.contains(type_name) {
2125            let Some(object_type) = Self::object_type_name_for_native_layout(type_name) else {
2126                return Ok(());
2127            };
2128            if !self.struct_types.contains_key(&object_type)
2129                || self.native_layout_types.contains(&object_type)
2130            {
2131                return Ok(());
2132            }
2133            (type_name.to_string(), object_type)
2134        } else {
2135            let candidates: Vec<String> = Self::native_layout_name_candidates_for_object(type_name)
2136                .into_iter()
2137                .filter(|candidate| self.native_layout_types.contains(candidate))
2138                .collect();
2139            if candidates.is_empty() {
2140                return Ok(());
2141            }
2142            if candidates.len() > 1 {
2143                return Err(ShapeError::SemanticError {
2144                    message: format!(
2145                        "type '{}' matches multiple `type C` companions ({}) - use one canonical name",
2146                        type_name,
2147                        candidates.join(", ")
2148                    ),
2149                    location: Some(self.span_to_source_location(span)),
2150                });
2151            }
2152            (candidates[0].clone(), type_name.to_string())
2153        };
2154
2155        let pair_key = format!("{}::{}", pair.0, pair.1);
2156        if self.generated_native_conversion_pairs.contains(&pair_key) {
2157            return Ok(());
2158        }
2159
2160        self.validate_native_conversion_pair(&pair.0, &pair.1, span)?;
2161        self.generate_native_conversion_direction(&pair.0, &pair.1, span)?;
2162        self.generate_native_conversion_direction(&pair.1, &pair.0, span)?;
2163        self.generated_native_conversion_pairs.insert(pair_key);
2164        Ok(())
2165    }
2166
2167    fn object_type_name_for_native_layout(name: &str) -> Option<String> {
2168        if let Some(base) = name.strip_suffix("Layout")
2169            && !base.is_empty()
2170        {
2171            return Some(base.to_string());
2172        }
2173        if let Some(base) = name.strip_suffix('C')
2174            && !base.is_empty()
2175        {
2176            return Some(base.to_string());
2177        }
2178        if let Some(base) = name.strip_prefix('C')
2179            && !base.is_empty()
2180            && base
2181                .chars()
2182                .next()
2183                .map(|ch| ch.is_ascii_uppercase())
2184                .unwrap_or(false)
2185        {
2186            return Some(base.to_string());
2187        }
2188        None
2189    }
2190
2191    fn native_layout_name_candidates_for_object(name: &str) -> Vec<String> {
2192        vec![
2193            format!("{}Layout", name),
2194            format!("{}C", name),
2195            format!("C{}", name),
2196        ]
2197    }
2198
2199    fn validate_native_conversion_pair(
2200        &self,
2201        c_type: &str,
2202        object_type: &str,
2203        span: shape_ast::ast::Span,
2204    ) -> Result<()> {
2205        if !self.native_layout_types.contains(c_type) {
2206            return Err(ShapeError::SemanticError {
2207                message: format!("'{}' is not declared as `type C`", c_type),
2208                location: Some(self.span_to_source_location(span)),
2209            });
2210        }
2211        if self.native_layout_types.contains(object_type) {
2212            return Err(ShapeError::SemanticError {
2213                message: format!(
2214                    "auto conversion target '{}' cannot also be declared as `type C`",
2215                    object_type
2216                ),
2217                location: Some(self.span_to_source_location(span)),
2218            });
2219        }
2220
2221        let c_type_info =
2222            self.struct_generic_info
2223                .get(c_type)
2224                .ok_or_else(|| ShapeError::SemanticError {
2225                    message: format!("missing compiler metadata for `type C {}`", c_type),
2226                    location: Some(self.span_to_source_location(span)),
2227                })?;
2228        let object_type_info =
2229            self.struct_generic_info
2230                .get(object_type)
2231                .ok_or_else(|| ShapeError::SemanticError {
2232                    message: format!(
2233                        "missing compiler metadata for companion type '{}'",
2234                        object_type
2235                    ),
2236                    location: Some(self.span_to_source_location(span)),
2237                })?;
2238
2239        if !c_type_info.type_params.is_empty() || !object_type_info.type_params.is_empty() {
2240            return Err(ShapeError::SemanticError {
2241                message: format!(
2242                    "auto `type C` conversions currently require non-generic types (`{}` <-> `{}`)",
2243                    c_type, object_type
2244                ),
2245                location: Some(self.span_to_source_location(span)),
2246            });
2247        }
2248
2249        let c_fields = self
2250            .struct_types
2251            .get(c_type)
2252            .map(|(fields, _)| fields)
2253            .ok_or_else(|| ShapeError::SemanticError {
2254                message: format!("missing field metadata for `type C {}`", c_type),
2255                location: Some(self.span_to_source_location(span)),
2256            })?;
2257        let object_fields = self
2258            .struct_types
2259            .get(object_type)
2260            .map(|(fields, _)| fields)
2261            .ok_or_else(|| ShapeError::SemanticError {
2262                message: format!(
2263                    "missing field metadata for companion type '{}'",
2264                    object_type
2265                ),
2266                location: Some(self.span_to_source_location(span)),
2267            })?;
2268
2269        let c_field_set: std::collections::HashSet<&str> =
2270            c_fields.iter().map(String::as_str).collect();
2271        let object_field_set: std::collections::HashSet<&str> =
2272            object_fields.iter().map(String::as_str).collect();
2273        if c_field_set != object_field_set {
2274            return Err(ShapeError::SemanticError {
2275                message: format!(
2276                    "auto conversion pair '{}' <-> '{}' must have identical runtime fields",
2277                    c_type, object_type
2278                ),
2279                location: Some(self.span_to_source_location(span)),
2280            });
2281        }
2282
2283        for field_name in c_field_set {
2284            let c_ann = c_type_info
2285                .runtime_field_types
2286                .get(field_name)
2287                .ok_or_else(|| ShapeError::SemanticError {
2288                    message: format!(
2289                        "missing type metadata for field '{}.{}'",
2290                        c_type, field_name
2291                    ),
2292                    location: Some(self.span_to_source_location(span)),
2293                })?;
2294            let object_ann = object_type_info
2295                .runtime_field_types
2296                .get(field_name)
2297                .ok_or_else(|| ShapeError::SemanticError {
2298                    message: format!(
2299                        "missing type metadata for field '{}.{}'",
2300                        object_type, field_name
2301                    ),
2302                    location: Some(self.span_to_source_location(span)),
2303                })?;
2304            if c_ann != object_ann {
2305                return Err(ShapeError::SemanticError {
2306                    message: format!(
2307                        "field type mismatch for auto conversion '{}.{}' (`{}`) vs '{}.{}' (`{}`)",
2308                        c_type,
2309                        field_name,
2310                        c_ann.to_type_string(),
2311                        object_type,
2312                        field_name,
2313                        object_ann.to_type_string()
2314                    ),
2315                    location: Some(self.span_to_source_location(span)),
2316                });
2317            }
2318        }
2319
2320        Ok(())
2321    }
2322
2323    fn generate_native_conversion_direction(
2324        &mut self,
2325        source_type: &str,
2326        target_type: &str,
2327        span: shape_ast::ast::Span,
2328    ) -> Result<()> {
2329        let fn_name = format!(
2330            "__auto_native_from_{}_to_{}",
2331            Self::sanitize_auto_symbol(source_type),
2332            Self::sanitize_auto_symbol(target_type)
2333        );
2334        if self.function_defs.contains_key(&fn_name) {
2335            return Ok(());
2336        }
2337
2338        let target_fields = self
2339            .struct_types
2340            .get(target_type)
2341            .map(|(fields, _)| fields.clone())
2342            .ok_or_else(|| ShapeError::SemanticError {
2343                message: format!(
2344                    "missing target type metadata for auto conversion '{}'",
2345                    target_type
2346                ),
2347                location: Some(self.span_to_source_location(span)),
2348            })?;
2349
2350        let source_expr = Expr::Identifier("value".to_string(), span);
2351        let struct_fields = target_fields
2352            .iter()
2353            .map(|field| {
2354                (
2355                    field.clone(),
2356                    Expr::PropertyAccess {
2357                        object: Box::new(source_expr.clone()),
2358                        property: field.clone(),
2359                        optional: false,
2360                        span,
2361                    },
2362                )
2363            })
2364            .collect::<Vec<_>>();
2365        let body = vec![Statement::Return(
2366            Some(Expr::StructLiteral {
2367                type_name: target_type.to_string(),
2368                fields: struct_fields,
2369                span,
2370            }),
2371            span,
2372        )];
2373        let fn_def = FunctionDef {
2374            name: fn_name.clone(),
2375            name_span: span,
2376            declaring_module_path: None,
2377            doc_comment: None,
2378            params: vec![FunctionParameter {
2379                pattern: DestructurePattern::Identifier("value".to_string(), span),
2380                is_const: false,
2381                is_reference: false,
2382                is_mut_reference: false,
2383                is_out: false,
2384                type_annotation: Some(TypeAnnotation::Reference(source_type.to_string())),
2385                default_value: None,
2386            }],
2387            return_type: Some(TypeAnnotation::Reference(target_type.to_string())),
2388            body,
2389            type_params: Some(Vec::new()),
2390            annotations: Vec::new(),
2391            is_async: false,
2392            is_comptime: false,
2393            where_clause: None,
2394        };
2395        self.register_function(&fn_def)?;
2396        self.compile_function(&fn_def)?;
2397
2398        self.program.register_trait_method_symbol(
2399            "From",
2400            target_type,
2401            Some(source_type),
2402            "from",
2403            &fn_name,
2404        );
2405        self.program.register_trait_method_symbol(
2406            "Into",
2407            source_type,
2408            Some(target_type),
2409            "into",
2410            &fn_name,
2411        );
2412        let _ = self.type_inference.env.register_trait_impl_named(
2413            "From",
2414            target_type,
2415            source_type,
2416            vec!["from".to_string()],
2417        );
2418        let _ = self.type_inference.env.register_trait_impl_named(
2419            "Into",
2420            source_type,
2421            target_type,
2422            vec!["into".to_string()],
2423        );
2424        Ok(())
2425    }
2426
2427    fn sanitize_auto_symbol(name: &str) -> String {
2428        let mut out = String::with_capacity(name.len());
2429        for ch in name.chars() {
2430            if ch.is_ascii_alphanumeric() {
2431                out.push(ch);
2432            } else {
2433                out.push('_');
2434            }
2435        }
2436        out
2437    }
2438
2439    /// Execute comptime annotation handlers for a struct type definition.
2440    ///
2441    /// Mirrors `execute_comptime_handlers` in functions.rs but uses
2442    /// `ComptimeTarget::from_type()` to build the target from struct fields.
2443    fn execute_struct_comptime_handlers(
2444        &mut self,
2445        struct_def: &shape_ast::ast::StructTypeDef,
2446    ) -> Result<bool> {
2447        let mut removed = false;
2448        for ann in &struct_def.annotations {
2449            let compiled = self.program.compiled_annotations.get(&ann.name).cloned();
2450            if let Some(compiled) = compiled {
2451                let handlers = [
2452                    compiled.comptime_pre_handler,
2453                    compiled.comptime_post_handler,
2454                ];
2455                for handler in handlers.into_iter().flatten() {
2456                    // Build field info for ComptimeTarget::from_type()
2457                    // Include per-field annotations so comptime handlers can inspect them.
2458                    let fields: Vec<(
2459                        String,
2460                        Option<shape_ast::ast::TypeAnnotation>,
2461                        Vec<shape_ast::ast::functions::Annotation>,
2462                    )> = struct_def
2463                        .fields
2464                        .iter()
2465                        .map(|f| {
2466                            (
2467                                f.name.clone(),
2468                                Some(f.type_annotation.clone()),
2469                                f.annotations.clone(),
2470                            )
2471                        })
2472                        .collect();
2473
2474                    let target = super::comptime_target::ComptimeTarget::from_type(
2475                        &struct_def.name,
2476                        &fields,
2477                    );
2478                    let target_value = target.to_nanboxed();
2479                    let target_name = struct_def.name.clone();
2480                    let handler_span = handler.span;
2481                    let execution =
2482                        self.execute_comptime_annotation_handler(ann, &handler, target_value, &compiled.param_names, &[])?;
2483
2484                    if self
2485                        .process_comptime_directives(execution.directives, &target_name)
2486                        .map_err(|e| ShapeError::RuntimeError {
2487                            message: format!(
2488                                "Comptime handler '{}' directive processing failed: {}",
2489                                ann.name, e
2490                            ),
2491                            location: Some(self.span_to_source_location(handler_span)),
2492                        })?
2493                    {
2494                        removed = true;
2495                        break;
2496                    }
2497                }
2498            }
2499            if removed {
2500                break;
2501            }
2502        }
2503        Ok(removed)
2504    }
2505
2506    fn current_module_path_for(&self, module_name: &str) -> String {
2507        if let Some(parent) = self.module_scope_stack.last() {
2508            format!("{}::{}", parent, module_name)
2509        } else {
2510            module_name.to_string()
2511        }
2512    }
2513
2514    fn qualify_module_symbol(module_path: &str, name: &str) -> String {
2515        format!("{}::{}", module_path, name)
2516    }
2517
2518    fn qualify_module_item(&self, item: &Item, module_path: &str) -> Result<Item> {
2519        match item {
2520            Item::Function(func, span) => {
2521                let mut qualified = func.clone();
2522                qualified.name = Self::qualify_module_symbol(module_path, &func.name);
2523                Ok(Item::Function(qualified, *span))
2524            }
2525            Item::VariableDecl(decl, span) => {
2526                if decl.kind != VarKind::Const {
2527                    return Err(ShapeError::SemanticError {
2528                        message: "module-level variable declarations currently require `const`"
2529                            .to_string(),
2530                        location: Some(self.span_to_source_location(*span)),
2531                    });
2532                }
2533                let mut qualified = decl.clone();
2534                let Some(name) = decl.pattern.as_identifier() else {
2535                    return Err(ShapeError::SemanticError {
2536                        message:
2537                            "module-level constants currently require a simple identifier binding"
2538                                .to_string(),
2539                        location: Some(self.span_to_source_location(*span)),
2540                    });
2541                };
2542                qualified.pattern = DestructurePattern::Identifier(
2543                    Self::qualify_module_symbol(module_path, name),
2544                    *span,
2545                );
2546                Ok(Item::VariableDecl(qualified, *span))
2547            }
2548            Item::Statement(Statement::VariableDecl(decl, stmt_span), item_span) => {
2549                if decl.kind != VarKind::Const {
2550                    return Err(ShapeError::SemanticError {
2551                        message: "module-level variable declarations currently require `const`"
2552                            .to_string(),
2553                        location: Some(self.span_to_source_location(*stmt_span)),
2554                    });
2555                }
2556                let mut qualified = decl.clone();
2557                let Some(name) = decl.pattern.as_identifier() else {
2558                    return Err(ShapeError::SemanticError {
2559                        message:
2560                            "module-level constants currently require a simple identifier binding"
2561                                .to_string(),
2562                        location: Some(self.span_to_source_location(*stmt_span)),
2563                    });
2564                };
2565                qualified.pattern = DestructurePattern::Identifier(
2566                    Self::qualify_module_symbol(module_path, name),
2567                    *stmt_span,
2568                );
2569                Ok(Item::Statement(
2570                    Statement::VariableDecl(qualified, *stmt_span),
2571                    *item_span,
2572                ))
2573            }
2574            Item::Statement(Statement::Assignment(assign, stmt_span), item_span) => {
2575                let mut qualified = assign.clone();
2576                if let Some(name) = assign.pattern.as_identifier() {
2577                    qualified.pattern = DestructurePattern::Identifier(
2578                        Self::qualify_module_symbol(module_path, name),
2579                        *stmt_span,
2580                    );
2581                }
2582                Ok(Item::Statement(
2583                    Statement::Assignment(qualified, *stmt_span),
2584                    *item_span,
2585                ))
2586            }
2587            Item::Export(export, span) if export.source_decl.is_some() => {
2588                // pub const/let/var: unwrap the source_decl and qualify it as a VariableDecl
2589                let decl = export.source_decl.as_ref().unwrap();
2590                if decl.kind != VarKind::Const {
2591                    return Err(ShapeError::SemanticError {
2592                        message: "module-level variable declarations currently require `const`"
2593                            .to_string(),
2594                        location: Some(self.span_to_source_location(*span)),
2595                    });
2596                }
2597                let mut qualified = decl.clone();
2598                let Some(name) = decl.pattern.as_identifier() else {
2599                    return Err(ShapeError::SemanticError {
2600                        message:
2601                            "module-level constants currently require a simple identifier binding"
2602                                .to_string(),
2603                        location: Some(self.span_to_source_location(*span)),
2604                    });
2605                };
2606                qualified.pattern = DestructurePattern::Identifier(
2607                    Self::qualify_module_symbol(module_path, name),
2608                    *span,
2609                );
2610                Ok(Item::VariableDecl(qualified, *span))
2611            }
2612            _ => Ok(item.clone()),
2613        }
2614    }
2615
2616    fn collect_module_runtime_exports(
2617        &self,
2618        items: &[Item],
2619        module_path: &str,
2620    ) -> Vec<(String, String)> {
2621        let mut exports = Vec::new();
2622        for item in items {
2623            match item {
2624                Item::Function(func, _) => {
2625                    exports.push((
2626                        func.name.clone(),
2627                        Self::qualify_module_symbol(module_path, &func.name),
2628                    ));
2629                }
2630                Item::VariableDecl(decl, _) => {
2631                    if decl.kind == VarKind::Const
2632                        && let Some(name) = decl.pattern.as_identifier()
2633                    {
2634                        exports.push((
2635                            name.to_string(),
2636                            Self::qualify_module_symbol(module_path, name),
2637                        ));
2638                    }
2639                }
2640                Item::Statement(Statement::VariableDecl(decl, _), _) => {
2641                    if decl.kind == VarKind::Const
2642                        && let Some(name) = decl.pattern.as_identifier()
2643                    {
2644                        exports.push((
2645                            name.to_string(),
2646                            Self::qualify_module_symbol(module_path, name),
2647                        ));
2648                    }
2649                }
2650                Item::Export(export, _) => {
2651                    if let Some(ref decl) = export.source_decl {
2652                        if let Some(name) = decl.pattern.as_identifier() {
2653                            exports.push((
2654                                name.to_string(),
2655                                Self::qualify_module_symbol(module_path, name),
2656                            ));
2657                        }
2658                    }
2659                }
2660                Item::Module(module, _) => {
2661                    exports.push((
2662                        module.name.clone(),
2663                        Self::qualify_module_symbol(module_path, &module.name),
2664                    ));
2665                }
2666                _ => {}
2667            }
2668        }
2669        exports.sort_by(|a, b| a.0.cmp(&b.0));
2670        exports.dedup_by(|a, b| a.0 == b.0);
2671        exports
2672    }
2673
2674    fn module_target_fields(items: &[Item]) -> Vec<(String, String)> {
2675        let mut fields = Vec::new();
2676        for item in items {
2677            match item {
2678                Item::Function(func, _) => fields.push((func.name.clone(), "function".to_string())),
2679                Item::VariableDecl(decl, _) => {
2680                    if let Some(name) = decl.pattern.as_identifier() {
2681                        let type_name = decl
2682                            .type_annotation
2683                            .as_ref()
2684                            .and_then(TypeAnnotation::as_simple_name)
2685                            .unwrap_or("any")
2686                            .to_string();
2687                        fields.push((name.to_string(), type_name));
2688                    }
2689                }
2690                Item::Statement(Statement::VariableDecl(decl, _), _) => {
2691                    if let Some(name) = decl.pattern.as_identifier() {
2692                        let type_name = decl
2693                            .type_annotation
2694                            .as_ref()
2695                            .and_then(TypeAnnotation::as_simple_name)
2696                            .unwrap_or("any")
2697                            .to_string();
2698                        fields.push((name.to_string(), type_name));
2699                    }
2700                }
2701                Item::Export(export, _) => {
2702                    if let Some(ref decl) = export.source_decl {
2703                        if let Some(name) = decl.pattern.as_identifier() {
2704                            let type_name = decl
2705                                .type_annotation
2706                                .as_ref()
2707                                .and_then(TypeAnnotation::as_simple_name)
2708                                .unwrap_or("any")
2709                                .to_string();
2710                            fields.push((name.to_string(), type_name));
2711                        }
2712                    }
2713                }
2714                Item::StructType(def, _) => fields.push((def.name.clone(), "type".to_string())),
2715                Item::Enum(def, _) => fields.push((def.name.clone(), "type".to_string())),
2716                Item::TypeAlias(def, _) => fields.push((def.name.clone(), "type".to_string())),
2717                Item::Module(def, _) => fields.push((def.name.clone(), "module".to_string())),
2718                _ => {}
2719            }
2720        }
2721        fields
2722    }
2723
2724    fn process_comptime_directives_for_module(
2725        &mut self,
2726        directives: Vec<super::comptime_builtins::ComptimeDirective>,
2727        module_name: &str,
2728        module_items: &mut Vec<Item>,
2729    ) -> std::result::Result<bool, String> {
2730        let mut removed = false;
2731        for directive in directives {
2732            match directive {
2733                super::comptime_builtins::ComptimeDirective::Extend(extend) => {
2734                    self.apply_comptime_extend(extend, module_name)
2735                        .map_err(|e| e.to_string())?;
2736                }
2737                super::comptime_builtins::ComptimeDirective::RemoveTarget => {
2738                    removed = true;
2739                    break;
2740                }
2741                super::comptime_builtins::ComptimeDirective::ReplaceModule { items } => {
2742                    *module_items = items;
2743                }
2744                super::comptime_builtins::ComptimeDirective::SetParamType { .. }
2745                | super::comptime_builtins::ComptimeDirective::SetParamValue { .. } => {
2746                    return Err(
2747                        "`set param` directives are only valid when compiling function targets"
2748                            .to_string(),
2749                    );
2750                }
2751                super::comptime_builtins::ComptimeDirective::SetReturnType { .. } => {
2752                    return Err(
2753                        "`set return` directives are only valid when compiling function targets"
2754                            .to_string(),
2755                    );
2756                }
2757                super::comptime_builtins::ComptimeDirective::ReplaceBody { .. } => {
2758                    return Err(
2759                        "`replace body` directives are only valid when compiling function targets"
2760                            .to_string(),
2761                    );
2762                }
2763            }
2764        }
2765        Ok(removed)
2766    }
2767
2768    fn execute_module_comptime_handlers(
2769        &mut self,
2770        module_def: &ModuleDecl,
2771        module_path: &str,
2772        module_items: &mut Vec<Item>,
2773    ) -> Result<bool> {
2774        let mut removed = false;
2775        for ann in &module_def.annotations {
2776            let compiled = self.program.compiled_annotations.get(&ann.name).cloned();
2777            if let Some(compiled) = compiled {
2778                let handlers = [
2779                    compiled.comptime_pre_handler,
2780                    compiled.comptime_post_handler,
2781                ];
2782                for handler in handlers.into_iter().flatten() {
2783                    let target = super::comptime_target::ComptimeTarget::from_module(
2784                        module_path,
2785                        &Self::module_target_fields(module_items),
2786                    );
2787                    let target_value = target.to_nanboxed();
2788                    let handler_span = handler.span;
2789                    let execution =
2790                        self.execute_comptime_annotation_handler(ann, &handler, target_value, &compiled.param_names, &[])?;
2791                    if self
2792                        .process_comptime_directives_for_module(
2793                            execution.directives,
2794                            module_path,
2795                            module_items,
2796                        )
2797                        .map_err(|e| ShapeError::RuntimeError {
2798                            message: format!(
2799                                "Comptime handler '{}' directive processing failed: {}",
2800                                ann.name, e
2801                            ),
2802                            location: Some(self.span_to_source_location(handler_span)),
2803                        })?
2804                    {
2805                        removed = true;
2806                        break;
2807                    }
2808                }
2809            }
2810            if removed {
2811                break;
2812            }
2813        }
2814        Ok(removed)
2815    }
2816
2817    fn inject_module_local_comptime_helper_aliases(
2818        &self,
2819        module_path: &str,
2820        helpers: &mut Vec<FunctionDef>,
2821    ) {
2822        let module_prefix = format!("{}::", module_path);
2823        let mut seen: std::collections::HashSet<String> =
2824            helpers.iter().map(|h| h.name.clone()).collect();
2825        let mut aliases = Vec::new();
2826
2827        for helper in helpers.iter() {
2828            let Some(local_name) = helper.name.strip_prefix(&module_prefix) else {
2829                continue;
2830            };
2831            if local_name.contains("::") || !seen.insert(local_name.to_string()) {
2832                continue;
2833            }
2834            let mut alias = helper.clone();
2835            alias.name = local_name.to_string();
2836            aliases.push(alias);
2837        }
2838
2839        helpers.extend(aliases);
2840    }
2841
2842    fn execute_module_inline_comptime_blocks(
2843        &mut self,
2844        module_path: &str,
2845        module_items: &mut Vec<Item>,
2846    ) -> Result<bool> {
2847        loop {
2848            let Some(idx) = module_items
2849                .iter()
2850                .position(|item| matches!(item, Item::Comptime(_, _)))
2851            else {
2852                break;
2853            };
2854
2855            let (stmts, span) = match module_items[idx].clone() {
2856                Item::Comptime(stmts, span) => (stmts, span),
2857                _ => unreachable!("index is guarded by position() matcher"),
2858            };
2859
2860            let extensions: Vec<_> = self
2861                .extension_registry
2862                .as_ref()
2863                .map(|r| r.as_ref().clone())
2864                .unwrap_or_default();
2865            let trait_impls = self.type_inference.env.trait_impl_keys();
2866            let known_type_symbols: std::collections::HashSet<String> = self
2867                .struct_types
2868                .keys()
2869                .chain(self.type_aliases.keys())
2870                .cloned()
2871                .collect();
2872            let mut comptime_helpers = self.collect_comptime_helpers();
2873            self.inject_module_local_comptime_helper_aliases(module_path, &mut comptime_helpers);
2874
2875            let execution = super::comptime::execute_comptime(
2876                &stmts,
2877                &comptime_helpers,
2878                &extensions,
2879                trait_impls,
2880                known_type_symbols,
2881            )
2882            .map_err(|e| ShapeError::RuntimeError {
2883                message: format!(
2884                    "Comptime block evaluation failed: {}",
2885                    super::helpers::strip_error_prefix(&e)
2886                ),
2887                location: Some(self.span_to_source_location(span)),
2888            })?;
2889
2890            if self
2891                .process_comptime_directives_for_module(
2892                    execution.directives,
2893                    module_path,
2894                    module_items,
2895                )
2896                .map_err(|e| ShapeError::RuntimeError {
2897                    message: format!("Comptime block directive processing failed: {}", e),
2898                    location: Some(self.span_to_source_location(span)),
2899                })?
2900            {
2901                return Ok(true);
2902            }
2903
2904            if idx < module_items.len() && matches!(module_items[idx], Item::Comptime(_, _)) {
2905                module_items.remove(idx);
2906            }
2907        }
2908
2909        Ok(false)
2910    }
2911
2912    fn register_missing_module_functions(&mut self, item: &Item) -> Result<()> {
2913        match item {
2914            Item::Function(func, _) => {
2915                if !self.function_defs.contains_key(&func.name) {
2916                    self.register_function(func)?;
2917                }
2918                Ok(())
2919            }
2920            Item::Export(export, _) => match &export.item {
2921                ExportItem::Function(func) => {
2922                    if !self.function_defs.contains_key(&func.name) {
2923                        self.register_function(func)?;
2924                    }
2925                    Ok(())
2926                }
2927                _ => Ok(()),
2928            },
2929            Item::Module(module, _) => {
2930                let module_path = self.current_module_path_for(module.name.as_str());
2931                self.module_scope_stack.push(module_path.clone());
2932                let register_result = (|| -> Result<()> {
2933                    for inner in &module.items {
2934                        let qualified = self.qualify_module_item(inner, &module_path)?;
2935                        self.register_missing_module_functions(&qualified)?;
2936                    }
2937                    Ok(())
2938                })();
2939                self.module_scope_stack.pop();
2940                register_result
2941            }
2942            _ => Ok(()),
2943        }
2944    }
2945
2946    fn compile_module_decl(&mut self, module_def: &ModuleDecl, span: Span) -> Result<()> {
2947        for ann in &module_def.annotations {
2948            self.validate_annotation_target_usage(ann, AnnotationTargetKind::Module, span)?;
2949        }
2950
2951        let module_path = self.current_module_path_for(&module_def.name);
2952        self.module_scope_stack.push(module_path.clone());
2953
2954        let mut module_items = module_def.items.clone();
2955        if self.execute_module_comptime_handlers(module_def, &module_path, &mut module_items)? {
2956            self.module_scope_stack.pop();
2957            return Ok(());
2958        }
2959        if self.execute_module_inline_comptime_blocks(&module_path, &mut module_items)? {
2960            self.module_scope_stack.pop();
2961            return Ok(());
2962        }
2963
2964        let mut qualified_items = Vec::with_capacity(module_items.len());
2965        for inner in &module_items {
2966            qualified_items.push(self.qualify_module_item(inner, &module_path)?);
2967        }
2968
2969        for qualified in &qualified_items {
2970            self.register_missing_module_functions(qualified)?;
2971        }
2972
2973        for qualified in &qualified_items {
2974            self.compile_item_with_context(qualified, false)?;
2975        }
2976
2977        let exports = self.collect_module_runtime_exports(&module_items, &module_path);
2978        let entries: Vec<ObjectEntry> = exports
2979            .into_iter()
2980            .map(|(name, value_ident)| ObjectEntry::Field {
2981                key: name,
2982                value: Expr::Identifier(value_ident, span),
2983                type_annotation: None,
2984            })
2985            .collect();
2986        let module_object = Expr::Object(entries, span);
2987        self.compile_expr(&module_object)?;
2988
2989        let binding_idx = self.get_or_create_module_binding(&module_path);
2990        self.emit(Instruction::new(
2991            OpCode::StoreModuleBinding,
2992            Some(Operand::ModuleBinding(binding_idx)),
2993        ));
2994        self.propagate_initializer_type_to_slot(binding_idx, false, false);
2995
2996        if self.module_scope_stack.len() == 1 {
2997            self.module_namespace_bindings
2998                .insert(module_def.name.clone());
2999        }
3000
3001        self.emit_annotation_lifecycle_calls_for_module(
3002            &module_path,
3003            &module_def.annotations,
3004            Some(binding_idx),
3005        )?;
3006
3007        self.module_scope_stack.pop();
3008        Ok(())
3009    }
3010
3011    /// Compile a query (Backtest, Alert, or With/CTE).
3012    ///
3013    /// For CTE (WITH) queries:
3014    /// 1. Compile each CTE subquery and store the result in a named module_binding variable.
3015    /// 2. Compile the main query (which can reference CTEs by name as variables).
3016    ///
3017    /// For Backtest and Alert queries, emit a stub for now.
3018    fn compile_query(&mut self, query: &Query) -> Result<()> {
3019        match query {
3020            Query::With(with_query) => {
3021                // Compile each CTE: evaluate its subquery and store as a named variable
3022                for cte in &with_query.ctes {
3023                    // Recursively compile the CTE's subquery
3024                    self.compile_query(&cte.query)?;
3025
3026                    // Store the result in a module_binding variable with the CTE's name
3027                    let binding_idx = self.get_or_create_module_binding(&cte.name);
3028                    self.emit(Instruction::new(
3029                        OpCode::StoreModuleBinding,
3030                        Some(Operand::ModuleBinding(binding_idx)),
3031                    ));
3032                }
3033
3034                // Compile the main query
3035                self.compile_query(&with_query.query)?;
3036            }
3037            Query::Backtest(_backtest) => {
3038                // Backtest queries require runtime context to evaluate.
3039                // Push null as placeholder — the runtime executor handles backtest
3040                // execution when given a full ExecutionContext.
3041                self.emit(Instruction::simple(OpCode::PushNull));
3042            }
3043            Query::Alert(alert) => {
3044                // Compile alert condition
3045                self.compile_expr(&alert.condition)?;
3046                // Push null as placeholder (alert evaluation requires runtime context)
3047                self.emit(Instruction::simple(OpCode::Pop));
3048                self.emit(Instruction::simple(OpCode::PushNull));
3049            }
3050        }
3051        Ok(())
3052    }
3053
3054    pub(super) fn propagate_initializer_type_to_slot(&mut self, slot: u16, is_local: bool, _is_mutable: bool) {
3055        self.propagate_assignment_type_to_slot(slot, is_local, true);
3056    }
3057
3058    /// Compile a statement
3059    pub(super) fn compile_statement(&mut self, stmt: &Statement) -> Result<()> {
3060        match stmt {
3061            Statement::Return(expr_opt, _span) => {
3062                // Prevent returning references — refs are scoped borrows
3063                // that cannot escape the function (would create dangling refs).
3064                if let Some(expr) = expr_opt {
3065                    if let Expr::Reference { span: ref_span, .. } = expr {
3066                        return Err(ShapeError::SemanticError {
3067                            message: "cannot return a reference — references are scoped borrows that cannot escape the function. Return an owned value instead".to_string(),
3068                            location: Some(self.span_to_source_location(*ref_span)),
3069                        });
3070                    }
3071                    // Note: returning a ref_local identifier is allowed — compile_expr
3072                    // emits DerefLoad which returns the dereferenced *value*, not the
3073                    // reference itself. Only returning `&x` (Expr::Reference) is blocked.
3074                    self.compile_expr(expr)?;
3075                } else {
3076                    self.emit(Instruction::simple(OpCode::PushNull));
3077                }
3078                // Emit drops for all active drop scopes before returning
3079                let total_scopes = self.drop_locals.len();
3080                if total_scopes > 0 {
3081                    self.emit_drops_for_early_exit(total_scopes)?;
3082                }
3083                self.emit(Instruction::simple(OpCode::ReturnValue));
3084            }
3085
3086            Statement::Break(_) => {
3087                let in_loop = !self.loop_stack.is_empty();
3088                if in_loop {
3089                    // Emit drops for drop scopes inside the loop before breaking
3090                    let scopes_to_exit = self
3091                        .loop_stack
3092                        .last()
3093                        .map(|ctx| self.drop_locals.len().saturating_sub(ctx.drop_scope_depth))
3094                        .unwrap_or(0);
3095                    if scopes_to_exit > 0 {
3096                        self.emit_drops_for_early_exit(scopes_to_exit)?;
3097                    }
3098                    let jump_idx = self.emit_jump(OpCode::Jump, 0);
3099                    if let Some(loop_ctx) = self.loop_stack.last_mut() {
3100                        loop_ctx.break_jumps.push(jump_idx);
3101                    }
3102                } else {
3103                    return Err(ShapeError::RuntimeError {
3104                        message: "break statement outside of loop".to_string(),
3105                        location: None,
3106                    });
3107                }
3108            }
3109
3110            Statement::Continue(_) => {
3111                if let Some(loop_ctx) = self.loop_stack.last() {
3112                    // Copy values we need before mutable borrow
3113                    let scopes_to_exit = self
3114                        .drop_locals
3115                        .len()
3116                        .saturating_sub(loop_ctx.drop_scope_depth);
3117                    let continue_target = loop_ctx.continue_target;
3118                    // Emit drops for drop scopes inside the loop before continuing
3119                    if scopes_to_exit > 0 {
3120                        self.emit_drops_for_early_exit(scopes_to_exit)?;
3121                    }
3122                    let offset = continue_target as i32 - self.program.current_offset() as i32 - 1;
3123                    self.emit(Instruction::new(
3124                        OpCode::Jump,
3125                        Some(Operand::Offset(offset)),
3126                    ));
3127                } else {
3128                    return Err(ShapeError::RuntimeError {
3129                        message: "continue statement outside of loop".to_string(),
3130                        location: None,
3131                    });
3132                }
3133            }
3134
3135            Statement::VariableDecl(var_decl, _) => {
3136                // Set pending variable name for hoisting integration.
3137                // compile_typed_object_literal uses self to include hoisted fields in the schema.
3138                self.pending_variable_name =
3139                    var_decl.pattern.as_identifier().map(|s| s.to_string());
3140
3141                // Compile-time range check: if the type annotation is a width type
3142                // (i8, u8, i16, etc.) and the initializer is a constant expression,
3143                // verify the value fits in the declared width.
3144                if let (Some(type_ann), Some(init_expr)) =
3145                    (&var_decl.type_annotation, &var_decl.value)
3146                {
3147                    if let shape_ast::ast::TypeAnnotation::Basic(type_name) = type_ann {
3148                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
3149                            if let Some(const_val) =
3150                                crate::compiler::expressions::function_calls::eval_const_expr_to_nanboxed(init_expr)
3151                            {
3152                                let in_range = if let Some(i) = const_val.as_i64() {
3153                                    w.in_range_i64(i)
3154                                } else if let Some(f) = const_val.as_f64() {
3155                                    // Float → int truncation check
3156                                    let i = f as i64;
3157                                    (i as f64 == f) && w.in_range_i64(i)
3158                                } else {
3159                                    true // non-numeric, let runtime handle it
3160                                };
3161                                if !in_range {
3162                                    return Err(shape_ast::error::ShapeError::SemanticError {
3163                                        message: format!(
3164                                            "value does not fit in `{}` (range {}..={})",
3165                                            type_name,
3166                                            w.min_value(),
3167                                            w.max_value()
3168                                        ),
3169                                        location: Some(self.span_to_source_location(shape_ast::ast::Spanned::span(init_expr))),
3170                                    });
3171                                }
3172                            }
3173                        }
3174                    }
3175                }
3176
3177                // Compile initializer — register the variable even if the initializer fails,
3178                // to prevent cascading "Undefined variable" errors on later references.
3179                let init_err = if let Some(init_expr) = &var_decl.value {
3180                    // Special handling: Table row literal syntax
3181                    // `let t: Table<T> = [a, b], [c, d]` → compile as table construction
3182                    if let Expr::TableRows(rows, tr_span) = init_expr {
3183                        match self.compile_table_rows(rows, &var_decl.type_annotation, *tr_span) {
3184                            Ok(()) => None,
3185                            Err(e) => {
3186                                self.emit(Instruction::simple(OpCode::PushNull));
3187                                Some(e)
3188                            }
3189                        }
3190                    } else {
3191                        match self.compile_expr(init_expr) {
3192                            Ok(()) => None,
3193                            Err(e) => {
3194                                self.emit(Instruction::simple(OpCode::PushNull));
3195                                Some(e)
3196                            }
3197                        }
3198                    }
3199                } else {
3200                    self.emit(Instruction::simple(OpCode::PushNull));
3201                    None
3202                };
3203
3204                // Clear pending variable name after init expression is compiled
3205                self.pending_variable_name = None;
3206
3207                // Emit BindSchema for Table<T> annotations (runtime safety net)
3208                if let Some(ref type_ann) = var_decl.type_annotation {
3209                    if let Some(schema_id) = self.get_table_schema_id(type_ann) {
3210                        self.emit(Instruction::new(
3211                            OpCode::BindSchema,
3212                            Some(Operand::Count(schema_id)),
3213                        ));
3214                    }
3215                }
3216
3217                // At top-level (no current function), create module_bindings; otherwise create locals
3218                if self.current_function.is_none() {
3219                    // Top-level: create module_binding variable
3220                    if let Some(name) = var_decl.pattern.as_identifier() {
3221                        let binding_idx = self.get_or_create_module_binding(name);
3222                        self.emit(Instruction::new(
3223                            OpCode::StoreModuleBinding,
3224                            Some(Operand::ModuleBinding(binding_idx)),
3225                        ));
3226
3227                        // Track const module bindings for reassignment checks
3228                        if var_decl.kind == VarKind::Const {
3229                            self.const_module_bindings.insert(binding_idx);
3230                        }
3231
3232                        // Track immutable `let` bindings at module level
3233                        if var_decl.kind == VarKind::Let && !var_decl.is_mut {
3234                            self.immutable_module_bindings.insert(binding_idx);
3235                        }
3236
3237                        // Track type annotation if present (for type checker)
3238                        if let Some(ref type_ann) = var_decl.type_annotation {
3239                            if let Some(type_name) =
3240                                Self::tracked_type_name_from_annotation(type_ann)
3241                            {
3242                                self.set_module_binding_type_info(binding_idx, &type_name);
3243                            }
3244                            // Handle Table<T> generic annotation
3245                            self.try_track_datatable_type(type_ann, binding_idx, false)?;
3246                        } else {
3247                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
3248                            self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
3249                        }
3250
3251                        // Track for auto-drop at program exit
3252                        let binding_type_name = self
3253                            .type_tracker
3254                            .get_binding_type(binding_idx)
3255                            .and_then(|info| info.type_name.clone());
3256                        let drop_kind = binding_type_name
3257                            .as_ref()
3258                            .and_then(|tn| self.drop_type_info.get(tn).copied())
3259                            .or_else(|| {
3260                                var_decl
3261                                    .type_annotation
3262                                    .as_ref()
3263                                    .and_then(|ann| self.annotation_drop_kind(ann))
3264                            });
3265                        if drop_kind.is_some() {
3266                            let is_async = match drop_kind {
3267                                Some(DropKind::AsyncOnly) => true,
3268                                Some(DropKind::Both) => false,
3269                                Some(DropKind::SyncOnly) | None => false,
3270                            };
3271                            self.track_drop_module_binding(binding_idx, is_async);
3272                        }
3273                    } else {
3274                        self.compile_destructure_pattern_global(&var_decl.pattern)?;
3275                    }
3276                } else {
3277                    // Inside function: create local variable
3278                    self.compile_destructure_pattern(&var_decl.pattern)?;
3279
3280                    // Patch StoreLocal → StoreLocalTyped for width-typed simple bindings.
3281                    // compile_destructure_pattern emits StoreLocal(idx) for Identifier patterns;
3282                    // we upgrade it here when the type annotation is a width type.
3283                    if let (Some(name), Some(TypeAnnotation::Basic(type_name))) = (
3284                        var_decl.pattern.as_identifier(),
3285                        var_decl.type_annotation.as_ref(),
3286                    ) {
3287                        if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
3288                            if let Some(local_idx) = self.resolve_local(name) {
3289                                if let Some(last) = self.program.instructions.last_mut() {
3290                                    if last.opcode == OpCode::StoreLocal {
3291                                        last.opcode = OpCode::StoreLocalTyped;
3292                                        last.operand = Some(Operand::TypedLocal(
3293                                            local_idx,
3294                                            crate::bytecode::NumericWidth::from_int_width(w),
3295                                        ));
3296                                    }
3297                                }
3298                            }
3299                        }
3300                    }
3301
3302                    // Track const locals for reassignment checks
3303                    if var_decl.kind == VarKind::Const {
3304                        if let Some(name) = var_decl.pattern.as_identifier() {
3305                            if let Some(local_idx) = self.resolve_local(name) {
3306                                self.const_locals.insert(local_idx);
3307                            }
3308                        }
3309                    }
3310
3311                    // Track immutable `let` bindings (not `let mut` and not `var`)
3312                    // `let` without `mut` is immutable by default.
3313                    // `var` is always mutable (inferred from usage).
3314                    // `let mut` is explicitly mutable.
3315                    if var_decl.kind == VarKind::Let && !var_decl.is_mut {
3316                        if let Some(name) = var_decl.pattern.as_identifier() {
3317                            if let Some(local_idx) = self.resolve_local(name) {
3318                                self.immutable_locals.insert(local_idx);
3319                            }
3320                        }
3321                    }
3322
3323                    // Track type annotation first (so drop tracking can resolve the type)
3324                    if let Some(name) = var_decl.pattern.as_identifier() {
3325                        if let Some(ref type_ann) = var_decl.type_annotation {
3326                            if let Some(type_name) =
3327                                Self::tracked_type_name_from_annotation(type_ann)
3328                            {
3329                                // Get the local index for self variable
3330                                if let Some(local_idx) = self.resolve_local(name) {
3331                                    self.set_local_type_info(local_idx, &type_name);
3332                                }
3333                            }
3334                            // Handle Table<T> generic annotation
3335                            if let Some(local_idx) = self.resolve_local(name) {
3336                                self.try_track_datatable_type(type_ann, local_idx, true)?;
3337                            }
3338                        } else if let Some(local_idx) = self.resolve_local(name) {
3339                            let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
3340                            self.propagate_initializer_type_to_slot(local_idx, true, is_mutable);
3341                        }
3342                    }
3343
3344                    // Track for auto-drop at scope exit (DropCall silently skips non-Drop types).
3345                    // Select sync vs async opcode based on the type's DropKind.
3346                    if let Some(name) = var_decl.pattern.as_identifier() {
3347                        if let Some(local_idx) = self.resolve_local(name) {
3348                            let drop_kind = self.local_drop_kind(local_idx).or_else(|| {
3349                                var_decl
3350                                    .type_annotation
3351                                    .as_ref()
3352                                    .and_then(|ann| self.annotation_drop_kind(ann))
3353                            });
3354
3355                            let is_async = match drop_kind {
3356                                Some(DropKind::AsyncOnly) => {
3357                                    if !self.current_function_is_async {
3358                                        let tn = self
3359                                            .type_tracker
3360                                            .get_local_type(local_idx)
3361                                            .and_then(|info| info.type_name.clone())
3362                                            .unwrap_or_else(|| name.to_string());
3363                                        return Err(ShapeError::SemanticError {
3364                                            message: format!(
3365                                                "type '{}' has only an async drop() and cannot be used in a sync context; \
3366                                                 add a sync method drop(self) or use it inside an async function",
3367                                                tn
3368                                            ),
3369                                            location: None,
3370                                        });
3371                                    }
3372                                    true
3373                                }
3374                                Some(DropKind::Both) => self.current_function_is_async,
3375                                Some(DropKind::SyncOnly) | None => false,
3376                            };
3377                            self.track_drop_local(local_idx, is_async);
3378                        }
3379                    }
3380                }
3381
3382                if let Some(e) = init_err {
3383                    return Err(e);
3384                }
3385            }
3386
3387            Statement::Assignment(assign, _) => 'assign: {
3388                // Check for const reassignment
3389                if let Some(name) = assign.pattern.as_identifier() {
3390                    if let Some(local_idx) = self.resolve_local(name) {
3391                        if self.const_locals.contains(&local_idx) {
3392                            return Err(ShapeError::SemanticError {
3393                                message: format!("Cannot reassign const variable '{}'", name),
3394                                location: None,
3395                            });
3396                        }
3397                        // Check for immutable `let` reassignment
3398                        if self.immutable_locals.contains(&local_idx) {
3399                            return Err(ShapeError::SemanticError {
3400                                message: format!(
3401                                    "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
3402                                    name
3403                                ),
3404                                location: None,
3405                            });
3406                        }
3407                    } else {
3408                        let scoped_name = self
3409                            .resolve_scoped_module_binding_name(name)
3410                            .unwrap_or_else(|| name.to_string());
3411                        if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
3412                            if self.const_module_bindings.contains(&binding_idx) {
3413                                return Err(ShapeError::SemanticError {
3414                                    message: format!("Cannot reassign const variable '{}'", name),
3415                                    location: None,
3416                                });
3417                            }
3418                            // Check for immutable `let` reassignment at module level
3419                            if self.immutable_module_bindings.contains(&binding_idx) {
3420                                return Err(ShapeError::SemanticError {
3421                                    message: format!(
3422                                        "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
3423                                        name
3424                                    ),
3425                                    location: None,
3426                                });
3427                            }
3428                        }
3429                    }
3430                }
3431
3432                // Optimization: x = x.push(val) → ArrayPushLocal (O(1) in-place mutation)
3433                if let Some(name) = assign.pattern.as_identifier() {
3434                    if let Expr::MethodCall {
3435                        receiver,
3436                        method,
3437                        args,
3438                        ..
3439                    } = &assign.value
3440                    {
3441                        if method == "push" && args.len() == 1 {
3442                            if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
3443                                if recv_name == name {
3444                                    if let Some(local_idx) = self.resolve_local(name) {
3445                                        if !self.ref_locals.contains(&local_idx) {
3446                                            self.compile_expr(&args[0])?;
3447                                            let pushed_numeric = self.last_expr_numeric_type;
3448                                            self.emit(Instruction::new(
3449                                                OpCode::ArrayPushLocal,
3450                                                Some(Operand::Local(local_idx)),
3451                                            ));
3452                                            if let Some(numeric_type) = pushed_numeric {
3453                                                self.mark_slot_as_numeric_array(
3454                                                    local_idx,
3455                                                    true,
3456                                                    numeric_type,
3457                                                );
3458                                            }
3459                                            break 'assign;
3460                                        }
3461                                    } else {
3462                                        let binding_idx = self.get_or_create_module_binding(name);
3463                                        self.compile_expr(&args[0])?;
3464                                        let pushed_numeric = self.last_expr_numeric_type;
3465                                        self.emit(Instruction::new(
3466                                            OpCode::ArrayPushLocal,
3467                                            Some(Operand::ModuleBinding(binding_idx)),
3468                                        ));
3469                                        if let Some(numeric_type) = pushed_numeric {
3470                                            self.mark_slot_as_numeric_array(
3471                                                binding_idx,
3472                                                false,
3473                                                numeric_type,
3474                                            );
3475                                        }
3476                                        break 'assign;
3477                                    }
3478                                }
3479                            }
3480                        }
3481                    }
3482                }
3483
3484                // Compile value
3485                self.compile_expr(&assign.value)?;
3486                let assigned_ident = assign.pattern.as_identifier().map(str::to_string);
3487
3488                // Store in variable
3489                self.compile_destructure_assignment(&assign.pattern)?;
3490                if let Some(name) = assigned_ident.as_deref() {
3491                    self.propagate_assignment_type_to_identifier(name);
3492                }
3493            }
3494
3495            Statement::Expression(expr, _) => {
3496                // Fast path: arr.push(val) as standalone statement → in-place mutation
3497                // (avoids the LoadLocal+Pop overhead from the expression-level optimization)
3498                if let Expr::MethodCall {
3499                    receiver,
3500                    method,
3501                    args,
3502                    ..
3503                } = expr
3504                {
3505                    if method == "push" && args.len() == 1 {
3506                        if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
3507                            if let Some(local_idx) = self.resolve_local(recv_name) {
3508                                if !self.ref_locals.contains(&local_idx) {
3509                                    self.compile_expr(&args[0])?;
3510                                    let pushed_numeric = self.last_expr_numeric_type;
3511                                    self.emit(Instruction::new(
3512                                        OpCode::ArrayPushLocal,
3513                                        Some(Operand::Local(local_idx)),
3514                                    ));
3515                                    if let Some(numeric_type) = pushed_numeric {
3516                                        self.mark_slot_as_numeric_array(
3517                                            local_idx,
3518                                            true,
3519                                            numeric_type,
3520                                        );
3521                                    }
3522                                    return Ok(());
3523                                }
3524                            } else if !self
3525                                .mutable_closure_captures
3526                                .contains_key(recv_name.as_str())
3527                            {
3528                                let binding_idx = self.get_or_create_module_binding(recv_name);
3529                                self.compile_expr(&args[0])?;
3530                                self.emit(Instruction::new(
3531                                    OpCode::ArrayPushLocal,
3532                                    Some(Operand::ModuleBinding(binding_idx)),
3533                                ));
3534                                return Ok(());
3535                            }
3536                        }
3537                    }
3538                }
3539                self.compile_expr(expr)?;
3540                self.emit(Instruction::simple(OpCode::Pop));
3541            }
3542
3543            Statement::For(for_loop, _) => {
3544                self.compile_for_loop(for_loop)?;
3545            }
3546
3547            Statement::While(while_loop, _) => {
3548                self.compile_while_loop(while_loop)?;
3549            }
3550
3551            Statement::If(if_stmt, _) => {
3552                self.compile_if_statement(if_stmt)?;
3553            }
3554            Statement::Extend(extend, span) => {
3555                if !self.comptime_mode {
3556                    return Err(ShapeError::SemanticError {
3557                        message:
3558                            "`extend` as a statement is only valid inside `comptime { }` context"
3559                                .to_string(),
3560                        location: Some(self.span_to_source_location(*span)),
3561                    });
3562                }
3563                self.emit_comptime_extend_directive(extend, *span)?;
3564            }
3565            Statement::RemoveTarget(span) => {
3566                if !self.comptime_mode {
3567                    return Err(ShapeError::SemanticError {
3568                        message: "`remove target` is only valid inside `comptime { }` context"
3569                            .to_string(),
3570                        location: Some(self.span_to_source_location(*span)),
3571                    });
3572                }
3573                self.emit_comptime_remove_directive(*span)?;
3574            }
3575            Statement::SetParamType {
3576                param_name,
3577                type_annotation,
3578                span,
3579            } => {
3580                if !self.comptime_mode {
3581                    return Err(ShapeError::SemanticError {
3582                        message: "`set param` is only valid inside `comptime { }` context"
3583                            .to_string(),
3584                        location: Some(self.span_to_source_location(*span)),
3585                    });
3586                }
3587                self.emit_comptime_set_param_type_directive(param_name, type_annotation, *span)?;
3588            }
3589            Statement::SetParamValue {
3590                param_name,
3591                expression,
3592                span,
3593            } => {
3594                if !self.comptime_mode {
3595                    return Err(ShapeError::SemanticError {
3596                        message: "`set param` is only valid inside `comptime { }` context"
3597                            .to_string(),
3598                        location: Some(self.span_to_source_location(*span)),
3599                    });
3600                }
3601                self.emit_comptime_set_param_value_directive(param_name, expression, *span)?;
3602            }
3603            Statement::SetReturnType {
3604                type_annotation,
3605                span,
3606            } => {
3607                if !self.comptime_mode {
3608                    return Err(ShapeError::SemanticError {
3609                        message: "`set return` is only valid inside `comptime { }` context"
3610                            .to_string(),
3611                        location: Some(self.span_to_source_location(*span)),
3612                    });
3613                }
3614                self.emit_comptime_set_return_type_directive(type_annotation, *span)?;
3615            }
3616            Statement::SetReturnExpr { expression, span } => {
3617                if !self.comptime_mode {
3618                    return Err(ShapeError::SemanticError {
3619                        message: "`set return` is only valid inside `comptime { }` context"
3620                            .to_string(),
3621                        location: Some(self.span_to_source_location(*span)),
3622                    });
3623                }
3624                self.emit_comptime_set_return_expr_directive(expression, *span)?;
3625            }
3626            Statement::ReplaceBody { body, span } => {
3627                if !self.comptime_mode {
3628                    return Err(ShapeError::SemanticError {
3629                        message: "`replace body` is only valid inside `comptime { }` context"
3630                            .to_string(),
3631                        location: Some(self.span_to_source_location(*span)),
3632                    });
3633                }
3634                self.emit_comptime_replace_body_directive(body, *span)?;
3635            }
3636            Statement::ReplaceBodyExpr { expression, span } => {
3637                if !self.comptime_mode {
3638                    return Err(ShapeError::SemanticError {
3639                        message: "`replace body` is only valid inside `comptime { }` context"
3640                            .to_string(),
3641                        location: Some(self.span_to_source_location(*span)),
3642                    });
3643                }
3644                self.emit_comptime_replace_body_expr_directive(expression, *span)?;
3645            }
3646            Statement::ReplaceModuleExpr { expression, span } => {
3647                if !self.comptime_mode {
3648                    return Err(ShapeError::SemanticError {
3649                        message: "`replace module` is only valid inside `comptime { }` context"
3650                            .to_string(),
3651                        location: Some(self.span_to_source_location(*span)),
3652                    });
3653                }
3654                self.emit_comptime_replace_module_expr_directive(expression, *span)?;
3655            }
3656        }
3657        Ok(())
3658    }
3659}
3660
3661#[cfg(test)]
3662mod tests {
3663    use crate::compiler::BytecodeCompiler;
3664    use crate::executor::{VMConfig, VirtualMachine};
3665    use shape_ast::parser::parse_program;
3666
3667    #[test]
3668    fn test_module_decl_function_resolves_module_const() {
3669        let code = r#"
3670            mod math {
3671                const BASE = 21
3672                fn twice() {
3673                    BASE * 2
3674                }
3675            }
3676            math.twice()
3677        "#;
3678
3679        let program = parse_program(code).expect("Failed to parse");
3680        let bytecode = BytecodeCompiler::new()
3681            .compile(&program)
3682            .expect("Failed to compile");
3683
3684        let mut vm = VirtualMachine::new(VMConfig::default());
3685        vm.load_program(bytecode);
3686        vm.populate_module_objects();
3687        let result = vm.execute(None).expect("Failed to execute");
3688        assert_eq!(
3689            result
3690                .as_number_coerce()
3691                .expect("module call should return number"),
3692            42.0
3693        );
3694    }
3695
3696    #[test]
3697    fn test_module_annotation_can_replace_module_items() {
3698        let code = r#"
3699            annotation synth_module() {
3700                targets: [module]
3701                comptime post(target, ctx) {
3702                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
3703                }
3704            }
3705
3706            @synth_module()
3707            mod demo {}
3708
3709            demo.plus_two()
3710        "#;
3711
3712        let program = parse_program(code).expect("Failed to parse");
3713        let bytecode = BytecodeCompiler::new()
3714            .compile(&program)
3715            .expect("Failed to compile");
3716
3717        let mut vm = VirtualMachine::new(VMConfig::default());
3718        vm.load_program(bytecode);
3719        vm.populate_module_objects();
3720        let result = vm.execute(None).expect("Failed to execute");
3721        assert_eq!(
3722            result
3723                .as_number_coerce()
3724                .expect("module call should return number"),
3725            42.0
3726        );
3727    }
3728
3729    #[test]
3730    fn test_module_inline_comptime_can_replace_module_items() {
3731        let code = r#"
3732            mod demo {
3733                comptime {
3734                    replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
3735                }
3736            }
3737
3738            demo.plus_two()
3739        "#;
3740
3741        let program = parse_program(code).expect("Failed to parse");
3742        let bytecode = BytecodeCompiler::new()
3743            .compile(&program)
3744            .expect("Failed to compile");
3745
3746        let mut vm = VirtualMachine::new(VMConfig::default());
3747        vm.load_program(bytecode);
3748        vm.populate_module_objects();
3749        let result = vm.execute(None).expect("Failed to execute");
3750        assert_eq!(
3751            result
3752                .as_number_coerce()
3753                .expect("module call should return number"),
3754            42.0
3755        );
3756    }
3757
3758    #[test]
3759    fn test_module_inline_comptime_can_use_module_local_comptime_helper() {
3760        let code = r#"
3761            mod demo {
3762                comptime fn synth() {
3763                    "const ANSWER = 40; fn plus_two() { ANSWER + 2 }"
3764                }
3765
3766                comptime {
3767                    replace module (synth())
3768                }
3769            }
3770
3771            demo.plus_two()
3772        "#;
3773
3774        let program = parse_program(code).expect("Failed to parse");
3775        let bytecode = BytecodeCompiler::new()
3776            .compile(&program)
3777            .expect("Failed to compile");
3778
3779        let mut vm = VirtualMachine::new(VMConfig::default());
3780        vm.load_program(bytecode);
3781        vm.populate_module_objects();
3782        let result = vm.execute(None).expect("Failed to execute");
3783        assert_eq!(
3784            result
3785                .as_number_coerce()
3786                .expect("module call should return number"),
3787            42.0
3788        );
3789    }
3790
3791    #[test]
3792    fn test_type_annotated_variable_no_wrapping() {
3793        // BUG-1/BUG-2 fix: variable declarations must NOT emit WrapTypeAnnotation
3794        // (the wrapper broke arithmetic and comparisons)
3795        let code = r#"
3796            type Currency = Number
3797            let x: Currency = 123
3798        "#;
3799        let program = parse_program(code).expect("Failed to parse");
3800        let bytecode = BytecodeCompiler::new()
3801            .compile(&program)
3802            .expect("Failed to compile");
3803
3804        // WrapTypeAnnotation should NOT be emitted for variable declarations
3805        let has_wrap_instruction = bytecode
3806            .instructions
3807            .iter()
3808            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
3809        assert!(
3810            !has_wrap_instruction,
3811            "Should NOT emit WrapTypeAnnotation for type-annotated variable"
3812        );
3813    }
3814
3815    #[test]
3816    fn test_untyped_variable_no_wrapping() {
3817        // Variables without type annotations should NOT emit WrapTypeAnnotation
3818        let code = r#"
3819            let x = 123
3820        "#;
3821        let program = parse_program(code).expect("Failed to parse");
3822        let bytecode = BytecodeCompiler::new()
3823            .compile(&program)
3824            .expect("Failed to compile");
3825
3826        // Check that WrapTypeAnnotation instruction was NOT emitted
3827        let has_wrap_instruction = bytecode
3828            .instructions
3829            .iter()
3830            .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
3831        assert!(
3832            !has_wrap_instruction,
3833            "Should NOT emit WrapTypeAnnotation for untyped variable"
3834        );
3835    }
3836
3837    // ===== Phase 2: Extend Block Compilation Tests =====
3838
3839    #[test]
3840    fn test_extend_block_compiles() {
3841        let code = r#"
3842            extend Number {
3843                method double() {
3844                    return self * 2
3845                }
3846            }
3847        "#;
3848        let program = parse_program(code).expect("Failed to parse extend block");
3849        let bytecode = BytecodeCompiler::new().compile(&program);
3850        assert!(
3851            bytecode.is_ok(),
3852            "Extend block should compile: {:?}",
3853            bytecode.err()
3854        );
3855
3856        // Verify a function named "Number.double" was generated (qualified extend name).
3857        let bytecode = bytecode.unwrap();
3858        let has_double = bytecode.functions.iter().any(|f| f.name == "Number.double");
3859        assert!(
3860            has_double,
3861            "Should generate 'Number.double' function from extend block"
3862        );
3863    }
3864
3865    #[test]
3866    fn test_extend_method_has_self_param() {
3867        let code = r#"
3868            extend Number {
3869                method add(n) {
3870                    return self + n
3871                }
3872            }
3873        "#;
3874        let program = parse_program(code).expect("Failed to parse");
3875        let bytecode = BytecodeCompiler::new()
3876            .compile(&program)
3877            .expect("Failed to compile");
3878
3879        let func = bytecode.functions.iter().find(|f| f.name == "Number.add");
3880        assert!(func.is_some(), "Should have 'Number.add' function");
3881        // The function should have 2 params: self + n
3882        assert_eq!(
3883            func.unwrap().arity,
3884            2,
3885            "add() should have arity 2 (self + n)"
3886        );
3887    }
3888
3889    #[test]
3890    fn test_extend_method_rejects_explicit_self_param() {
3891        let code = r#"
3892            extend Number {
3893                method add(self, n) {
3894                    return self + n
3895                }
3896            }
3897        "#;
3898        let program = parse_program(code).expect("Failed to parse");
3899        let err = BytecodeCompiler::new()
3900            .compile(&program)
3901            .expect_err("Compiler should reject explicit self receiver param in methods");
3902        let msg = format!("{err}");
3903        assert!(
3904            msg.contains("explicit `self` parameter"),
3905            "Expected explicit self error, got: {msg}"
3906        );
3907    }
3908
3909    // ===== Phase 3: Annotation Handler Compilation Tests =====
3910
3911    #[test]
3912    fn test_annotation_def_compiles_handlers() {
3913        let code = r#"
3914            annotation warmup(period) {
3915                before(args, ctx) {
3916                    args
3917                }
3918                after(args, result, ctx) {
3919                    result
3920                }
3921            }
3922            function test() { return 42; }
3923        "#;
3924        let program = parse_program(code).expect("Failed to parse annotation def");
3925        let bytecode = BytecodeCompiler::new().compile(&program);
3926        assert!(
3927            bytecode.is_ok(),
3928            "Annotation def should compile: {:?}",
3929            bytecode.err()
3930        );
3931
3932        let bytecode = bytecode.unwrap();
3933        // Verify CompiledAnnotation was registered
3934        assert!(
3935            bytecode.compiled_annotations.contains_key("warmup"),
3936            "Should have compiled 'warmup' annotation"
3937        );
3938
3939        let compiled = bytecode.compiled_annotations.get("warmup").unwrap();
3940        assert!(
3941            compiled.before_handler.is_some(),
3942            "Should have before handler"
3943        );
3944        assert!(
3945            compiled.after_handler.is_some(),
3946            "Should have after handler"
3947        );
3948    }
3949
3950    #[test]
3951    fn test_annotation_handler_function_names() {
3952        let code = r#"
3953            annotation my_ann(x) {
3954                before(args, ctx) {
3955                    args
3956                }
3957            }
3958            function test() { return 1; }
3959        "#;
3960        let program = parse_program(code).expect("Failed to parse");
3961        let bytecode = BytecodeCompiler::new()
3962            .compile(&program)
3963            .expect("Failed to compile");
3964
3965        // Handler should be compiled as an internal function
3966        let compiled = bytecode.compiled_annotations.get("my_ann").unwrap();
3967        let handler_id = compiled.before_handler.unwrap() as usize;
3968        assert!(
3969            handler_id < bytecode.functions.len(),
3970            "Handler function ID should be valid"
3971        );
3972
3973        let handler_fn = &bytecode.functions[handler_id];
3974        assert_eq!(
3975            handler_fn.name, "my_ann___before",
3976            "Handler function should be named my_ann___before"
3977        );
3978    }
3979
3980    // ===== Phase 4: Compile-Time Function Wrapping Tests =====
3981
3982    #[test]
3983    fn test_annotated_function_generates_wrapper() {
3984        let code = r#"
3985            annotation tracked(label) {
3986                before(args, ctx) {
3987                    args
3988                }
3989            }
3990            @tracked("my_func")
3991            function compute(x) {
3992                return x * 2
3993            }
3994            function test() { return 1; }
3995        "#;
3996        let program = parse_program(code).expect("Failed to parse");
3997        let bytecode = BytecodeCompiler::new().compile(&program);
3998        assert!(
3999            bytecode.is_ok(),
4000            "Annotated function should compile: {:?}",
4001            bytecode.err()
4002        );
4003
4004        let bytecode = bytecode.unwrap();
4005        // Should have the original function (wrapper) and the impl
4006        let has_impl = bytecode
4007            .functions
4008            .iter()
4009            .any(|f| f.name == "compute___impl");
4010        assert!(has_impl, "Should generate compute___impl function");
4011
4012        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
4013        assert!(has_wrapper, "Should keep compute as wrapper");
4014    }
4015
4016    #[test]
4017    fn test_unannotated_function_no_wrapper() {
4018        let code = r#"
4019            function plain(x) {
4020                return x + 1
4021            }
4022        "#;
4023        let program = parse_program(code).expect("Failed to parse");
4024        let bytecode = BytecodeCompiler::new()
4025            .compile(&program)
4026            .expect("Failed to compile");
4027
4028        // Should NOT have an ___impl function
4029        let has_impl = bytecode
4030            .functions
4031            .iter()
4032            .any(|f| f.name.ends_with("___impl"));
4033        assert!(
4034            !has_impl,
4035            "Non-annotated function should not generate ___impl"
4036        );
4037    }
4038
4039    // ===== Sprint 10: Annotation chaining and target validation =====
4040
4041    #[test]
4042    fn test_annotation_chaining_generates_chain() {
4043        // Two annotations on the same function should generate chained wrappers
4044        let code = r#"
4045            annotation first() {
4046                before(args, ctx) {
4047                    return args
4048                }
4049            }
4050
4051            annotation second() {
4052                before(args, ctx) {
4053                    return args
4054                }
4055            }
4056
4057            @first
4058            @second
4059            function compute(x) {
4060                return x * 2
4061            }
4062        "#;
4063        let program = parse_program(code).expect("Failed to parse");
4064        let bytecode = BytecodeCompiler::new().compile(&program);
4065        assert!(
4066            bytecode.is_ok(),
4067            "Chained annotations should compile: {:?}",
4068            bytecode.err()
4069        );
4070        let bytecode = bytecode.unwrap();
4071
4072        // Should have: compute (outermost wrapper), compute___impl (body), compute___second (intermediate)
4073        let has_impl = bytecode
4074            .functions
4075            .iter()
4076            .any(|f| f.name == "compute___impl");
4077        assert!(has_impl, "Should generate compute___impl function");
4078        let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
4079        assert!(has_wrapper, "Should keep compute as outermost wrapper");
4080        let has_intermediate = bytecode
4081            .functions
4082            .iter()
4083            .any(|f| f.name == "compute___second");
4084        assert!(
4085            has_intermediate,
4086            "Should generate compute___second intermediate wrapper"
4087        );
4088    }
4089
4090    #[test]
4091    fn test_annotation_allowed_targets_inferred() {
4092        // An annotation with before/after should have allowed_targets = [Function]
4093        let code = r#"
4094            annotation traced() {
4095                before(args, ctx) {
4096                    return args
4097                }
4098            }
4099        "#;
4100        let program = parse_program(code).expect("Failed to parse");
4101        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
4102        let ann = bytecode
4103            .compiled_annotations
4104            .get("traced")
4105            .expect("traced annotation");
4106        assert!(
4107            !ann.allowed_targets.is_empty(),
4108            "before handler should restrict targets"
4109        );
4110        assert!(
4111            ann.allowed_targets
4112                .contains(&shape_ast::ast::functions::AnnotationTargetKind::Function),
4113            "before handler should allow Function target"
4114        );
4115    }
4116
4117    #[test]
4118    fn test_annotation_allowed_targets_explicit_override() {
4119        // Explicit `targets: [...]` should override inferred defaults.
4120        let code = r#"
4121            annotation traced() {
4122                targets: [type]
4123                before(args, ctx) {
4124                    return args
4125                }
4126            }
4127        "#;
4128        let program = parse_program(code).expect("Failed to parse");
4129        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
4130        let ann = bytecode
4131            .compiled_annotations
4132            .get("traced")
4133            .expect("traced annotation");
4134        assert_eq!(
4135            ann.allowed_targets,
4136            vec![shape_ast::ast::functions::AnnotationTargetKind::Type]
4137        );
4138    }
4139
4140    #[test]
4141    fn test_metadata_only_annotation_defaults_to_definition_targets() {
4142        // An annotation with only metadata handler should default to definition targets.
4143        let code = r#"
4144            annotation info() {
4145                metadata() {
4146                    return { version: 1 }
4147                }
4148            }
4149        "#;
4150        let program = parse_program(code).expect("Failed to parse");
4151        let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
4152        let ann = bytecode
4153            .compiled_annotations
4154            .get("info")
4155            .expect("info annotation");
4156        assert_eq!(
4157            ann.allowed_targets,
4158            vec![
4159                shape_ast::ast::functions::AnnotationTargetKind::Function,
4160                shape_ast::ast::functions::AnnotationTargetKind::Type,
4161                shape_ast::ast::functions::AnnotationTargetKind::Module
4162            ],
4163            "metadata-only annotation should default to definition targets"
4164        );
4165    }
4166
4167    #[test]
4168    fn test_definition_lifecycle_targets_reject_expression_target() {
4169        let code = r#"
4170            annotation info() {
4171                targets: [expression]
4172                metadata(target, ctx) {
4173                    target.name
4174                }
4175            }
4176        "#;
4177        let program = parse_program(code).expect("Failed to parse");
4178        let err = BytecodeCompiler::new()
4179            .compile(&program)
4180            .expect_err("metadata hooks on expression targets should fail");
4181        let msg = format!("{}", err);
4182        assert!(
4183            msg.contains("not a definition target"),
4184            "expected definition-target restriction error, got: {}",
4185            msg
4186        );
4187    }
4188
4189    #[test]
4190    fn test_annotation_target_validation_on_struct_type() {
4191        // Function-only annotation applied to a type should fail.
4192        let code = r#"
4193            annotation traced() {
4194                before(args, ctx) { return args }
4195            }
4196
4197            @traced()
4198            type Point { x: int }
4199        "#;
4200        let program = parse_program(code).expect("Failed to parse");
4201        let err = BytecodeCompiler::new()
4202            .compile(&program)
4203            .expect_err("function-only annotation on type should fail");
4204        let msg = format!("{}", err);
4205        assert!(
4206            msg.contains("cannot be applied to a type"),
4207            "expected type target validation error, got: {}",
4208            msg
4209        );
4210    }
4211
4212    #[test]
4213    fn test_type_c_emits_native_layout_metadata() {
4214        let bytecode = compiles_to(
4215            r#"
4216            type C Pair32 {
4217                left: i32,
4218                right: i32,
4219            }
4220            "#,
4221        );
4222
4223        assert_eq!(bytecode.native_struct_layouts.len(), 1);
4224        let layout = &bytecode.native_struct_layouts[0];
4225        assert_eq!(layout.name, "Pair32");
4226        assert_eq!(layout.abi, "C");
4227        assert_eq!(layout.size, 8);
4228        assert_eq!(layout.align, 4);
4229        assert_eq!(layout.fields.len(), 2);
4230        assert_eq!(layout.fields[0].name, "left");
4231        assert_eq!(layout.fields[0].offset, 0);
4232        assert_eq!(layout.fields[0].size, 4);
4233        assert_eq!(layout.fields[1].name, "right");
4234        assert_eq!(layout.fields[1].offset, 4);
4235        assert_eq!(layout.fields[1].size, 4);
4236    }
4237
4238    #[test]
4239    fn test_type_c_auto_generates_into_from_traits() {
4240        let bytecode = compiles_to(
4241            r#"
4242            type C QuoteC {
4243                bid: i64,
4244                ask: i64,
4245            }
4246
4247            type Quote {
4248                bid: i64,
4249                ask: i64,
4250            }
4251            "#,
4252        );
4253
4254        let c_to_shape =
4255            bytecode.lookup_trait_method_symbol("Into", "QuoteC", Some("Quote"), "into");
4256        let shape_to_c =
4257            bytecode.lookup_trait_method_symbol("Into", "Quote", Some("QuoteC"), "into");
4258        let from_c = bytecode.lookup_trait_method_symbol("From", "Quote", Some("QuoteC"), "from");
4259        let from_shape =
4260            bytecode.lookup_trait_method_symbol("From", "QuoteC", Some("Quote"), "from");
4261
4262        assert!(c_to_shape.is_some(), "expected Into<Quote> for QuoteC");
4263        assert!(shape_to_c.is_some(), "expected Into<QuoteC> for Quote");
4264        assert!(from_c.is_some(), "expected From<QuoteC> for Quote");
4265        assert!(from_shape.is_some(), "expected From<Quote> for QuoteC");
4266    }
4267
4268    #[test]
4269    fn test_type_c_auto_conversion_function_compiles() {
4270        let _ = compiles_to(
4271            r#"
4272            type Quote {
4273                bid: i64,
4274                ask: i64,
4275            }
4276
4277            type C QuoteC {
4278                bid: i64,
4279                ask: i64,
4280            }
4281
4282            fn spread(q: QuoteC) -> i64 {
4283                let q_shape = __auto_native_from_QuoteC_to_Quote(q);
4284                q_shape.ask - q_shape.bid
4285            }
4286
4287            spread(QuoteC { bid: 10, ask: 13 })
4288            "#,
4289        );
4290    }
4291
4292    #[test]
4293    fn test_type_c_auto_conversion_rejects_incompatible_fields() {
4294        let program = parse_program(
4295            r#"
4296            type Price {
4297                value: i64,
4298            }
4299
4300            type C PriceC {
4301                value: u64,
4302            }
4303            "#,
4304        )
4305        .expect("parse failed");
4306        let err = BytecodeCompiler::new()
4307            .compile(&program)
4308            .expect_err("incompatible type C conversion pair should fail");
4309        let msg = format!("{}", err);
4310        assert!(
4311            msg.contains("field type mismatch for auto conversion"),
4312            "expected type mismatch error, got: {}",
4313            msg
4314        );
4315    }
4316
4317    // ===== Task 1: Meta on traits =====
4318
4319    // ===== Drop Track: Sprint 2 Tests =====
4320
4321    fn compiles_to(code: &str) -> crate::bytecode::BytecodeProgram {
4322        let program = parse_program(code).expect("parse failed");
4323        let compiler = BytecodeCompiler::new();
4324        compiler.compile(&program).expect("compile failed")
4325    }
4326
4327    // --- Permission checking tests ---
4328
4329    #[test]
4330    fn test_extract_module_name() {
4331        assert_eq!(BytecodeCompiler::extract_module_name("file"), "file");
4332        assert_eq!(BytecodeCompiler::extract_module_name("std::file"), "file");
4333        assert_eq!(BytecodeCompiler::extract_module_name("std/io"), "io");
4334        assert_eq!(BytecodeCompiler::extract_module_name("a::b::c"), "c");
4335        assert_eq!(BytecodeCompiler::extract_module_name(""), "");
4336    }
4337
4338    #[test]
4339    fn test_permission_check_allows_pure_module_imports() {
4340        // json is a pure module — should compile even with empty permissions
4341        let code = "from json use { parse }";
4342        let program = parse_program(code).expect("parse failed");
4343        let mut compiler = BytecodeCompiler::new();
4344        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4345        // Should not fail — json requires no permissions
4346        let _result = compiler.compile(&program);
4347    }
4348
4349    #[test]
4350    fn test_permission_check_blocks_file_import_under_pure() {
4351        let code = "from file use { read_text }";
4352        let program = parse_program(code).expect("parse failed");
4353        let mut compiler = BytecodeCompiler::new();
4354        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4355        let result = compiler.compile(&program);
4356        assert!(
4357            result.is_err(),
4358            "Expected permission error for file::read_text under pure"
4359        );
4360        let err_msg = format!("{}", result.unwrap_err());
4361        assert!(
4362            err_msg.contains("Permission denied"),
4363            "Error should mention permission denied: {err_msg}"
4364        );
4365        assert!(
4366            err_msg.contains("fs.read"),
4367            "Error should mention fs.read: {err_msg}"
4368        );
4369    }
4370
4371    #[test]
4372    fn test_permission_check_allows_file_import_with_fs_read() {
4373        let code = "from file use { read_text }";
4374        let program = parse_program(code).expect("parse failed");
4375        let mut compiler = BytecodeCompiler::new();
4376        let pset = shape_abi_v1::PermissionSet::from_iter([shape_abi_v1::Permission::FsRead]);
4377        compiler.set_permission_set(Some(pset));
4378        // Should not fail
4379        let _result = compiler.compile(&program);
4380    }
4381
4382    #[test]
4383    fn test_permission_check_no_permission_set_allows_everything() {
4384        // When permission_set is None (default), no checking is done
4385        let code = "from file use { read_text }";
4386        let program = parse_program(code).expect("parse failed");
4387        let compiler = BytecodeCompiler::new();
4388        // permission_set is None by default — should compile fine
4389        let _result = compiler.compile(&program);
4390    }
4391
4392    #[test]
4393    fn test_permission_check_namespace_import_blocked() {
4394        let code = "use http";
4395        let program = parse_program(code).expect("parse failed");
4396        let mut compiler = BytecodeCompiler::new();
4397        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
4398        let result = compiler.compile(&program);
4399        assert!(
4400            result.is_err(),
4401            "Expected permission error for `use http` under pure"
4402        );
4403        let err_msg = format!("{}", result.unwrap_err());
4404        assert!(
4405            err_msg.contains("Permission denied"),
4406            "Error should mention permission denied: {err_msg}"
4407        );
4408    }
4409
4410    #[test]
4411    fn test_permission_check_namespace_import_allowed() {
4412        let code = "use http";
4413        let program = parse_program(code).expect("parse failed");
4414        let mut compiler = BytecodeCompiler::new();
4415        compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::full()));
4416        // Should not fail
4417        let _result = compiler.compile(&program);
4418    }
4419}