1use std::collections::BTreeSet;
2
3use crate::codegen::bigint_pool::BigIntPool;
4use crate::codegen::closures::{ClosureMeta, ClosureSig};
5use crate::codegen::dependency_usage::DependencyUsage;
6use crate::codegen::function_adapters::AdapterMeta;
7use crate::codegen::string_pool::StringPool;
8use crate::codegen::{bounds, cast_check, throw};
9use crate::{
10 AccessorKind, BinOp, ClosureBody, ExprId, Intrinsic, PostfixTarget, Shape, StmtId, Type,
11 TypedAst, TypedChainPart, TypedExprKind, TypedObjectFieldSource, TypedStmtKind,
12 TypedSwitchValue,
13};
14
15pub struct CodegenAnalysis {
16 pub string_pool: StringPool,
17 pub bigint_pool: BigIntPool,
18 pub dependency_usage: DependencyUsage,
19 pub closure_metas: Vec<ClosureMeta>,
20 pub adapter_metas: Vec<AdapterMeta>,
21 pub mentioned_closure_sigs: Vec<ClosureSig>,
24 pub extra_field_names: Vec<String>,
25 adapter_seen: BTreeSet<crate::MangledName>,
26}
27
28impl CodegenAnalysis {
29 pub fn collect(
30 ta: &TypedAst,
31 dependencies: &[&crate::PackageDeclaration],
32 ) -> Result<Self, crate::compiler_error::CompilerFailure> {
33 let mut analysis = Self {
34 string_pool: StringPool::default(),
35 bigint_pool: BigIntPool::default(),
36 dependency_usage: DependencyUsage::empty(),
37 closure_metas: Vec::new(),
38 adapter_metas: Vec::new(),
39 mentioned_closure_sigs: Vec::new(),
40 extra_field_names: Vec::new(),
41 adapter_seen: BTreeSet::new(),
42 };
43
44 for helper in ["#toJson", "#staticValue"] {
47 analysis.dependency_usage.note_member(crate::mangle::extend(
48 &crate::mangle::prelude("ObjectConstructor"),
49 helper,
50 ));
51 }
52
53 for (id, ty) in &ta.runtime_source_types {
54 let span = ta
55 .try_expr(*id)
56 .map_err(crate::codegen::arena_failure)?
57 .span;
58 analysis
59 .visit_type(ty)
60 .map_err(|error| error.with_span(span))?;
61 analysis
62 .string_pool
63 .intern_text(&cast_check::error_prefix(ty));
64 }
65 if !ta.runtime_source_types.is_empty() {
66 for text in cast_check::TYPE_TAG_STRINGS {
67 analysis.string_pool.intern_text(text);
68 }
69 for name in [
70 "numeric",
71 "inc",
72 "dec",
73 "to_number",
74 "to_index",
75 "to_string",
76 "member",
77 "invoke",
78 "property",
79 ] {
80 analysis
81 .dependency_usage
82 .note_value(crate::mangle::prelude(&format!("__value_{name}")));
83 }
84 }
85 for (id, types) in &ta.runtime_chain_types {
86 let span = ta
87 .try_expr(*id)
88 .map_err(crate::codegen::arena_failure)?
89 .span;
90 for ty in types {
91 let ty = crate::typechecker::infer::narrowing::strip_nullish(ty);
92 analysis.visit_type_at(&ty, span)?;
93 analysis
94 .string_pool
95 .intern_text(&cast_check::error_prefix(&ty));
96 }
97 }
98
99 for shape in &ta.shapes {
100 if matches!(shape, Shape::Object { .. }) {
101 analysis
102 .dependency_usage
103 .collect_typed_object_stringify_host_value();
104 }
105 analysis.dependency_usage.note_shape(shape.clone());
106 }
107 for g in &ta.globals {
108 analysis.visit_type_at(&g.ty, g.span)?;
109 }
110 let guarded_bindings = super::init_guard::guarded_globals(ta)?
111 .into_iter()
112 .map(|guard| guard.binding)
113 .chain(
114 super::init_guard::guarded_classes(ta)?
115 .into_iter()
116 .map(|class| class.name),
117 )
118 .collect::<Vec<_>>();
119 if !guarded_bindings.is_empty() {
120 analysis
121 .dependency_usage
122 .note_type(crate::mangle::prelude("ReferenceError"));
123 }
124 for binding in guarded_bindings {
125 analysis
126 .string_pool
127 .intern_text(&super::init_guard::before_initialization_message(&binding));
128 }
129
130 if throw::body_end_may_be_reached(ta) {
131 analysis
132 .string_pool
133 .intern_text(throw::MISSING_RETURN_VALUE_MESSAGE);
134 }
135 for f in &ta.functions {
136 for p in &f.params {
137 if p.boxed {
138 analysis.note_binding_cell();
139 }
140 analysis
141 .visit_type(&p.ty)
142 .map_err(|error| error.with_span(p.name.span))?;
143 }
144 analysis.visit_type_at(&f.return_type, f.span)?;
145 analysis.walk_stmt(ta, f.body)?;
146 }
147 for &stmt_id in &ta.top_level_statements {
148 analysis.walk_stmt(ta, stmt_id)?;
149 }
150 for stmt_id in ta.class_body_roots() {
151 analysis.walk_stmt(ta, stmt_id)?;
152 }
153 for expr_id in ta.class_field_initializers() {
154 analysis.walk_expr(ta, expr_id)?;
155 }
156 if !ta.runtime_class_fields.is_empty()
157 || ta
158 .runtime_class_parameters
159 .values()
160 .any(|params| !params.is_empty())
161 || ta
162 .functions
163 .iter()
164 .any(|function| !function.generics.is_empty())
165 || ta
166 .runtime_class_contexts
167 .values()
168 .any(|contexts| !contexts.is_empty())
169 {
170 analysis
171 .mentioned_closure_sigs
172 .push(super::field_guards::signature());
173 }
174 if let Some(argument) = &ta.finalizer_argument {
175 analysis.note_cast(&argument.target, Some(&argument.check))?;
176 }
177 analysis.note_narrowing_checks(ta)?;
178 analysis.note_inherited_conversions(ta, dependencies)?;
179 for test in ta.runtime_type_tests.values() {
180 analysis.note_narrowing_test(test)?;
181 }
182 analysis.note_dependency_narrowing_checks(dependencies)?;
183
184 for name in [
187 "__value_defaults_fit",
188 "__value_invoke_defaults",
189 "Number#toString",
190 "string_concat",
191 ] {
192 analysis
193 .dependency_usage
194 .note_value(crate::mangle::prelude(name));
195 }
196
197 Ok(analysis)
198 }
199
200 fn note_narrowing_checks(
205 &mut self,
206 ta: &TypedAst,
207 ) -> Result<(), crate::compiler_error::CompilerFailure> {
208 for decl in &ta.types {
209 let crate::TypedTypeDecl::Class(class) = decl else {
210 continue;
211 };
212 if class
213 .methods
214 .iter()
215 .any(|method| matches!(method.name.name.as_str(), "toString" | "toJson"))
216 {
217 self.note_conversion_dispatch()?;
218 }
219 for check in class
220 .fields
221 .iter()
222 .filter_map(|f| f.narrowing_check.as_ref())
223 {
224 self.note_narrowing_check(check)?;
225 }
226 }
227 Ok(())
228 }
229
230 fn note_inherited_conversions(
233 &mut self,
234 ta: &TypedAst,
235 dependencies: &[&crate::PackageDeclaration],
236 ) -> Result<(), crate::compiler_error::CompilerFailure> {
237 let mut parents: Vec<_> = ta
238 .types
239 .iter()
240 .filter_map(|decl| match decl {
241 crate::TypedTypeDecl::Class(class) => class.extends.as_ref(),
242 _ => None,
243 })
244 .collect();
245 let mut visited = BTreeSet::new();
246 while let Some(parent) = parents.pop() {
247 if !visited.insert(parent) {
248 continue;
249 }
250 let Some(symbol) = dependencies
251 .iter()
252 .flat_map(|package| package.runtime_types.values().chain(package.types.values()))
253 .find(|symbol| &symbol.mangled_name == parent)
254 else {
255 continue;
256 };
257 let crate::TypeKind::Class {
258 methods, extends, ..
259 } = &symbol.kind
260 else {
261 continue;
262 };
263 if methods.contains_key("toString") || methods.contains_key("toJson") {
264 self.note_conversion_dispatch()?;
265 return Ok(());
266 }
267 if let Some(extends) = extends {
268 parents.push(&extends.parent);
269 }
270 }
271 Ok(())
272 }
273
274 fn note_conversion_dispatch(&mut self) -> Result<(), crate::compiler_error::CompilerFailure> {
275 self.string_pool.intern_text("Value is not callable");
276 self.string_pool
277 .intern_text("Unbound function has no this receiver");
278 self.string_pool
279 .intern_text(&cast_check::error_prefix(&Type::String));
280 for tag in cast_check::TYPE_TAG_STRINGS {
281 self.string_pool.intern_text(tag);
282 }
283 self.mentioned_closure_sigs
284 .push(ClosureSig::of(0, &Type::String)?);
285 Ok(())
286 }
287
288 fn note_dependency_narrowing_checks(
289 &mut self,
290 dependencies: &[&crate::PackageDeclaration],
291 ) -> Result<(), crate::compiler_error::CompilerFailure> {
292 for package in dependencies {
293 for symbol in package.runtime_types.values().chain(package.types.values()) {
294 let crate::TypeKind::Class {
295 narrowing_checks, ..
296 } = &symbol.kind
297 else {
298 continue;
299 };
300 for check in narrowing_checks.values() {
301 self.note_narrowing_check(check)?;
302 }
303 }
304 }
305 Ok(())
306 }
307
308 fn note_narrowing_check(
309 &mut self,
310 check: &crate::FieldNarrowingCheck,
311 ) -> Result<(), crate::compiler_error::CompilerFailure> {
312 self.string_pool.intern_text(&check.message);
313 self.note_narrowing_test(&check.test)?;
314
315 Ok(())
316 }
317
318 fn note_narrowing_test(
319 &mut self,
320 test: &crate::FieldNarrowingTest,
321 ) -> Result<(), crate::compiler_error::CompilerFailure> {
322 match test {
323 crate::FieldNarrowingTest::Shape(shape) => {
324 self.visit_type(shape)?;
325 self.note_shape_member_names(shape);
326 }
327 crate::FieldNarrowingTest::Interface(test) => {
328 let shape = Type::Object {
329 index: test.index.clone(),
330 fields: test.members.clone(),
331 };
332 self.visit_type(&shape)?;
333 self.note_shape_member_names(&shape);
334 }
335 crate::FieldNarrowingTest::NonNull
336 | crate::FieldNarrowingTest::Substituted
337 | crate::FieldNarrowingTest::Representation => {}
338 };
339 Ok(())
340 }
341
342 fn note_cast(
345 &mut self,
346 target_ty: &Type,
347 check: Option<&Type>,
348 ) -> Result<(), crate::compiler_error::CompilerFailure> {
349 self.string_pool
350 .intern_text(&cast_check::error_prefix(target_ty));
351 for tag in cast_check::TYPE_TAG_STRINGS {
352 self.string_pool.intern_text(tag);
353 }
354 self.visit_type(target_ty)?;
355 if let Some(check) = check {
356 self.visit_type(check)?;
357 self.note_shape_member_names(check);
358 }
359 Ok(())
360 }
361
362 fn note_shape_member_names(&mut self, ty: &Type) {
380 match ty.peel() {
381 Type::Object { fields, index } => {
382 if let Some(index) = index {
383 self.note_record_helpers();
384 self.note_shape_member_names(&index.value);
385 }
386 if !fields.is_empty() {
387 self.mentioned_closure_sigs.push(
388 crate::codegen::classes::accessor_closure_sig(AccessorKind::Get),
389 );
390 }
391 for (name, field) in fields {
392 self.extra_field_names.push(name.clone());
393 self.extra_field_names
394 .push(crate::codegen::classes::accessor_getter_name(name));
395 self.note_shape_member_names(&field.ty);
396 }
397 }
398 Type::Array(elem) => self.note_shape_member_names(elem),
399 Type::Tuple(elems) => {
400 for e in elems {
401 self.note_shape_member_names(e);
402 }
403 }
404 Type::Union(members) => {
405 for m in members {
406 self.note_shape_member_names(m);
407 }
408 }
409 _ => {}
410 }
411 }
412
413 fn visit_type_at(
423 &mut self,
424 ty: &Type,
425 span: crate::Span,
426 ) -> Result<(), crate::compiler_error::CompilerFailure> {
427 self.visit_type(ty).map_err(|error| error.with_span(span))
428 }
429
430 fn visit_type(&mut self, ty: &Type) -> Result<(), crate::compiler_error::CompilerFailure> {
431 if let Type::Object {
432 index: Some(index), ..
433 } = ty.peel()
434 {
435 self.note_record_helpers();
436 self.visit_type(&index.value)?;
437 }
438 self.dependency_usage.collect_type(ty);
439 crate::codegen::closures::walk_type(ty, &mut self.mentioned_closure_sigs)?;
440
441 Ok(())
442 }
443
444 fn note_record_helpers(&mut self) {
445 for helper in crate::codegen::dependency_usage::RECORD_HELPERS {
446 self.dependency_usage.note_member(crate::mangle::extend(
447 &crate::mangle::prelude("ObjectConstructor"),
448 helper,
449 ));
450 }
451 }
452
453 fn walk_stmt(
454 &mut self,
455 ta: &TypedAst,
456 id: StmtId,
457 ) -> Result<(), crate::compiler_error::CompilerFailure> {
458 self.note_stmt_pre(ta, id)?;
459 match &ta.try_stmt(id).map_err(crate::codegen::arena_failure)?.kind {
460 TypedStmtKind::Let { value, .. } | TypedStmtKind::Const { value, .. } => {
461 self.walk_expr(ta, *value)?;
462 }
463 TypedStmtKind::If {
464 condition,
465 then_block,
466 else_block,
467 } => {
468 self.walk_expr(ta, *condition)?;
469 self.walk_stmt(ta, *then_block)?;
470 if let Some(else_block) = else_block {
471 self.walk_stmt(ta, *else_block)?;
472 }
473 }
474 TypedStmtKind::While { condition, body } => {
475 self.walk_expr(ta, *condition)?;
476 self.walk_stmt(ta, *body)?;
477 }
478 TypedStmtKind::For {
479 init,
480 condition,
481 update,
482 body,
483 } => {
484 if let Some(init) = init {
485 self.walk_stmt(ta, *init)?;
486 }
487 if let Some(condition) = condition {
488 self.walk_expr(ta, *condition)?;
489 }
490 if let Some(update) = update {
491 self.walk_stmt(ta, *update)?;
492 }
493 self.walk_stmt(ta, *body)?;
494 }
495 TypedStmtKind::ForOf { iter, body, .. } => {
496 self.walk_expr(ta, *iter)?;
497 self.walk_stmt(ta, *body)?;
498 }
499 TypedStmtKind::DoWhile { body, condition } => {
500 self.walk_stmt(ta, *body)?;
501 self.walk_expr(ta, *condition)?;
502 }
503 TypedStmtKind::Switch {
504 discriminant,
505 cases,
506 default,
507 ..
508 } => {
509 self.walk_expr(ta, *discriminant)?;
510 for comparison in cases
511 .iter()
512 .flat_map(crate::TypedSwitchCase::label_comparisons)
513 {
514 self.walk_expr(ta, comparison)?;
515 }
516 for case in cases {
517 self.walk_stmt(ta, case.body)?;
518 }
519 if let Some(default) = default {
520 self.walk_stmt(ta, *default)?;
521 }
522 }
523 TypedStmtKind::Break | TypedStmtKind::Continue | TypedStmtKind::ReboxLocal { .. } => {}
524 TypedStmtKind::Return(value) => {
525 if let Some(value) = value {
526 self.walk_expr(ta, *value)?;
527 }
528 }
529 TypedStmtKind::Expr(expr) => self.walk_expr(ta, *expr)?,
530 TypedStmtKind::Block(stmts) => {
531 for &stmt in stmts {
532 self.walk_stmt(ta, stmt)?;
533 }
534 }
535 TypedStmtKind::AssignLocal { value, .. }
536 | TypedStmtKind::AssignGlobal { value, .. } => self.walk_expr(ta, *value)?,
537 TypedStmtKind::AssignField {
538 receiver, value, ..
539 } => {
540 self.walk_expr(ta, *receiver)?;
541 self.walk_expr(ta, *value)?;
542 }
543 TypedStmtKind::AssignIndex {
544 receiver,
545 index,
546 value,
547 ..
548 } => {
549 self.walk_expr(ta, *receiver)?;
550 self.walk_expr(ta, *index)?;
551 self.walk_expr(ta, *value)?;
552 }
553 TypedStmtKind::NarrowRegion { source, body, .. } => {
554 self.walk_expr(ta, *source)?;
555 self.walk_stmt(ta, *body)?;
556 }
557 TypedStmtKind::Throw { value } => self.walk_expr(ta, *value)?,
558 TypedStmtKind::Try {
559 body,
560 catches,
561 finally,
562 } => {
563 self.walk_stmt(ta, *body)?;
564 for clause in catches {
565 self.walk_stmt(ta, clause.body)?;
566 }
567 if let Some(finally) = finally {
568 self.walk_stmt(ta, *finally)?;
569 }
570 }
571 }
572 self.note_stmt_post(ta, id)?;
573 Ok(())
574 }
575
576 fn walk_expr(
577 &mut self,
578 ta: &TypedAst,
579 id: ExprId,
580 ) -> Result<(), crate::compiler_error::CompilerFailure> {
581 let expr = ta.try_expr(id).map_err(crate::codegen::arena_failure)?;
582 self.note_expr_pre(ta, id)
583 .map_err(|error| error.with_span(expr.span))?;
584 let _: () = match &expr.kind {
585 TypedExprKind::Call { args, .. }
586 | TypedExprKind::VirtualCall { args, .. }
587 | TypedExprKind::SuperCtorCall { args, .. }
588 | TypedExprKind::SuperMethodCall { args, .. }
589 | TypedExprKind::IntrinsicCall { args, .. } => {
590 for &arg in args {
591 self.walk_expr(ta, arg)?;
592 }
593 }
594 TypedExprKind::CallClosure { callee, args } => {
595 self.walk_expr(ta, *callee)?;
596 for &arg in args {
597 self.walk_expr(ta, arg)?;
598 }
599 }
600 TypedExprKind::GenericCall {
601 args, type_args, ..
602 } => {
603 self.mentioned_closure_sigs
604 .push(super::field_guards::signature());
605 for ty in type_args {
606 self.visit_type(ty)?;
607 }
608 for arg in args {
609 self.walk_expr(ta, arg.expr)?;
610 }
611 }
612 TypedExprKind::Closure { body, .. } => match *body {
613 ClosureBody::Expr(expr) => self.walk_expr(ta, expr)?,
614 ClosureBody::Block(stmt) => self.walk_stmt(ta, stmt)?,
615 },
616 TypedExprKind::Binary { lhs, rhs, .. } => {
617 self.walk_expr(ta, *lhs)?;
618 self.walk_expr(ta, *rhs)?;
619 }
620 TypedExprKind::EffectThen { effect, result } => {
621 self.walk_expr(ta, *effect)?;
622 self.walk_expr(ta, *result)?;
623 }
624 TypedExprKind::Sequence { stmts, result } => {
625 for &stmt in stmts {
626 self.walk_stmt(ta, stmt)?;
627 }
628 self.walk_expr(ta, *result)?;
629 }
630 TypedExprKind::Unary { operand, .. }
631 | TypedExprKind::TypeofTag { value: operand, .. }
632 | TypedExprKind::InstanceOf { value: operand, .. }
633 | TypedExprKind::NonNullAssert { value: operand } => {
634 self.walk_expr(ta, *operand)?;
635 }
636 TypedExprKind::MethodCall { receiver, args, .. } => {
637 self.walk_expr(ta, *receiver)?;
638 for &arg in args {
639 self.walk_expr(ta, arg)?;
640 }
641 }
642 TypedExprKind::GenericMethodCall { receiver, args, .. } => {
643 self.walk_expr(ta, *receiver)?;
644 for arg in args {
645 self.walk_expr(ta, arg.expr)?;
646 }
647 }
648 TypedExprKind::ObjectLiteral { members, .. } => {
649 for member in members {
650 for expression in member.expressions() {
651 self.walk_expr(ta, expression)?;
652 }
653 }
654 }
655 TypedExprKind::ArrayLiteral { elements, .. } => {
656 for elem in elements {
657 self.walk_expr(ta, elem.expr_id())?;
658 }
659 }
660 TypedExprKind::TupleLiteral { elements, .. } => {
661 for &elem in elements {
662 self.walk_expr(ta, elem)?;
663 }
664 }
665 TypedExprKind::FieldAccess { receiver, .. }
666 | TypedExprKind::InterfacePropertyAccess { receiver, .. } => {
667 self.walk_expr(ta, *receiver)?;
668 }
669 TypedExprKind::IndexAccess { receiver, index } => {
670 self.walk_expr(ta, *receiver)?;
671 self.walk_expr(ta, *index)?;
672 }
673 TypedExprKind::Narrowed { source, inner, .. } => {
674 self.walk_expr(ta, *source)?;
675 self.walk_expr(ta, *inner)?;
676 }
677 TypedExprKind::Ternary { cond, then_, else_ } => {
678 self.walk_expr(ta, *cond)?;
679 self.walk_expr(ta, *then_)?;
680 self.walk_expr(ta, *else_)?;
681 }
682 TypedExprKind::NullishCoalesce { lhs, rhs } => {
683 self.walk_expr(ta, *lhs)?;
684 self.walk_expr(ta, *rhs)?;
685 }
686 TypedExprKind::OptionalChain { base, parts } => {
687 self.walk_expr(ta, *base)?;
688 for part in parts {
689 match part {
690 TypedChainPart::Index { idx, .. } => self.walk_expr(ta, *idx)?,
691 TypedChainPart::Call { args, .. }
692 | TypedChainPart::MethodCall { args, .. } => {
693 for &arg in args {
694 self.walk_expr(ta, arg)?;
695 }
696 }
697 TypedChainPart::Field { .. }
698 | TypedChainPart::InterfaceProperty { .. }
699 | TypedChainPart::NonNull { .. } => {}
700 }
701 }
702 }
703 TypedExprKind::PostfixUnary { target, .. } => match target {
704 PostfixTarget::Field { receiver, .. } => self.walk_expr(ta, *receiver)?,
705 PostfixTarget::Index {
706 receiver, index, ..
707 } => {
708 self.walk_expr(ta, *receiver)?;
709 self.walk_expr(ta, *index)?;
710 }
711 PostfixTarget::Local { .. } | PostfixTarget::Global { .. } => {}
712 },
713 TypedExprKind::Cast { value, .. } => self.walk_expr(ta, *value)?,
714 TypedExprKind::Number(_)
715 | TypedExprKind::BigInt(_)
716 | TypedExprKind::String(_)
717 | TypedExprKind::Boolean(_)
718 | TypedExprKind::Null
719 | TypedExprKind::Undefined
720 | TypedExprKind::This
721 | TypedExprKind::Regex { .. }
722 | TypedExprKind::LocalRef { .. }
723 | TypedExprKind::LocalNarrowRef { .. }
724 | TypedExprKind::GlobalRef { .. }
725 | TypedExprKind::FunctionRef { .. }
726 | TypedExprKind::NumberEnumMember { .. }
727 | TypedExprKind::StringEnumMember { .. } => {}
728 };
729 Ok(())
730 }
731
732 fn note_stmt_pre(
733 &mut self,
734 ta: &TypedAst,
735 id: StmtId,
736 ) -> Result<(), crate::compiler_error::CompilerFailure> {
737 let stmt = ta.try_stmt(id).map_err(crate::codegen::arena_failure)?;
738 if matches!(
739 stmt.kind,
740 TypedStmtKind::Let { boxed: true, .. }
741 | TypedStmtKind::AssignLocal { boxed: true, .. }
742 | TypedStmtKind::ReboxLocal { .. }
743 ) {
744 self.note_binding_cell();
745 }
746 let _: () = match &stmt.kind {
747 TypedStmtKind::Let { ty, .. } | TypedStmtKind::Const { ty, .. } => {
748 self.visit_type_at(ty, stmt.span)?;
749 }
750 TypedStmtKind::ForOf { element_ty, .. } => {
751 self.visit_type_at(element_ty, stmt.span)?;
752 }
753 TypedStmtKind::Switch {
754 discriminant_ty,
755 cases,
756 ..
757 } => {
758 self.visit_type_at(discriminant_ty, stmt.span)?;
759 for case in cases {
760 for value in &case.values {
761 if let TypedSwitchValue::Enum { enum_name, .. } = value {
762 self.dependency_usage.note_type(enum_name.clone());
763 }
764 }
765 }
766 }
767 TypedStmtKind::AssignLocal { target_ty, .. } => {
768 self.visit_type_at(target_ty, stmt.span)?;
769 }
770 TypedStmtKind::AssignGlobal {
771 mangled, target_ty, ..
772 } => {
773 self.dependency_usage.note_value(mangled.clone());
774 self.visit_type_at(target_ty, stmt.span)?;
775 }
776 TypedStmtKind::AssignField { receiver, name, .. } => {
777 let receiver_ty = ta
778 .source_type(*receiver)
779 .map_err(crate::codegen::arena_failure)?;
780 if let Some(iface) = crate::codegen::host_property_iface(receiver_ty) {
783 self.dependency_usage.note_member(crate::mangle::extend(
784 &iface,
785 &crate::mangle::property_setter(&name.name),
786 ));
787 }
788 if crate::codegen::may_hold_builtin_value(receiver_ty) {
789 self.note_record_helpers();
790 }
791 self.extra_field_names.push(name.name.clone());
792 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Set);
793 }
794 TypedStmtKind::AssignIndex {
795 receiver, elem_ty, ..
796 } => {
797 if ta
798 .source_type(*receiver)
799 .map_err(crate::codegen::arena_failure)?
800 .is_structural_object()
801 {
802 self.note_record_helpers();
803 }
804 self.visit_type_at(elem_ty, stmt.span)?;
805 self.note_index_check();
806 }
807 TypedStmtKind::NarrowRegion { cast_info, .. } => {
808 self.visit_type_at(&cast_info.from_ty, stmt.span)?;
809 self.visit_type_at(&cast_info.to_ty, stmt.span)?;
810 }
811 TypedStmtKind::Try { catches, .. } => {
812 for clause in catches {
815 self.visit_type_at(&clause.ty, stmt.span)?;
816 }
817 }
818 TypedStmtKind::If { .. }
819 | TypedStmtKind::While { .. }
820 | TypedStmtKind::For { .. }
821 | TypedStmtKind::DoWhile { .. }
822 | TypedStmtKind::Break
823 | TypedStmtKind::Continue
824 | TypedStmtKind::ReboxLocal { .. }
825 | TypedStmtKind::Return(_)
826 | TypedStmtKind::Expr(_)
827 | TypedStmtKind::Block(_)
828 | TypedStmtKind::Throw { .. } => {}
829 };
830 Ok(())
831 }
832
833 fn note_stmt_post(
834 &mut self,
835 ta: &TypedAst,
836 id: StmtId,
837 ) -> Result<(), crate::compiler_error::CompilerFailure> {
838 let _: () = if let TypedStmtKind::Switch { cases, .. } =
839 &ta.try_stmt(id).map_err(crate::codegen::arena_failure)?.kind
840 {
841 for case in cases {
842 for value in &case.values {
843 match value {
844 TypedSwitchValue::String { value, .. } => {
845 self.string_pool.intern_text(value);
846 }
847 TypedSwitchValue::Enum {
848 value: crate::EnumVariantPayload::String(text),
849 ..
850 } => {
851 self.string_pool.intern_text(text);
852 }
853 _ => {}
854 }
855 }
856 }
857 };
858 Ok(())
859 }
860
861 fn note_expr_pre(
862 &mut self,
863 ta: &TypedAst,
864 id: ExprId,
865 ) -> Result<(), crate::compiler_error::CompilerFailure> {
866 let expr = ta.try_expr(id).map_err(crate::codegen::arena_failure)?;
867 let has_binding_cell = match &expr.kind {
868 TypedExprKind::LocalRef { boxed: true, .. }
869 | TypedExprKind::PostfixUnary {
870 target: PostfixTarget::Local { boxed: true, .. },
871 ..
872 } => true,
873 TypedExprKind::Closure {
874 params, captured, ..
875 } => {
876 params.iter().any(|param| param.boxed)
877 || captured.iter().any(|capture| capture.boxed)
878 }
879 _ => false,
880 };
881 if has_binding_cell {
882 self.note_binding_cell();
883 }
884 if matches!(
885 expr.kind,
886 TypedExprKind::IndexAccess { .. }
887 | TypedExprKind::Binary {
888 op: crate::BinOp::In,
889 ..
890 }
891 ) {
892 self.note_record_helpers();
893 }
894 if matches!(expr.kind, TypedExprKind::PostfixUnary { .. }) {
895 self.note_record_helpers();
896 }
897 self.visit_type(&expr.ty)
898 .map_err(|error| error.with_span(expr.span))?;
899 let _: () = match &expr.kind {
900 TypedExprKind::String(text) => {
901 self.string_pool.record_expr(id, text);
902 }
903 TypedExprKind::StringEnumMember {
904 enum_mangled,
905 value,
906 ..
907 } => {
908 self.string_pool.record_expr(id, value);
909 self.dependency_usage.note_type(enum_mangled.clone());
910 }
911 TypedExprKind::BigInt(digits) => {
912 self.bigint_pool.intern_digits(digits)?;
913 self.dependency_usage
914 .collect_bigint_host_value("fromNumber");
915 }
916 TypedExprKind::GlobalRef { mangled, .. } => {
917 self.dependency_usage.note_value(mangled.clone());
918 }
919 TypedExprKind::FunctionRef { name, mangled } => {
920 self.dependency_usage.note_value(mangled.clone());
921 if self.adapter_seen.insert(mangled.clone()) {
922 self.adapter_metas.push(AdapterMeta {
923 name: name.name.clone(),
924 mangled: mangled.clone(),
925 signature: expr.ty.clone(),
926 });
927 }
928 }
929 TypedExprKind::NumberEnumMember { enum_mangled, .. } => {
930 self.dependency_usage.note_type(enum_mangled.clone());
931 }
932 TypedExprKind::Binary { op, lhs, .. } => {
933 if let Some(name) = op.bitwise_name() {
934 self.dependency_usage
935 .note_value(crate::mangle::prelude(&format!("__value_{name}")));
936 self.dependency_usage
938 .note_value(crate::mangle::prelude("__value_bitor"));
939 }
940 if matches!(op, BinOp::Pow) && matches!(expr.ty.peel(), Type::Number) {
941 self.dependency_usage
942 .note_value(crate::runtime::prelude::math::math_key("pow"));
943 }
944 if expr.ty.is_bigint() {
945 match op {
946 BinOp::Add => self.dependency_usage.collect_bigint_host_value("add"),
947 BinOp::Sub => self.dependency_usage.collect_bigint_host_value("sub"),
948 BinOp::Mul => self.dependency_usage.collect_bigint_host_value("mul"),
949 BinOp::Div => self.dependency_usage.collect_bigint_host_value("div"),
950 BinOp::Rem => self.dependency_usage.collect_bigint_host_value("mod"),
951 BinOp::Pow => self.dependency_usage.collect_bigint_host_value("pow"),
952 BinOp::Eq
953 | BinOp::BitAnd
954 | BinOp::BitOr
955 | BinOp::BitXor
956 | BinOp::Shl
957 | BinOp::Shr
958 | BinOp::UnsignedShr
959 | BinOp::NotEq
960 | BinOp::Lt
961 | BinOp::Gt
962 | BinOp::Le
963 | BinOp::Ge
964 | BinOp::And
965 | BinOp::Or
966 | BinOp::In
967 | BinOp::NullishCoalesce => {}
968 }
969 }
970 if ta
971 .try_expr(*lhs)
972 .map_err(crate::codegen::arena_failure)?
973 .ty
974 .is_bigint()
975 && matches!(
976 op,
977 BinOp::Eq | BinOp::NotEq | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge
978 )
979 {
980 self.dependency_usage.collect_bigint_host_value("cmp");
981 }
982 if matches!(op, BinOp::In)
983 && let TypedExprKind::String(name) = &ta
984 .try_expr(*lhs)
985 .map_err(crate::codegen::arena_failure)?
986 .kind
987 {
988 self.extra_field_names.push(name.clone());
989 self.extra_field_names
990 .push(crate::codegen::classes::accessor_getter_name(name));
991 self.extra_field_names
992 .push(crate::codegen::classes::accessor_setter_name(name));
993 for kind in [AccessorKind::Get, AccessorKind::Set] {
994 self.mentioned_closure_sigs
995 .push(crate::codegen::classes::accessor_closure_sig(kind));
996 }
997 }
998 }
999 TypedExprKind::Unary { op, operand } => {
1000 if matches!(op, crate::UnOp::BitNot) {
1001 self.dependency_usage
1002 .note_value(crate::mangle::prelude("__value_bitnot"));
1003 self.dependency_usage
1004 .note_value(crate::mangle::prelude("__value_bitor"));
1005 }
1006 let operand_ty = ta
1007 .try_expr(*operand)
1008 .map_err(crate::codegen::arena_failure)?
1009 .ty
1010 .peel();
1011 if matches!(op, crate::UnOp::Neg) && operand_ty.is_bigint() {
1012 self.dependency_usage.collect_bigint_host_value("neg");
1013 }
1014 if matches!(op, crate::UnOp::Pos)
1015 && (operand_ty.is_string_shaped()
1016 || matches!(operand_ty.primitive_behavior(), crate::Type::Union(_)))
1017 {
1018 self.dependency_usage.collect_number_coercion_host_value();
1019 }
1020 }
1021 TypedExprKind::Call { mangled, .. } | TypedExprKind::GenericCall { mangled, .. } => {
1022 self.dependency_usage.note_value(mangled.clone());
1023 }
1024 TypedExprKind::VirtualCall { target, tool, .. } => {
1025 self.dependency_usage
1026 .note_value(crate::mangle::host(&target.package_name(), tool));
1027 self.dependency_usage
1028 .note_value(crate::mangle::host(target.host_module(), "call"));
1029 if !matches!(expr.ty.peel(), Type::String) {
1030 self.dependency_usage.collect_json_host_values();
1031 }
1032 }
1033 TypedExprKind::IntrinsicCall { kind, .. } => match kind {
1034 Intrinsic::JsonParse | Intrinsic::JsonStringify => {
1035 self.dependency_usage.collect_json_host_values();
1036 }
1037 Intrinsic::BigIntFromString => {
1038 self.dependency_usage
1039 .collect_bigint_host_value("fromString");
1040 }
1041 Intrinsic::ToString => {
1042 self.dependency_usage
1043 .note_value(crate::mangle::prelude("__value_to_string"));
1044 }
1045 Intrinsic::ToObject => {
1046 self.dependency_usage.note_member(crate::mangle::extend(
1047 &crate::mangle::prelude("ObjectConstructor"),
1048 "#toObject",
1049 ));
1050 }
1051 Intrinsic::Assert => {}
1052 },
1053 TypedExprKind::MethodCall {
1054 receiver,
1055 iface,
1056 name,
1057 args,
1058 ..
1059 } => {
1060 self.note_method_call(
1061 ta.source_type(*receiver)
1062 .map_err(crate::codegen::arena_failure)?,
1063 iface,
1064 name,
1065 args.len(),
1066 &expr.ty,
1067 )?;
1068 }
1069 TypedExprKind::GenericMethodCall {
1070 receiver,
1071 iface,
1072 name,
1073 args,
1074 ..
1075 } => {
1076 self.note_method_call(
1077 ta.source_type(*receiver)
1078 .map_err(crate::codegen::arena_failure)?,
1079 iface,
1080 name,
1081 args.len(),
1082 &expr.ty,
1083 )?;
1084 }
1085 TypedExprKind::InterfacePropertyAccess { iface, name, .. } => {
1086 self.dependency_usage
1087 .note_member(crate::mangle::extend(iface, &name.name));
1088 }
1089 TypedExprKind::ObjectLiteral { fields, members } => {
1090 if members
1091 .iter()
1092 .any(|m| matches!(m, crate::TypedObjectMember::Computed { .. }))
1093 {
1094 self.note_record_helpers();
1095 }
1096 if members.iter().any(|member| {
1097 matches!(
1098 member,
1099 crate::TypedObjectMember::Spread { .. }
1100 | crate::TypedObjectMember::Computed { .. }
1101 )
1102 }) {
1103 self.dependency_usage.note_member(crate::mangle::extend(
1104 &crate::mangle::prelude("ObjectConstructor"),
1105 "#spread",
1106 ));
1107 }
1108 for member in members {
1109 if let crate::TypedObjectMember::Spread { source, .. } = member
1110 && let Some(omitted) = ta.spread_omitted_fields.get(source)
1111 {
1112 self.extra_field_names.extend(omitted.iter().cloned());
1113 }
1114 }
1115 for field in fields {
1116 let mut source = Some(&field.source);
1117 while let Some(TypedObjectFieldSource::Spread {
1118 source_ty,
1119 field_name,
1120 fallback,
1121 ..
1122 }) = source
1123 {
1124 self.visit_type(source_ty)?;
1125 self.extra_field_names.push(field_name.clone());
1128 self.note_shape_member_names(source_ty);
1129 source = fallback.as_deref();
1130 }
1131 }
1132 }
1133 TypedExprKind::ArrayLiteral { element_ty, .. } => {
1134 self.visit_type(element_ty)?;
1135 }
1136 TypedExprKind::TupleLiteral { element_types, .. } => {
1137 for ty in element_types {
1138 self.visit_type(ty)?;
1139 }
1140 }
1141 TypedExprKind::FieldAccess { receiver, name } => {
1142 self.extra_field_names.push(name.name.clone());
1143 self.note_shaped_property_access(
1144 ta.source_type(*receiver)
1145 .map_err(crate::codegen::arena_failure)?,
1146 &name.name,
1147 AccessorKind::Get,
1148 );
1149 }
1150 TypedExprKind::IndexAccess { receiver, .. } => {
1151 self.note_index_check();
1152 self.note_string_index(
1153 ta.source_type(*receiver)
1154 .map_err(crate::codegen::arena_failure)?,
1155 );
1156 }
1157 TypedExprKind::Closure {
1158 runtime_generics,
1159 params,
1160 captured,
1161 body,
1162 return_type,
1163 ..
1164 } => {
1165 self.closure_metas.push(ClosureMeta {
1166 this_type: ta.closure_this.get(&id).cloned(),
1167 self_name: ta.closure_names.get(&id).cloned(),
1168 runtime_generics: runtime_generics.clone(),
1169 expr_id: id,
1170 signature: expr.ty.clone(),
1171 captured: captured.clone(),
1172 params: params.clone(),
1173 body: body.clone(),
1174 return_type: return_type.clone(),
1175 });
1176 for p in params {
1177 self.visit_type(&p.ty)?;
1178 }
1179 self.visit_type(return_type)?;
1180 }
1181 TypedExprKind::Narrowed { cast_info, .. } => {
1182 self.visit_type(&cast_info.from_ty)?;
1183 self.visit_type(&cast_info.to_ty)?;
1184 }
1185 TypedExprKind::OptionalChain { base, parts } => {
1186 self.note_chain_parts(ta, id, *base, parts)?;
1187 }
1188 TypedExprKind::PostfixUnary { target, .. } => match target {
1189 PostfixTarget::Local { .. } => {
1190 self.note_postfix_target(&expr.ty)?;
1191 }
1192 PostfixTarget::Global { mangled, .. } => {
1193 self.dependency_usage.note_value(mangled.clone());
1194 self.note_postfix_target(&expr.ty)?;
1195 }
1196 PostfixTarget::Field { receiver, name, .. } => {
1197 self.note_postfix_target(&expr.ty)?;
1198 let receiver_ty = ta
1199 .source_type(*receiver)
1200 .map_err(crate::codegen::arena_failure)?;
1201 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Get);
1202 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Set);
1203 if let Some(iface) = crate::codegen::host_property_iface(receiver_ty) {
1204 self.dependency_usage
1205 .note_member(crate::mangle::extend(&iface, &name.name));
1206 self.dependency_usage.note_member(crate::mangle::extend(
1207 &iface,
1208 &crate::mangle::property_setter(&name.name),
1209 ));
1210 }
1211 }
1212 PostfixTarget::Index { elem_ty, .. } => {
1213 self.note_postfix_target(elem_ty)?;
1214 self.note_index_check();
1215 }
1216 },
1217 TypedExprKind::NonNullAssert { .. } => {
1218 self.string_pool.intern_text(throw::NON_NULL_ASSERT_MESSAGE);
1219 }
1220 TypedExprKind::Cast {
1221 target_ty, check, ..
1222 } => self.note_cast(target_ty, check.as_deref())?,
1223 TypedExprKind::Regex { source, flags } => {
1224 self.string_pool.intern_text(source);
1225 self.string_pool.intern_text(flags);
1226 }
1227 TypedExprKind::CallClosure { callee, .. } => {
1228 self.dependency_usage
1229 .note_value(crate::mangle::prelude("__value_invoke_defaults"));
1230 self.string_pool.intern_text(&cast_check::error_prefix(
1231 ta.source_type(*callee)
1232 .map_err(crate::codegen::arena_failure)?,
1233 ));
1234 for tag in cast_check::TYPE_TAG_STRINGS {
1235 self.string_pool.intern_text(tag);
1236 }
1237 }
1238 TypedExprKind::InstanceOf { class, .. } => {
1239 self.visit_type(class)?;
1242 }
1243 TypedExprKind::Number(_)
1244 | TypedExprKind::Boolean(_)
1245 | TypedExprKind::Null
1246 | TypedExprKind::Undefined
1247 | TypedExprKind::This
1248 | TypedExprKind::EffectThen { .. }
1249 | TypedExprKind::Sequence { .. }
1250 | TypedExprKind::LocalRef { .. }
1251 | TypedExprKind::LocalNarrowRef { .. }
1252 | TypedExprKind::SuperCtorCall { .. }
1253 | TypedExprKind::SuperMethodCall { .. }
1254 | TypedExprKind::TypeofTag { .. }
1255 | TypedExprKind::Ternary { .. }
1256 | TypedExprKind::NullishCoalesce { .. } => {}
1257 };
1258 Ok(())
1259 }
1260
1261 fn note_method_call(
1264 &mut self,
1265 receiver_ty: &Type,
1266 iface: &crate::MangledName,
1267 name: &crate::Ident,
1268 arity: usize,
1269 ret: &Type,
1270 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1271 self.dependency_usage
1272 .note_member(crate::mangle::extend(iface, &name.name));
1273 self.string_pool.intern_text("Value is not callable");
1274 self.string_pool
1275 .intern_text("Unbound function has no this receiver");
1276 self.extra_field_names.push(name.name.clone());
1277 self.note_shape_dispatch(receiver_ty, arity, ret)?;
1278
1279 Ok(())
1280 }
1281
1282 fn note_shape_dispatch(
1293 &mut self,
1294 receiver_ty: &Type,
1295 arity: usize,
1296 ret: &Type,
1297 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1298 self.string_pool.intern_text("Value is not callable");
1299 self.string_pool
1300 .intern_text("Unbound function has no this receiver");
1301 let receiver_ty = crate::typechecker::infer::narrowing::strip_nullish(receiver_ty);
1303 if !matches!(
1304 receiver_ty.peel(),
1305 Type::InterfaceRef { .. } | Type::ClassRef { .. }
1306 ) {
1307 return Ok(());
1308 }
1309 self.mentioned_closure_sigs
1310 .push(ClosureSig::of(arity, ret)?);
1311
1312 Ok(())
1313 }
1314
1315 fn note_binding_cell(&mut self) {
1316 self.string_pool
1317 .intern_text(super::function_emitter::binding_cells::UNINITIALIZED_PARAMETER_MESSAGE);
1318 }
1319
1320 fn note_chain_parts(
1323 &mut self,
1324 ta: &TypedAst,
1325 id: ExprId,
1326 base: ExprId,
1327 parts: &[TypedChainPart],
1328 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1329 let source_types = ta.runtime_chain_types.get(&id);
1330 let mut receiver_ty = ta
1331 .source_type(base)
1332 .map_err(crate::codegen::arena_failure)?;
1333 for (index, part) in parts.iter().enumerate() {
1334 if let TypedChainPart::MethodCall { iface, name, .. }
1335 | TypedChainPart::InterfaceProperty { iface, name, .. } = part
1336 {
1337 self.string_pool.intern_text(iface.as_str());
1338 self.string_pool.intern_text(&name.name);
1339 }
1340 match part {
1341 TypedChainPart::Field {
1342 name, result_ty, ..
1343 } => {
1344 self.extra_field_names.push(name.name.clone());
1345 self.visit_type(result_ty)?;
1346 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Get);
1347 }
1348 TypedChainPart::InterfaceProperty {
1349 iface,
1350 name,
1351 result_ty,
1352 span,
1353 ..
1354 } => {
1355 if ta.authored_call_arguments(*span).is_some()
1356 && !crate::codegen::is_host_package(iface.as_str())
1357 {
1358 for helper in ["__value_member", "__value_invoke"] {
1359 self.dependency_usage
1360 .note_value(crate::mangle::prelude(helper));
1361 }
1362 }
1363 self.extra_field_names.push(name.name.clone());
1364 self.dependency_usage
1365 .note_member(crate::mangle::extend(iface, &name.name));
1366 self.visit_type(result_ty)?;
1367 }
1368 TypedChainPart::Index { result_ty, .. } => {
1369 self.note_record_helpers();
1370 self.visit_type(result_ty)?;
1371 self.note_index_check();
1374 self.note_string_index(receiver_ty);
1375 }
1376 TypedChainPart::Call {
1377 result_ty,
1378 union_signature,
1379 ..
1380 } => {
1381 self.dependency_usage
1382 .note_value(crate::mangle::prelude("__value_invoke_defaults"));
1383 self.visit_type(result_ty)?;
1384 if let Some(signature) = union_signature {
1385 self.visit_type(signature)?;
1386 }
1387 }
1388 TypedChainPart::NonNull { result_ty, .. } => {
1389 self.visit_type(result_ty)?;
1390 self.string_pool.intern_text(throw::NON_NULL_ASSERT_MESSAGE);
1391 }
1392 TypedChainPart::MethodCall {
1393 iface,
1394 name,
1395 args,
1396 result_ty,
1397 span,
1398 ..
1399 } => {
1400 if ta.authored_call_arguments(*span).is_some()
1401 && !crate::codegen::is_host_package(iface.as_str())
1402 {
1403 for helper in ["__value_member", "__value_invoke"] {
1404 self.dependency_usage
1405 .note_value(crate::mangle::prelude(helper));
1406 }
1407 }
1408 self.extra_field_names.push(name.name.clone());
1409 self.dependency_usage
1410 .note_member(crate::mangle::extend(iface, &name.name));
1411 self.visit_type(result_ty)?;
1412 self.note_shape_dispatch(receiver_ty, args.len(), result_ty)?;
1413 }
1414 }
1415 receiver_ty = source_types.map_or_else(|| part.result_ty(), |types| &types[index + 1]);
1416 }
1417 Ok(())
1418 }
1419
1420 fn note_shaped_property_access(&mut self, receiver_ty: &Type, prop: &str, kind: AccessorKind) {
1433 if matches!(kind, AccessorKind::Set) {
1434 self.dependency_usage.note_member(crate::mangle::extend(
1435 &crate::mangle::prelude("ObjectConstructor"),
1436 "#insertField",
1437 ));
1438 }
1439 self.mentioned_closure_sigs
1440 .push(super::field_guards::signature());
1441 if !is_shaped_receiver(receiver_ty) && !matches!(receiver_ty.peel(), Type::ClassRef { .. })
1442 {
1443 return;
1444 }
1445 self.string_pool.intern_text("Value is not callable");
1446 self.string_pool
1447 .intern_text("Unbound function has no this receiver");
1448 self.extra_field_names
1451 .push(crate::codegen::classes::accessor_getter_name(prop));
1452 self.mentioned_closure_sigs
1453 .push(crate::codegen::classes::accessor_closure_sig(
1454 AccessorKind::Get,
1455 ));
1456 if matches!(kind, AccessorKind::Set) {
1457 self.extra_field_names
1458 .push(crate::codegen::classes::accessor_setter_name(prop));
1459 self.mentioned_closure_sigs
1460 .push(crate::codegen::classes::accessor_closure_sig(
1461 AccessorKind::Set,
1462 ));
1463 self.string_pool
1466 .intern_text(throw::READ_ONLY_PROPERTY_MESSAGE);
1467 }
1468 }
1469
1470 fn note_string_index(&mut self, receiver_ty: &Type) {
1473 if crate::typechecker::infer::narrowing::strip_nullish(receiver_ty).is_string_shaped() {
1474 self.dependency_usage
1475 .note_value(crate::mangle::prelude("string_index"));
1476 }
1477 }
1478
1479 fn note_index_check(&mut self) {
1480 self.string_pool.intern_text(bounds::INDEX_OOB_MESSAGE);
1481 for ty in [Type::Array(Box::new(Type::Unknown)), Type::Uint8Array] {
1482 self.string_pool.intern_text(&cast_check::error_prefix(&ty));
1483 }
1484 for tag in cast_check::TYPE_TAG_STRINGS {
1485 self.string_pool.intern_text(tag);
1486 }
1487 }
1488
1489 fn note_postfix_target(
1490 &mut self,
1491 ty: &Type,
1492 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1493 self.dependency_usage.collect_postfix_bigint_ops(ty);
1494 self.visit_type(ty)?;
1495
1496 Ok(())
1497 }
1498}
1499
1500fn is_shaped_receiver(ty: &Type) -> bool {
1504 let ty = crate::typechecker::infer::narrowing::strip_nullish(ty);
1505 match ty.peel() {
1506 Type::InterfaceRef { .. } | Type::Object { .. } => true,
1507 Type::Union(members) => members
1508 .iter()
1509 .any(|m| matches!(m.peel(), Type::InterfaceRef { .. } | Type::Object { .. })),
1510 _ => false,
1511 }
1512}