Skip to main content

tsz_solver/
db.rs

1//! Type database abstraction for the solver.
2//!
3//! This trait isolates solver logic from concrete storage so we can
4//! swap in a query system (e.g., Salsa) without touching core logic.
5
6use crate::ObjectLiteralBuilder;
7use crate::def::DefId;
8use crate::element_access::{ElementAccessEvaluator, ElementAccessResult};
9use crate::intern::TypeInterner;
10use crate::narrowing;
11use crate::operations_property::PropertyAccessResult;
12use crate::subtype::TypeResolver;
13use crate::type_factory::TypeFactory;
14use crate::types::{
15    CallableShape, CallableShapeId, ConditionalType, ConditionalTypeId, FunctionShape,
16    FunctionShapeId, IndexInfo, IntrinsicKind, MappedType, MappedTypeId, ObjectFlags, ObjectShape,
17    ObjectShapeId, PropertyInfo, PropertyLookup, RelationCacheKey, StringIntrinsicKind, SymbolRef,
18    TemplateLiteralId, TemplateSpan, TupleElement, TupleListId, TypeApplication, TypeApplicationId,
19    TypeData, TypeId, TypeListId, TypeParamInfo, Variance,
20};
21use rustc_hash::{FxHashMap, FxHashSet};
22use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
23use std::sync::{Arc, RwLock};
24use tsz_binder::SymbolId;
25use tsz_common::interner::Atom;
26
27/// Query interface for the solver.
28///
29/// This keeps solver components generic and prevents them from reaching
30/// into concrete storage structures directly.
31pub trait TypeDatabase {
32    fn intern(&self, key: TypeData) -> TypeId;
33    fn lookup(&self, id: TypeId) -> Option<TypeData>;
34    fn intern_string(&self, s: &str) -> Atom;
35    fn resolve_atom(&self, atom: Atom) -> String;
36    fn resolve_atom_ref(&self, atom: Atom) -> Arc<str>;
37    fn type_list(&self, id: TypeListId) -> Arc<[TypeId]>;
38    fn tuple_list(&self, id: TupleListId) -> Arc<[TupleElement]>;
39    fn template_list(&self, id: TemplateLiteralId) -> Arc<[TemplateSpan]>;
40    fn object_shape(&self, id: ObjectShapeId) -> Arc<ObjectShape>;
41    fn object_property_index(&self, shape_id: ObjectShapeId, name: Atom) -> PropertyLookup;
42    fn function_shape(&self, id: FunctionShapeId) -> Arc<FunctionShape>;
43    fn callable_shape(&self, id: CallableShapeId) -> Arc<CallableShape>;
44    fn conditional_type(&self, id: ConditionalTypeId) -> Arc<ConditionalType>;
45    fn mapped_type(&self, id: MappedTypeId) -> Arc<MappedType>;
46    fn type_application(&self, id: TypeApplicationId) -> Arc<TypeApplication>;
47
48    fn literal_string(&self, value: &str) -> TypeId;
49    fn literal_number(&self, value: f64) -> TypeId;
50    fn literal_boolean(&self, value: bool) -> TypeId;
51    fn literal_bigint(&self, value: &str) -> TypeId;
52    fn literal_bigint_with_sign(&self, negative: bool, digits: &str) -> TypeId;
53
54    fn union(&self, members: Vec<TypeId>) -> TypeId;
55    fn union_from_sorted_vec(&self, flat: Vec<TypeId>) -> TypeId;
56    fn union2(&self, left: TypeId, right: TypeId) -> TypeId;
57    fn union3(&self, first: TypeId, second: TypeId, third: TypeId) -> TypeId;
58    fn intersection(&self, members: Vec<TypeId>) -> TypeId;
59    fn intersection2(&self, left: TypeId, right: TypeId) -> TypeId;
60    /// Raw intersection without normalization (used to avoid infinite recursion)
61    fn intersect_types_raw2(&self, left: TypeId, right: TypeId) -> TypeId;
62    fn array(&self, element: TypeId) -> TypeId;
63    fn tuple(&self, elements: Vec<TupleElement>) -> TypeId;
64    fn object(&self, properties: Vec<PropertyInfo>) -> TypeId;
65    fn object_with_flags(&self, properties: Vec<PropertyInfo>, flags: ObjectFlags) -> TypeId;
66    fn object_with_flags_and_symbol(
67        &self,
68        properties: Vec<PropertyInfo>,
69        flags: ObjectFlags,
70        symbol: Option<SymbolId>,
71    ) -> TypeId;
72    fn object_fresh(&self, properties: Vec<PropertyInfo>) -> TypeId {
73        self.object_with_flags(properties, ObjectFlags::FRESH_LITERAL)
74    }
75    fn object_with_index(&self, shape: ObjectShape) -> TypeId;
76    fn function(&self, shape: FunctionShape) -> TypeId;
77    fn callable(&self, shape: CallableShape) -> TypeId;
78    fn template_literal(&self, spans: Vec<TemplateSpan>) -> TypeId;
79    fn conditional(&self, conditional: ConditionalType) -> TypeId;
80    fn mapped(&self, mapped: MappedType) -> TypeId;
81    fn reference(&self, symbol: SymbolRef) -> TypeId;
82    fn lazy(&self, def_id: DefId) -> TypeId;
83    fn bound_parameter(&self, index: u32) -> TypeId;
84    fn recursive(&self, depth: u32) -> TypeId;
85    fn type_param(&self, info: TypeParamInfo) -> TypeId;
86    fn type_query(&self, symbol: SymbolRef) -> TypeId;
87    fn enum_type(&self, def_id: DefId, structural_type: TypeId) -> TypeId;
88    fn application(&self, base: TypeId, args: Vec<TypeId>) -> TypeId;
89
90    fn literal_string_atom(&self, atom: Atom) -> TypeId;
91    fn union_preserve_members(&self, members: Vec<TypeId>) -> TypeId;
92    fn readonly_type(&self, inner: TypeId) -> TypeId;
93    fn keyof(&self, inner: TypeId) -> TypeId;
94    fn index_access(&self, object_type: TypeId, index_type: TypeId) -> TypeId;
95    fn this_type(&self) -> TypeId;
96    fn no_infer(&self, inner: TypeId) -> TypeId;
97    fn unique_symbol(&self, symbol: SymbolRef) -> TypeId;
98    fn infer(&self, info: TypeParamInfo) -> TypeId;
99    fn string_intrinsic(&self, kind: StringIntrinsicKind, type_arg: TypeId) -> TypeId;
100
101    /// Get the base class type for a symbol (class/interface).
102    /// Returns the `TypeId` of the extends clause, or None if the symbol doesn't extend anything.
103    /// This is used by the BCT algorithm to find common base classes.
104    fn get_class_base_type(&self, symbol_id: SymbolId) -> Option<TypeId>;
105
106    /// Check if a type is a "unit type" (represents exactly one value).
107    /// Unit types include literals, enum members, unique symbols, null, undefined, void, never,
108    /// and tuples composed entirely of unit types.
109    /// Results are cached for O(1) lookup after first computation.
110    fn is_unit_type(&self, type_id: TypeId) -> bool;
111}
112
113impl TypeDatabase for TypeInterner {
114    fn intern(&self, key: TypeData) -> TypeId {
115        Self::intern(self, key)
116    }
117
118    fn lookup(&self, id: TypeId) -> Option<TypeData> {
119        Self::lookup(self, id)
120    }
121
122    fn intern_string(&self, s: &str) -> Atom {
123        Self::intern_string(self, s)
124    }
125
126    fn resolve_atom(&self, atom: Atom) -> String {
127        Self::resolve_atom(self, atom)
128    }
129
130    fn resolve_atom_ref(&self, atom: Atom) -> Arc<str> {
131        Self::resolve_atom_ref(self, atom)
132    }
133
134    fn type_list(&self, id: TypeListId) -> Arc<[TypeId]> {
135        Self::type_list(self, id)
136    }
137
138    fn tuple_list(&self, id: TupleListId) -> Arc<[TupleElement]> {
139        Self::tuple_list(self, id)
140    }
141
142    fn template_list(&self, id: TemplateLiteralId) -> Arc<[TemplateSpan]> {
143        Self::template_list(self, id)
144    }
145
146    fn object_shape(&self, id: ObjectShapeId) -> Arc<ObjectShape> {
147        Self::object_shape(self, id)
148    }
149
150    fn object_property_index(&self, shape_id: ObjectShapeId, name: Atom) -> PropertyLookup {
151        Self::object_property_index(self, shape_id, name)
152    }
153
154    fn function_shape(&self, id: FunctionShapeId) -> Arc<FunctionShape> {
155        Self::function_shape(self, id)
156    }
157
158    fn callable_shape(&self, id: CallableShapeId) -> Arc<CallableShape> {
159        Self::callable_shape(self, id)
160    }
161
162    fn conditional_type(&self, id: ConditionalTypeId) -> Arc<ConditionalType> {
163        Self::conditional_type(self, id)
164    }
165
166    fn mapped_type(&self, id: MappedTypeId) -> Arc<MappedType> {
167        Self::mapped_type(self, id)
168    }
169
170    fn type_application(&self, id: TypeApplicationId) -> Arc<TypeApplication> {
171        Self::type_application(self, id)
172    }
173
174    fn literal_string(&self, value: &str) -> TypeId {
175        Self::literal_string(self, value)
176    }
177
178    fn literal_number(&self, value: f64) -> TypeId {
179        Self::literal_number(self, value)
180    }
181
182    fn literal_boolean(&self, value: bool) -> TypeId {
183        Self::literal_boolean(self, value)
184    }
185
186    fn literal_bigint(&self, value: &str) -> TypeId {
187        Self::literal_bigint(self, value)
188    }
189
190    fn literal_bigint_with_sign(&self, negative: bool, digits: &str) -> TypeId {
191        Self::literal_bigint_with_sign(self, negative, digits)
192    }
193
194    fn union(&self, members: Vec<TypeId>) -> TypeId {
195        Self::union(self, members)
196    }
197
198    fn union_from_sorted_vec(&self, flat: Vec<TypeId>) -> TypeId {
199        Self::union_from_sorted_vec(self, flat)
200    }
201
202    fn union2(&self, left: TypeId, right: TypeId) -> TypeId {
203        Self::union2(self, left, right)
204    }
205
206    fn union3(&self, first: TypeId, second: TypeId, third: TypeId) -> TypeId {
207        Self::union3(self, first, second, third)
208    }
209
210    fn intersection(&self, members: Vec<TypeId>) -> TypeId {
211        Self::intersection(self, members)
212    }
213
214    fn intersection2(&self, left: TypeId, right: TypeId) -> TypeId {
215        Self::intersection2(self, left, right)
216    }
217
218    fn intersect_types_raw2(&self, left: TypeId, right: TypeId) -> TypeId {
219        Self::intersect_types_raw2(self, left, right)
220    }
221
222    fn array(&self, element: TypeId) -> TypeId {
223        Self::array(self, element)
224    }
225
226    fn tuple(&self, elements: Vec<TupleElement>) -> TypeId {
227        Self::tuple(self, elements)
228    }
229
230    fn object(&self, properties: Vec<PropertyInfo>) -> TypeId {
231        Self::object(self, properties)
232    }
233
234    fn object_with_flags(&self, properties: Vec<PropertyInfo>, flags: ObjectFlags) -> TypeId {
235        Self::object_with_flags(self, properties, flags)
236    }
237
238    fn object_with_flags_and_symbol(
239        &self,
240        properties: Vec<PropertyInfo>,
241        flags: ObjectFlags,
242        symbol: Option<SymbolId>,
243    ) -> TypeId {
244        Self::object_with_flags_and_symbol(self, properties, flags, symbol)
245    }
246
247    fn object_with_index(&self, shape: ObjectShape) -> TypeId {
248        Self::object_with_index(self, shape)
249    }
250
251    fn function(&self, shape: FunctionShape) -> TypeId {
252        Self::function(self, shape)
253    }
254
255    fn callable(&self, shape: CallableShape) -> TypeId {
256        Self::callable(self, shape)
257    }
258
259    fn template_literal(&self, spans: Vec<TemplateSpan>) -> TypeId {
260        Self::template_literal(self, spans)
261    }
262
263    fn conditional(&self, conditional: ConditionalType) -> TypeId {
264        Self::conditional(self, conditional)
265    }
266
267    fn mapped(&self, mapped: MappedType) -> TypeId {
268        Self::mapped(self, mapped)
269    }
270
271    fn reference(&self, symbol: SymbolRef) -> TypeId {
272        Self::reference(self, symbol)
273    }
274
275    fn lazy(&self, def_id: DefId) -> TypeId {
276        Self::lazy(self, def_id)
277    }
278
279    fn bound_parameter(&self, index: u32) -> TypeId {
280        Self::bound_parameter(self, index)
281    }
282
283    fn recursive(&self, depth: u32) -> TypeId {
284        Self::recursive(self, depth)
285    }
286
287    fn type_param(&self, info: TypeParamInfo) -> TypeId {
288        Self::type_param(self, info)
289    }
290
291    fn type_query(&self, symbol: SymbolRef) -> TypeId {
292        Self::type_query(self, symbol)
293    }
294
295    fn enum_type(&self, def_id: DefId, structural_type: TypeId) -> TypeId {
296        Self::enum_type(self, def_id, structural_type)
297    }
298
299    fn application(&self, base: TypeId, args: Vec<TypeId>) -> TypeId {
300        Self::application(self, base, args)
301    }
302
303    fn literal_string_atom(&self, atom: Atom) -> TypeId {
304        Self::literal_string_atom(self, atom)
305    }
306
307    fn union_preserve_members(&self, members: Vec<TypeId>) -> TypeId {
308        Self::union_preserve_members(self, members)
309    }
310
311    fn readonly_type(&self, inner: TypeId) -> TypeId {
312        Self::readonly_type(self, inner)
313    }
314
315    fn keyof(&self, inner: TypeId) -> TypeId {
316        Self::keyof(self, inner)
317    }
318
319    fn index_access(&self, object_type: TypeId, index_type: TypeId) -> TypeId {
320        Self::index_access(self, object_type, index_type)
321    }
322
323    fn this_type(&self) -> TypeId {
324        Self::this_type(self)
325    }
326
327    fn no_infer(&self, inner: TypeId) -> TypeId {
328        Self::no_infer(self, inner)
329    }
330
331    fn unique_symbol(&self, symbol: SymbolRef) -> TypeId {
332        Self::unique_symbol(self, symbol)
333    }
334
335    fn infer(&self, info: TypeParamInfo) -> TypeId {
336        Self::infer(self, info)
337    }
338
339    fn string_intrinsic(&self, kind: StringIntrinsicKind, type_arg: TypeId) -> TypeId {
340        Self::string_intrinsic(self, kind, type_arg)
341    }
342
343    fn get_class_base_type(&self, _symbol_id: SymbolId) -> Option<TypeId> {
344        // TypeInterner doesn't have access to the Binder, so it can't resolve base classes.
345        // The Checker will override this to provide the actual implementation.
346        None
347    }
348
349    fn is_unit_type(&self, type_id: TypeId) -> bool {
350        Self::is_unit_type(self, type_id)
351    }
352}
353
354/// Implement `TypeResolver` for `TypeInterner` with default noop implementations.
355///
356/// `TypeInterner` doesn't have access to the Binder or type environment,
357/// so it cannot resolve symbol references or `DefIds`. This implementation
358/// returns None for all resolution operations, which is the correct behavior
359/// for contexts that don't have access to type binding information.
360impl TypeResolver for TypeInterner {
361    fn resolve_ref(&self, _symbol: SymbolRef, _interner: &dyn TypeDatabase) -> Option<TypeId> {
362        None
363    }
364
365    fn resolve_lazy(&self, _def_id: DefId, _interner: &dyn TypeDatabase) -> Option<TypeId> {
366        None
367    }
368
369    fn get_type_params(&self, _symbol: SymbolRef) -> Option<Vec<TypeParamInfo>> {
370        None
371    }
372
373    fn get_lazy_type_params(&self, _def_id: DefId) -> Option<Vec<TypeParamInfo>> {
374        None
375    }
376
377    fn def_to_symbol_id(&self, _def_id: DefId) -> Option<SymbolId> {
378        None
379    }
380
381    fn symbol_to_def_id(&self, _symbol: SymbolRef) -> Option<DefId> {
382        None
383    }
384
385    fn get_boxed_type(&self, kind: IntrinsicKind) -> Option<TypeId> {
386        TypeInterner::get_boxed_type(self, kind)
387    }
388
389    fn get_array_base_type(&self) -> Option<TypeId> {
390        self.get_array_base_type()
391    }
392
393    fn get_array_base_type_params(&self) -> &[TypeParamInfo] {
394        self.get_array_base_type_params()
395    }
396}
397
398/// Query layer for higher-level solver operations.
399///
400/// This is the incremental boundary where caching and (future) salsa hooks live.
401/// Inherits from `TypeResolver` to enable Lazy/Ref type resolution through `evaluate_type()`.
402pub trait QueryDatabase: TypeDatabase + TypeResolver {
403    /// Expose the underlying `TypeDatabase` view for legacy entry points.
404    fn as_type_database(&self) -> &dyn TypeDatabase;
405
406    /// Expose the checked construction surface for type constructors.
407    #[inline]
408    fn factory(&self) -> TypeFactory<'_> {
409        TypeFactory::new(self.as_type_database())
410    }
411
412    /// Register the canonical `Array<T>` base type used by property access resolution.
413    ///
414    /// Some call paths resolve properties through a `TypeInterner`-backed database,
415    /// while others use a `TypeEnvironment`-backed resolver. Implementations should
416    /// store this in whichever backing stores they use so `T[]` methods/properties
417    /// (e.g. `push`, `length`) resolve consistently.
418    fn register_array_base_type(&self, _type_id: TypeId, _type_params: Vec<TypeParamInfo>) {}
419
420    /// Register a boxed interface type for a primitive intrinsic kind.
421    ///
422    /// Similar to `register_array_base_type`, this ensures that property access
423    /// resolution can find the correct interface type (e.g., String, Number) for
424    /// primitive types, regardless of which database backend is used.
425    fn register_boxed_type(&self, _kind: IntrinsicKind, _type_id: TypeId) {}
426
427    fn evaluate_conditional(&self, cond: &ConditionalType) -> TypeId {
428        crate::evaluate::evaluate_conditional(self.as_type_database(), cond)
429    }
430
431    fn evaluate_index_access(&self, object_type: TypeId, index_type: TypeId) -> TypeId {
432        self.evaluate_index_access_with_options(
433            object_type,
434            index_type,
435            self.no_unchecked_indexed_access(),
436        )
437    }
438
439    fn evaluate_index_access_with_options(
440        &self,
441        object_type: TypeId,
442        index_type: TypeId,
443        no_unchecked_indexed_access: bool,
444    ) -> TypeId {
445        crate::evaluate::evaluate_index_access_with_options(
446            self.as_type_database(),
447            object_type,
448            index_type,
449            no_unchecked_indexed_access,
450        )
451    }
452
453    fn evaluate_type(&self, type_id: TypeId) -> TypeId {
454        crate::evaluate::evaluate_type(self.as_type_database(), type_id)
455    }
456
457    fn evaluate_type_with_options(
458        &self,
459        type_id: TypeId,
460        no_unchecked_indexed_access: bool,
461    ) -> TypeId {
462        if !no_unchecked_indexed_access {
463            return self.evaluate_type(type_id);
464        }
465
466        let mut evaluator = crate::evaluate::TypeEvaluator::new(self.as_type_database());
467        evaluator.set_no_unchecked_indexed_access(no_unchecked_indexed_access);
468        evaluator.evaluate(type_id)
469    }
470
471    fn evaluate_mapped(&self, mapped: &MappedType) -> TypeId {
472        crate::evaluate::evaluate_mapped(self.as_type_database(), mapped)
473    }
474
475    /// Look up a shared cache entry for evaluated generic applications.
476    fn lookup_application_eval_cache(
477        &self,
478        _def_id: DefId,
479        _args: &[TypeId],
480        _no_unchecked_indexed_access: bool,
481    ) -> Option<TypeId> {
482        None
483    }
484
485    /// Store an evaluated generic application result in the shared cache.
486    fn insert_application_eval_cache(
487        &self,
488        _def_id: DefId,
489        _args: &[TypeId],
490        _no_unchecked_indexed_access: bool,
491        _result: TypeId,
492    ) {
493    }
494
495    fn evaluate_keyof(&self, operand: TypeId) -> TypeId {
496        crate::evaluate::evaluate_keyof(self.as_type_database(), operand)
497    }
498
499    fn narrow(&self, type_id: TypeId, narrower: TypeId) -> TypeId
500    where
501        Self: Sized,
502    {
503        crate::narrowing::NarrowingContext::new(self).narrow(type_id, narrower)
504    }
505
506    fn resolve_property_access(
507        &self,
508        object_type: TypeId,
509        prop_name: &str,
510    ) -> crate::operations_property::PropertyAccessResult;
511
512    fn resolve_property_access_with_options(
513        &self,
514        object_type: TypeId,
515        prop_name: &str,
516        no_unchecked_indexed_access: bool,
517    ) -> crate::operations_property::PropertyAccessResult;
518
519    fn property_access_type(
520        &self,
521        object_type: TypeId,
522        prop_name: &str,
523    ) -> crate::operations_property::PropertyAccessResult {
524        self.resolve_property_access_with_options(
525            object_type,
526            prop_name,
527            self.no_unchecked_indexed_access(),
528        )
529    }
530
531    fn no_unchecked_indexed_access(&self) -> bool {
532        false
533    }
534
535    fn set_no_unchecked_indexed_access(&self, _enabled: bool) {}
536
537    fn contextual_property_type(&self, expected: TypeId, prop_name: &str) -> Option<TypeId> {
538        let ctx = crate::ContextualTypeContext::with_expected(self.as_type_database(), expected);
539        ctx.get_property_type(prop_name)
540    }
541
542    fn is_property_readonly(&self, object_type: TypeId, prop_name: &str) -> bool {
543        crate::operations_property::property_is_readonly(
544            self.as_type_database(),
545            object_type,
546            prop_name,
547        )
548    }
549
550    fn is_readonly_index_signature(
551        &self,
552        object_type: TypeId,
553        wants_string: bool,
554        wants_number: bool,
555    ) -> bool {
556        crate::operations_property::is_readonly_index_signature(
557            self.as_type_database(),
558            object_type,
559            wants_string,
560            wants_number,
561        )
562    }
563
564    /// Resolve element access (array/tuple indexing) with detailed error reporting
565    fn resolve_element_access(
566        &self,
567        object_type: TypeId,
568        index_type: TypeId,
569        literal_index: Option<usize>,
570    ) -> ElementAccessResult {
571        let evaluator = ElementAccessEvaluator::new(self.as_type_database());
572        evaluator.resolve_element_access(object_type, index_type, literal_index)
573    }
574
575    /// Resolve element access type with cache-friendly error normalization.
576    fn resolve_element_access_type(
577        &self,
578        object_type: TypeId,
579        index_type: TypeId,
580        literal_index: Option<usize>,
581    ) -> TypeId {
582        match self.resolve_element_access(object_type, index_type, literal_index) {
583            crate::element_access::ElementAccessResult::Success(type_id) => type_id,
584            _ => TypeId::ERROR,
585        }
586    }
587
588    /// Collect properties that can be spread into object literals.
589    fn collect_object_spread_properties(&self, spread_type: TypeId) -> Vec<PropertyInfo> {
590        let builder = ObjectLiteralBuilder::new(self.as_type_database());
591        builder.collect_spread_properties(spread_type)
592    }
593
594    /// Get index signatures for a type
595    fn get_index_signatures(&self, type_id: TypeId) -> IndexInfo;
596
597    /// Check if a type contains null or undefined
598    fn is_nullish_type(&self, type_id: TypeId) -> bool;
599
600    /// Remove null and undefined from a type
601    fn remove_nullish(&self, type_id: TypeId) -> TypeId;
602
603    /// Get the canonical `TypeId` for a type, achieving O(1) structural identity checks.
604    ///
605    /// This memoizes the Canonicalizer output so that structurally identical types
606    /// (e.g., `type A = Box<Box<string>>` and `type B = Box<Box<string>>`) return
607    /// the same canonical `TypeId`.
608    ///
609    /// The implementation must:
610    /// - Use a fresh Canonicalizer with empty stacks (for absolute De Bruijn indices)
611    /// - Only expand `TypeAlias` (`DefKind::TypeAlias`), preserving nominal types
612    /// - Cache the result for O(1) subsequent lookups
613    ///
614    /// Task #49: Global Canonical Mapping
615    fn canonical_id(&self, type_id: TypeId) -> TypeId;
616
617    /// Subtype check with compiler flags.
618    ///
619    /// The `flags` parameter is a packed u16 bitmask matching `RelationCacheKey.flags`:
620    /// - bit 0: `strict_null_checks`
621    /// - bit 1: `strict_function_types`
622    /// - bit 2: `exact_optional_property_types`
623    /// - bit 3: `no_unchecked_indexed_access`
624    /// - bit 4: `disable_method_bivariance`
625    /// - bit 5: `allow_void_return`
626    /// - bit 6: `allow_bivariant_rest`
627    /// - bit 7: `allow_bivariant_param_count`
628    fn is_subtype_of(&self, source: TypeId, target: TypeId) -> bool {
629        // Default implementation: use non-strict mode for backward compatibility
630        // Individual callers can use is_subtype_of_with_flags for explicit flag control
631        self.is_subtype_of_with_flags(source, target, 0)
632    }
633
634    /// Subtype check with explicit compiler flags.
635    ///
636    /// The `flags` parameter is a packed u16 bitmask matching `RelationCacheKey.flags`.
637    fn is_subtype_of_with_flags(&self, source: TypeId, target: TypeId, flags: u16) -> bool {
638        // Default implementation: use SubtypeChecker with default flags
639        // (This will be overridden by QueryCache with proper caching)
640        crate::subtype::is_subtype_of_with_flags(self.as_type_database(), source, target, flags)
641    }
642
643    /// TypeScript assignability check with full compatibility rules (The Lawyer).
644    ///
645    /// This is distinct from `is_subtype_of`:
646    /// - `is_subtype_of` = Strict structural subtyping (The Judge) - for internal solver use
647    /// - `is_assignable_to` = Loose with TS rules (The Lawyer) - for Checker diagnostics
648    ///
649    /// The Lawyer handles:
650    /// - Any type propagation (any is assignable to/from everything)
651    /// - Legacy null/undefined assignability (without strictNullChecks)
652    /// - Weak type detection (excess property checking)
653    /// - Empty object accepts any non-nullish value
654    /// - Function bivariance (when not in strictFunctionTypes mode)
655    ///
656    /// Uses separate cache from `is_subtype_of` to prevent cache poisoning.
657    fn is_assignable_to(&self, source: TypeId, target: TypeId) -> bool {
658        // Default implementation: use non-strict mode for backward compatibility
659        // Individual callers can use is_assignable_to_with_flags for explicit flag control
660        self.is_assignable_to_with_flags(source, target, 0)
661    }
662
663    /// Assignability check with explicit compiler flags.
664    ///
665    /// The `flags` parameter is a packed u16 bitmask matching `RelationCacheKey.flags`.
666    fn is_assignable_to_with_flags(&self, source: TypeId, target: TypeId, flags: u16) -> bool;
667
668    /// Look up a cached subtype result for the given key.
669    /// Returns `None` if the result is not cached.
670    /// Default implementation returns `None` (no caching).
671    fn lookup_subtype_cache(&self, _key: RelationCacheKey) -> Option<bool> {
672        None
673    }
674
675    /// Cache a subtype result for the given key.
676    /// Default implementation is a no-op.
677    fn insert_subtype_cache(&self, _key: RelationCacheKey, _result: bool) {}
678
679    /// Look up a cached assignability result for the given key.
680    /// Returns `None` if the result is not cached.
681    /// Default implementation returns `None` (no caching).
682    fn lookup_assignability_cache(&self, _key: RelationCacheKey) -> Option<bool> {
683        None
684    }
685
686    /// Cache an assignability result for the given key.
687    /// Default implementation is a no-op.
688    fn insert_assignability_cache(&self, _key: RelationCacheKey, _result: bool) {}
689
690    fn new_inference_context(&self) -> crate::infer::InferenceContext<'_> {
691        crate::infer::InferenceContext::new(self.as_type_database())
692    }
693
694    /// Task #41: Get the variance mask for a generic type definition.
695    ///
696    /// Returns the variance of each type parameter for the given `DefId`.
697    /// Returns None if the `DefId` is not a generic type or variance cannot be determined.
698    fn get_type_param_variance(&self, def_id: DefId) -> Option<Arc<[Variance]>>;
699}
700
701impl QueryDatabase for TypeInterner {
702    fn as_type_database(&self) -> &dyn TypeDatabase {
703        self
704    }
705
706    fn register_array_base_type(&self, type_id: TypeId, type_params: Vec<TypeParamInfo>) {
707        self.set_array_base_type(type_id, type_params);
708    }
709
710    fn register_boxed_type(&self, kind: IntrinsicKind, type_id: TypeId) {
711        TypeInterner::set_boxed_type(self, kind, type_id);
712    }
713
714    fn get_index_signatures(&self, type_id: TypeId) -> IndexInfo {
715        match self.lookup(type_id) {
716            Some(TypeData::ObjectWithIndex(shape_id)) => {
717                let shape = self.object_shape(shape_id);
718                IndexInfo {
719                    string_index: shape.string_index.clone(),
720                    number_index: shape.number_index.clone(),
721                }
722            }
723            Some(TypeData::Array(element)) => {
724                // Arrays have number index signature with element type
725                IndexInfo {
726                    string_index: None,
727                    number_index: Some(crate::types::IndexSignature {
728                        key_type: TypeId::NUMBER,
729                        value_type: element,
730                        readonly: false,
731                    }),
732                }
733            }
734            Some(TypeData::Tuple(elements_id)) => {
735                // Tuples have number index signature with union of element types
736                let elements = self.tuple_list(elements_id);
737                let element_types: Vec<TypeId> = elements.iter().map(|e| e.type_id).collect();
738                let value_type = if element_types.is_empty() {
739                    TypeId::UNDEFINED
740                } else if element_types.len() == 1 {
741                    element_types[0]
742                } else {
743                    self.union(element_types)
744                };
745                IndexInfo {
746                    string_index: None,
747                    number_index: Some(crate::types::IndexSignature {
748                        key_type: TypeId::NUMBER,
749                        value_type,
750                        readonly: false,
751                    }),
752                }
753            }
754            Some(TypeData::Union(members_id)) => {
755                // For unions, collect index signatures from all members
756                let members = self.type_list(members_id);
757                let mut string_indices = Vec::new();
758                let mut number_indices = Vec::new();
759
760                for &member in members.iter() {
761                    let info = self.get_index_signatures(member);
762                    if let Some(sig) = info.string_index {
763                        string_indices.push(sig);
764                    }
765                    if let Some(sig) = info.number_index {
766                        number_indices.push(sig);
767                    }
768                }
769
770                // Union of the value types
771                let string_index = if string_indices.is_empty() {
772                    None
773                } else {
774                    Some(crate::types::IndexSignature {
775                        key_type: TypeId::STRING,
776                        value_type: self
777                            .union(string_indices.iter().map(|s| s.value_type).collect()),
778                        readonly: string_indices.iter().all(|s| s.readonly),
779                    })
780                };
781
782                let number_index = if number_indices.is_empty() {
783                    None
784                } else {
785                    Some(crate::types::IndexSignature {
786                        key_type: TypeId::NUMBER,
787                        value_type: self
788                            .union(number_indices.iter().map(|s| s.value_type).collect()),
789                        readonly: number_indices.iter().all(|s| s.readonly),
790                    })
791                };
792
793                IndexInfo {
794                    string_index,
795                    number_index,
796                }
797            }
798            Some(TypeData::Intersection(members_id)) => {
799                // For intersections, combine index signatures
800                let members = self.type_list(members_id);
801                let mut string_index = None;
802                let mut number_index = None;
803
804                for &member in members.iter() {
805                    let info = self.get_index_signatures(member);
806                    if let Some(sig) = info.string_index {
807                        string_index = Some(sig);
808                    }
809                    if let Some(sig) = info.number_index {
810                        number_index = Some(sig);
811                    }
812                }
813
814                IndexInfo {
815                    string_index,
816                    number_index,
817                }
818            }
819            _ => IndexInfo::default(),
820        }
821    }
822
823    fn is_nullish_type(&self, type_id: TypeId) -> bool {
824        narrowing::is_nullish_type(self, type_id)
825    }
826
827    fn remove_nullish(&self, type_id: TypeId) -> TypeId {
828        narrowing::remove_nullish(self, type_id)
829    }
830
831    fn is_assignable_to(&self, source: TypeId, target: TypeId) -> bool {
832        // Default implementation: use non-strict mode for backward compatibility
833        self.is_assignable_to_with_flags(source, target, 0)
834    }
835
836    fn is_assignable_to_with_flags(&self, source: TypeId, target: TypeId, flags: u16) -> bool {
837        use crate::compat::CompatChecker;
838        let mut checker = CompatChecker::new(self);
839        if flags != 0 {
840            checker.apply_flags(flags);
841        }
842        checker.is_assignable(source, target)
843    }
844
845    fn resolve_property_access(
846        &self,
847        object_type: TypeId,
848        prop_name: &str,
849    ) -> crate::operations_property::PropertyAccessResult {
850        // TypeInterner doesn't have TypeResolver capability, so it can't resolve Lazy types
851        // Use PropertyAccessEvaluator with QueryDatabase (self implements both TypeDatabase and TypeResolver)
852        let evaluator = crate::operations_property::PropertyAccessEvaluator::new(self);
853        evaluator.resolve_property_access(object_type, prop_name)
854    }
855
856    fn resolve_property_access_with_options(
857        &self,
858        object_type: TypeId,
859        prop_name: &str,
860        no_unchecked_indexed_access: bool,
861    ) -> crate::operations_property::PropertyAccessResult {
862        let mut evaluator = crate::operations_property::PropertyAccessEvaluator::new(self);
863        evaluator.set_no_unchecked_indexed_access(no_unchecked_indexed_access);
864        evaluator.resolve_property_access(object_type, prop_name)
865    }
866
867    fn get_type_param_variance(&self, _def_id: DefId) -> Option<Arc<[Variance]>> {
868        // TypeInterner doesn't have access to type parameter information.
869        // The Checker will override this to provide the actual implementation.
870        None
871    }
872
873    fn canonical_id(&self, type_id: TypeId) -> TypeId {
874        // TypeInterner doesn't have caching, so compute directly
875        use crate::canonicalize::Canonicalizer;
876        let mut canon = Canonicalizer::new(self, self);
877        canon.canonicalize(type_id)
878    }
879}
880
881type EvalCacheKey = (TypeId, bool);
882type ApplicationEvalCacheKey = (DefId, Vec<TypeId>, bool);
883type ElementAccessTypeCacheKey = (TypeId, TypeId, Option<u32>, bool);
884type PropertyAccessCacheKey = (TypeId, Atom, bool);
885
886#[derive(Debug, Clone, Copy, PartialEq, Eq)]
887pub enum RelationCacheProbe {
888    Hit(bool),
889    MissNotCached,
890}
891
892#[derive(Debug, Clone, Copy, PartialEq, Eq)]
893pub struct RelationCacheStats {
894    pub subtype_hits: u64,
895    pub subtype_misses: u64,
896    pub subtype_entries: usize,
897    pub assignability_hits: u64,
898    pub assignability_misses: u64,
899    pub assignability_entries: usize,
900}
901
902/// Query database wrapper with basic caching.
903pub struct QueryCache<'a> {
904    interner: &'a TypeInterner,
905    eval_cache: RwLock<FxHashMap<EvalCacheKey, TypeId>>,
906    application_eval_cache: RwLock<FxHashMap<ApplicationEvalCacheKey, TypeId>>,
907    element_access_cache: RwLock<FxHashMap<ElementAccessTypeCacheKey, TypeId>>,
908    object_spread_properties_cache: RwLock<FxHashMap<TypeId, Vec<PropertyInfo>>>,
909    subtype_cache: RwLock<FxHashMap<RelationCacheKey, bool>>,
910    /// CRITICAL: Separate cache for assignability to prevent cache poisoning.
911    /// This ensures that loose assignability results (e.g., any is assignable to number)
912    /// don't contaminate strict subtype checks.
913    assignability_cache: RwLock<FxHashMap<RelationCacheKey, bool>>,
914    property_cache: RwLock<FxHashMap<PropertyAccessCacheKey, PropertyAccessResult>>,
915    /// Task #41: Variance cache for generic type parameters.
916    /// Stores computed variance masks for `DefIds` to enable O(1) generic assignability.
917    variance_cache: RwLock<FxHashMap<DefId, Arc<[Variance]>>>,
918    /// Task #49: Canonical cache for O(1) structural identity checks.
919    /// Maps `TypeId` -> canonical `TypeId` for structurally identical types.
920    canonical_cache: RwLock<FxHashMap<TypeId, TypeId>>,
921    subtype_cache_hits: AtomicU64,
922    subtype_cache_misses: AtomicU64,
923    assignability_cache_hits: AtomicU64,
924    assignability_cache_misses: AtomicU64,
925    no_unchecked_indexed_access: AtomicBool,
926}
927
928impl<'a> QueryCache<'a> {
929    pub fn new(interner: &'a TypeInterner) -> Self {
930        QueryCache {
931            interner,
932            eval_cache: RwLock::new(FxHashMap::default()),
933            application_eval_cache: RwLock::new(FxHashMap::default()),
934            element_access_cache: RwLock::new(FxHashMap::default()),
935            object_spread_properties_cache: RwLock::new(FxHashMap::default()),
936            subtype_cache: RwLock::new(FxHashMap::default()),
937            assignability_cache: RwLock::new(FxHashMap::default()),
938            property_cache: RwLock::new(FxHashMap::default()),
939            variance_cache: RwLock::new(FxHashMap::default()),
940            canonical_cache: RwLock::new(FxHashMap::default()),
941            subtype_cache_hits: AtomicU64::new(0),
942            subtype_cache_misses: AtomicU64::new(0),
943            assignability_cache_hits: AtomicU64::new(0),
944            assignability_cache_misses: AtomicU64::new(0),
945            no_unchecked_indexed_access: AtomicBool::new(false),
946        }
947    }
948
949    pub fn clear(&self) {
950        // Handle poisoned locks gracefully - if poisoned, clear the cache anyway
951        match self.eval_cache.write() {
952            Ok(mut cache) => cache.clear(),
953            Err(e) => e.into_inner().clear(),
954        }
955        match self.element_access_cache.write() {
956            Ok(mut cache) => cache.clear(),
957            Err(e) => e.into_inner().clear(),
958        }
959        match self.application_eval_cache.write() {
960            Ok(mut cache) => cache.clear(),
961            Err(e) => e.into_inner().clear(),
962        }
963        match self.object_spread_properties_cache.write() {
964            Ok(mut cache) => cache.clear(),
965            Err(e) => e.into_inner().clear(),
966        }
967        match self.subtype_cache.write() {
968            Ok(mut cache) => cache.clear(),
969            Err(e) => e.into_inner().clear(),
970        }
971        match self.assignability_cache.write() {
972            Ok(mut cache) => cache.clear(),
973            Err(e) => e.into_inner().clear(),
974        }
975        match self.property_cache.write() {
976            Ok(mut cache) => cache.clear(),
977            Err(e) => e.into_inner().clear(),
978        }
979        match self.variance_cache.write() {
980            Ok(mut cache) => cache.clear(),
981            Err(e) => e.into_inner().clear(),
982        }
983        match self.canonical_cache.write() {
984            Ok(mut cache) => cache.clear(),
985            Err(e) => e.into_inner().clear(),
986        }
987        self.reset_relation_cache_stats();
988    }
989
990    pub fn relation_cache_stats(&self) -> RelationCacheStats {
991        let subtype_entries = match self.subtype_cache.read() {
992            Ok(cache) => cache.len(),
993            Err(e) => e.into_inner().len(),
994        };
995        let assignability_entries = match self.assignability_cache.read() {
996            Ok(cache) => cache.len(),
997            Err(e) => e.into_inner().len(),
998        };
999        RelationCacheStats {
1000            subtype_hits: self.subtype_cache_hits.load(Ordering::Relaxed),
1001            subtype_misses: self.subtype_cache_misses.load(Ordering::Relaxed),
1002            subtype_entries,
1003            assignability_hits: self.assignability_cache_hits.load(Ordering::Relaxed),
1004            assignability_misses: self.assignability_cache_misses.load(Ordering::Relaxed),
1005            assignability_entries,
1006        }
1007    }
1008
1009    pub fn reset_relation_cache_stats(&self) {
1010        self.subtype_cache_hits.store(0, Ordering::Relaxed);
1011        self.subtype_cache_misses.store(0, Ordering::Relaxed);
1012        self.assignability_cache_hits.store(0, Ordering::Relaxed);
1013        self.assignability_cache_misses.store(0, Ordering::Relaxed);
1014    }
1015
1016    pub fn probe_subtype_cache(&self, key: RelationCacheKey) -> RelationCacheProbe {
1017        match self.lookup_subtype_cache(key) {
1018            Some(result) => RelationCacheProbe::Hit(result),
1019            None => RelationCacheProbe::MissNotCached,
1020        }
1021    }
1022
1023    pub fn probe_assignability_cache(&self, key: RelationCacheKey) -> RelationCacheProbe {
1024        match self.lookup_assignability_cache(key) {
1025            Some(result) => RelationCacheProbe::Hit(result),
1026            None => RelationCacheProbe::MissNotCached,
1027        }
1028    }
1029
1030    /// Helper to check a cache with poisoned lock handling.
1031    fn check_cache(
1032        &self,
1033        cache: &RwLock<FxHashMap<RelationCacheKey, bool>>,
1034        key: RelationCacheKey,
1035    ) -> Option<bool> {
1036        match cache.read() {
1037            Ok(cached) => cached.get(&key).copied(),
1038            Err(e) => e.into_inner().get(&key).copied(),
1039        }
1040    }
1041
1042    /// Helper to insert into a cache with poisoned lock handling.
1043    fn insert_cache(
1044        &self,
1045        cache: &RwLock<FxHashMap<RelationCacheKey, bool>>,
1046        key: RelationCacheKey,
1047        result: bool,
1048    ) {
1049        match cache.write() {
1050            Ok(mut c) => {
1051                c.insert(key, result);
1052            }
1053            Err(e) => {
1054                e.into_inner().insert(key, result);
1055            }
1056        }
1057    }
1058
1059    fn check_property_cache(&self, key: PropertyAccessCacheKey) -> Option<PropertyAccessResult> {
1060        match self.property_cache.read() {
1061            Ok(cache) => cache.get(&key).cloned(),
1062            Err(e) => e.into_inner().get(&key).cloned(),
1063        }
1064    }
1065
1066    fn insert_property_cache(&self, key: PropertyAccessCacheKey, result: PropertyAccessResult) {
1067        match self.property_cache.write() {
1068            Ok(mut cache) => {
1069                cache.insert(key, result);
1070            }
1071            Err(e) => {
1072                e.into_inner().insert(key, result);
1073            }
1074        }
1075    }
1076
1077    fn check_element_access_cache(&self, key: ElementAccessTypeCacheKey) -> Option<TypeId> {
1078        match self.element_access_cache.read() {
1079            Ok(cache) => cache.get(&key).copied(),
1080            Err(e) => e.into_inner().get(&key).copied(),
1081        }
1082    }
1083
1084    fn insert_element_access_cache(&self, key: ElementAccessTypeCacheKey, result: TypeId) {
1085        match self.element_access_cache.write() {
1086            Ok(mut cache) => {
1087                cache.insert(key, result);
1088            }
1089            Err(e) => {
1090                e.into_inner().insert(key, result);
1091            }
1092        }
1093    }
1094
1095    fn check_application_eval_cache(&self, key: ApplicationEvalCacheKey) -> Option<TypeId> {
1096        match self.application_eval_cache.read() {
1097            Ok(cache) => cache.get(&key).copied(),
1098            Err(e) => e.into_inner().get(&key).copied(),
1099        }
1100    }
1101
1102    fn insert_application_eval_cache(&self, key: ApplicationEvalCacheKey, result: TypeId) {
1103        match self.application_eval_cache.write() {
1104            Ok(mut cache) => {
1105                cache.insert(key, result);
1106            }
1107            Err(e) => {
1108                e.into_inner().insert(key, result);
1109            }
1110        }
1111    }
1112
1113    fn check_object_spread_properties_cache(&self, key: TypeId) -> Option<Vec<PropertyInfo>> {
1114        match self.object_spread_properties_cache.read() {
1115            Ok(cache) => cache.get(&key).cloned(),
1116            Err(e) => e.into_inner().get(&key).cloned(),
1117        }
1118    }
1119
1120    fn insert_object_spread_properties_cache(&self, key: TypeId, value: Vec<PropertyInfo>) {
1121        match self.object_spread_properties_cache.write() {
1122            Ok(mut cache) => {
1123                cache.insert(key, value);
1124            }
1125            Err(e) => {
1126                e.into_inner().insert(key, value);
1127            }
1128        }
1129    }
1130
1131    fn collect_object_spread_properties_inner(
1132        &self,
1133        spread_type: TypeId,
1134        visited: &mut FxHashSet<TypeId>,
1135    ) -> Vec<PropertyInfo> {
1136        let normalized =
1137            self.evaluate_type_with_options(spread_type, self.no_unchecked_indexed_access());
1138
1139        if !visited.insert(normalized) {
1140            return Vec::new();
1141        }
1142
1143        if normalized != spread_type {
1144            return self.collect_object_spread_properties_inner(normalized, visited);
1145        }
1146
1147        let Some(key) = self.interner.lookup(normalized) else {
1148            return Vec::new();
1149        };
1150
1151        match key {
1152            TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
1153                self.interner.object_shape(shape_id).properties.to_vec()
1154            }
1155            TypeData::Callable(shape_id) => {
1156                self.interner.callable_shape(shape_id).properties.to_vec()
1157            }
1158            TypeData::Intersection(members_id) => {
1159                let members = self.interner.type_list(members_id);
1160                let mut merged: FxHashMap<Atom, PropertyInfo> = FxHashMap::default();
1161
1162                for &member in members.iter() {
1163                    for prop in self.collect_object_spread_properties_inner(member, visited) {
1164                        merged.insert(prop.name, prop);
1165                    }
1166                }
1167
1168                merged.into_values().collect()
1169            }
1170            _ => Vec::new(),
1171        }
1172    }
1173}
1174
1175impl TypeDatabase for QueryCache<'_> {
1176    fn intern(&self, key: TypeData) -> TypeId {
1177        self.interner.intern(key)
1178    }
1179
1180    fn lookup(&self, id: TypeId) -> Option<TypeData> {
1181        self.interner.lookup(id)
1182    }
1183
1184    fn intern_string(&self, s: &str) -> Atom {
1185        self.interner.intern_string(s)
1186    }
1187
1188    fn resolve_atom(&self, atom: Atom) -> String {
1189        self.interner.resolve_atom(atom)
1190    }
1191
1192    fn resolve_atom_ref(&self, atom: Atom) -> Arc<str> {
1193        self.interner.resolve_atom_ref(atom)
1194    }
1195
1196    fn type_list(&self, id: TypeListId) -> Arc<[TypeId]> {
1197        self.interner.type_list(id)
1198    }
1199
1200    fn tuple_list(&self, id: TupleListId) -> Arc<[TupleElement]> {
1201        self.interner.tuple_list(id)
1202    }
1203
1204    fn template_list(&self, id: TemplateLiteralId) -> Arc<[TemplateSpan]> {
1205        self.interner.template_list(id)
1206    }
1207
1208    fn object_shape(&self, id: ObjectShapeId) -> Arc<ObjectShape> {
1209        self.interner.object_shape(id)
1210    }
1211
1212    fn object_property_index(&self, shape_id: ObjectShapeId, name: Atom) -> PropertyLookup {
1213        self.interner.object_property_index(shape_id, name)
1214    }
1215
1216    fn function_shape(&self, id: FunctionShapeId) -> Arc<FunctionShape> {
1217        self.interner.function_shape(id)
1218    }
1219
1220    fn callable_shape(&self, id: CallableShapeId) -> Arc<CallableShape> {
1221        self.interner.callable_shape(id)
1222    }
1223
1224    fn conditional_type(&self, id: ConditionalTypeId) -> Arc<ConditionalType> {
1225        self.interner.conditional_type(id)
1226    }
1227
1228    fn mapped_type(&self, id: MappedTypeId) -> Arc<MappedType> {
1229        self.interner.mapped_type(id)
1230    }
1231
1232    fn type_application(&self, id: TypeApplicationId) -> Arc<TypeApplication> {
1233        self.interner.type_application(id)
1234    }
1235
1236    fn literal_string(&self, value: &str) -> TypeId {
1237        self.interner.literal_string(value)
1238    }
1239
1240    fn literal_number(&self, value: f64) -> TypeId {
1241        self.interner.literal_number(value)
1242    }
1243
1244    fn literal_boolean(&self, value: bool) -> TypeId {
1245        self.interner.literal_boolean(value)
1246    }
1247
1248    fn literal_bigint(&self, value: &str) -> TypeId {
1249        self.interner.literal_bigint(value)
1250    }
1251
1252    fn literal_bigint_with_sign(&self, negative: bool, digits: &str) -> TypeId {
1253        self.interner.literal_bigint_with_sign(negative, digits)
1254    }
1255
1256    fn union(&self, members: Vec<TypeId>) -> TypeId {
1257        self.interner.union(members)
1258    }
1259
1260    fn union_from_sorted_vec(&self, flat: Vec<TypeId>) -> TypeId {
1261        self.interner.union_from_sorted_vec(flat)
1262    }
1263
1264    fn union2(&self, left: TypeId, right: TypeId) -> TypeId {
1265        self.interner.union2(left, right)
1266    }
1267
1268    fn union3(&self, first: TypeId, second: TypeId, third: TypeId) -> TypeId {
1269        self.interner.union3(first, second, third)
1270    }
1271
1272    fn intersection(&self, members: Vec<TypeId>) -> TypeId {
1273        self.interner.intersection(members)
1274    }
1275
1276    fn intersection2(&self, left: TypeId, right: TypeId) -> TypeId {
1277        self.interner.intersection2(left, right)
1278    }
1279
1280    fn intersect_types_raw2(&self, left: TypeId, right: TypeId) -> TypeId {
1281        self.interner.intersect_types_raw2(left, right)
1282    }
1283
1284    fn array(&self, element: TypeId) -> TypeId {
1285        self.interner.array(element)
1286    }
1287
1288    fn tuple(&self, elements: Vec<TupleElement>) -> TypeId {
1289        self.interner.tuple(elements)
1290    }
1291
1292    fn object(&self, properties: Vec<PropertyInfo>) -> TypeId {
1293        self.interner.object(properties)
1294    }
1295
1296    fn object_with_flags(&self, properties: Vec<PropertyInfo>, flags: ObjectFlags) -> TypeId {
1297        self.interner.object_with_flags(properties, flags)
1298    }
1299
1300    fn object_with_flags_and_symbol(
1301        &self,
1302        properties: Vec<PropertyInfo>,
1303        flags: ObjectFlags,
1304        symbol: Option<SymbolId>,
1305    ) -> TypeId {
1306        self.interner
1307            .object_with_flags_and_symbol(properties, flags, symbol)
1308    }
1309
1310    fn object_with_index(&self, shape: ObjectShape) -> TypeId {
1311        self.interner.object_with_index(shape)
1312    }
1313
1314    fn function(&self, shape: FunctionShape) -> TypeId {
1315        self.interner.function(shape)
1316    }
1317
1318    fn callable(&self, shape: CallableShape) -> TypeId {
1319        self.interner.callable(shape)
1320    }
1321
1322    fn template_literal(&self, spans: Vec<TemplateSpan>) -> TypeId {
1323        self.interner.template_literal(spans)
1324    }
1325
1326    fn conditional(&self, conditional: ConditionalType) -> TypeId {
1327        self.interner.conditional(conditional)
1328    }
1329
1330    fn mapped(&self, mapped: MappedType) -> TypeId {
1331        self.interner.mapped(mapped)
1332    }
1333
1334    fn reference(&self, symbol: SymbolRef) -> TypeId {
1335        self.interner.reference(symbol)
1336    }
1337
1338    fn lazy(&self, def_id: DefId) -> TypeId {
1339        self.interner.lazy(def_id)
1340    }
1341
1342    fn bound_parameter(&self, index: u32) -> TypeId {
1343        self.interner.bound_parameter(index)
1344    }
1345
1346    fn recursive(&self, depth: u32) -> TypeId {
1347        self.interner.recursive(depth)
1348    }
1349
1350    fn type_param(&self, info: TypeParamInfo) -> TypeId {
1351        self.interner.type_param(info)
1352    }
1353
1354    fn type_query(&self, symbol: SymbolRef) -> TypeId {
1355        self.interner.type_query(symbol)
1356    }
1357
1358    fn enum_type(&self, def_id: DefId, structural_type: TypeId) -> TypeId {
1359        self.interner.enum_type(def_id, structural_type)
1360    }
1361
1362    fn application(&self, base: TypeId, args: Vec<TypeId>) -> TypeId {
1363        self.interner.application(base, args)
1364    }
1365
1366    fn literal_string_atom(&self, atom: Atom) -> TypeId {
1367        self.interner.literal_string_atom(atom)
1368    }
1369
1370    fn union_preserve_members(&self, members: Vec<TypeId>) -> TypeId {
1371        self.interner.union_preserve_members(members)
1372    }
1373
1374    fn readonly_type(&self, inner: TypeId) -> TypeId {
1375        self.interner.readonly_type(inner)
1376    }
1377
1378    fn keyof(&self, inner: TypeId) -> TypeId {
1379        self.interner.keyof(inner)
1380    }
1381
1382    fn index_access(&self, object_type: TypeId, index_type: TypeId) -> TypeId {
1383        self.interner.index_access(object_type, index_type)
1384    }
1385
1386    fn this_type(&self) -> TypeId {
1387        self.interner.this_type()
1388    }
1389
1390    fn no_infer(&self, inner: TypeId) -> TypeId {
1391        self.interner.no_infer(inner)
1392    }
1393
1394    fn unique_symbol(&self, symbol: SymbolRef) -> TypeId {
1395        self.interner.unique_symbol(symbol)
1396    }
1397
1398    fn infer(&self, info: TypeParamInfo) -> TypeId {
1399        self.interner.infer(info)
1400    }
1401
1402    fn string_intrinsic(&self, kind: StringIntrinsicKind, type_arg: TypeId) -> TypeId {
1403        self.interner.string_intrinsic(kind, type_arg)
1404    }
1405
1406    fn get_class_base_type(&self, symbol_id: SymbolId) -> Option<TypeId> {
1407        // Delegate to the interner
1408        self.interner.get_class_base_type(symbol_id)
1409    }
1410
1411    fn is_unit_type(&self, type_id: TypeId) -> bool {
1412        self.interner.is_unit_type(type_id)
1413    }
1414}
1415
1416/// Implement `TypeResolver` for `QueryCache` with default noop implementations.
1417///
1418/// `QueryCache` doesn't have access to the Binder or type environment,
1419/// so it cannot resolve symbol references or `DefIds`. This implementation
1420/// returns None for all resolution operations.
1421impl TypeResolver for QueryCache<'_> {
1422    fn resolve_ref(&self, _symbol: SymbolRef, _interner: &dyn TypeDatabase) -> Option<TypeId> {
1423        None
1424    }
1425
1426    fn resolve_lazy(&self, _def_id: DefId, _interner: &dyn TypeDatabase) -> Option<TypeId> {
1427        None
1428    }
1429
1430    fn get_type_params(&self, _symbol: SymbolRef) -> Option<Vec<TypeParamInfo>> {
1431        None
1432    }
1433
1434    fn get_lazy_type_params(&self, _def_id: DefId) -> Option<Vec<TypeParamInfo>> {
1435        None
1436    }
1437
1438    fn def_to_symbol_id(&self, _def_id: DefId) -> Option<SymbolId> {
1439        None
1440    }
1441
1442    fn symbol_to_def_id(&self, _symbol: SymbolRef) -> Option<DefId> {
1443        None
1444    }
1445
1446    fn get_boxed_type(&self, kind: IntrinsicKind) -> Option<TypeId> {
1447        self.interner.get_boxed_type(kind)
1448    }
1449
1450    fn get_array_base_type(&self) -> Option<TypeId> {
1451        self.interner.get_array_base_type()
1452    }
1453
1454    fn get_array_base_type_params(&self) -> &[TypeParamInfo] {
1455        self.interner.get_array_base_type_params()
1456    }
1457}
1458
1459impl QueryDatabase for QueryCache<'_> {
1460    fn as_type_database(&self) -> &dyn TypeDatabase {
1461        self
1462    }
1463
1464    fn register_array_base_type(&self, type_id: TypeId, type_params: Vec<TypeParamInfo>) {
1465        self.interner.set_array_base_type(type_id, type_params);
1466    }
1467
1468    fn register_boxed_type(&self, kind: IntrinsicKind, type_id: TypeId) {
1469        self.interner.set_boxed_type(kind, type_id);
1470    }
1471
1472    fn evaluate_type(&self, type_id: TypeId) -> TypeId {
1473        self.evaluate_type_with_options(type_id, self.no_unchecked_indexed_access())
1474    }
1475
1476    fn evaluate_type_with_options(
1477        &self,
1478        type_id: TypeId,
1479        no_unchecked_indexed_access: bool,
1480    ) -> TypeId {
1481        let trace_enabled = crate::query_trace::enabled();
1482        let trace_query_id = trace_enabled.then(|| {
1483            let query_id = crate::query_trace::next_query_id();
1484            crate::query_trace::unary_start(
1485                query_id,
1486                "evaluate_type_with_options",
1487                type_id,
1488                no_unchecked_indexed_access,
1489            );
1490            query_id
1491        });
1492        let key = (type_id, no_unchecked_indexed_access);
1493        // Handle poisoned locks gracefully
1494        let cached = match self.eval_cache.read() {
1495            Ok(cache) => cache.get(&key).copied(),
1496            Err(e) => e.into_inner().get(&key).copied(),
1497        };
1498
1499        if let Some(result) = cached {
1500            if let Some(query_id) = trace_query_id {
1501                crate::query_trace::unary_end(query_id, "evaluate_type_with_options", result, true);
1502            }
1503            return result;
1504        }
1505
1506        let mut evaluator = crate::evaluate::TypeEvaluator::new(self.as_type_database());
1507        evaluator.set_no_unchecked_indexed_access(no_unchecked_indexed_access);
1508        evaluator = evaluator.with_query_db(self);
1509        let result = evaluator.evaluate(type_id);
1510        match self.eval_cache.write() {
1511            Ok(mut cache) => {
1512                cache.insert(key, result);
1513            }
1514            Err(e) => {
1515                e.into_inner().insert(key, result);
1516            }
1517        }
1518        if let Some(query_id) = trace_query_id {
1519            crate::query_trace::unary_end(query_id, "evaluate_type_with_options", result, false);
1520        }
1521        result
1522    }
1523
1524    fn lookup_application_eval_cache(
1525        &self,
1526        def_id: DefId,
1527        args: &[TypeId],
1528        no_unchecked_indexed_access: bool,
1529    ) -> Option<TypeId> {
1530        self.check_application_eval_cache((def_id, args.to_vec(), no_unchecked_indexed_access))
1531    }
1532
1533    fn insert_application_eval_cache(
1534        &self,
1535        def_id: DefId,
1536        args: &[TypeId],
1537        no_unchecked_indexed_access: bool,
1538        result: TypeId,
1539    ) {
1540        self.insert_application_eval_cache(
1541            (def_id, args.to_vec(), no_unchecked_indexed_access),
1542            result,
1543        );
1544    }
1545
1546    fn is_subtype_of_with_flags(&self, source: TypeId, target: TypeId, flags: u16) -> bool {
1547        let trace_enabled = crate::query_trace::enabled();
1548        let trace_query_id = trace_enabled.then(|| {
1549            let query_id = crate::query_trace::next_query_id();
1550            crate::query_trace::relation_start(
1551                query_id,
1552                "is_subtype_of_with_flags",
1553                source,
1554                target,
1555                flags,
1556            );
1557            query_id
1558        });
1559        let key = RelationCacheKey::subtype(source, target, flags, 0);
1560        // Handle poisoned locks gracefully
1561        let cached = match self.subtype_cache.read() {
1562            Ok(cache) => cache.get(&key).copied(),
1563            Err(e) => e.into_inner().get(&key).copied(),
1564        };
1565
1566        if let Some(result) = cached {
1567            if let Some(query_id) = trace_query_id {
1568                crate::query_trace::relation_end(
1569                    query_id,
1570                    "is_subtype_of_with_flags",
1571                    result,
1572                    true,
1573                );
1574            }
1575            return result;
1576        }
1577
1578        let result = crate::subtype::is_subtype_of_with_flags(
1579            self.as_type_database(),
1580            source,
1581            target,
1582            flags,
1583        );
1584        match self.subtype_cache.write() {
1585            Ok(mut cache) => {
1586                cache.insert(key, result);
1587            }
1588            Err(e) => {
1589                e.into_inner().insert(key, result);
1590            }
1591        }
1592        if let Some(query_id) = trace_query_id {
1593            crate::query_trace::relation_end(query_id, "is_subtype_of_with_flags", result, false);
1594        }
1595        result
1596    }
1597
1598    fn is_assignable_to_with_flags(&self, source: TypeId, target: TypeId, flags: u16) -> bool {
1599        let trace_enabled = crate::query_trace::enabled();
1600        let trace_query_id = trace_enabled.then(|| {
1601            let query_id = crate::query_trace::next_query_id();
1602            crate::query_trace::relation_start(
1603                query_id,
1604                "is_assignable_to_with_flags",
1605                source,
1606                target,
1607                flags,
1608            );
1609            query_id
1610        });
1611        // Task A: Use passed flags instead of hardcoded 0,0
1612        let key = RelationCacheKey::assignability(source, target, flags, 0);
1613
1614        if let Some(result) = self.check_cache(&self.assignability_cache, key) {
1615            if let Some(query_id) = trace_query_id {
1616                crate::query_trace::relation_end(
1617                    query_id,
1618                    "is_assignable_to_with_flags",
1619                    result,
1620                    true,
1621                );
1622            }
1623            return result;
1624        }
1625
1626        // Use CompatChecker with all compatibility rules
1627        use crate::compat::CompatChecker;
1628        let mut checker = CompatChecker::new(self.as_type_database());
1629
1630        // FIX: Apply flags to ensure checker matches the cache key configuration
1631        // This prevents cache poisoning where results from non-strict checks
1632        // leak into strict checks (Gap C fix)
1633        checker.apply_flags(flags);
1634
1635        let result = checker.is_assignable(source, target);
1636
1637        self.insert_cache(&self.assignability_cache, key, result);
1638        if let Some(query_id) = trace_query_id {
1639            crate::query_trace::relation_end(
1640                query_id,
1641                "is_assignable_to_with_flags",
1642                result,
1643                false,
1644            );
1645        }
1646        result
1647    }
1648
1649    /// Convenience wrapper for `is_subtype_of` with default flags.
1650    fn is_subtype_of(&self, source: TypeId, target: TypeId) -> bool {
1651        self.is_subtype_of_with_flags(source, target, 0) // Default non-strict mode for backward compatibility
1652    }
1653
1654    /// Convenience wrapper for `is_assignable_to` with default flags.
1655    fn is_assignable_to(&self, source: TypeId, target: TypeId) -> bool {
1656        self.is_assignable_to_with_flags(source, target, 0) // Default non-strict mode for backward compatibility
1657    }
1658
1659    fn lookup_subtype_cache(&self, key: RelationCacheKey) -> Option<bool> {
1660        let result = match self.subtype_cache.read() {
1661            Ok(cache) => cache.get(&key).copied(),
1662            Err(e) => e.into_inner().get(&key).copied(),
1663        };
1664        if result.is_some() {
1665            self.subtype_cache_hits.fetch_add(1, Ordering::Relaxed);
1666        } else {
1667            self.subtype_cache_misses.fetch_add(1, Ordering::Relaxed);
1668        }
1669        result
1670    }
1671
1672    fn insert_subtype_cache(&self, key: RelationCacheKey, result: bool) {
1673        match self.subtype_cache.write() {
1674            Ok(mut cache) => {
1675                cache.insert(key, result);
1676            }
1677            Err(e) => {
1678                e.into_inner().insert(key, result);
1679            }
1680        }
1681    }
1682
1683    fn lookup_assignability_cache(&self, key: RelationCacheKey) -> Option<bool> {
1684        let result = match self.assignability_cache.read() {
1685            Ok(cache) => cache.get(&key).copied(),
1686            Err(e) => e.into_inner().get(&key).copied(),
1687        };
1688        if result.is_some() {
1689            self.assignability_cache_hits
1690                .fetch_add(1, Ordering::Relaxed);
1691        } else {
1692            self.assignability_cache_misses
1693                .fetch_add(1, Ordering::Relaxed);
1694        }
1695        result
1696    }
1697
1698    fn insert_assignability_cache(&self, key: RelationCacheKey, result: bool) {
1699        match self.assignability_cache.write() {
1700            Ok(mut cache) => {
1701                cache.insert(key, result);
1702            }
1703            Err(e) => {
1704                e.into_inner().insert(key, result);
1705            }
1706        }
1707    }
1708
1709    fn get_index_signatures(&self, type_id: TypeId) -> IndexInfo {
1710        // Delegate to the interner - caching could be added later if needed
1711        self.interner.get_index_signatures(type_id)
1712    }
1713
1714    fn is_nullish_type(&self, type_id: TypeId) -> bool {
1715        // Delegate to the interner
1716        self.interner.is_nullish_type(type_id)
1717    }
1718
1719    fn remove_nullish(&self, type_id: TypeId) -> TypeId {
1720        // Delegate to the interner
1721        self.interner.remove_nullish(type_id)
1722    }
1723
1724    fn resolve_property_access(
1725        &self,
1726        object_type: TypeId,
1727        prop_name: &str,
1728    ) -> crate::operations_property::PropertyAccessResult {
1729        self.resolve_property_access_with_options(
1730            object_type,
1731            prop_name,
1732            self.no_unchecked_indexed_access(),
1733        )
1734    }
1735
1736    fn resolve_property_access_with_options(
1737        &self,
1738        object_type: TypeId,
1739        prop_name: &str,
1740        no_unchecked_indexed_access: bool,
1741    ) -> crate::operations_property::PropertyAccessResult {
1742        // QueryCache doesn't have full TypeResolver capability, so use PropertyAccessEvaluator
1743        // with the current QueryDatabase.
1744        let prop_atom = self.interner.intern_string(prop_name);
1745        let key = (object_type, prop_atom, no_unchecked_indexed_access);
1746        if let Some(result) = self.check_property_cache(key) {
1747            return result;
1748        }
1749
1750        let mut evaluator = crate::operations_property::PropertyAccessEvaluator::new(self);
1751        evaluator.set_no_unchecked_indexed_access(no_unchecked_indexed_access);
1752        let result = evaluator.resolve_property_access(object_type, prop_name);
1753        self.insert_property_cache(key, result.clone());
1754        result
1755    }
1756
1757    fn resolve_element_access_type(
1758        &self,
1759        object_type: TypeId,
1760        index_type: TypeId,
1761        literal_index: Option<usize>,
1762    ) -> TypeId {
1763        let key = (
1764            object_type,
1765            index_type,
1766            literal_index.map(|idx| idx as u32),
1767            self.no_unchecked_indexed_access(),
1768        );
1769        if let Some(result) = self.check_element_access_cache(key) {
1770            return result;
1771        }
1772
1773        let result = match self.resolve_element_access(object_type, index_type, literal_index) {
1774            crate::element_access::ElementAccessResult::Success(type_id) => type_id,
1775            _ => TypeId::ERROR,
1776        };
1777
1778        self.insert_element_access_cache(key, result);
1779        result
1780    }
1781
1782    fn collect_object_spread_properties(&self, spread_type: TypeId) -> Vec<PropertyInfo> {
1783        if let Some(cached) = self.check_object_spread_properties_cache(spread_type) {
1784            return cached;
1785        }
1786
1787        let mut visited: FxHashSet<TypeId> = FxHashSet::default();
1788        let result = self.collect_object_spread_properties_inner(spread_type, &mut visited);
1789        self.insert_object_spread_properties_cache(spread_type, result.clone());
1790        result
1791    }
1792
1793    fn no_unchecked_indexed_access(&self) -> bool {
1794        self.no_unchecked_indexed_access.load(Ordering::Relaxed)
1795    }
1796
1797    fn set_no_unchecked_indexed_access(&self, enabled: bool) {
1798        self.no_unchecked_indexed_access
1799            .store(enabled, Ordering::Relaxed);
1800    }
1801
1802    fn get_type_param_variance(&self, def_id: DefId) -> Option<Arc<[Variance]>> {
1803        // 1. Check cache first (lock-free read)
1804        if let Ok(cache) = self.variance_cache.read()
1805            && let Some(cached) = cache.get(&def_id)
1806        {
1807            return Some(Arc::clone(cached));
1808        }
1809
1810        // 2. Compute variance using the type's body
1811        // This requires the database to also be a TypeResolver (which QueryDatabase is)
1812        let params = self.get_lazy_type_params(def_id)?;
1813        if params.is_empty() {
1814            return None;
1815        }
1816
1817        let body = self.resolve_lazy(def_id, self.as_type_database())?;
1818
1819        let mut variances = Vec::with_capacity(params.len());
1820        for param in &params {
1821            // Compute variance for each type parameter
1822            let v = crate::variance::compute_variance(self, body, param.name);
1823            variances.push(v);
1824        }
1825        let result = Arc::from(variances);
1826
1827        // 3. Store in cache
1828        match self.variance_cache.write() {
1829            Ok(mut cache) => {
1830                cache.insert(def_id, Arc::clone(&result));
1831            }
1832            Err(e) => {
1833                e.into_inner().insert(def_id, Arc::clone(&result));
1834            }
1835        }
1836
1837        Some(result)
1838    }
1839
1840    fn canonical_id(&self, type_id: TypeId) -> TypeId {
1841        // Check cache first
1842        let cached = match self.canonical_cache.read() {
1843            Ok(cache) => cache.get(&type_id).copied(),
1844            Err(e) => e.into_inner().get(&type_id).copied(),
1845        };
1846
1847        if let Some(canonical) = cached {
1848            return canonical;
1849        }
1850
1851        // Compute canonical form using a fresh Canonicalizer
1852        // CRITICAL: Always start with empty stacks for absolute De Bruijn indices
1853        // This ensures the cached TypeId represents the absolute structural form
1854        use crate::canonicalize::Canonicalizer;
1855        let mut canon = Canonicalizer::new(self.as_type_database(), self);
1856        let canonical = canon.canonicalize(type_id);
1857
1858        // Cache the result
1859        match self.canonical_cache.write() {
1860            Ok(mut cache) => {
1861                cache.insert(type_id, canonical);
1862            }
1863            Err(e) => {
1864                e.into_inner().insert(type_id, canonical);
1865            }
1866        }
1867
1868        canonical
1869    }
1870}
1871
1872#[cfg(test)]
1873#[path = "../tests/db_tests.rs"]
1874mod tests;