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