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