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