1#[path = "checker/intrinsic_environment.rs"]
14mod intrinsic_environment;
15
16use std::collections::{BTreeMap, HashMap};
17
18use crate::diagnostic::{Diagnostic, DiagnosticCode, Recovered};
19use crate::lint::{LintProfile, LintTable};
20use crate::source::{SourceId, TextRange};
21use crate::syntax::{
22 ArrayElement, AssignmentTarget, BindingPattern, CallArgument, ClassDeclaration, ClassMember,
23 EntityName, Expr, Expression, ForBinding, ForInitializer, FunctionBody, FunctionLike,
24 FunctionType, IdentifierNode, ImportBinding, InterfaceDeclaration, KeywordType, Literal,
25 MemberProperty, NodeId, ObjectMember, PropertyName, SourceFile, Statement, Token, Ty,
26 TypeAliasDeclaration, TypeLiteral, TypeMember, TypeNode, TypeReference, VariableDeclaration,
27 VariableKind,
28};
29use crate::warning::analyze_warnings;
30use intrinsic_environment::GlobalEnvironment;
31
32pub const DUPLICATE_DECLARATION: DiagnosticCode = DiagnosticCode::new("BAMTS-C001");
34pub const CANNOT_FIND_NAME: DiagnosticCode = DiagnosticCode::new("BAMTS-C002");
36pub const CANNOT_FIND_TYPE: DiagnosticCode = DiagnosticCode::new("BAMTS-C003");
38pub const TYPE_NOT_ASSIGNABLE: DiagnosticCode = DiagnosticCode::new("BAMTS-C004");
40
41const DUPLICATE_MESSAGE: &str = "A block-scoped declaration cannot redeclare an existing binding.";
42const CANNOT_FIND_NAME_MESSAGE: &str = "Cannot find name in any enclosing scope.";
43const CANNOT_FIND_TYPE_MESSAGE: &str = "Cannot find type name in any enclosing scope.";
44const NOT_ASSIGNABLE_MESSAGE: &str = "Initializer type is not assignable to the annotated type.";
45
46#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
48pub struct ScopeId(u32);
49
50impl ScopeId {
51 #[must_use]
52 pub const fn get(self) -> u32 {
53 self.0
54 }
55}
56
57#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
59pub struct SymbolId(u32);
60
61impl SymbolId {
62 #[must_use]
63 pub const fn new(value: u32) -> Self {
64 Self(value)
65 }
66
67 #[must_use]
68 pub const fn get(self) -> u32 {
69 self.0
70 }
71}
72
73#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
75pub struct TypeId(u32);
76
77impl TypeId {
78 #[must_use]
79 pub const fn get(self) -> u32 {
80 self.0
81 }
82}
83
84#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
86pub enum ScopeKind {
87 Global,
88 Module,
89 Function,
90 Block,
91 For,
92 Catch,
93 Class,
94}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
98pub struct Scope {
99 kind: ScopeKind,
100 parent: Option<ScopeId>,
101 values: BTreeMap<String, SymbolId>,
102 types: BTreeMap<String, SymbolId>,
103}
104
105impl Scope {
106 #[must_use]
107 pub const fn kind(&self) -> ScopeKind {
108 self.kind
109 }
110
111 #[must_use]
112 pub const fn parent(&self) -> Option<ScopeId> {
113 self.parent
114 }
115
116 #[must_use]
118 pub fn value(&self, name: &str) -> Option<SymbolId> {
119 self.values.get(name).copied()
120 }
121
122 #[must_use]
124 pub fn type_binding(&self, name: &str) -> Option<SymbolId> {
125 self.types.get(name).copied()
126 }
127}
128
129#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
132pub enum SymbolKind {
133 IntrinsicValue,
134 IntrinsicType,
135 Variable(VariableKind),
136 Function,
137 Parameter,
138 Class,
139 Interface,
140 TypeAlias,
141 Enum,
142 TypeParameter,
143 Import,
144 Namespace,
145}
146
147impl SymbolKind {
148 const fn occupies_value(self) -> bool {
149 matches!(
150 self,
151 Self::IntrinsicValue
152 | Self::Variable(_)
153 | Self::Function
154 | Self::Parameter
155 | Self::Class
156 | Self::Enum
157 | Self::Import
158 | Self::Namespace
159 )
160 }
161
162 const fn occupies_type(self) -> bool {
163 matches!(
164 self,
165 Self::IntrinsicType
166 | Self::Class
167 | Self::Enum
168 | Self::Interface
169 | Self::TypeAlias
170 | Self::TypeParameter
171 | Self::Import
172 )
173 }
174
175 const fn value_mergeable(self) -> bool {
177 matches!(self, Self::Variable(VariableKind::Var) | Self::Function)
178 }
179
180 const fn type_mergeable(self) -> bool {
182 matches!(self, Self::Interface)
183 }
184}
185
186#[derive(Clone, Debug, Eq, PartialEq)]
188pub struct Symbol {
189 name: String,
190 kind: SymbolKind,
191 scope: ScopeId,
192 declaration: NodeId,
193 range: TextRange,
194}
195
196impl Symbol {
197 #[must_use]
198 pub fn name(&self) -> &str {
199 &self.name
200 }
201
202 #[must_use]
203 pub const fn kind(&self) -> SymbolKind {
204 self.kind
205 }
206
207 #[must_use]
208 pub const fn scope(&self) -> ScopeId {
209 self.scope
210 }
211
212 #[must_use]
213 pub const fn declaration(&self) -> NodeId {
214 self.declaration
215 }
216
217 #[must_use]
218 pub const fn range(&self) -> TextRange {
219 self.range
220 }
221}
222
223#[derive(Clone, Debug, Eq, Hash, PartialEq)]
225pub struct PropertyType {
226 name: Box<str>,
227 optional: bool,
228 type_id: TypeId,
229}
230
231impl PropertyType {
232 #[must_use]
233 pub fn new(name: impl Into<Box<str>>, optional: bool, type_id: TypeId) -> Self {
234 Self {
235 name: name.into(),
236 optional,
237 type_id,
238 }
239 }
240
241 #[must_use]
242 pub fn name(&self) -> &str {
243 &self.name
244 }
245
246 #[must_use]
247 pub const fn optional(&self) -> bool {
248 self.optional
249 }
250
251 #[must_use]
252 pub const fn type_id(&self) -> TypeId {
253 self.type_id
254 }
255}
256
257#[derive(Clone, Debug, Eq, Hash, PartialEq)]
259pub struct FunctionSignature {
260 parameters: Vec<TypeId>,
261 return_type: TypeId,
262}
263
264impl FunctionSignature {
265 #[must_use]
266 pub fn parameters(&self) -> &[TypeId] {
267 &self.parameters
268 }
269
270 #[must_use]
271 pub const fn return_type(&self) -> TypeId {
272 self.return_type
273 }
274}
275
276#[derive(Clone, Debug, Eq, Hash, PartialEq)]
281pub enum Type {
282 Error,
283 Any,
284 Unknown,
285 Never,
286 Void,
287 Null,
288 Undefined,
289 Boolean,
290 Number,
291 BigInt,
292 String,
293 Symbol,
294 Object,
295 BooleanLiteral(bool),
296 NumberLiteral(Box<str>),
297 StringLiteral(Box<str>),
298 BigIntLiteral(Box<str>),
299 Array(TypeId),
300 Union(Vec<TypeId>),
301 ObjectType(Vec<PropertyType>),
302 Function(FunctionSignature),
303 Named(SymbolId),
305 NumericEnum(SymbolId),
307}
308
309#[derive(Clone, Debug)]
315pub struct TypeTable {
316 types: Vec<Type>,
317 index: HashMap<Type, TypeId>,
318 error: TypeId,
319 any: TypeId,
320 unknown: TypeId,
321 never: TypeId,
322 void: TypeId,
323 null: TypeId,
324 undefined: TypeId,
325 boolean: TypeId,
326 number: TypeId,
327 bigint: TypeId,
328 string: TypeId,
329 symbol: TypeId,
330 object: TypeId,
331}
332
333impl Default for TypeTable {
334 fn default() -> Self {
335 Self::new()
336 }
337}
338
339impl TypeTable {
340 #[must_use]
342 pub fn new() -> Self {
343 let mut table = Self {
344 types: Vec::new(),
345 index: HashMap::new(),
346 error: TypeId(0),
347 any: TypeId(0),
348 unknown: TypeId(0),
349 never: TypeId(0),
350 void: TypeId(0),
351 null: TypeId(0),
352 undefined: TypeId(0),
353 boolean: TypeId(0),
354 number: TypeId(0),
355 bigint: TypeId(0),
356 string: TypeId(0),
357 symbol: TypeId(0),
358 object: TypeId(0),
359 };
360 table.error = table.intern(Type::Error);
361 table.any = table.intern(Type::Any);
362 table.unknown = table.intern(Type::Unknown);
363 table.never = table.intern(Type::Never);
364 table.void = table.intern(Type::Void);
365 table.null = table.intern(Type::Null);
366 table.undefined = table.intern(Type::Undefined);
367 table.boolean = table.intern(Type::Boolean);
368 table.number = table.intern(Type::Number);
369 table.bigint = table.intern(Type::BigInt);
370 table.string = table.intern(Type::String);
371 table.symbol = table.intern(Type::Symbol);
372 table.object = table.intern(Type::Object);
373 table
374 }
375
376 fn intern(&mut self, ty: Type) -> TypeId {
377 if let Some(existing) = self.index.get(&ty) {
378 return *existing;
379 }
380 let id = TypeId(u32::try_from(self.types.len()).expect("type count fits in u32"));
381 self.types.push(ty.clone());
382 self.index.insert(ty, id);
383 id
384 }
385
386 #[must_use]
388 pub fn get(&self, id: TypeId) -> &Type {
389 &self.types[id.0 as usize]
390 }
391
392 #[must_use]
393 pub const fn error_type(&self) -> TypeId {
394 self.error
395 }
396 #[must_use]
397 pub const fn any(&self) -> TypeId {
398 self.any
399 }
400 #[must_use]
401 pub const fn unknown(&self) -> TypeId {
402 self.unknown
403 }
404 #[must_use]
405 pub const fn never(&self) -> TypeId {
406 self.never
407 }
408 #[must_use]
409 pub const fn void(&self) -> TypeId {
410 self.void
411 }
412 #[must_use]
413 pub const fn null_type(&self) -> TypeId {
414 self.null
415 }
416 #[must_use]
417 pub const fn undefined_type(&self) -> TypeId {
418 self.undefined
419 }
420 #[must_use]
421 pub const fn boolean(&self) -> TypeId {
422 self.boolean
423 }
424 #[must_use]
425 pub const fn number(&self) -> TypeId {
426 self.number
427 }
428 #[must_use]
429 pub const fn bigint(&self) -> TypeId {
430 self.bigint
431 }
432 #[must_use]
433 pub const fn string(&self) -> TypeId {
434 self.string
435 }
436 #[must_use]
437 pub const fn symbol_type(&self) -> TypeId {
438 self.symbol
439 }
440 #[must_use]
441 pub const fn object(&self) -> TypeId {
442 self.object
443 }
444
445 pub fn boolean_literal(&mut self, value: bool) -> TypeId {
447 self.intern(Type::BooleanLiteral(value))
448 }
449
450 pub fn number_literal(&mut self, text: &str) -> TypeId {
452 self.intern(Type::NumberLiteral(text.into()))
453 }
454
455 pub fn string_literal(&mut self, text: &str) -> TypeId {
457 self.intern(Type::StringLiteral(text.into()))
458 }
459
460 pub fn bigint_literal(&mut self, text: &str) -> TypeId {
462 self.intern(Type::BigIntLiteral(text.into()))
463 }
464
465 pub fn named(&mut self, symbol: SymbolId) -> TypeId {
467 self.intern(Type::Named(symbol))
468 }
469
470 pub fn numeric_enum(&mut self, symbol: SymbolId) -> TypeId {
472 self.intern(Type::NumericEnum(symbol))
473 }
474
475 pub fn array(&mut self, element: TypeId) -> TypeId {
477 self.intern(Type::Array(element))
478 }
479
480 pub fn object_type(&mut self, mut properties: Vec<PropertyType>) -> TypeId {
482 properties.sort_by(|left, right| left.name.cmp(&right.name));
483 properties.dedup_by(|left, right| left.name == right.name);
484 self.intern(Type::ObjectType(properties))
485 }
486
487 pub fn function(&mut self, parameters: Vec<TypeId>, return_type: TypeId) -> TypeId {
489 self.intern(Type::Function(FunctionSignature {
490 parameters,
491 return_type,
492 }))
493 }
494
495 pub fn union(&mut self, members: &[TypeId]) -> TypeId {
497 let mut flat = Vec::new();
498 for member in members {
499 match self.get(*member) {
500 Type::Any => return self.any,
501 Type::Unknown => return self.unknown,
502 Type::Never => {}
503 Type::Union(nested) => flat.extend(nested.iter().copied()),
504 _ => flat.push(*member),
505 }
506 }
507 flat.sort_by_key(|id| id.get());
508 flat.dedup();
509 match flat.len() {
510 0 => self.never,
511 1 => flat[0],
512 _ => self.intern(Type::Union(flat)),
513 }
514 }
515
516 #[must_use]
519 pub fn assignable(&self, source: TypeId, target: TypeId) -> bool {
520 if source == target {
521 return true;
522 }
523 let (from, to) = (self.get(source), self.get(target));
524 match (from, to) {
525 (Type::Error, _) | (_, Type::Error) => true,
526 (Type::Any, _) | (_, Type::Any) => true,
528 (_, Type::Unknown) => true,
530 (Type::Unknown, _) => false,
531 (Type::Never, _) => true,
534 (_, Type::Never) => false,
535 (Type::StringLiteral(_), Type::String) => true,
536 (Type::NumberLiteral(_), Type::Number) => true,
537 (Type::BooleanLiteral(_), Type::Boolean) => true,
538 (Type::BigIntLiteral(_), Type::BigInt) => true,
539 (Type::NumericEnum(_), Type::Number) | (Type::Number, Type::NumericEnum(_)) => true,
540 (Type::Union(sources), _) => sources.iter().all(|s| self.assignable(*s, target)),
541 (_, Type::Union(targets)) => targets.iter().any(|t| self.assignable(source, *t)),
542 (Type::Array(source_element), Type::Array(target_element)) => {
543 self.assignable(*source_element, *target_element)
544 }
545 (Type::ObjectType(source_props), Type::ObjectType(target_props)) => {
546 self.object_assignable(source_props, target_props)
547 }
548 (Type::Function(source_sig), Type::Function(target_sig)) => {
549 self.function_assignable(source_sig, target_sig)
550 }
551 _ => false,
552 }
553 }
554
555 #[must_use]
558 pub fn relation(&self, source: TypeId, target: TypeId) -> TypeRelation {
559 let compatible = self.assignable(source, target);
560 if !compatible {
561 return TypeRelation {
562 compatible,
563 hazards: Box::new([]),
564 };
565 }
566
567 let mut hazards = Vec::new();
568 if let (Type::Function(from), Type::Function(to)) = (self.get(source), self.get(target)) {
569 if from.parameters.len() < to.parameters.len() {
570 hazards.push(RelationHazard::FewerCallbackParameters);
571 }
572 if matches!(self.get(to.return_type), Type::Void)
573 && !matches!(self.get(from.return_type), Type::Void | Type::Never)
574 {
575 hazards.push(RelationHazard::ValueReturnedToVoid);
576 }
577 }
578 if matches!(
579 (self.get(source), self.get(target)),
580 (Type::NumericEnum(_), Type::Number) | (Type::Number, Type::NumericEnum(_))
581 ) {
582 hazards.push(RelationHazard::NumericEnumNumber);
583 }
584 if let (Type::ObjectType(from), Type::ObjectType(to)) = (self.get(source), self.get(target))
585 {
586 for target_property in to.iter().filter(|property| property.optional) {
587 let Some(source_property) = from
588 .iter()
589 .find(|property| property.name == target_property.name)
590 else {
591 continue;
592 };
593 if matches!(self.get(source_property.type_id), Type::Undefined)
594 && !self.contains_undefined(target_property.type_id)
595 {
596 hazards.push(RelationHazard::ExplicitUndefinedForOptional);
597 break;
598 }
599 }
600 }
601 TypeRelation {
602 compatible,
603 hazards: hazards.into_boxed_slice(),
604 }
605 }
606
607 fn contains_undefined(&self, type_id: TypeId) -> bool {
608 match self.get(type_id) {
609 Type::Undefined => true,
610 Type::Union(members) => members
611 .iter()
612 .any(|member| self.contains_undefined(*member)),
613 _ => false,
614 }
615 }
616
617 fn object_assignable(&self, source: &[PropertyType], target: &[PropertyType]) -> bool {
618 target.iter().all(
621 |want| match source.iter().find(|have| have.name == want.name) {
622 Some(have) => {
623 self.assignable(have.type_id, want.type_id)
624 || (want.optional && matches!(self.get(have.type_id), Type::Undefined))
625 }
626 None => want.optional,
627 },
628 )
629 }
630
631 fn function_assignable(&self, source: &FunctionSignature, target: &FunctionSignature) -> bool {
632 if source.parameters.len() > target.parameters.len() {
633 return false;
634 }
635 for (source_param, target_param) in source.parameters.iter().zip(&target.parameters) {
636 if !self.assignable(*target_param, *source_param) {
639 return false;
640 }
641 }
642 matches!(self.get(target.return_type), Type::Void)
643 || self.assignable(source.return_type, target.return_type)
644 }
645}
646
647#[derive(Clone, Debug, Eq, PartialEq)]
650pub struct TypeRelation {
651 compatible: bool,
652 hazards: Box<[RelationHazard]>,
653}
654
655impl TypeRelation {
656 #[must_use]
657 pub const fn compatible(&self) -> bool {
658 self.compatible
659 }
660
661 #[must_use]
662 pub fn hazards(&self) -> &[RelationHazard] {
663 &self.hazards
664 }
665}
666
667#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
669pub enum RelationHazard {
670 ExplicitUndefinedForOptional,
671 FewerCallbackParameters,
672 ValueReturnedToVoid,
673 NumericEnumNumber,
674}
675
676#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
678pub struct ObjectId(u32);
679
680#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
682pub struct NodeKey {
683 pub source_id: SourceId,
684 pub node_id: NodeId,
685}
686
687#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
689pub enum SemanticHazard {
690 UncheckedIndexRead,
691 ExplicitUndefinedOptional,
692 DetachedMethod,
693 DivergentAccessor,
694 ReadonlyAliasMutation,
695 FewerCallbackParameters,
696 ValueReturnedToVoid,
697 OpenObjectKeys,
698 IndexSignatureDotAccess,
699 ImplicitAny,
700 UncheckedAssertion,
701 DeclarationInferenceDependency,
702 TypeImportedAsValue,
703 TypeReexportedAsValue,
704 UncheckedSideEffectImport,
705 InteropDependentDefaultImport,
706 CjsEsmNamedExportMismatch,
707 VirtualCallInConstructor,
708 InitializedFieldShadowsAccessor,
709 ImplicitOverride,
710 NumericEnumNumber,
711 NumericEnumReverseLookup,
712 NonExhaustiveSwitch,
713 InvalidNumberFormatting,
714 NumericKeyOrder,
715 JsonStringifyUnserializable,
716 UncheckedJsonParse,
717 NumericDefaultSort,
718 LooseEqualityCoercion,
719 ObjectToPrimitive,
720 SymbolInterpolation,
721 UnsafeToStringTag,
722 UninitializedFieldShadowsAccessor,
723}
724
725#[derive(Clone, Debug, Eq, PartialEq)]
727pub struct HazardFact {
728 pub hazard: SemanticHazard,
729 pub range: TextRange,
730 pub note: Option<Box<str>>,
731}
732
733#[derive(Clone, Debug, Default)]
735pub struct AnalysisFacts {
736 hazards: Vec<HazardFact>,
737}
738
739impl AnalysisFacts {
740 #[must_use]
741 pub fn hazards(&self) -> &[HazardFact] {
742 &self.hazards
743 }
744
745 pub(crate) fn push(&mut self, fact: HazardFact) {
746 if !self
747 .hazards
748 .iter()
749 .any(|existing| existing.hazard == fact.hazard && existing.range == fact.range)
750 {
751 self.hazards.push(fact);
752 }
753 }
754}
755
756#[derive(Clone, Debug)]
758pub struct SemanticModel {
759 scopes: Vec<Scope>,
760 symbols: Vec<Symbol>,
761 symbol_types: Vec<TypeId>,
762 references: HashMap<NodeId, SymbolId>,
763 types: TypeTable,
764 module_scope: ScopeId,
765 facts: AnalysisFacts,
766}
767
768impl SemanticModel {
769 #[must_use]
771 pub fn scopes(&self) -> &[Scope] {
772 &self.scopes
773 }
774
775 #[must_use]
777 pub fn scope(&self, id: ScopeId) -> &Scope {
778 &self.scopes[id.0 as usize]
779 }
780
781 #[must_use]
783 pub const fn module_scope(&self) -> ScopeId {
784 self.module_scope
785 }
786
787 #[must_use]
789 pub fn symbols(&self) -> &[Symbol] {
790 &self.symbols
791 }
792
793 #[must_use]
795 pub fn symbol(&self, id: SymbolId) -> &Symbol {
796 &self.symbols[id.0 as usize]
797 }
798
799 #[must_use]
801 pub fn symbol_type(&self, id: SymbolId) -> TypeId {
802 self.symbol_types[id.0 as usize]
803 }
804
805 #[must_use]
807 pub const fn types(&self) -> &TypeTable {
808 &self.types
809 }
810
811 #[must_use]
813 pub const fn facts(&self) -> &AnalysisFacts {
814 &self.facts
815 }
816
817 pub(crate) fn replace_facts(&mut self, facts: AnalysisFacts) {
818 self.facts = facts;
819 }
820
821 #[must_use]
823 pub fn reference(&self, node: NodeId) -> Option<SymbolId> {
824 self.references.get(&node).copied()
825 }
826
827 #[must_use]
829 pub fn resolved_reference_count(&self) -> usize {
830 self.references.len()
831 }
832
833 #[must_use]
835 pub fn lookup_value(&self, scope: ScopeId, name: &str) -> Option<SymbolId> {
836 let mut current = Some(scope);
837 while let Some(id) = current {
838 let scope = &self.scopes[id.0 as usize];
839 if let Some(symbol) = scope.values.get(name) {
840 return Some(*symbol);
841 }
842 current = scope.parent;
843 }
844 None
845 }
846
847 #[must_use]
849 pub fn lookup_type(&self, scope: ScopeId, name: &str) -> Option<SymbolId> {
850 let mut current = Some(scope);
851 while let Some(id) = current {
852 let scope = &self.scopes[id.0 as usize];
853 if let Some(symbol) = scope.types.get(name) {
854 return Some(*symbol);
855 }
856 current = scope.parent;
857 }
858 None
859 }
860}
861
862#[must_use]
864pub fn check(source_file: &Recovered<SourceFile>) -> Recovered<SemanticModel> {
865 check_with_lints(source_file, &LintTable::new(LintProfile::Default))
866}
867
868#[must_use]
870pub fn check_with_lints(
871 source_file: &Recovered<SourceFile>,
872 levels: &LintTable,
873) -> Recovered<SemanticModel> {
874 let source = source_file.product();
875 let (mut model, mut diagnostics) = check_core(source);
876 model.replace_facts(crate::rules::semantic::collect_facts(source, &model));
877 diagnostics.extend(analyze_warnings(source_file, levels));
878 diagnostics.extend(crate::rules::analyze_semantic(source, &model, None, levels));
879 Recovered::new(model, diagnostics)
880}
881
882#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
884pub struct ResolvedModuleEdge {
885 pub from: SourceId,
886 pub specifier: NodeId,
887 pub to: SourceId,
888}
889
890#[derive(Clone, Copy)]
892pub struct ProgramCheckInput<'a> {
893 pub files: &'a [Recovered<SourceFile>],
894 pub edges: &'a [ResolvedModuleEdge],
895}
896
897#[derive(Clone, Debug)]
899pub struct ProgramSemanticModel {
900 files: BTreeMap<SourceId, SemanticModel>,
901 edges: Box<[ResolvedModuleEdge]>,
902}
903
904impl ProgramSemanticModel {
905 #[must_use]
906 pub fn file(&self, source_id: SourceId) -> Option<&SemanticModel> {
907 self.files.get(&source_id)
908 }
909
910 #[must_use]
911 pub fn edges(&self) -> &[ResolvedModuleEdge] {
912 &self.edges
913 }
914}
915
916#[must_use]
918pub fn check_program(
919 input: ProgramCheckInput<'_>,
920 levels: &LintTable,
921) -> Recovered<ProgramSemanticModel> {
922 let mut files = BTreeMap::new();
923 let mut diagnostics = Vec::new();
924 for recovered in input.files {
925 let source = recovered.product();
926 let (mut model, core_diagnostics) = check_core(source);
927 model.replace_facts(crate::rules::semantic::collect_facts(source, &model));
928 diagnostics.extend(core_diagnostics);
929 diagnostics.extend(analyze_warnings(recovered, levels));
930 files.insert(source.source_id(), model);
931 }
932 crate::rules::semantic::collect_program_facts(input.files, input.edges, &mut files);
933 let program = ProgramSemanticModel {
934 files,
935 edges: input.edges.into(),
936 };
937 for recovered in input.files {
938 let source = recovered.product();
939 let model = program
940 .file(source.source_id())
941 .expect("program model contains every input source");
942 diagnostics.extend(crate::rules::analyze_semantic(
943 source,
944 model,
945 Some(&program),
946 levels,
947 ));
948 }
949 Recovered::new(program, diagnostics)
950}
951
952fn check_core(source: &SourceFile) -> (SemanticModel, Vec<Diagnostic>) {
953 let mut checker = Checker::new(source);
954 checker.run();
955 checker.finish()
956}
957
958#[derive(Clone, Copy)]
960enum TypeState {
961 Unresolved,
962 InProgress,
963 Done(TypeId),
964}
965
966#[derive(Clone, Copy)]
968enum TypeDef<'src> {
969 Alias {
970 scope: ScopeId,
971 type_parameters: Option<&'src crate::syntax::TypeParameterList>,
972 node: &'src Ty,
973 },
974 Interface {
975 scope: ScopeId,
976 type_parameters: Option<&'src crate::syntax::TypeParameterList>,
977 extends: &'src [TypeReference],
978 members: &'src [crate::syntax::TypeMemberNode],
979 },
980}
981
982struct Checker<'src> {
983 source: &'src SourceFile,
984 intrinsics: GlobalEnvironment,
985 scopes: Vec<Scope>,
986 symbols: Vec<Symbol>,
987 symbol_types: Vec<TypeId>,
988 type_state: Vec<TypeState>,
989 type_defs: HashMap<SymbolId, TypeDef<'src>>,
990 references: HashMap<NodeId, SymbolId>,
991 diagnostics: Vec<Diagnostic>,
992 types: TypeTable,
993 module_scope: ScopeId,
994}
995
996impl<'src> Checker<'src> {
997 fn new(source: &'src SourceFile) -> Self {
998 let mut checker = Self {
999 source,
1000 intrinsics: GlobalEnvironment::standard(),
1001 scopes: Vec::new(),
1002 symbols: Vec::new(),
1003 symbol_types: Vec::new(),
1004 type_state: Vec::new(),
1005 type_defs: HashMap::new(),
1006 references: HashMap::new(),
1007 diagnostics: Vec::new(),
1008 types: TypeTable::new(),
1009 module_scope: ScopeId(0),
1010 };
1011 let global_scope = checker.new_scope(ScopeKind::Global, None);
1012 checker.module_scope = checker.new_scope(ScopeKind::Module, Some(global_scope));
1013 checker.bind_intrinsic_environment(global_scope);
1014 checker
1015 }
1016
1017 fn bind_intrinsic_environment(&mut self, scope: ScopeId) {
1018 for name in self.intrinsics.values() {
1019 self.declare(
1020 name,
1021 SymbolKind::IntrinsicValue,
1022 scope,
1023 NodeId::default(),
1024 NodeId::default_range(),
1025 );
1026 }
1027 for name in self.intrinsics.types() {
1028 self.declare(
1029 name,
1030 SymbolKind::IntrinsicType,
1031 scope,
1032 NodeId::default(),
1033 NodeId::default_range(),
1034 );
1035 }
1036 }
1037
1038 fn run(&mut self) {
1039 let statements = self.source.statements();
1040 let scope = self.module_scope;
1041 self.bind_statements(statements, scope);
1042 self.bind_hoisted_statements(statements, scope);
1043 self.resolve_statements(statements, scope);
1044 }
1045
1046 fn finish(self) -> (SemanticModel, Vec<Diagnostic>) {
1047 let model = SemanticModel {
1048 scopes: self.scopes,
1049 symbols: self.symbols,
1050 symbol_types: self.symbol_types,
1051 references: self.references,
1052 types: self.types,
1053 module_scope: self.module_scope,
1054 facts: AnalysisFacts::default(),
1055 };
1056 (model, self.diagnostics)
1057 }
1058
1059 fn text(&self, token: &Token) -> &'src str {
1062 self.source.token_text(token).unwrap_or("")
1063 }
1064
1065 fn identifier_text(&self, identifier: &IdentifierNode) -> &'src str {
1066 self.text(identifier.data().token())
1067 }
1068
1069 fn new_scope(&mut self, kind: ScopeKind, parent: Option<ScopeId>) -> ScopeId {
1070 let id = ScopeId(u32::try_from(self.scopes.len()).expect("scope count fits in u32"));
1071 self.scopes.push(Scope {
1072 kind,
1073 parent,
1074 values: BTreeMap::new(),
1075 types: BTreeMap::new(),
1076 });
1077 id
1078 }
1079
1080 fn value_hoist_scope(&self, scope: ScopeId) -> ScopeId {
1085 let mut current = scope;
1086 loop {
1087 let node = &self.scopes[current.0 as usize];
1088 if matches!(node.kind, ScopeKind::Function | ScopeKind::Module) {
1089 return current;
1090 }
1091 match node.parent {
1092 Some(parent) => current = parent,
1093 None => return current,
1094 }
1095 }
1096 }
1097
1098 fn emit(&mut self, code: DiagnosticCode, range: TextRange, message: &'static str) {
1099 self.diagnostics.push(Diagnostic::error(
1100 code,
1101 self.source.source_id(),
1102 range,
1103 message,
1104 ));
1105 }
1106
1107 fn declare(
1110 &mut self,
1111 name: &str,
1112 kind: SymbolKind,
1113 scope: ScopeId,
1114 declaration: NodeId,
1115 range: TextRange,
1116 ) -> SymbolId {
1117 let scope = if matches!(
1122 kind,
1123 SymbolKind::Variable(VariableKind::Var) | SymbolKind::Function
1124 ) {
1125 self.value_hoist_scope(scope)
1126 } else {
1127 scope
1128 };
1129 if kind.occupies_value()
1130 && let Some(existing) = self.scopes[scope.0 as usize].values.get(name)
1131 && kind.value_mergeable()
1132 && self.symbols[existing.get() as usize].kind.value_mergeable()
1133 {
1134 return *existing;
1135 }
1136 let id = SymbolId(u32::try_from(self.symbols.len()).expect("symbol count fits in u32"));
1137 self.symbols.push(Symbol {
1138 name: name.to_owned(),
1139 kind,
1140 scope,
1141 declaration,
1142 range,
1143 });
1144 self.symbol_types.push(self.types.any());
1145 self.type_state.push(TypeState::Unresolved);
1146
1147 let mut conflict = false;
1148 if kind.occupies_value() {
1149 conflict |= self.insert_value(scope, name, id, kind);
1150 }
1151 if kind.occupies_type() {
1152 conflict |= self.insert_type(scope, name, id, kind);
1153 }
1154 if conflict {
1155 self.emit(DUPLICATE_DECLARATION, range, DUPLICATE_MESSAGE);
1156 }
1157 id
1158 }
1159
1160 fn insert_value(&mut self, scope: ScopeId, name: &str, id: SymbolId, kind: SymbolKind) -> bool {
1161 match self.scopes[scope.0 as usize].values.get(name) {
1162 None => {
1163 self.scopes[scope.0 as usize]
1164 .values
1165 .insert(name.to_owned(), id);
1166 false
1167 }
1168 Some(existing) => {
1169 let existing_kind = self.symbols[existing.get() as usize].kind;
1170 !(kind.value_mergeable() && existing_kind.value_mergeable())
1171 }
1172 }
1173 }
1174
1175 fn insert_type(&mut self, scope: ScopeId, name: &str, id: SymbolId, kind: SymbolKind) -> bool {
1176 match self.scopes[scope.0 as usize].types.get(name) {
1177 None => {
1178 self.scopes[scope.0 as usize]
1179 .types
1180 .insert(name.to_owned(), id);
1181 false
1182 }
1183 Some(existing) => {
1184 let existing_kind = self.symbols[existing.get() as usize].kind;
1185 !(kind.type_mergeable() && existing_kind.type_mergeable())
1186 }
1187 }
1188 }
1189
1190 fn bind_statements(&mut self, statements: &'src [crate::syntax::Stmt], scope: ScopeId) {
1191 for statement in statements {
1192 self.bind_statement(statement, scope);
1193 }
1194 }
1195
1196 fn bind_hoisted_statements(&mut self, statements: &'src [crate::syntax::Stmt], scope: ScopeId) {
1200 for statement in statements {
1201 self.bind_hoisted_statement(statement, scope);
1202 }
1203 }
1204
1205 fn bind_hoisted_statement(&mut self, statement: &'src crate::syntax::Stmt, scope: ScopeId) {
1206 match statement.data() {
1207 Statement::Variable(variable) if variable.kind == VariableKind::Var => {
1208 self.bind_variable(variable, scope, statement.id());
1209 }
1210 Statement::Function(function) => {
1211 if let Some(name) = &function.function.name {
1212 self.declare(
1213 self.identifier_text(name),
1214 SymbolKind::Function,
1215 scope,
1216 statement.id(),
1217 name.range(),
1218 );
1219 }
1220 }
1221 Statement::Block(block) => {
1222 self.bind_hoisted_statements(&block.data().statements, scope)
1223 }
1224 Statement::If(statement) => {
1225 self.bind_hoisted_statement(&statement.consequent, scope);
1226 if let Some(alternate) = &statement.alternate {
1227 self.bind_hoisted_statement(alternate, scope);
1228 }
1229 }
1230 Statement::Switch(statement) => {
1231 for case in &statement.cases {
1232 self.bind_hoisted_statements(&case.data().consequent, scope);
1233 }
1234 }
1235 Statement::For(for_statement) => {
1236 if let Some(ForInitializer::Variable(variable)) = &for_statement.initializer
1237 && variable.kind == VariableKind::Var
1238 {
1239 self.bind_variable(variable, scope, NodeId::default());
1240 }
1241 self.bind_hoisted_statement(&for_statement.body, scope);
1242 }
1243 Statement::ForIn(for_statement) => {
1244 if let ForBinding::Variable(variable) = &for_statement.binding
1245 && variable.kind == VariableKind::Var
1246 {
1247 self.bind_variable(variable, scope, NodeId::default());
1248 }
1249 self.bind_hoisted_statement(&for_statement.body, scope);
1250 }
1251 Statement::ForOf(for_statement) => {
1252 if let ForBinding::Variable(variable) = &for_statement.binding
1253 && variable.kind == VariableKind::Var
1254 {
1255 self.bind_variable(variable, scope, NodeId::default());
1256 }
1257 self.bind_hoisted_statement(&for_statement.body, scope);
1258 }
1259 Statement::While(statement) => self.bind_hoisted_statement(&statement.body, scope),
1260 Statement::DoWhile(statement) => self.bind_hoisted_statement(&statement.body, scope),
1261 Statement::Try(statement) => {
1262 self.bind_hoisted_statements(&statement.block.data().statements, scope);
1263 if let Some(handler) = &statement.handler {
1264 self.bind_hoisted_statements(&handler.data().body.data().statements, scope);
1265 }
1266 if let Some(finalizer) = &statement.finalizer {
1267 self.bind_hoisted_statements(&finalizer.data().statements, scope);
1268 }
1269 }
1270 Statement::With(statement) => self.bind_hoisted_statement(&statement.body, scope),
1271 Statement::Labeled(statement) => self.bind_hoisted_statement(&statement.body, scope),
1272 Statement::Namespace(namespace) => {
1273 self.bind_hoisted_statements(&namespace.body.data().statements, scope);
1274 }
1275 Statement::Declare(inner) => self.bind_hoisted_statement(inner, scope),
1276 Statement::Export(crate::syntax::ExportDeclaration::Named(
1277 crate::syntax::ExportNamedDeclaration::Declaration(inner),
1278 )) => self.bind_hoisted_statement(inner, scope),
1279 _ => {}
1280 }
1281 }
1282
1283 fn bind_statement(&mut self, statement: &'src crate::syntax::Stmt, scope: ScopeId) {
1284 let declaration = statement.id();
1285 match statement.data() {
1286 Statement::Variable(variable) => self.bind_variable(variable, scope, declaration),
1287 Statement::Function(function) => {
1288 if let Some(name) = &function.function.name {
1289 self.declare(
1290 self.identifier_text(name),
1291 SymbolKind::Function,
1292 scope,
1293 declaration,
1294 name.range(),
1295 );
1296 }
1297 }
1298 Statement::Class(class) => {
1299 if let Some(name) = &class.name {
1300 self.declare(
1301 self.identifier_text(name),
1302 SymbolKind::Class,
1303 scope,
1304 declaration,
1305 name.range(),
1306 );
1307 }
1308 }
1309 Statement::Interface(interface) => self.bind_interface(interface, scope, declaration),
1310 Statement::TypeAlias(alias) => self.bind_type_alias(alias, scope, declaration),
1311 Statement::Enum(declaration_node) => {
1312 self.declare(
1313 self.identifier_text(&declaration_node.name),
1314 SymbolKind::Enum,
1315 scope,
1316 declaration,
1317 declaration_node.name.range(),
1318 );
1319 }
1320 Statement::Namespace(namespace) => {
1321 self.declare(
1322 self.identifier_text(&namespace.name),
1323 SymbolKind::Namespace,
1324 scope,
1325 declaration,
1326 namespace.name.range(),
1327 );
1328 }
1329 Statement::Import(import) => self.bind_import(import, scope, declaration),
1330 Statement::ImportEquals(import) => {
1331 self.declare(
1332 self.identifier_text(&import.local),
1333 SymbolKind::Import,
1334 scope,
1335 declaration,
1336 import.local.range(),
1337 );
1338 }
1339 Statement::Declare(inner) => self.bind_statement(inner, scope),
1340 Statement::Export(crate::syntax::ExportDeclaration::Named(
1341 crate::syntax::ExportNamedDeclaration::Declaration(inner),
1342 )) => {
1343 self.bind_statement(inner, scope);
1344 }
1345 _ => {}
1346 }
1347 }
1348
1349 fn bind_variable(
1350 &mut self,
1351 variable: &'src VariableDeclaration,
1352 scope: ScopeId,
1353 declaration: NodeId,
1354 ) {
1355 for declarator in &variable.declarations {
1356 self.bind_pattern(
1357 &declarator.data().binding,
1358 variable.kind,
1359 scope,
1360 declaration,
1361 );
1362 }
1363 }
1364
1365 fn bind_pattern(
1366 &mut self,
1367 pattern: &'src crate::syntax::Pattern,
1368 kind: VariableKind,
1369 scope: ScopeId,
1370 declaration: NodeId,
1371 ) {
1372 match pattern.data() {
1373 BindingPattern::Identifier(name) => {
1374 self.declare(
1375 self.identifier_text(name),
1376 SymbolKind::Variable(kind),
1377 scope,
1378 declaration,
1379 name.range(),
1380 );
1381 }
1382 BindingPattern::Object(object) => {
1383 for property in &object.properties {
1384 self.bind_pattern(&property.binding, kind, scope, declaration);
1385 }
1386 }
1387 BindingPattern::Array(array) => {
1388 for element in &array.elements {
1389 if let crate::syntax::ArrayBindingElement::Binding(inner) = element {
1390 self.bind_pattern(inner, kind, scope, declaration);
1391 }
1392 }
1393 }
1394 BindingPattern::Rest(rest) => {
1395 self.bind_pattern(&rest.argument, kind, scope, declaration);
1396 }
1397 BindingPattern::Assignment(assignment) => {
1398 self.bind_pattern(&assignment.left, kind, scope, declaration);
1399 }
1400 BindingPattern::Missing(_) => {}
1401 }
1402 }
1403
1404 fn bind_interface(
1405 &mut self,
1406 interface: &'src InterfaceDeclaration,
1407 scope: ScopeId,
1408 declaration: NodeId,
1409 ) {
1410 let id = self.declare(
1411 self.identifier_text(&interface.name),
1412 SymbolKind::Interface,
1413 scope,
1414 declaration,
1415 interface.name.range(),
1416 );
1417 let type_scope = self.new_scope(ScopeKind::Block, Some(scope));
1418 self.bind_type_parameter_names(interface.type_parameters.as_ref(), type_scope);
1419 self.type_defs.entry(id).or_insert(TypeDef::Interface {
1422 scope: type_scope,
1423 type_parameters: interface.type_parameters.as_ref(),
1424 extends: &interface.extends,
1425 members: &interface.members,
1426 });
1427 }
1428
1429 fn bind_type_alias(
1430 &mut self,
1431 alias: &'src TypeAliasDeclaration,
1432 scope: ScopeId,
1433 declaration: NodeId,
1434 ) {
1435 let id = self.declare(
1436 self.identifier_text(&alias.name),
1437 SymbolKind::TypeAlias,
1438 scope,
1439 declaration,
1440 alias.name.range(),
1441 );
1442 let type_scope = self.new_scope(ScopeKind::Block, Some(scope));
1443 self.bind_type_parameter_names(alias.type_parameters.as_ref(), type_scope);
1444 self.type_defs.insert(
1445 id,
1446 TypeDef::Alias {
1447 scope: type_scope,
1448 type_parameters: alias.type_parameters.as_ref(),
1449 node: &alias.type_node,
1450 },
1451 );
1452 }
1453
1454 fn bind_import(
1455 &mut self,
1456 import: &'src crate::syntax::ImportDeclaration,
1457 scope: ScopeId,
1458 declaration: NodeId,
1459 ) {
1460 let Some(clause) = &import.clause else {
1461 return;
1462 };
1463 if let Some(default) = &clause.default {
1464 self.declare(
1465 self.identifier_text(default),
1466 SymbolKind::Import,
1467 scope,
1468 declaration,
1469 default.range(),
1470 );
1471 }
1472 match &clause.binding {
1473 Some(ImportBinding::Namespace(name)) => {
1474 self.declare(
1475 self.identifier_text(name),
1476 SymbolKind::Import,
1477 scope,
1478 declaration,
1479 name.range(),
1480 );
1481 }
1482 Some(ImportBinding::Named(specifiers)) => {
1483 for specifier in specifiers {
1484 let local = &specifier.data().local;
1485 self.declare(
1486 self.identifier_text(local),
1487 SymbolKind::Import,
1488 scope,
1489 declaration,
1490 local.range(),
1491 );
1492 }
1493 }
1494 None => {}
1495 }
1496 }
1497
1498 fn resolve_statements(&mut self, statements: &'src [crate::syntax::Stmt], scope: ScopeId) {
1501 for statement in statements {
1502 self.resolve_statement(statement, scope);
1503 }
1504 }
1505
1506 fn resolve_statement(&mut self, statement: &'src crate::syntax::Stmt, scope: ScopeId) {
1507 match statement.data() {
1508 Statement::Variable(variable) => self.resolve_variable(variable, scope),
1509 Statement::Function(function) => self.resolve_function(&function.function, scope),
1510 Statement::Class(class) => self.resolve_class(class, scope),
1511 Statement::Interface(interface) => {
1512 if let Some(id) = self.scopes[scope.0 as usize]
1513 .types
1514 .get(self.identifier_text(&interface.name))
1515 .copied()
1516 {
1517 let _ = self.resolve_type_symbol(id);
1518 }
1519 }
1520 Statement::TypeAlias(alias) => {
1521 if let Some(id) = self.scopes[scope.0 as usize]
1522 .types
1523 .get(self.identifier_text(&alias.name))
1524 .copied()
1525 {
1526 let _ = self.resolve_type_symbol(id);
1527 }
1528 }
1529 Statement::Block(block) => {
1530 let child = self.new_scope(ScopeKind::Block, Some(scope));
1531 self.bind_statements(&block.data().statements, child);
1532 self.resolve_statements(&block.data().statements, child);
1533 }
1534 Statement::Expression(statement) => self.resolve_expr(&statement.expression, scope),
1535 Statement::If(statement) => {
1536 self.resolve_expr(&statement.test, scope);
1537 self.resolve_statement(&statement.consequent, scope);
1538 if let Some(alternate) = &statement.alternate {
1539 self.resolve_statement(alternate, scope);
1540 }
1541 }
1542 Statement::Switch(statement) => {
1543 self.resolve_expr(&statement.discriminant, scope);
1544 let child = self.new_scope(ScopeKind::Block, Some(scope));
1545 for case in &statement.cases {
1546 if let Some(test) = &case.data().test {
1547 self.resolve_expr(test, child);
1548 }
1549 self.bind_statements(&case.data().consequent, child);
1550 }
1551 for case in &statement.cases {
1552 self.resolve_statements(&case.data().consequent, child);
1553 }
1554 }
1555 Statement::For(for_statement) => {
1556 let child = self.new_scope(ScopeKind::For, Some(scope));
1557 if let Some(initializer) = &for_statement.initializer {
1558 self.resolve_for_initializer(initializer, child);
1559 }
1560 if let Some(test) = &for_statement.test {
1561 self.resolve_expr(test, child);
1562 }
1563 if let Some(update) = &for_statement.update {
1564 self.resolve_expr(update, child);
1565 }
1566 self.resolve_statement(&for_statement.body, child);
1567 }
1568 Statement::ForIn(for_statement) => {
1569 let child = self.new_scope(ScopeKind::For, Some(scope));
1570 self.resolve_for_binding(&for_statement.binding, child);
1571 self.resolve_expr(&for_statement.object, child);
1572 self.resolve_statement(&for_statement.body, child);
1573 }
1574 Statement::ForOf(for_statement) => {
1575 let child = self.new_scope(ScopeKind::For, Some(scope));
1576 self.resolve_for_binding(&for_statement.binding, child);
1577 self.resolve_expr(&for_statement.iterable, child);
1578 self.resolve_statement(&for_statement.body, child);
1579 }
1580 Statement::While(statement) => {
1581 self.resolve_expr(&statement.test, scope);
1582 self.resolve_statement(&statement.body, scope);
1583 }
1584 Statement::DoWhile(statement) => {
1585 self.resolve_statement(&statement.body, scope);
1586 self.resolve_expr(&statement.test, scope);
1587 }
1588 Statement::Try(statement) => {
1589 let block = &statement.block;
1590 let try_scope = self.new_scope(ScopeKind::Block, Some(scope));
1591 self.bind_statements(&block.data().statements, try_scope);
1592 self.resolve_statements(&block.data().statements, try_scope);
1593 if let Some(handler) = &statement.handler {
1594 let catch_scope = self.new_scope(ScopeKind::Catch, Some(scope));
1595 if let Some(binding) = &handler.data().binding {
1596 self.bind_pattern(binding, VariableKind::Let, catch_scope, handler.id());
1597 }
1598 let body = &handler.data().body;
1599 self.bind_statements(&body.data().statements, catch_scope);
1600 self.resolve_statements(&body.data().statements, catch_scope);
1601 }
1602 if let Some(finalizer) = &statement.finalizer {
1603 let finally_scope = self.new_scope(ScopeKind::Block, Some(scope));
1604 self.bind_statements(&finalizer.data().statements, finally_scope);
1605 self.resolve_statements(&finalizer.data().statements, finally_scope);
1606 }
1607 }
1608 Statement::With(statement) => {
1609 self.resolve_expr(&statement.object, scope);
1610 self.resolve_statement(&statement.body, scope);
1611 }
1612 Statement::Labeled(statement) => self.resolve_statement(&statement.body, scope),
1613 Statement::Return(statement) => {
1614 if let Some(argument) = &statement.argument {
1615 self.resolve_expr(argument, scope);
1616 }
1617 }
1618 Statement::Throw(statement) => self.resolve_expr(&statement.argument, scope),
1619 Statement::Enum(declaration) => {
1620 for member in &declaration.members {
1621 if let Some(initializer) = &member.data().initializer {
1622 self.resolve_expr(initializer, scope);
1623 }
1624 }
1625 }
1626 Statement::Namespace(namespace) => {
1627 let child = self.new_scope(ScopeKind::Block, Some(scope));
1628 let body = &namespace.body;
1629 self.bind_statements(&body.data().statements, child);
1630 self.resolve_statements(&body.data().statements, child);
1631 }
1632 Statement::Declare(inner) => self.resolve_statement(inner, scope),
1633 Statement::Export(export) => self.resolve_export(export, scope),
1634 _ => {}
1635 }
1636 }
1637
1638 fn resolve_export(&mut self, export: &'src crate::syntax::ExportDeclaration, scope: ScopeId) {
1639 match export {
1640 crate::syntax::ExportDeclaration::Named(
1641 crate::syntax::ExportNamedDeclaration::Declaration(inner),
1642 ) => self.resolve_statement(inner, scope),
1643 crate::syntax::ExportDeclaration::Default(default) => match &default.value {
1644 crate::syntax::ExportDefaultValue::Function(function) => {
1645 self.resolve_function(function, scope);
1646 }
1647 crate::syntax::ExportDefaultValue::Class(class) => self.resolve_class(class, scope),
1648 crate::syntax::ExportDefaultValue::Expression(expression) => {
1649 self.resolve_expr(expression, scope);
1650 }
1651 crate::syntax::ExportDefaultValue::Missing(_) => {}
1652 },
1653 crate::syntax::ExportDeclaration::Assignment(expression) => {
1654 self.resolve_expr(expression, scope);
1655 }
1656 _ => {}
1657 }
1658 }
1659
1660 fn resolve_for_initializer(&mut self, initializer: &'src ForInitializer, scope: ScopeId) {
1661 match initializer {
1662 ForInitializer::Variable(variable) => {
1663 self.bind_variable(variable, scope, NodeId::default());
1664 self.resolve_variable(variable, scope);
1665 }
1666 ForInitializer::Expression(expression) => self.resolve_expr(expression, scope),
1667 }
1668 }
1669
1670 fn resolve_for_binding(&mut self, binding: &'src ForBinding, scope: ScopeId) {
1671 match binding {
1672 ForBinding::Variable(variable) => {
1673 self.bind_variable(variable, scope, NodeId::default());
1674 self.resolve_variable(variable, scope);
1675 }
1676 ForBinding::Target(target) => self.resolve_assignment_target(target, scope),
1677 }
1678 }
1679
1680 fn resolve_variable(&mut self, variable: &'src VariableDeclaration, scope: ScopeId) {
1681 for declarator in &variable.declarations {
1682 let declarator = declarator.data();
1683 if let Some(initializer) = &declarator.initializer {
1684 self.resolve_expr(initializer, scope);
1685 }
1686 let annotation = declarator
1687 .type_annotation
1688 .as_ref()
1689 .map(|annotation| self.resolve_type(&annotation.data().type_node, scope));
1690 let initializer_type = declarator
1691 .initializer
1692 .as_ref()
1693 .map(|initializer| self.type_of_expr(initializer, scope));
1694
1695 if let BindingPattern::Identifier(name) = declarator.binding.data() {
1697 let declared = annotation
1698 .or(initializer_type)
1699 .unwrap_or_else(|| self.types.any());
1700 if let Some(symbol) = self.lookup_value(scope, self.identifier_text(name)) {
1701 self.symbol_types[symbol.get() as usize] = declared;
1702 }
1703 if let (Some(target), Some(source)) = (annotation, initializer_type)
1704 && !self.types.assignable(source, target)
1705 {
1706 let range = declarator
1707 .initializer
1708 .as_ref()
1709 .map_or_else(|| name.range(), |initializer| initializer.range());
1710 self.emit(TYPE_NOT_ASSIGNABLE, range, NOT_ASSIGNABLE_MESSAGE);
1711 }
1712 }
1713 }
1714 }
1715
1716 fn resolve_function(&mut self, function: &'src FunctionLike, parent: ScopeId) {
1717 let scope = self.new_scope(ScopeKind::Function, Some(parent));
1718 for name in ["arguments", "this"] {
1719 let explicitly_bound = function.parameters.iter().any(|parameter| {
1720 matches!(
1721 parameter.data().binding.data(),
1722 BindingPattern::Identifier(identifier)
1723 if self.identifier_text(identifier) == name
1724 )
1725 });
1726 if !explicitly_bound {
1727 self.declare(
1728 name,
1729 SymbolKind::Parameter,
1730 scope,
1731 NodeId::default(),
1732 NodeId::default_range(),
1733 );
1734 }
1735 }
1736 if let Some(name) = &function.name {
1737 self.declare(
1738 self.identifier_text(name),
1739 SymbolKind::Function,
1740 scope,
1741 name.id(),
1742 name.range(),
1743 );
1744 }
1745 self.bind_type_parameters(function.type_parameters.as_ref(), scope);
1746 for parameter in &function.parameters {
1747 self.resolve_parameter(parameter, scope);
1748 }
1749 if let Some(return_type) = &function.return_type {
1750 let _ = self.resolve_type(&return_type.data().type_node, scope);
1751 }
1752 match &function.body {
1753 Some(FunctionBody::Block(block)) => {
1754 self.bind_statements(&block.data().statements, scope);
1755 self.bind_hoisted_statements(&block.data().statements, scope);
1756 self.resolve_statements(&block.data().statements, scope);
1757 }
1758 Some(FunctionBody::Expression(expression)) => self.resolve_expr(expression, scope),
1759 _ => {}
1760 }
1761 }
1762
1763 fn bind_type_parameters(
1764 &mut self,
1765 list: Option<&'src crate::syntax::TypeParameterList>,
1766 scope: ScopeId,
1767 ) {
1768 self.bind_type_parameter_names(list, scope);
1769 self.resolve_type_parameter_bounds(list, scope);
1770 }
1771
1772 fn bind_type_parameter_names(
1773 &mut self,
1774 list: Option<&'src crate::syntax::TypeParameterList>,
1775 scope: ScopeId,
1776 ) {
1777 let Some(list) = list else {
1778 return;
1779 };
1780 for parameter in &list.parameters {
1781 let data = parameter.data();
1782 self.declare(
1783 self.identifier_text(&data.name),
1784 SymbolKind::TypeParameter,
1785 scope,
1786 parameter.id(),
1787 data.name.range(),
1788 );
1789 }
1790 }
1791
1792 fn resolve_type_parameter_bounds(
1793 &mut self,
1794 list: Option<&'src crate::syntax::TypeParameterList>,
1795 scope: ScopeId,
1796 ) {
1797 let Some(list) = list else {
1798 return;
1799 };
1800 for parameter in &list.parameters {
1801 let data = parameter.data();
1802 if let Some(constraint) = &data.constraint {
1803 let _ = self.resolve_type(constraint, scope);
1804 }
1805 if let Some(default) = &data.default {
1806 let _ = self.resolve_type(default, scope);
1807 }
1808 }
1809 }
1810
1811 fn resolve_parameter(&mut self, parameter: &'src crate::syntax::ParameterNode, scope: ScopeId) {
1812 let data = parameter.data();
1813 self.bind_pattern(&data.binding, VariableKind::Let, scope, parameter.id());
1814 if let (BindingPattern::Identifier(name), Some(annotation)) =
1815 (data.binding.data(), &data.type_annotation)
1816 {
1817 let resolved = self.resolve_type(&annotation.data().type_node, scope);
1818 if let Some(symbol) = self.scopes[scope.0 as usize]
1819 .values
1820 .get(self.identifier_text(name))
1821 .copied()
1822 {
1823 self.symbol_types[symbol.get() as usize] = resolved;
1824 }
1825 } else if let Some(annotation) = &data.type_annotation {
1826 let _ = self.resolve_type(&annotation.data().type_node, scope);
1827 }
1828 if let Some(initializer) = &data.initializer {
1829 self.resolve_expr(initializer, scope);
1830 }
1831 }
1832
1833 fn resolve_class(&mut self, class: &'src ClassDeclaration, parent: ScopeId) {
1834 let scope = self.new_scope(ScopeKind::Class, Some(parent));
1835 self.bind_type_parameters(class.type_parameters.as_ref(), scope);
1836 if let Some(heritage) = &class.extends {
1837 self.resolve_expr(&heritage.expression, parent);
1838 }
1839 for implemented in &class.implements {
1840 let _ = self.resolve_type(implemented, scope);
1841 }
1842 for member in &class.members {
1843 self.resolve_class_member(member.data(), scope);
1844 }
1845 }
1846
1847 fn resolve_class_member(&mut self, member: &'src ClassMember, scope: ScopeId) {
1848 match member {
1849 ClassMember::Method(method) => {
1850 self.resolve_property_name(&method.name, scope);
1851 self.resolve_function(&method.function, scope);
1852 }
1853 ClassMember::Constructor(constructor) => {
1854 let child = self.new_scope(ScopeKind::Function, Some(scope));
1855 for name in ["arguments", "this"] {
1856 let explicitly_bound = constructor.parameters.iter().any(|parameter| {
1857 matches!(
1858 parameter.data().binding.data(),
1859 BindingPattern::Identifier(identifier)
1860 if self.identifier_text(identifier) == name
1861 )
1862 });
1863 if !explicitly_bound {
1864 self.declare(
1865 name,
1866 SymbolKind::Parameter,
1867 child,
1868 NodeId::default(),
1869 NodeId::default_range(),
1870 );
1871 }
1872 }
1873 for parameter in &constructor.parameters {
1874 self.resolve_parameter(parameter, child);
1875 }
1876 self.bind_statements(&constructor.body.data().statements, child);
1877 self.resolve_statements(&constructor.body.data().statements, child);
1878 }
1879 ClassMember::Property(property) => {
1880 self.resolve_property_name(&property.name, scope);
1881 if let Some(annotation) = &property.type_annotation {
1882 let _ = self.resolve_type(&annotation.data().type_node, scope);
1883 }
1884 if let Some(initializer) = &property.initializer {
1885 self.resolve_expr(initializer, scope);
1886 }
1887 }
1888 ClassMember::AutoAccessor(accessor) => {
1889 self.resolve_property_name(&accessor.name, scope);
1890 if let Some(initializer) = &accessor.initializer {
1891 self.resolve_expr(initializer, scope);
1892 }
1893 }
1894 ClassMember::StaticBlock(block) => {
1895 let child = self.new_scope(ScopeKind::Block, Some(scope));
1896 self.bind_statements(&block.data().statements, child);
1897 self.resolve_statements(&block.data().statements, child);
1898 }
1899 _ => {}
1900 }
1901 }
1902
1903 fn resolve_property_name(&mut self, name: &'src PropertyName, scope: ScopeId) {
1904 if let PropertyName::Computed(expression) = name {
1905 self.resolve_expr(expression, scope);
1906 }
1907 }
1908
1909 fn resolve_expr(&mut self, expression: &'src Expr, scope: ScopeId) {
1910 match expression.data() {
1911 Expression::Identifier(identifier) => self.resolve_value(identifier, scope),
1912 Expression::Array(array) => {
1913 for element in &array.elements {
1914 match element {
1915 ArrayElement::Expression(inner) => self.resolve_expr(inner, scope),
1916 ArrayElement::Spread(spread) => self.resolve_expr(&spread.argument, scope),
1917 _ => {}
1918 }
1919 }
1920 }
1921 Expression::Object(object) => {
1922 for member in &object.members {
1923 self.resolve_object_member(member.data(), scope);
1924 }
1925 }
1926 Expression::Function(function) => self.resolve_function(&function.function, scope),
1927 Expression::Class(class) => self.resolve_class(&class.class, scope),
1928 Expression::Arrow(arrow) => {
1929 let child = self.new_scope(ScopeKind::Function, Some(scope));
1930 self.bind_type_parameters(arrow.type_parameters.as_ref(), child);
1931 for parameter in &arrow.parameters {
1932 self.resolve_parameter(parameter, child);
1933 }
1934 if let Some(return_type) = &arrow.return_type {
1935 let _ = self.resolve_type(&return_type.data().type_node, child);
1936 }
1937 match &arrow.body {
1938 FunctionBody::Block(block) => {
1939 self.bind_statements(&block.data().statements, child);
1940 self.resolve_statements(&block.data().statements, child);
1941 }
1942 FunctionBody::Expression(inner) => self.resolve_expr(inner, child),
1943 FunctionBody::Missing(_) => {}
1944 }
1945 }
1946 Expression::Call(call) => {
1947 self.resolve_expr(&call.callee, scope);
1948 self.resolve_type_arguments(call.type_arguments.as_ref(), scope);
1949 self.resolve_arguments(&call.arguments, scope);
1950 }
1951 Expression::New(new) => {
1952 self.resolve_expr(&new.callee, scope);
1953 self.resolve_type_arguments(new.type_arguments.as_ref(), scope);
1954 self.resolve_arguments(&new.arguments, scope);
1955 }
1956 Expression::Member(member) => {
1957 self.resolve_expr(&member.object, scope);
1958 if let MemberProperty::Computed(inner) = &member.property {
1959 self.resolve_expr(inner, scope);
1960 }
1961 }
1962 Expression::Await(await_expression) => {
1963 self.resolve_expr(&await_expression.argument, scope);
1964 }
1965 Expression::Yield(yield_expression) => {
1966 if let Some(argument) = &yield_expression.argument {
1967 self.resolve_expr(argument, scope);
1968 }
1969 }
1970 Expression::Unary(unary) => self.resolve_expr(&unary.argument, scope),
1971 Expression::Update(update) => self.resolve_assignment_target(&update.argument, scope),
1972 Expression::Binary(binary) => {
1973 self.resolve_expr(&binary.left, scope);
1974 self.resolve_expr(&binary.right, scope);
1975 }
1976 Expression::Logical(logical) => {
1977 self.resolve_expr(&logical.left, scope);
1978 self.resolve_expr(&logical.right, scope);
1979 }
1980 Expression::Conditional(conditional) => {
1981 self.resolve_expr(&conditional.test, scope);
1982 self.resolve_expr(&conditional.consequent, scope);
1983 self.resolve_expr(&conditional.alternate, scope);
1984 }
1985 Expression::Assignment(assignment) => {
1986 self.resolve_assignment_target(&assignment.left, scope);
1987 self.resolve_expr(&assignment.right, scope);
1988 }
1989 Expression::Sequence(sequence) => {
1990 for inner in &sequence.expressions {
1991 self.resolve_expr(inner, scope);
1992 }
1993 }
1994 Expression::Parenthesized(inner) => self.resolve_expr(inner, scope),
1995 Expression::As(cast) => {
1996 self.resolve_expr(&cast.expression, scope);
1997 if let Some(type_node) = &cast.type_node {
1998 let _ = self.resolve_type(type_node, scope);
1999 }
2000 }
2001 Expression::Satisfies(satisfies) => {
2002 self.resolve_expr(&satisfies.expression, scope);
2003 let _ = self.resolve_type(&satisfies.type_node, scope);
2004 }
2005 Expression::TypeAssertion(assertion) => {
2006 self.resolve_expr(&assertion.expression, scope);
2007 let _ = self.resolve_type(&assertion.type_node, scope);
2008 }
2009 Expression::NonNull(non_null) => self.resolve_expr(&non_null.expression, scope),
2010 Expression::TaggedTemplate(tagged) => {
2011 self.resolve_expr(&tagged.tag, scope);
2012 for inner in &tagged.template.expressions {
2013 self.resolve_expr(inner, scope);
2014 }
2015 }
2016 Expression::Template(template) => {
2017 for inner in &template.expressions {
2018 self.resolve_expr(inner, scope);
2019 }
2020 }
2021 Expression::Import(import) => {
2022 self.resolve_expr(&import.source, scope);
2023 if let Some(options) = &import.options {
2024 self.resolve_expr(options, scope);
2025 }
2026 }
2027 _ => {}
2028 }
2029 }
2030
2031 fn resolve_object_member(&mut self, member: &'src ObjectMember, scope: ScopeId) {
2032 match member {
2033 ObjectMember::Property(property) => {
2034 self.resolve_property_name(&property.name, scope);
2035 self.resolve_expr(&property.value, scope);
2036 }
2037 ObjectMember::Method(method) => {
2038 self.resolve_property_name(&method.name, scope);
2039 self.resolve_function(&method.function, scope);
2040 }
2041 ObjectMember::Spread(spread) => self.resolve_expr(&spread.argument, scope),
2042 ObjectMember::Missing(_) => {}
2043 }
2044 }
2045
2046 fn resolve_arguments(&mut self, arguments: &'src [CallArgument], scope: ScopeId) {
2047 for argument in arguments {
2048 match argument {
2049 CallArgument::Expression(inner) => self.resolve_expr(inner, scope),
2050 CallArgument::Spread(spread) => self.resolve_expr(&spread.argument, scope),
2051 CallArgument::Missing(_) => {}
2052 }
2053 }
2054 }
2055
2056 fn resolve_type_arguments(
2057 &mut self,
2058 arguments: Option<&'src crate::syntax::TypeArgumentList>,
2059 scope: ScopeId,
2060 ) {
2061 if let Some(list) = arguments {
2062 for argument in &list.arguments {
2063 let _ = self.resolve_type(argument, scope);
2064 }
2065 }
2066 }
2067
2068 fn resolve_assignment_target(
2069 &mut self,
2070 target: &'src crate::syntax::AssignmentTargetNode,
2071 scope: ScopeId,
2072 ) {
2073 match target.data() {
2074 AssignmentTarget::Identifier(identifier) => self.resolve_value(identifier, scope),
2075 AssignmentTarget::Member(member) => {
2076 self.resolve_expr(&member.object, scope);
2077 if let MemberProperty::Computed(inner) = &member.property {
2078 self.resolve_expr(inner, scope);
2079 }
2080 }
2081 AssignmentTarget::Object(object) => {
2082 for property in &object.properties {
2083 self.resolve_property_name(&property.name, scope);
2084 self.resolve_assignment_target(&property.target, scope);
2085 if let Some(initializer) = &property.initializer {
2086 self.resolve_expr(initializer, scope);
2087 }
2088 }
2089 }
2090 AssignmentTarget::Array(array) => {
2091 for element in &array.elements {
2092 if let crate::syntax::AssignmentArrayElement::Target(inner) = element {
2093 self.resolve_assignment_target(inner, scope);
2094 }
2095 }
2096 }
2097 AssignmentTarget::Missing(_) => {}
2098 }
2099 }
2100
2101 fn resolve_value(&mut self, identifier: &IdentifierNode, scope: ScopeId) {
2102 let name = self.identifier_text(identifier);
2103 if name.is_empty() {
2104 return;
2105 }
2106 if let Some(symbol) = self.lookup_value(scope, name) {
2107 self.references.insert(identifier.id(), symbol);
2108 } else {
2109 self.emit(
2110 CANNOT_FIND_NAME,
2111 identifier.range(),
2112 CANNOT_FIND_NAME_MESSAGE,
2113 );
2114 }
2115 }
2116
2117 fn lookup_value(&self, scope: ScopeId, name: &str) -> Option<SymbolId> {
2118 let mut current = Some(scope);
2119 while let Some(id) = current {
2120 let scope = &self.scopes[id.0 as usize];
2121 if let Some(symbol) = scope.values.get(name) {
2122 return Some(*symbol);
2123 }
2124 current = scope.parent;
2125 }
2126 None
2127 }
2128
2129 fn lookup_type(&self, scope: ScopeId, name: &str) -> Option<SymbolId> {
2130 let mut current = Some(scope);
2131 while let Some(id) = current {
2132 let scope = &self.scopes[id.0 as usize];
2133 if let Some(symbol) = scope.types.get(name) {
2134 return Some(*symbol);
2135 }
2136 current = scope.parent;
2137 }
2138 None
2139 }
2140
2141 fn resolve_type(&mut self, node: &'src Ty, scope: ScopeId) -> TypeId {
2144 match node.data() {
2145 TypeNode::Keyword(keyword) => self.keyword_type(*keyword),
2146 TypeNode::Literal(literal) => self.literal_type(literal),
2147 TypeNode::Reference(reference) => {
2148 self.resolve_type_reference(reference, scope, node.range())
2149 }
2150 TypeNode::Union(members) => {
2151 let resolved: Vec<TypeId> = members
2152 .iter()
2153 .map(|member| self.resolve_type(member, scope))
2154 .collect();
2155 self.types.union(&resolved)
2156 }
2157 TypeNode::Array(element) => {
2158 let resolved = self.resolve_type(element, scope);
2159 self.types.array(resolved)
2160 }
2161 TypeNode::Object(object) => self.resolve_object_type(&object.members, scope),
2162 TypeNode::Function(function) => self.resolve_function_type(function, scope),
2163 TypeNode::Parenthesized(inner) => self.resolve_type(inner, scope),
2164 TypeNode::Tuple(tuple) => {
2165 let element_types: Vec<TypeId> = tuple
2166 .elements
2167 .iter()
2168 .map(|element| self.resolve_type(&element.type_node, scope))
2169 .collect();
2170 let element = self.types.union(&element_types);
2171 self.types.array(element)
2172 }
2173 _ => self.types.error_type(),
2174 }
2175 }
2176
2177 fn keyword_type(&self, keyword: KeywordType) -> TypeId {
2178 match keyword {
2179 KeywordType::Any => self.types.any(),
2180 KeywordType::Unknown => self.types.unknown(),
2181 KeywordType::Never => self.types.never(),
2182 KeywordType::Void => self.types.void(),
2183 KeywordType::Undefined => self.types.undefined_type(),
2184 KeywordType::Null => self.types.null_type(),
2185 KeywordType::Boolean => self.types.boolean(),
2186 KeywordType::Number => self.types.number(),
2187 KeywordType::BigInt => self.types.bigint(),
2188 KeywordType::String => self.types.string(),
2189 KeywordType::Symbol => self.types.symbol_type(),
2190 KeywordType::Object => self.types.object(),
2191 KeywordType::Intrinsic => self.types.error_type(),
2192 }
2193 }
2194
2195 fn literal_type(&mut self, literal: &TypeLiteral) -> TypeId {
2196 match literal {
2197 TypeLiteral::String(token) => {
2198 let text = self.text(token.data().token());
2199 self.types.string_literal(text)
2200 }
2201 TypeLiteral::Number(token) => {
2202 let text = self.text(token.data().token());
2203 self.types.number_literal(text)
2204 }
2205 TypeLiteral::BigInt(token) => {
2206 let text = self.text(token.data().token());
2207 self.types.bigint_literal(text)
2208 }
2209 TypeLiteral::Boolean(token) => {
2210 let value = self.text(token.data().token()) == "true";
2211 self.types.boolean_literal(value)
2212 }
2213 TypeLiteral::Null(_) => self.types.null_type(),
2214 TypeLiteral::Unary { .. } => self.types.number(),
2215 }
2216 }
2217
2218 fn resolve_type_reference(
2219 &mut self,
2220 reference: &'src TypeReference,
2221 scope: ScopeId,
2222 range: TextRange,
2223 ) -> TypeId {
2224 if let Some(argument_list) = &reference.type_arguments {
2225 for argument in &argument_list.arguments {
2226 let _ = self.resolve_type(argument, scope);
2227 }
2228 }
2229 let EntityName::Identifier(identifier) = &reference.name else {
2230 return self.types.error_type();
2232 };
2233 let name = self.identifier_text(identifier);
2234 match self.lookup_type(scope, name) {
2235 Some(symbol) => match self.symbols[symbol.get() as usize].kind {
2236 SymbolKind::Interface | SymbolKind::TypeAlias => self.resolve_type_symbol(symbol),
2237 SymbolKind::Class | SymbolKind::Enum | SymbolKind::TypeParameter => {
2238 self.types.named(symbol)
2239 }
2240 _ => self.types.error_type(),
2241 },
2242 None => {
2243 self.emit(CANNOT_FIND_TYPE, range, CANNOT_FIND_TYPE_MESSAGE);
2244 self.types.error_type()
2245 }
2246 }
2247 }
2248
2249 fn resolve_type_symbol(&mut self, symbol: SymbolId) -> TypeId {
2250 match self.type_state[symbol.get() as usize] {
2251 TypeState::Done(id) => return id,
2252 TypeState::InProgress => return self.types.error_type(),
2253 TypeState::Unresolved => {}
2254 }
2255 let Some(definition) = self.type_defs.get(&symbol).copied() else {
2256 let id = self.types.error_type();
2257 self.type_state[symbol.get() as usize] = TypeState::Done(id);
2258 return id;
2259 };
2260 self.type_state[symbol.get() as usize] = TypeState::InProgress;
2261 let resolved = match definition {
2262 TypeDef::Alias {
2263 scope,
2264 type_parameters,
2265 node,
2266 } => {
2267 self.resolve_type_parameter_bounds(type_parameters, scope);
2268 self.resolve_type(node, scope)
2269 }
2270 TypeDef::Interface {
2271 scope,
2272 type_parameters,
2273 extends,
2274 members,
2275 } => {
2276 self.resolve_type_parameter_bounds(type_parameters, scope);
2277 self.resolve_interface_type(scope, extends, members)
2278 }
2279 };
2280 self.type_state[symbol.get() as usize] = TypeState::Done(resolved);
2281 resolved
2282 }
2283
2284 fn resolve_interface_type(
2285 &mut self,
2286 scope: ScopeId,
2287 extends: &'src [TypeReference],
2288 members: &'src [crate::syntax::TypeMemberNode],
2289 ) -> TypeId {
2290 let mut properties = self.type_member_properties(members, scope);
2291 for base in extends {
2292 let base_type = self.resolve_type_reference(base, scope, NodeId::default_range());
2293 if let Type::ObjectType(base_props) = self.types.get(base_type) {
2294 for base_prop in base_props.clone() {
2295 if !properties.iter().any(|prop| prop.name == base_prop.name) {
2296 properties.push(base_prop);
2297 }
2298 }
2299 }
2300 }
2301 self.types.object_type(properties)
2302 }
2303
2304 fn resolve_object_type(
2305 &mut self,
2306 members: &'src [crate::syntax::TypeMemberNode],
2307 scope: ScopeId,
2308 ) -> TypeId {
2309 let properties = self.type_member_properties(members, scope);
2310 self.types.object_type(properties)
2311 }
2312
2313 fn type_member_properties(
2314 &mut self,
2315 members: &'src [crate::syntax::TypeMemberNode],
2316 scope: ScopeId,
2317 ) -> Vec<PropertyType> {
2318 let mut properties = Vec::new();
2319 for member in members {
2320 match member.data() {
2321 TypeMember::Property(property) => {
2322 if let Some(name) = self.property_key(&property.name) {
2323 let type_id = match &property.type_annotation {
2324 Some(annotation) => {
2325 self.resolve_type(&annotation.data().type_node, scope)
2326 }
2327 None => self.types.any(),
2328 };
2329 properties.push(PropertyType::new(name, property.optional, type_id));
2330 }
2331 }
2332 TypeMember::Method(method) => {
2333 if let Some(name) = self.property_key(&method.name) {
2334 let type_id = self.resolve_function_type(&method.function, scope);
2335 properties.push(PropertyType::new(name, method.optional, type_id));
2336 }
2337 }
2338 _ => {}
2339 }
2340 }
2341 properties
2342 }
2343
2344 fn resolve_function_type(&mut self, function: &'src FunctionType, scope: ScopeId) -> TypeId {
2345 let child = self.new_scope(ScopeKind::Function, Some(scope));
2346 self.bind_type_parameters(function.type_parameters.as_ref(), child);
2347 let parameters: Vec<TypeId> = function
2348 .parameters
2349 .iter()
2350 .map(|parameter| self.resolve_type(¶meter.type_annotation.data().type_node, child))
2351 .collect();
2352 let return_type = self.resolve_type(&function.return_type, child);
2353 self.types.function(parameters, return_type)
2354 }
2355
2356 fn property_key(&self, name: &PropertyName) -> Option<String> {
2357 match name {
2358 PropertyName::Identifier(identifier) => {
2359 Some(self.identifier_text(identifier).to_owned())
2360 }
2361 PropertyName::String(string) => {
2362 let text = self.text(string.data().token());
2363 Some(
2364 text.trim_matches(|c| c == '"' || c == '\'' || c == '`')
2365 .to_owned(),
2366 )
2367 }
2368 PropertyName::Number(number) => Some(self.text(number.data().token()).to_owned()),
2369 _ => None,
2370 }
2371 }
2372
2373 fn type_of_expr(&mut self, expression: &'src Expr, scope: ScopeId) -> TypeId {
2376 match expression.data() {
2377 Expression::Identifier(identifier) => {
2378 self.references.get(&identifier.id()).map_or_else(
2379 || self.types.any(),
2380 |symbol| self.symbol_types[symbol.get() as usize],
2381 )
2382 }
2383 Expression::Literal(literal) => self.type_of_literal(literal),
2384 Expression::Parenthesized(inner) => self.type_of_expr(inner, scope),
2385 Expression::NonNull(non_null) => self.type_of_expr(&non_null.expression, scope),
2386 Expression::As(cast) => match &cast.type_node {
2387 Some(type_node) => self.resolve_type(type_node, scope),
2388 None => self.type_of_expr(&cast.expression, scope),
2389 },
2390 Expression::TypeAssertion(assertion) => self.resolve_type(&assertion.type_node, scope),
2391 Expression::Array(array) => {
2392 let mut element_types = Vec::new();
2393 for element in &array.elements {
2394 if let ArrayElement::Expression(inner) = element {
2395 let inner_type = self.type_of_expr(inner, scope);
2396 element_types.push(inner_type);
2397 }
2398 }
2399 let element = if element_types.is_empty() {
2400 self.types.never()
2401 } else {
2402 self.types.union(&element_types)
2403 };
2404 self.types.array(element)
2405 }
2406 Expression::Object(object) => {
2407 let mut properties = Vec::new();
2408 for member in &object.members {
2409 match member.data() {
2410 ObjectMember::Property(property) => {
2411 if let Some(name) = self.property_key(&property.name) {
2412 let value_type = self.type_of_expr(&property.value, scope);
2413 properties.push(PropertyType::new(name, false, value_type));
2414 }
2415 }
2416 ObjectMember::Method(method) => {
2417 if let Some(name) = self.property_key(&method.name) {
2418 let method_type =
2419 self.type_of_function_like(&method.function, scope);
2420 properties.push(PropertyType::new(name, false, method_type));
2421 }
2422 }
2423 _ => {}
2424 }
2425 }
2426 self.types.object_type(properties)
2427 }
2428 _ => self.types.any(),
2429 }
2430 }
2431
2432 fn type_of_function_like(&mut self, function: &'src FunctionLike, parent: ScopeId) -> TypeId {
2433 let scope = self.new_scope(ScopeKind::Function, Some(parent));
2434 self.bind_type_parameters(function.type_parameters.as_ref(), scope);
2435 let mut parameters = Vec::with_capacity(function.parameters.len());
2436 for parameter in &function.parameters {
2437 let parameter_type = match ¶meter.data().type_annotation {
2438 Some(annotation) => self.resolve_type(&annotation.data().type_node, scope),
2439 None => self.types.any(),
2440 };
2441 parameters.push(parameter_type);
2442 }
2443 let return_type = match &function.return_type {
2444 Some(annotation) => self.resolve_type(&annotation.data().type_node, scope),
2445 None => self.types.any(),
2446 };
2447 self.types.function(parameters, return_type)
2448 }
2449
2450 fn type_of_literal(&mut self, literal: &Literal) -> TypeId {
2451 match literal {
2452 Literal::String(token) => {
2453 let text = self.text(token.data().token());
2454 self.types.string_literal(text)
2455 }
2456 Literal::Number(token) => {
2457 let text = self.text(token.data().token());
2458 self.types.number_literal(text)
2459 }
2460 Literal::BigInt(token) => {
2461 let text = self.text(token.data().token());
2462 self.types.bigint_literal(text)
2463 }
2464 Literal::Boolean(token) => {
2465 let value = self.text(token.data().token()) == "true";
2466 self.types.boolean_literal(value)
2467 }
2468 Literal::Null(_) => self.types.null_type(),
2469 Literal::Regex(_) => self.types.object(),
2470 }
2471 }
2472}
2473
2474trait DefaultRange {
2476 fn default_range() -> TextRange;
2477}
2478
2479impl DefaultRange for NodeId {
2480 fn default_range() -> TextRange {
2481 use crate::source::Utf16Pos;
2482 TextRange::new(Utf16Pos::ZERO, Utf16Pos::ZERO).expect("zero range is ordered")
2483 }
2484}
2485
2486#[cfg(test)]
2487mod tests {
2488 use super::{
2489 CANNOT_FIND_NAME, CANNOT_FIND_TYPE, DUPLICATE_DECLARATION, PropertyType, ScopeKind,
2490 SymbolKind, TYPE_NOT_ASSIGNABLE, TypeTable, check,
2491 };
2492 use crate::diagnostic::{DiagnosticSeverity, Recovered};
2493 use crate::source::{ScriptKind, SourceId, SourceText, TextRange, Utf16Pos};
2494 use crate::syntax::{
2495 ArrowFunction, BindingPattern, Block, EntityName, Expr, Expression, ExpressionStatement,
2496 FunctionBody, Identifier, IdentifierNode, KeywordType, Literal, MissingNode, Node, NodeId,
2497 NodeKind, NumericLiteral, Parameter, ParameterNode, SourceFile, Statement, Stmt,
2498 StringLiteral, Token, TokenKind, TypeAnnotation, TypeNode,
2499 };
2500 use crate::{parser, scanner};
2501 use std::sync::Arc;
2502
2503 #[test]
2506 fn top_and_bottom_types_bound_the_lattice() {
2507 let table = TypeTable::new();
2508 assert!(table.assignable(table.never(), table.number()));
2510 assert!(!table.assignable(table.number(), table.never()));
2511 assert!(table.assignable(table.number(), table.unknown()));
2513 assert!(!table.assignable(table.unknown(), table.number()));
2514 assert!(table.assignable(table.any(), table.number()));
2516 assert!(table.assignable(table.number(), table.any()));
2517 }
2518
2519 #[test]
2520 fn literals_widen_to_their_base_primitive_only() {
2521 let mut table = TypeTable::new();
2522 let one = table.number_literal("1");
2523 assert!(table.assignable(one, table.number()));
2524 assert!(!table.assignable(table.number(), one));
2525 assert!(!table.assignable(one, table.string()));
2526 }
2527
2528 #[test]
2529 fn union_source_requires_all_members_target_requires_one() {
2530 let mut table = TypeTable::new();
2531 let number_or_string = table.union(&[table.number(), table.string()]);
2532 assert!(table.assignable(table.number(), number_or_string));
2533 assert!(!table.assignable(table.boolean(), number_or_string));
2534 assert!(table.assignable(number_or_string, table.unknown()));
2535 assert!(!table.assignable(number_or_string, table.number()));
2536 }
2537
2538 #[test]
2539 fn union_normalizes_absorption_and_duplicates() {
2540 let mut table = TypeTable::new();
2541 assert_eq!(
2542 table.union(&[table.number(), table.number()]),
2543 table.number()
2544 );
2545 assert_eq!(
2546 table.union(&[table.number(), table.never()]),
2547 table.number()
2548 );
2549 assert_eq!(table.union(&[table.number(), table.any()]), table.any());
2550 }
2551
2552 #[test]
2553 fn arrays_are_covariant_in_their_element() {
2554 let mut table = TypeTable::new();
2555 let number_literal = table.number_literal("1");
2556 let literal_array = table.array(number_literal);
2557 let number_array = table.array(table.number());
2558 assert!(table.assignable(literal_array, number_array));
2559 assert!(!table.assignable(number_array, literal_array));
2560 }
2561
2562 #[test]
2563 fn objects_are_structural_with_optional_and_excess_rules() {
2564 let mut table = TypeTable::new();
2565 let required = table.object_type(vec![PropertyType::new("x", false, table.number())]);
2566 let with_excess = table.object_type(vec![
2567 PropertyType::new("x", false, table.number()),
2568 PropertyType::new("y", false, table.string()),
2569 ]);
2570 let missing = table.object_type(vec![PropertyType::new("y", false, table.string())]);
2571 let optional = table.object_type(vec![PropertyType::new("x", true, table.number())]);
2572 let empty = table.object_type(vec![]);
2573
2574 assert!(table.assignable(with_excess, required));
2576 assert!(!table.assignable(missing, required));
2578 assert!(table.assignable(empty, optional));
2580 }
2581
2582 #[test]
2583 fn functions_are_contravariant_in_params_covariant_in_return() {
2584 let mut table = TypeTable::new();
2585 let animal = table.named(super::SymbolId::new(100));
2586 let dog = table.named(super::SymbolId::new(101));
2587 let number = table.number();
2590 let takes_number = table.function(vec![number], table.void());
2591 let number_literal = table.number_literal("1");
2592 let takes_number_literal = table.function(vec![number_literal], table.void());
2593 assert!(!table.assignable(takes_number_literal, takes_number));
2596 let takes_none = table.function(vec![], table.void());
2598 assert!(table.assignable(takes_none, takes_number));
2599 let returns_number = table.function(vec![], table.number());
2601 assert!(table.assignable(returns_number, takes_none));
2602 assert_ne!(animal, dog);
2604 }
2605
2606 #[test]
2607 fn relation_retains_optional_callback_void_and_enum_hazards() {
2608 let mut table = TypeTable::new();
2609 let source_object =
2610 table.object_type(vec![PropertyType::new("x", false, table.undefined_type())]);
2611 let target_object = table.object_type(vec![PropertyType::new("x", true, table.number())]);
2612 let optional = table.relation(source_object, target_object);
2613 assert!(optional.compatible());
2614 assert!(
2615 optional
2616 .hazards()
2617 .contains(&super::RelationHazard::ExplicitUndefinedForOptional)
2618 );
2619
2620 let source_function = table.function(Vec::new(), table.number());
2621 let target_function = table.function(vec![table.number()], table.void());
2622 let callback = table.relation(source_function, target_function);
2623 assert!(
2624 callback
2625 .hazards()
2626 .contains(&super::RelationHazard::FewerCallbackParameters)
2627 );
2628 assert!(
2629 callback
2630 .hazards()
2631 .contains(&super::RelationHazard::ValueReturnedToVoid)
2632 );
2633
2634 let enum_type = table.numeric_enum(super::SymbolId::new(200));
2635 let enum_boundary = table.relation(enum_type, table.number());
2636 assert!(enum_boundary.compatible());
2637 assert!(
2638 enum_boundary
2639 .hazards()
2640 .contains(&super::RelationHazard::NumericEnumNumber)
2641 );
2642 }
2643
2644 fn source(text: &str) -> Arc<SourceText> {
2647 Arc::new(SourceText::new(text))
2648 }
2649
2650 fn check_text(text: &str) -> Recovered<super::SemanticModel> {
2651 let parsed = parser::parse(scanner::scan(
2652 SourceId::new(0),
2653 ScriptKind::TypeScript,
2654 source(text),
2655 ));
2656 check(&parsed)
2657 }
2658
2659 fn checker_codes(result: &Recovered<super::SemanticModel>) -> Vec<&'static str> {
2660 result
2661 .diagnostics()
2662 .iter()
2663 .map(|diagnostic| diagnostic.code().as_str())
2664 .filter(|code| code.starts_with("BAMTS-C"))
2665 .collect()
2666 }
2667
2668 fn range(start: usize, end: usize) -> TextRange {
2669 TextRange::new(Utf16Pos::new(start), Utf16Pos::new(end)).expect("ordered range")
2670 }
2671
2672 fn identifier(id: u32, name: &str, start: usize) -> IdentifierNode {
2673 let end = start + name.len();
2674 Node::new(
2675 NodeId::new(id),
2676 range(start, end),
2677 Identifier::new(Token::new(TokenKind::Identifier, range(start, end))),
2678 )
2679 }
2680
2681 fn file(text: &str, statements: Vec<Stmt>) -> Recovered<SourceFile> {
2684 let source = source(text);
2685 let end = source.len_utf16().get();
2686 let eof = Token::new(TokenKind::EndOfFile, range(end, end));
2687 let file = SourceFile::new(
2688 NodeId::new(0),
2689 SourceId::new(1),
2690 ScriptKind::TypeScript,
2691 range(0, end),
2692 source,
2693 Vec::new(),
2694 statements,
2695 eof,
2696 Vec::new(),
2697 );
2698 Recovered::clean(file)
2699 }
2700
2701 fn keyword_annotation(
2702 id: u32,
2703 keyword: KeywordType,
2704 start: usize,
2705 end: usize,
2706 ) -> Node<TypeAnnotation> {
2707 let type_node = Node::new(
2708 NodeId::new(id),
2709 range(start, end),
2710 TypeNode::Keyword(keyword),
2711 );
2712 Node::new(
2713 NodeId::new(id + 1),
2714 range(start, end),
2715 TypeAnnotation {
2716 type_node: Box::new(type_node),
2717 },
2718 )
2719 }
2720
2721 fn variable(
2722 id: u32,
2723 text: &str,
2724 name: &str,
2725 name_start: usize,
2726 annotation: Option<Node<TypeAnnotation>>,
2727 initializer: Option<Box<Expr>>,
2728 ) -> Stmt {
2729 let name_node = identifier(id + 1, name, name_start);
2730 let binding = Node::new(
2731 NodeId::new(id + 2),
2732 name_node.range(),
2733 BindingPattern::Identifier(name_node),
2734 );
2735 let declarator = Node::new(
2736 NodeId::new(id + 3),
2737 range(0, text.len()),
2738 crate::syntax::VariableDeclarator {
2739 binding,
2740 definite: false,
2741 type_annotation: annotation,
2742 initializer,
2743 },
2744 );
2745 Node::new(
2746 NodeId::new(id),
2747 range(0, text.len()),
2748 Statement::Variable(crate::syntax::VariableDeclaration {
2749 kind: crate::syntax::VariableKind::Const,
2750 declarations: vec![declarator],
2751 }),
2752 )
2753 }
2754
2755 fn number_expr(id: u32, text: &str, start: usize) -> Box<Expr> {
2756 let end = start + text.len();
2757 let literal = Node::new(
2758 NodeId::new(id + 1),
2759 range(start, end),
2760 NumericLiteral::new(Token::new(TokenKind::NumericLiteral, range(start, end))),
2761 );
2762 Box::new(Node::new(
2763 NodeId::new(id),
2764 range(start, end),
2765 Expression::Literal(Literal::Number(literal)),
2766 ))
2767 }
2768
2769 fn string_expr(id: u32, text: &str, start: usize) -> Box<Expr> {
2770 let end = start + text.len();
2771 let literal = Node::new(
2772 NodeId::new(id + 1),
2773 range(start, end),
2774 StringLiteral::new(Token::new(TokenKind::StringLiteral, range(start, end))),
2775 );
2776 Box::new(Node::new(
2777 NodeId::new(id),
2778 range(start, end),
2779 Expression::Literal(Literal::String(literal)),
2780 ))
2781 }
2782
2783 fn identifier_expr(id: u32, name: &str, start: usize) -> Box<Expr> {
2784 Box::new(Node::new(
2785 NodeId::new(id),
2786 range(start, start + name.len()),
2787 Expression::Identifier(identifier(id + 1, name, start)),
2788 ))
2789 }
2790
2791 fn expression_statement(id: u32, expression: Box<Expr>) -> Stmt {
2792 Node::new(
2793 NodeId::new(id),
2794 expression.range(),
2795 Statement::Expression(ExpressionStatement { expression }),
2796 )
2797 }
2798
2799 fn semantic_codes(model: &Recovered<super::SemanticModel>) -> Vec<&'static str> {
2800 model
2801 .diagnostics()
2802 .iter()
2803 .map(|diagnostic| diagnostic.code().as_str())
2804 .collect()
2805 }
2806
2807 #[test]
2808 fn binds_a_variable_and_resolves_its_later_reference() {
2809 let statements = vec![
2810 variable(
2811 10,
2812 "const a = 1;",
2813 "a",
2814 6,
2815 None,
2816 Some(number_expr(20, "1", 10)),
2817 ),
2818 expression_statement(30, identifier_expr(31, "a", 13)),
2819 ];
2820 let result = check(&file("const a = 1; a;", statements));
2821 assert!(semantic_codes(&result).is_empty());
2822 let model = result.product();
2823 let symbol = model
2824 .lookup_value(model.module_scope(), "a")
2825 .expect("a is bound");
2826 assert!(matches!(
2827 model.symbol(symbol).kind(),
2828 SymbolKind::Variable(_)
2829 ));
2830 assert_eq!(model.resolved_reference_count(), 1);
2831 assert_eq!(model.scope(model.module_scope()).kind(), ScopeKind::Module);
2832 }
2833
2834 #[test]
2835 fn reports_an_unresolved_local_value_reference() {
2836 let statements = vec![expression_statement(30, identifier_expr(31, "missing", 0))];
2837 let result = check(&file("missing;", statements));
2838 assert_eq!(semantic_codes(&result), [CANNOT_FIND_NAME.as_str()]);
2839 }
2840
2841 #[test]
2842 fn a_global_value_reference_is_not_unresolved() {
2843 let statements = vec![expression_statement(30, identifier_expr(31, "console", 0))];
2844 let result = check(&file("console;", statements));
2845 assert!(semantic_codes(&result).is_empty());
2846 }
2847
2848 #[test]
2849 fn standard_global_families_bind_as_intrinsics() {
2850 let names = [
2851 "JSON",
2853 "Math",
2854 "Object",
2855 "Array",
2856 "Promise",
2857 "Error",
2858 "TypeError",
2859 "escape",
2860 "unescape",
2861 "Map",
2863 "Set",
2864 "Symbol",
2865 "Reflect",
2866 "Atomics",
2867 "Int8Array",
2868 "BigUint64Array",
2869 "setTimeout",
2871 "clearInterval",
2872 "queueMicrotask",
2873 "URL",
2874 "URLSearchParams",
2875 "TextEncoder",
2876 "TextDecoder",
2877 "console",
2879 "process",
2880 "globalThis",
2881 ];
2882 let text = names.join(";");
2883 let mut start = 0;
2884 let statements = names
2885 .iter()
2886 .enumerate()
2887 .map(|(index, name)| {
2888 let statement = expression_statement(
2889 u32::try_from(index * 2 + 30).expect("test node id fits u32"),
2890 identifier_expr(
2891 u32::try_from(index * 2 + 31).expect("test node id fits u32"),
2892 name,
2893 start,
2894 ),
2895 );
2896 start += name.len() + 1;
2897 statement
2898 })
2899 .collect();
2900 let result = check(&file(&text, statements));
2901 assert!(
2902 semantic_codes(&result).is_empty(),
2903 "intrinsic diagnostics: {:?}",
2904 result.diagnostics()
2905 );
2906 assert_eq!(result.product().resolved_reference_count(), names.len());
2907 }
2908
2909 #[test]
2910 fn local_bindings_shadow_intrinsics() {
2911 let statements = vec![
2912 variable(
2913 10,
2914 "const console = 1;",
2915 "console",
2916 6,
2917 None,
2918 Some(number_expr(20, "1", 16)),
2919 ),
2920 expression_statement(30, identifier_expr(31, "console", 19)),
2921 ];
2922 let result = check(&file("const console = 1; console;", statements));
2923 assert!(semantic_codes(&result).is_empty());
2924 let model = result.product();
2925 let local = model
2926 .lookup_value(model.module_scope(), "console")
2927 .expect("local console binding exists");
2928 assert_eq!(model.reference(NodeId::new(32)), Some(local));
2929 }
2930
2931 #[test]
2932 fn reports_an_unknown_name_even_with_intrinsics() {
2933 let statements = vec![expression_statement(
2934 30,
2935 identifier_expr(31, "notAGlobal", 0),
2936 )];
2937 let result = check(&file("notAGlobal;", statements));
2938 assert_eq!(semantic_codes(&result), [CANNOT_FIND_NAME.as_str()]);
2939 }
2940
2941 #[test]
2942 fn reports_a_duplicate_block_scoped_declaration() {
2943 let statements = vec![
2944 variable(
2945 10,
2946 "const a = 1;",
2947 "a",
2948 6,
2949 None,
2950 Some(number_expr(20, "1", 10)),
2951 ),
2952 variable(
2953 40,
2954 "const a = 2;",
2955 "a",
2956 19,
2957 None,
2958 Some(number_expr(50, "2", 23)),
2959 ),
2960 ];
2961 let result = check(&file("const a = 1; const a = 2;", statements));
2962 assert_eq!(semantic_codes(&result), [DUPLICATE_DECLARATION.as_str()]);
2963 }
2964
2965 #[test]
2966 fn a_shadowing_binding_in_a_nested_block_is_not_a_duplicate() {
2967 let inner = variable(
2968 40,
2969 "const a = 2;",
2970 "a",
2971 21,
2972 None,
2973 Some(number_expr(50, "2", 25)),
2974 );
2975 let block = Node::new(
2976 NodeId::new(60),
2977 range(13, 29),
2978 Statement::Block(Node::new(
2979 NodeId::new(61),
2980 range(13, 29),
2981 Block {
2982 statements: vec![inner],
2983 },
2984 )),
2985 );
2986 let statements = vec![
2987 variable(
2988 10,
2989 "const a = 1;",
2990 "a",
2991 6,
2992 None,
2993 Some(number_expr(20, "1", 10)),
2994 ),
2995 block,
2996 ];
2997 let result = check(&file("const a = 1; { const a = 2; }", statements));
2998 assert!(semantic_codes(&result).is_empty());
2999 }
3000
3001 #[test]
3002 fn a_number_literal_is_not_assignable_to_a_string_annotation() {
3003 let annotation = keyword_annotation(70, KeywordType::String, 9, 15);
3004 let statements = vec![variable(
3005 10,
3006 "const x: string = 1;",
3007 "x",
3008 6,
3009 Some(annotation),
3010 Some(number_expr(20, "1", 18)),
3011 )];
3012 let result = check(&file("const x: string = 1;", statements));
3013 assert_eq!(semantic_codes(&result), [TYPE_NOT_ASSIGNABLE.as_str()]);
3014 }
3015
3016 #[test]
3017 fn a_matching_literal_initializer_is_accepted() {
3018 let annotation = keyword_annotation(70, KeywordType::Number, 9, 15);
3019 let statements = vec![variable(
3020 10,
3021 "const x: number = 1;",
3022 "x",
3023 6,
3024 Some(annotation),
3025 Some(number_expr(20, "1", 18)),
3026 )];
3027 let result = check(&file("const x: number = 1;", statements));
3028 assert!(semantic_codes(&result).is_empty());
3029 }
3030
3031 #[test]
3032 fn an_unresolved_type_annotation_reports_cannot_find_type() {
3033 let reference = crate::syntax::TypeReference {
3034 name: EntityName::Identifier(identifier(71, "Foo", 9)),
3035 type_arguments: None,
3036 };
3037 let type_node = Node::new(
3038 NodeId::new(72),
3039 range(9, 12),
3040 TypeNode::Reference(reference),
3041 );
3042 let annotation = Node::new(
3043 NodeId::new(73),
3044 range(9, 12),
3045 TypeAnnotation {
3046 type_node: Box::new(type_node),
3047 },
3048 );
3049 let statements = vec![variable(
3050 10,
3051 "const x: Foo;",
3052 "x",
3053 6,
3054 Some(annotation),
3055 None,
3056 )];
3057 let result = check(&file("const x: Foo;", statements));
3058 assert_eq!(semantic_codes(&result), [CANNOT_FIND_TYPE.as_str()]);
3059 }
3060
3061 #[test]
3062 fn generic_declarations_bind_their_type_parameters() {
3063 let result = check_text(
3064 "type Box<T> = { value: T };\
3065 interface Pair<T> { left: T; map<U>(value: U): T; }\
3066 class Store<T> { value: T; method<U>(value: U): T { return this.value; } }",
3067 );
3068 assert!(checker_codes(&result).is_empty());
3069 }
3070
3071 #[test]
3072 fn imported_names_bind_in_the_type_namespace_through_exports() {
3073 let result = check_text(
3074 "import type { Remote } from './remote.ts';\
3075 export type Local<T> = Remote;\
3076 export interface Public<T> { value: Local<T>; remote: Remote; }",
3077 );
3078 assert!(checker_codes(&result).is_empty());
3079 }
3080
3081 #[test]
3082 fn standard_iterator_and_generator_interfaces_are_bound() {
3083 let result = check_text(
3084 "declare let iterator: IterableIterator<number>;\
3085 async function* values(): AsyncGenerator<number> { yield 1; }",
3086 );
3087 assert!(checker_codes(&result).is_empty());
3088 }
3089
3090 #[test]
3091 fn functions_bind_arguments_this_and_their_local_name() {
3092 let result = check_text(
3093 "const recursive = function self(this: void) { arguments; return self; };\
3094 class C { method() { arguments; return this; } }",
3095 );
3096 assert!(checker_codes(&result).is_empty());
3097 }
3098
3099 #[test]
3100 fn ambient_declarations_bind_before_their_uses() {
3101 let result = check_text(
3102 "const before: Box<number> = make<number>();\
3103 declare interface Box<T> { value: T; }\
3104 declare function make<T>(): Box<T>;",
3105 );
3106 assert!(checker_codes(&result).is_empty());
3107 }
3108
3109 #[test]
3110 fn local_generic_casts_resolve_in_the_enclosing_function() {
3111 let result = check_text(
3112 "function copy<T>(value: T): T { const result = value as T; return result; }",
3113 );
3114 assert!(checker_codes(&result).is_empty());
3115 }
3116
3117 #[test]
3118 fn const_assertions_preserve_literal_expression_types() {
3119 let result = check_text("const state: \"ready\" = \"ready\" as const;");
3120 assert!(checker_codes(&result).is_empty());
3121 }
3122
3123 #[test]
3124 fn object_methods_satisfy_structural_function_members() {
3125 let result = check_text(
3126 "interface Service { compute(value: number): Promise<number>; }\
3127 const service: Service = { async compute(value: number) { return value; } };",
3128 );
3129 assert!(checker_codes(&result).is_empty());
3130 }
3131
3132 #[test]
3133 fn unknown_names_and_real_initializer_mismatches_remain_errors() {
3134 let result =
3135 check_text("missingValue; let missing: MissingType; const count: number = 'wrong';");
3136 assert_eq!(
3137 checker_codes(&result),
3138 [
3139 CANNOT_FIND_NAME.as_str(),
3140 CANNOT_FIND_TYPE.as_str(),
3141 TYPE_NOT_ASSIGNABLE.as_str(),
3142 ]
3143 );
3144 }
3145
3146 #[test]
3147 fn hard_warnings_merge_into_ordered_diagnostics() {
3148 let text = "try {} catch (error) { error.message; }";
3151 let statements = vec![expression_statement(30, identifier_expr(31, "nope", 0))];
3154 let result = check(&file(text, statements));
3155 let diagnostics = result.diagnostics();
3156 assert!(
3158 diagnostics
3159 .iter()
3160 .any(|diagnostic| diagnostic.code() == CANNOT_FIND_NAME)
3161 );
3162 assert!(
3163 diagnostics
3164 .iter()
3165 .any(|diagnostic| diagnostic.severity() == DiagnosticSeverity::Warning)
3166 );
3167 let mut sorted = diagnostics.to_vec();
3169 sorted.sort();
3170 assert_eq!(diagnostics, sorted.as_slice());
3171 }
3172
3173 #[test]
3174 fn a_parameter_reference_resolves_within_its_function_scope() {
3175 let parameter_name = identifier(81, "p", 11);
3176 let binding = Node::new(
3177 NodeId::new(82),
3178 parameter_name.range(),
3179 BindingPattern::Identifier(parameter_name),
3180 );
3181 let parameter: ParameterNode = Node::new(
3182 NodeId::new(83),
3183 range(11, 12),
3184 Parameter {
3185 decorators: Vec::new(),
3186 modifiers: crate::syntax::ParameterModifiers::default(),
3187 binding,
3188 optional: false,
3189 type_annotation: None,
3190 initializer: None,
3191 },
3192 );
3193 let body = identifier_expr(90, "p", 17);
3194 let arrow = Node::new(
3195 NodeId::new(80),
3196 range(10, 18),
3197 Expression::Arrow(ArrowFunction {
3198 is_async: false,
3199 type_parameters: None,
3200 parameters: vec![parameter],
3201 return_type: None,
3202 body: FunctionBody::Expression(body),
3203 }),
3204 );
3205 let statements = vec![variable(
3206 10,
3207 "const f = (p) => p;",
3208 "f",
3209 6,
3210 None,
3211 Some(Box::new(arrow)),
3212 )];
3213 let result = check(&file("const f = (p) => p;", statements));
3214 assert!(semantic_codes(&result).is_empty());
3215 let model = result.product();
3217 assert!(
3218 model
3219 .scopes()
3220 .iter()
3221 .any(|scope| scope.kind() == ScopeKind::Function)
3222 );
3223 }
3224
3225 #[test]
3226 fn a_string_initializer_matches_a_string_annotation() {
3227 let annotation = keyword_annotation(70, KeywordType::String, 9, 15);
3228 let statements = vec![variable(
3229 10,
3230 "const s: string = \"ok\";",
3231 "s",
3232 6,
3233 Some(annotation),
3234 Some(string_expr(20, "\"ok\"", 18)),
3235 )];
3236 let result = check(&file("const s: string = \"ok\";", statements));
3237 assert!(semantic_codes(&result).is_empty());
3238 let model = result.product();
3239 let symbol = model
3240 .lookup_value(model.module_scope(), "s")
3241 .expect("s is bound");
3242 assert_eq!(model.symbol_type(symbol), model.types().string());
3243 }
3244
3245 #[test]
3246 fn missing_identifiers_never_panic_the_checker() {
3247 let missing = Node::new(
3249 NodeId::new(31),
3250 range(0, 0),
3251 Expression::Missing(MissingNode::new(NodeKind::IdentifierExpression)),
3252 );
3253 let statements = vec![expression_statement(30, Box::new(missing))];
3254 let result = check(&file("", statements));
3255 assert!(semantic_codes(&result).is_empty());
3256 }
3257
3258 fn var_declaration(
3261 kind: crate::syntax::VariableKind,
3262 id: u32,
3263 name: &str,
3264 name_start: usize,
3265 initializer: Option<Box<Expr>>,
3266 ) -> crate::syntax::VariableDeclaration {
3267 let name_node = identifier(id + 1, name, name_start);
3268 let binding = Node::new(
3269 NodeId::new(id + 2),
3270 name_node.range(),
3271 BindingPattern::Identifier(name_node),
3272 );
3273 let declarator = Node::new(
3274 NodeId::new(id + 3),
3275 range(name_start, name_start + name.len()),
3276 crate::syntax::VariableDeclarator {
3277 binding,
3278 definite: false,
3279 type_annotation: None,
3280 initializer,
3281 },
3282 );
3283 crate::syntax::VariableDeclaration {
3284 kind,
3285 declarations: vec![declarator],
3286 }
3287 }
3288
3289 fn variable_kind(
3290 kind: crate::syntax::VariableKind,
3291 id: u32,
3292 text: &str,
3293 name: &str,
3294 name_start: usize,
3295 initializer: Option<Box<Expr>>,
3296 ) -> Stmt {
3297 Node::new(
3298 NodeId::new(id),
3299 range(0, text.len()),
3300 Statement::Variable(var_declaration(kind, id, name, name_start, initializer)),
3301 )
3302 }
3303
3304 fn block_statement(id: u32, statements: Vec<Stmt>) -> Stmt {
3305 Node::new(
3306 NodeId::new(id),
3307 range(0, 1),
3308 Statement::Block(Node::new(
3309 NodeId::new(id + 1),
3310 range(0, 1),
3311 Block { statements },
3312 )),
3313 )
3314 }
3315
3316 #[test]
3317 fn a_var_in_a_block_hoists_to_the_module_and_resolves_outside() {
3318 let inner = variable_kind(
3319 crate::syntax::VariableKind::Var,
3320 40,
3321 "var a = 1;",
3322 "a",
3323 6,
3324 Some(number_expr(50, "1", 10)),
3325 );
3326 let block = block_statement(60, vec![inner]);
3327 let statements = vec![
3328 block,
3329 expression_statement(70, identifier_expr(71, "a", 15)),
3330 ];
3331 let result = check(&file("{ var a = 1; } a;", statements));
3332 assert!(semantic_codes(&result).is_empty());
3333 let model = result.product();
3334 let symbol = model
3335 .lookup_value(model.module_scope(), "a")
3336 .expect("var a hoists to the module scope");
3337 assert!(matches!(
3338 model.symbol(symbol).kind(),
3339 SymbolKind::Variable(crate::syntax::VariableKind::Var)
3340 ));
3341 assert_eq!(model.resolved_reference_count(), 1);
3342 }
3343
3344 #[test]
3345 fn a_var_in_a_nested_block_binds_before_its_declaration() {
3346 let inner = variable_kind(
3347 crate::syntax::VariableKind::Var,
3348 40,
3349 "var a = 1;",
3350 "a",
3351 9,
3352 Some(number_expr(50, "1", 13)),
3353 );
3354 let statements = vec![
3355 expression_statement(30, identifier_expr(31, "a", 0)),
3356 block_statement(60, vec![inner]),
3357 ];
3358 let result = check(&file("a; { var a = 1; }", statements));
3359 assert!(semantic_codes(&result).is_empty());
3360 assert_eq!(result.product().resolved_reference_count(), 1);
3361 }
3362
3363 #[test]
3364 fn a_for_initializer_var_hoists_to_the_module() {
3365 let for_stmt = Node::new(
3366 NodeId::new(60),
3367 range(0, 1),
3368 Statement::For(crate::syntax::ForStatement {
3369 initializer: Some(crate::syntax::ForInitializer::Variable(var_declaration(
3370 crate::syntax::VariableKind::Var,
3371 40,
3372 "i",
3373 9,
3374 Some(number_expr(50, "0", 13)),
3375 ))),
3376 test: None,
3377 update: None,
3378 body: Box::new(block_statement(80, vec![])),
3379 }),
3380 );
3381 let statements = vec![
3382 for_stmt,
3383 expression_statement(90, identifier_expr(91, "i", 23)),
3384 ];
3385 let result = check(&file("for (var i = 0; ; ) {} i;", statements));
3386 assert!(semantic_codes(&result).is_empty());
3387 let model = result.product();
3388 assert!(
3389 model.lookup_value(model.module_scope(), "i").is_some(),
3390 "for-initializer var hoists out of the for scope"
3391 );
3392 assert_eq!(model.resolved_reference_count(), 1);
3393 }
3394
3395 #[test]
3396 fn a_var_in_a_nested_function_does_not_escape_to_the_outer_scope() {
3397 let inner = variable_kind(
3398 crate::syntax::VariableKind::Var,
3399 40,
3400 "var x = 1;",
3401 "x",
3402 15,
3403 Some(number_expr(50, "1", 19)),
3404 );
3405 let body = Node::new(
3406 NodeId::new(70),
3407 range(0, 1),
3408 Block {
3409 statements: vec![inner],
3410 },
3411 );
3412 let function = crate::syntax::FunctionLike {
3413 decorators: Vec::new(),
3414 name: Some(identifier(81, "f", 9)),
3415 is_async: false,
3416 is_generator: false,
3417 type_parameters: None,
3418 parameters: Vec::new(),
3419 return_type: None,
3420 body: Some(FunctionBody::Block(body)),
3421 };
3422 let fn_stmt = Node::new(
3423 NodeId::new(80),
3424 range(0, 1),
3425 Statement::Function(crate::syntax::FunctionDeclaration { function }),
3426 );
3427 let result = check(&file("function f() { var x = 1; }", vec![fn_stmt]));
3428 assert!(semantic_codes(&result).is_empty());
3429 let model = result.product();
3430 assert!(
3431 model.lookup_value(model.module_scope(), "f").is_some(),
3432 "the function declaration binds at the module scope"
3433 );
3434 assert!(
3435 model.lookup_value(model.module_scope(), "x").is_none(),
3436 "the inner var stays inside its own function scope"
3437 );
3438 }
3439
3440 #[test]
3441 fn a_function_declaration_in_a_block_hoists_to_the_module() {
3442 let function = crate::syntax::FunctionLike {
3443 decorators: Vec::new(),
3444 name: Some(identifier(81, "g", 14)),
3445 is_async: false,
3446 is_generator: false,
3447 type_parameters: None,
3448 parameters: Vec::new(),
3449 return_type: None,
3450 body: Some(FunctionBody::Block(Node::new(
3451 NodeId::new(82),
3452 range(15, 17),
3453 Block {
3454 statements: Vec::new(),
3455 },
3456 ))),
3457 };
3458 let declaration = Node::new(
3459 NodeId::new(80),
3460 range(2, 17),
3461 Statement::Function(crate::syntax::FunctionDeclaration { function }),
3462 );
3463 let statements = vec![
3464 expression_statement(70, identifier_expr(71, "g", 0)),
3465 block_statement(90, vec![declaration]),
3466 ];
3467 let result = check(&file("g; { function g() {} }", statements));
3468 assert!(semantic_codes(&result).is_empty());
3469 let model = result.product();
3470 assert!(
3471 model.lookup_value(model.module_scope(), "g").is_some(),
3472 "block function declaration hoists to the module scope"
3473 );
3474 assert_eq!(model.resolved_reference_count(), 1);
3475 }
3476
3477 #[test]
3478 fn a_let_in_a_block_does_not_hoist_and_is_unresolved_outside() {
3479 let inner = variable_kind(
3480 crate::syntax::VariableKind::Let,
3481 40,
3482 "let b = 1;",
3483 "b",
3484 6,
3485 Some(number_expr(50, "1", 10)),
3486 );
3487 let block = block_statement(60, vec![inner]);
3488 let statements = vec![
3489 block,
3490 expression_statement(70, identifier_expr(71, "b", 15)),
3491 ];
3492 let result = check(&file("{ let b = 1; } b;", statements));
3493 assert_eq!(semantic_codes(&result), [CANNOT_FIND_NAME.as_str()]);
3494 let model = result.product();
3495 assert!(
3496 model.lookup_value(model.module_scope(), "b").is_none(),
3497 "let stays block-scoped and never reaches the module scope"
3498 );
3499 }
3500}