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)
992 && (operand_ty.is_string_shaped()
993 || matches!(operand_ty.primitive_behavior(), crate::Type::Union(_)))
994 {
995 self.dependency_usage.collect_number_coercion_host_value();
996 }
997 }
998 TypedExprKind::Call { mangled, .. } | TypedExprKind::GenericCall { mangled, .. } => {
999 self.dependency_usage.note_value(mangled.clone());
1000 }
1001 TypedExprKind::VirtualCall { target, tool, .. } => {
1002 self.dependency_usage
1003 .note_value(crate::mangle::host(&target.package_name(), tool));
1004 self.dependency_usage
1005 .note_value(crate::mangle::host(target.host_module(), "call"));
1006 if !matches!(expr.ty.peel(), Type::String) {
1007 self.dependency_usage.collect_json_host_values();
1008 }
1009 }
1010 TypedExprKind::IntrinsicCall { kind, .. } => match kind {
1011 Intrinsic::JsonParse | Intrinsic::JsonStringify => {
1012 self.dependency_usage.collect_json_host_values();
1013 }
1014 Intrinsic::BigIntFromString => {
1015 self.dependency_usage
1016 .collect_bigint_host_value("fromString");
1017 }
1018 Intrinsic::ToString => {
1019 self.dependency_usage
1020 .note_value(crate::mangle::prelude("__value_to_string"));
1021 }
1022 Intrinsic::ToObject => {
1023 self.dependency_usage.note_member(crate::mangle::extend(
1024 &crate::mangle::prelude("ObjectConstructor"),
1025 "#toObject",
1026 ));
1027 }
1028 Intrinsic::Assert => {}
1029 },
1030 TypedExprKind::MethodCall {
1031 receiver,
1032 iface,
1033 name,
1034 args,
1035 ..
1036 } => {
1037 self.note_method_call(
1038 ta.source_type(*receiver)
1039 .map_err(crate::codegen::arena_failure)?,
1040 iface,
1041 name,
1042 args.len(),
1043 &expr.ty,
1044 )?;
1045 }
1046 TypedExprKind::GenericMethodCall {
1047 receiver,
1048 iface,
1049 name,
1050 args,
1051 ..
1052 } => {
1053 self.note_method_call(
1054 ta.source_type(*receiver)
1055 .map_err(crate::codegen::arena_failure)?,
1056 iface,
1057 name,
1058 args.len(),
1059 &expr.ty,
1060 )?;
1061 }
1062 TypedExprKind::InterfacePropertyAccess { iface, name, .. } => {
1063 self.dependency_usage
1064 .note_member(crate::mangle::extend(iface, &name.name));
1065 }
1066 TypedExprKind::ObjectLiteral { fields, members } => {
1067 if members
1068 .iter()
1069 .any(|m| matches!(m, crate::TypedObjectMember::Computed { .. }))
1070 {
1071 self.note_record_helpers();
1072 }
1073 if members.iter().any(|member| {
1074 matches!(
1075 member,
1076 crate::TypedObjectMember::Spread { .. }
1077 | crate::TypedObjectMember::Computed { .. }
1078 )
1079 }) {
1080 self.dependency_usage.note_member(crate::mangle::extend(
1081 &crate::mangle::prelude("ObjectConstructor"),
1082 "#spread",
1083 ));
1084 }
1085 for member in members {
1086 if let crate::TypedObjectMember::Spread { source, .. } = member
1087 && let Some(omitted) = ta.spread_omitted_fields.get(source)
1088 {
1089 self.extra_field_names.extend(omitted.iter().cloned());
1090 }
1091 }
1092 for field in fields {
1093 let mut source = Some(&field.source);
1094 while let Some(TypedObjectFieldSource::Spread {
1095 source_ty,
1096 field_name,
1097 fallback,
1098 ..
1099 }) = source
1100 {
1101 self.visit_type(source_ty)?;
1102 self.extra_field_names.push(field_name.clone());
1105 self.note_shape_member_names(source_ty);
1106 source = fallback.as_deref();
1107 }
1108 }
1109 }
1110 TypedExprKind::ArrayLiteral { element_ty, .. } => {
1111 self.visit_type(element_ty)?;
1112 }
1113 TypedExprKind::TupleLiteral { element_types, .. } => {
1114 for ty in element_types {
1115 self.visit_type(ty)?;
1116 }
1117 }
1118 TypedExprKind::FieldAccess { receiver, name } => {
1119 self.extra_field_names.push(name.name.clone());
1120 self.note_shaped_property_access(
1121 ta.source_type(*receiver)
1122 .map_err(crate::codegen::arena_failure)?,
1123 &name.name,
1124 AccessorKind::Get,
1125 );
1126 }
1127 TypedExprKind::IndexAccess { receiver, .. } => {
1128 self.note_index_check();
1129 self.note_string_index(
1130 ta.source_type(*receiver)
1131 .map_err(crate::codegen::arena_failure)?,
1132 );
1133 }
1134 TypedExprKind::Closure {
1135 runtime_generics,
1136 params,
1137 captured,
1138 body,
1139 return_type,
1140 ..
1141 } => {
1142 self.closure_metas.push(ClosureMeta {
1143 this_type: ta.closure_this.get(&id).cloned(),
1144 self_name: ta.closure_names.get(&id).cloned(),
1145 runtime_generics: runtime_generics.clone(),
1146 expr_id: id,
1147 signature: expr.ty.clone(),
1148 captured: captured.clone(),
1149 params: params.clone(),
1150 body: body.clone(),
1151 return_type: return_type.clone(),
1152 });
1153 for p in params {
1154 self.visit_type(&p.ty)?;
1155 }
1156 self.visit_type(return_type)?;
1157 }
1158 TypedExprKind::Narrowed { cast_info, .. } => {
1159 self.visit_type(&cast_info.from_ty)?;
1160 self.visit_type(&cast_info.to_ty)?;
1161 }
1162 TypedExprKind::OptionalChain { base, parts } => {
1163 self.note_chain_parts(ta, id, *base, parts)?;
1164 }
1165 TypedExprKind::PostfixUnary { target, .. } => match target {
1166 PostfixTarget::Local { .. } => {
1167 self.note_postfix_target(&expr.ty)?;
1168 }
1169 PostfixTarget::Global { mangled, .. } => {
1170 self.dependency_usage.note_value(mangled.clone());
1171 self.note_postfix_target(&expr.ty)?;
1172 }
1173 PostfixTarget::Field { receiver, name, .. } => {
1174 self.note_postfix_target(&expr.ty)?;
1175 let receiver_ty = ta
1176 .source_type(*receiver)
1177 .map_err(crate::codegen::arena_failure)?;
1178 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Get);
1179 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Set);
1180 if let Some(iface) = crate::codegen::host_property_iface(receiver_ty) {
1181 self.dependency_usage
1182 .note_member(crate::mangle::extend(&iface, &name.name));
1183 self.dependency_usage.note_member(crate::mangle::extend(
1184 &iface,
1185 &crate::mangle::property_setter(&name.name),
1186 ));
1187 }
1188 }
1189 PostfixTarget::Index { elem_ty, .. } => {
1190 self.note_postfix_target(elem_ty)?;
1191 self.note_index_check();
1192 }
1193 },
1194 TypedExprKind::NonNullAssert { .. } => {
1195 self.string_pool.intern_text(throw::NON_NULL_ASSERT_MESSAGE);
1196 }
1197 TypedExprKind::Cast {
1198 target_ty, check, ..
1199 } => {
1200 self.string_pool
1201 .intern_text(&cast_check::error_prefix(target_ty));
1202 for tag in cast_check::TYPE_TAG_STRINGS {
1203 self.string_pool.intern_text(tag);
1204 }
1205 self.visit_type(target_ty)?;
1206 if let Some(check) = check {
1207 self.visit_type(check)?;
1208 self.note_shape_member_names(check);
1209 }
1210 }
1211 TypedExprKind::Regex { source, flags } => {
1212 self.string_pool.intern_text(source);
1213 self.string_pool.intern_text(flags);
1214 }
1215 TypedExprKind::CallClosure { callee, .. } => {
1216 self.dependency_usage
1217 .note_value(crate::mangle::prelude("__value_invoke_defaults"));
1218 self.string_pool.intern_text(&cast_check::error_prefix(
1219 ta.source_type(*callee)
1220 .map_err(crate::codegen::arena_failure)?,
1221 ));
1222 for tag in cast_check::TYPE_TAG_STRINGS {
1223 self.string_pool.intern_text(tag);
1224 }
1225 }
1226 TypedExprKind::InstanceOf { class, .. } => {
1227 self.visit_type(class)?;
1230 }
1231 TypedExprKind::Number(_)
1232 | TypedExprKind::Boolean(_)
1233 | TypedExprKind::Null
1234 | TypedExprKind::Undefined
1235 | TypedExprKind::This
1236 | TypedExprKind::EffectThen { .. }
1237 | TypedExprKind::Sequence { .. }
1238 | TypedExprKind::LocalRef { .. }
1239 | TypedExprKind::LocalNarrowRef { .. }
1240 | TypedExprKind::SuperCtorCall { .. }
1241 | TypedExprKind::SuperMethodCall { .. }
1242 | TypedExprKind::TypeofTag { .. }
1243 | TypedExprKind::Ternary { .. }
1244 | TypedExprKind::NullishCoalesce { .. } => {}
1245 };
1246 Ok(())
1247 }
1248
1249 fn note_method_call(
1252 &mut self,
1253 receiver_ty: &Type,
1254 iface: &crate::MangledName,
1255 name: &crate::Ident,
1256 arity: usize,
1257 ret: &Type,
1258 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1259 self.dependency_usage
1260 .note_member(crate::mangle::extend(iface, &name.name));
1261 self.string_pool.intern_text("Value is not callable");
1262 self.string_pool
1263 .intern_text("Unbound function has no this receiver");
1264 self.extra_field_names.push(name.name.clone());
1265 self.note_shape_dispatch(receiver_ty, arity, ret)?;
1266
1267 Ok(())
1268 }
1269
1270 fn note_shape_dispatch(
1281 &mut self,
1282 receiver_ty: &Type,
1283 arity: usize,
1284 ret: &Type,
1285 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1286 self.string_pool.intern_text("Value is not callable");
1287 self.string_pool
1288 .intern_text("Unbound function has no this receiver");
1289 let receiver_ty = crate::typechecker::infer::narrowing::strip_nullish(receiver_ty);
1291 if !matches!(
1292 receiver_ty.peel(),
1293 Type::InterfaceRef { .. } | Type::ClassRef { .. }
1294 ) {
1295 return Ok(());
1296 }
1297 self.mentioned_closure_sigs
1298 .push(ClosureSig::of(arity, ret)?);
1299
1300 Ok(())
1301 }
1302
1303 fn note_binding_cell(&mut self) {
1304 self.string_pool
1305 .intern_text(super::function_emitter::binding_cells::UNINITIALIZED_PARAMETER_MESSAGE);
1306 }
1307
1308 fn note_chain_parts(
1311 &mut self,
1312 ta: &TypedAst,
1313 id: ExprId,
1314 base: ExprId,
1315 parts: &[TypedChainPart],
1316 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1317 let source_types = ta.runtime_chain_types.get(&id);
1318 let mut receiver_ty = ta
1319 .source_type(base)
1320 .map_err(crate::codegen::arena_failure)?;
1321 for (index, part) in parts.iter().enumerate() {
1322 if let TypedChainPart::MethodCall { iface, name, .. }
1323 | TypedChainPart::InterfaceProperty { iface, name, .. } = part
1324 {
1325 self.string_pool.intern_text(iface.as_str());
1326 self.string_pool.intern_text(&name.name);
1327 }
1328 match part {
1329 TypedChainPart::Field {
1330 name, result_ty, ..
1331 } => {
1332 self.extra_field_names.push(name.name.clone());
1333 self.visit_type(result_ty)?;
1334 self.note_shaped_property_access(receiver_ty, &name.name, AccessorKind::Get);
1335 }
1336 TypedChainPart::InterfaceProperty {
1337 iface,
1338 name,
1339 result_ty,
1340 span,
1341 ..
1342 } => {
1343 if ta.authored_call_arguments(*span).is_some()
1344 && !crate::codegen::is_host_package(iface.as_str())
1345 {
1346 for helper in ["__value_member", "__value_invoke"] {
1347 self.dependency_usage
1348 .note_value(crate::mangle::prelude(helper));
1349 }
1350 }
1351 self.extra_field_names.push(name.name.clone());
1352 self.dependency_usage
1353 .note_member(crate::mangle::extend(iface, &name.name));
1354 self.visit_type(result_ty)?;
1355 }
1356 TypedChainPart::Index { result_ty, .. } => {
1357 self.note_record_helpers();
1358 self.visit_type(result_ty)?;
1359 self.note_index_check();
1362 self.note_string_index(receiver_ty);
1363 }
1364 TypedChainPart::Call {
1365 result_ty,
1366 union_signature,
1367 ..
1368 } => {
1369 self.dependency_usage
1370 .note_value(crate::mangle::prelude("__value_invoke_defaults"));
1371 self.visit_type(result_ty)?;
1372 if let Some(signature) = union_signature {
1373 self.visit_type(signature)?;
1374 }
1375 }
1376 TypedChainPart::NonNull { result_ty, .. } => {
1377 self.visit_type(result_ty)?;
1378 self.string_pool.intern_text(throw::NON_NULL_ASSERT_MESSAGE);
1379 }
1380 TypedChainPart::MethodCall {
1381 iface,
1382 name,
1383 args,
1384 result_ty,
1385 span,
1386 ..
1387 } => {
1388 if ta.authored_call_arguments(*span).is_some()
1389 && !crate::codegen::is_host_package(iface.as_str())
1390 {
1391 for helper in ["__value_member", "__value_invoke"] {
1392 self.dependency_usage
1393 .note_value(crate::mangle::prelude(helper));
1394 }
1395 }
1396 self.extra_field_names.push(name.name.clone());
1397 self.dependency_usage
1398 .note_member(crate::mangle::extend(iface, &name.name));
1399 self.visit_type(result_ty)?;
1400 self.note_shape_dispatch(receiver_ty, args.len(), result_ty)?;
1401 }
1402 }
1403 receiver_ty = source_types.map_or_else(|| part.result_ty(), |types| &types[index + 1]);
1404 }
1405 Ok(())
1406 }
1407
1408 fn note_shaped_property_access(&mut self, receiver_ty: &Type, prop: &str, kind: AccessorKind) {
1421 if matches!(kind, AccessorKind::Set) {
1422 self.dependency_usage.note_member(crate::mangle::extend(
1423 &crate::mangle::prelude("ObjectConstructor"),
1424 "#insertField",
1425 ));
1426 }
1427 self.mentioned_closure_sigs
1428 .push(super::field_guards::signature());
1429 if !is_shaped_receiver(receiver_ty) && !matches!(receiver_ty.peel(), Type::ClassRef { .. })
1430 {
1431 return;
1432 }
1433 self.string_pool.intern_text("Value is not callable");
1434 self.string_pool
1435 .intern_text("Unbound function has no this receiver");
1436 self.extra_field_names
1439 .push(crate::codegen::classes::accessor_getter_name(prop));
1440 self.mentioned_closure_sigs
1441 .push(crate::codegen::classes::accessor_closure_sig(
1442 AccessorKind::Get,
1443 ));
1444 if matches!(kind, AccessorKind::Set) {
1445 self.extra_field_names
1446 .push(crate::codegen::classes::accessor_setter_name(prop));
1447 self.mentioned_closure_sigs
1448 .push(crate::codegen::classes::accessor_closure_sig(
1449 AccessorKind::Set,
1450 ));
1451 self.string_pool
1454 .intern_text(throw::READ_ONLY_PROPERTY_MESSAGE);
1455 }
1456 }
1457
1458 fn note_string_index(&mut self, receiver_ty: &Type) {
1461 if crate::typechecker::infer::narrowing::strip_nullish(receiver_ty).is_string_shaped() {
1462 self.dependency_usage
1463 .note_value(crate::mangle::prelude("string_index"));
1464 }
1465 }
1466
1467 fn note_index_check(&mut self) {
1468 self.string_pool.intern_text(bounds::INDEX_OOB_MESSAGE);
1469 for ty in [Type::Array(Box::new(Type::Unknown)), Type::Uint8Array] {
1470 self.string_pool.intern_text(&cast_check::error_prefix(&ty));
1471 }
1472 for tag in cast_check::TYPE_TAG_STRINGS {
1473 self.string_pool.intern_text(tag);
1474 }
1475 }
1476
1477 fn note_postfix_target(
1478 &mut self,
1479 ty: &Type,
1480 ) -> Result<(), crate::compiler_error::CompilerFailure> {
1481 self.dependency_usage.collect_postfix_bigint_ops(ty);
1482 self.visit_type(ty)?;
1483
1484 Ok(())
1485 }
1486}
1487
1488fn is_shaped_receiver(ty: &Type) -> bool {
1492 let ty = crate::typechecker::infer::narrowing::strip_nullish(ty);
1493 match ty.peel() {
1494 Type::InterfaceRef { .. } | Type::Object { .. } => true,
1495 Type::Union(members) => members
1496 .iter()
1497 .any(|m| matches!(m.peel(), Type::InterfaceRef { .. } | Type::Object { .. })),
1498 _ => false,
1499 }
1500}