1use crate::bytecode::{Function, Instruction, OpCode, Operand};
4use shape_ast::ast::{
5 AnnotationTargetKind, DestructurePattern, EnumDef, EnumMemberKind, ExportItem, Expr,
6 FunctionDef, FunctionParameter, Item, Literal, ModuleDecl, ObjectEntry, Query, Span, Spanned,
7 Statement, TypeAnnotation, VarKind,
8};
9use shape_ast::error::{Result, ShapeError};
10use shape_runtime::type_schema::{EnumVariantInfo, FieldType};
11
12use super::{
13 BytecodeCompiler, DropKind, ImportedAnnotationSymbol, ImportedSymbol, ModuleBuiltinFunction,
14 ParamPassMode, StructGenericInfo,
15};
16
17#[derive(Debug, Clone)]
18struct NativeFieldLayoutSpec {
19 c_type: String,
20 size: u64,
21 align: u64,
22}
23
24impl BytecodeCompiler {
25 fn register_builtin_function_decl(
26 &mut self,
27 def: &shape_ast::ast::BuiltinFunctionDecl,
28 ) -> Result<()> {
29 let export_name = def
30 .name
31 .rsplit("::")
32 .next()
33 .unwrap_or(def.name.as_str())
34 .to_string();
35 let source_module_path = if let Some((owner_module, _)) = def.name.rsplit_once("::") {
36 self.resolve_canonical_module_path(owner_module)
37 .unwrap_or_else(|| owner_module.to_string())
38 } else {
39 return Ok(());
40 };
41
42 self.module_builtin_functions.insert(
43 def.name.clone(),
44 ModuleBuiltinFunction {
45 export_name,
46 source_module_path,
47 },
48 );
49 Ok(())
50 }
51
52 fn emit_comptime_internal_call(
53 &mut self,
54 method: &str,
55 args: Vec<Expr>,
56 span: Span,
57 ) -> Result<()> {
58 let call = Expr::QualifiedFunctionCall {
59 namespace: "__comptime__".to_string(),
60 function: method.to_string(),
61 args,
62 named_args: Vec::new(),
63 span,
64 };
65 let prev = self.allow_internal_comptime_namespace;
66 self.allow_internal_comptime_namespace = true;
67 let compile_result = self.compile_expr(&call);
68 self.allow_internal_comptime_namespace = prev;
69 compile_result?;
70 self.emit(Instruction::simple(OpCode::Pop));
71 Ok(())
72 }
73
74 fn serialize_directive_payload(
79 &self,
80 value: &(impl serde::Serialize + ?Sized),
81 directive_label: &str,
82 span: Span,
83 ) -> Result<String> {
84 serde_json::to_string(value).map_err(|e| ShapeError::RuntimeError {
85 message: format!("Failed to serialize comptime {} directive: {}", directive_label, e),
86 location: Some(self.span_to_source_location(span)),
87 })
88 }
89
90 fn require_comptime_mode(&self, directive_name: &str, span: Span) -> Result<()> {
92 if !self.comptime_mode {
93 return Err(ShapeError::SemanticError {
94 message: format!("`{}` is only valid inside `comptime {{}}` context", directive_name),
95 location: Some(self.span_to_source_location(span)),
96 });
97 }
98 Ok(())
99 }
100
101 fn emit_comptime_extend_directive(
102 &mut self,
103 extend: &shape_ast::ast::ExtendStatement,
104 span: Span,
105 ) -> Result<()> {
106 let payload = self.serialize_directive_payload(extend, "extend", span)?;
107 self.emit_comptime_internal_call(
108 "__emit_extend",
109 vec![Expr::Literal(Literal::String(payload), span)],
110 span,
111 )
112 }
113
114 fn emit_comptime_remove_directive(&mut self, span: Span) -> Result<()> {
115 self.emit_comptime_internal_call("__emit_remove", Vec::new(), span)
116 }
117
118 fn emit_comptime_set_param_value_directive(
119 &mut self,
120 param_name: &str,
121 expression: &Expr,
122 span: Span,
123 ) -> Result<()> {
124 self.emit_comptime_internal_call(
125 "__emit_set_param_value",
126 vec![
127 Expr::Literal(Literal::String(param_name.to_string()), span),
128 expression.clone(),
129 ],
130 span,
131 )
132 }
133
134 fn emit_comptime_set_param_type_directive(
135 &mut self,
136 param_name: &str,
137 type_annotation: &TypeAnnotation,
138 span: Span,
139 ) -> Result<()> {
140 let payload = self.serialize_directive_payload(type_annotation, "param type", span)?;
141 self.emit_comptime_internal_call(
142 "__emit_set_param_type",
143 vec![
144 Expr::Literal(Literal::String(param_name.to_string()), span),
145 Expr::Literal(Literal::String(payload), span),
146 ],
147 span,
148 )
149 }
150
151 fn emit_comptime_set_return_type_directive(
152 &mut self,
153 type_annotation: &TypeAnnotation,
154 span: Span,
155 ) -> Result<()> {
156 let payload = self.serialize_directive_payload(type_annotation, "return type", span)?;
157 self.emit_comptime_internal_call(
158 "__emit_set_return_type",
159 vec![Expr::Literal(Literal::String(payload), span)],
160 span,
161 )
162 }
163
164 fn emit_comptime_set_return_expr_directive(
165 &mut self,
166 expression: &Expr,
167 span: Span,
168 ) -> Result<()> {
169 self.emit_comptime_internal_call("__emit_set_return_type", vec![expression.clone()], span)
170 }
171
172 fn emit_comptime_replace_body_directive(
173 &mut self,
174 body: &[Statement],
175 span: Span,
176 ) -> Result<()> {
177 let payload = self.serialize_directive_payload(body, "replace-body", span)?;
178 self.emit_comptime_internal_call(
179 "__emit_replace_body",
180 vec![Expr::Literal(Literal::String(payload), span)],
181 span,
182 )
183 }
184
185 fn emit_comptime_replace_body_expr_directive(
186 &mut self,
187 expression: &Expr,
188 span: Span,
189 ) -> Result<()> {
190 self.emit_comptime_internal_call("__emit_replace_body", vec![expression.clone()], span)
191 }
192
193 fn emit_comptime_replace_module_expr_directive(
194 &mut self,
195 expression: &Expr,
196 span: Span,
197 ) -> Result<()> {
198 self.emit_comptime_internal_call("__emit_replace_module", vec![expression.clone()], span)
199 }
200
201 pub(super) fn register_item_functions(&mut self, item: &Item) -> Result<()> {
202 match item {
203 Item::Function(func_def, _) => self.register_function(func_def),
204 Item::BuiltinFunctionDecl(def, _) => self.register_builtin_function_decl(def),
205 Item::Module(module_def, _) => {
206 let module_path = self.current_module_path_for(module_def.name.as_str());
207 self.module_scope_stack.push(module_path.clone());
208 let register_result = (|| -> Result<()> {
209 for inner in &module_def.items {
210 let qualified = self.qualify_module_item(inner, &module_path)?;
211 self.register_item_functions(&qualified)?;
212 }
213 Ok(())
214 })();
215 self.module_scope_stack.pop();
216 register_result
217 }
218 Item::Trait(trait_def, _) => {
219 self.known_traits.insert(trait_def.name.clone());
220 self.trait_defs
221 .insert(trait_def.name.clone(), trait_def.clone());
222 self.type_inference.env.define_trait(trait_def);
224 Ok(())
225 }
226 Item::ForeignFunction(def, _) => {
227 let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
230 self.function_arity_bounds
231 .insert(def.name.clone(), (caller_visible, caller_visible));
232 self.function_const_params
233 .insert(def.name.clone(), Vec::new());
234 let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
235 let (vis_ref_params, vis_ref_mutates) = if def.params.iter().any(|p| p.is_out) {
236 let mut vrp = Vec::new();
237 let mut vrm = Vec::new();
238 for (i, p) in def.params.iter().enumerate() {
239 if !p.is_out {
240 vrp.push(ref_params.get(i).copied().unwrap_or(false));
241 vrm.push(ref_mutates.get(i).copied().unwrap_or(false));
242 }
243 }
244 (vrp, vrm)
245 } else {
246 (ref_params, ref_mutates)
247 };
248
249 let func = crate::bytecode::Function {
250 name: def.name.clone(),
251 arity: caller_visible as u16,
252 param_names: def
253 .params
254 .iter()
255 .filter(|p| !p.is_out)
256 .flat_map(|p| p.get_identifiers())
257 .collect(),
258 locals_count: 0,
259 entry_point: 0,
260 body_length: 0,
261 is_closure: false,
262 captures_count: 0,
263 is_async: def.is_async,
264 ref_params: vis_ref_params,
265 ref_mutates: vis_ref_mutates,
266 mutable_captures: Vec::new(),
267 frame_descriptor: None,
268 osr_entry_points: Vec::new(),
269 mir_data: None,
270 };
271 self.program.functions.push(func);
272
273 self.foreign_function_defs
276 .insert(def.name.clone(), def.clone());
277
278 Ok(())
279 }
280 Item::Export(export, _) => match &export.item {
281 ExportItem::Function(func_def) => self.register_function(func_def),
282 ExportItem::BuiltinFunction(def) => self.register_builtin_function_decl(def),
283 ExportItem::Trait(trait_def) => {
284 self.known_traits.insert(trait_def.name.clone());
285 self.trait_defs
286 .insert(trait_def.name.clone(), trait_def.clone());
287 self.type_inference.env.define_trait(trait_def);
289 Ok(())
290 }
291 ExportItem::Annotation(annotation_def) => {
292 self.compile_annotation_def(annotation_def)
293 }
294 ExportItem::ForeignFunction(def) => {
295 let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
297 self.function_arity_bounds
298 .insert(def.name.clone(), (caller_visible, caller_visible));
299 self.function_const_params
300 .insert(def.name.clone(), Vec::new());
301 let (ref_params, ref_mutates) = Self::native_param_reference_contract(def);
302 let (vis_ref_params, vis_ref_mutates) = if def.params.iter().any(|p| p.is_out) {
303 let mut vrp = Vec::new();
304 let mut vrm = Vec::new();
305 for (i, p) in def.params.iter().enumerate() {
306 if !p.is_out {
307 vrp.push(ref_params.get(i).copied().unwrap_or(false));
308 vrm.push(ref_mutates.get(i).copied().unwrap_or(false));
309 }
310 }
311 (vrp, vrm)
312 } else {
313 (ref_params, ref_mutates)
314 };
315
316 let func = crate::bytecode::Function {
317 name: def.name.clone(),
318 arity: caller_visible as u16,
319 param_names: def
320 .params
321 .iter()
322 .filter(|p| !p.is_out)
323 .flat_map(|p| p.get_identifiers())
324 .collect(),
325 locals_count: 0,
326 entry_point: 0,
327 body_length: 0,
328 is_closure: false,
329 captures_count: 0,
330 is_async: def.is_async,
331 ref_params: vis_ref_params,
332 ref_mutates: vis_ref_mutates,
333 mutable_captures: Vec::new(),
334 frame_descriptor: None,
335 osr_entry_points: Vec::new(),
336 mir_data: None,
337 };
338 self.program.functions.push(func);
339
340 self.foreign_function_defs
341 .insert(def.name.clone(), def.clone());
342
343 Ok(())
344 }
345 _ => Ok(()),
346 },
347 Item::Extend(extend, _) => {
348 for method in &extend.methods {
350 let func_def = self.desugar_extend_method(method, &extend.type_name)?;
351 self.register_function(&func_def)?;
352 }
353 Ok(())
354 }
355 Item::Impl(impl_block, _) => {
356 if impl_block.is_comptime {
369 self.comptime_impl_blocks.push(impl_block.clone());
370 return Ok(());
371 }
372 let raw_trait_name = match &impl_block.trait_name {
377 shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
378 shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
379 };
380 let type_name = match &impl_block.target_type {
381 shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
382 shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
383 };
384 let impl_name = impl_block.impl_name.as_deref();
385
386 let (canonical_trait, trait_basename) = self.resolve_trait_name(raw_trait_name);
388
389 if trait_basename == "From" || trait_basename == "TryFrom" {
393 return self.compile_from_impl(impl_block, &trait_basename, type_name);
394 }
395
396 let overridden: std::collections::HashSet<&str> =
398 impl_block.methods.iter().map(|m| m.name.as_str()).collect();
399
400 for method in &impl_block.methods {
401 let func_def = self.desugar_impl_method(
402 method,
403 &trait_basename,
404 type_name,
405 impl_name,
406 &impl_block.target_type,
407 )?;
408 self.program.register_trait_method_symbol(
409 &trait_basename,
410 type_name,
411 impl_name,
412 &method.name,
413 &func_def.name,
414 );
415 self.register_function(&func_def)?;
416
417 if trait_basename == "Drop" && method.name == "drop" {
419 let type_key = type_name.to_string();
420 let existing = self.drop_type_info.get(&type_key).copied();
421 let new_kind = if method.is_async {
422 match existing {
423 Some(DropKind::SyncOnly) | Some(DropKind::Both) => DropKind::Both,
424 _ => DropKind::AsyncOnly,
425 }
426 } else {
427 match existing {
428 Some(DropKind::AsyncOnly) | Some(DropKind::Both) => DropKind::Both,
429 _ => DropKind::SyncOnly,
430 }
431 };
432 self.drop_type_info.insert(type_key, new_kind);
433 }
434 }
435
436 if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
438 for member in &trait_def.members {
439 if let shape_ast::ast::types::TraitMember::Default(default_method) = member
440 {
441 if !overridden.contains(default_method.name.as_str()) {
442 let func_def = self.desugar_impl_method(
443 default_method,
444 &trait_basename,
445 type_name,
446 impl_name,
447 &impl_block.target_type,
448 )?;
449 self.program.register_trait_method_symbol(
450 &trait_basename,
451 type_name,
452 impl_name,
453 &default_method.name,
454 &func_def.name,
455 );
456 self.register_function(&func_def)?;
457 }
458 }
459 }
460 }
461
462 self.build_and_register_vtable(
490 &trait_basename,
491 type_name,
492 impl_block,
493 )?;
494
495 let all_method_names: Vec<String> =
498 impl_block.methods.iter().map(|m| m.name.clone()).collect();
499 if let Some(selector) = impl_name {
500 let _ = self.type_inference.env.register_trait_impl_named(
501 &trait_basename,
502 type_name,
503 selector,
504 all_method_names,
505 );
506 } else {
507 let _ = self.type_inference.env.register_trait_impl(
508 &trait_basename,
509 type_name,
510 all_method_names,
511 );
512 }
513
514 if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
518 for super_ann in &trait_def.super_traits {
519 let super_name = match super_ann {
520 TypeAnnotation::Basic(name) => name.clone(),
521 TypeAnnotation::Reference(name) => name.to_string(),
522 TypeAnnotation::Generic { name, .. } => name.to_string(),
523 _ => continue,
524 };
525 let (_canonical_super, super_basename) = self.resolve_trait_name(&super_name);
526 if !self
527 .type_inference
528 .env
529 .type_implements_trait(type_name, &super_basename)
530 {
531 return Err(ShapeError::SemanticError {
532 message: format!(
533 "impl {} for {} requires supertrait '{}' to be implemented first",
534 trait_basename, type_name, super_basename
535 ),
536 location: None,
537 });
538 }
539 }
540 }
541
542 Ok(())
543 }
544 _ => Ok(()),
545 }
546 }
547
548 pub(super) fn predeclare_item_struct_schemas(&mut self, item: &Item) {
560 match item {
561 Item::StructType(struct_def, _) => {
562 self.predeclare_struct_schema(struct_def);
563 }
564 Item::Export(export, _) => {
565 if let ExportItem::Struct(struct_def) = &export.item {
566 self.predeclare_struct_schema(struct_def);
567 }
568 }
569 Item::Module(module_def, _) => {
570 let module_path = self.current_module_path_for(module_def.name.as_str());
571 self.module_scope_stack.push(module_path.clone());
572 for inner in &module_def.items {
573 if let Ok(qualified) = self.qualify_module_item(inner, &module_path) {
574 self.predeclare_item_struct_schemas(&qualified);
575 }
576 }
577 self.module_scope_stack.pop();
578 }
579 _ => {}
580 }
581 }
582
583 pub(super) fn register_function(&mut self, func_def: &FunctionDef) -> Result<()> {
585 if !func_def.name.contains("::") && !func_def.name.contains('.') {
589 if let Some(existing) = self
590 .program
591 .functions
592 .iter()
593 .find(|f| f.name == func_def.name)
594 {
595 if existing.arity == func_def.params.len() as u16 {
600 return Ok(());
601 }
602 return Err(ShapeError::SemanticError {
603 message: format!(
604 "Duplicate function definition: '{}' is already defined",
605 func_def.name
606 ),
607 location: Some(self.span_to_source_location(func_def.name_span)),
608 });
609 }
610 }
611
612 self.function_defs
613 .insert(func_def.name.clone(), func_def.clone());
614
615 let total_params = func_def.params.len();
616 let mut required_params = total_params;
617 let mut saw_default = false;
618 let mut const_params = Vec::new();
619 for (idx, param) in func_def.params.iter().enumerate() {
620 if param.is_const {
621 const_params.push(idx);
622 }
623 if param.default_value.is_some() {
624 if !saw_default {
625 required_params = idx;
626 saw_default = true;
627 }
628 } else if saw_default {
629 return Err(ShapeError::SemanticError {
630 message: "Required parameter cannot follow a parameter with a default value"
631 .to_string(),
632 location: Some(self.span_to_source_location(param.span())),
633 });
634 }
635 }
636
637 self.function_arity_bounds
638 .insert(func_def.name.clone(), (required_params, total_params));
639 self.function_const_params
640 .insert(func_def.name.clone(), const_params);
641
642 let inferred_param_modes = self
643 .inferred_param_pass_modes
644 .get(&func_def.name)
645 .cloned()
646 .unwrap_or_default();
647 let mut ref_params: Vec<bool> = Vec::with_capacity(func_def.params.len());
648 let mut ref_mutates: Vec<bool> = Vec::with_capacity(func_def.params.len());
649 for (idx, param) in func_def.params.iter().enumerate() {
650 let fallback = if param.is_reference {
651 ParamPassMode::ByRefShared
652 } else {
653 ParamPassMode::ByValue
654 };
655 let mode = inferred_param_modes.get(idx).copied().unwrap_or(fallback);
656 ref_params.push(mode.is_reference());
657 ref_mutates.push(mode.is_exclusive());
658 }
659
660 let func = Function {
661 name: func_def.name.clone(),
662 arity: func_def.params.len() as u16,
663 param_names: func_def
664 .params
665 .iter()
666 .flat_map(|p| p.get_identifiers())
667 .collect(),
668 locals_count: 0, entry_point: 0, body_length: 0, is_closure: false,
672 captures_count: 0,
673 is_async: func_def.is_async,
674 ref_params,
675 ref_mutates,
676 mutable_captures: Vec::new(),
677 frame_descriptor: None,
678 osr_entry_points: Vec::new(),
679 mir_data: None,
680 };
681
682 self.program.functions.push(func);
683
684 if let Some(ref return_type) = func_def.return_type {
689 if let Some(type_name) = return_type.as_simple_name() {
690 self.type_tracker
691 .register_function_return_type(&func_def.name, type_name);
692 }
693 }
694
695 Ok(())
696 }
697
698 pub(super) fn compile_item_with_context(&mut self, item: &Item, is_last: bool) -> Result<()> {
701 match item {
702 Item::Function(func_def, _) => self.compile_function(func_def)?,
703 Item::Module(module_def, span) => {
704 self.compile_module_decl(module_def, *span)?;
705 }
706 Item::VariableDecl(var_decl, span) => {
707 if var_decl.kind == shape_ast::ast::VarKind::Const {
716 if let Some(ref init_expr) = var_decl.value {
717 if !Self::const_initializer_is_comptime_evaluable(init_expr) {
718 return Err(ShapeError::SemanticError {
719 message: format!(
720 "module-level `const` initializer must be comptime-evaluable \
721 (literal, or unary `-`/`!` on a literal). \
722 Function calls and other runtime-dependent expressions are \
723 rejected per R8 W8 Cluster A (2026-05-24). \
724 Extending the comptime evaluator is v0.4-concurrency-design-pass \
725 territory per docs/v0.3-close-summary.md \u{a7}5.15."
726 ),
727 location: Some(self.span_to_source_location(*span)),
728 });
729 }
730 }
731 }
732 let mut ref_borrow = None;
735 let init_err = if let Some(init_expr) = &var_decl.value {
736 let saved_pending_variable_name = self.pending_variable_name.clone();
737 let saved_pending_variable_typed_array_kind =
738 self.pending_variable_typed_array_kind;
739 self.pending_variable_name = var_decl
740 .pattern
741 .as_identifier()
742 .map(|name| name.to_string());
743 self.pending_variable_typed_array_kind = var_decl
755 .type_annotation
756 .as_ref()
757 .and_then(|ann| self.resolve_typed_array_kind_from_annotation(ann));
758 match self.compile_expr_for_reference_binding(init_expr) {
759 Ok(tracked_borrow) => {
760 ref_borrow = tracked_borrow;
761 self.pending_variable_name = saved_pending_variable_name;
762 self.pending_variable_typed_array_kind =
763 saved_pending_variable_typed_array_kind;
764 None
765 }
766 Err(e) => {
767 self.pending_variable_name = saved_pending_variable_name;
768 self.pending_variable_typed_array_kind =
769 saved_pending_variable_typed_array_kind;
770 self.emit(Instruction::simple(OpCode::PushNull));
772 Some(e)
773 }
774 }
775 } else {
776 self.emit(Instruction::simple(OpCode::PushNull));
777 None
778 };
779 let captured_empty_array_alloc_idx =
783 self.pending_empty_array_alloc_idx.take();
784
785 if let Some(name) = var_decl.pattern.as_identifier() {
786 let binding_idx = self.get_or_create_module_binding(name);
793 self.emit(Instruction::new(
794 OpCode::StoreModuleBinding,
795 Some(Operand::ModuleBinding(binding_idx)),
796 ));
797 if let Some(kind) = self.pending_variable_typed_array_kind {
804 self.v2_typed_array_module_bindings.insert(binding_idx, kind);
805 }
806 self.register_empty_array_accumulator(
811 crate::compiler::EmptyArrayAccumulatorKey::ModuleBinding(binding_idx),
812 var_decl.value.as_ref(),
813 captured_empty_array_alloc_idx,
814 name,
815 var_decl.value.as_ref().map(|v| v.span()),
816 );
817 if let Some(value) = &var_decl.value {
818 self.finish_reference_binding_from_expr(
819 binding_idx,
820 false,
821 name,
822 value,
823 ref_borrow,
824 );
825 self.update_callable_binding_from_expr(binding_idx, false, value);
826 } else {
827 self.clear_reference_binding(binding_idx, false);
828 self.clear_callable_binding(binding_idx, false);
829 }
830
831 if let Some(ref type_ann) = var_decl.type_annotation {
833 if let Some(type_name) = Self::tracked_type_name_from_annotation(type_ann) {
834 self.set_module_binding_type_info(binding_idx, &type_name);
835 }
836 } else {
837 let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
838 self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
839 }
840
841 let binding_type_name = self
843 .type_tracker
844 .get_binding_type(binding_idx)
845 .and_then(|info| info.type_name.clone());
846 let drop_kind = binding_type_name
847 .as_ref()
848 .and_then(|tn| self.drop_type_info.get(tn).copied())
849 .or_else(|| {
850 var_decl
851 .type_annotation
852 .as_ref()
853 .and_then(|ann| self.annotation_drop_kind(ann))
854 });
855 if drop_kind.is_some() {
856 let is_async = match drop_kind {
857 Some(DropKind::AsyncOnly) => true,
858 Some(DropKind::Both) => false,
859 Some(DropKind::SyncOnly) | None => false,
860 };
861 self.track_drop_module_binding(binding_idx, is_async);
862 }
863 } else {
864 self.compile_destructure_pattern_global(&var_decl.pattern)?;
865 }
866
867 if let Some(e) = init_err {
868 return Err(e);
869 }
870 }
871 Item::Assignment(assign, _) => {
872 self.compile_statement(&Statement::Assignment(assign.clone(), Span::DUMMY))?;
873 }
874 Item::Expression(expr, _) => {
875 self.compile_expr(expr)?;
876 if !is_last {
878 self.emit(Instruction::simple(OpCode::Pop));
879 }
880 }
881 Item::Statement(stmt, stmt_item_span) => {
882 if let Statement::VariableDecl(var_decl, decl_span) = stmt {
889 if var_decl.kind == shape_ast::ast::VarKind::Const {
890 if let Some(ref init_expr) = var_decl.value {
891 if !Self::const_initializer_is_comptime_evaluable(init_expr) {
892 return Err(ShapeError::SemanticError {
893 message: format!(
894 "`const` initializer must be comptime-evaluable \
895 (literal, or unary `-`/`!` on a literal). \
896 Function calls and other runtime-dependent expressions \
897 are rejected per R8 W8 Cluster A (2026-05-24). \
898 Extending the comptime evaluator is v0.4-concurrency-\
899 design-pass territory per docs/v0.3-close-summary.md \u{a7}5.15."
900 ),
901 location: Some(self.span_to_source_location(*decl_span)),
902 });
903 }
904 }
905 }
906 }
907 let _ = stmt_item_span;
908 if is_last {
910 if let Statement::Expression(expr, _) = stmt {
911 self.compile_expr(expr)?;
912 return Ok(());
914 }
915 }
916 self.compile_statement(stmt)?;
917 }
918 Item::Export(export, export_span) => {
919 if let Some(ref var_decl) = export.source_decl {
922 let mut ref_borrow = None;
923 if let Some(init_expr) = &var_decl.value {
924 let saved_pending_variable_name = self.pending_variable_name.clone();
925 let saved_pending_variable_typed_array_kind =
926 self.pending_variable_typed_array_kind;
927 self.pending_variable_name = var_decl
928 .pattern
929 .as_identifier()
930 .map(|name| name.to_string());
931 self.pending_variable_typed_array_kind = var_decl
935 .type_annotation
936 .as_ref()
937 .and_then(|ann| self.resolve_typed_array_kind_from_annotation(ann));
938 let compile_result = self.compile_expr_for_reference_binding(init_expr);
939 self.pending_variable_name = saved_pending_variable_name;
940 self.pending_variable_typed_array_kind =
941 saved_pending_variable_typed_array_kind;
942 ref_borrow = compile_result?;
943 if ref_borrow.is_some() {
944 return Err(ShapeError::SemanticError {
945 message:
946 "[B0003] cannot return or store a reference that outlives its owner"
947 .to_string(),
948 location: Some(self.span_to_source_location(init_expr.span())),
949 });
950 }
951 } else {
952 self.emit(Instruction::simple(OpCode::PushNull));
953 }
954 if let Some(name) = var_decl.pattern.as_identifier() {
955 let binding_idx = self.get_or_create_module_binding(name);
956 self.emit(Instruction::new(
957 OpCode::StoreModuleBinding,
958 Some(Operand::ModuleBinding(binding_idx)),
959 ));
960 if let Some(value) = &var_decl.value {
961 self.finish_reference_binding_from_expr(
962 binding_idx,
963 false,
964 name,
965 value,
966 ref_borrow,
967 );
968 self.update_callable_binding_from_expr(binding_idx, false, value);
969 } else {
970 self.clear_reference_binding(binding_idx, false);
971 self.clear_callable_binding(binding_idx, false);
972 }
973 }
974 }
975 match &export.item {
976 ExportItem::Function(func_def) => self.compile_function(func_def)?,
977 ExportItem::Annotation(annotation_def) => {
978 self.compile_annotation_def(annotation_def)?;
979 }
980 ExportItem::Enum(enum_def) => self.register_enum(enum_def)?,
981 ExportItem::Struct(struct_def) => {
982 self.register_struct_type(struct_def, *export_span)?;
983 if self.struct_types.contains_key(&struct_def.name) {
984 self.emit_annotation_lifecycle_calls_for_type(
985 &struct_def.name,
986 &struct_def.annotations,
987 )?;
988 }
989 }
990 ExportItem::Trait(_) => {} ExportItem::ForeignFunction(def) => self.compile_foreign_function(def)?,
992 _ => {}
993 }
994 }
995 Item::Stream(_stream, _) => {
996 return Err(ShapeError::StreamError {
997 message: "Streaming functionality has been removed".to_string(),
998 stream_name: None,
999 });
1000 }
1001 Item::TypeAlias(type_alias, _) => {
1002 let base_type_name = match &type_alias.type_annotation {
1004 TypeAnnotation::Basic(name) => Some(name.clone()),
1005 TypeAnnotation::Reference(name) => Some(name.to_string()),
1006 _ => None,
1007 };
1008 self.type_aliases.insert(
1009 type_alias.name.clone(),
1010 base_type_name
1011 .clone()
1012 .unwrap_or_else(|| format!("{:?}", type_alias.type_annotation)),
1013 );
1014 self.type_inference.env.define_type_alias(
1016 &type_alias.name,
1017 &type_alias.type_annotation,
1018 type_alias.meta_param_overrides.clone(),
1019 );
1020
1021 let _ = (&base_type_name, &type_alias.meta_param_overrides);
1057 }
1058 Item::StructType(struct_def, span) => {
1059 self.register_struct_type(struct_def, *span)?;
1060 if self.struct_types.contains_key(&struct_def.name) {
1061 self.emit_annotation_lifecycle_calls_for_type(
1062 &struct_def.name,
1063 &struct_def.annotations,
1064 )?;
1065 }
1066 }
1067 Item::Enum(enum_def, _) => {
1068 self.register_enum(enum_def)?;
1069 }
1070 Item::Import(import_stmt, _) => {
1072 self.register_import_names(import_stmt)?;
1082 }
1083 Item::Extend(extend, _) => {
1084 for method in &extend.methods {
1086 let func_def = self.desugar_extend_method(method, &extend.type_name)?;
1087 self.compile_function(&func_def)?;
1088 }
1089 }
1090 Item::Impl(impl_block, _) => {
1091 if impl_block.is_comptime {
1097 return Ok(());
1098 }
1099 let raw_trait_name = match &impl_block.trait_name {
1101 shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
1102 shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
1103 };
1104 let type_name = match &impl_block.target_type {
1105 shape_ast::ast::types::TypeName::Simple(n) => n.as_str(),
1106 shape_ast::ast::types::TypeName::Generic { name, .. } => name.as_str(),
1107 };
1108 let impl_name = impl_block.impl_name.as_deref();
1109
1110 let (canonical_trait, trait_basename) = self.resolve_trait_name(raw_trait_name);
1112
1113 if trait_basename == "From" || trait_basename == "TryFrom" {
1115 return self.compile_from_impl_bodies(impl_block, &trait_basename, type_name);
1116 }
1117
1118 let overridden: std::collections::HashSet<&str> =
1120 impl_block.methods.iter().map(|m| m.name.as_str()).collect();
1121
1122 for method in &impl_block.methods {
1123 let func_def = self.desugar_impl_method(
1124 method,
1125 &trait_basename,
1126 type_name,
1127 impl_name,
1128 &impl_block.target_type,
1129 )?;
1130 self.compile_function(&func_def)?;
1131 }
1132
1133 if let Some(trait_def) = self.trait_defs.get(&canonical_trait).cloned() {
1135 for member in &trait_def.members {
1136 if let shape_ast::ast::types::TraitMember::Default(default_method) = member
1137 {
1138 if !overridden.contains(default_method.name.as_str()) {
1139 let func_def = self.desugar_impl_method(
1140 default_method,
1141 &trait_basename,
1142 type_name,
1143 impl_name,
1144 &impl_block.target_type,
1145 )?;
1146 self.compile_function(&func_def)?;
1147 }
1148 }
1149 }
1150 }
1151 }
1152 Item::AnnotationDef(ann_def, _) => {
1153 self.compile_annotation_def(ann_def)?;
1154 }
1155 Item::Comptime(stmts, span) => {
1156 let extensions: Vec<_> = self
1158 .extension_registry
1159 .as_ref()
1160 .map(|r| r.as_ref().clone())
1161 .unwrap_or_default();
1162 let trait_impls = self.type_inference.env.trait_impl_keys();
1163 let known_type_symbols: std::collections::HashSet<String> = self
1164 .struct_types
1165 .keys()
1166 .chain(self.type_aliases.keys())
1167 .cloned()
1168 .collect();
1169 let comptime_helpers = self.collect_comptime_helpers();
1170 let type_snapshot = super::comptime_builtins::build_type_reflection_snapshot(
1174 self,
1175 &[],
1176 );
1177 let comptime_impl_blocks = self.comptime_impl_blocks.clone();
1180 let comptime_context_trait_defs: Vec<_> =
1181 self.trait_defs.values().cloned().collect();
1182 let comptime_context_struct_defs: Vec<_> = self
1183 .comptime_context_struct_defs
1184 .values()
1185 .cloned()
1186 .collect();
1187 let execution = super::comptime::execute_comptime_with_context(
1188 stmts,
1189 &comptime_helpers,
1190 &comptime_impl_blocks,
1191 &comptime_context_trait_defs,
1192 &comptime_context_struct_defs,
1193 &extensions,
1194 trait_impls,
1195 known_type_symbols,
1196 type_snapshot,
1197 )
1198 .map_err(|e| ShapeError::RuntimeError {
1199 message: format!(
1200 "Comptime block evaluation failed: {}",
1201 super::helpers::strip_error_prefix(&e)
1202 ),
1203 location: Some(self.span_to_source_location(*span)),
1204 })?;
1205 self.process_comptime_directives(execution.directives, "")
1206 .map_err(|e| ShapeError::RuntimeError {
1207 message: format!("Comptime block directive processing failed: {}", e),
1208 location: Some(self.span_to_source_location(*span)),
1209 })?;
1210 }
1211 Item::Query(query, _span) => {
1212 self.compile_query(query)?;
1213 if !is_last {
1215 self.emit(Instruction::simple(OpCode::Pop));
1216 }
1217 }
1218 Item::ForeignFunction(def, _) => self.compile_foreign_function(def)?,
1219 _ => {} }
1221 Ok(())
1222 }
1223
1224 fn register_import_names(&mut self, import_stmt: &shape_ast::ast::ImportStmt) -> Result<()> {
1229 use shape_ast::ast::ImportItems;
1230
1231 if let Some(pset) = self.permission_set.clone() {
1234 self.check_import_permissions(import_stmt, &pset)?;
1235 }
1236
1237 match &import_stmt.items {
1238 ImportItems::Named(specs) => {
1239 for spec in specs {
1240 if spec.is_annotation {
1241 self.module_scope_sources
1245 .entry(import_stmt.from.clone())
1246 .or_insert_with(|| import_stmt.from.clone());
1247 self.imported_annotations.insert(
1248 spec.name.clone(),
1249 ImportedAnnotationSymbol {
1250 original_name: spec.name.clone(),
1251 _module_path: import_stmt.from.clone(),
1252 hidden_module_name: import_stmt.from.clone(),
1253 },
1254 );
1255 continue;
1256 }
1257 let local_name = spec.alias.as_ref().unwrap_or(&spec.name);
1258 self.imported_names.insert(
1261 local_name.clone(),
1262 ImportedSymbol {
1263 original_name: spec.name.clone(),
1264 module_path: import_stmt.from.clone(),
1265 kind: None, },
1267 );
1268 }
1269 }
1270 ImportItems::Namespace { name, alias } => {
1271 let local_name = alias.as_ref().unwrap_or(name);
1274 let binding_idx = self.get_or_create_module_binding(local_name);
1275 self.module_namespace_bindings.insert(local_name.clone());
1276 self.module_scope_sources
1277 .entry(local_name.clone())
1278 .or_insert_with(|| import_stmt.from.clone());
1279 let module_path = if import_stmt.from.is_empty() {
1280 name.as_str()
1281 } else {
1282 import_stmt.from.as_str()
1283 };
1284 self.register_extension_module_schema(module_path);
1287 let module_schema_name = format!("__mod_{}", module_path);
1288 if self
1289 .type_tracker
1290 .schema_registry()
1291 .get(&module_schema_name)
1292 .is_some()
1293 {
1294 self.set_module_binding_type_info(binding_idx, &module_schema_name);
1295 }
1296 let _ = binding_idx;
1298 }
1299 }
1300 Ok(())
1301 }
1302
1303 fn check_import_permissions(
1308 &mut self,
1309 import_stmt: &shape_ast::ast::ImportStmt,
1310 pset: &shape_abi_v1::PermissionSet,
1311 ) -> Result<()> {
1312 use shape_ast::ast::ImportItems;
1313 use shape_runtime::stdlib::capability_tags;
1314
1315 let module_name = &import_stmt.from as &str;
1317
1318 match &import_stmt.items {
1319 ImportItems::Named(specs) => {
1320 for spec in specs {
1321 let required = capability_tags::required_permissions(module_name, &spec.name);
1322 if !required.is_empty() && !required.is_subset(pset) {
1323 let missing = required.difference(pset);
1324 let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
1325 return Err(ShapeError::SemanticError {
1326 message: format!(
1327 "Permission denied: {module_name}::{} requires {} capability, \
1328 but the active permission set does not include it. \
1329 Add the permission to [permissions] in shape.toml or use a less \
1330 restrictive preset.",
1331 spec.name,
1332 missing_names.join(", "),
1333 ),
1334 location: None,
1335 });
1336 }
1337 self.record_blob_permissions(module_name, &spec.name);
1338 }
1339 }
1340 ImportItems::Namespace { .. } => {
1341 let required = capability_tags::module_permissions(module_name);
1344 if !required.is_empty() && !required.is_subset(pset) {
1345 let missing = required.difference(pset);
1346 let missing_names: Vec<&str> = missing.iter().map(|p| p.name()).collect();
1347 return Err(ShapeError::SemanticError {
1348 message: format!(
1349 "Permission denied: module '{module_name}' requires {} capabilities, \
1350 but the active permission set does not include them. \
1351 Add the permissions to [permissions] in shape.toml or use a less \
1352 restrictive preset.",
1353 missing_names.join(", "),
1354 ),
1355 location: None,
1356 });
1357 }
1358 if let Some(ref mut blob) = self.current_blob_builder {
1360 let module_perms = capability_tags::module_permissions(module_name);
1361 blob.record_permissions(&module_perms);
1362 }
1363 }
1364 }
1365 Ok(())
1366 }
1367
1368 pub(super) fn register_graph_imports_for_module(
1375 &mut self,
1376 module_id: crate::module_graph::ModuleId,
1377 graph: &crate::module_graph::ModuleGraph,
1378 ) -> Result<()> {
1379 use crate::module_graph::{ModuleSourceKind, ResolvedImport};
1380
1381 let node = graph.node(module_id);
1382 let resolved_imports = node.resolved_imports.clone();
1383
1384 for ri in &resolved_imports {
1385 match ri {
1386 ResolvedImport::Namespace {
1387 local_name,
1388 canonical_path,
1389 module_id: dep_id,
1390 } => {
1391 let dep_node = graph.node(*dep_id);
1392
1393 let canonical_idx = self.get_or_create_module_binding(canonical_path);
1395
1396 if matches!(
1398 dep_node.source_kind,
1399 ModuleSourceKind::NativeModule | ModuleSourceKind::Hybrid
1400 ) {
1401 self.register_extension_module_schema(canonical_path);
1402 let module_schema_name = format!("__mod_{}", canonical_path);
1403 if self
1404 .type_tracker
1405 .schema_registry()
1406 .get(&module_schema_name)
1407 .is_some()
1408 {
1409 self.set_module_binding_type_info(canonical_idx, &module_schema_name);
1410 }
1411 }
1412
1413 if local_name != canonical_path {
1415 let alias_idx = self.get_or_create_module_binding(local_name);
1416
1417 let module_schema_name = format!("__mod_{}", canonical_path);
1419 if self
1420 .type_tracker
1421 .schema_registry()
1422 .get(&module_schema_name)
1423 .is_some()
1424 {
1425 self.set_module_binding_type_info(alias_idx, &module_schema_name);
1426 }
1427
1428 self.emit(Instruction::new(
1430 OpCode::LoadModuleBinding,
1431 Some(Operand::ModuleBinding(canonical_idx)),
1432 ));
1433 self.emit(Instruction::new(
1434 OpCode::StoreModuleBinding,
1435 Some(Operand::ModuleBinding(alias_idx)),
1436 ));
1437 }
1438
1439 self.module_namespace_bindings.insert(local_name.clone());
1441 self.graph_namespace_map
1442 .insert(local_name.clone(), canonical_path.clone());
1443
1444 for (export_name, exp) in &dep_node.interface.exports {
1450 if matches!(
1451 exp.kind,
1452 shape_ast::module_utils::ModuleExportKind::Annotation
1453 ) {
1454 self.imported_annotations
1455 .entry(export_name.clone())
1456 .or_insert_with(|| ImportedAnnotationSymbol {
1457 original_name: export_name.clone(),
1458 _module_path: canonical_path.clone(),
1459 hidden_module_name: canonical_path.clone(),
1460 });
1461 }
1462 }
1463 }
1464 ResolvedImport::Named {
1465 canonical_path,
1466 module_id: dep_id,
1467 symbols,
1468 } => {
1469 let dep_node = graph.node(*dep_id);
1470
1471 for sym in symbols {
1472 if sym.is_annotation {
1473 self.module_scope_sources
1480 .entry(canonical_path.clone())
1481 .or_insert_with(|| canonical_path.clone());
1482 self.imported_annotations
1484 .entry(sym.local_name.clone())
1485 .or_insert_with(|| ImportedAnnotationSymbol {
1486 original_name: sym.original_name.clone(),
1487 _module_path: canonical_path.clone(),
1488 hidden_module_name: canonical_path.clone(),
1489 });
1490 continue;
1491 }
1492
1493 self.imported_names
1496 .entry(sym.local_name.clone())
1497 .or_insert_with(|| ImportedSymbol {
1498 original_name: sym.original_name.clone(),
1499 module_path: canonical_path.clone(),
1500 kind: Some(sym.kind),
1501 });
1502
1503 if matches!(
1505 dep_node.source_kind,
1506 ModuleSourceKind::NativeModule | ModuleSourceKind::Hybrid
1507 ) && matches!(
1508 sym.kind,
1509 shape_ast::module_utils::ModuleExportKind::Function
1510 | shape_ast::module_utils::ModuleExportKind::BuiltinFunction
1511 ) {
1512 self.module_builtin_functions
1513 .entry(sym.local_name.clone())
1514 .or_insert_with(|| ModuleBuiltinFunction {
1515 export_name: sym.original_name.clone(),
1516 source_module_path: canonical_path.clone(),
1517 });
1518 }
1519
1520 if matches!(
1529 sym.kind,
1530 shape_ast::module_utils::ModuleExportKind::Value
1531 ) {
1532 if let Some(ref dep_ast) = dep_node.ast {
1533 for item in &dep_ast.items {
1534 if let shape_ast::ast::Item::Export(export, _) = item {
1535 if let Some(ref decl) = export.source_decl {
1536 if decl.kind == shape_ast::ast::VarKind::Const {
1537 if let Some(decl_name) = decl.pattern.as_identifier() {
1538 if decl_name == sym.original_name {
1539 if let Some(ref init) = decl.value {
1540 self.imported_consts
1541 .entry(sym.local_name.clone())
1542 .or_insert_with(|| init.clone());
1543 }
1544 }
1545 }
1546 }
1547 }
1548 }
1549 }
1550 }
1551 }
1552 }
1553 }
1554 }
1555 }
1556
1557 Ok(())
1558 }
1559
1560 pub(super) fn register_extension_module_schema(&mut self, module_path: &str) {
1561 let Some(registry) = self.extension_registry.as_ref() else {
1562 return;
1563 };
1564 let Some(module) = registry
1565 .iter()
1566 .rev()
1567 .find(|m| m.name == module_path)
1568 else {
1569 return;
1570 };
1571
1572 let mut global_max_ext_id: Option<shape_runtime::type_schema::SchemaId> = None;
1582 for ext_module in registry.iter() {
1583 for schema in &ext_module.type_schemas {
1584 global_max_ext_id = Some(match global_max_ext_id {
1585 Some(prev) => prev.max(schema.id),
1586 None => schema.id,
1587 });
1588 }
1589 }
1590 for schema in &module.type_schemas {
1591 if self
1592 .type_tracker
1593 .schema_registry()
1594 .get(&schema.name)
1595 .is_none()
1596 {
1597 self.type_tracker
1598 .schema_registry_mut()
1599 .register(schema.clone());
1600 }
1601 }
1602 if let Some(max_id) = global_max_ext_id {
1603 self.type_tracker
1604 .schema_registry()
1605 .ensure_next_id_above(max_id);
1606 }
1607
1608 let schema_name = format!("__mod_{}", module_path);
1609 if self
1610 .type_tracker
1611 .schema_registry()
1612 .get(&schema_name)
1613 .is_some()
1614 {
1615 return;
1616 }
1617
1618 let mut export_names: Vec<String> = module
1619 .export_names_available(self.comptime_mode)
1620 .into_iter()
1621 .map(|name| name.to_string())
1622 .collect();
1623
1624 for artifact in &module.module_artifacts {
1625 if artifact.module_path != module_path {
1626 continue;
1627 }
1628 let Some(source) = artifact.source.as_deref() else {
1629 continue;
1630 };
1631 if let Ok(names) =
1632 shape_runtime::module_loader::collect_exported_function_names_from_source(
1633 &artifact.module_path,
1634 source,
1635 )
1636 {
1637 export_names.extend(names);
1638 }
1639 }
1640
1641 export_names.sort();
1642 export_names.dedup();
1643
1644 let fields: Vec<(String, FieldType)> = export_names
1645 .into_iter()
1646 .map(|name| (name, FieldType::Any))
1647 .collect();
1648 self.type_tracker
1658 .schema_registry_mut()
1659 .register_type_scoped(schema_name, fields);
1660 }
1661
1662 fn register_enum(&mut self, enum_def: &EnumDef) -> Result<()> {
1664 let variants: Vec<EnumVariantInfo> = enum_def
1665 .members
1666 .iter()
1667 .enumerate()
1668 .map(|(id, member)| {
1669 match &member.kind {
1676 EnumMemberKind::Unit { .. } => {
1677 EnumVariantInfo::new(&member.name, id as u16, 0)
1678 }
1679 EnumMemberKind::Tuple(types) => {
1680 EnumVariantInfo::new(&member.name, id as u16, types.len() as u16)
1681 }
1682 EnumMemberKind::Struct(fields) => {
1683 let names: Vec<String> =
1684 fields.iter().map(|f| f.name.clone()).collect();
1685 EnumVariantInfo::new_struct(&member.name, id as u16, names)
1686 }
1687 }
1688 })
1689 .collect();
1690
1691 for member in &enum_def.members {
1699 if let EnumMemberKind::Struct(fields) = &member.kind {
1700 let kv: Vec<(String, shape_ast::ast::TypeAnnotation)> = fields
1701 .iter()
1702 .map(|f| (f.name.clone(), f.type_annotation.clone()))
1703 .collect();
1704 self.enum_struct_variant_fields
1705 .insert((enum_def.name.clone(), member.name.clone()), kv.clone());
1706 if let Some(basename) = enum_def.name.rsplit("::").next() {
1707 if basename != enum_def.name {
1708 self.enum_struct_variant_fields
1709 .insert((basename.to_string(), member.name.clone()), kv);
1710 }
1711 }
1712 }
1713 if let EnumMemberKind::Tuple(types) = &member.kind {
1717 let tv = types.clone();
1718 self.enum_tuple_variant_fields
1719 .insert((enum_def.name.clone(), member.name.clone()), tv.clone());
1720 if let Some(basename) = enum_def.name.rsplit("::").next() {
1721 if basename != enum_def.name {
1722 self.enum_tuple_variant_fields
1723 .insert((basename.to_string(), member.name.clone()), tv);
1724 }
1725 }
1726 }
1727 }
1728
1729 let schema = shape_runtime::type_schema::TypeSchema::new_enum(&enum_def.name, variants.clone());
1730 self.type_tracker.schema_registry_mut().register(schema);
1731
1732 if let Some(basename) = enum_def.name.rsplit("::").next() {
1735 if basename != enum_def.name
1736 && self
1737 .type_tracker
1738 .schema_registry()
1739 .get(basename)
1740 .is_none()
1741 {
1742 let alias_schema =
1743 shape_runtime::type_schema::TypeSchema::new_enum(basename, variants);
1744 self.type_tracker.schema_registry_mut().register(alias_schema);
1745 }
1746 }
1747 Ok(())
1748 }
1749
1750 pub fn register_imported_items(&mut self, items: &[Item]) {
1755 for item in items {
1756 match item {
1757 Item::Export(export, _) => {
1758 match &export.item {
1759 ExportItem::Enum(enum_def) => {
1760 let _ = self.register_enum(enum_def);
1761 }
1762 ExportItem::Struct(struct_def) => {
1763 let _ = self.register_struct_type(struct_def, Span::DUMMY);
1765 }
1766 ExportItem::Function(func_def) => {
1767 let _ = self.register_function(func_def);
1769 }
1770 _ => {}
1771 }
1772 }
1773 Item::Enum(enum_def, _) => {
1774 let _ = self.register_enum(enum_def);
1775 }
1776 _ => {}
1777 }
1778 }
1779 }
1780
1781 pub(super) fn desugar_extend_method(
1792 &self,
1793 method: &shape_ast::ast::types::MethodDef,
1794 target_type: &shape_ast::ast::TypeName,
1795 ) -> Result<FunctionDef> {
1796 let receiver_type = Some(Self::type_name_to_annotation(target_type));
1797 let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1798
1799 let type_str = match target_type {
1802 shape_ast::ast::TypeName::Simple(n) => n.clone(),
1803 shape_ast::ast::TypeName::Generic { name, .. } => name.clone(),
1804 };
1805
1806 let extend_type_params: Vec<shape_ast::ast::TypeParam> = match target_type {
1815 shape_ast::ast::TypeName::Generic { type_args, .. } => type_args
1816 .iter()
1817 .filter_map(|ta| match ta {
1818 shape_ast::ast::TypeAnnotation::Basic(name)
1819 if name.len() == 1
1820 && name.chars().next().is_some_and(|c| c.is_ascii_uppercase()) =>
1821 {
1822 Some(shape_ast::ast::TypeParam::Type {
1823 name: name.clone(),
1824 span: Span::DUMMY,
1825 doc_comment: None,
1826 default_type: None,
1827 trait_bounds: Vec::new(),
1828 })
1829 }
1830 _ => None,
1831 })
1832 .collect(),
1833 _ => Vec::new(),
1834 };
1835
1836 let mut merged_type_params: Vec<shape_ast::ast::TypeParam> = extend_type_params;
1854 if let Some(method_tps) = method.type_params.as_ref() {
1855 for tp in method_tps {
1856 let name = tp.name();
1859 if !merged_type_params.iter().any(|m| m.name() == name) {
1860 merged_type_params.push(tp.clone());
1861 }
1862 }
1863 }
1864
1865 Ok(FunctionDef {
1866 name: format!("{}.{}", type_str, method.name),
1867 name_span: Span::DUMMY,
1868 declaring_module_path: method.declaring_module_path.clone(),
1869 doc_comment: None,
1870 params,
1871 return_type: method.return_type.clone(),
1872 body,
1873 type_params: Some(merged_type_params),
1874 annotations: method.annotations.clone(),
1875 is_async: method.is_async,
1876 is_comptime: false,
1877 where_clause: None,
1878 })
1879 }
1880
1881 fn desugar_impl_method(
1918 &self,
1919 method: &shape_ast::ast::types::MethodDef,
1920 trait_name: &str,
1921 type_name: &str,
1922 impl_name: Option<&str>,
1923 target_type: &shape_ast::ast::TypeName,
1924 ) -> Result<FunctionDef> {
1925 let (impl_type_params, receiver_type) =
1935 Self::synthesize_impl_type_params(target_type);
1936
1937 let (params, body) = self.desugar_method_signature_and_body(method, receiver_type)?;
1938
1939 let method_name = if trait_name == "Drop" && method.name == "drop" && method.is_async {
1942 "drop_async".to_string()
1943 } else {
1944 method.name.clone()
1945 };
1946 let fn_name = if let Some(name) = impl_name {
1947 format!("{}::{}::{}::{}", trait_name, type_name, name, method_name)
1948 } else {
1949 format!("{}::{}", type_name, method_name)
1950 };
1951
1952 let return_type = method.return_type.clone().or_else(|| {
1966 let (canonical_trait, _) = self.resolve_trait_name(trait_name);
1967 self.trait_defs
1968 .get(&canonical_trait)
1969 .and_then(|trait_def| {
1970 for member in &trait_def.members {
1977 match member {
1978 shape_ast::ast::types::TraitMember::Required(
1979 shape_ast::ast::TraitMemberSignature::Method {
1980 name,
1981 return_type,
1982 ..
1983 },
1984 ) if name == &method.name => {
1985 return Some(return_type.clone());
1986 }
1987 shape_ast::ast::types::TraitMember::Default(default_method)
1988 if default_method.name == method.name =>
1989 {
1990 return default_method.return_type.clone();
1991 }
1992 _ => {}
1993 }
1994 }
1995 None
1996 })
1997 });
1998
1999 let mut merged_impl_type_params: Vec<shape_ast::ast::TypeParam> = impl_type_params;
2003 if let Some(method_tps) = method.type_params.as_ref() {
2004 for tp in method_tps {
2005 let name = tp.name();
2006 if !merged_impl_type_params.iter().any(|m| m.name() == name) {
2007 merged_impl_type_params.push(tp.clone());
2008 }
2009 }
2010 }
2011
2012 Ok(FunctionDef {
2013 name: fn_name,
2014 name_span: Span::DUMMY,
2015 declaring_module_path: method.declaring_module_path.clone(),
2016 doc_comment: None,
2017 params,
2018 return_type,
2019 body,
2020 type_params: Some(merged_impl_type_params),
2021 annotations: method.annotations.clone(),
2022 is_async: method.is_async,
2023 is_comptime: false,
2024 where_clause: None,
2025 })
2026 }
2027
2028 fn synthesize_impl_type_params(
2038 target_type: &shape_ast::ast::TypeName,
2039 ) -> (Vec<shape_ast::ast::TypeParam>, Option<shape_ast::ast::TypeAnnotation>) {
2040 let type_base = match target_type {
2041 shape_ast::ast::TypeName::Simple(n) => n.as_str(),
2042 shape_ast::ast::TypeName::Generic { name, .. } => name.as_str(),
2043 };
2044
2045 let is_single_param_generic = matches!(type_base, "Array" | "Vec");
2047 let is_dual_param_generic = matches!(type_base, "HashMap" | "Map");
2049
2050 if is_single_param_generic {
2051 let type_params = vec![shape_ast::ast::TypeParam::Type {
2052 name: "T".to_string(),
2053 span: Span::DUMMY,
2054 doc_comment: None,
2055 default_type: None,
2056 trait_bounds: Vec::new(),
2057 }];
2058 let receiver_ann = shape_ast::ast::TypeAnnotation::Generic {
2059 name: shape_ast::ast::type_path::TypePath::simple(type_base),
2060 args: vec![shape_ast::ast::TypeAnnotation::Basic("T".to_string())],
2061 };
2062 (type_params, Some(receiver_ann))
2063 } else if is_dual_param_generic {
2064 let type_params = vec![
2065 shape_ast::ast::TypeParam::Type {
2066 name: "K".to_string(),
2067 span: Span::DUMMY,
2068 doc_comment: None,
2069 default_type: None,
2070 trait_bounds: Vec::new(),
2071 },
2072 shape_ast::ast::TypeParam::Type {
2073 name: "V".to_string(),
2074 span: Span::DUMMY,
2075 doc_comment: None,
2076 default_type: None,
2077 trait_bounds: Vec::new(),
2078 },
2079 ];
2080 let receiver_ann = shape_ast::ast::TypeAnnotation::Generic {
2081 name: shape_ast::ast::type_path::TypePath::simple(type_base),
2082 args: vec![
2083 shape_ast::ast::TypeAnnotation::Basic("K".to_string()),
2084 shape_ast::ast::TypeAnnotation::Basic("V".to_string()),
2085 ],
2086 };
2087 (type_params, Some(receiver_ann))
2088 } else {
2089 (Vec::new(), Some(Self::type_name_to_annotation(target_type)))
2091 }
2092 }
2093
2094 fn desugar_method_signature_and_body(
2098 &self,
2099 method: &shape_ast::ast::types::MethodDef,
2100 receiver_type: Option<shape_ast::ast::TypeAnnotation>,
2101 ) -> Result<(Vec<FunctionParameter>, Vec<Statement>)> {
2102 if let Some(receiver) = method
2103 .params
2104 .first()
2105 .and_then(|p| p.pattern.as_identifier())
2106 {
2107 if receiver == "self" {
2108 let location = method
2109 .params
2110 .first()
2111 .map(|p| self.span_to_source_location(p.span()));
2112 return Err(ShapeError::SemanticError {
2113 message: format!(
2114 "Method '{}' has an explicit `self` parameter, but method receivers are implicit. Use `method {}(...)` without `self`.",
2115 method.name, method.name
2116 ),
2117 location,
2118 });
2119 }
2120 }
2121
2122 let mut params = vec![FunctionParameter {
2123 pattern: shape_ast::ast::DestructurePattern::Identifier(
2124 "self".to_string(),
2125 Span::DUMMY,
2126 ),
2127 is_const: false,
2128 is_reference: false,
2129 is_mut_reference: false,
2130 is_out: false,
2131 type_annotation: receiver_type,
2132 default_value: None,
2133 }];
2134 params.extend(method.params.clone());
2135
2136 Ok((params, method.body.clone()))
2137 }
2138
2139 fn compile_from_impl(
2150 &mut self,
2151 impl_block: &shape_ast::ast::types::ImplBlock,
2152 trait_name: &str,
2153 target_type: &str,
2154 ) -> Result<()> {
2155 let source_type = match &impl_block.trait_name {
2157 shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
2158 match &type_args[0] {
2159 TypeAnnotation::Basic(name) => name.clone(),
2160 TypeAnnotation::Reference(name) => name.to_string(),
2161 other => {
2162 return Err(ShapeError::SemanticError {
2163 message: format!(
2164 "{} impl requires a simple source type, found {:?}",
2165 trait_name, other
2166 ),
2167 location: None,
2168 });
2169 }
2170 }
2171 }
2172 _ => {
2173 return Err(ShapeError::SemanticError {
2174 message: format!(
2175 "{} impl requires a generic type argument, e.g., {}<string>",
2176 trait_name, trait_name
2177 ),
2178 location: None,
2179 });
2180 }
2181 };
2182
2183 let selector = impl_block.impl_name.as_deref().unwrap_or(target_type);
2186
2187 for method in &impl_block.methods {
2188 let func_def =
2189 self.desugar_from_method(method, trait_name, target_type, &source_type)?;
2190 let from_fn_name = func_def.name.clone();
2191
2192 self.program.register_trait_method_symbol(
2194 trait_name,
2195 target_type,
2196 Some(&source_type),
2197 &method.name,
2198 &from_fn_name,
2199 );
2200 self.register_function(&func_def)?;
2201
2202 if trait_name == "From" {
2204 self.program.register_trait_method_symbol(
2206 "Into",
2207 &source_type,
2208 Some(selector),
2209 "into",
2210 &from_fn_name,
2211 );
2212
2213 let wrapper_name =
2215 self.emit_from_to_tryinto_wrapper(&from_fn_name, &source_type, target_type)?;
2216 self.program.register_trait_method_symbol(
2217 "TryInto",
2218 &source_type,
2219 Some(selector),
2220 "tryInto",
2221 &wrapper_name,
2222 );
2223
2224 let _ = self.type_inference.env.register_trait_impl_named(
2226 "Into",
2227 &source_type,
2228 selector,
2229 vec!["into".to_string()],
2230 );
2231 let _ = self.type_inference.env.register_trait_impl_named(
2232 "TryInto",
2233 &source_type,
2234 selector,
2235 vec!["tryInto".to_string()],
2236 );
2237 } else {
2238 self.program.register_trait_method_symbol(
2240 "TryInto",
2241 &source_type,
2242 Some(selector),
2243 "tryInto",
2244 &from_fn_name,
2245 );
2246
2247 let _ = self.type_inference.env.register_trait_impl_named(
2249 "TryInto",
2250 &source_type,
2251 selector,
2252 vec!["tryInto".to_string()],
2253 );
2254 }
2255 }
2256
2257 let all_method_names: Vec<String> =
2259 impl_block.methods.iter().map(|m| m.name.clone()).collect();
2260 let _ = self.type_inference.env.register_trait_impl_named(
2261 trait_name,
2262 target_type,
2263 &source_type,
2264 all_method_names,
2265 );
2266
2267 Ok(())
2268 }
2269
2270 fn compile_from_impl_bodies(
2275 &mut self,
2276 impl_block: &shape_ast::ast::types::ImplBlock,
2277 trait_name: &str,
2278 target_type: &str,
2279 ) -> Result<()> {
2280 let source_type = match &impl_block.trait_name {
2281 shape_ast::ast::types::TypeName::Generic { type_args, .. } if !type_args.is_empty() => {
2282 match &type_args[0] {
2283 TypeAnnotation::Basic(name) => name.clone(),
2284 TypeAnnotation::Reference(name) => name.to_string(),
2285 _ => return Ok(()), }
2287 }
2288 _ => return Ok(()),
2289 };
2290
2291 for method in &impl_block.methods {
2292 let func_def =
2293 self.desugar_from_method(method, trait_name, target_type, &source_type)?;
2294 self.compile_function(&func_def)?;
2295 }
2296
2297 if trait_name == "From" {
2299 for method in &impl_block.methods {
2300 let from_fn_name = format!(
2301 "{}::{}::{}::{}",
2302 trait_name, target_type, source_type, method.name
2303 );
2304 let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
2305 if let Some(func_def) = self.function_defs.get(&wrapper_name).cloned() {
2307 let _ = self.compile_function(&func_def);
2308 let _ = from_fn_name; }
2312 }
2313 }
2314
2315 Ok(())
2316 }
2317
2318 fn desugar_from_method(
2323 &self,
2324 method: &shape_ast::ast::types::MethodDef,
2325 trait_name: &str,
2326 target_type: &str,
2327 source_type: &str,
2328 ) -> Result<FunctionDef> {
2329 if let Some(first) = method
2331 .params
2332 .first()
2333 .and_then(|p| p.pattern.as_identifier())
2334 {
2335 if first == "self" {
2336 return Err(ShapeError::SemanticError {
2337 message: format!(
2338 "{}::{} methods are constructors and must not have a `self` parameter",
2339 trait_name, method.name
2340 ),
2341 location: None,
2342 });
2343 }
2344 }
2345
2346 let fn_name = format!(
2347 "{}::{}::{}::{}",
2348 trait_name, target_type, source_type, method.name
2349 );
2350
2351 Ok(FunctionDef {
2352 name: fn_name,
2353 name_span: Span::DUMMY,
2354 declaring_module_path: method.declaring_module_path.clone(),
2355 doc_comment: None,
2356 params: method.params.clone(),
2357 return_type: method.return_type.clone(),
2358 body: method.body.clone(),
2359 type_params: Some(Vec::new()),
2360 annotations: Vec::new(),
2361 is_async: method.is_async,
2362 is_comptime: false,
2363 where_clause: None,
2364 })
2365 }
2366
2367 fn emit_from_to_tryinto_wrapper(
2372 &mut self,
2373 from_fn_name: &str,
2374 source_type: &str,
2375 target_type: &str,
2376 ) -> Result<String> {
2377 let wrapper_name = format!("__from_tryinto_{}_{}", source_type, target_type);
2378
2379 let span = Span::DUMMY;
2381 let body = vec![Statement::Return(
2382 Some(Expr::FunctionCall {
2383 name: "Ok".to_string(),
2384 args: vec![Expr::FunctionCall {
2385 name: from_fn_name.to_string(),
2386 args: vec![Expr::Identifier("value".to_string(), span)],
2387 named_args: Vec::new(),
2388 span,
2389 }],
2390 named_args: Vec::new(),
2391 span,
2392 }),
2393 span,
2394 )];
2395
2396 let func_def = FunctionDef {
2397 name: wrapper_name.clone(),
2398 name_span: span,
2399 declaring_module_path: None,
2400 doc_comment: None,
2401 params: vec![FunctionParameter {
2402 pattern: DestructurePattern::Identifier("value".to_string(), span),
2403 is_const: false,
2404 is_reference: false,
2405 is_mut_reference: false,
2406 is_out: false,
2407 type_annotation: None,
2408 default_value: None,
2409 }],
2410 return_type: None,
2411 body,
2412 type_params: Some(Vec::new()),
2413 annotations: Vec::new(),
2414 is_async: false,
2415 is_comptime: false,
2416 where_clause: None,
2417 };
2418
2419 self.register_function(&func_def)?;
2420
2421 Ok(wrapper_name)
2422 }
2423
2424 fn type_name_to_annotation(
2425 type_name: &shape_ast::ast::TypeName,
2426 ) -> shape_ast::ast::TypeAnnotation {
2427 match type_name {
2428 shape_ast::ast::TypeName::Simple(name) => {
2429 shape_ast::ast::TypeAnnotation::Basic(name.to_string())
2430 }
2431 shape_ast::ast::TypeName::Generic { name, type_args } => {
2432 shape_ast::ast::TypeAnnotation::Generic {
2433 name: name.clone(),
2434 args: type_args.clone(),
2435 }
2436 }
2437 }
2438 }
2439
2440 fn compile_annotation_def(&mut self, ann_def: &shape_ast::ast::AnnotationDef) -> Result<()> {
2449 use crate::bytecode::CompiledAnnotation;
2450 use shape_ast::ast::AnnotationHandlerType;
2451
2452 let mut compiled = CompiledAnnotation {
2453 name: ann_def.name.clone(),
2454 param_names: ann_def
2455 .params
2456 .iter()
2457 .flat_map(|p| p.get_identifiers())
2458 .collect(),
2459 before_handler: None,
2460 after_handler: None,
2461 on_define_handler: None,
2462 metadata_handler: None,
2463 comptime_pre_handler: None,
2464 comptime_post_handler: None,
2465 allowed_targets: Vec::new(),
2466 };
2467
2468 for handler in &ann_def.handlers {
2469 match handler.handler_type {
2472 AnnotationHandlerType::ComptimePre => {
2473 compiled.comptime_pre_handler = Some(handler.clone());
2474 continue;
2475 }
2476 AnnotationHandlerType::ComptimePost => {
2477 compiled.comptime_post_handler = Some(handler.clone());
2478 continue;
2479 }
2480 _ => {}
2481 }
2482
2483 if handler.params.iter().any(|p| p.is_variadic) {
2484 return Err(ShapeError::SemanticError {
2485 message:
2486 "Variadic annotation handler params (`...args`) are only supported on comptime handlers"
2487 .to_string(),
2488 location: Some(self.span_to_source_location(handler.span)),
2489 });
2490 }
2491
2492 let handler_type_str = match handler.handler_type {
2493 AnnotationHandlerType::Before => "before",
2494 AnnotationHandlerType::After => "after",
2495 AnnotationHandlerType::OnDefine => "on_define",
2496 AnnotationHandlerType::Metadata => "metadata",
2497 AnnotationHandlerType::ComptimePre => unreachable!(),
2498 AnnotationHandlerType::ComptimePost => unreachable!(),
2499 };
2500
2501 let func_name = format!("{}___{}", ann_def.name, handler_type_str);
2502
2503 let mut params = vec![FunctionParameter {
2505 pattern: shape_ast::ast::DestructurePattern::Identifier(
2506 "self".to_string(),
2507 Span::DUMMY,
2508 ),
2509 is_const: false,
2510 is_reference: false,
2511 is_mut_reference: false,
2512 is_out: false,
2513 type_annotation: None,
2514 default_value: None,
2515 }];
2516 for ann_param in &ann_def.params {
2518 params.push(ann_param.clone());
2519 }
2520 for param in &handler.params {
2522 let inferred_type = if param.name == "ctx" {
2523 Some(TypeAnnotation::Object(vec![
2524 shape_ast::ast::ObjectTypeField {
2525 name: "state".to_string(),
2526 optional: false,
2527 type_annotation: TypeAnnotation::Basic("unknown".to_string()),
2528 annotations: vec![],
2529 },
2530 shape_ast::ast::ObjectTypeField {
2531 name: "event_log".to_string(),
2532 optional: false,
2533 type_annotation: TypeAnnotation::Array(Box::new(
2534 TypeAnnotation::Basic("unknown".to_string()),
2535 )),
2536 annotations: vec![],
2537 },
2538 ]))
2539 } else if matches!(
2540 handler.handler_type,
2541 AnnotationHandlerType::OnDefine | AnnotationHandlerType::Metadata
2542 ) && (param.name == "fn" || param.name == "target")
2543 {
2544 Some(TypeAnnotation::Object(vec![
2545 shape_ast::ast::ObjectTypeField {
2546 name: "name".to_string(),
2547 optional: false,
2548 type_annotation: TypeAnnotation::Basic("string".to_string()),
2549 annotations: vec![],
2550 },
2551 shape_ast::ast::ObjectTypeField {
2552 name: "kind".to_string(),
2553 optional: false,
2554 type_annotation: TypeAnnotation::Basic("string".to_string()),
2555 annotations: vec![],
2556 },
2557 shape_ast::ast::ObjectTypeField {
2558 name: "id".to_string(),
2559 optional: false,
2560 type_annotation: TypeAnnotation::Basic("int".to_string()),
2561 annotations: vec![],
2562 },
2563 ]))
2564 } else {
2565 None
2566 };
2567
2568 params.push(FunctionParameter {
2569 pattern: shape_ast::ast::DestructurePattern::Identifier(
2570 param.name.clone(),
2571 Span::DUMMY,
2572 ),
2573 is_const: false,
2574 is_reference: false,
2575 is_mut_reference: false,
2576 is_out: false,
2577 type_annotation: inferred_type,
2578 default_value: None,
2579 });
2580 }
2581
2582 let body = vec![Statement::Return(Some(handler.body.clone()), Span::DUMMY)];
2584
2585 let func_def = FunctionDef {
2586 name: func_name,
2587 name_span: Span::DUMMY,
2588 declaring_module_path: None,
2589 doc_comment: None,
2590 params,
2591 return_type: handler.return_type.clone(),
2592 body,
2593 type_params: Some(Vec::new()),
2594 annotations: Vec::new(),
2595 is_async: false,
2596 is_comptime: false,
2597 where_clause: None,
2598 };
2599
2600 self.register_function(&func_def)?;
2601 self.compile_function(&func_def)?;
2602
2603 let func_idx = self.program.functions.len() - 1;
2610 self.program.functions[func_idx].locals_count = self.next_local;
2611 self.capture_function_local_storage_hints(func_idx);
2612
2613 let func_id = (self.program.functions.len() - 1) as u16;
2614
2615 match handler.handler_type {
2616 AnnotationHandlerType::Before => compiled.before_handler = Some(func_id),
2617 AnnotationHandlerType::After => compiled.after_handler = Some(func_id),
2618 AnnotationHandlerType::OnDefine => compiled.on_define_handler = Some(func_id),
2619 AnnotationHandlerType::Metadata => compiled.metadata_handler = Some(func_id),
2620 AnnotationHandlerType::ComptimePre => {} AnnotationHandlerType::ComptimePost => {} }
2623 }
2624
2625 if let Some(explicit) = &ann_def.allowed_targets {
2631 compiled.allowed_targets = explicit.clone();
2632 } else if compiled.before_handler.is_some()
2633 || compiled.after_handler.is_some()
2634 || compiled.comptime_pre_handler.is_some()
2635 || compiled.comptime_post_handler.is_some()
2636 {
2637 compiled.allowed_targets =
2638 vec![shape_ast::ast::functions::AnnotationTargetKind::Function];
2639 } else if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
2640 compiled.allowed_targets = vec![
2641 shape_ast::ast::functions::AnnotationTargetKind::Function,
2642 shape_ast::ast::functions::AnnotationTargetKind::Type,
2643 shape_ast::ast::functions::AnnotationTargetKind::Module,
2644 ];
2645 }
2646
2647 if compiled.on_define_handler.is_some() || compiled.metadata_handler.is_some() {
2650 if compiled.allowed_targets.is_empty() {
2651 return Err(ShapeError::SemanticError {
2652 message: format!(
2653 "Annotation '{}' uses `on_define`/`metadata` and cannot have unrestricted targets. Allowed targets are: function, type, module",
2654 ann_def.name
2655 ),
2656 location: Some(self.span_to_source_location(ann_def.span)),
2657 });
2658 }
2659 if let Some(invalid) = compiled
2660 .allowed_targets
2661 .iter()
2662 .find(|kind| !Self::is_definition_annotation_target(**kind))
2663 {
2664 let invalid_label = format!("{:?}", invalid).to_lowercase();
2665 return Err(ShapeError::SemanticError {
2666 message: format!(
2667 "Annotation '{}' uses `on_define`/`metadata`, but target '{}' is not a definition target. Allowed targets are: function, type, module",
2668 ann_def.name, invalid_label
2669 ),
2670 location: Some(self.span_to_source_location(ann_def.span)),
2671 });
2672 }
2673 }
2674
2675 self.program
2676 .compiled_annotations
2677 .insert(ann_def.name.clone(), compiled);
2678 Ok(())
2679 }
2680
2681 fn predeclare_struct_schema(&mut self, struct_def: &shape_ast::ast::StructTypeDef) {
2703 use shape_ast::ast::Literal;
2704 use shape_runtime::type_schema::FieldAnnotation;
2705
2706 if self
2707 .type_tracker
2708 .schema_registry()
2709 .get(&struct_def.name)
2710 .is_some()
2711 {
2712 return;
2713 }
2714 let runtime_fields: Vec<(String, shape_runtime::type_schema::FieldType)> = struct_def
2715 .fields
2716 .iter()
2717 .filter(|f| !f.is_comptime)
2718 .map(|f| {
2719 (
2720 f.name.clone(),
2721 Self::type_annotation_to_field_type(&f.type_annotation),
2722 )
2723 })
2724 .collect();
2725 let field_annotations: Vec<Vec<FieldAnnotation>> = struct_def
2728 .fields
2729 .iter()
2730 .filter(|f| !f.is_comptime)
2731 .map(|f| {
2732 f.annotations
2733 .iter()
2734 .map(|ann| FieldAnnotation {
2735 name: ann.name.clone(),
2736 args: ann
2737 .args
2738 .iter()
2739 .filter_map(|arg| match arg {
2740 Expr::Literal(Literal::String(s), _) => Some(s.clone()),
2741 _ => None,
2742 })
2743 .collect(),
2744 })
2745 .collect()
2746 })
2747 .collect();
2748 self.type_tracker
2749 .schema_registry_mut()
2750 .register_type_with_annotations(
2751 struct_def.name.clone(),
2752 runtime_fields,
2753 field_annotations,
2754 );
2755 }
2756
2757 fn register_struct_type(
2762 &mut self,
2763 struct_def: &shape_ast::ast::StructTypeDef,
2764 span: shape_ast::ast::Span,
2765 ) -> Result<()> {
2766 use shape_runtime::type_schema::{FieldAnnotation, TypeSchemaBuilder};
2767
2768 for ann in &struct_def.annotations {
2770 self.validate_annotation_target_usage(
2771 ann,
2772 shape_ast::ast::functions::AnnotationTargetKind::Type,
2773 span,
2774 )?;
2775 }
2776
2777 if struct_def.native_layout.is_some() {
2778 self.native_layout_types.insert(struct_def.name.clone());
2779 } else {
2780 self.native_layout_types.remove(&struct_def.name);
2781 }
2782
2783 let runtime_field_names: Vec<String> = struct_def
2788 .fields
2789 .iter()
2790 .filter(|f| !f.is_comptime)
2791 .map(|f| f.name.clone())
2792 .collect();
2793 let runtime_field_types = struct_def
2794 .fields
2795 .iter()
2796 .filter(|f| !f.is_comptime)
2797 .map(|f| (f.name.clone(), f.type_annotation.clone()))
2798 .collect::<std::collections::HashMap<_, _>>();
2799 self.struct_types
2800 .insert(struct_def.name.clone(), (runtime_field_names, span));
2801 self.struct_generic_info.insert(
2802 struct_def.name.clone(),
2803 StructGenericInfo {
2804 type_params: struct_def.type_params.clone().unwrap_or_default(),
2805 runtime_field_types,
2806 },
2807 );
2808 self.comptime_context_struct_defs
2818 .insert(struct_def.name.clone(), struct_def.clone());
2819 self.predeclare_struct_schema(struct_def);
2820
2821 if self.execute_struct_comptime_handlers(struct_def)? {
2824 self.struct_types.remove(&struct_def.name);
2825 self.struct_generic_info.remove(&struct_def.name);
2826 self.comptime_context_struct_defs.remove(&struct_def.name);
2827 return Ok(());
2828 }
2829
2830 if struct_def.native_layout.is_some() {
2831 self.register_native_struct_layout(struct_def, span)?;
2832 }
2833
2834 if self
2836 .type_tracker
2837 .schema_registry()
2838 .get(&struct_def.name)
2839 .is_none()
2840 {
2841 let mut builder = TypeSchemaBuilder::new(struct_def.name.clone());
2842 for field in &struct_def.fields {
2843 if field.is_comptime {
2844 continue;
2845 }
2846 let field_type = Self::type_annotation_to_field_type(&field.type_annotation);
2847 let mut annotations = Vec::new();
2848 for ann in &field.annotations {
2849 let args: Vec<String> = ann
2850 .args
2851 .iter()
2852 .filter_map(Self::eval_annotation_arg)
2853 .collect();
2854 annotations.push(FieldAnnotation {
2855 name: ann.name.clone(),
2856 args,
2857 });
2858 }
2859 builder = builder.field_with_meta(field.name.clone(), field_type, annotations);
2860 }
2861 builder.register(self.type_tracker.schema_registry_mut());
2862 }
2863
2864 for field in &struct_def.fields {
2899 if !field.is_comptime {
2900 continue;
2901 }
2902 if let Some(ref default_expr) = field.default_value {
2903 match default_expr {
2904 Expr::Literal(Literal::Number(_), _)
2905 | Expr::Literal(Literal::Int(_), _)
2906 | Expr::Literal(Literal::String(_), _)
2907 | Expr::Literal(Literal::Bool(_), _)
2908 | Expr::Literal(Literal::None, _) => {
2909 }
2913 _ => {
2914 return Err(ShapeError::SemanticError {
2915 message: format!(
2916 "Comptime field '{}' on type '{}' must have a literal default value",
2917 field.name, struct_def.name
2918 ),
2919 location: None,
2920 });
2921 }
2922 }
2923 }
2924 }
2927
2928 self.maybe_generate_native_type_conversions(&struct_def.name, span)?;
2929
2930 Ok(())
2931 }
2932
2933 fn register_native_struct_layout(
2934 &mut self,
2935 struct_def: &shape_ast::ast::StructTypeDef,
2936 span: shape_ast::ast::Span,
2937 ) -> Result<()> {
2938 if struct_def.type_params.is_some() {
2939 return Err(ShapeError::SemanticError {
2940 message: format!(
2941 "type C '{}' cannot be generic in this version",
2942 struct_def.name
2943 ),
2944 location: Some(self.span_to_source_location(span)),
2945 });
2946 }
2947
2948 if struct_def.fields.iter().any(|f| f.is_comptime) {
2949 return Err(ShapeError::SemanticError {
2950 message: format!(
2951 "type C '{}' cannot contain comptime fields",
2952 struct_def.name
2953 ),
2954 location: Some(self.span_to_source_location(span)),
2955 });
2956 }
2957
2958 let abi = struct_def
2959 .native_layout
2960 .as_ref()
2961 .map(|b| b.abi.clone())
2962 .unwrap_or_else(|| "C".to_string());
2963 if abi != "C" {
2964 return Err(ShapeError::SemanticError {
2965 message: format!(
2966 "type '{}' uses unsupported native ABI '{}'; only C is supported",
2967 struct_def.name, abi
2968 ),
2969 location: Some(self.span_to_source_location(span)),
2970 });
2971 }
2972
2973 let mut struct_align: u64 = 1;
2974 let mut offset: u64 = 0;
2975 let mut field_layouts = Vec::with_capacity(struct_def.fields.len());
2976
2977 for field in &struct_def.fields {
2978 let field_spec =
2979 self.native_field_layout_spec(&field.type_annotation, span, &struct_def.name)?;
2980 struct_align = struct_align.max(field_spec.align);
2981 offset = Self::align_to(offset, field_spec.align);
2982 if offset > u32::MAX as u64
2983 || field_spec.size > u32::MAX as u64
2984 || field_spec.align > u32::MAX as u64
2985 {
2986 return Err(ShapeError::SemanticError {
2987 message: format!(
2988 "type C '{}' layout exceeds supported size/alignment limits",
2989 struct_def.name
2990 ),
2991 location: Some(self.span_to_source_location(span)),
2992 });
2993 }
2994 field_layouts.push(crate::bytecode::NativeStructFieldLayout {
2995 name: field.name.clone(),
2996 c_type: field_spec.c_type,
2997 offset: offset as u32,
2998 size: field_spec.size as u32,
2999 align: field_spec.align as u32,
3000 });
3001 offset = offset.saturating_add(field_spec.size);
3002 }
3003
3004 let size = Self::align_to(offset, struct_align);
3005 if size > u32::MAX as u64 || struct_align > u32::MAX as u64 {
3006 return Err(ShapeError::SemanticError {
3007 message: format!(
3008 "type C '{}' layout exceeds supported size/alignment limits",
3009 struct_def.name
3010 ),
3011 location: Some(self.span_to_source_location(span)),
3012 });
3013 }
3014
3015 let entry = crate::bytecode::NativeStructLayoutEntry {
3016 name: struct_def.name.clone(),
3017 abi,
3018 size: size as u32,
3019 align: struct_align as u32,
3020 fields: field_layouts,
3021 };
3022
3023 if let Some(existing) = self
3024 .program
3025 .native_struct_layouts
3026 .iter_mut()
3027 .find(|existing| existing.name == entry.name)
3028 {
3029 *existing = entry;
3030 } else {
3031 self.program.native_struct_layouts.push(entry);
3032 }
3033
3034 Ok(())
3035 }
3036
3037 fn align_to(value: u64, align: u64) -> u64 {
3038 debug_assert!(align > 0);
3039 let mask = align - 1;
3040 (value + mask) & !mask
3041 }
3042
3043 fn native_field_layout_spec(
3044 &self,
3045 ann: &shape_ast::ast::TypeAnnotation,
3046 span: shape_ast::ast::Span,
3047 struct_name: &str,
3048 ) -> Result<NativeFieldLayoutSpec> {
3049 use shape_ast::ast::TypeAnnotation;
3050
3051 let pointer = std::mem::size_of::<usize>() as u64;
3052
3053 let fail = || -> Result<NativeFieldLayoutSpec> {
3054 Err(ShapeError::SemanticError {
3055 message: format!(
3056 "unsupported type C field type '{}' in '{}'",
3057 ann.to_type_string(),
3058 struct_name
3059 ),
3060 location: Some(self.span_to_source_location(span)),
3061 })
3062 };
3063
3064 if let Some(name) = ann.as_type_name_str() {
3065 if let Some(existing) = self
3066 .program
3067 .native_struct_layouts
3068 .iter()
3069 .find(|layout| layout.name == name)
3070 {
3071 return Ok(NativeFieldLayoutSpec {
3072 c_type: name.to_string(),
3073 size: existing.size as u64,
3074 align: existing.align as u64,
3075 });
3076 }
3077
3078 let spec = match name {
3079 "f64" | "number" | "Number" | "float" => ("f64", 8, 8),
3080 "f32" => ("f32", 4, 4),
3081 "i64" | "int" | "integer" | "Int" | "Integer" => ("i64", 8, 8),
3082 "i32" => ("i32", 4, 4),
3083 "i16" => ("i16", 2, 2),
3084 "i8" | "char" => ("i8", 1, 1),
3085 "u64" => ("u64", 8, 8),
3086 "u32" => ("u32", 4, 4),
3087 "u16" => ("u16", 2, 2),
3088 "u8" | "byte" => ("u8", 1, 1),
3089 "bool" | "boolean" => ("bool", 1, 1),
3090 "isize" => ("isize", pointer, pointer),
3091 "usize" | "ptr" | "pointer" => ("ptr", pointer, pointer),
3092 "string" | "str" | "cstring" => ("cstring", pointer, pointer),
3093 _ => return fail(),
3094 };
3095 return Ok(NativeFieldLayoutSpec {
3096 c_type: spec.0.to_string(),
3097 size: spec.1,
3098 align: spec.2,
3099 });
3100 }
3101 match ann {
3102 TypeAnnotation::Generic { name, args } if name == "Option" && args.len() == 1 => {
3103 let inner = self.native_field_layout_spec(&args[0], span, struct_name)?;
3104 if inner.c_type == "cstring" {
3105 Ok(NativeFieldLayoutSpec {
3106 c_type: "cstring?".to_string(),
3107 size: pointer,
3108 align: pointer,
3109 })
3110 } else {
3111 fail()
3112 }
3113 }
3114 _ => fail(),
3115 }
3116 }
3117
3118 fn maybe_generate_native_type_conversions(
3119 &mut self,
3120 type_name: &str,
3121 span: shape_ast::ast::Span,
3122 ) -> Result<()> {
3123 let pair = if self.native_layout_types.contains(type_name) {
3124 let Some(object_type) = Self::object_type_name_for_native_layout(type_name) else {
3125 return Ok(());
3126 };
3127 if !self.struct_types.contains_key(&object_type)
3128 || self.native_layout_types.contains(&object_type)
3129 {
3130 return Ok(());
3131 }
3132 (type_name.to_string(), object_type)
3133 } else {
3134 let candidates: Vec<String> = Self::native_layout_name_candidates_for_object(type_name)
3135 .into_iter()
3136 .filter(|candidate| self.native_layout_types.contains(candidate))
3137 .collect();
3138 if candidates.is_empty() {
3139 return Ok(());
3140 }
3141 if candidates.len() > 1 {
3142 return Err(ShapeError::SemanticError {
3143 message: format!(
3144 "type '{}' matches multiple `type C` companions ({}) - use one canonical name",
3145 type_name,
3146 candidates.join(", ")
3147 ),
3148 location: Some(self.span_to_source_location(span)),
3149 });
3150 }
3151 (candidates[0].clone(), type_name.to_string())
3152 };
3153
3154 let pair_key = format!("{}::{}", pair.0, pair.1);
3155 if self.generated_native_conversion_pairs.contains(&pair_key) {
3156 return Ok(());
3157 }
3158
3159 self.validate_native_conversion_pair(&pair.0, &pair.1, span)?;
3160 self.generate_native_conversion_direction(&pair.0, &pair.1, span)?;
3161 self.generate_native_conversion_direction(&pair.1, &pair.0, span)?;
3162 self.generated_native_conversion_pairs.insert(pair_key);
3163 Ok(())
3164 }
3165
3166 fn object_type_name_for_native_layout(name: &str) -> Option<String> {
3167 if let Some(base) = name.strip_suffix("Layout")
3168 && !base.is_empty()
3169 {
3170 return Some(base.to_string());
3171 }
3172 if let Some(base) = name.strip_suffix('C')
3173 && !base.is_empty()
3174 {
3175 return Some(base.to_string());
3176 }
3177 if let Some(base) = name.strip_prefix('C')
3178 && !base.is_empty()
3179 && base
3180 .chars()
3181 .next()
3182 .map(|ch| ch.is_ascii_uppercase())
3183 .unwrap_or(false)
3184 {
3185 return Some(base.to_string());
3186 }
3187 None
3188 }
3189
3190 fn native_layout_name_candidates_for_object(name: &str) -> Vec<String> {
3191 vec![
3192 format!("{}Layout", name),
3193 format!("{}C", name),
3194 format!("C{}", name),
3195 ]
3196 }
3197
3198 fn validate_native_conversion_pair(
3199 &self,
3200 c_type: &str,
3201 object_type: &str,
3202 span: shape_ast::ast::Span,
3203 ) -> Result<()> {
3204 if !self.native_layout_types.contains(c_type) {
3205 return Err(ShapeError::SemanticError {
3206 message: format!("'{}' is not declared as `type C`", c_type),
3207 location: Some(self.span_to_source_location(span)),
3208 });
3209 }
3210 if self.native_layout_types.contains(object_type) {
3211 return Err(ShapeError::SemanticError {
3212 message: format!(
3213 "auto conversion target '{}' cannot also be declared as `type C`",
3214 object_type
3215 ),
3216 location: Some(self.span_to_source_location(span)),
3217 });
3218 }
3219
3220 let c_type_info =
3221 self.struct_generic_info
3222 .get(c_type)
3223 .ok_or_else(|| ShapeError::SemanticError {
3224 message: format!("missing compiler metadata for `type C {}`", c_type),
3225 location: Some(self.span_to_source_location(span)),
3226 })?;
3227 let object_type_info =
3228 self.struct_generic_info
3229 .get(object_type)
3230 .ok_or_else(|| ShapeError::SemanticError {
3231 message: format!(
3232 "missing compiler metadata for companion type '{}'",
3233 object_type
3234 ),
3235 location: Some(self.span_to_source_location(span)),
3236 })?;
3237
3238 if !c_type_info.type_params.is_empty() || !object_type_info.type_params.is_empty() {
3239 return Err(ShapeError::SemanticError {
3240 message: format!(
3241 "auto `type C` conversions currently require non-generic types (`{}` <-> `{}`)",
3242 c_type, object_type
3243 ),
3244 location: Some(self.span_to_source_location(span)),
3245 });
3246 }
3247
3248 let c_fields = self
3249 .struct_types
3250 .get(c_type)
3251 .map(|(fields, _)| fields)
3252 .ok_or_else(|| ShapeError::SemanticError {
3253 message: format!("missing field metadata for `type C {}`", c_type),
3254 location: Some(self.span_to_source_location(span)),
3255 })?;
3256 let object_fields = self
3257 .struct_types
3258 .get(object_type)
3259 .map(|(fields, _)| fields)
3260 .ok_or_else(|| ShapeError::SemanticError {
3261 message: format!(
3262 "missing field metadata for companion type '{}'",
3263 object_type
3264 ),
3265 location: Some(self.span_to_source_location(span)),
3266 })?;
3267
3268 let c_field_set: std::collections::HashSet<&str> =
3269 c_fields.iter().map(String::as_str).collect();
3270 let object_field_set: std::collections::HashSet<&str> =
3271 object_fields.iter().map(String::as_str).collect();
3272 if c_field_set != object_field_set {
3273 return Err(ShapeError::SemanticError {
3274 message: format!(
3275 "auto conversion pair '{}' <-> '{}' must have identical runtime fields",
3276 c_type, object_type
3277 ),
3278 location: Some(self.span_to_source_location(span)),
3279 });
3280 }
3281
3282 for field_name in c_field_set {
3283 let c_ann = c_type_info
3284 .runtime_field_types
3285 .get(field_name)
3286 .ok_or_else(|| ShapeError::SemanticError {
3287 message: format!(
3288 "missing type metadata for field '{}.{}'",
3289 c_type, field_name
3290 ),
3291 location: Some(self.span_to_source_location(span)),
3292 })?;
3293 let object_ann = object_type_info
3294 .runtime_field_types
3295 .get(field_name)
3296 .ok_or_else(|| ShapeError::SemanticError {
3297 message: format!(
3298 "missing type metadata for field '{}.{}'",
3299 object_type, field_name
3300 ),
3301 location: Some(self.span_to_source_location(span)),
3302 })?;
3303 if c_ann != object_ann {
3304 return Err(ShapeError::SemanticError {
3305 message: format!(
3306 "field type mismatch for auto conversion '{}.{}' (`{}`) vs '{}.{}' (`{}`)",
3307 c_type,
3308 field_name,
3309 c_ann.to_type_string(),
3310 object_type,
3311 field_name,
3312 object_ann.to_type_string()
3313 ),
3314 location: Some(self.span_to_source_location(span)),
3315 });
3316 }
3317 }
3318
3319 Ok(())
3320 }
3321
3322 fn generate_native_conversion_direction(
3323 &mut self,
3324 source_type: &str,
3325 target_type: &str,
3326 span: shape_ast::ast::Span,
3327 ) -> Result<()> {
3328 let fn_name = format!(
3329 "__auto_native_from_{}_to_{}",
3330 Self::sanitize_auto_symbol(source_type),
3331 Self::sanitize_auto_symbol(target_type)
3332 );
3333 if self.function_defs.contains_key(&fn_name) {
3334 return Ok(());
3335 }
3336
3337 let target_fields = self
3338 .struct_types
3339 .get(target_type)
3340 .map(|(fields, _)| fields.clone())
3341 .ok_or_else(|| ShapeError::SemanticError {
3342 message: format!(
3343 "missing target type metadata for auto conversion '{}'",
3344 target_type
3345 ),
3346 location: Some(self.span_to_source_location(span)),
3347 })?;
3348
3349 let source_expr = Expr::Identifier("value".to_string(), span);
3350 let struct_fields = target_fields
3351 .iter()
3352 .map(|field| {
3353 (
3354 field.clone(),
3355 Expr::PropertyAccess {
3356 object: Box::new(source_expr.clone()),
3357 property: field.clone(),
3358 optional: false,
3359 span,
3360 },
3361 )
3362 })
3363 .collect::<Vec<_>>();
3364 let body = vec![Statement::Return(
3365 Some(Expr::StructLiteral {
3366 type_name: target_type.into(),
3367 fields: struct_fields,
3368 span,
3369 }),
3370 span,
3371 )];
3372 let fn_def = FunctionDef {
3373 name: fn_name.clone(),
3374 name_span: span,
3375 declaring_module_path: None,
3376 doc_comment: None,
3377 params: vec![FunctionParameter {
3378 pattern: DestructurePattern::Identifier("value".to_string(), span),
3379 is_const: false,
3380 is_reference: false,
3381 is_mut_reference: false,
3382 is_out: false,
3383 type_annotation: Some(TypeAnnotation::Reference(source_type.into())),
3384 default_value: None,
3385 }],
3386 return_type: Some(TypeAnnotation::Reference(target_type.into())),
3387 body,
3388 type_params: Some(Vec::new()),
3389 annotations: Vec::new(),
3390 is_async: false,
3391 is_comptime: false,
3392 where_clause: None,
3393 };
3394 self.register_function(&fn_def)?;
3395 self.compile_function(&fn_def)?;
3396
3397 self.program.register_trait_method_symbol(
3398 "From",
3399 target_type,
3400 Some(source_type),
3401 "from",
3402 &fn_name,
3403 );
3404 self.program.register_trait_method_symbol(
3405 "Into",
3406 source_type,
3407 Some(target_type),
3408 "into",
3409 &fn_name,
3410 );
3411 let _ = self.type_inference.env.register_trait_impl_named(
3412 "From",
3413 target_type,
3414 source_type,
3415 vec!["from".to_string()],
3416 );
3417 let _ = self.type_inference.env.register_trait_impl_named(
3418 "Into",
3419 source_type,
3420 target_type,
3421 vec!["into".to_string()],
3422 );
3423 Ok(())
3424 }
3425
3426 fn sanitize_auto_symbol(name: &str) -> String {
3427 let mut out = String::with_capacity(name.len());
3428 for ch in name.chars() {
3429 if ch.is_ascii_alphanumeric() {
3430 out.push(ch);
3431 } else {
3432 out.push('_');
3433 }
3434 }
3435 out
3436 }
3437
3438 fn execute_struct_comptime_handlers(
3443 &mut self,
3444 struct_def: &shape_ast::ast::StructTypeDef,
3445 ) -> Result<bool> {
3446 let mut removed = false;
3447 for ann in &struct_def.annotations {
3448 if let Some((_, compiled)) = self.lookup_compiled_annotation(ann) {
3449 let handlers = [
3450 compiled.comptime_pre_handler,
3451 compiled.comptime_post_handler,
3452 ];
3453 for handler in handlers.into_iter().flatten() {
3454 let fields: Vec<(
3457 String,
3458 Option<shape_ast::ast::TypeAnnotation>,
3459 Vec<shape_ast::ast::functions::Annotation>,
3460 )> = struct_def
3461 .fields
3462 .iter()
3463 .map(|f| {
3464 (
3465 f.name.clone(),
3466 Some(f.type_annotation.clone()),
3467 f.annotations.clone(),
3468 )
3469 })
3470 .collect();
3471
3472 let target = super::comptime_target::ComptimeTarget::from_type(
3473 &struct_def.name,
3474 &fields,
3475 );
3476 let target_value = target.to_nanboxed()?;
3480 let target_name = struct_def.name.clone();
3481 let handler_span = handler.span;
3482 let execution = self.execute_comptime_annotation_handler(
3483 ann,
3484 &handler,
3485 target_value,
3486 &compiled.param_names,
3487 &[],
3488 )?;
3489
3490 if self
3491 .process_comptime_directives(execution.directives, &target_name)
3492 .map_err(|e| ShapeError::RuntimeError {
3493 message: format!(
3494 "Comptime handler '{}' directive processing failed: {}",
3495 ann.name, e
3496 ),
3497 location: Some(self.span_to_source_location(handler_span)),
3498 })?
3499 {
3500 removed = true;
3501 break;
3502 }
3503 }
3504 }
3505 if removed {
3506 break;
3507 }
3508 }
3509 Ok(removed)
3510 }
3511
3512 fn current_module_path_for(&self, module_name: &str) -> String {
3513 if let Some(parent) = self.module_scope_stack.last() {
3514 format!("{}::{}", parent, module_name)
3515 } else {
3516 module_name.to_string()
3517 }
3518 }
3519
3520 pub(super) fn qualify_module_symbol(module_path: &str, name: &str) -> String {
3521 format!("{}::{}", module_path, name)
3522 }
3523
3524 fn const_initializer_is_comptime_evaluable(expr: &shape_ast::ast::Expr) -> bool {
3536 use shape_ast::ast::Expr;
3537 match expr {
3538 Expr::Literal(_, _) => true,
3539 Expr::UnaryOp { operand, .. } => {
3540 Self::const_initializer_is_comptime_evaluable(operand)
3541 }
3542 _ => false,
3543 }
3544 }
3545
3546 fn is_builtin_type_name(name: &str) -> bool {
3549 matches!(
3550 name,
3551 "int" | "number" | "string" | "bool" | "decimal" | "bigint"
3552 | "Array" | "HashMap" | "Option" | "Result" | "DateTime"
3553 | "Content" | "Table" | "DataTable" | "Mat"
3554 | "Code" | "KeyValue"
3561 | "Json" | "Duration" | "Regex"
3562 | "Vec"
3563 | "int8" | "int16" | "int32" | "int64"
3564 | "uint8" | "uint16" | "uint32" | "uint64"
3565 | "float32" | "float64"
3566 | "IoHandle"
3567 )
3568 }
3569
3570 fn qualify_type_name(
3571 type_name: &shape_ast::ast::TypeName,
3572 module_path: &str,
3573 ) -> shape_ast::ast::TypeName {
3574 match type_name {
3575 shape_ast::ast::TypeName::Simple(path)
3576 if !path.is_qualified() && !Self::is_builtin_type_name(path.as_str()) =>
3577 {
3578 shape_ast::ast::TypeName::Simple(
3579 Self::qualify_module_symbol(module_path, path.as_str()).into(),
3580 )
3581 }
3582 shape_ast::ast::TypeName::Generic { name, type_args }
3583 if !name.is_qualified() && !Self::is_builtin_type_name(name.as_str()) =>
3584 {
3585 shape_ast::ast::TypeName::Generic {
3586 name: Self::qualify_module_symbol(module_path, name.as_str()).into(),
3587 type_args: type_args.clone(),
3588 }
3589 }
3590 _ => type_name.clone(),
3591 }
3592 }
3593
3594 pub(super) fn qualify_module_item(&self, item: &Item, module_path: &str) -> Result<Item> {
3595 match item {
3596 Item::Function(func, span) => {
3597 let mut qualified = func.clone();
3598 qualified.name = Self::qualify_module_symbol(module_path, &func.name);
3599 Ok(Item::Function(qualified, *span))
3600 }
3601 Item::Export(export, span) if export.source_decl.is_none() => {
3602 let mut qualified = export.clone();
3603 match &mut qualified.item {
3604 ExportItem::Function(func) => {
3605 func.name = Self::qualify_module_symbol(module_path, &func.name);
3606 }
3607 ExportItem::BuiltinFunction(func) => {
3608 func.name = Self::qualify_module_symbol(module_path, &func.name);
3609 }
3610 ExportItem::ForeignFunction(func) => {
3611 func.name = Self::qualify_module_symbol(module_path, &func.name);
3612 }
3613 ExportItem::Annotation(annotation) => {
3614 annotation.name =
3615 Self::qualify_module_symbol(module_path, &annotation.name);
3616 }
3617 ExportItem::Struct(def) => {
3618 def.name = Self::qualify_module_symbol(module_path, &def.name);
3619 }
3620 ExportItem::Enum(def) => {
3621 def.name = Self::qualify_module_symbol(module_path, &def.name);
3622 }
3623 ExportItem::TypeAlias(def) => {
3624 def.name = Self::qualify_module_symbol(module_path, &def.name);
3625 }
3626 ExportItem::Trait(def) => {
3627 def.name = Self::qualify_module_symbol(module_path, &def.name);
3628 }
3629 _ => {}
3630 }
3631 Ok(Item::Export(qualified, *span))
3632 }
3633 Item::BuiltinFunctionDecl(def, span) => {
3634 let mut qualified = def.clone();
3635 qualified.name = Self::qualify_module_symbol(module_path, &def.name);
3636 Ok(Item::BuiltinFunctionDecl(qualified, *span))
3637 }
3638 Item::AnnotationDef(def, span) => {
3639 let mut qualified = def.clone();
3640 qualified.name = Self::qualify_module_symbol(module_path, &def.name);
3641 Ok(Item::AnnotationDef(qualified, *span))
3642 }
3643 Item::VariableDecl(decl, span) => {
3644 if decl.kind != VarKind::Const {
3645 return Err(ShapeError::SemanticError {
3646 message: "module-level variable declarations currently require `const`"
3647 .to_string(),
3648 location: Some(self.span_to_source_location(*span)),
3649 });
3650 }
3651 let mut qualified = decl.clone();
3652 let Some(name) = decl.pattern.as_identifier() else {
3653 return Err(ShapeError::SemanticError {
3654 message:
3655 "module-level constants currently require a simple identifier binding"
3656 .to_string(),
3657 location: Some(self.span_to_source_location(*span)),
3658 });
3659 };
3660 qualified.pattern = DestructurePattern::Identifier(
3661 Self::qualify_module_symbol(module_path, name),
3662 *span,
3663 );
3664 Ok(Item::VariableDecl(qualified, *span))
3665 }
3666 Item::Statement(Statement::VariableDecl(decl, stmt_span), item_span) => {
3667 if decl.kind != VarKind::Const {
3668 return Err(ShapeError::SemanticError {
3669 message: "module-level variable declarations currently require `const`"
3670 .to_string(),
3671 location: Some(self.span_to_source_location(*stmt_span)),
3672 });
3673 }
3674 let mut qualified = decl.clone();
3675 let Some(name) = decl.pattern.as_identifier() else {
3676 return Err(ShapeError::SemanticError {
3677 message:
3678 "module-level constants currently require a simple identifier binding"
3679 .to_string(),
3680 location: Some(self.span_to_source_location(*stmt_span)),
3681 });
3682 };
3683 qualified.pattern = DestructurePattern::Identifier(
3684 Self::qualify_module_symbol(module_path, name),
3685 *stmt_span,
3686 );
3687 Ok(Item::Statement(
3688 Statement::VariableDecl(qualified, *stmt_span),
3689 *item_span,
3690 ))
3691 }
3692 Item::Statement(Statement::Assignment(assign, stmt_span), item_span) => {
3693 let mut qualified = assign.clone();
3694 if let Some(name) = assign.pattern.as_identifier() {
3695 qualified.pattern = DestructurePattern::Identifier(
3696 Self::qualify_module_symbol(module_path, name),
3697 *stmt_span,
3698 );
3699 }
3700 Ok(Item::Statement(
3701 Statement::Assignment(qualified, *stmt_span),
3702 *item_span,
3703 ))
3704 }
3705 Item::Export(export, span) if export.source_decl.is_some() => {
3706 let decl = export.source_decl.as_ref().unwrap();
3708 if decl.kind != VarKind::Const {
3709 return Err(ShapeError::SemanticError {
3710 message: "module-level variable declarations currently require `const`"
3711 .to_string(),
3712 location: Some(self.span_to_source_location(*span)),
3713 });
3714 }
3715 let mut qualified = decl.clone();
3716 let Some(name) = decl.pattern.as_identifier() else {
3717 return Err(ShapeError::SemanticError {
3718 message:
3719 "module-level constants currently require a simple identifier binding"
3720 .to_string(),
3721 location: Some(self.span_to_source_location(*span)),
3722 });
3723 };
3724 qualified.pattern = DestructurePattern::Identifier(
3725 Self::qualify_module_symbol(module_path, name),
3726 *span,
3727 );
3728 Ok(Item::VariableDecl(qualified, *span))
3729 }
3730 Item::StructType(def, span) => {
3731 let mut q = def.clone();
3732 q.name = Self::qualify_module_symbol(module_path, &def.name);
3733 Ok(Item::StructType(q, *span))
3734 }
3735 Item::Enum(def, span) => {
3736 let mut q = def.clone();
3737 q.name = Self::qualify_module_symbol(module_path, &def.name);
3738 Ok(Item::Enum(q, *span))
3739 }
3740 Item::TypeAlias(def, span) => {
3741 let mut q = def.clone();
3742 q.name = Self::qualify_module_symbol(module_path, &def.name);
3743 Ok(Item::TypeAlias(q, *span))
3744 }
3745 Item::Trait(def, span) => {
3746 let mut q = def.clone();
3747 q.name = Self::qualify_module_symbol(module_path, &def.name);
3748 Ok(Item::Trait(q, *span))
3749 }
3750 Item::Extend(extend, span) => {
3751 let mut q = extend.clone();
3752 q.type_name = Self::qualify_type_name(&extend.type_name, module_path);
3753 Ok(Item::Extend(q, *span))
3754 }
3755 Item::Impl(impl_block, span) => {
3756 let mut q = impl_block.clone();
3757 q.target_type = Self::qualify_type_name(&impl_block.target_type, module_path);
3758 Ok(Item::Impl(q, *span))
3760 }
3761 _ => Ok(item.clone()),
3762 }
3763 }
3764
3765 pub(super) fn collect_module_runtime_exports(
3766 &self,
3767 items: &[Item],
3768 module_path: &str,
3769 ) -> Vec<(String, String)> {
3770 let mut exports = Vec::new();
3771 let has_explicit_exports = items.iter().any(|item| matches!(item, Item::Export(..)));
3772
3773 if has_explicit_exports {
3774 for item in items {
3775 let Item::Export(export, _) = item else {
3776 continue;
3777 };
3778 if let Some(ref decl) = export.source_decl {
3779 if let Some(name) = decl.pattern.as_identifier() {
3780 exports.push((
3781 name.to_string(),
3782 Self::qualify_module_symbol(module_path, name),
3783 ));
3784 }
3785 }
3786 match &export.item {
3787 ExportItem::Function(func) => {
3788 let exported_name = func
3789 .name
3790 .rsplit("::")
3791 .next()
3792 .unwrap_or(func.name.as_str())
3793 .to_string();
3794 exports.push((
3795 exported_name.clone(),
3796 Self::qualify_module_symbol(module_path, &exported_name),
3797 ));
3798 }
3799 ExportItem::ForeignFunction(func) => {
3800 let exported_name = func
3801 .name
3802 .rsplit("::")
3803 .next()
3804 .unwrap_or(func.name.as_str())
3805 .to_string();
3806 exports.push((
3807 exported_name.clone(),
3808 Self::qualify_module_symbol(module_path, &exported_name),
3809 ));
3810 }
3811 ExportItem::Named(specs) => {
3812 for spec in specs {
3813 let exported_name =
3814 spec.alias.clone().unwrap_or_else(|| spec.name.clone());
3815 exports.push((
3816 exported_name,
3817 Self::qualify_module_symbol(module_path, &spec.name),
3818 ));
3819 }
3820 }
3821 ExportItem::Annotation(_) => {}
3829 _ => {}
3830 }
3831 }
3832 exports.sort_by(|a, b| a.0.cmp(&b.0));
3833 exports.dedup_by(|a, b| a.0 == b.0);
3834 return exports;
3835 }
3836
3837 for item in items {
3838 match item {
3839 Item::Function(func, _) => {
3840 exports.push((
3841 func.name.clone(),
3842 Self::qualify_module_symbol(module_path, &func.name),
3843 ));
3844 }
3845 Item::VariableDecl(decl, _) => {
3846 if decl.kind == VarKind::Const
3847 && let Some(name) = decl.pattern.as_identifier()
3848 {
3849 exports.push((
3850 name.to_string(),
3851 Self::qualify_module_symbol(module_path, name),
3852 ));
3853 }
3854 }
3855 Item::Statement(Statement::VariableDecl(decl, _), _) => {
3856 if decl.kind == VarKind::Const
3857 && let Some(name) = decl.pattern.as_identifier()
3858 {
3859 exports.push((
3860 name.to_string(),
3861 Self::qualify_module_symbol(module_path, name),
3862 ));
3863 }
3864 }
3865 Item::Export(export, _) => {
3866 if let Some(ref decl) = export.source_decl {
3867 if let Some(name) = decl.pattern.as_identifier() {
3868 exports.push((
3869 name.to_string(),
3870 Self::qualify_module_symbol(module_path, name),
3871 ));
3872 }
3873 }
3874 }
3875 Item::Module(module, _) => {
3876 exports.push((
3877 module.name.clone(),
3878 Self::qualify_module_symbol(module_path, &module.name),
3879 ));
3880 }
3881 Item::AnnotationDef(_, _) => {}
3884 _ => {}
3889 }
3890 }
3891 exports.sort_by(|a, b| a.0.cmp(&b.0));
3892 exports.dedup_by(|a, b| a.0 == b.0);
3893 exports
3894 }
3895
3896 fn module_target_fields(items: &[Item]) -> Vec<(String, String)> {
3897 let mut fields = Vec::new();
3898 for item in items {
3899 match item {
3900 Item::Function(func, _) => fields.push((func.name.clone(), "function".to_string())),
3901 Item::VariableDecl(decl, _) => {
3902 if let Some(name) = decl.pattern.as_identifier() {
3903 let type_name = decl
3904 .type_annotation
3905 .as_ref()
3906 .and_then(TypeAnnotation::as_simple_name)
3907 .unwrap_or("any")
3908 .to_string();
3909 fields.push((name.to_string(), type_name));
3910 }
3911 }
3912 Item::Statement(Statement::VariableDecl(decl, _), _) => {
3913 if let Some(name) = decl.pattern.as_identifier() {
3914 let type_name = decl
3915 .type_annotation
3916 .as_ref()
3917 .and_then(TypeAnnotation::as_simple_name)
3918 .unwrap_or("any")
3919 .to_string();
3920 fields.push((name.to_string(), type_name));
3921 }
3922 }
3923 Item::Export(export, _) => {
3924 if let Some(ref decl) = export.source_decl {
3925 if let Some(name) = decl.pattern.as_identifier() {
3926 let type_name = decl
3927 .type_annotation
3928 .as_ref()
3929 .and_then(TypeAnnotation::as_simple_name)
3930 .unwrap_or("any")
3931 .to_string();
3932 fields.push((name.to_string(), type_name));
3933 }
3934 }
3935 }
3936 Item::StructType(def, _) => fields.push((def.name.clone(), "type".to_string())),
3937 Item::Enum(def, _) => fields.push((def.name.clone(), "type".to_string())),
3938 Item::TypeAlias(def, _) => fields.push((def.name.clone(), "type".to_string())),
3939 Item::Module(def, _) => fields.push((def.name.clone(), "module".to_string())),
3940 Item::AnnotationDef(def, _) => {
3942 fields.push((def.name.clone(), "annotation".to_string()))
3943 }
3944 _ => {}
3945 }
3946 }
3947 fields
3948 }
3949
3950 fn process_comptime_directives_for_module(
3951 &mut self,
3952 directives: Vec<super::comptime_builtins::ComptimeDirective>,
3953 module_name: &str,
3954 module_items: &mut Vec<Item>,
3955 ) -> std::result::Result<bool, String> {
3956 let mut removed = false;
3957 for directive in directives {
3958 match directive {
3959 super::comptime_builtins::ComptimeDirective::Extend(extend) => {
3960 self.apply_comptime_extend(extend, module_name)
3961 .map_err(|e| e.to_string())?;
3962 }
3963 super::comptime_builtins::ComptimeDirective::RemoveTarget => {
3964 removed = true;
3965 break;
3966 }
3967 super::comptime_builtins::ComptimeDirective::ReplaceModule { items } => {
3968 *module_items = items;
3969 }
3970 super::comptime_builtins::ComptimeDirective::SetParamType { .. }
3971 | super::comptime_builtins::ComptimeDirective::SetParamValue { .. } => {
3972 return Err(
3973 "`set param` directives are only valid when compiling function targets"
3974 .to_string(),
3975 );
3976 }
3977 super::comptime_builtins::ComptimeDirective::SetReturnType { .. } => {
3978 return Err(
3979 "`set return` directives are only valid when compiling function targets"
3980 .to_string(),
3981 );
3982 }
3983 super::comptime_builtins::ComptimeDirective::ReplaceBody { .. } => {
3984 return Err(
3985 "`replace body` directives are only valid when compiling function targets"
3986 .to_string(),
3987 );
3988 }
3989 }
3990 }
3991 Ok(removed)
3992 }
3993
3994 fn execute_module_comptime_handlers(
3995 &mut self,
3996 module_def: &ModuleDecl,
3997 module_path: &str,
3998 module_items: &mut Vec<Item>,
3999 ) -> Result<bool> {
4000 let mut removed = false;
4001 for ann in &module_def.annotations {
4002 if let Some((_, compiled)) = self.lookup_compiled_annotation(ann) {
4003 let handlers = [
4004 compiled.comptime_pre_handler,
4005 compiled.comptime_post_handler,
4006 ];
4007 for handler in handlers.into_iter().flatten() {
4008 let target = super::comptime_target::ComptimeTarget::from_module(
4009 module_path,
4010 &Self::module_target_fields(module_items),
4011 );
4012 let target_value = target.to_nanboxed()?;
4016 let handler_span = handler.span;
4017 let execution = self.execute_comptime_annotation_handler(
4018 ann,
4019 &handler,
4020 target_value,
4021 &compiled.param_names,
4022 &[],
4023 )?;
4024 if self
4025 .process_comptime_directives_for_module(
4026 execution.directives,
4027 module_path,
4028 module_items,
4029 )
4030 .map_err(|e| ShapeError::RuntimeError {
4031 message: format!(
4032 "Comptime handler '{}' directive processing failed: {}",
4033 ann.name, e
4034 ),
4035 location: Some(self.span_to_source_location(handler_span)),
4036 })?
4037 {
4038 removed = true;
4039 break;
4040 }
4041 }
4042 }
4043 if removed {
4044 break;
4045 }
4046 }
4047 Ok(removed)
4048 }
4049
4050 fn inject_module_local_comptime_helper_aliases(
4051 &self,
4052 module_path: &str,
4053 helpers: &mut Vec<FunctionDef>,
4054 ) {
4055 let module_prefix = format!("{}::", module_path);
4056 let mut seen: std::collections::HashSet<String> =
4057 helpers.iter().map(|h| h.name.clone()).collect();
4058 let mut aliases = Vec::new();
4059
4060 for helper in helpers.iter() {
4061 let Some(local_name) = helper.name.strip_prefix(&module_prefix) else {
4062 continue;
4063 };
4064 if local_name.contains("::") || !seen.insert(local_name.to_string()) {
4065 continue;
4066 }
4067 let mut alias = helper.clone();
4068 alias.name = local_name.to_string();
4069 aliases.push(alias);
4070 }
4071
4072 helpers.extend(aliases);
4073 }
4074
4075 fn execute_module_inline_comptime_blocks(
4076 &mut self,
4077 module_path: &str,
4078 module_items: &mut Vec<Item>,
4079 ) -> Result<bool> {
4080 loop {
4081 let Some(idx) = module_items
4082 .iter()
4083 .position(|item| matches!(item, Item::Comptime(_, _)))
4084 else {
4085 break;
4086 };
4087
4088 let (stmts, span) = match module_items[idx].clone() {
4089 Item::Comptime(stmts, span) => (stmts, span),
4090 _ => unreachable!("index is guarded by position() matcher"),
4091 };
4092
4093 let extensions: Vec<_> = self
4094 .extension_registry
4095 .as_ref()
4096 .map(|r| r.as_ref().clone())
4097 .unwrap_or_default();
4098 let trait_impls = self.type_inference.env.trait_impl_keys();
4099 let known_type_symbols: std::collections::HashSet<String> = self
4100 .struct_types
4101 .keys()
4102 .chain(self.type_aliases.keys())
4103 .cloned()
4104 .collect();
4105 let mut comptime_helpers = self.collect_comptime_helpers();
4106 self.inject_module_local_comptime_helper_aliases(module_path, &mut comptime_helpers);
4107
4108 let type_snapshot = super::comptime_builtins::build_type_reflection_snapshot(
4111 self,
4112 &[],
4113 );
4114 let comptime_impl_blocks = self.comptime_impl_blocks.clone();
4117 let comptime_context_trait_defs: Vec<_> =
4118 self.trait_defs.values().cloned().collect();
4119 let comptime_context_struct_defs: Vec<_> = self
4120 .comptime_context_struct_defs
4121 .values()
4122 .cloned()
4123 .collect();
4124 let execution = super::comptime::execute_comptime_with_context(
4125 &stmts,
4126 &comptime_helpers,
4127 &comptime_impl_blocks,
4128 &comptime_context_trait_defs,
4129 &comptime_context_struct_defs,
4130 &extensions,
4131 trait_impls,
4132 known_type_symbols,
4133 type_snapshot,
4134 )
4135 .map_err(|e| ShapeError::RuntimeError {
4136 message: format!(
4137 "Comptime block evaluation failed: {}",
4138 super::helpers::strip_error_prefix(&e)
4139 ),
4140 location: Some(self.span_to_source_location(span)),
4141 })?;
4142
4143 if self
4144 .process_comptime_directives_for_module(
4145 execution.directives,
4146 module_path,
4147 module_items,
4148 )
4149 .map_err(|e| ShapeError::RuntimeError {
4150 message: format!("Comptime block directive processing failed: {}", e),
4151 location: Some(self.span_to_source_location(span)),
4152 })?
4153 {
4154 return Ok(true);
4155 }
4156
4157 if idx < module_items.len() && matches!(module_items[idx], Item::Comptime(_, _)) {
4158 module_items.remove(idx);
4159 }
4160 }
4161
4162 Ok(false)
4163 }
4164
4165 pub(super) fn register_missing_module_items(&mut self, item: &Item) -> Result<()> {
4166 match item {
4167 Item::Function(func, _) => {
4168 if !self.function_defs.contains_key(&func.name) {
4169 self.register_function(func)?;
4170 }
4171 Ok(())
4172 }
4173 Item::Trait(trait_def, _) => {
4174 if !self.trait_defs.contains_key(&trait_def.name) {
4175 self.known_traits.insert(trait_def.name.clone());
4176 self.trait_defs
4177 .insert(trait_def.name.clone(), trait_def.clone());
4178 self.type_inference.env.define_trait(trait_def);
4179 }
4180 Ok(())
4181 }
4182 Item::Enum(enum_def, _) => {
4183 self.register_enum(enum_def)?;
4184 Ok(())
4185 }
4186 Item::StructType(struct_def, span) => {
4187 let existing_is_empty = self
4203 .struct_types
4204 .get(&struct_def.name)
4205 .map(|(names, _)| names.is_empty())
4206 .unwrap_or(false);
4207 let has_real_fields = struct_def
4208 .fields
4209 .iter()
4210 .any(|f| !f.is_comptime);
4211 if !self.struct_types.contains_key(&struct_def.name)
4212 || (existing_is_empty && has_real_fields)
4213 {
4214 let runtime_field_names: Vec<String> = struct_def
4215 .fields
4216 .iter()
4217 .filter(|f| !f.is_comptime)
4218 .map(|f| f.name.clone())
4219 .collect();
4220 let runtime_field_types = struct_def
4221 .fields
4222 .iter()
4223 .filter(|f| !f.is_comptime)
4224 .map(|f| (f.name.clone(), f.type_annotation.clone()))
4225 .collect::<std::collections::HashMap<_, _>>();
4226 self.struct_types.insert(
4227 struct_def.name.clone(),
4228 (runtime_field_names, *span),
4229 );
4230 self.struct_generic_info.insert(
4231 struct_def.name.clone(),
4232 StructGenericInfo {
4233 type_params: struct_def.type_params.clone().unwrap_or_default(),
4234 runtime_field_types,
4235 },
4236 );
4237 self.comptime_context_struct_defs
4246 .insert(struct_def.name.clone(), struct_def.clone());
4247 }
4248 Ok(())
4249 }
4250 Item::TypeAlias(type_alias, _) => {
4251 if !self.type_aliases.contains_key(&type_alias.name) {
4252 let base_type_name = match &type_alias.type_annotation {
4253 TypeAnnotation::Basic(name) => Some(name.clone()),
4254 TypeAnnotation::Reference(name) => Some(name.to_string()),
4255 _ => None,
4256 };
4257 self.type_aliases.insert(
4258 type_alias.name.clone(),
4259 base_type_name.unwrap_or_else(|| {
4260 format!("{:?}", type_alias.type_annotation)
4261 }),
4262 );
4263 self.type_inference.env.define_type_alias(
4264 &type_alias.name,
4265 &type_alias.type_annotation,
4266 type_alias.meta_param_overrides.clone(),
4267 );
4268 }
4269 Ok(())
4270 }
4271 Item::BuiltinFunctionDecl(def, _) => {
4272 self.register_builtin_function_decl(def)
4273 }
4274 Item::ForeignFunction(def, _) => {
4275 if !self.function_defs.contains_key(&def.name) {
4276 let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
4278 self.function_arity_bounds
4279 .insert(def.name.clone(), (caller_visible, caller_visible));
4280 self.function_const_params
4281 .insert(def.name.clone(), Vec::new());
4282 self.foreign_function_defs
4283 .insert(def.name.clone(), def.clone());
4284 }
4285 Ok(())
4286 }
4287 Item::Export(export, _) => match &export.item {
4288 ExportItem::Function(func) => {
4289 if !self.function_defs.contains_key(&func.name) {
4290 self.register_function(func)?;
4291 }
4292 Ok(())
4293 }
4294 ExportItem::Trait(trait_def) => {
4295 if !self.trait_defs.contains_key(&trait_def.name) {
4296 self.known_traits.insert(trait_def.name.clone());
4297 self.trait_defs
4298 .insert(trait_def.name.clone(), trait_def.clone());
4299 self.type_inference.env.define_trait(trait_def);
4300 }
4301 Ok(())
4302 }
4303 ExportItem::Enum(enum_def) => {
4304 self.register_enum(enum_def)?;
4305 Ok(())
4306 }
4307 ExportItem::Struct(struct_def) => {
4308 if !self.struct_types.contains_key(&struct_def.name) {
4310 let runtime_field_names: Vec<String> = struct_def
4311 .fields
4312 .iter()
4313 .filter(|f| !f.is_comptime)
4314 .map(|f| f.name.clone())
4315 .collect();
4316 let runtime_field_types = struct_def
4317 .fields
4318 .iter()
4319 .filter(|f| !f.is_comptime)
4320 .map(|f| (f.name.clone(), f.type_annotation.clone()))
4321 .collect::<std::collections::HashMap<_, _>>();
4322 self.struct_types.insert(
4323 struct_def.name.clone(),
4324 (runtime_field_names, Span::DUMMY),
4325 );
4326 self.struct_generic_info.insert(
4327 struct_def.name.clone(),
4328 StructGenericInfo {
4329 type_params: struct_def.type_params.clone().unwrap_or_default(),
4330 runtime_field_types,
4331 },
4332 );
4333 self.comptime_context_struct_defs
4338 .insert(struct_def.name.clone(), struct_def.clone());
4339 }
4340 Ok(())
4341 }
4342 ExportItem::TypeAlias(type_alias) => {
4343 if !self.type_aliases.contains_key(&type_alias.name) {
4344 let base_type_name = match &type_alias.type_annotation {
4345 TypeAnnotation::Basic(name) => Some(name.clone()),
4346 TypeAnnotation::Reference(name) => Some(name.to_string()),
4347 _ => None,
4348 };
4349 self.type_aliases.insert(
4350 type_alias.name.clone(),
4351 base_type_name.unwrap_or_else(|| {
4352 format!("{:?}", type_alias.type_annotation)
4353 }),
4354 );
4355 self.type_inference.env.define_type_alias(
4356 &type_alias.name,
4357 &type_alias.type_annotation,
4358 type_alias.meta_param_overrides.clone(),
4359 );
4360 }
4361 Ok(())
4362 }
4363 ExportItem::BuiltinFunction(def) => {
4364 self.register_builtin_function_decl(def)
4365 }
4366 ExportItem::ForeignFunction(def) => {
4367 if !self.function_defs.contains_key(&def.name) {
4368 let caller_visible = def.params.iter().filter(|p| !p.is_out).count();
4369 self.function_arity_bounds
4370 .insert(def.name.clone(), (caller_visible, caller_visible));
4371 self.function_const_params
4372 .insert(def.name.clone(), Vec::new());
4373 self.foreign_function_defs
4374 .insert(def.name.clone(), def.clone());
4375 }
4376 Ok(())
4377 }
4378 _ => Ok(()),
4379 },
4380 Item::Impl(..) | Item::Extend(..) => {
4384 self.register_item_functions(item)
4385 }
4386 Item::Module(module, _) => {
4387 let module_path = self.current_module_path_for(module.name.as_str());
4388 self.module_scope_stack.push(module_path.clone());
4389 let register_result = (|| -> Result<()> {
4390 for inner in &module.items {
4391 let qualified = self.qualify_module_item(inner, &module_path)?;
4392 self.register_missing_module_items(&qualified)?;
4393 }
4394 Ok(())
4395 })();
4396 self.module_scope_stack.pop();
4397 register_result
4398 }
4399 _ => Ok(()),
4400 }
4401 }
4402
4403 fn compile_module_decl(&mut self, module_def: &ModuleDecl, span: Span) -> Result<()> {
4404 for ann in &module_def.annotations {
4405 self.validate_annotation_target_usage(ann, AnnotationTargetKind::Module, span)?;
4406 }
4407
4408 let module_path = self.current_module_path_for(&module_def.name);
4409 if let Some(parent_path) = self.module_scope_stack.last().cloned()
4410 && let Some(parent_source) = self.resolve_canonical_module_path(&parent_path)
4411 {
4412 self.module_scope_sources
4413 .entry(module_path.clone())
4414 .or_insert_with(|| format!("{}::{}", parent_source, module_def.name));
4415 }
4416 self.module_scope_stack.push(module_path.clone());
4417 self.push_module_reference_scope();
4418
4419 let mut module_items = module_def.items.clone();
4420 if self.execute_module_comptime_handlers(module_def, &module_path, &mut module_items)? {
4421 self.pop_module_reference_scope();
4422 self.module_scope_stack.pop();
4423 return Ok(());
4424 }
4425 if self.execute_module_inline_comptime_blocks(&module_path, &mut module_items)? {
4426 self.pop_module_reference_scope();
4427 self.module_scope_stack.pop();
4428 return Ok(());
4429 }
4430
4431 let mut qualified_items = Vec::with_capacity(module_items.len());
4432 for inner in &module_items {
4433 qualified_items.push(self.qualify_module_item(inner, &module_path)?);
4434 }
4435
4436 for qualified in &qualified_items {
4437 self.register_missing_module_items(qualified)?;
4438 }
4439
4440 self.non_function_mir_context_stack
4441 .push(module_path.clone());
4442 let compile_result = (|| -> Result<()> {
4443 for (idx, qualified) in qualified_items.iter().enumerate() {
4444 let future_names = self
4445 .future_reference_use_names_for_remaining_items(&qualified_items[idx + 1..]);
4446 self.push_future_reference_use_names(future_names);
4447 let compile_result = self.compile_item_with_context(qualified, false);
4448 self.pop_future_reference_use_names();
4449 compile_result?;
4450 self.release_unused_module_reference_borrows_for_remaining_items(
4451 &qualified_items[idx + 1..],
4452 );
4453 }
4454 Ok(())
4455 })();
4456 self.non_function_mir_context_stack.pop();
4457 compile_result?;
4458
4459 let exports = self.collect_module_runtime_exports(&module_items, &module_path);
4460 let entries: Vec<ObjectEntry> = exports
4461 .into_iter()
4462 .map(|(name, value_ident)| ObjectEntry::Field {
4463 key: name,
4464 value: Expr::Identifier(value_ident, span),
4465 type_annotation: None,
4466 })
4467 .collect();
4468 let module_object = Expr::Object(entries, span);
4469 self.compile_expr(&module_object)?;
4470
4471 let binding_idx = self.get_or_create_module_binding(&module_path);
4472 self.emit(Instruction::new(
4473 OpCode::StoreModuleBinding,
4474 Some(Operand::ModuleBinding(binding_idx)),
4475 ));
4476 self.propagate_initializer_type_to_slot(binding_idx, false, false);
4477
4478 if self.module_scope_stack.len() == 1 {
4479 self.module_namespace_bindings
4480 .insert(module_def.name.clone());
4481 }
4482
4483 self.emit_annotation_lifecycle_calls_for_module(
4484 &module_path,
4485 &module_def.annotations,
4486 Some(binding_idx),
4487 )?;
4488
4489 self.pop_module_reference_scope();
4490 self.module_scope_stack.pop();
4491 Ok(())
4492 }
4493
4494 fn compile_query(&mut self, query: &Query) -> Result<()> {
4502 match query {
4503 Query::With(with_query) => {
4504 for cte in &with_query.ctes {
4506 self.compile_query(&cte.query)?;
4508
4509 let binding_idx = self.get_or_create_module_binding(&cte.name);
4511 self.emit(Instruction::new(
4512 OpCode::StoreModuleBinding,
4513 Some(Operand::ModuleBinding(binding_idx)),
4514 ));
4515 }
4516
4517 self.compile_query(&with_query.query)?;
4519 }
4520 Query::Backtest(_backtest) => {
4521 self.emit(Instruction::simple(OpCode::PushNull));
4525 }
4526 Query::Alert(alert) => {
4527 self.compile_expr(&alert.condition)?;
4529 self.emit(Instruction::simple(OpCode::Pop));
4531 self.emit(Instruction::simple(OpCode::PushNull));
4532 }
4533 }
4534 Ok(())
4535 }
4536
4537 pub(super) fn propagate_initializer_type_to_slot(
4538 &mut self,
4539 slot: u16,
4540 is_local: bool,
4541 _is_mutable: bool,
4542 ) {
4543 self.propagate_assignment_type_to_slot(slot, is_local, true);
4544 }
4545
4546 pub(super) fn compile_statement(&mut self, stmt: &Statement) -> Result<()> {
4548 match stmt {
4549 Statement::Return(expr_opt, _span) => {
4550 if let Some(expr) = expr_opt {
4551 self.plan_flexible_binding_escape_from_expr(expr);
4552 if matches!(expr, Expr::FunctionExpr { .. }) {
4560 self.emit_make_closure_heap_next = true;
4561 }
4562 if self.current_function_return_reference_summary.is_some() {
4563 self.compile_expr_preserving_refs(expr)?;
4564 } else {
4565 self.compile_expr(expr)?;
4566 }
4567 } else {
4568 self.emit(Instruction::simple(OpCode::PushNull));
4569 }
4570 let total_scopes = self.drop_locals.len();
4572 if total_scopes > 0 {
4573 self.emit_drops_for_early_exit(total_scopes)?;
4574 }
4575 self.emit_return_value_with_ownership();
4576 }
4577
4578 Statement::Break(_) => {
4579 let in_loop = !self.loop_stack.is_empty();
4580 if in_loop {
4581 let scopes_to_exit = self
4583 .loop_stack
4584 .last()
4585 .map(|ctx| self.drop_locals.len().saturating_sub(ctx.drop_scope_depth))
4586 .unwrap_or(0);
4587 if scopes_to_exit > 0 {
4588 self.emit_drops_for_early_exit(scopes_to_exit)?;
4589 }
4590 let jump_idx = self.emit_jump(OpCode::Jump, 0);
4591 if let Some(loop_ctx) = self.loop_stack.last_mut() {
4592 loop_ctx.break_jumps.push(jump_idx);
4593 }
4594 } else {
4595 return Err(ShapeError::RuntimeError {
4596 message: "break statement outside of loop".to_string(),
4597 location: None,
4598 });
4599 }
4600 }
4601
4602 Statement::Continue(_) => {
4603 if let Some(loop_ctx) = self.loop_stack.last() {
4604 let scopes_to_exit = self
4606 .drop_locals
4607 .len()
4608 .saturating_sub(loop_ctx.drop_scope_depth);
4609 let continue_target = loop_ctx.continue_target;
4610 if scopes_to_exit > 0 {
4612 self.emit_drops_for_early_exit(scopes_to_exit)?;
4613 }
4614 if continue_target == usize::MAX {
4615 let jump_idx = self.emit_jump(OpCode::Jump, 0);
4617 if let Some(loop_ctx) = self.loop_stack.last_mut() {
4618 loop_ctx.continue_jumps.push(jump_idx);
4619 }
4620 } else {
4621 let offset =
4622 continue_target as i32 - self.program.current_offset() as i32 - 1;
4623 self.emit(Instruction::new(
4624 OpCode::Jump,
4625 Some(Operand::Offset(offset)),
4626 ));
4627 }
4628 } else {
4629 return Err(ShapeError::RuntimeError {
4630 message: "continue statement outside of loop".to_string(),
4631 location: None,
4632 });
4633 }
4634 }
4635
4636 Statement::VariableDecl(var_decl, _) => {
4637 self.pending_variable_name =
4640 var_decl.pattern.as_identifier().map(|s| s.to_string());
4641 self.pending_variable_typed_array_kind = var_decl
4652 .type_annotation
4653 .as_ref()
4654 .and_then(|ann| self.resolve_typed_array_kind_from_annotation(ann));
4655 self.pending_variable_typed_map_kind = var_decl
4661 .type_annotation
4662 .as_ref()
4663 .and_then(|ann| {
4664 crate::compiler::v2_map_emission::map_key_value_from_annotation(ann)
4665 })
4666 .and_then(|(k, v)| {
4667 crate::compiler::v2_typed_map_emission::should_use_typed_map(&k, &v)
4668 });
4669
4670 if let (Some(type_ann), Some(init_expr)) =
4674 (&var_decl.type_annotation, &var_decl.value)
4675 {
4676 if let shape_ast::ast::TypeAnnotation::Basic(type_name) = type_ann {
4677 if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
4678 let _ = (w, type_name);
4688 if let Some(const_val) =
4689 crate::compiler::expressions::function_calls::eval_const_expr_to_nanboxed(init_expr)
4690 {
4691 match const_val {}
4692 }
4693 }
4694 }
4695 }
4696
4697 let mut ref_borrow = None;
4700 let init_err = if let Some(init_expr) = &var_decl.value {
4701 if let Expr::TableRows(rows, tr_span) = init_expr {
4704 match self.compile_table_rows(rows, &var_decl.type_annotation, *tr_span) {
4705 Ok(()) => None,
4706 Err(e) => {
4707 self.emit(Instruction::simple(OpCode::PushNull));
4708 Some(e)
4709 }
4710 }
4711 } else if let Expr::Array(items, arr_span) = init_expr {
4712 let is_table_annotated = matches!(
4715 &var_decl.type_annotation,
4716 Some(shape_ast::ast::TypeAnnotation::Generic { name, args })
4717 if name == "Table" && args.len() == 1
4718 );
4719 if is_table_annotated {
4720 let single_row = vec![items.clone()];
4721 match self.compile_table_rows(
4722 &single_row,
4723 &var_decl.type_annotation,
4724 *arr_span,
4725 ) {
4726 Ok(()) => None,
4727 Err(e) => {
4728 self.emit(Instruction::simple(OpCode::PushNull));
4729 Some(e)
4730 }
4731 }
4732 } else {
4733 match self.compile_expr_for_reference_binding(init_expr) {
4734 Ok(tracked_borrow) => {
4735 ref_borrow = tracked_borrow;
4736 None
4737 }
4738 Err(e) => {
4739 self.emit(Instruction::simple(OpCode::PushNull));
4740 Some(e)
4741 }
4742 }
4743 }
4744 } else {
4745 match self.compile_expr_for_reference_binding(init_expr) {
4746 Ok(tracked_borrow) => {
4747 ref_borrow = tracked_borrow;
4748 None
4749 }
4750 Err(e) => {
4751 self.emit(Instruction::simple(OpCode::PushNull));
4752 Some(e)
4753 }
4754 }
4755 }
4756 } else {
4757 self.emit(Instruction::simple(OpCode::PushNull));
4758 None
4759 };
4760
4761 self.pending_variable_name = None;
4767 let captured_typed_array_kind = self.pending_variable_typed_array_kind;
4768 self.pending_variable_typed_array_kind = None;
4769 let captured_typed_map_kind = self.pending_variable_typed_map_kind;
4770 self.pending_variable_typed_map_kind = None;
4771 let captured_empty_array_alloc_idx =
4775 self.pending_empty_array_alloc_idx.take();
4776
4777 let is_dyn_coerce = init_err.is_none()
4794 && var_decl
4795 .type_annotation
4796 .as_ref()
4797 .map(|ann| {
4798 crate::compiler::trait_object_emission::trait_name_from_annotation(ann)
4799 .is_some()
4800 })
4801 .unwrap_or(false);
4802 if is_dyn_coerce {
4803 if let Some(trait_name) = var_decl
4804 .type_annotation
4805 .as_ref()
4806 .and_then(crate::compiler::trait_object_emission::trait_name_from_annotation)
4807 {
4808 let sid = self.program.add_string(trait_name.to_string());
4809 self.emit(Instruction::new(
4810 OpCode::BoxTraitObject,
4811 Some(Operand::Name(shape_value::StringId(sid as u32))),
4812 ));
4813 }
4814 }
4815
4816 if let Some(ref type_ann) = var_decl.type_annotation {
4818 if let Some(schema_id) = self.get_table_schema_id(type_ann) {
4819 self.emit(Instruction::new(
4820 OpCode::BindSchema,
4821 Some(Operand::Count(schema_id)),
4822 ));
4823 }
4824 }
4825
4826 if self.current_function.is_none() {
4828 if let Some(name) = var_decl.pattern.as_identifier() {
4830 let binding_idx = self.get_or_create_module_binding(name);
4837
4838 let used_typed_store = if let Some(TypeAnnotation::Basic(type_name)) =
4841 var_decl.type_annotation.as_ref()
4842 {
4843 if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
4844 self.emit(Instruction::new(
4845 OpCode::StoreModuleBindingTyped,
4846 Some(Operand::TypedModuleBinding(
4847 binding_idx,
4848 crate::bytecode::NumericWidth::from_int_width(w),
4849 )),
4850 ));
4851 true
4852 } else {
4853 false
4854 }
4855 } else {
4856 false
4857 };
4858 if !used_typed_store {
4859 self.emit(Instruction::new(
4860 OpCode::StoreModuleBinding,
4861 Some(Operand::ModuleBinding(binding_idx)),
4862 ));
4863 }
4864
4865 if let Some(kind) = captured_typed_array_kind {
4867 self.v2_typed_array_module_bindings.insert(binding_idx, kind);
4868 }
4869 if let Some(name) = var_decl.pattern.as_identifier() {
4873 self.register_empty_array_accumulator(
4874 crate::compiler::EmptyArrayAccumulatorKey::ModuleBinding(
4875 binding_idx,
4876 ),
4877 var_decl.value.as_ref(),
4878 captured_empty_array_alloc_idx,
4879 name,
4880 var_decl.value.as_ref().map(|v| v.span()),
4881 );
4882 }
4883 if let Some(kind) = captured_typed_map_kind {
4885 self.v2_typed_map_module_bindings.insert(binding_idx, kind);
4886 }
4887 if let Some(ckind) = self.pending_variable_container_kind.take() {
4891 self.mut_self_container_bindings.insert(binding_idx, ckind);
4892 }
4893 if let Some(trait_name) = var_decl
4898 .type_annotation
4899 .as_ref()
4900 .and_then(crate::compiler::trait_object_emission::trait_name_from_annotation)
4901 {
4902 self.dyn_module_bindings
4903 .insert(binding_idx, trait_name.to_string());
4904 }
4905
4906 if let Some(ref type_ann) = var_decl.type_annotation {
4908 if let Some(type_name) =
4909 Self::tracked_type_name_from_annotation(type_ann)
4910 {
4911 self.set_module_binding_type_info(binding_idx, &type_name);
4912 }
4913 if let Some(ct) = crate::compiler::monomorphization::type_resolution::declared_annotation_concrete_type(self, type_ann) {
4920 self.module_binding_concrete_types.insert(binding_idx, ct);
4921 }
4922 self.try_track_datatable_type(type_ann, binding_idx, false)?;
4924 } else {
4925 let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
4926 self.propagate_initializer_type_to_slot(binding_idx, false, is_mutable);
4927 if let Some(init_expr) = var_decl.value.as_ref() {
4939 if let Some(ct) = crate::compiler::monomorphization::type_resolution::concrete_type_for_expr(self, init_expr) {
4940 self.module_binding_concrete_types.insert(binding_idx, ct);
4941 }
4942 }
4943 }
4944
4945 if let Some(init_expr) = var_decl.value.as_ref() {
4995 if let Some(shape_value::v2::ConcreteType::Array(elem)) =
4996 crate::compiler::monomorphization::type_resolution::specialized_call_return_concrete_type(
4997 self, init_expr,
4998 )
4999 {
5000 self.module_binding_array_element_types
5001 .insert(binding_idx, (*elem).clone());
5002 if let Some(elem_ann) = crate::compiler::expressions::closures::concrete_type_to_type_annotation(&elem) {
5003 let vec_ann = shape_ast::ast::TypeAnnotation::Generic {
5004 name: shape_ast::ast::TypePath::simple("Vec"),
5005 args: vec![elem_ann],
5006 };
5007 if let Some(type_name) = Self::tracked_type_name_from_annotation(&vec_ann) {
5008 self.set_module_binding_type_info(binding_idx, &type_name);
5009 }
5010 }
5011 }
5012 }
5013
5014 let binding_type_name = self
5016 .type_tracker
5017 .get_binding_type(binding_idx)
5018 .and_then(|info| info.type_name.clone());
5019 let drop_kind = binding_type_name
5020 .as_ref()
5021 .and_then(|tn| self.drop_type_info.get(tn).copied())
5022 .or_else(|| {
5023 var_decl
5024 .type_annotation
5025 .as_ref()
5026 .and_then(|ann| self.annotation_drop_kind(ann))
5027 });
5028 if drop_kind.is_some() {
5029 let is_async = match drop_kind {
5030 Some(DropKind::AsyncOnly) => true,
5031 Some(DropKind::Both) => false,
5032 Some(DropKind::SyncOnly) | None => false,
5033 };
5034 self.track_drop_module_binding(binding_idx, is_async);
5035 }
5036 if let Some(value) = &var_decl.value {
5037 self.finish_reference_binding_from_expr(
5038 binding_idx,
5039 false,
5040 name,
5041 value,
5042 ref_borrow,
5043 );
5044 self.update_callable_binding_from_expr(binding_idx, false, value);
5045 } else {
5046 self.clear_reference_binding(binding_idx, false);
5047 self.clear_callable_binding(binding_idx, false);
5048 }
5049 } else {
5050 self.compile_destructure_pattern_global(&var_decl.pattern)?;
5051 }
5052
5053 for (binding_name, _) in var_decl.pattern.get_bindings() {
5054 let scoped_name = self
5055 .resolve_scoped_module_binding_name(&binding_name)
5056 .unwrap_or(binding_name);
5057 if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
5058 if var_decl.kind == VarKind::Const {
5059 self.const_module_bindings.insert(binding_idx);
5060 }
5061 if var_decl.kind == VarKind::Let && !var_decl.is_mut {
5062 self.immutable_module_bindings.insert(binding_idx);
5063 }
5064 }
5065 }
5066 self.apply_binding_semantics_to_pattern_bindings(
5067 &var_decl.pattern,
5068 false,
5069 Self::binding_semantics_for_var_decl(var_decl),
5070 );
5071 self.plan_flexible_binding_storage_for_pattern_initializer(
5072 &var_decl.pattern,
5073 false,
5074 var_decl.value.as_ref(),
5075 );
5076 } else {
5077 self.compile_destructure_pattern(&var_decl.pattern)?;
5079
5080 if let (Some(name), Some(TypeAnnotation::Basic(type_name))) = (
5084 var_decl.pattern.as_identifier(),
5085 var_decl.type_annotation.as_ref(),
5086 ) {
5087 if let Some(w) = shape_ast::IntWidth::from_name(type_name) {
5088 if let Some(local_idx) = self.resolve_local(name) {
5089 if let Some(last) = self.program.instructions.last_mut() {
5090 if last.opcode == OpCode::StoreLocal {
5091 last.opcode = OpCode::StoreLocalTyped;
5092 last.operand = Some(Operand::TypedLocal(
5093 local_idx,
5094 crate::bytecode::NumericWidth::from_int_width(w),
5095 ));
5096 }
5097 }
5098 }
5099 }
5100 }
5101
5102 if let Some(name) = var_decl.pattern.as_identifier() {
5130 let is_owned_binding = var_decl.kind == VarKind::Let
5131 || var_decl.kind == VarKind::Const;
5132 if is_owned_binding {
5133 if let Some(local_idx) = self.resolve_local(name) {
5134 let box_by_default =
5135 super::helpers::box_by_default_enabled();
5136 let should_promote = self
5137 .mir_storage_class_for_slot(local_idx)
5138 .map_or(false, |sc| {
5139 matches!(
5140 sc,
5141 crate::type_tracking::BindingStorageClass::Direct
5142 ) || (box_by_default
5143 && matches!(
5144 sc,
5145 crate::type_tracking::BindingStorageClass::UniqueHeap
5146 ))
5147 });
5148 let callee_already_owned = var_decl
5156 .value
5157 .as_ref()
5158 .and_then(|init| {
5159 self.return_ownership_hint_for_initializer(init)
5160 })
5161 .map_or(false, |hint| {
5162 hint == crate::mir::ReturnOwnershipMode::NewlyOwned
5163 });
5164 if should_promote && !callee_already_owned {
5165 let instr_count = self.program.instructions.len();
5168 if instr_count > 0 {
5169 let last = self.program.instructions[instr_count - 1];
5170 if last.opcode == OpCode::StoreLocal {
5171 self.program.instructions.pop();
5173 self.emit(Instruction::simple(OpCode::PromoteToOwned));
5174 self.emit(last);
5175 }
5176 }
5177 }
5178 }
5179 }
5180 }
5181
5182 for (binding_name, _) in var_decl.pattern.get_bindings() {
5183 if let Some(local_idx) = self.resolve_local(&binding_name) {
5184 if var_decl.kind == VarKind::Const {
5185 self.const_locals.insert(local_idx);
5186 }
5187 if var_decl.kind == VarKind::Let && !var_decl.is_mut {
5188 self.immutable_locals.insert(local_idx);
5189 }
5190 if var_decl.kind == VarKind::Let && var_decl.is_mut {
5196 self.owned_mutable_locals.insert(binding_name.clone());
5197 }
5198 }
5199 }
5200 self.apply_binding_semantics_to_pattern_bindings(
5201 &var_decl.pattern,
5202 true,
5203 Self::binding_semantics_for_var_decl(var_decl),
5204 );
5205 if let Some(init) = var_decl.value.as_ref() {
5210 if let Some(hint) = self.return_ownership_hint_for_initializer(init) {
5211 self.apply_return_ownership_hint_to_pattern_bindings(
5212 &var_decl.pattern,
5213 true,
5214 hint,
5215 );
5216 }
5217 }
5218 self.plan_flexible_binding_storage_for_pattern_initializer(
5219 &var_decl.pattern,
5220 true,
5221 var_decl.value.as_ref(),
5222 );
5223
5224 if let Some(name) = var_decl.pattern.as_identifier() {
5226 if let Some(ref type_ann) = var_decl.type_annotation {
5227 if let Some(type_name) =
5228 Self::tracked_type_name_from_annotation(type_ann)
5229 {
5230 if let Some(local_idx) = self.resolve_local(name) {
5232 self.set_local_type_info(local_idx, &type_name);
5233 }
5234 }
5235 if let Some(local_idx) = self.resolve_local(name) {
5240 if let Some(ct) = crate::compiler::monomorphization::type_resolution::declared_annotation_concrete_type(self, type_ann) {
5241 self.current_function_local_concrete_types.insert(local_idx, ct);
5242 }
5243 }
5244 if let Some(local_idx) = self.resolve_local(name) {
5246 self.try_track_datatable_type(type_ann, local_idx, true)?;
5247 }
5248 if let Some(trait_name) =
5252 crate::compiler::trait_object_emission::trait_name_from_annotation(type_ann)
5253 {
5254 if let Some(local_idx) = self.resolve_local(name) {
5255 self.dyn_locals
5256 .insert(local_idx, trait_name.to_string());
5257 }
5258 }
5259 } else if let Some(local_idx) = self.resolve_local(name) {
5260 let is_mutable = var_decl.kind == shape_ast::ast::VarKind::Var;
5261 self.propagate_initializer_type_to_slot(local_idx, true, is_mutable);
5262 if let Some(init_expr) = var_decl.value.as_ref() {
5273 if let Some(ct) = crate::compiler::monomorphization::type_resolution::concrete_type_for_expr(self, init_expr) {
5274 self.current_function_local_concrete_types.insert(local_idx, ct);
5275 }
5276 }
5277 }
5278 }
5279
5280 if let Some(kind) = captured_typed_array_kind {
5282 if let Some(name) = var_decl.pattern.as_identifier() {
5283 if let Some(local_idx) = self.resolve_local(name) {
5284 self.v2_typed_array_locals.insert(local_idx, kind);
5285 }
5286 }
5287 }
5288 if let Some(name) = var_decl.pattern.as_identifier() {
5293 if let Some(local_idx) = self.resolve_local(name) {
5294 self.register_empty_array_accumulator(
5295 crate::compiler::EmptyArrayAccumulatorKey::Local(local_idx),
5296 var_decl.value.as_ref(),
5297 captured_empty_array_alloc_idx,
5298 name,
5299 var_decl.value.as_ref().map(|v| v.span()),
5300 );
5301 }
5302 }
5303 if let Some(kind) = captured_typed_map_kind {
5316 if let Some(name) = var_decl.pattern.as_identifier() {
5317 if let Some(local_idx) = self.resolve_local(name) {
5318 self.v2_typed_map_locals.insert(local_idx, kind);
5319 }
5320 }
5321 }
5322
5323 if let Some(init_expr) = var_decl.value.as_ref() {
5354 if let Some(shape_value::v2::ConcreteType::Array(elem)) =
5355 crate::compiler::monomorphization::type_resolution::specialized_call_return_concrete_type(
5356 self, init_expr,
5357 )
5358 {
5359 if let Some(name) = var_decl.pattern.as_identifier() {
5360 if let Some(local_idx) = self.resolve_local(name) {
5361 self.local_array_element_types
5362 .insert(local_idx, (*elem).clone());
5363 if let Some(elem_ann) = crate::compiler::expressions::closures::concrete_type_to_type_annotation(&elem) {
5372 let vec_ann = shape_ast::ast::TypeAnnotation::Generic {
5373 name: shape_ast::ast::TypePath::simple("Vec"),
5374 args: vec![elem_ann],
5375 };
5376 if let Some(type_name) = Self::tracked_type_name_from_annotation(&vec_ann) {
5377 self.set_local_type_info(local_idx, &type_name);
5378 }
5379 }
5380 }
5381 }
5382 }
5383 }
5384
5385 let captured_container_kind = self.pending_variable_container_kind.take();
5394 if let Some(kind) = captured_container_kind {
5395 if let Some(name) = var_decl.pattern.as_identifier() {
5396 if let Some(local_idx) = self.resolve_local(name) {
5397 self.mut_self_container_locals.insert(local_idx, kind);
5398 }
5399 }
5400 }
5401
5402 if let Some(name) = var_decl.pattern.as_identifier() {
5405 if let Some(local_idx) = self.resolve_local(name) {
5406 let drop_kind = self.local_drop_kind(local_idx).or_else(|| {
5407 var_decl
5408 .type_annotation
5409 .as_ref()
5410 .and_then(|ann| self.annotation_drop_kind(ann))
5411 });
5412
5413 let is_async = match drop_kind {
5414 Some(DropKind::AsyncOnly) => {
5415 if !self.current_function_is_async {
5416 let tn = self
5417 .type_tracker
5418 .get_local_type(local_idx)
5419 .and_then(|info| info.type_name.clone())
5420 .unwrap_or_else(|| name.to_string());
5421 return Err(ShapeError::SemanticError {
5422 message: format!(
5423 "type '{}' has only an async drop() and cannot be used in a sync context; \
5424 add a sync method drop(self) or use it inside an async function",
5425 tn
5426 ),
5427 location: None,
5428 });
5429 }
5430 true
5431 }
5432 Some(DropKind::Both) => self.current_function_is_async,
5433 Some(DropKind::SyncOnly) | None => false,
5434 };
5435 self.track_drop_local(local_idx, is_async);
5436 if self.binding_slot_needs_ownership_drop(local_idx, var_decl.kind) {
5460 self.track_ownership_drop_local(local_idx);
5461 }
5462 if let Some(value) = &var_decl.value {
5463 self.finish_reference_binding_from_expr(
5464 local_idx, true, name, value, ref_borrow,
5465 );
5466 self.update_callable_binding_from_expr(local_idx, true, value);
5467 } else {
5468 self.clear_reference_binding(local_idx, true);
5469 self.clear_callable_binding(local_idx, true);
5470 }
5471 }
5472 }
5473 }
5474
5475 if let Some(e) = init_err {
5476 return Err(e);
5477 }
5478 }
5479
5480 Statement::Assignment(assign, _) => 'assign: {
5481 if let Some(name) = assign.pattern.as_identifier() {
5483 if let Some(local_idx) = self.resolve_local(name) {
5484 if !self.current_binding_uses_mir_write_authority(true)
5485 && self.const_locals.contains(&local_idx)
5486 {
5487 return Err(ShapeError::SemanticError {
5488 message: format!("Cannot reassign const variable '{}'", name),
5489 location: None,
5490 });
5491 }
5492 if !self.current_binding_uses_mir_write_authority(true)
5494 && self.immutable_locals.contains(&local_idx)
5495 {
5496 return Err(ShapeError::SemanticError {
5497 message: format!(
5498 "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
5499 name
5500 ),
5501 location: None,
5502 });
5503 }
5504 self.check_write_allowed_in_current_context(
5505 Self::borrow_key_for_local(local_idx),
5506 None,
5507 )
5508 .map_err(|e| match e {
5509 ShapeError::SemanticError { message, location } => {
5510 let user_msg = message.replace(
5511 &format!("(slot {})", local_idx),
5512 &format!("'{}'", name),
5513 );
5514 ShapeError::SemanticError {
5515 message: user_msg,
5516 location,
5517 }
5518 }
5519 other => other,
5520 })?;
5521 } else {
5522 let scoped_name = self
5523 .resolve_scoped_module_binding_name(name)
5524 .unwrap_or_else(|| name.to_string());
5525 if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
5526 if !self.current_binding_uses_mir_write_authority(false)
5527 && self.const_module_bindings.contains(&binding_idx)
5528 {
5529 return Err(ShapeError::SemanticError {
5530 message: format!("Cannot reassign const variable '{}'", name),
5531 location: None,
5532 });
5533 }
5534 if !self.current_binding_uses_mir_write_authority(false)
5536 && self.immutable_module_bindings.contains(&binding_idx)
5537 {
5538 return Err(ShapeError::SemanticError {
5539 message: format!(
5540 "Cannot reassign immutable variable '{}'. Use `let mut` or `var` for mutable bindings",
5541 name
5542 ),
5543 location: None,
5544 });
5545 }
5546 self.check_write_allowed_in_current_context(
5547 Self::borrow_key_for_module_binding(binding_idx),
5548 None,
5549 )
5550 .map_err(|e| match e {
5551 ShapeError::SemanticError { message, location } => {
5552 let user_msg = message.replace(
5553 &format!(
5554 "(slot {})",
5555 Self::borrow_key_for_module_binding(binding_idx)
5556 ),
5557 &format!("'{}'", name),
5558 );
5559 ShapeError::SemanticError {
5560 message: user_msg,
5561 location,
5562 }
5563 }
5564 other => other,
5565 })?;
5566 }
5567 }
5568 }
5569
5570 if let Some(name) = assign.pattern.as_identifier() {
5572 if let Expr::MethodCall {
5573 receiver,
5574 method,
5575 args,
5576 ..
5577 } = &assign.value
5578 {
5579 if method == "push" && args.len() == 1 {
5580 if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
5581 if recv_name == name {
5582 if let Some(local_idx) = self.resolve_local(name) {
5583 self.compile_expr(&args[0])?;
5584 let pushed_numeric = self.last_expr_numeric_type;
5585 self.emit(Instruction::new(
5586 OpCode::ArrayPushLocal,
5587 Some(Operand::Local(local_idx)),
5588 ));
5589 if let Some(numeric_type) = pushed_numeric {
5590 self.mark_slot_as_numeric_array(
5591 local_idx,
5592 true,
5593 numeric_type,
5594 );
5595 }
5596 self.plan_flexible_binding_storage_from_expr(
5597 local_idx,
5598 true,
5599 &assign.value,
5600 );
5601 break 'assign;
5602 } else {
5603 let binding_idx = self.get_or_create_module_binding(name);
5604 self.compile_expr(&args[0])?;
5605 let pushed_numeric = self.last_expr_numeric_type;
5606 self.emit(Instruction::new(
5607 OpCode::ArrayPushLocal,
5608 Some(Operand::ModuleBinding(binding_idx)),
5609 ));
5610 if let Some(numeric_type) = pushed_numeric {
5611 self.mark_slot_as_numeric_array(
5612 binding_idx,
5613 false,
5614 numeric_type,
5615 );
5616 }
5617 self.plan_flexible_binding_storage_from_expr(
5618 binding_idx,
5619 false,
5620 &assign.value,
5621 );
5622 break 'assign;
5623 }
5624 }
5625 }
5626 }
5627 }
5628 }
5629
5630 let saved_pending_variable_name = self.pending_variable_name.clone();
5632 self.pending_variable_name =
5633 assign.pattern.as_identifier().map(|name| name.to_string());
5634 let compile_result = self.compile_expr_for_reference_binding(&assign.value);
5635 self.pending_variable_name = saved_pending_variable_name;
5636 let ref_borrow = compile_result?;
5637 let assigned_ident = assign.pattern.as_identifier().map(str::to_string);
5638
5639 self.compile_destructure_assignment(&assign.pattern)?;
5641 if let Some(name) = assigned_ident.as_deref() {
5642 if let Some(local_idx) = self.resolve_local(name) {
5643 if !self.local_binding_is_reference_value(local_idx) {
5644 self.finish_reference_binding_from_expr(
5645 local_idx,
5646 true,
5647 name,
5648 &assign.value,
5649 ref_borrow,
5650 );
5651 self.update_callable_binding_from_expr(local_idx, true, &assign.value);
5652 }
5653 self.plan_flexible_binding_storage_from_expr(
5654 local_idx,
5655 true,
5656 &assign.value,
5657 );
5658 } else if let Some(scoped_name) = self.resolve_scoped_module_binding_name(name)
5659 {
5660 if let Some(&binding_idx) = self.module_bindings.get(&scoped_name) {
5661 self.finish_reference_binding_from_expr(
5662 binding_idx,
5663 false,
5664 name,
5665 &assign.value,
5666 ref_borrow,
5667 );
5668 self.update_callable_binding_from_expr(
5669 binding_idx,
5670 false,
5671 &assign.value,
5672 );
5673 self.plan_flexible_binding_storage_from_expr(
5674 binding_idx,
5675 false,
5676 &assign.value,
5677 );
5678 }
5679 }
5680 self.propagate_assignment_type_to_identifier(name);
5681 }
5682 }
5683
5684 Statement::Expression(expr, _) => {
5685 if let Expr::MethodCall {
5698 receiver,
5699 method,
5700 args,
5701 ..
5702 } = expr
5703 {
5704 let bespoke_push_blocked = if method == "push"
5705 && args.len() == 1
5706 && let Expr::Identifier(recv_name, _) = receiver.as_ref()
5707 {
5708 let local_kind = self
5709 .resolve_local(recv_name)
5710 .and_then(|idx| self.mut_self_container_locals.get(&idx).copied());
5711 let module_kind = if local_kind.is_none() {
5712 let scoped = self
5713 .resolve_scoped_module_binding_name(recv_name)
5714 .unwrap_or_else(|| recv_name.to_string());
5715 self.module_bindings
5716 .get(&scoped)
5717 .copied()
5718 .and_then(|idx| {
5719 self.mut_self_container_bindings.get(&idx).copied()
5720 })
5721 } else {
5722 None
5723 };
5724 local_kind
5725 .or(module_kind)
5726 .map(|kind| {
5727 !matches!(
5728 kind,
5729 crate::compiler::mutation_writeback::ContainerKind::Array
5730 )
5731 })
5732 .unwrap_or(false)
5733 } else {
5734 false
5735 };
5736 if method == "push" && args.len() == 1 && !bespoke_push_blocked {
5737 if let Expr::Identifier(recv_name, _) = receiver.as_ref() {
5738 let source_loc = self.span_to_source_location(receiver.as_ref().span());
5739 if self.compile_first_push_to_empty_accumulator(
5747 recv_name,
5748 &args[0],
5749 Some(source_loc.clone()),
5750 )? {
5751 self.emit(Instruction::simple(OpCode::Pop));
5752 return Ok(());
5753 }
5754 let typed_kind = self
5765 .resolve_receiver_typed_array_kind(receiver.as_ref());
5766 if let Some(local_idx) = self.resolve_local(recv_name) {
5767 if !self.ref_locals.contains(&local_idx) {
5768 self.check_named_binding_write_allowed(
5769 recv_name,
5770 Some(source_loc.clone()),
5771 )?;
5772 }
5773 if let Some(kind) = typed_kind {
5774 self.emit(Instruction::new(
5777 OpCode::LoadLocal,
5778 Some(Operand::Local(local_idx)),
5779 ));
5780 self.compile_typed_array_element_value(kind, &args[0])?;
5781 self.emit(Instruction::simple(kind.push_opcode()));
5782 return Ok(());
5783 }
5784 self.compile_expr(&args[0])?;
5785 let pushed_numeric = self.last_expr_numeric_type;
5786 self.emit(Instruction::new(
5787 OpCode::ArrayPushLocal,
5788 Some(Operand::Local(local_idx)),
5789 ));
5790 if let Some(numeric_type) = pushed_numeric {
5791 self.mark_slot_as_numeric_array(local_idx, true, numeric_type);
5792 }
5793 return Ok(());
5794 } else if !self
5795 .mutable_closure_captures
5796 .contains_key(recv_name.as_str())
5797 {
5798 self.check_named_binding_write_allowed(
5799 recv_name,
5800 Some(source_loc),
5801 )?;
5802 let binding_idx = self.get_or_create_module_binding(recv_name);
5803 if let Some(kind) = typed_kind {
5804 self.emit(Instruction::new(
5805 OpCode::LoadModuleBinding,
5806 Some(Operand::ModuleBinding(binding_idx)),
5807 ));
5808 self.compile_typed_array_element_value(kind, &args[0])?;
5809 self.emit(Instruction::simple(kind.push_opcode()));
5810 return Ok(());
5811 }
5812 self.compile_expr(&args[0])?;
5813 self.emit(Instruction::new(
5814 OpCode::ArrayPushLocal,
5815 Some(Operand::ModuleBinding(binding_idx)),
5816 ));
5817 return Ok(());
5818 }
5819 }
5820 }
5821 }
5822 self.compile_expr(expr)?;
5823 self.emit(Instruction::simple(OpCode::Pop));
5824 }
5825
5826 Statement::For(for_loop, _) => {
5827 self.compile_for_loop(for_loop)?;
5828 }
5829
5830 Statement::While(while_loop, _) => {
5831 self.compile_while_loop(while_loop)?;
5832 }
5833
5834 Statement::If(if_stmt, _) => {
5835 self.compile_if_statement(if_stmt)?;
5836 }
5837 Statement::Extend(extend, span) => {
5838 self.require_comptime_mode("extend", *span)?;
5839 self.emit_comptime_extend_directive(extend, *span)?;
5840 }
5841 Statement::RemoveTarget(span) => {
5842 self.require_comptime_mode("remove target", *span)?;
5843 self.emit_comptime_remove_directive(*span)?;
5844 }
5845 Statement::SetParamType {
5846 param_name,
5847 type_annotation,
5848 span,
5849 } => {
5850 self.require_comptime_mode("set param", *span)?;
5851 self.emit_comptime_set_param_type_directive(param_name, type_annotation, *span)?;
5852 }
5853 Statement::SetParamValue {
5854 param_name,
5855 expression,
5856 span,
5857 } => {
5858 self.require_comptime_mode("set param", *span)?;
5859 self.emit_comptime_set_param_value_directive(param_name, expression, *span)?;
5860 }
5861 Statement::SetReturnType {
5862 type_annotation,
5863 span,
5864 } => {
5865 self.require_comptime_mode("set return", *span)?;
5866 self.emit_comptime_set_return_type_directive(type_annotation, *span)?;
5867 }
5868 Statement::SetReturnExpr { expression, span } => {
5869 self.require_comptime_mode("set return", *span)?;
5870 self.emit_comptime_set_return_expr_directive(expression, *span)?;
5871 }
5872 Statement::ReplaceBody { body, span } => {
5873 self.require_comptime_mode("replace body", *span)?;
5874 self.emit_comptime_replace_body_directive(body, *span)?;
5875 }
5876 Statement::ReplaceBodyExpr { expression, span } => {
5877 self.require_comptime_mode("replace body", *span)?;
5878 self.emit_comptime_replace_body_expr_directive(expression, *span)?;
5879 }
5880 Statement::ReplaceModuleExpr { expression, span } => {
5881 self.require_comptime_mode("replace module", *span)?;
5882 self.emit_comptime_replace_module_expr_directive(expression, *span)?;
5883 }
5884 }
5885 Ok(())
5886 }
5887}
5888
5889#[cfg(test)]
5890mod tests {
5891 use crate::compiler::BytecodeCompiler;
5892 use crate::executor::{VMConfig, VirtualMachine};
5893 use shape_ast::ast::{Item, Span, Statement};
5894 use shape_ast::parser::parse_program;
5895
5896 #[cfg(any())]
5909 #[test]
5910 fn test_module_decl_function_resolves_module_const() {
5911 let code = r#"
5912 mod math {
5913 const BASE = 21
5914 fn twice() {
5915 BASE * 2
5916 }
5917 }
5918 math::twice()
5919 "#;
5920
5921 let program = parse_program(code).expect("Failed to parse");
5922 let bytecode = BytecodeCompiler::new()
5923 .compile(&program)
5924 .expect("Failed to compile");
5925
5926 let mut vm = VirtualMachine::new(VMConfig::default());
5927 vm.load_program(bytecode);
5928 vm.populate_module_objects();
5929 let result = vm.execute(None).expect("Failed to execute");
5930 assert_eq!(
5931 result
5932 .as_number_coerce()
5933 .expect("module call should return number"),
5934 42.0
5935 );
5936 }
5937
5938 #[cfg(any())]
5939 #[test]
5940 fn test_module_annotation_can_replace_module_items() {
5941 let code = r#"
5942 annotation synth_module() {
5943 targets: [module]
5944 comptime post(target, ctx) {
5945 replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
5946 }
5947 }
5948
5949 @synth_module()
5950 mod demo {}
5951
5952 demo::plus_two()
5953 "#;
5954
5955 let program = parse_program(code).expect("Failed to parse");
5956 let bytecode = BytecodeCompiler::new()
5957 .compile(&program)
5958 .expect("Failed to compile");
5959
5960 let mut vm = VirtualMachine::new(VMConfig::default());
5961 vm.load_program(bytecode);
5962 vm.populate_module_objects();
5963 let result = vm.execute(None).expect("Failed to execute");
5964 assert_eq!(
5965 result
5966 .as_number_coerce()
5967 .expect("module call should return number"),
5968 42.0
5969 );
5970 }
5971
5972 #[cfg(any())]
5973 #[test]
5974 fn test_module_inline_comptime_can_replace_module_items() {
5975 let code = r#"
5976 mod demo {
5977 comptime {
5978 replace module ("const ANSWER = 40; fn plus_two() { ANSWER + 2 }")
5979 }
5980 }
5981
5982 demo::plus_two()
5983 "#;
5984
5985 let program = parse_program(code).expect("Failed to parse");
5986 let bytecode = BytecodeCompiler::new()
5987 .compile(&program)
5988 .expect("Failed to compile");
5989
5990 let mut vm = VirtualMachine::new(VMConfig::default());
5991 vm.load_program(bytecode);
5992 vm.populate_module_objects();
5993 let result = vm.execute(None).expect("Failed to execute");
5994 assert_eq!(
5995 result
5996 .as_number_coerce()
5997 .expect("module call should return number"),
5998 42.0
5999 );
6000 }
6001
6002 #[cfg(any())]
6003 #[test]
6004 fn test_module_inline_comptime_can_use_module_local_comptime_helper() {
6005 let code = r#"
6006 mod demo {
6007 comptime fn synth() {
6008 "const ANSWER = 40; fn plus_two() { ANSWER + 2 }"
6009 }
6010
6011 comptime {
6012 replace module (synth())
6013 }
6014 }
6015
6016 demo::plus_two()
6017 "#;
6018
6019 let program = parse_program(code).expect("Failed to parse");
6020 let bytecode = BytecodeCompiler::new()
6021 .compile(&program)
6022 .expect("Failed to compile");
6023
6024 let mut vm = VirtualMachine::new(VMConfig::default());
6025 vm.load_program(bytecode);
6026 vm.populate_module_objects();
6027 let result = vm.execute(None).expect("Failed to execute");
6028 assert_eq!(
6029 result
6030 .as_number_coerce()
6031 .expect("module call should return number"),
6032 42.0
6033 );
6034 }
6035
6036 #[test]
6037 fn test_type_annotated_variable_no_wrapping() {
6038 let code = r#"
6041 type Currency = Number
6042 let x: Currency = 123
6043 "#;
6044 let program = parse_program(code).expect("Failed to parse");
6045 let bytecode = BytecodeCompiler::new()
6046 .compile(&program)
6047 .expect("Failed to compile");
6048
6049 let has_wrap_instruction = bytecode
6051 .instructions
6052 .iter()
6053 .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
6054 assert!(
6055 !has_wrap_instruction,
6056 "Should NOT emit WrapTypeAnnotation for type-annotated variable"
6057 );
6058 }
6059
6060 #[test]
6061 fn test_untyped_variable_no_wrapping() {
6062 let code = r#"
6064 let x = 123
6065 "#;
6066 let program = parse_program(code).expect("Failed to parse");
6067 let bytecode = BytecodeCompiler::new()
6068 .compile(&program)
6069 .expect("Failed to compile");
6070
6071 let has_wrap_instruction = bytecode
6073 .instructions
6074 .iter()
6075 .any(|instr| instr.opcode == crate::bytecode::OpCode::WrapTypeAnnotation);
6076 assert!(
6077 !has_wrap_instruction,
6078 "Should NOT emit WrapTypeAnnotation for untyped variable"
6079 );
6080 }
6081
6082 #[test]
6085 fn test_extend_block_compiles() {
6086 let code = r#"
6087 extend Number {
6088 method double() {
6089 return self * 2
6090 }
6091 }
6092 "#;
6093 let program = parse_program(code).expect("Failed to parse extend block");
6094 let bytecode = BytecodeCompiler::new().compile(&program);
6095 assert!(
6096 bytecode.is_ok(),
6097 "Extend block should compile: {:?}",
6098 bytecode.err()
6099 );
6100
6101 let bytecode = bytecode.unwrap();
6103 let has_double = bytecode.functions.iter().any(|f| f.name == "Number.double");
6104 assert!(
6105 has_double,
6106 "Should generate 'Number.double' function from extend block"
6107 );
6108 }
6109
6110 #[test]
6111 fn test_extend_method_has_self_param() {
6112 let code = r#"
6113 extend Number {
6114 method add(n) {
6115 return self + n
6116 }
6117 }
6118 "#;
6119 let program = parse_program(code).expect("Failed to parse");
6120 let bytecode = BytecodeCompiler::new()
6121 .compile(&program)
6122 .expect("Failed to compile");
6123
6124 let func = bytecode.functions.iter().find(|f| f.name == "Number.add");
6125 assert!(func.is_some(), "Should have 'Number.add' function");
6126 assert_eq!(
6128 func.unwrap().arity,
6129 2,
6130 "add() should have arity 2 (self + n)"
6131 );
6132 }
6133
6134 #[test]
6135 fn test_extend_method_rejects_explicit_self_param() {
6136 let code = r#"
6137 extend Number {
6138 method add(self, n) {
6139 return self + n
6140 }
6141 }
6142 "#;
6143 let program = parse_program(code).expect("Failed to parse");
6144 let err = BytecodeCompiler::new()
6145 .compile(&program)
6146 .expect_err("Compiler should reject explicit self receiver param in methods");
6147 let msg = format!("{err}");
6148 assert!(
6149 msg.contains("explicit `self` parameter"),
6150 "Expected explicit self error, got: {msg}"
6151 );
6152 }
6153
6154 #[test]
6157 fn test_annotation_def_compiles_handlers() {
6158 let code = r#"
6159 annotation warmup(period) {
6160 before(args, ctx) {
6161 args
6162 }
6163 after(args, result, ctx) {
6164 result
6165 }
6166 }
6167 function test() { return 42; }
6168 "#;
6169 let program = parse_program(code).expect("Failed to parse annotation def");
6170 let bytecode = BytecodeCompiler::new().compile(&program);
6171 assert!(
6172 bytecode.is_ok(),
6173 "Annotation def should compile: {:?}",
6174 bytecode.err()
6175 );
6176
6177 let bytecode = bytecode.unwrap();
6178 assert!(
6180 bytecode.compiled_annotations.contains_key("warmup"),
6181 "Should have compiled 'warmup' annotation"
6182 );
6183
6184 let compiled = bytecode.compiled_annotations.get("warmup").unwrap();
6185 assert!(
6186 compiled.before_handler.is_some(),
6187 "Should have before handler"
6188 );
6189 assert!(
6190 compiled.after_handler.is_some(),
6191 "Should have after handler"
6192 );
6193 }
6194
6195 #[test]
6196 fn test_exported_annotation_def_compiles_handlers() {
6197 let code = r#"
6198 pub annotation warmup(period) {
6199 before(args, ctx) {
6200 args
6201 }
6202 }
6203
6204 @warmup(5)
6205 fn test() { 42 }
6206 "#;
6207 let program = parse_program(code).expect("Failed to parse exported annotation def");
6208 let bytecode = BytecodeCompiler::new().compile(&program);
6209 assert!(
6210 bytecode.is_ok(),
6211 "Exported annotation def should compile: {:?}",
6212 bytecode.err()
6213 );
6214
6215 let bytecode = bytecode.unwrap();
6216 assert!(
6217 bytecode.compiled_annotations.contains_key("warmup"),
6218 "Should have compiled exported 'warmup' annotation"
6219 );
6220 }
6221
6222 #[test]
6223 fn test_annotation_handler_function_names() {
6224 let code = r#"
6225 annotation my_ann(x) {
6226 before(args, ctx) {
6227 args
6228 }
6229 }
6230 function test() { return 1; }
6231 "#;
6232 let program = parse_program(code).expect("Failed to parse");
6233 let bytecode = BytecodeCompiler::new()
6234 .compile(&program)
6235 .expect("Failed to compile");
6236
6237 let compiled = bytecode.compiled_annotations.get("my_ann").unwrap();
6239 let handler_id = compiled.before_handler.unwrap() as usize;
6240 assert!(
6241 handler_id < bytecode.functions.len(),
6242 "Handler function ID should be valid"
6243 );
6244
6245 let handler_fn = &bytecode.functions[handler_id];
6246 assert_eq!(
6247 handler_fn.name, "my_ann___before",
6248 "Handler function should be named my_ann___before"
6249 );
6250 }
6251
6252 #[test]
6255 fn test_annotated_function_generates_wrapper() {
6256 let code = r#"
6257 annotation tracked(label) {
6258 before(args, ctx) {
6259 args
6260 }
6261 }
6262 @tracked("my_func")
6263 function compute(x) {
6264 return x * 2
6265 }
6266 function test() { return 1; }
6267 "#;
6268 let program = parse_program(code).expect("Failed to parse");
6269 let bytecode = BytecodeCompiler::new().compile(&program);
6270 assert!(
6271 bytecode.is_ok(),
6272 "Annotated function should compile: {:?}",
6273 bytecode.err()
6274 );
6275
6276 let bytecode = bytecode.unwrap();
6277 let has_impl = bytecode
6279 .functions
6280 .iter()
6281 .any(|f| f.name == "compute___impl");
6282 assert!(has_impl, "Should generate compute___impl function");
6283
6284 let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
6285 assert!(has_wrapper, "Should keep compute as wrapper");
6286 }
6287
6288 #[test]
6289 fn test_unannotated_function_no_wrapper() {
6290 let code = r#"
6291 function plain(x) {
6292 return x + 1
6293 }
6294 "#;
6295 let program = parse_program(code).expect("Failed to parse");
6296 let bytecode = BytecodeCompiler::new()
6297 .compile(&program)
6298 .expect("Failed to compile");
6299
6300 let has_impl = bytecode
6302 .functions
6303 .iter()
6304 .any(|f| f.name.ends_with("___impl"));
6305 assert!(
6306 !has_impl,
6307 "Non-annotated function should not generate ___impl"
6308 );
6309 }
6310
6311 #[test]
6314 fn test_annotation_chaining_generates_chain() {
6315 let code = r#"
6317 annotation first() {
6318 before(args, ctx) {
6319 return args
6320 }
6321 }
6322
6323 annotation second() {
6324 before(args, ctx) {
6325 return args
6326 }
6327 }
6328
6329 @first
6330 @second
6331 function compute(x) {
6332 return x * 2
6333 }
6334 "#;
6335 let program = parse_program(code).expect("Failed to parse");
6336 let bytecode = BytecodeCompiler::new().compile(&program);
6337 assert!(
6338 bytecode.is_ok(),
6339 "Chained annotations should compile: {:?}",
6340 bytecode.err()
6341 );
6342 let bytecode = bytecode.unwrap();
6343
6344 let has_impl = bytecode
6346 .functions
6347 .iter()
6348 .any(|f| f.name == "compute___impl");
6349 assert!(has_impl, "Should generate compute___impl function");
6350 let has_wrapper = bytecode.functions.iter().any(|f| f.name == "compute");
6351 assert!(has_wrapper, "Should keep compute as outermost wrapper");
6352 let has_intermediate = bytecode
6353 .functions
6354 .iter()
6355 .any(|f| f.name == "compute___second");
6356 assert!(
6357 has_intermediate,
6358 "Should generate compute___second intermediate wrapper"
6359 );
6360 }
6361
6362 #[test]
6363 fn test_annotation_allowed_targets_inferred() {
6364 let code = r#"
6366 annotation traced() {
6367 before(args, ctx) {
6368 return args
6369 }
6370 }
6371 "#;
6372 let program = parse_program(code).expect("Failed to parse");
6373 let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
6374 let ann = bytecode
6375 .compiled_annotations
6376 .get("traced")
6377 .expect("traced annotation");
6378 assert!(
6379 !ann.allowed_targets.is_empty(),
6380 "before handler should restrict targets"
6381 );
6382 assert!(
6383 ann.allowed_targets
6384 .contains(&shape_ast::ast::functions::AnnotationTargetKind::Function),
6385 "before handler should allow Function target"
6386 );
6387 }
6388
6389 #[test]
6390 fn test_annotation_allowed_targets_explicit_override() {
6391 let code = r#"
6393 annotation traced() {
6394 targets: [type]
6395 before(args, ctx) {
6396 return args
6397 }
6398 }
6399 "#;
6400 let program = parse_program(code).expect("Failed to parse");
6401 let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
6402 let ann = bytecode
6403 .compiled_annotations
6404 .get("traced")
6405 .expect("traced annotation");
6406 assert_eq!(
6407 ann.allowed_targets,
6408 vec![shape_ast::ast::functions::AnnotationTargetKind::Type]
6409 );
6410 }
6411
6412 #[test]
6413 fn test_metadata_only_annotation_defaults_to_definition_targets() {
6414 let code = r#"
6416 annotation info() {
6417 metadata() {
6418 return { version: 1 }
6419 }
6420 }
6421 "#;
6422 let program = parse_program(code).expect("Failed to parse");
6423 let bytecode = BytecodeCompiler::new().compile(&program).expect("compile");
6424 let ann = bytecode
6425 .compiled_annotations
6426 .get("info")
6427 .expect("info annotation");
6428 assert_eq!(
6429 ann.allowed_targets,
6430 vec![
6431 shape_ast::ast::functions::AnnotationTargetKind::Function,
6432 shape_ast::ast::functions::AnnotationTargetKind::Type,
6433 shape_ast::ast::functions::AnnotationTargetKind::Module
6434 ],
6435 "metadata-only annotation should default to definition targets"
6436 );
6437 }
6438
6439 #[test]
6440 fn test_definition_lifecycle_targets_reject_expression_target() {
6441 let code = r#"
6442 annotation info() {
6443 targets: [expression]
6444 metadata(target, ctx) {
6445 target.name
6446 }
6447 }
6448 "#;
6449 let program = parse_program(code).expect("Failed to parse");
6450 let err = BytecodeCompiler::new()
6451 .compile(&program)
6452 .expect_err("metadata hooks on expression targets should fail");
6453 let msg = format!("{}", err);
6454 assert!(
6455 msg.contains("not a definition target"),
6456 "expected definition-target restriction error, got: {}",
6457 msg
6458 );
6459 }
6460
6461 #[test]
6462 fn test_annotation_target_validation_on_struct_type() {
6463 let code = r#"
6465 annotation traced() {
6466 before(args, ctx) { return args }
6467 }
6468
6469 @traced()
6470 type Point { x: int }
6471 "#;
6472 let program = parse_program(code).expect("Failed to parse");
6473 let err = BytecodeCompiler::new()
6474 .compile(&program)
6475 .expect_err("function-only annotation on type should fail");
6476 let msg = format!("{}", err);
6477 assert!(
6478 msg.contains("cannot be applied to a type"),
6479 "expected type target validation error, got: {}",
6480 msg
6481 );
6482 }
6483
6484 #[test]
6485 fn test_type_c_emits_native_layout_metadata() {
6486 let bytecode = compiles_to(
6487 r#"
6488 type C Pair32 {
6489 left: i32,
6490 right: i32,
6491 }
6492 "#,
6493 );
6494
6495 assert_eq!(bytecode.native_struct_layouts.len(), 1);
6496 let layout = &bytecode.native_struct_layouts[0];
6497 assert_eq!(layout.name, "Pair32");
6498 assert_eq!(layout.abi, "C");
6499 assert_eq!(layout.size, 8);
6500 assert_eq!(layout.align, 4);
6501 assert_eq!(layout.fields.len(), 2);
6502 assert_eq!(layout.fields[0].name, "left");
6503 assert_eq!(layout.fields[0].offset, 0);
6504 assert_eq!(layout.fields[0].size, 4);
6505 assert_eq!(layout.fields[1].name, "right");
6506 assert_eq!(layout.fields[1].offset, 4);
6507 assert_eq!(layout.fields[1].size, 4);
6508 }
6509
6510 #[test]
6511 fn test_type_c_auto_generates_into_from_traits() {
6512 let bytecode = compiles_to(
6513 r#"
6514 type C QuoteC {
6515 bid: i64,
6516 ask: i64,
6517 }
6518
6519 type Quote {
6520 bid: i64,
6521 ask: i64,
6522 }
6523 "#,
6524 );
6525
6526 let c_to_shape =
6527 bytecode.lookup_trait_method_symbol("Into", "QuoteC", Some("Quote"), "into");
6528 let shape_to_c =
6529 bytecode.lookup_trait_method_symbol("Into", "Quote", Some("QuoteC"), "into");
6530 let from_c = bytecode.lookup_trait_method_symbol("From", "Quote", Some("QuoteC"), "from");
6531 let from_shape =
6532 bytecode.lookup_trait_method_symbol("From", "QuoteC", Some("Quote"), "from");
6533
6534 assert!(c_to_shape.is_some(), "expected Into<Quote> for QuoteC");
6535 assert!(shape_to_c.is_some(), "expected Into<QuoteC> for Quote");
6536 assert!(from_c.is_some(), "expected From<QuoteC> for Quote");
6537 assert!(from_shape.is_some(), "expected From<Quote> for QuoteC");
6538 }
6539
6540 #[test]
6541 fn test_type_c_auto_conversion_function_compiles() {
6542 let _ = compiles_to(
6543 r#"
6544 type Quote {
6545 bid: i64,
6546 ask: i64,
6547 }
6548
6549 type C QuoteC {
6550 bid: i64,
6551 ask: i64,
6552 }
6553
6554 fn spread(q: QuoteC) -> i64 {
6555 let q_shape = __auto_native_from_QuoteC_to_Quote(q);
6556 q_shape.ask - q_shape.bid
6557 }
6558
6559 spread(QuoteC { bid: 10, ask: 13 })
6560 "#,
6561 );
6562 }
6563
6564 #[test]
6565 fn test_type_c_auto_conversion_rejects_incompatible_fields() {
6566 let program = parse_program(
6567 r#"
6568 type Price {
6569 value: i64,
6570 }
6571
6572 type C PriceC {
6573 value: u64,
6574 }
6575 "#,
6576 )
6577 .expect("parse failed");
6578 let err = BytecodeCompiler::new()
6579 .compile(&program)
6580 .expect_err("incompatible type C conversion pair should fail");
6581 let msg = format!("{}", err);
6582 assert!(
6583 msg.contains("field type mismatch for auto conversion"),
6584 "expected type mismatch error, got: {}",
6585 msg
6586 );
6587 }
6588
6589 fn compiles_to(code: &str) -> crate::bytecode::BytecodeProgram {
6594 let program = parse_program(code).expect("parse failed");
6595 let compiler = BytecodeCompiler::new();
6596 compiler.compile(&program).expect("compile failed")
6597 }
6598
6599 #[test]
6602 fn test_permission_check_allows_pure_module_imports() {
6603 let code = "from std::core::json use { parse }";
6605 let program = parse_program(code).expect("parse failed");
6606 let mut compiler = BytecodeCompiler::new();
6607 compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
6608 let _result = compiler.compile(&program);
6610 }
6611
6612 #[test]
6613 fn test_permission_check_blocks_file_import_under_pure() {
6614 let code = "from std::core::file use { read_text }";
6615 let program = parse_program(code).expect("parse failed");
6616 let mut compiler = BytecodeCompiler::new();
6617 compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
6618 let result = compiler.compile(&program);
6619 assert!(
6620 result.is_err(),
6621 "Expected permission error for file::read_text under pure"
6622 );
6623 let err_msg = format!("{}", result.unwrap_err());
6624 assert!(
6625 err_msg.contains("Permission denied"),
6626 "Error should mention permission denied: {err_msg}"
6627 );
6628 assert!(
6629 err_msg.contains("fs.read"),
6630 "Error should mention fs.read: {err_msg}"
6631 );
6632 }
6633
6634 #[test]
6635 fn test_permission_check_allows_file_import_with_fs_read() {
6636 let code = "from std::core::file use { read_text }";
6637 let program = parse_program(code).expect("parse failed");
6638 let mut compiler = BytecodeCompiler::new();
6639 let pset = shape_abi_v1::PermissionSet::from_iter([shape_abi_v1::Permission::FsRead]);
6640 compiler.set_permission_set(Some(pset));
6641 let _result = compiler.compile(&program);
6643 }
6644
6645 #[test]
6646 fn test_permission_check_no_permission_set_allows_everything() {
6647 let code = "from std::core::file use { read_text }";
6649 let program = parse_program(code).expect("parse failed");
6650 let compiler = BytecodeCompiler::new();
6651 let _result = compiler.compile(&program);
6653 }
6654
6655 #[test]
6656 fn test_permission_check_namespace_import_blocked() {
6657 let code = "use std::core::http";
6658 let program = parse_program(code).expect("parse failed");
6659 let mut compiler = BytecodeCompiler::new();
6660 compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::pure()));
6661 let result = compiler.compile(&program);
6662 assert!(
6663 result.is_err(),
6664 "Expected permission error for `use std::core::http` under pure"
6665 );
6666 let err_msg = format!("{}", result.unwrap_err());
6667 assert!(
6668 err_msg.contains("Permission denied"),
6669 "Error should mention permission denied: {err_msg}"
6670 );
6671 }
6672
6673 #[test]
6674 fn test_permission_check_namespace_import_allowed() {
6675 let code = "use std::core::http";
6676 let program = parse_program(code).expect("parse failed");
6677 let mut compiler = BytecodeCompiler::new();
6678 compiler.set_permission_set(Some(shape_abi_v1::PermissionSet::full()));
6679 let _result = compiler.compile(&program);
6681 }
6682
6683 fn test_decl(kind: shape_ast::ast::VarKind, is_mut: bool) -> shape_ast::ast::VariableDecl {
6684 shape_ast::ast::VariableDecl {
6685 kind,
6686 is_mut,
6687 pattern: shape_ast::ast::DestructurePattern::Identifier(
6688 "x".to_string(),
6689 shape_ast::ast::Span::DUMMY,
6690 ),
6691 type_annotation: None,
6692 value: None,
6693 ownership: Default::default(),
6694 }
6695 }
6696
6697 #[test]
6698 fn test_binding_semantics_for_decl_maps_let_var_classes() {
6699 let let_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6700 shape_ast::ast::VarKind::Let,
6701 false,
6702 ));
6703 assert_eq!(
6704 let_semantics.ownership_class,
6705 crate::type_tracking::BindingOwnershipClass::OwnedImmutable
6706 );
6707 assert_eq!(
6708 let_semantics.storage_class,
6709 crate::type_tracking::BindingStorageClass::Direct
6710 );
6711
6712 let let_mut_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6713 shape_ast::ast::VarKind::Let,
6714 true,
6715 ));
6716 assert_eq!(
6717 let_mut_semantics.ownership_class,
6718 crate::type_tracking::BindingOwnershipClass::OwnedMutable
6719 );
6720 assert_eq!(
6721 let_mut_semantics.storage_class,
6722 crate::type_tracking::BindingStorageClass::Direct
6723 );
6724
6725 let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6726 shape_ast::ast::VarKind::Var,
6727 false,
6728 ));
6729 assert_eq!(
6730 var_semantics.ownership_class,
6731 crate::type_tracking::BindingOwnershipClass::Flexible
6732 );
6733 assert_eq!(
6734 var_semantics.storage_class,
6735 crate::type_tracking::BindingStorageClass::Deferred
6736 );
6737 }
6738
6739 #[test]
6740 fn test_destructured_module_bindings_get_binding_semantics() {
6741 let mut compiler = BytecodeCompiler::new();
6742 let pattern = shape_ast::ast::DestructurePattern::Array(vec![
6743 shape_ast::ast::DestructurePattern::Identifier(
6744 "left".to_string(),
6745 shape_ast::ast::Span::DUMMY,
6746 ),
6747 shape_ast::ast::DestructurePattern::Identifier(
6748 "right".to_string(),
6749 shape_ast::ast::Span::DUMMY,
6750 ),
6751 ]);
6752 compiler
6753 .compile_destructure_pattern_global(&pattern)
6754 .expect("destructure should compile");
6755 compiler.apply_binding_semantics_to_pattern_bindings(
6756 &pattern,
6757 false,
6758 BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6759 shape_ast::ast::VarKind::Let,
6760 false,
6761 )),
6762 );
6763
6764 let left_idx = *compiler
6765 .module_bindings
6766 .get("left")
6767 .expect("left binding should exist");
6768 let right_idx = *compiler
6769 .module_bindings
6770 .get("right")
6771 .expect("right binding should exist");
6772
6773 assert_eq!(
6774 compiler
6775 .type_tracker
6776 .get_binding_semantics(left_idx)
6777 .map(|semantics| semantics.ownership_class),
6778 Some(crate::type_tracking::BindingOwnershipClass::OwnedImmutable)
6779 );
6780 assert_eq!(
6781 compiler
6782 .type_tracker
6783 .get_binding_semantics(left_idx)
6784 .map(|semantics| semantics.storage_class),
6785 Some(crate::type_tracking::BindingStorageClass::Direct)
6786 );
6787 assert_eq!(
6788 compiler
6789 .type_tracker
6790 .get_binding_semantics(right_idx)
6791 .map(|semantics| semantics.ownership_class),
6792 Some(crate::type_tracking::BindingOwnershipClass::OwnedImmutable)
6793 );
6794 }
6795
6796 #[test]
6797 fn test_flexible_binding_alias_initializer_marks_shared_storage() {
6798 let mut compiler = BytecodeCompiler::new();
6799 compiler.push_scope();
6800 let source = compiler.declare_local("source").expect("declare source");
6801 let dest = compiler.declare_local("dest").expect("declare dest");
6802 let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6803 shape_ast::ast::VarKind::Var,
6804 false,
6805 ));
6806 compiler
6807 .type_tracker
6808 .set_local_binding_semantics(source, var_semantics);
6809 compiler
6810 .type_tracker
6811 .set_local_binding_semantics(dest, var_semantics);
6812
6813 compiler.plan_flexible_binding_storage_from_expr(
6814 dest,
6815 true,
6816 &shape_ast::ast::Expr::Identifier("source".to_string(), shape_ast::ast::Span::DUMMY),
6817 );
6818
6819 assert_eq!(
6820 compiler
6821 .type_tracker
6822 .get_local_binding_semantics(source)
6823 .map(|semantics| semantics.storage_class),
6824 Some(crate::type_tracking::BindingStorageClass::SharedCow)
6825 );
6826 assert_eq!(
6827 compiler
6828 .type_tracker
6829 .get_local_binding_semantics(dest)
6830 .map(|semantics| semantics.storage_class),
6831 Some(crate::type_tracking::BindingStorageClass::SharedCow)
6832 );
6833 }
6834
6835 #[test]
6836 fn test_flexible_destructure_bindings_finalize_to_direct_storage() {
6837 let mut compiler = BytecodeCompiler::new();
6838 compiler.push_scope();
6839 let left = compiler.declare_local("left").expect("declare left");
6840 let right = compiler.declare_local("right").expect("declare right");
6841 let var_semantics = BytecodeCompiler::binding_semantics_for_var_decl(&test_decl(
6842 shape_ast::ast::VarKind::Var,
6843 false,
6844 ));
6845 compiler
6846 .type_tracker
6847 .set_local_binding_semantics(left, var_semantics);
6848 compiler
6849 .type_tracker
6850 .set_local_binding_semantics(right, var_semantics);
6851
6852 let pattern = shape_ast::ast::DestructurePattern::Array(vec![
6853 shape_ast::ast::DestructurePattern::Identifier(
6854 "left".to_string(),
6855 shape_ast::ast::Span::DUMMY,
6856 ),
6857 shape_ast::ast::DestructurePattern::Identifier(
6858 "right".to_string(),
6859 shape_ast::ast::Span::DUMMY,
6860 ),
6861 ]);
6862 compiler.plan_flexible_binding_storage_for_pattern_initializer(
6863 &pattern,
6864 true,
6865 Some(&shape_ast::ast::Expr::Identifier(
6866 "source".to_string(),
6867 shape_ast::ast::Span::DUMMY,
6868 )),
6869 );
6870
6871 assert_eq!(
6872 compiler
6873 .type_tracker
6874 .get_local_binding_semantics(left)
6875 .map(|semantics| semantics.storage_class),
6876 Some(crate::type_tracking::BindingStorageClass::Direct)
6877 );
6878 assert_eq!(
6879 compiler
6880 .type_tracker
6881 .get_local_binding_semantics(right)
6882 .map(|semantics| semantics.storage_class),
6883 Some(crate::type_tracking::BindingStorageClass::Direct)
6884 );
6885 }
6886
6887 #[test]
6888 fn test_module_var_alias_decl_marks_shared_storage() {
6889 let program = parse_program(
6890 r#"
6891 var source = [1]
6892 var alias = source
6893 "#,
6894 )
6895 .expect("parse failed");
6896 let mut compiler = BytecodeCompiler::new();
6897 let first_decl = match &program.items[0] {
6898 Item::VariableDecl(var_decl, _) => {
6899 Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
6900 }
6901 Item::Statement(stmt, _) => stmt.clone(),
6902 _ => panic!("expected first variable declaration"),
6903 };
6904 let second_decl = match &program.items[1] {
6905 Item::VariableDecl(var_decl, _) => {
6906 Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
6907 }
6908 Item::Statement(stmt, _) => stmt.clone(),
6909 _ => panic!("expected second variable declaration"),
6910 };
6911 compiler
6912 .compile_statement(&first_decl)
6913 .expect("first decl should compile");
6914 compiler
6915 .compile_statement(&second_decl)
6916 .expect("second decl should compile");
6917
6918 let source_idx = *compiler
6919 .module_bindings
6920 .get("source")
6921 .expect("source binding should exist");
6922 let alias_idx = *compiler
6923 .module_bindings
6924 .get("alias")
6925 .expect("alias binding should exist");
6926
6927 assert_eq!(
6928 compiler
6929 .type_tracker
6930 .get_binding_semantics(source_idx)
6931 .map(|semantics| semantics.storage_class),
6932 Some(crate::type_tracking::BindingStorageClass::SharedCow)
6933 );
6934 assert_eq!(
6935 compiler
6936 .type_tracker
6937 .get_binding_semantics(alias_idx)
6938 .map(|semantics| semantics.storage_class),
6939 Some(crate::type_tracking::BindingStorageClass::SharedCow)
6940 );
6941 }
6942
6943 #[test]
6944 fn test_module_var_fresh_decl_marks_direct_storage() {
6945 let program = parse_program("var values = [1, 2, 3]").expect("parse failed");
6946 let mut compiler = BytecodeCompiler::new();
6947 let decl = match &program.items[0] {
6948 Item::VariableDecl(var_decl, _) => {
6949 Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
6950 }
6951 Item::Statement(stmt, _) => stmt.clone(),
6952 _ => panic!("expected variable declaration"),
6953 };
6954 compiler
6955 .compile_statement(&decl)
6956 .expect("decl should compile");
6957
6958 let values_idx = *compiler
6959 .module_bindings
6960 .get("values")
6961 .expect("values binding should exist");
6962
6963 assert_eq!(
6964 compiler
6965 .type_tracker
6966 .get_binding_semantics(values_idx)
6967 .map(|semantics| semantics.storage_class),
6968 Some(crate::type_tracking::BindingStorageClass::Direct)
6969 );
6970 }
6971
6972 #[test]
6973 fn test_module_var_collection_escape_marks_source_unique_heap() {
6974 let program = parse_program(
6975 r#"
6976 var source = [1]
6977 var wrapped = [source]
6978 "#,
6979 )
6980 .expect("parse failed");
6981 let mut compiler = BytecodeCompiler::new();
6982 for item in &program.items {
6983 let stmt = match item {
6984 Item::VariableDecl(var_decl, _) => {
6985 Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
6986 }
6987 Item::Statement(stmt, _) => stmt.clone(),
6988 _ => continue,
6989 };
6990 compiler
6991 .compile_statement(&stmt)
6992 .expect("item should compile");
6993 }
6994
6995 let source_idx = *compiler
6996 .module_bindings
6997 .get("source")
6998 .expect("source binding should exist");
6999 let wrapped_idx = *compiler
7000 .module_bindings
7001 .get("wrapped")
7002 .expect("wrapped binding should exist");
7003
7004 assert_eq!(
7005 compiler
7006 .type_tracker
7007 .get_binding_semantics(source_idx)
7008 .map(|semantics| semantics.storage_class),
7009 Some(crate::type_tracking::BindingStorageClass::UniqueHeap)
7010 );
7011 assert_eq!(
7012 compiler
7013 .type_tracker
7014 .get_binding_semantics(wrapped_idx)
7015 .map(|semantics| semantics.storage_class),
7016 Some(crate::type_tracking::BindingStorageClass::Direct)
7017 );
7018 }
7019
7020 #[test]
7021 fn test_module_var_assignment_alias_marks_shared_storage() {
7022 let program = parse_program(
7023 r#"
7024 var source = [1]
7025 var alias = []
7026 alias = source
7027 "#,
7028 )
7029 .expect("parse failed");
7030 let mut compiler = BytecodeCompiler::new();
7031 for item in &program.items {
7032 let stmt = match item {
7033 Item::VariableDecl(var_decl, _) => {
7034 Statement::VariableDecl(var_decl.clone(), Span::DUMMY)
7035 }
7036 Item::Assignment(assign, _) => Statement::Assignment(assign.clone(), Span::DUMMY),
7037 Item::Statement(stmt, _) => stmt.clone(),
7038 _ => continue,
7039 };
7040 compiler
7041 .compile_statement(&stmt)
7042 .expect("item should compile");
7043 }
7044
7045 let source_idx = *compiler
7046 .module_bindings
7047 .get("source")
7048 .expect("source binding should exist");
7049 let alias_idx = *compiler
7050 .module_bindings
7051 .get("alias")
7052 .expect("alias binding should exist");
7053
7054 assert_eq!(
7055 compiler
7056 .type_tracker
7057 .get_binding_semantics(source_idx)
7058 .map(|semantics| semantics.storage_class),
7059 Some(crate::type_tracking::BindingStorageClass::SharedCow)
7060 );
7061 assert_eq!(
7062 compiler
7063 .type_tracker
7064 .get_binding_semantics(alias_idx)
7065 .map(|semantics| semantics.storage_class),
7066 Some(crate::type_tracking::BindingStorageClass::SharedCow)
7067 );
7068 }
7069
7070 #[test]
7083 fn desugar_impl_method_backfills_return_type_from_trait_declaration() {
7084 let code = r#"
7095 trait T { method name() -> string }
7096 type X {}
7097 impl T for X {
7098 method name() { "x" }
7099 }
7100 "#;
7101 let program = parse_program(code).expect("Failed to parse");
7102 let bytecode = BytecodeCompiler::new()
7103 .compile(&program)
7104 .expect("Failed to compile");
7105
7106 let func_def = bytecode
7110 .expanded_function_defs
7111 .get("X::name")
7112 .expect("X::name function def should be registered");
7113
7114 assert!(
7115 func_def.return_type.is_some(),
7116 "T1' gap 3: impl method `X::name` return_type should be \
7117 backfilled from trait declaration `T::method name() -> string`, \
7118 got None"
7119 );
7120
7121 let return_ann = func_def
7125 .return_type
7126 .as_ref()
7127 .expect("return_type Some after backfill");
7128 match return_ann {
7129 shape_ast::ast::TypeAnnotation::Basic(name) => {
7130 assert_eq!(
7131 name, "string",
7132 "T1' gap 3: backfilled return_type must be the \
7133 trait's declared `string`, got Basic(`{}`)",
7134 name
7135 );
7136 }
7137 other => panic!(
7138 "T1' gap 3: expected Basic(\"string\") from trait \
7139 declaration, got: {:?}",
7140 other
7141 ),
7142 }
7143 }
7144
7145 #[test]
7146 fn desugar_impl_method_preserves_explicit_impl_return_type() {
7147 let code = r#"
7157 trait T { method name() -> string }
7158 type X {}
7159 impl T for X {
7160 method name() -> string { "x" }
7161 }
7162 "#;
7163 let program = parse_program(code).expect("Failed to parse");
7164 let bytecode = BytecodeCompiler::new()
7165 .compile(&program)
7166 .expect("Failed to compile");
7167
7168 let func_def = bytecode
7169 .expanded_function_defs
7170 .get("X::name")
7171 .expect("X::name function def should be registered");
7172
7173 let return_ann = func_def
7174 .return_type
7175 .as_ref()
7176 .expect("return_type Some — impl declared explicitly");
7177 match return_ann {
7178 shape_ast::ast::TypeAnnotation::Basic(name) => {
7179 assert_eq!(
7180 name, "string",
7181 "T1' gap 3: explicit impl return_type must be \
7182 preserved verbatim"
7183 );
7184 }
7185 other => panic!(
7186 "T1' gap 3: expected explicit Basic(\"string\") from \
7187 impl source, got: {:?}",
7188 other
7189 ),
7190 }
7191 }
7192
7193 #[test]
7194 fn desugar_impl_method_leaves_none_when_trait_method_has_no_return_type() {
7195 let code = r#"
7208 trait T {
7209 method greet() { print("hi") }
7210 }
7211 type X {}
7212 impl T for X {}
7213 "#;
7214 let program = parse_program(code).expect("Failed to parse");
7215 let bytecode = BytecodeCompiler::new()
7216 .compile(&program)
7217 .expect("Failed to compile");
7218
7219 if let Some(func_def) = bytecode.expanded_function_defs.get("X::greet") {
7224 assert!(
7225 func_def.return_type.is_none(),
7226 "T1' gap 3: trait default method without return_type \
7227 must not fabricate a default annotation, got: {:?}",
7228 func_def.return_type
7229 );
7230 }
7231 }
7236}