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