Skip to main content

tsz_solver/
types.rs

1//! Type representation for the structural solver.
2//!
3//! Types are represented as lightweight `TypeId` handles that point into
4//! an interning table. The actual structure is stored in `TypeData`.
5
6use crate::def::DefId;
7use serde::Serialize;
8use tsz_binder::SymbolId;
9use tsz_common::interner::Atom;
10
11/// A lightweight handle to an interned type.
12/// Equality check is O(1) - just compare the u32 values.
13///
14/// # Sentinel Value Semantics
15///
16/// The following sentinel values have specific semantics for error handling and type inference:
17///
18/// ## `TypeId::ERROR`
19/// Used when type resolution **fails** due to an actual error:
20/// - Missing AST nodes or invalid syntax
21/// - Type annotation that cannot be resolved
22/// - Failed type inference with no fallback
23///
24/// **Error propagation**: ERROR is "contagious" - operations on ERROR types return ERROR.
25/// This prevents cascading errors from a single root cause. Property access on ERROR
26/// returns ERROR silently (no additional diagnostics emitted).
27///
28/// **Example uses:**
29/// - Missing type annotation: `let x;` -> ERROR (prevents "any poisoning")
30/// - Failed generic inference with no constraint/default
31/// - Invalid type syntax or unresolved type references
32///
33/// ## `TypeId::UNKNOWN`
34/// The TypeScript `unknown` type - a type-safe alternative to `any`.
35/// Use when the type is genuinely unknown at compile time, but should be
36/// checked before use.
37///
38/// **Strict behavior**: Property access on UNKNOWN returns `IsUnknown` result,
39/// which the checker reports as TS2571 "Object is of type 'unknown'".
40///
41/// **Example uses:**
42/// - Explicit `unknown` type annotation
43/// - Return type of functions that could return anything
44/// - Missing `this` parameter type (stricter than `any`)
45///
46/// ## `TypeId::ANY`
47/// The TypeScript `any` type - opts out of type checking entirely.
48/// Use for intentional any-typed values or interop with untyped code.
49///
50/// **Permissive behavior**: Property access on ANY succeeds and returns ANY.
51/// No type errors are produced for any-typed expressions.
52///
53/// **Example uses:**
54/// - Explicit `any` type annotation
55/// - Arrays with no element type context: `[]` defaults to `any[]`
56/// - Interop with JavaScript libraries without type definitions
57///
58/// ## `TypeId::NEVER`
59/// The bottom type - represents values that can never exist.
60/// Used for exhaustive checking and functions that never return.
61///
62/// **Example uses:**
63/// - Function that always throws or loops forever
64/// - Exhaustive switch/if narrowing (remaining type after all cases)
65/// - Intersection of incompatible types
66///
67/// ## Summary: When to Use Each
68///
69/// | Scenario                          | Use           |
70/// |-----------------------------------|---------------|
71/// | Type resolution failed            | `ERROR`       |
72/// | Missing required type annotation  | `ERROR`       |
73/// | Failed inference (no fallback)    | `ERROR`       |
74/// | Explicit `unknown` annotation     | `UNKNOWN`     |
75/// | Missing `this` parameter type     | `UNKNOWN`     |
76/// | Explicit `any` annotation         | `ANY`         |
77/// | Empty array literal `[]`          | `any[]`       |
78/// | Function never returns            | `NEVER`       |
79/// | Exhaustive narrowing remainder    | `NEVER`       |
80#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Default)]
81pub struct TypeId(pub u32);
82
83impl TypeId {
84    /// Internal placeholder - no valid type.
85    pub const NONE: Self = Self(0);
86
87    /// Error sentinel - type resolution failed.
88    /// Propagates through operations to prevent cascading errors.
89    /// See struct-level docs for detailed semantics.
90    pub const ERROR: Self = Self(1);
91
92    /// The bottom type - represents values that can never exist.
93    /// Used for exhaustive checks and functions that never return.
94    pub const NEVER: Self = Self(2);
95
96    /// TypeScript's `unknown` type - type-safe top type.
97    /// Requires type narrowing before use. See struct-level docs.
98    pub const UNKNOWN: Self = Self(3);
99
100    /// TypeScript's `any` type - opts out of type checking.
101    /// All operations succeed, returning `any`. See struct-level docs.
102    pub const ANY: Self = Self(4);
103
104    /// The `void` type - used for functions with no meaningful return.
105    pub const VOID: Self = Self(5);
106
107    /// The `undefined` type - represents the undefined value.
108    pub const UNDEFINED: Self = Self(6);
109
110    /// The `null` type - represents the null value.
111    pub const NULL: Self = Self(7);
112
113    /// The `boolean` type - union of true | false.
114    pub const BOOLEAN: Self = Self(8);
115
116    /// The `number` type - all numeric values.
117    pub const NUMBER: Self = Self(9);
118
119    /// The `string` type - all string values.
120    pub const STRING: Self = Self(10);
121
122    /// The `bigint` type - arbitrary precision integers.
123    pub const BIGINT: Self = Self(11);
124
125    /// The `symbol` type - unique symbol values.
126    pub const SYMBOL: Self = Self(12);
127
128    /// The `object` type - any non-primitive value.
129    pub const OBJECT: Self = Self(13);
130
131    /// The literal type `true`.
132    pub const BOOLEAN_TRUE: Self = Self(14);
133
134    /// The literal type `false`.
135    pub const BOOLEAN_FALSE: Self = Self(15);
136
137    /// The `Function` type - any callable.
138    pub const FUNCTION: Self = Self(16);
139
140    /// Synthetic Promise base type for Promise<T> when Promise symbol is not resolved.
141    /// Used to allow `promise_like_return_type_argument` to extract T from await expressions.
142    pub const PROMISE_BASE: Self = Self(17);
143
144    /// Internal sentinel indicating that expression checking should be delegated
145    /// to `CheckerState` for complex cases that need full checker context.
146    /// This is NOT a real type and should never escape ExpressionChecker/CheckerState.
147    pub const DELEGATE: Self = Self(18);
148
149    /// Internal sentinel used to represent 'any' in strict mode (North Star Fix).
150    /// Behaves like 'any' but does NOT silence structural mismatches.
151    pub const STRICT_ANY: Self = Self(19);
152
153    /// First user-defined type ID (after built-in intrinsics)
154    pub const FIRST_USER: u32 = 100;
155
156    pub const fn is_intrinsic(self) -> bool {
157        self.0 < Self::FIRST_USER
158    }
159
160    pub fn is_error(self) -> bool {
161        self == Self::ERROR
162    }
163
164    pub fn is_any(self) -> bool {
165        self == Self::ANY
166    }
167
168    pub fn is_unknown(self) -> bool {
169        self == Self::UNKNOWN
170    }
171
172    pub fn is_never(self) -> bool {
173        self == Self::NEVER
174    }
175
176    /// Returns true if this type is nullish (null or undefined).
177    /// Useful for strict null checking logic.
178    #[inline]
179    pub fn is_nullish(self) -> bool {
180        self == Self::NULL || self == Self::UNDEFINED
181    }
182
183    /// Returns true if this type is nullable (null, undefined, or void).
184    /// VOID is considered nullable because it represents undefined in some contexts.
185    #[inline]
186    pub fn is_nullable(self) -> bool {
187        self == Self::NULL || self == Self::UNDEFINED || self == Self::VOID
188    }
189
190    /// Returns true if this type is a top type (any or unknown).
191    /// Top types are assignable from all other types.
192    #[inline]
193    pub fn is_top_type(self) -> bool {
194        self == Self::ANY || self == Self::UNKNOWN
195    }
196
197    /// Returns true if this type is any or unknown (types that accept anything).
198    /// Alias for `is_top_type` for clarity in some contexts.
199    #[inline]
200    pub fn is_any_or_unknown(self) -> bool {
201        self.is_top_type()
202    }
203
204    // =========================================================================
205    // Local/Global Partitioning (for ScopedTypeInterner GC)
206    // =========================================================================
207
208    /// Mask for the local bit (MSB of u32).
209    ///
210    /// Local IDs have MSB=1 (0x80000000+), Global IDs have MSB=0 (0x7FFFFFFF-).
211    /// This partitioning allows `ScopedTypeInterner` to create ephemeral types
212    /// that don't pollute the global `TypeId` space.
213    pub const LOCAL_MASK: u32 = 0x80000000;
214
215    /// Check if this `TypeId` is a local (ephemeral) type.
216    ///
217    /// Local types are created by `ScopedTypeInterner` and are only valid
218    /// for the current operation/request. They are automatically freed
219    /// when the `ScopedTypeInterner` is dropped.
220    ///
221    /// Returns `true` if MSB is set (0x80000000+).
222    pub const fn is_local(self) -> bool {
223        (self.0 & Self::LOCAL_MASK) != 0
224    }
225
226    /// Check if this `TypeId` is a global (persistent) type.
227    ///
228    /// Global types are managed by `TypeInterner` and persist for the lifetime
229    /// of the project/server. These include declarations and intrinsics.
230    ///
231    /// Returns `true` if MSB is clear (0x7FFFFFFF-).
232    pub const fn is_global(self) -> bool {
233        !self.is_local()
234    }
235}
236
237/// Cache key for type relation queries (subtype, assignability, etc.).
238///
239/// This key includes Lawyer-layer configuration flags to ensure that results
240/// computed under different rules (strict vs non-strict) don't contaminate each other.
241///
242/// ## Fields
243///
244/// - `source`: The source type being compared
245/// - `target`: The target type being compared
246/// - `relation`: Distinguishes between different relation types (0 = subtype, 1 = assignability, etc.)
247/// - `flags`: Bitmask for boolean compiler options (u16 to support current and future flags):
248///   - bit 0: `strict_null_checks`
249///   - bit 1: `strict_function_types`
250///   - bit 2: `exact_optional_property_types`
251///   - bit 3: `no_unchecked_indexed_access`
252///   - bit 4: `disable_method_bivariance` (Sound Mode)
253///   - bit 5: `allow_void_return`
254///   - bit 6: `allow_bivariant_rest`
255///   - bit 7: `allow_bivariant_param_count`
256///   - bits 8-15: Reserved for future flags (`strict_any_propagation`, `strict_structural_checking`, etc.)
257/// - `any_mode`: Controls how `any` is treated (0 = All, 1 = `TopLevelOnly`)
258#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
259pub struct RelationCacheKey {
260    pub source: TypeId,
261    pub target: TypeId,
262    pub relation: u8,
263    pub flags: u16,
264    pub any_mode: u8,
265}
266
267impl RelationCacheKey {
268    /// Relation type constants to prevent magic number errors.
269    pub const SUBTYPE: u8 = 0;
270    pub const ASSIGNABLE: u8 = 1;
271    pub const IDENTICAL: u8 = 2;
272
273    // Named flag constants for the `flags` bitmask.
274    // Each bit represents a compiler option that affects type relation results.
275    pub const FLAG_STRICT_NULL_CHECKS: u16 = 1 << 0;
276    pub const FLAG_STRICT_FUNCTION_TYPES: u16 = 1 << 1;
277    pub const FLAG_EXACT_OPTIONAL_PROPERTY_TYPES: u16 = 1 << 2;
278    pub const FLAG_NO_UNCHECKED_INDEXED_ACCESS: u16 = 1 << 3;
279    pub const FLAG_DISABLE_METHOD_BIVARIANCE: u16 = 1 << 4;
280    pub const FLAG_ALLOW_VOID_RETURN: u16 = 1 << 5;
281    pub const FLAG_ALLOW_BIVARIANT_REST: u16 = 1 << 6;
282    pub const FLAG_ALLOW_BIVARIANT_PARAM_COUNT: u16 = 1 << 7;
283
284    /// Create a new cache key for subtype checking.
285    pub const fn subtype(source: TypeId, target: TypeId, flags: u16, any_mode: u8) -> Self {
286        Self {
287            source,
288            target,
289            relation: Self::SUBTYPE,
290            flags,
291            any_mode,
292        }
293    }
294
295    /// Create a new cache key for assignability checking.
296    pub const fn assignability(source: TypeId, target: TypeId, flags: u16, any_mode: u8) -> Self {
297        Self {
298            source,
299            target,
300            relation: Self::ASSIGNABLE,
301            flags,
302            any_mode,
303        }
304    }
305}
306
307/// Priority levels for generic type inference constraints.
308///
309/// TypeScript uses a multi-pass inference algorithm where constraints are processed
310/// in priority order. Higher priority constraints (like explicit type annotations) are
311/// processed first, then lower priority constraints (like contextual types from return
312/// position) are processed in subsequent passes.
313///
314/// This prevents circular dependencies and `any` leakage in complex generic scenarios
315/// like `Array.prototype.map` or `Promise.then`.
316///
317/// ## Priority Order (Highest to Lowest)
318///
319/// 1. **`NakedTypeVariable`** - Direct type parameter with no constraints (highest)
320/// 2. **`HomomorphicMappedType`** - Mapped types that preserve structure
321/// 3. **`PartialHomomorphicMappedType`** - Partially homomorphic mapped types
322/// 4. **`MappedType`** - Generic mapped types
323/// 5. **`ContravariantConditional`** - Conditional types in contravariant position
324/// 6. **`ReturnType`** - Contextual type from return position (low priority)
325/// 7. **`LowPriority`** - Fallback inference (lowest)
326/// 8. **Circular** - Detected circular dependency (prevents infinite loops)
327///
328/// ## Example
329///
330/// ```typescript
331/// function map<U>(arr: T[], fn: (x: T) => U): U[];
332/// // When calling map(x => x.toString()):
333/// // 1. T is inferred from array element type (NakedTypeVariable)
334/// // 2. U is inferred from return type contextual type (ReturnType)
335/// // Processing T first prevents circular T <-> U dependency
336/// ```
337///
338/// Part of the Priority-Based Contextual Inference implementation.
339#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
340pub enum InferencePriority {
341    /// Naked type variable with no constraints (highest priority).
342    /// Example: `<T>` where T appears directly in parameter types.
343    NakedTypeVariable = 1 << 0,
344
345    /// Mapped type that preserves array/tuple structure.
346    /// Example: `Partial<T[]>` preserves array structure.
347    HomomorphicMappedType = 1 << 1,
348
349    /// Partially homomorphic mapped type.
350    /// Example: Mapped types with some mixed properties.
351    PartialHomomorphicMappedType = 1 << 2,
352
353    /// Generic mapped type.
354    /// Example: `{ [K in keyof T]: U }`
355    MappedType = 1 << 3,
356
357    /// Conditional type in contravariant position.
358    /// Example: Inference from function parameter types in conditional types.
359    ContravariantConditional = 1 << 4,
360
361    /// Contextual type from return position.
362    /// Example: `const x: number = fn()` where fn is generic.
363    ReturnType = 1 << 5,
364
365    /// Low priority fallback inference.
366    LowPriority = 1 << 6,
367
368    /// Detected circular dependency (prevents infinite loops).
369    /// Set when a type parameter depends on itself through constraints.
370    Circular = 1 << 7,
371}
372
373impl InferencePriority {
374    /// Check if this priority level should be processed in a given pass.
375    ///
376    /// Multi-pass inference processes constraints in increasing priority order.
377    /// Returns true if this priority matches or is lower than the current pass level.
378    pub fn should_process_in_pass(&self, current_pass: Self) -> bool {
379        *self >= current_pass && *self != Self::Circular
380    }
381
382    /// Get the next priority level for multi-pass inference.
383    pub const fn next_level(&self) -> Option<Self> {
384        match self {
385            Self::NakedTypeVariable => Some(Self::HomomorphicMappedType),
386            Self::HomomorphicMappedType => Some(Self::PartialHomomorphicMappedType),
387            Self::PartialHomomorphicMappedType => Some(Self::MappedType),
388            Self::MappedType => Some(Self::ContravariantConditional),
389            Self::ContravariantConditional => Some(Self::ReturnType),
390            Self::ReturnType => Some(Self::LowPriority),
391            Self::LowPriority | Self::Circular => None,
392        }
393    }
394
395    /// Default priority for normal constraint collection.
396    pub const NORMAL: Self = Self::ReturnType;
397
398    /// Highest priority for explicit type annotations.
399    pub const HIGHEST: Self = Self::NakedTypeVariable;
400
401    /// Lowest priority for fallback inference.
402    pub const LOWEST: Self = Self::LowPriority;
403}
404
405/// Interned list of `TypeId` values (e.g., unions/intersections).
406#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
407pub struct TypeListId(pub u32);
408
409/// Interned object shape (properties + index signatures).
410#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
411pub struct ObjectShapeId(pub u32);
412
413/// Interned tuple element list.
414#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
415pub struct TupleListId(pub u32);
416
417/// Interned function shape.
418#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
419pub struct FunctionShapeId(pub u32);
420
421/// Interned callable shape.
422#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
423pub struct CallableShapeId(pub u32);
424
425/// Interned type application (Base<Args>).
426#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
427pub struct TypeApplicationId(pub u32);
428
429/// Interned template literal span list.
430#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
431pub struct TemplateLiteralId(pub u32);
432
433/// Interned conditional type.
434#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
435pub struct ConditionalTypeId(pub u32);
436
437/// Interned mapped type.
438#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
439pub struct MappedTypeId(pub u32);
440
441/// Well-known Symbol property keys used in the iterator protocol.
442/// These are used to represent `[Symbol.iterator]` and `[Symbol.asyncIterator]` property names.
443#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
444pub enum WellKnownSymbolKey {
445    /// Symbol.iterator - used for sync iterables
446    Iterator,
447    /// Symbol.asyncIterator - used for async iterables
448    AsyncIterator,
449    /// Symbol.hasInstance - used for instanceof checks
450    HasInstance,
451    /// Symbol.isConcatSpreadable - used for array concat behavior
452    IsConcatSpreadable,
453    /// Symbol.match - used for String.match
454    Match,
455    /// Symbol.matchAll - used for String.matchAll
456    MatchAll,
457    /// Symbol.replace - used for String.replace
458    Replace,
459    /// Symbol.search - used for String.search
460    Search,
461    /// Symbol.split - used for String.split
462    Split,
463    /// Symbol.species - used for derived constructors
464    Species,
465    /// Symbol.toPrimitive - used for type coercion
466    ToPrimitive,
467    /// Symbol.toStringTag - used for Object.prototype.toString
468    ToStringTag,
469    /// Symbol.unscopables - used for with statement
470    Unscopables,
471    /// Symbol.dispose - used for using declarations
472    Dispose,
473    /// Symbol.asyncDispose - used for async using declarations
474    AsyncDispose,
475}
476
477impl WellKnownSymbolKey {
478    /// Returns the conventional string property name for this well-known symbol.
479    /// This follows the convention of using `"[Symbol.iterator]"` etc. as property names.
480    pub const fn as_property_name(&self) -> &'static str {
481        match self {
482            Self::Iterator => "[Symbol.iterator]",
483            Self::AsyncIterator => "[Symbol.asyncIterator]",
484            Self::HasInstance => "[Symbol.hasInstance]",
485            Self::IsConcatSpreadable => "[Symbol.isConcatSpreadable]",
486            Self::Match => "[Symbol.match]",
487            Self::MatchAll => "[Symbol.matchAll]",
488            Self::Replace => "[Symbol.replace]",
489            Self::Search => "[Symbol.search]",
490            Self::Split => "[Symbol.split]",
491            Self::Species => "[Symbol.species]",
492            Self::ToPrimitive => "[Symbol.toPrimitive]",
493            Self::ToStringTag => "[Symbol.toStringTag]",
494            Self::Unscopables => "[Symbol.unscopables]",
495            Self::Dispose => "[Symbol.dispose]",
496            Self::AsyncDispose => "[Symbol.asyncDispose]",
497        }
498    }
499
500    /// Parses a property name string into a well-known symbol key.
501    /// Returns `None` if the string is not a well-known symbol property name.
502    pub fn from_property_name(name: &str) -> Option<Self> {
503        match name {
504            "[Symbol.iterator]" => Some(Self::Iterator),
505            "[Symbol.asyncIterator]" => Some(Self::AsyncIterator),
506            "[Symbol.hasInstance]" => Some(Self::HasInstance),
507            "[Symbol.isConcatSpreadable]" => Some(Self::IsConcatSpreadable),
508            "[Symbol.match]" => Some(Self::Match),
509            "[Symbol.matchAll]" => Some(Self::MatchAll),
510            "[Symbol.replace]" => Some(Self::Replace),
511            "[Symbol.search]" => Some(Self::Search),
512            "[Symbol.split]" => Some(Self::Split),
513            "[Symbol.species]" => Some(Self::Species),
514            "[Symbol.toPrimitive]" => Some(Self::ToPrimitive),
515            "[Symbol.toStringTag]" => Some(Self::ToStringTag),
516            "[Symbol.unscopables]" => Some(Self::Unscopables),
517            "[Symbol.dispose]" => Some(Self::Dispose),
518            "[Symbol.asyncDispose]" => Some(Self::AsyncDispose),
519            _ => None,
520        }
521    }
522}
523
524/// The structural "shape" of a type.
525/// This is the key used for interning - structurally identical types
526/// will have the same `TypeData` and therefore the same `TypeId`.
527#[derive(Clone, Debug, PartialEq, Eq, Hash)]
528pub enum TypeData {
529    /// Intrinsic types (any, unknown, never, void, null, undefined, boolean, number, string, bigint, symbol, object)
530    Intrinsic(IntrinsicKind),
531
532    /// Literal types ("hello", 42, true, 123n)
533    Literal(LiteralValue),
534
535    /// Object type with sorted property list for structural identity
536    Object(ObjectShapeId),
537
538    /// Object type with index signatures
539    /// For objects like { [key: string]: number, foo: string }
540    ObjectWithIndex(ObjectShapeId),
541
542    /// Union type (A | B | C)
543    Union(TypeListId),
544
545    /// Intersection type (A & B & C)
546    Intersection(TypeListId),
547
548    /// Array type
549    Array(TypeId),
550
551    /// Tuple type
552    Tuple(TupleListId),
553
554    /// Function type
555    Function(FunctionShapeId),
556
557    /// Callable type with overloaded signatures
558    /// For interfaces with call/construct signatures
559    Callable(CallableShapeId),
560
561    /// Type parameter (generic)
562    TypeParameter(TypeParamInfo),
563
564    /// Bound type parameter using De Bruijn index for alpha-equivalence.
565    ///
566    /// Represents a type parameter relative to the current binding scope.
567    /// Used by the Canonicalizer to achieve alpha-equivalence, where
568    /// `type F<T> = T` and `type G<U> = U` are considered identical.
569    ///
570    /// ## Alpha-Equivalence (Task #32)
571    ///
572    /// When canonicalizing generic types, we replace named type parameters
573    /// with positional indices to achieve structural identity.
574    ///
575    /// ### Example
576    ///
577    /// ```typescript
578    /// type F<T> = { value: T };  // canonicalizes to Object({ value: BoundParameter(0) })
579    /// type G<U> = { value: U };  // also canonicalizes to Object({ value: BoundParameter(0) })
580    /// // Both get the same TypeId because they're structurally identical
581    /// ```
582    ///
583    /// ## De Bruijn Index Semantics
584    ///
585    /// - `BoundParameter(0)` = the most recently bound type parameter
586    /// - `BoundParameter(1)` = the second-most recently bound type parameter
587    /// - `BoundParameter(n)` = the (n+1)th-most recently bound type parameter
588    BoundParameter(u32),
589
590    /// Reference to a named type (interface, class, type alias)
591    /// Uses `SymbolId` to break infinite recursion
592    /// DEPRECATED: Use `Lazy(DefId)` for new code. This is kept for backward compatibility
593    /// during the migration from `SymbolRef` to `DefId`.
594    /// PHASE 4.2: REMOVED - Migration complete, all types now use Lazy(DefId)
595    // Ref(SymbolRef),
596
597    /// Lazy reference to a type definition.
598    ///
599    /// Unlike `Ref(SymbolRef)` which references Binder symbols, `Lazy(DefId)` uses
600    /// Solver-owned identifiers that:
601    /// - Don't require Binder context
602    /// - Support content-addressed hashing for LSP stability
603    /// - Enable Salsa integration for incremental compilation
604    ///
605    /// The type is evaluated lazily when first accessed, resolving to the actual
606    /// type stored in the `DefinitionStore`.
607    ///
608    /// ## Migration
609    ///
610    /// Eventually all `Ref(SymbolRef)` usages will be replaced with `Lazy(DefId)`.
611    Lazy(DefId),
612
613    /// Recursive type reference using De Bruijn index.
614    ///
615    /// Represents a back-reference to a type N levels up the nesting path.
616    /// This is used for canonicalizing recursive types to achieve O(1) equality.
617    ///
618    /// ## Graph Isomorphism (Task #32)
619    ///
620    /// When canonicalizing recursive type aliases, we replace cycles with
621    /// relative De Bruijn indices instead of absolute Lazy references.
622    ///
623    /// ### Example
624    ///
625    /// ```typescript
626    /// type A = { x: A };  // canonicalizes to Object({ x: Recursive(0) })
627    /// type B = { x: B };  // also canonicalizes to Object({ x: Recursive(0) })
628    /// // Both get the same TypeId because they're structurally identical
629    /// ```
630    ///
631    /// ## De Bruijn Index Semantics
632    ///
633    /// - `Recursive(0)` = the current type itself (immediate recursion)
634    /// - `Recursive(1)` = one level up (parent in the nesting chain)
635    /// - `Recursive(n)` = n levels up
636    ///
637    /// ## Nominal vs Structural
638    ///
639    /// This is ONLY used for structural types (type aliases). Nominal types
640    /// (classes, interfaces) preserve their Lazy(DefId) for nominal identity.
641    Recursive(u32),
642
643    /// Enum type with nominal identity and structural member types.
644    ///
645    /// Enums are nominal types - two different enums with the same member types
646    /// are NOT compatible (e.g., `enum E1 { A, B }` is not assignable to `enum E2 { A, B }`).
647    ///
648    /// - `DefId`: The unique identity of the enum (for E1 vs E2 nominal checking)
649    /// - `TypeId`: The structural union of member types (e.g., 0 | 1 for numeric enums),
650    ///   used for assignability to primitives (e.g., E1 assignable to number)
651    Enum(DefId, TypeId),
652
653    /// Generic type application (Base<Args>)
654    Application(TypeApplicationId),
655
656    /// Conditional type (T extends U ? X : Y)
657    Conditional(ConditionalTypeId),
658
659    /// Mapped type ({ [K in Keys]: `ValueType` })
660    Mapped(MappedTypeId),
661
662    /// Index access type (T[K])
663    IndexAccess(TypeId, TypeId),
664
665    /// Template literal type (`hello${string}world`)
666    TemplateLiteral(TemplateLiteralId),
667
668    /// Type query (typeof expression in type position)
669    TypeQuery(SymbolRef),
670
671    /// `KeyOf` type operator (keyof T)
672    KeyOf(TypeId),
673
674    /// Readonly type modifier (readonly T[])
675    ReadonlyType(TypeId),
676
677    /// Unique symbol type
678    UniqueSymbol(SymbolRef),
679
680    /// Infer type (infer R in conditional types)
681    Infer(TypeParamInfo),
682
683    /// This type (polymorphic this)
684    ThisType,
685
686    /// String manipulation intrinsic types
687    /// Uppercase<T>, Lowercase<T>, Capitalize<T>, Uncapitalize<T>
688    StringIntrinsic {
689        kind: StringIntrinsicKind,
690        type_arg: TypeId,
691    },
692
693    /// Module namespace type (import * as ns from "module")
694    /// Uses `SymbolRef` for lazy evaluation to avoid circular dependency issues
695    ModuleNamespace(SymbolRef),
696
697    /// `NoInfer`<T> utility type (TypeScript 5.4+)
698    /// Prevents inference from flowing through this type position.
699    /// During inference, this blocks inference. During evaluation/subtyping,
700    /// it evaluates to the inner type (transparent).
701    NoInfer(TypeId),
702
703    /// Error type for recovery
704    Error,
705}
706
707/// Generic type application (Base<Args>)
708#[derive(Clone, Debug, PartialEq, Eq, Hash)]
709pub struct TypeApplication {
710    pub base: TypeId,
711    pub args: Vec<TypeId>,
712}
713
714/// Intrinsic type kinds
715#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
716pub enum IntrinsicKind {
717    Any,
718    Unknown,
719    Never,
720    Void,
721    Null,
722    Undefined,
723    Boolean,
724    Number,
725    String,
726    Bigint,
727    Symbol,
728    Object,
729    Function,
730}
731
732/// String manipulation intrinsic kinds
733#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
734pub enum StringIntrinsicKind {
735    Uppercase,
736    Lowercase,
737    Capitalize,
738    Uncapitalize,
739}
740
741impl IntrinsicKind {
742    pub const fn to_type_id(self) -> TypeId {
743        match self {
744            Self::Any => TypeId::ANY,
745            Self::Unknown => TypeId::UNKNOWN,
746            Self::Never => TypeId::NEVER,
747            Self::Void => TypeId::VOID,
748            Self::Null => TypeId::NULL,
749            Self::Undefined => TypeId::UNDEFINED,
750            Self::Boolean => TypeId::BOOLEAN,
751            Self::Number => TypeId::NUMBER,
752            Self::String => TypeId::STRING,
753            Self::Bigint => TypeId::BIGINT,
754            Self::Symbol => TypeId::SYMBOL,
755            Self::Object => TypeId::OBJECT,
756            Self::Function => TypeId::FUNCTION,
757        }
758    }
759}
760
761/// Literal values (for literal types)
762#[derive(Clone, Debug, PartialEq, Eq, Hash)]
763pub enum LiteralValue {
764    String(Atom),
765    Number(OrderedFloat),
766    BigInt(Atom),
767    Boolean(bool),
768}
769
770impl LiteralValue {
771    /// Returns the primitive `TypeId` that this literal widens to.
772    ///
773    /// - `String(_)` → `TypeId::STRING`
774    /// - `Number(_)` → `TypeId::NUMBER`
775    /// - `Boolean(_)` → `TypeId::BOOLEAN`
776    /// - `BigInt(_)` → `TypeId::BIGINT`
777    pub const fn primitive_type_id(&self) -> TypeId {
778        match self {
779            Self::String(_) => TypeId::STRING,
780            Self::Number(_) => TypeId::NUMBER,
781            Self::Boolean(_) => TypeId::BOOLEAN,
782            Self::BigInt(_) => TypeId::BIGINT,
783        }
784    }
785}
786
787/// Wrapper for f64 that implements Eq and Hash for use in `TypeData`
788#[derive(Clone, Copy, Debug)]
789pub struct OrderedFloat(pub f64);
790
791impl PartialEq for OrderedFloat {
792    fn eq(&self, other: &Self) -> bool {
793        self.0.to_bits() == other.0.to_bits()
794    }
795}
796
797impl Eq for OrderedFloat {}
798
799impl std::hash::Hash for OrderedFloat {
800    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
801        self.0.to_bits().hash(state);
802    }
803}
804
805/// Visibility modifier for class properties
806#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Default)]
807pub enum Visibility {
808    /// Public property - structural compatibility applies
809    #[default]
810    Public,
811    /// Private property - nominal compatibility only
812    Private,
813    /// Protected property - nominal compatibility only
814    Protected,
815}
816
817/// Property information for object types
818#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
819pub struct PropertyInfo {
820    pub name: Atom,
821    /// Read type (getter/lookup).
822    pub type_id: TypeId,
823    /// Write type (setter/assignment).
824    pub write_type: TypeId,
825    pub optional: bool,
826    pub readonly: bool,
827    pub is_method: bool,
828    /// Visibility modifier for nominal subtyping
829    pub visibility: Visibility,
830    /// Symbol that declared this property (for nominal identity checks)
831    pub parent_id: Option<SymbolId>,
832}
833
834impl PropertyInfo {
835    /// Create a property with default settings (non-optional, non-readonly, public).
836    /// Sets `write_type` equal to `type_id`.
837    pub const fn new(name: Atom, type_id: TypeId) -> Self {
838        Self {
839            name,
840            type_id,
841            write_type: type_id,
842            optional: false,
843            readonly: false,
844            is_method: false,
845            visibility: Visibility::Public,
846            parent_id: None,
847        }
848    }
849
850    /// Create a method property with default settings.
851    pub const fn method(name: Atom, type_id: TypeId) -> Self {
852        Self {
853            is_method: true,
854            ..Self::new(name, type_id)
855        }
856    }
857
858    /// Create an optional property with default settings.
859    pub const fn opt(name: Atom, type_id: TypeId) -> Self {
860        Self {
861            optional: true,
862            ..Self::new(name, type_id)
863        }
864    }
865
866    /// Create a readonly property with default settings.
867    pub const fn readonly(name: Atom, type_id: TypeId) -> Self {
868        Self {
869            readonly: true,
870            ..Self::new(name, type_id)
871        }
872    }
873
874    /// Find a property by name in a slice of properties.
875    pub fn find_in_slice(props: &[Self], name: Atom) -> Option<&Self> {
876        props.iter().find(|p| p.name == name)
877    }
878}
879
880#[derive(Copy, Clone, Debug, PartialEq, Eq)]
881pub enum PropertyLookup {
882    Found(usize),
883    NotFound,
884    Uncached,
885}
886
887/// Index signature information for object types
888/// Represents `{ [key: string]: ValueType }` or `{ [key: number]: ValueType }`
889#[derive(Clone, Debug, PartialEq, Eq, Hash)]
890pub struct IndexSignature {
891    /// The key type (usually string or number)
892    pub key_type: TypeId,
893    /// The value type for all indexed properties
894    pub value_type: TypeId,
895    /// Whether the index signature is readonly
896    pub readonly: bool,
897}
898
899/// Combined index signature information for a type
900/// Provides convenient access to both string and number index signatures
901#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
902pub struct IndexInfo {
903    /// String index signature: { [key: string]: T }
904    pub string_index: Option<IndexSignature>,
905    /// Number index signature: { [key: number]: T }
906    pub number_index: Option<IndexSignature>,
907}
908
909bitflags::bitflags! {
910    #[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug)]
911    pub struct ObjectFlags: u32 {
912        const FRESH_LITERAL = 1 << 0;
913    }
914}
915
916/// Object type with properties and optional index signatures
917///
918/// NOTE: The `symbol` field affects BOTH Hash and `PartialEq` for nominal discrimination.
919/// This ensures that different classes get different `TypeIds` in the interner.
920/// Structural subtyping is computed explicitly in the Solver, not via `PartialEq`.
921#[derive(Clone, Debug)]
922pub struct ObjectShape {
923    /// Object-level flags (e.g. fresh literal tracking).
924    pub flags: ObjectFlags,
925    /// Named properties (sorted by name for consistent hashing)
926    pub properties: Vec<PropertyInfo>,
927    /// String index signature: { [key: string]: T }
928    pub string_index: Option<IndexSignature>,
929    /// Number index signature: { [key: number]: T }
930    pub number_index: Option<IndexSignature>,
931    /// Nominal identity for class instance types (prevents structural interning of distinct classes)
932    pub symbol: Option<tsz_binder::SymbolId>,
933}
934
935impl PartialEq for ObjectShape {
936    fn eq(&self, other: &Self) -> bool {
937        // Include symbol in equality check to ensure different classes get different TypeIds
938        // The Solver does structural subtyping explicitly, not via PartialEq
939        self.flags == other.flags
940            && self.properties == other.properties
941            && self.string_index == other.string_index
942            && self.number_index == other.number_index
943            && self.symbol == other.symbol
944    }
945}
946
947impl Eq for ObjectShape {}
948
949impl std::hash::Hash for ObjectShape {
950    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
951        // Include the `symbol` field in hash for nominal interning
952        // This ensures different classes get different TypeIds
953        self.flags.hash(state);
954        self.properties.hash(state);
955        self.string_index.hash(state);
956        self.number_index.hash(state);
957        self.symbol.hash(state);
958    }
959}
960
961impl Default for ObjectShape {
962    fn default() -> Self {
963        Self {
964            flags: ObjectFlags::empty(),
965            properties: Vec::new(),
966            string_index: None,
967            number_index: None,
968            symbol: None,
969        }
970    }
971}
972
973/// Tuple element information
974#[derive(Clone, Debug, PartialEq, Eq, Hash)]
975pub struct TupleElement {
976    pub type_id: TypeId,
977    pub name: Option<Atom>,
978    pub optional: bool,
979    pub rest: bool,
980}
981
982/// Type predicate information (x is T / asserts x is T).
983#[derive(Clone, Debug, PartialEq, Eq, Hash)]
984pub struct TypePredicate {
985    pub asserts: bool,
986    pub target: TypePredicateTarget,
987    pub type_id: Option<TypeId>,
988    pub parameter_index: Option<usize>,
989}
990
991#[derive(Clone, Debug, PartialEq, Eq, Hash)]
992pub enum TypePredicateTarget {
993    This,
994    Identifier(Atom),
995}
996
997/// Function shape for function types
998#[derive(Clone, Debug, PartialEq, Eq, Hash)]
999pub struct FunctionShape {
1000    pub type_params: Vec<TypeParamInfo>,
1001    pub params: Vec<ParamInfo>,
1002    pub this_type: Option<TypeId>,
1003    pub return_type: TypeId,
1004    pub type_predicate: Option<TypePredicate>,
1005    pub is_constructor: bool,
1006    /// Whether this function is a method (bivariant parameters) vs a standalone function (contravariant when strictFunctionTypes)
1007    pub is_method: bool,
1008}
1009
1010impl FunctionShape {
1011    /// Create a simple function shape with params and return type.
1012    /// No type params, no this, no predicate, not a constructor or method.
1013    pub const fn new(params: Vec<ParamInfo>, return_type: TypeId) -> Self {
1014        Self {
1015            type_params: Vec::new(),
1016            params,
1017            this_type: None,
1018            return_type,
1019            type_predicate: None,
1020            is_constructor: false,
1021            is_method: false,
1022        }
1023    }
1024}
1025
1026/// Call signature for overloaded functions
1027/// Represents a single call signature in an overloaded type
1028#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1029pub struct CallSignature {
1030    pub type_params: Vec<TypeParamInfo>,
1031    pub params: Vec<ParamInfo>,
1032    pub this_type: Option<TypeId>,
1033    pub return_type: TypeId,
1034    pub type_predicate: Option<TypePredicate>,
1035    /// Whether this call signature is from a method (uses bivariant parameter checking).
1036    /// Methods in TypeScript are intentionally bivariant for compatibility reasons.
1037    pub is_method: bool,
1038}
1039
1040impl CallSignature {
1041    /// Create a simple call signature with params and return type.
1042    pub const fn new(params: Vec<ParamInfo>, return_type: TypeId) -> Self {
1043        Self {
1044            type_params: Vec::new(),
1045            params,
1046            this_type: None,
1047            return_type,
1048            type_predicate: None,
1049            is_method: false,
1050        }
1051    }
1052}
1053
1054/// Callable type with multiple overloaded call signatures
1055/// Represents types like:
1056/// ```typescript
1057/// interface Overloaded {
1058///   (x: string): number;
1059///   (x: number): string;
1060/// }
1061/// ```
1062/// NOTE: The `symbol` field affects BOTH Hash and `PartialEq` for nominal discrimination.
1063/// This ensures that different classes get different `TypeIds` in the interner.
1064/// Structural subtyping is computed explicitly in the Solver, not via `PartialEq`.
1065#[derive(Clone, Debug, Default)]
1066pub struct CallableShape {
1067    /// Call signatures (order matters for overload resolution)
1068    pub call_signatures: Vec<CallSignature>,
1069    /// Constructor signatures
1070    pub construct_signatures: Vec<CallSignature>,
1071    /// Optional properties on the callable (e.g., Function.prototype)
1072    pub properties: Vec<PropertyInfo>,
1073    /// String index signature (for static index signatures on classes)
1074    pub string_index: Option<IndexSignature>,
1075    /// Number index signature (for static index signatures on classes)
1076    pub number_index: Option<IndexSignature>,
1077    /// Nominal identity for class constructors (prevents structural interning of distinct classes)
1078    pub symbol: Option<tsz_binder::SymbolId>,
1079}
1080
1081impl PartialEq for CallableShape {
1082    fn eq(&self, other: &Self) -> bool {
1083        // Include symbol in equality check to ensure different classes get different TypeIds
1084        // The Solver does structural subtyping explicitly, not via PartialEq
1085        self.call_signatures == other.call_signatures
1086            && self.construct_signatures == other.construct_signatures
1087            && self.properties == other.properties
1088            && self.string_index == other.string_index
1089            && self.number_index == other.number_index
1090            && self.symbol == other.symbol
1091    }
1092}
1093
1094impl Eq for CallableShape {}
1095
1096impl std::hash::Hash for CallableShape {
1097    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1098        // Include the `symbol` field in hash for nominal interning
1099        // This ensures different classes get different TypeIds
1100        self.call_signatures.hash(state);
1101        self.construct_signatures.hash(state);
1102        self.properties.hash(state);
1103        self.string_index.hash(state);
1104        self.number_index.hash(state);
1105        self.symbol.hash(state);
1106    }
1107}
1108
1109/// Parameter information
1110#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
1111pub struct ParamInfo {
1112    pub name: Option<Atom>,
1113    pub type_id: TypeId,
1114    pub optional: bool,
1115    pub rest: bool,
1116}
1117
1118impl ParamInfo {
1119    /// Create a required parameter.
1120    pub const fn required(name: Atom, type_id: TypeId) -> Self {
1121        Self {
1122            name: Some(name),
1123            type_id,
1124            optional: false,
1125            rest: false,
1126        }
1127    }
1128
1129    /// Create an optional parameter.
1130    pub const fn optional(name: Atom, type_id: TypeId) -> Self {
1131        Self {
1132            optional: true,
1133            ..Self::required(name, type_id)
1134        }
1135    }
1136
1137    /// Create a rest parameter.
1138    pub const fn rest(name: Atom, type_id: TypeId) -> Self {
1139        Self {
1140            rest: true,
1141            ..Self::required(name, type_id)
1142        }
1143    }
1144
1145    /// Create an unnamed required parameter.
1146    pub const fn unnamed(type_id: TypeId) -> Self {
1147        Self {
1148            name: None,
1149            type_id,
1150            optional: false,
1151            rest: false,
1152        }
1153    }
1154}
1155
1156/// Type parameter information
1157#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1158pub struct TypeParamInfo {
1159    pub name: Atom,
1160    pub constraint: Option<TypeId>,
1161    pub default: Option<TypeId>,
1162    /// Whether this is a const type parameter (TS 5.0+)
1163    /// Const type parameters preserve literal types and infer readonly modifiers
1164    pub is_const: bool,
1165}
1166
1167/// Reference to a symbol (for named types)
1168#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1169pub struct SymbolRef(pub u32);
1170
1171/// Conditional type structure
1172#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1173pub struct ConditionalType {
1174    pub check_type: TypeId,
1175    pub extends_type: TypeId,
1176    pub true_type: TypeId,
1177    pub false_type: TypeId,
1178    pub is_distributive: bool,
1179}
1180
1181/// Mapped type structure
1182#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1183pub struct MappedType {
1184    pub type_param: TypeParamInfo,
1185    pub constraint: TypeId,
1186    pub name_type: Option<TypeId>,
1187    pub template: TypeId,
1188    pub readonly_modifier: Option<MappedModifier>,
1189    pub optional_modifier: Option<MappedModifier>,
1190}
1191
1192/// Mapped type modifier (+/-)
1193#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1194pub enum MappedModifier {
1195    Add,
1196    Remove,
1197}
1198
1199/// Template literal span
1200#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1201pub enum TemplateSpan {
1202    Text(Atom),
1203    Type(TypeId),
1204}
1205
1206impl TemplateSpan {
1207    /// Check if this span is a text span
1208    pub const fn is_text(&self) -> bool {
1209        matches!(self, Self::Text(_))
1210    }
1211
1212    /// Check if this span is a type interpolation
1213    pub const fn is_type(&self) -> bool {
1214        matches!(self, Self::Type(_))
1215    }
1216
1217    /// Get the text content if this is a text span
1218    pub const fn as_text(&self) -> Option<Atom> {
1219        match self {
1220            Self::Text(atom) => Some(*atom),
1221            _ => None,
1222        }
1223    }
1224
1225    /// Get the type ID if this is a type span
1226    pub const fn as_type(&self) -> Option<TypeId> {
1227        match self {
1228            Self::Type(type_id) => Some(*type_id),
1229            _ => None,
1230        }
1231    }
1232
1233    /// Create a type span
1234    pub const fn type_from_id(type_id: TypeId) -> Self {
1235        Self::Type(type_id)
1236    }
1237}
1238
1239/// Process escape sequences in a template literal string
1240/// Handles: \${, \\, \n, \r, \t, \b, \f, \v, \0, \xXX, \uXXXX, \u{X...}
1241pub fn process_template_escape_sequences(input: &str) -> String {
1242    let mut result = String::with_capacity(input.len());
1243    let mut chars = input.chars();
1244    let mut last_was_backslash = false;
1245
1246    while let Some(c) = chars.next() {
1247        if last_was_backslash {
1248            last_was_backslash = false;
1249            match c {
1250                '$' => {
1251                    // \$${ becomes $ (not an interpolation)
1252                    result.push('$');
1253                }
1254                '\\' => result.push('\\'),
1255                'n' => result.push('\n'),
1256                'r' => result.push('\r'),
1257                't' => result.push('\t'),
1258                'b' => result.push('\x08'),
1259                'f' => result.push('\x0c'),
1260                'v' => result.push('\x0b'),
1261                '0' => result.push('\0'),
1262                'x' => {
1263                    // \xXX - exactly 2 hex digits
1264                    let hex1 = chars.next().unwrap_or('0');
1265                    let hex2 = chars.next().unwrap_or('0');
1266                    let code = u8::from_str_radix(&format!("{hex1}{hex2}"), 16).unwrap_or(0);
1267                    result.push(code as char);
1268                }
1269                'u' => {
1270                    // \uXXXX or \u{X...}
1271                    if let Some('{') = chars.next() {
1272                        // \u{X...} - Unicode code point
1273                        let mut code_str = String::new();
1274                        for nc in chars.by_ref() {
1275                            if nc == '}' {
1276                                break;
1277                            }
1278                            code_str.push(nc);
1279                        }
1280                        if let Ok(code) = u32::from_str_radix(&code_str, 16)
1281                            && let Some(c) = char::from_u32(code)
1282                        {
1283                            result.push(c);
1284                        }
1285                    } else {
1286                        // \uXXXX - exactly 4 hex digits
1287                        let mut code_str = String::new();
1288                        for _ in 0..4 {
1289                            if let Some(nc) = chars.next() {
1290                                code_str.push(nc);
1291                            }
1292                        }
1293                        if let Ok(code) = u16::from_str_radix(&code_str, 16)
1294                            && let Some(c) = char::from_u32(code as u32)
1295                        {
1296                            result.push(c);
1297                        }
1298                    }
1299                }
1300                _ => {
1301                    // Unknown escape - preserve the backslash and character
1302                    result.push('\\');
1303                    result.push(c);
1304                }
1305            }
1306        } else if c == '\\' {
1307            last_was_backslash = true;
1308        } else {
1309            result.push(c);
1310        }
1311    }
1312
1313    // Handle trailing backslash
1314    if last_was_backslash {
1315        result.push('\\');
1316    }
1317
1318    result
1319}
1320
1321/// Returns true if the type name corresponds to a built-in type that should
1322/// be represented structurally or intrinsically, rather than by reference.
1323///
1324/// ## Built-in vs Referenced Types
1325///
1326/// **Built-in types** (managed by the compiler) are represented directly by their
1327/// structure (e.g., `TypeData::Array`) rather than by symbol reference (`TypeData::Ref`).
1328/// This ensures canonicalization: `Array<number>` and `number[]` resolve to the same type.
1329///
1330/// **Referenced types** (user-defined and lib types) are represented as `TypeData::Ref(symbol_id)`
1331/// and resolved lazily during type checking through the `TypeEnvironment`.
1332///
1333/// ## Examples
1334///
1335/// - `Array<T>` → `TypeData::Array(T)` (structural, not `Ref`)
1336/// - `Uppercase<S>` → `TypeData::StringIntrinsic { kind: Uppercase, ... }`
1337/// - `MyInterface` → `TypeData::Ref(SymbolRef(sym_id))`
1338///
1339/// ## When to Add Types
1340///
1341/// Add a type to this list if:
1342/// 1. It has special structural representation in `TypeData` (e.g., `Array`)
1343/// 2. It is a compiler intrinsic (e.g., `Uppercase`, `Lowercase`)
1344/// 3. It needs canonicalization with alternative syntax (e.g., `T[]` vs `Array<T>`)
1345///
1346/// **DO NOT** add:
1347/// - Regular lib types like `Promise`, `Map`, `Set` (these use `Ref`)
1348/// - User-defined interfaces or type aliases
1349pub fn is_compiler_managed_type(name: &str) -> bool {
1350    matches!(
1351        name,
1352        "Array" |          // Canonicalizes with T[] syntax
1353        "ReadonlyArray" |   // Built-in readonly array type
1354        "Uppercase" |       // String intrinsic
1355        "Lowercase" |       // String intrinsic
1356        "Capitalize" |      // String intrinsic
1357        "Uncapitalize" // String intrinsic
1358    )
1359}
1360
1361// =============================================================================
1362// Variance Types (Task #41)
1363// =============================================================================
1364
1365bitflags::bitflags! {
1366    /// Variance of a type parameter in a generic type.
1367    ///
1368    /// Variance determines how subtyping of generic types relates to subtyping
1369    /// of their type arguments. This is critical for O(1) generic assignability.
1370    ///
1371    /// ## Variance Kinds
1372    ///
1373    /// - **Covariant** (COVARIANT): T<U> <: T<V> iff U <: V
1374    ///   - Example: `Array`, `ReadonlyArray`, `Promise`
1375    /// - Most common for immutable containers
1376    ///
1377    /// - **Contravariant** (CONTRAVARIANT): T<U> <: T<V> iff V <: U (reversed)
1378    ///   - Example: Function parameters (in strict mode)
1379    /// - Rare in practice, mostly for function types
1380    ///
1381    /// - **Invariant** (COVARIANT | CONTRAVARIANT): T<U> <: T<V> iff U === V
1382    ///   - Example: Mutable properties, `Box<T>` with read/write
1383    /// - Requires both directions to hold
1384    ///
1385    /// - **Independent** (empty): Type parameter not used in variance position
1386    ///   - Example: Type parameter only used in non-variance positions
1387    /// - Can be skipped in subtype checks (always compatible)
1388    ///
1389    /// ## Examples
1390    ///
1391    /// ```typescript
1392    /// // Covariant: Array< Dog > <: Array< Animal >
1393    /// type Covariant<T> = { readonly get(): T };
1394    ///
1395    /// // Contravariant: Writer< Animal > <: Writer< Dog >
1396    /// type Contravariant<T> = { write(x: T): void };
1397    ///
1398    /// // Invariant: Box<Dog> NOT <: Box<Animal> (mutable!)
1399    /// type Invariant<T> = { get(): T; set(x: T): void };
1400    /// ```
1401    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
1402    pub struct Variance: u8 {
1403        /// Covariant position (e.g., function return types)
1404        const COVARIANT = 1 << 0;
1405        /// Contravariant position (e.g., function parameters)
1406        const CONTRAVARIANT = 1 << 1;
1407    }
1408}
1409
1410impl Variance {
1411    /// Check if this is an independent type parameter (not used in variance position).
1412    pub const fn is_independent(&self) -> bool {
1413        self.is_empty()
1414    }
1415
1416    /// Check if this is covariant only.
1417    pub const fn is_covariant(&self) -> bool {
1418        self.contains(Self::COVARIANT) && !self.contains(Self::CONTRAVARIANT)
1419    }
1420
1421    /// Check if this is contravariant only.
1422    pub const fn is_contravariant(&self) -> bool {
1423        self.contains(Self::CONTRAVARIANT) && !self.contains(Self::COVARIANT)
1424    }
1425
1426    /// Check if this is invariant (both covariant and contravariant).
1427    pub fn is_invariant(&self) -> bool {
1428        self.contains(Self::COVARIANT | Self::CONTRAVARIANT)
1429    }
1430
1431    /// Compose two variances (for nested generics).
1432    ///
1433    /// Rules:
1434    /// - Independent × anything = Independent
1435    /// - Covariant × Covariant = Covariant
1436    /// - Covariant × Contravariant = Contravariant
1437    /// - Contravariant × Covariant = Contravariant
1438    /// - Contravariant × Contravariant = Covariant
1439    /// - Invariant × anything = Invariant
1440    pub fn compose(&self, other: Self) -> Self {
1441        if self.is_invariant() || other.is_invariant() {
1442            return Self::COVARIANT | Self::CONTRAVARIANT;
1443        }
1444        if self.is_independent() || other.is_independent() {
1445            return Self::empty();
1446        }
1447
1448        // XOR for covariance composition
1449        let is_covariant = self.is_covariant() == other.is_covariant();
1450        let is_contravariant = !is_covariant;
1451
1452        let mut result = Self::empty();
1453        if is_covariant {
1454            result |= Self::COVARIANT;
1455        }
1456        if is_contravariant {
1457            result |= Self::CONTRAVARIANT;
1458        }
1459        result
1460    }
1461}
1462
1463#[cfg(test)]
1464#[path = "../tests/types_tests.rs"]
1465mod tests;