1use std::collections::{BTreeMap, BTreeSet, HashMap};
5
6use wasm_encoder::{HeapType, RefType, ValType};
7
8use crate::codegen::closures::ClosureSig;
9use crate::codegen::internal_failure;
10use crate::codegen::intrinsics::{IntrinsicTypeIndices, intrinsic_supertypes};
11use crate::compiler_error::CompilerFailure;
12use crate::{Dispatch, ExprId, MangledName, Type};
13
14#[derive(Clone, Debug)]
18pub enum FieldSetup {
19 Init { field: String, value: ExprId },
21 ParamCopy {
23 field: String,
24 param: Box<crate::TypedParam>,
25 },
26 Reset { field: String },
30}
31
32#[derive(Default, Clone, Copy, Debug)]
33pub struct ClassGuardLayout {
34 pub inheritance_depth: u32,
35 pub named_payload_len: u32,
36 pub has_instance_guards: bool,
37}
38
39#[derive(Default, Clone, Debug)]
40pub struct SymbolTable {
41 pub(crate) field_lookup_function: Option<u32>,
42 pub(crate) resultless_functions: BTreeSet<u32>,
43 host_parameter_defaults: BTreeMap<u32, Vec<Option<crate::DefaultValue>>>,
45 pub class_type_parameters: BTreeMap<MangledName, Vec<String>>,
46 pub runtime_generic_functions: BTreeSet<MangledName>,
47 pub field_guard_targets: BTreeMap<u32, Type>,
48 pub type_descriptor_functions: BTreeMap<Type, u32>,
49 pub type_descriptor_globals: BTreeMap<Type, u32>,
50 pub descriptor_schemas: BTreeMap<Type, String>,
53 types: BTreeMap<MangledName, u32>,
54 funcs: BTreeMap<MangledName, u32>,
55 globals: BTreeMap<MangledName, u32>,
56 global_types: BTreeMap<MangledName, Type>,
57 init_guards: BTreeMap<MangledName, crate::codegen::init_guard::InitFlag>,
58 class_declaration_flags: BTreeMap<usize, Vec<u32>>,
61 intrinsic_type_indices: Option<IntrinsicTypeIndices>,
62 pub(crate) this_environment_type: Option<u32>,
63 pub(crate) call_metadata_type: Option<u32>,
64 pub(crate) function_argument_metadata: BTreeMap<MangledName, String>,
65 class_struct_type_idx: BTreeMap<MangledName, u32>,
68 class_vtable_type_idx: BTreeMap<MangledName, u32>,
69 class_vtable_global_idx: BTreeMap<MangledName, u32>,
70 class_getter_global_idx: BTreeMap<MangledName, u32>,
71 class_setter_global_idx: BTreeMap<MangledName, u32>,
72 class_method_func_idx: BTreeMap<(MangledName, String), u32>,
73 class_ctor_init_func_idx: BTreeMap<MangledName, u32>,
77 class_method_adapter_func_idx: BTreeMap<(MangledName, String), u32>,
80 class_method_slot: BTreeMap<(MangledName, String), u32>,
83 class_payload_methods: BTreeSet<(MangledName, String)>,
85 rewritable_members: crate::codegen::classes::RewritableMembers,
87 class_method_sig: BTreeMap<(MangledName, String), u32>,
89 class_method_abi: BTreeMap<(MangledName, String), MethodSlotAbi>,
92 class_ctor_abi: BTreeMap<MangledName, Vec<ValType>>,
95 class_field_slot: BTreeMap<(MangledName, String), u32>,
98 class_field_narrowing_check: BTreeMap<(MangledName, String), crate::FieldNarrowingCheck>,
100 class_field_setup: BTreeMap<MangledName, Vec<FieldSetup>>,
103 vtable_global_idx: BTreeMap<Type, u32>,
104 field_names_global_idx: BTreeMap<Vec<super::field_names::FieldName>, u32>,
105 optional_field_name_type: Option<u32>,
106 field_name_string_global_idx: BTreeMap<String, u32>,
107 box_type_idx: HashMap<ValType, u32>,
109 struct_supertype: BTreeMap<u32, u32>,
112 closure_func_type_idx: BTreeMap<ClosureSig, u32>,
113 closure_struct_type_idx: BTreeMap<ClosureSig, u32>,
114 closure_coercions: BTreeMap<ClosureSig, u32>,
115 closure_coercion_vtable_type: Option<u32>,
116 env_type_idx: BTreeMap<ExprId, u32>,
117 closure_func_idx: BTreeMap<ExprId, u32>,
118 closure_vtable_global_idx: Option<u32>,
119 error_tag_idx: Option<u32>,
121 adapter_func_idx: BTreeMap<MangledName, u32>,
122 adapter_closure_global_idx: BTreeMap<MangledName, u32>,
123 shared_closure_globals: BTreeSet<MangledName>,
126 runtime_validator_idx: BTreeMap<Type, u32>,
128 generic_runtime_validators: BTreeMap<MangledName, (Vec<String>, u32)>,
129 instance_field_guards: BTreeMap<(Type, MangledName, String), u32>,
130 class_guard_layout: BTreeMap<MangledName, ClassGuardLayout>,
131 top_level_fns: BTreeMap<MangledName, TopLevelFn>,
133 iface_dispatch: BTreeMap<MangledName, Dispatch>,
134 static_value_tags: BTreeMap<MangledName, String>,
137 iface_method_abi: BTreeMap<MangledName, MethodSlotAbi>,
140 intrinsic_members: BTreeSet<MangledName>,
142}
143
144#[derive(Clone, Debug)]
145pub struct TopLevelFn {
146 pub wasm_idx: u32,
147 pub params: Vec<Type>,
148 pub ret: Type,
149 pub is_host: bool,
152}
153
154#[derive(Clone, Debug, Default, PartialEq)]
167pub struct MethodSlotAbi {
168 pub params: Vec<ValType>,
170 pub ret: Option<ValType>,
172}
173
174pub fn is_erased(ty: &Type) -> bool {
182 match ty.lowered() {
183 Type::TypeVar(_) | Type::GenericParam { .. } | Type::ClassRef { .. } => true,
184 Type::Union(members) => members.iter().any(is_erased),
185 _ => false,
186 }
187}
188
189pub(crate) fn is_nullable_ref(val: ValType) -> bool {
192 matches!(val, ValType::Ref(RefType { nullable: true, .. }))
193}
194
195pub(crate) fn may_hold_null(ty: &Type) -> bool {
204 match ty.lowered() {
205 Type::Null
208 | Type::Void
209 | Type::Unknown
210 | Type::TypeVar(_)
211 | Type::GenericParam { .. }
212 | Type::AliasRef { .. } => true,
213 Type::Union(members) => members.iter().any(may_hold_null),
214 _ => false,
215 }
216}
217
218impl SymbolTable {
219 pub fn new() -> Self {
220 Self::default()
221 }
222
223 pub fn type_idx(&self, mangled: &MangledName) -> Option<u32> {
224 self.types.get(mangled).copied()
225 }
226
227 pub fn func_idx(&self, mangled: &MangledName) -> Option<u32> {
228 self.funcs.get(mangled).copied()
229 }
230
231 pub fn global_idx(&self, mangled: &MangledName) -> Option<u32> {
232 self.globals.get(mangled).copied()
233 }
234
235 pub fn global_type(&self, mangled: &MangledName) -> Option<&Type> {
236 self.global_types.get(mangled)
237 }
238
239 pub fn init_guard(
240 &self,
241 global: &MangledName,
242 ) -> Option<&crate::codegen::init_guard::InitFlag> {
243 self.init_guards.get(global)
244 }
245
246 pub fn class_declaration_flags(&self, index: usize) -> &[u32] {
247 self.class_declaration_flags
248 .get(&index)
249 .map_or(&[], Vec::as_slice)
250 }
251
252 pub fn prelude_func_idx(&self, symbol: &str) -> Option<u32> {
253 self.func_idx(&crate::mangle::prelude(symbol))
254 }
255
256 pub fn prelude_global_idx(&self, symbol: &str) -> Option<u32> {
257 self.global_idx(&crate::mangle::prelude(symbol))
258 }
259
260 pub fn string_type_idx(&self) -> Option<u32> {
261 self.intrinsic_type_indices.map(|i| i.string)
262 }
263
264 pub fn raw_string_type_idx(&self) -> Option<u32> {
265 self.intrinsic_type_indices.map(|i| i.raw_string)
266 }
267
268 pub fn bigint_type_idx(&self) -> Option<u32> {
269 self.intrinsic_type_indices.map(|i| i.bigint)
270 }
271
272 pub fn raw_bigint_type_idx(&self) -> Option<u32> {
273 self.intrinsic_type_indices.map(|i| i.raw_bigint)
274 }
275
276 pub fn regex_type_idx(&self) -> Option<u32> {
277 self.intrinsic_type_indices.map(|i| i.regex)
278 }
279
280 pub fn regex_match_type_idx(&self) -> Option<u32> {
281 self.intrinsic_type_indices.map(|i| i.regex_match)
282 }
283
284 pub fn regex_capture_array_type_idx(&self) -> Option<u32> {
285 self.intrinsic_type_indices.map(|i| i.regex_capture_array)
286 }
287
288 pub fn regex_match_box_type_idx(&self) -> Option<u32> {
289 self.intrinsic_type_indices.map(|i| i.regex_match_box)
290 }
291
292 pub fn boxed_number_type_idx(&self) -> Option<u32> {
293 self.intrinsic_type_indices.map(|i| i.boxed_number)
294 }
295
296 pub fn boxed_boolean_type_idx(&self) -> Option<u32> {
297 self.intrinsic_type_indices.map(|i| i.boxed_boolean)
298 }
299
300 pub fn raw_array_type_idx(&self) -> Option<u32> {
301 self.intrinsic_type_indices.map(|i| i.raw_array)
302 }
303
304 pub fn field_names_type_idx(&self) -> Option<u32> {
305 self.intrinsic_type_indices.map(|i| i.field_names)
306 }
307
308 pub fn object_shape_type_idx(&self) -> Option<u32> {
309 self.intrinsic_type_indices.map(|i| i.object_shape)
310 }
311
312 pub fn array_type_idx(&self) -> Option<u32> {
313 self.intrinsic_type_indices.map(|i| i.array)
314 }
315
316 pub fn raw_uint8_array_type_idx(&self) -> Option<u32> {
317 self.intrinsic_type_indices.map(|i| i.raw_uint8_array)
318 }
319
320 pub fn uint8_array_type_idx(&self) -> Option<u32> {
321 self.intrinsic_type_indices.map(|i| i.uint8_array)
322 }
323
324 pub fn closure_type_idx(&self) -> Option<u32> {
325 self.intrinsic_type_indices.map(|i| i.closure)
326 }
327
328 pub fn intrinsic_type_indices(&self) -> Option<IntrinsicTypeIndices> {
329 self.intrinsic_type_indices
330 }
331
332 pub fn object_subtype_idx(&self, ty: &Type) -> Option<u32> {
333 match ty {
334 Type::Object { .. } => self.object_shape_type_idx(),
335 _ => None,
336 }
337 }
338
339 pub fn class_struct_type_idx(&self, mangled: &MangledName) -> Option<u32> {
340 self.class_struct_type_idx.get(mangled).copied()
341 }
342
343 pub fn class_vtable_type_idx(&self, mangled: &MangledName) -> Option<u32> {
344 self.class_vtable_type_idx.get(mangled).copied()
345 }
346
347 pub fn class_vtable_global_idx(&self, mangled: &MangledName) -> Option<u32> {
348 self.class_vtable_global_idx.get(mangled).copied()
349 }
350
351 pub fn class_getter_global_idx(&self, mangled: &MangledName) -> Option<u32> {
352 self.class_getter_global_idx.get(mangled).copied()
353 }
354
355 pub fn class_setter_global_idx(&self, mangled: &MangledName) -> Option<u32> {
356 self.class_setter_global_idx.get(mangled).copied()
357 }
358
359 pub fn class_method_func_idx(&self, class: &MangledName, method: &str) -> Option<u32> {
360 self.class_method_func_idx
361 .get(&(class.clone(), method.to_string()))
362 .copied()
363 }
364
365 pub fn class_ctor_init_func_idx(&self, class: &MangledName) -> Option<u32> {
366 self.class_ctor_init_func_idx.get(class).copied()
367 }
368
369 pub fn class_method_adapter_func_idx(&self, class: &MangledName, method: &str) -> Option<u32> {
370 self.class_method_adapter_func_idx
371 .get(&(class.clone(), method.to_string()))
372 .copied()
373 }
374
375 pub fn class_method_slot(&self, class: &MangledName, method: &str) -> Option<u32> {
376 self.class_method_slot
377 .get(&(class.clone(), method.to_string()))
378 .copied()
379 }
380
381 pub fn is_class_payload_method(&self, class: &MangledName, method: &str) -> bool {
382 self.class_payload_methods
383 .contains(&(class.clone(), method.to_string()))
384 }
385
386 pub fn class_method_sig(&self, class: &MangledName, method: &str) -> Option<u32> {
387 self.class_method_sig
388 .get(&(class.clone(), method.to_string()))
389 .copied()
390 }
391
392 pub fn class_method_abi(&self, class: &MangledName, method: &str) -> Option<&MethodSlotAbi> {
393 self.class_method_abi
394 .get(&(class.clone(), method.to_string()))
395 }
396
397 pub fn class_ctor_abi(&self, class: &MangledName) -> Option<&[ValType]> {
398 self.class_ctor_abi.get(class).map(Vec::as_slice)
399 }
400
401 pub fn class_field_slot(&self, class: &MangledName, field: &str) -> Option<u32> {
402 self.class_field_slot
403 .get(&(class.clone(), field.to_string()))
404 .copied()
405 }
406
407 pub fn class_field_narrowing_check(
409 &self,
410 class: &MangledName,
411 field: &str,
412 ) -> Option<&crate::FieldNarrowingCheck> {
413 self.class_field_narrowing_check
414 .get(&(class.clone(), field.to_string()))
415 }
416
417 pub fn class_field_narrowing_checks<'a>(
418 &'a self,
419 field: &'a str,
420 ) -> impl Iterator<Item = (&'a MangledName, &'a crate::FieldNarrowingCheck)> + 'a {
421 self.class_field_narrowing_check
422 .iter()
423 .filter(move |((_, name), _)| name == field)
424 .map(|((class, _), check)| (class, check))
425 }
426
427 pub fn class_field_setup(&self, class: &MangledName) -> Option<&[FieldSetup]> {
428 self.class_field_setup.get(class).map(Vec::as_slice)
429 }
430
431 pub fn vtable_global_idx(&self, ty: &Type) -> Option<u32> {
432 self.vtable_global_idx.get(ty).copied()
433 }
434
435 pub fn record_optional_field_name_type(&mut self, index: u32) {
436 self.optional_field_name_type = Some(index);
437 }
438
439 pub fn optional_field_name_type(&self) -> Result<u32, CompilerFailure> {
440 self.optional_field_name_type
441 .ok_or_else(|| internal_failure("optional field-name type was not declared"))
442 }
443
444 pub fn field_names_global_idx(
445 &self,
446 field_names: &[super::field_names::FieldName],
447 ) -> Option<u32> {
448 self.field_names_global_idx.get(field_names).copied()
449 }
450
451 pub fn field_name_string_global_idx(&self, name: &str) -> Option<u32> {
452 self.field_name_string_global_idx.get(name).copied()
453 }
454
455 pub fn box_type_idx(
460 &self,
461 ty: &Type,
462 ) -> Result<Option<u32>, crate::compiler_error::CompilerFailure> {
463 Ok(self.box_type_idx.get(&self.slot_value_type(ty)?).copied())
464 }
465
466 pub fn box_payload_type(&self, idx: u32) -> Option<ValType> {
474 self.box_type_idx
475 .iter()
476 .find(|&(_, &v)| v == idx)
477 .map(|(payload, _)| *payload)
478 }
479
480 pub fn closure_func_type_idx(&self, sig: ClosureSig) -> Option<u32> {
481 self.closure_func_type_idx.get(&sig).copied()
482 }
483
484 pub fn record_closure_coercion_vtable_type(&mut self, index: u32) {
485 self.closure_coercion_vtable_type = Some(index);
486 }
487
488 pub fn closure_coercion_vtable_type(
489 &self,
490 ) -> Result<u32, crate::compiler_error::CompilerFailure> {
491 self.closure_coercion_vtable_type.ok_or_else(|| {
492 crate::codegen::internal_failure("closure coercion vtable is not registered")
493 })
494 }
495
496 pub fn closure_signatures(&self) -> impl Iterator<Item = ClosureSig> + '_ {
497 self.closure_struct_type_idx.keys().copied()
498 }
499
500 pub fn record_closure_coercion(&mut self, target: ClosureSig, index: u32) {
501 self.closure_coercions.insert(target, index);
502 }
503
504 pub fn closure_coercion(&self, target: ClosureSig) -> Option<u32> {
505 self.closure_coercions.get(&target).copied()
506 }
507
508 pub fn closure_struct_type_idx(&self, sig: ClosureSig) -> Option<u32> {
509 self.closure_struct_type_idx.get(&sig).copied()
510 }
511
512 pub fn env_type_idx(&self, expr_id: ExprId) -> Option<u32> {
513 self.env_type_idx.get(&expr_id).copied()
514 }
515
516 pub fn closure_func_idx(&self, expr_id: ExprId) -> Option<u32> {
517 self.closure_func_idx.get(&expr_id).copied()
518 }
519
520 pub fn closure_vtable_global_idx(&self) -> Option<u32> {
521 self.closure_vtable_global_idx
522 }
523
524 pub fn adapter_func_idx(&self, mangled: &MangledName) -> Option<u32> {
525 self.adapter_func_idx.get(mangled).copied()
526 }
527
528 pub fn adapter_closure_global_idx(&self, mangled: &MangledName) -> Option<u32> {
529 self.adapter_closure_global_idx.get(mangled).copied()
530 }
531
532 pub fn is_shared_closure_global(&self, mangled: &MangledName) -> bool {
533 self.shared_closure_globals.contains(mangled)
534 }
535
536 pub fn ref_fits_slot(&self, value: RefType, slot: RefType) -> bool {
545 if value.nullable && !slot.nullable {
546 return false;
547 }
548 let (HeapType::Concrete(value_idx), HeapType::Concrete(slot_idx)) =
549 (value.heap_type, slot.heap_type)
550 else {
551 return value.heap_type == slot.heap_type;
552 };
553 let mut current = value_idx;
554 while current != slot_idx {
555 match self.struct_supertype.get(¤t) {
558 Some(&parent) if parent < current => current = parent,
559 _ => return false,
560 }
561 }
562 true
563 }
564
565 pub fn record_type(&mut self, mangled: MangledName, idx: u32) {
566 self.types.insert(mangled, idx);
567 }
568
569 pub fn set_intrinsic_type_indices(&mut self, indices: IntrinsicTypeIndices) {
572 self.intrinsic_type_indices = Some(indices);
573 for (child, parent) in intrinsic_supertypes(indices) {
574 self.record_struct_supertype(child, parent);
575 }
576 }
577
578 pub fn record_struct_supertype(&mut self, child: u32, parent: u32) {
579 self.struct_supertype.insert(child, parent);
580 }
581
582 pub fn record_class_struct_type(&mut self, mangled: MangledName, idx: u32) {
583 self.class_struct_type_idx.insert(mangled, idx);
584 }
585
586 pub fn record_class_vtable_type(&mut self, mangled: MangledName, idx: u32) {
587 self.class_vtable_type_idx.insert(mangled, idx);
588 }
589
590 pub fn record_class_vtable_global(&mut self, mangled: MangledName, idx: u32) {
591 self.class_vtable_global_idx.insert(mangled, idx);
592 }
593
594 pub fn record_class_getter_global(&mut self, mangled: MangledName, idx: u32) {
595 self.class_getter_global_idx.insert(mangled, idx);
596 }
597
598 pub fn record_class_setter_global(&mut self, mangled: MangledName, idx: u32) {
599 self.class_setter_global_idx.insert(mangled, idx);
600 }
601
602 pub fn record_class_method_func(&mut self, class: MangledName, method: String, idx: u32) {
603 self.class_method_func_idx.insert((class, method), idx);
604 }
605
606 pub fn record_class_ctor_init_func(&mut self, class: MangledName, idx: u32) {
607 self.class_ctor_init_func_idx.insert(class, idx);
608 }
609
610 pub fn record_class_method_adapter_func(
611 &mut self,
612 class: MangledName,
613 method: String,
614 idx: u32,
615 ) {
616 self.class_method_adapter_func_idx
617 .insert((class, method), idx);
618 }
619
620 pub fn record_class_method_slot(&mut self, class: MangledName, method: String, slot: u32) {
621 self.class_method_slot.insert((class, method), slot);
622 }
623
624 pub(crate) fn record_host_parameter_defaults(
625 &mut self,
626 func_idx: u32,
627 defaults: Vec<Option<crate::DefaultValue>>,
628 ) {
629 self.host_parameter_defaults.insert(func_idx, defaults);
630 }
631
632 pub(crate) fn host_call_defaults(
639 &self,
640 func_idx: u32,
641 arg_count: usize,
642 ) -> &[Option<crate::DefaultValue>] {
643 let defaults = self
644 .host_parameter_defaults
645 .get(&func_idx)
646 .map_or(&[][..], Vec::as_slice);
647 let receivers = defaults.len().saturating_sub(arg_count);
648 defaults.get(receivers..).unwrap_or_default()
649 }
650
651 pub fn record_class_payload_method(&mut self, class: MangledName, method: String) {
652 self.class_payload_methods.insert((class, method));
653 }
654
655 pub(crate) fn record_rewritable_members(
656 &mut self,
657 members: crate::codegen::classes::RewritableMembers,
658 ) {
659 self.rewritable_members = members;
660 }
661
662 pub fn is_rewritable_class_method(&self, class: &MangledName, method: &str) -> bool {
666 self.rewritable_members.includes(method) && self.is_class_payload_method(class, method)
667 }
668
669 pub fn record_class_method_sig(&mut self, class: MangledName, method: String, sig: u32) {
670 self.class_method_sig.insert((class, method), sig);
671 }
672
673 pub fn record_class_method_abi(
674 &mut self,
675 class: MangledName,
676 method: String,
677 abi: MethodSlotAbi,
678 ) {
679 self.class_method_abi.insert((class, method), abi);
680 }
681
682 pub fn record_class_ctor_abi(&mut self, class: MangledName, params: Vec<ValType>) {
683 self.class_ctor_abi.insert(class, params);
684 }
685
686 pub fn record_class_field_narrowing_check(
687 &mut self,
688 class: MangledName,
689 field: String,
690 check: crate::FieldNarrowingCheck,
691 ) {
692 self.class_field_narrowing_check
693 .insert((class, field), check);
694 }
695
696 pub fn record_class_field_slot(&mut self, class: MangledName, field: String, slot: u32) {
697 self.class_field_slot.insert((class, field), slot);
698 }
699
700 pub fn record_class_field_setup(&mut self, class: MangledName, setup: Vec<FieldSetup>) {
701 self.class_field_setup.insert(class, setup);
702 }
703
704 pub fn record_vtable_global(&mut self, ty: Type, idx: u32) {
705 self.vtable_global_idx.insert(ty, idx);
706 }
707
708 pub fn record_field_names_global(
709 &mut self,
710 field_names: Vec<super::field_names::FieldName>,
711 idx: u32,
712 ) {
713 self.field_names_global_idx.insert(field_names, idx);
714 }
715
716 pub fn record_field_name_string_global(&mut self, name: String, idx: u32) {
717 self.field_name_string_global_idx.insert(name, idx);
718 }
719
720 pub fn record_box_type(&mut self, value_type: ValType, idx: u32) {
721 self.box_type_idx.insert(value_type, idx);
722 }
723
724 pub fn record_closure_func_type(&mut self, sig: ClosureSig, idx: u32) {
725 self.closure_func_type_idx.insert(sig, idx);
726 }
727
728 pub fn record_closure_struct_type(&mut self, sig: ClosureSig, idx: u32) {
729 self.closure_struct_type_idx.insert(sig, idx);
730 }
731
732 pub fn record_env_type(&mut self, expr_id: ExprId, idx: u32) {
733 self.env_type_idx.insert(expr_id, idx);
734 }
735
736 pub fn record_closure_func_idx(&mut self, expr_id: ExprId, idx: u32) {
737 self.closure_func_idx.insert(expr_id, idx);
738 }
739
740 pub fn set_closure_vtable_global(&mut self, idx: u32) {
741 self.closure_vtable_global_idx = Some(idx);
742 }
743
744 pub fn error_tag_idx(&self) -> Option<u32> {
746 self.error_tag_idx
747 }
748
749 pub fn set_error_tag_idx(&mut self, idx: u32) {
750 self.error_tag_idx = Some(idx);
751 }
752
753 pub fn record_adapter_func_idx(&mut self, mangled: MangledName, idx: u32) {
754 self.adapter_func_idx.insert(mangled, idx);
755 }
756
757 pub fn record_adapter_closure_global_idx(&mut self, mangled: MangledName, idx: u32) {
758 self.adapter_closure_global_idx.insert(mangled, idx);
759 }
760
761 pub fn record_shared_closure_global_idx(&mut self, mangled: MangledName, idx: u32) {
762 self.shared_closure_globals.insert(mangled.clone());
763 self.adapter_closure_global_idx.insert(mangled, idx);
764 }
765
766 pub fn record_class_guard_layout(
767 &mut self,
768 class: MangledName,
769 parent: Option<&MangledName>,
770 named_len: u32,
771 guarded: bool,
772 ) -> Result<(), CompilerFailure> {
773 let depth = match parent {
774 Some(parent) => self
775 .recorded_class_guard_layout(parent)?
776 .inheritance_depth
777 .checked_add(1)
778 .ok_or_else(|| internal_failure("class inheritance depth overflowed"))?,
779 None => 0,
780 };
781 self.class_guard_layout.insert(
782 class,
783 ClassGuardLayout {
784 inheritance_depth: depth,
785 named_payload_len: named_len,
786 has_instance_guards: guarded,
787 },
788 );
789 Ok(())
790 }
791
792 pub fn class_guard_layout(&self, class: &MangledName) -> ClassGuardLayout {
796 self.class_guard_layout
797 .get(class)
798 .copied()
799 .unwrap_or_default()
800 }
801
802 pub fn recorded_class_guard_layout(
805 &self,
806 class: &MangledName,
807 ) -> Result<ClassGuardLayout, CompilerFailure> {
808 self.class_guard_layout.get(class).copied().ok_or_else(|| {
809 internal_failure(format!(
810 "class `{}` has no recorded guard layout",
811 class.as_str()
812 ))
813 })
814 }
815
816 pub fn record_instance_field_guard(
817 &mut self,
818 class: Type,
819 declaration: MangledName,
820 field: String,
821 function: u32,
822 ) {
823 self.instance_field_guards
824 .insert((class, declaration, field), function);
825 }
826
827 pub fn instance_field_guards<'a>(
828 &'a self,
829 class: &'a Type,
830 ) -> impl Iterator<Item = (&'a MangledName, &'a str, u32)> + 'a {
831 self.instance_field_guards
832 .iter()
833 .filter(move |((ty, _, _), _)| ty == class)
834 .map(|((_, declaration, field), function)| (declaration, field.as_str(), *function))
835 }
836
837 pub fn record_runtime_validator(&mut self, key: Type, idx: u32) {
838 if let Type::AliasRef { mangled, args, .. } | Type::InterfaceRef { mangled, args, .. } =
839 &key
840 && let Some(names) = generic_parameter_names(args)
841 {
842 self.generic_runtime_validators
843 .insert(mangled.clone(), (names, idx));
844 }
845 self.runtime_validator_idx.insert(key, idx);
846 }
847
848 pub fn runtime_validator_idx(&self, key: &Type) -> Option<u32> {
851 self.runtime_validator_idx
852 .get(key)
853 .copied()
854 .or_else(|| self.generic_runtime_validator(key).map(|(_, idx)| idx))
855 }
856
857 pub fn generic_runtime_validator(&self, key: &Type) -> Option<(&[String], u32)> {
858 let (Type::AliasRef {
859 mangled: identity, ..
860 }
861 | Type::InterfaceRef {
862 mangled: identity, ..
863 }) = key.lowered()
864 else {
865 return None;
866 };
867 let (names, index) = self.generic_runtime_validators.get(identity)?;
868 if self
869 .runtime_validator_idx
870 .get(key)
871 .is_some_and(|exact| exact != index)
872 {
873 return None;
874 }
875 Some((names.as_slice(), *index))
876 }
877
878 pub fn record_func(&mut self, mangled: MangledName, idx: u32) {
879 self.funcs.insert(mangled, idx);
880 }
881
882 pub fn record_global(&mut self, mangled: MangledName, idx: u32) {
883 self.globals.insert(mangled, idx);
884 }
885
886 pub fn record_init_guard(
888 &mut self,
889 global: MangledName,
890 flag: crate::codegen::init_guard::InitFlag,
891 ) {
892 self.init_guards.insert(global, flag);
893 }
894
895 pub fn record_class_declaration_flag(&mut self, index: usize, flag_idx: u32) {
896 self.class_declaration_flags
897 .entry(index)
898 .or_default()
899 .push(flag_idx);
900 }
901
902 pub fn record_typed_global(&mut self, mangled: MangledName, idx: u32, ty: Type) {
905 self.global_types.insert(mangled.clone(), ty);
906 self.record_global(mangled, idx);
907 }
908
909 pub fn record_imported_fn(
912 &mut self,
913 mangled: MangledName,
914 idx: u32,
915 params: Vec<Type>,
916 ret: Type,
917 is_host: bool,
918 ) {
919 self.funcs.insert(mangled.clone(), idx);
920 self.top_level_fns.insert(
921 mangled,
922 TopLevelFn {
923 wasm_idx: idx,
924 params,
925 ret,
926 is_host,
927 },
928 );
929 }
930
931 pub fn record_local_fn(
932 &mut self,
933 mangled: MangledName,
934 idx: u32,
935 params: Vec<Type>,
936 ret: Type,
937 ) -> Result<(), CompilerFailure> {
938 if !mangled.as_str().contains(crate::mangle::SEP) {
940 return Err(internal_failure(format!(
941 "local function `{}` has no mangled package prefix",
942 mangled.as_str()
943 )));
944 }
945 self.funcs.insert(mangled.clone(), idx);
946 self.top_level_fns.insert(
947 mangled,
948 TopLevelFn {
949 wasm_idx: idx,
950 params,
951 ret,
952 is_host: false,
953 },
954 );
955 Ok(())
956 }
957
958 pub fn top_level_fn(&self, mangled: &MangledName) -> Option<&TopLevelFn> {
959 self.top_level_fns.get(mangled)
960 }
961
962 pub fn record_iface_dispatch(&mut self, iface: MangledName, dispatch: Dispatch) {
963 self.iface_dispatch.insert(iface, dispatch);
964 }
965
966 pub fn record_static_value_tag(&mut self, iface: MangledName, tag: String) {
967 self.static_value_tags.insert(iface, tag);
968 }
969
970 pub fn static_value_tag(&self, iface: &MangledName) -> Option<&str> {
971 self.static_value_tags.get(iface).map(String::as_str)
972 }
973
974 pub fn iface_dispatch(&self, iface: &MangledName) -> Option<Dispatch> {
975 self.iface_dispatch.get(iface).copied()
976 }
977
978 pub fn record_iface_method_abi(&mut self, method_key: MangledName, abi: MethodSlotAbi) {
979 self.iface_method_abi.insert(method_key, abi);
980 }
981
982 pub fn iface_method_abi(&self, method_key: &MangledName) -> Option<&MethodSlotAbi> {
983 self.iface_method_abi.get(method_key)
984 }
985
986 pub fn record_intrinsic_member(&mut self, mangled: MangledName) {
987 self.intrinsic_members.insert(mangled);
988 }
989
990 pub fn is_intrinsic_member(&self, mangled: &MangledName) -> bool {
991 self.intrinsic_members.contains(mangled)
992 }
993
994 pub fn value_type(&self, ty: &Type) -> Result<ValType, crate::compiler_error::CompilerFailure> {
995 let ty = ty.lowered();
996 Ok(match ty {
997 Type::Number | Type::NumberLiteral(_) => ValType::F64,
998 Type::Boolean | Type::BooleanLiteral(_) => ValType::I32,
999 Type::String | Type::StringLiteral(_) => {
1000 let idx = self.string_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::String requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1001 ValType::Ref(RefType {
1002 nullable: false,
1003 heap_type: HeapType::Concrete(idx),
1004 })
1005 }
1006 Type::BigInt | Type::BigIntLiteral(_) => {
1007 let idx = self.bigint_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::BigInt requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1008 ValType::Ref(RefType {
1009 nullable: false,
1010 heap_type: HeapType::Concrete(idx),
1011 })
1012 }
1013 Type::Object { .. } => {
1014 let idx = self
1019 .intrinsic_type_indices()
1020 .ok_or_else(|| {
1021 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1022 })?
1023 .object_shape;
1024 ValType::Ref(RefType {
1025 nullable: false,
1026 heap_type: HeapType::Concrete(idx),
1027 })
1028 }
1029 Type::Array(_) => {
1030 let idx = self.array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1031 ValType::Ref(RefType {
1032 nullable: false,
1033 heap_type: HeapType::Concrete(idx),
1034 })
1035 }
1036 Type::Tuple(_) => {
1037 let idx = self.array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Tuple requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1040 ValType::Ref(RefType {
1041 nullable: false,
1042 heap_type: HeapType::Concrete(idx),
1043 })
1044 }
1045 Type::Uint8Array => {
1046 let idx = self.uint8_array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Uint8Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1047 ValType::Ref(RefType {
1048 nullable: false,
1049 heap_type: HeapType::Concrete(idx),
1050 })
1051 }
1052 Type::TypeVar(_)
1053 | Type::GenericParam { .. }
1054 | Type::Unknown
1055 | Type::NonPrimitive
1056 | Type::Void => {
1057 let object_idx = self
1060 .intrinsic_type_indices()
1061 .ok_or_else(|| {
1062 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1063 })?
1064 .object;
1065 ValType::Ref(RefType {
1066 nullable: true,
1067 heap_type: HeapType::Concrete(object_idx),
1068 })
1069 }
1070 Type::Function { .. } => {
1071 let sig = crate::codegen::closures::classify(ty)?;
1072 let idx = self.closure_struct_type_idx(sig).ok_or_else(|| {
1073 crate::codegen::internal_failure(format!(
1074 "closure signature {sig:?} is not registered"
1075 ))
1076 })?;
1077 ValType::Ref(RefType {
1078 nullable: false,
1079 heap_type: HeapType::Concrete(idx),
1080 })
1081 }
1082 Type::Null => {
1083 let object_idx = self
1084 .intrinsic_type_indices()
1085 .ok_or_else(|| {
1086 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1087 })?
1088 .object;
1089 ValType::Ref(RefType {
1090 nullable: true,
1091 heap_type: HeapType::Concrete(object_idx),
1092 })
1093 }
1094 Type::Undefined => {
1095 let intrinsic = self.intrinsic_type_indices().ok_or_else(|| {
1096 crate::codegen::internal_failure("undefined intrinsic is not declared")
1097 })?;
1098 ValType::Ref(RefType {
1099 nullable: false,
1100 heap_type: HeapType::Concrete(intrinsic.undefined),
1101 })
1102 }
1103 Type::Error => {
1104 return Err(crate::codegen::internal_failure(
1106 "error cannot occupy a value slot",
1107 ));
1108 }
1109 Type::Never => {
1110 let object_idx = self
1115 .intrinsic_type_indices()
1116 .ok_or_else(|| {
1117 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1118 })?
1119 .object;
1120 ValType::Ref(RefType {
1121 nullable: true,
1122 heap_type: HeapType::Concrete(object_idx),
1123 })
1124 }
1125 Type::Union(members) => {
1126 let lowered: Vec<ValType> = members
1127 .iter()
1128 .map(|m| self.value_type(m))
1129 .collect::<Result<_, _>>()?;
1130 let first_lowering = *lowered.first().ok_or_else(|| {
1131 crate::codegen::internal_failure("Type::Union holds ≥2 members")
1132 })?;
1133 if lowered.iter().all(|&lowering| lowering == first_lowering) {
1134 return Ok(first_lowering);
1135 }
1136 let all_object_or_null = members
1138 .iter()
1139 .all(|m| matches!(m.lowered(), Type::Object { .. } | Type::Null));
1140 let heap_idx = if all_object_or_null {
1141 self.intrinsic_type_indices()
1142 .ok_or_else(|| {
1143 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1144 })?
1145 .object_shape
1146 } else {
1147 self.intrinsic_type_indices()
1148 .ok_or_else(|| {
1149 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1150 })?
1151 .object
1152 };
1153 let nullable = lowered.iter().copied().any(is_nullable_ref)
1158 || members
1159 .iter()
1160 .any(|member| matches!(member.lowered(), Type::Undefined));
1161 ValType::Ref(RefType {
1162 nullable,
1163 heap_type: HeapType::Concrete(heap_idx),
1164 })
1165 }
1166 Type::ClassRef { mangled, .. } => match self.class_struct_type_idx(mangled) {
1174 Some(idx) => ValType::Ref(RefType {
1175 nullable: false,
1176 heap_type: HeapType::Concrete(idx),
1177 }),
1178 None => ValType::Ref(RefType {
1179 nullable: true,
1180 heap_type: HeapType::Concrete(
1181 self.intrinsic_type_indices()
1182 .ok_or_else(|| {
1183 crate::codegen::internal_failure(
1184 "intrinsics declared by codegen entry",
1185 )
1186 })?
1187 .object,
1188 ),
1189 }),
1190 },
1191 Type::InterfaceRef { .. } => {
1192 let object_idx = self
1193 .intrinsic_type_indices()
1194 .ok_or_else(|| {
1195 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1196 })?
1197 .object;
1198 ValType::Ref(RefType {
1199 nullable: true,
1200 heap_type: HeapType::Concrete(object_idx),
1201 })
1202 }
1203 Type::AliasRef { .. } => {
1204 let object_idx = self
1210 .intrinsic_type_indices()
1211 .ok_or_else(|| {
1212 crate::codegen::internal_failure("intrinsics declared by codegen entry")
1213 })?
1214 .object;
1215 ValType::Ref(RefType {
1216 nullable: true,
1217 heap_type: HeapType::Concrete(object_idx),
1218 })
1219 }
1220 Type::NumberEnum { .. } => {
1221 let idx = self.boxed_number_type_idx().ok_or_else(|| {
1222 crate::codegen::internal_failure(
1223 "Type::NumberEnum requires the intrinsic types to be declared",
1224 )
1225 })?;
1226 ValType::Ref(RefType {
1227 nullable: false,
1228 heap_type: HeapType::Concrete(idx),
1229 })
1230 }
1231 Type::StringEnum { .. } => {
1232 let idx = self.string_type_idx().ok_or_else(|| {
1233 crate::codegen::internal_failure(
1234 "Type::StringEnum requires the intrinsic types to be declared",
1235 )
1236 })?;
1237 ValType::Ref(RefType {
1238 nullable: false,
1239 heap_type: HeapType::Concrete(idx),
1240 })
1241 }
1242 Type::Alias { .. } | Type::Refined { .. } | Type::Readonly(_) => {
1243 return Err(crate::codegen::internal_failure(
1244 "unpeeled alias in value type lowering",
1245 ));
1246 }
1247 })
1248 }
1249
1250 pub fn wasm_result(
1251 &self,
1252 ty: &Type,
1253 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1254 Ok(vec![self.value_type(ty)?])
1255 }
1256
1257 pub fn slot_value_type(
1271 &self,
1272 ty: &Type,
1273 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1274 if is_erased(ty) {
1275 let object = self
1276 .intrinsic_type_indices()
1277 .ok_or_else(|| {
1278 crate::codegen::internal_failure(
1279 "intrinsics declared before class slot signatures",
1280 )
1281 })?
1282 .object;
1283 return Ok(ValType::Ref(RefType {
1284 nullable: true,
1285 heap_type: HeapType::Concrete(object),
1286 }));
1287 }
1288 self.value_type(ty)
1289 }
1290
1291 pub fn slot_wasm_result(
1292 &self,
1293 ty: &Type,
1294 ) -> Result<Vec<ValType>, crate::compiler_error::CompilerFailure> {
1295 Ok(vec![self.slot_value_type(ty)?])
1296 }
1297
1298 pub fn host_value_type(
1299 &self,
1300 ty: &Type,
1301 ) -> Result<ValType, crate::compiler_error::CompilerFailure> {
1302 if matches!(ty, Type::String | Type::StringLiteral(_)) {
1303 let idx = self.raw_string_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::String requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1304 return Ok(ValType::Ref(RefType {
1305 nullable: false,
1306 heap_type: HeapType::Concrete(idx),
1307 }));
1308 }
1309 if matches!(ty, Type::Uint8Array) {
1310 let idx = self.raw_uint8_array_type_idx().ok_or_else(|| crate::codegen::internal_failure("Type::Uint8Array requires the intrinsic types to be declared (declare_intrinsic_types)"))?;
1311 return Ok(ValType::Ref(RefType {
1312 nullable: false,
1313 heap_type: HeapType::Concrete(idx),
1314 }));
1315 }
1316 self.value_type(ty)
1317 }
1318}
1319
1320fn generic_parameter_names(args: &[Type]) -> Option<Vec<String>> {
1323 if args.is_empty() {
1324 return None;
1325 }
1326 args.iter()
1327 .map(|arg| match arg {
1328 Type::TypeVar(name) => Some(name.clone()),
1329 _ => None,
1330 })
1331 .collect()
1332}
1333
1334#[cfg(test)]
1335mod tests {
1336 use super::*;
1337
1338 #[test]
1339 fn func_idx_round_trip_across_name_shapes() {
1340 let mut map = SymbolTable::default();
1341 map.record_local_fn(
1342 crate::mangle::package_symbol("main", "main"),
1343 10,
1344 Vec::new(),
1345 Type::Void,
1346 )
1347 .unwrap();
1348 let unmangled: MangledName = serde_json::from_str("\"main\"").unwrap();
1349 assert!(
1350 map.record_local_fn(unmangled.clone(), 13, Vec::new(), Type::Void)
1351 .is_err()
1352 );
1353 assert_eq!(map.func_idx(&unmangled), None);
1354 map.record_imported_fn(
1355 crate::mangle::prelude("string_concat"),
1356 11,
1357 vec![Type::String, Type::String],
1358 Type::String,
1359 false,
1360 );
1361 map.record_func(
1362 crate::mangle::extend(&crate::mangle::prelude("Number"), "toString"),
1363 12,
1364 );
1365
1366 assert_eq!(
1367 map.func_idx(&crate::mangle::package_symbol("main", "main")),
1368 Some(10)
1369 );
1370 assert_eq!(map.prelude_func_idx("string_concat"), Some(11));
1371 assert_eq!(
1372 map.func_idx(&crate::mangle::extend(
1373 &crate::mangle::prelude("Number"),
1374 "toString",
1375 )),
1376 Some(12),
1377 );
1378
1379 assert_eq!(
1380 map.func_idx(&crate::mangle::package_symbol("main", "string_concat")),
1381 None,
1382 );
1383 assert_eq!(map.prelude_func_idx("toString"), None);
1384 }
1385}