pub struct CheckerState<'a> {
pub ctx: CheckerContext<'a>,
}Expand description
Type checker state using NodeArena and Solver type system.
This is a performance-optimized checker that works directly with the
cache-friendly Node architecture and uses the solver’s TypeInterner
for structural type equality.
The state is stored in a CheckerContext which can be shared with
specialized checker modules (expressions, statements, declarations).
Fields§
§ctx: CheckerContext<'a>Shared checker context containing all state.
Implementations§
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_type_not_assignable_at(
&mut self,
source: TypeId,
target: TypeId,
idx: NodeIndex,
)
pub fn error_type_not_assignable_at( &mut self, source: TypeId, target: TypeId, idx: NodeIndex, )
Report a type not assignable error (delegates to diagnose_assignment_failure).
Sourcepub fn error_type_not_assignable_at_with_anchor(
&mut self,
source: TypeId,
target: TypeId,
anchor_idx: NodeIndex,
)
pub fn error_type_not_assignable_at_with_anchor( &mut self, source: TypeId, target: TypeId, anchor_idx: NodeIndex, )
Report a type not assignable error at an exact AST node anchor.
pub fn error_type_does_not_satisfy_the_expected_type( &mut self, source: TypeId, target: TypeId, idx: NodeIndex, )
Sourcepub fn diagnose_assignment_failure(
&mut self,
source: TypeId,
target: TypeId,
idx: NodeIndex,
)
pub fn diagnose_assignment_failure( &mut self, source: TypeId, target: TypeId, idx: NodeIndex, )
Diagnose why an assignment failed and report a detailed error.
Sourcepub fn error_type_not_assignable_with_reason_at(
&mut self,
source: TypeId,
target: TypeId,
idx: NodeIndex,
)
pub fn error_type_not_assignable_with_reason_at( &mut self, source: TypeId, target: TypeId, idx: NodeIndex, )
Report a type not assignable error with detailed elaboration.
This method uses the solver’s “explain” API to determine WHY the types are incompatible (e.g., missing property, incompatible property types, etc.) and produces a richer diagnostic with that information.
Architecture Note: This follows the “Check Fast, Explain Slow” pattern.
The is_assignable_to check is fast (boolean). This explain call is slower
but produces better error messages. Only call this after a failed check.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn try_elaborate_object_literal_arg_error(
&mut self,
arg_idx: NodeIndex,
param_type: TypeId,
) -> bool
pub fn try_elaborate_object_literal_arg_error( &mut self, arg_idx: NodeIndex, param_type: TypeId, ) -> bool
Try to elaborate an argument type mismatch for object/array literal arguments.
When an object literal argument has a property whose value type doesn’t match the expected property type, tsc reports TS2322 on the specific property name rather than TS2345 on the whole argument. Similarly for array literals, tsc reports TS2322 on each element that doesn’t match the expected element type.
Returns true if elaboration produced at least one property-level error (TS2322),
meaning the caller should NOT emit TS2345 on the whole argument.
Sourcepub fn error_argument_not_assignable_at(
&mut self,
arg_type: TypeId,
param_type: TypeId,
idx: NodeIndex,
)
pub fn error_argument_not_assignable_at( &mut self, arg_type: TypeId, param_type: TypeId, idx: NodeIndex, )
Report an argument not assignable error using solver diagnostics with source tracking.
Sourcepub fn error_argument_count_mismatch_at(
&mut self,
expected: usize,
got: usize,
idx: NodeIndex,
)
pub fn error_argument_count_mismatch_at( &mut self, expected: usize, got: usize, idx: NodeIndex, )
Report an argument count mismatch error using solver diagnostics with source tracking. TS2554: Expected {0} arguments, but got {1}.
Sourcepub fn error_spread_must_be_tuple_or_rest_at(&mut self, idx: NodeIndex)
pub fn error_spread_must_be_tuple_or_rest_at(&mut self, idx: NodeIndex)
Report a spread argument type error (TS2556). TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
Sourcepub fn error_expected_at_least_arguments_at(
&mut self,
expected_min: usize,
got: usize,
idx: NodeIndex,
)
pub fn error_expected_at_least_arguments_at( &mut self, expected_min: usize, got: usize, idx: NodeIndex, )
Report an “expected at least N arguments” error (TS2555). TS2555: Expected at least {0} arguments, but got {1}.
Sourcepub fn error_no_overload_matches_at(
&mut self,
idx: NodeIndex,
failures: &[PendingDiagnostic],
)
pub fn error_no_overload_matches_at( &mut self, idx: NodeIndex, failures: &[PendingDiagnostic], )
Report “No overload matches this call” with related overload failures.
Sourcepub fn error_type_parameter_used_as_value(&mut self, name: &str, idx: NodeIndex)
pub fn error_type_parameter_used_as_value(&mut self, name: &str, idx: NodeIndex)
Report TS2693: type parameter used as value
Sourcepub fn error_this_type_mismatch_at(
&mut self,
expected_this: TypeId,
actual_this: TypeId,
idx: NodeIndex,
)
pub fn error_this_type_mismatch_at( &mut self, expected_this: TypeId, actual_this: TypeId, idx: NodeIndex, )
Report a “this type mismatch” error using solver diagnostics with source tracking.
Sourcepub fn error_not_callable_at(&mut self, type_id: TypeId, idx: NodeIndex)
pub fn error_not_callable_at(&mut self, type_id: TypeId, idx: NodeIndex)
Report a “type is not callable” error using solver diagnostics with source tracking.
Sourcepub fn error_get_accessor_not_callable_at(&mut self, idx: NodeIndex)
pub fn error_get_accessor_not_callable_at(&mut self, idx: NodeIndex)
Report TS6234: “This expression is not callable because it is a ‘get’ accessor. Did you mean to access it without ‘()’?”
Sourcepub fn error_class_constructor_without_new_at(
&mut self,
type_id: TypeId,
idx: NodeIndex,
)
pub fn error_class_constructor_without_new_at( &mut self, type_id: TypeId, idx: NodeIndex, )
Report TS2348: “Value of type ‘{0}’ is not callable. Did you mean to include ‘new’?” This is specifically for class constructors called without ‘new’.
Sourcepub fn error_non_void_function_called_with_new_at(&mut self, idx: NodeIndex)
pub fn error_non_void_function_called_with_new_at(&mut self, idx: NodeIndex)
Report TS2350: “Only a void function can be called with the ‘new’ keyword.”
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_generic_type_requires_type_arguments_at(
&mut self,
name: &str,
required_count: usize,
idx: NodeIndex,
)
pub fn error_generic_type_requires_type_arguments_at( &mut self, name: &str, required_count: usize, idx: NodeIndex, )
Report TS2314: Generic type ‘X’ requires N type argument(s).
Sourcepub fn error_type_constraint_not_satisfied(
&mut self,
type_arg: TypeId,
constraint: TypeId,
idx: NodeIndex,
)
pub fn error_type_constraint_not_satisfied( &mut self, type_arg: TypeId, constraint: TypeId, idx: NodeIndex, )
Report TS2344: Type does not satisfy constraint.
Sourcepub fn error_comparison_no_overlap(
&mut self,
left_type: TypeId,
right_type: TypeId,
is_equality: bool,
idx: NodeIndex,
)
pub fn error_comparison_no_overlap( &mut self, left_type: TypeId, right_type: TypeId, is_equality: bool, idx: NodeIndex, )
Report TS2367: This condition will always return ‘false’/‘true’ since the types have no overlap.
The message depends on the operator:
- For
===and==: “always return ‘false’” - For
!==and!=: “always return ‘true’”
Sourcepub fn error_type_assertion_no_overlap(
&mut self,
source_type: TypeId,
target_type: TypeId,
idx: NodeIndex,
)
pub fn error_type_assertion_no_overlap( &mut self, source_type: TypeId, target_type: TypeId, idx: NodeIndex, )
Report TS2352: Conversion of type ‘X’ to type ‘Y’ may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to ‘unknown’ first.
Sourcepub fn create_diagnostic_collector(&self) -> DiagnosticCollector<'_>
pub fn create_diagnostic_collector(&self) -> DiagnosticCollector<'_>
Create a diagnostic collector for batch error reporting.
Sourcepub fn merge_diagnostics(&mut self, collector: &DiagnosticCollector<'_>)
pub fn merge_diagnostics(&mut self, collector: &DiagnosticCollector<'_>)
Merge diagnostics from a collector into the checker’s diagnostics.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_cannot_find_name_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_cannot_find_name_at(&mut self, name: &str, idx: NodeIndex)
Report a cannot find name error using solver diagnostics with source tracking. Enhanced to provide suggestions for similar names, import suggestions, and library change suggestions for ES2015+ types.
Sourcepub fn error_cannot_find_global_type(&mut self, name: &str, idx: NodeIndex)
pub fn error_cannot_find_global_type(&mut self, name: &str, idx: NodeIndex)
Report error 2318/2583: Cannot find global type ‘X’.
- TS2318: Cannot find global type (for @noLib tests)
- TS2583: Cannot find name - suggests changing target library (for ES2015+ types)
Sourcepub fn error_cannot_find_name_change_lib(&mut self, name: &str, idx: NodeIndex)
pub fn error_cannot_find_name_change_lib(&mut self, name: &str, idx: NodeIndex)
Report TS2583: Cannot find name ‘X’ - suggest changing target library.
This error is emitted when an ES2015+ global (Promise, Map, Set, Symbol, etc.) is used as a value but is not available in the current lib configuration. It provides a helpful suggestion to change the lib compiler option.
Sourcepub fn error_cannot_find_name_change_target_lib(
&mut self,
name: &str,
idx: NodeIndex,
)
pub fn error_cannot_find_name_change_target_lib( &mut self, name: &str, idx: NodeIndex, )
Report TS2584: Cannot find name ‘X’ - suggest including ‘dom’ lib.
This error is emitted when a known DOM/ScriptHost global (console, window,
document, HTMLElement, etc.) is used but the ‘dom’ lib is not included.
Sourcepub fn error_cannot_find_name_install_node_types(
&mut self,
name: &str,
idx: NodeIndex,
)
pub fn error_cannot_find_name_install_node_types( &mut self, name: &str, idx: NodeIndex, )
Report TS2580: Cannot find name ‘X’ - suggest installing @types/node.
tsc uses TS2580 (without tsconfig suggestion) when the tsconfig has no types field,
and TS2591 (with tsconfig suggestion) when a types field is configured.
Most conformance tests have no types field, so TS2580 matches tsc behavior.
Sourcepub fn error_cannot_find_name_install_test_types(
&mut self,
name: &str,
idx: NodeIndex,
)
pub fn error_cannot_find_name_install_test_types( &mut self, name: &str, idx: NodeIndex, )
Report TS2582: Cannot find name ‘X’ - suggest installing test runner types.
Sourcepub fn error_cannot_find_name_with_suggestions(
&mut self,
name: &str,
suggestions: &[String],
idx: NodeIndex,
)
pub fn error_cannot_find_name_with_suggestions( &mut self, name: &str, suggestions: &[String], idx: NodeIndex, )
Report error 2304/2552: Cannot find name ‘X’ with suggestions. Provides a list of similar names that might be what the user intended.
Sourcepub fn error_cannot_find_name_did_you_mean_at(
&mut self,
name: &str,
suggestion: &str,
idx: NodeIndex,
)
pub fn error_cannot_find_name_did_you_mean_at( &mut self, name: &str, suggestion: &str, idx: NodeIndex, )
Report error 2552: Cannot find name ‘X’. Did you mean ‘Y’?
Sourcepub fn error_cannot_find_name_static_member_at(
&mut self,
name: &str,
class_name: &str,
idx: NodeIndex,
)
pub fn error_cannot_find_name_static_member_at( &mut self, name: &str, class_name: &str, idx: NodeIndex, )
Report error 2662: Cannot find name ‘X’. Did you mean the static member ‘C.X’?
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_not_a_constructor_at(&mut self, type_id: TypeId, idx: NodeIndex)
pub fn error_not_a_constructor_at(&mut self, type_id: TypeId, idx: NodeIndex)
Report TS2507: “Type ‘X’ is not a constructor function type” This is for extends clauses where the base type isn’t a constructor.
Sourcepub fn error_not_constructable_at(&mut self, type_id: TypeId, idx: NodeIndex)
pub fn error_not_constructable_at(&mut self, type_id: TypeId, idx: NodeIndex)
Report TS2351: “This expression is not constructable. Type ‘X’ has no construct signatures.”
This is for new expressions where the expression type has no construct signatures.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_property_missing_at(
&mut self,
prop_name: &str,
source: TypeId,
target: TypeId,
idx: NodeIndex,
)
pub fn error_property_missing_at( &mut self, prop_name: &str, source: TypeId, target: TypeId, idx: NodeIndex, )
Report a property missing error using solver diagnostics with source tracking.
Sourcepub fn error_property_not_exist_at(
&mut self,
prop_name: &str,
type_id: TypeId,
idx: NodeIndex,
)
pub fn error_property_not_exist_at( &mut self, prop_name: &str, type_id: TypeId, idx: NodeIndex, )
Report a property not exist error using solver diagnostics with source tracking. If a similar property name is found on the type, emits TS2551 (“Did you mean?”) instead of TS2339.
Sourcepub fn error_excess_property_at(
&mut self,
prop_name: &str,
target: TypeId,
idx: NodeIndex,
)
pub fn error_excess_property_at( &mut self, prop_name: &str, target: TypeId, idx: NodeIndex, )
Report an excess property error using solver diagnostics with source tracking.
Sourcepub fn error_readonly_property_at(&mut self, prop_name: &str, idx: NodeIndex)
pub fn error_readonly_property_at(&mut self, prop_name: &str, idx: NodeIndex)
Report a “Cannot assign to readonly property” error using solver diagnostics with source tracking.
Sourcepub fn error_readonly_index_signature_at(
&mut self,
object_type: TypeId,
idx: NodeIndex,
)
pub fn error_readonly_index_signature_at( &mut self, object_type: TypeId, idx: NodeIndex, )
Report TS2542: Index signature in type ‘{0}’ only permits reading.
Sourcepub fn error_private_method_not_writable(
&mut self,
prop_name: &str,
idx: NodeIndex,
)
pub fn error_private_method_not_writable( &mut self, prop_name: &str, idx: NodeIndex, )
Report TS2803: Cannot assign to private method. Private methods are not writable.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn error_subsequent_variable_declaration(
&mut self,
name: &str,
prev_type: TypeId,
current_type: TypeId,
idx: NodeIndex,
)
pub fn error_subsequent_variable_declaration( &mut self, name: &str, prev_type: TypeId, current_type: TypeId, idx: NodeIndex, )
Report error 2403: Subsequent variable declarations must have the same type.
Sourcepub fn error_variable_used_before_assigned_at(
&mut self,
name: &str,
idx: NodeIndex,
)
pub fn error_variable_used_before_assigned_at( &mut self, name: &str, idx: NodeIndex, )
Report TS2454: Variable is used before being assigned.
Sourcepub fn error_abstract_property_in_constructor(
&mut self,
prop_name: &str,
class_name: &str,
idx: NodeIndex,
)
pub fn error_abstract_property_in_constructor( &mut self, prop_name: &str, class_name: &str, idx: NodeIndex, )
Report error 2715: Abstract property ‘X’ in class ‘C’ cannot be accessed in the constructor.
Sourcepub fn error_namespace_no_export(
&mut self,
namespace_name: &str,
member_name: &str,
idx: NodeIndex,
)
pub fn error_namespace_no_export( &mut self, namespace_name: &str, member_name: &str, idx: NodeIndex, )
Report TS2694: Namespace has no exported member.
Sourcepub fn report_spread_not_object_type(&mut self, idx: NodeIndex)
pub fn report_spread_not_object_type(&mut self, idx: NodeIndex)
Report TS2698: Spread types may only be created from object types.
Sourcepub fn error_type_only_value_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_type_only_value_at(&mut self, name: &str, idx: NodeIndex)
Report TS2693/TS2585: Symbol only refers to a type, but is used as a value.
For ES2015+ types (Promise, Map, Set, Symbol, etc.), emits TS2585 with a suggestion to change the target library. For other types, emits TS2693 without the lib suggestion.
Sourcepub fn error_value_only_type_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_value_only_type_at(&mut self, name: &str, idx: NodeIndex)
Report TS2749: Symbol refers to a value, but is used as a type.
Sourcepub fn error_namespace_used_as_type_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_namespace_used_as_type_at(&mut self, name: &str, idx: NodeIndex)
Report TS2709: Cannot use namespace ‘{0}’ as a type.
Sourcepub fn error_namespace_used_as_value_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_namespace_used_as_value_at(&mut self, name: &str, idx: NodeIndex)
Report TS2708: Cannot use namespace ‘{0}’ as a value.
Sourcepub fn error_value_cannot_be_used_here_at(&mut self, name: &str, idx: NodeIndex)
pub fn error_value_cannot_be_used_here_at(&mut self, name: &str, idx: NodeIndex)
Report TS18050: The value ‘X’ cannot be used here. Emitted when a value (like a variable or literal) is used where it’s not permitted.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn with_judge<R, F>(&self, f: F) -> Rwhere
F: FnOnce(&DefaultJudge<'_>) -> R,
pub fn with_judge<R, F>(&self, f: F) -> Rwhere
F: FnOnce(&DefaultJudge<'_>) -> R,
Execute a closure with a configured Judge instance.
The Judge provides pure type algebra operations (is_subtype, evaluate, etc.)
without TypeScript-specific quirks. For assignability checking with TS rules,
use is_assignable_to which goes through the Lawyer (CompatChecker) layer.
Sourcepub fn judge_evaluate(&self, type_id: TypeId) -> TypeId
pub fn judge_evaluate(&self, type_id: TypeId) -> TypeId
Evaluate a type using the Judge.
Expands meta-types (conditionals, mapped types, etc.) to their concrete forms.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_assignable_to(&mut self, source: TypeId, target: TypeId) -> bool
pub fn is_assignable_to(&mut self, source: TypeId, target: TypeId) -> bool
Check if source type is assignable to target type.
This is the main entry point for assignability checking, used throughout the type system to validate assignments, function calls, returns, etc. Assignability is more permissive than subtyping.
Sourcepub fn is_assignable_to_strict(
&mut self,
source: TypeId,
target: TypeId,
) -> bool
pub fn is_assignable_to_strict( &mut self, source: TypeId, target: TypeId, ) -> bool
This keeps the same checker gateway (resolver + overrides + caches) as
is_assignable_to, but forces the strict-function-types relation flag.
Sourcepub fn is_assignable_to_strict_null(
&mut self,
source: TypeId,
target: TypeId,
) -> bool
pub fn is_assignable_to_strict_null( &mut self, source: TypeId, target: TypeId, ) -> bool
Check assignability while forcing strict null checks in relation flags.
This keeps the regular checker/solver assignability gateway (resolver, overrides, caching, and precondition setup) while pinning nullability semantics to strict mode for localized checks.
Sourcepub fn is_assignable_to_with_env(
&self,
source: TypeId,
target: TypeId,
env: &TypeEnvironment,
) -> bool
pub fn is_assignable_to_with_env( &self, source: TypeId, target: TypeId, env: &TypeEnvironment, ) -> bool
Check if source type is assignable to target type, resolving Ref types.
Uses the provided TypeEnvironment to resolve type references.
Sourcepub fn is_assignable_to_bivariant(
&mut self,
source: TypeId,
target: TypeId,
) -> bool
pub fn is_assignable_to_bivariant( &mut self, source: TypeId, target: TypeId, ) -> bool
Check if source type is assignable to target type with bivariant function parameter checking.
This is used for class method override checking, where methods are always bivariant (unlike function properties which are contravariant with strictFunctionTypes).
Follows the same pattern as is_assignable_to but calls is_assignable_to_bivariant_callback
which disables strict_function_types for the check.
Sourcepub fn are_types_overlapping(&mut self, left: TypeId, right: TypeId) -> bool
pub fn are_types_overlapping(&mut self, left: TypeId, right: TypeId) -> bool
Check if two types have any overlap (can ever be equal).
Used for TS2367: “This condition will always return ‘false’/‘true’ since the types ‘X’ and ‘Y’ have no overlap.”
Returns true if the types can potentially be equal, false if they can never have any common value.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_subtype_of(&mut self, source: TypeId, target: TypeId) -> bool
pub fn is_subtype_of(&mut self, source: TypeId, target: TypeId) -> bool
Check if source type is a subtype of target type.
This is the main entry point for subtype checking, used for type compatibility throughout the type system. Subtyping is stricter than assignability.
Sourcepub fn is_subtype_of_with_env(
&mut self,
source: TypeId,
target: TypeId,
env: &TypeEnvironment,
) -> bool
pub fn is_subtype_of_with_env( &mut self, source: TypeId, target: TypeId, env: &TypeEnvironment, ) -> bool
Check if source type is a subtype of target type with explicit environment.
Sourcepub fn are_types_identical(&self, type1: TypeId, type2: TypeId) -> bool
pub fn are_types_identical(&self, type1: TypeId, type2: TypeId) -> bool
Check if two types are identical (same TypeId).
Sourcepub fn is_assignable_to_union(&self, source: TypeId, targets: &[TypeId]) -> bool
pub fn is_assignable_to_union(&self, source: TypeId, targets: &[TypeId]) -> bool
Check if source type is assignable to ANY member of a target union.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_enum_type(&self, type_id: TypeId) -> bool
pub fn is_enum_type(&self, type_id: TypeId) -> bool
Check if a type is an enum type.
Returns true if the type represents a TypeScript enum.
Sourcepub fn is_const_enum_type(&self, type_id: TypeId) -> bool
pub fn is_const_enum_type(&self, type_id: TypeId) -> bool
Check if a type is a const enum type.
Const enums are fully inlined and cannot be accessed at runtime.
Sourcepub fn is_regular_enum_type(&self, type_id: TypeId) -> bool
pub fn is_regular_enum_type(&self, type_id: TypeId) -> bool
Check if a type is a regular (non-const) enum type.
Sourcepub fn is_enum_member_type(&self, type_id: TypeId) -> bool
pub fn is_enum_member_type(&self, type_id: TypeId) -> bool
Check if a type could be an enum member type.
Enum members can be:
- String literals (for string enums)
- Numeric literals (for numeric enums)
- Computed values (for heterogeneous enums)
Sourcepub fn get_enum_member_base_type(&self, type_id: TypeId) -> TypeId
pub fn get_enum_member_base_type(&self, type_id: TypeId) -> TypeId
Get the base member type for an enum (string or number).
Returns:
- STRING for string enums
- NUMBER for numeric enums
- UNION for heterogeneous enums
- UNKNOWN if the enum kind cannot be determined
Sourcepub fn enum_members_compatible(
&self,
enum_type1: TypeId,
enum_type2: TypeId,
) -> bool
pub fn enum_members_compatible( &self, enum_type1: TypeId, enum_type2: TypeId, ) -> bool
Check if enum member types are compatible.
TypeScript allows enum members to be compared if they are from compatible enum types (string enum members are string-compatible, number enum members are number-compatible).
Sourcepub fn is_enum_assignable_to(
&mut self,
enum_type: TypeId,
target_type: TypeId,
) -> bool
pub fn is_enum_assignable_to( &mut self, enum_type: TypeId, target_type: TypeId, ) -> bool
Check if an enum type is assignable to another type.
Enums are assignable to:
- Their exact enum type
- The primitive type (string/number) for literal enum members
Sourcepub fn is_enum_access_allowed(&self, enum_type: TypeId) -> bool
pub fn is_enum_access_allowed(&self, enum_type: TypeId) -> bool
Check if an enum access is allowed (not a const enum).
Const enums cannot be accessed as values at runtime - they are fully inlined. This check prevents runtime errors from accessing const enum members.
Sourcepub fn get_enum_member_access_type(&self, enum_type: TypeId) -> TypeId
pub fn get_enum_member_access_type(&self, enum_type: TypeId) -> TypeId
Get the type of an enum member access.
For enum members, this returns the literal type of the member
(e.g., “Red” for Color.Red in a string enum).
Sourcepub fn is_boxed_primitive_type(&self, type_id: TypeId) -> bool
pub fn is_boxed_primitive_type(&self, type_id: TypeId) -> bool
Check if a type is a boxed primitive type (Number, String, Boolean, BigInt, Symbol).
TypeScript has two representations for primitives:
number,string,boolean- primitive types (valid for arithmetic)Number,String,Boolean- interface wrapper types from lib.d.ts (NOT valid for arithmetic)
This method detects the boxed interface types to emit proper TS2362/TS2363/TS2365 errors.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_iterable_type(&mut self, type_id: TypeId) -> bool
pub fn is_iterable_type(&mut self, type_id: TypeId) -> bool
Check if a type is iterable (has Symbol.iterator protocol).
A type is iterable if it is:
- String type
- Array type
- Tuple type
- Has a [Symbol.iterator] method
- A union where all members are iterable
- An intersection where at least one member is iterable
Sourcepub fn is_async_iterable_type(&mut self, type_id: TypeId) -> bool
pub fn is_async_iterable_type(&mut self, type_id: TypeId) -> bool
Check if a type is async iterable (has Symbol.asyncIterator protocol).
Sourcepub fn for_of_element_type(&mut self, iterable_type: TypeId) -> TypeId
pub fn for_of_element_type(&mut self, iterable_type: TypeId) -> TypeId
Compute the element type produced by a for (... of expr) loop.
Handles arrays, tuples, unions, strings, and custom iterators via
the [Symbol.iterator]().next().value protocol.
Sourcepub fn check_for_of_iterability(
&mut self,
expr_type: TypeId,
expr_idx: NodeIndex,
is_async: bool,
) -> bool
pub fn check_for_of_iterability( &mut self, expr_type: TypeId, expr_idx: NodeIndex, is_async: bool, ) -> bool
Check iterability of a for-of expression and emit TS2488/TS2495/TS2504 if not iterable.
Returns true if the type is iterable (or async iterable for for-await-of).
Sourcepub fn check_spread_iterability(
&mut self,
spread_type: TypeId,
expr_idx: NodeIndex,
) -> bool
pub fn check_spread_iterability( &mut self, spread_type: TypeId, expr_idx: NodeIndex, ) -> bool
Check iterability of a spread argument and emit TS2488 if not iterable.
Used for spread in array literals and function call arguments.
Returns true if the type is iterable.
Sourcepub fn check_destructuring_iterability(
&mut self,
pattern_idx: NodeIndex,
pattern_type: TypeId,
init_expr: NodeIndex,
) -> bool
pub fn check_destructuring_iterability( &mut self, pattern_idx: NodeIndex, pattern_type: TypeId, init_expr: NodeIndex, ) -> bool
Check iterability for array destructuring patterns and emit TS2488 if not iterable.
This function is called before assigning types to binding elements in array destructuring to ensure that the source type is iterable.
§Parameters:
pattern_idx: The array binding pattern node indexpattern_type: The type being destructuredinit_expr: The initializer expression (used for error location)
§Validation:
- Checks if
pattern_typeis iterable - Emits TS2488 if the type is not iterable
- Skips check for ANY, UNKNOWN, ERROR types (defer to other checks)
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_promise_like_name(&self, name: &str) -> bool
pub fn is_promise_like_name(&self, name: &str) -> bool
Check if a name refers to a Promise-like type.
Returns true for “Promise”, “PromiseLike”, or any name containing “Promise”.
This handles built-in Promise types as well as custom Promise implementations.
Sourcepub fn type_ref_is_promise_like(&self, type_id: TypeId) -> bool
pub fn type_ref_is_promise_like(&self, type_id: TypeId) -> bool
Check if a type reference is a Promise or Promise-like type.
This handles:
- Direct Promise/PromiseLike references
- Promise
type applications - Object types from lib files (conservatively assumed to be Promise-like)
Sourcepub fn is_promise_type(&self, type_id: TypeId) -> bool
pub fn is_promise_type(&self, type_id: TypeId) -> bool
Check if a type is a Promise or Promise-like type.
This is used to validate async function return types.
Handles both Promise
IMPORTANT: This method is STRICT - it only returns true for actual Promise/PromiseLike types. It does NOT use the conservative assumption that all Object types might be Promise-like. This ensures TS2705 is correctly emitted for async functions with non-Promise return types.
Sourcepub fn check_global_promise_available(&mut self)
pub fn check_global_promise_available(&mut self)
Check if the global Promise type is available, emit TS2318 if not.
Called when processing async functions to ensure Promise is available. Matches TSC behavior which emits TS2318 “Cannot find global type ‘Promise’” when the Promise type is not in scope - INCLUDING when noLib is true.
Sourcepub fn promise_like_return_type_argument(
&mut self,
return_type: TypeId,
) -> Option<TypeId>
pub fn promise_like_return_type_argument( &mut self, return_type: TypeId, ) -> Option<TypeId>
Extract the type argument from a Promise
Returns Some(T) if the type is Promise
- Synthetic
PROMISE_BASEtype (when Promise symbol wasn’t resolved) - Direct Promise
applications - Type aliases that expand to Promise
- Classes that extend Promise
Sourcepub fn promise_like_type_argument_from_base(
&mut self,
base: TypeId,
args: &[TypeId],
visited_aliases: &mut Vec<SymbolId>,
) -> Option<TypeId>
pub fn promise_like_type_argument_from_base( &mut self, base: TypeId, args: &[TypeId], visited_aliases: &mut Vec<SymbolId>, ) -> Option<TypeId>
Extract type argument from a Promise-like base type.
Handles:
- Direct Promise/PromiseLike types
- Type aliases to Promise types
- Classes that extend Promise
Sourcepub fn promise_like_type_argument_from_alias(
&mut self,
sym_id: SymbolId,
args: &[TypeId],
visited_aliases: &mut Vec<SymbolId>,
) -> Option<TypeId>
pub fn promise_like_type_argument_from_alias( &mut self, sym_id: SymbolId, args: &[TypeId], visited_aliases: &mut Vec<SymbolId>, ) -> Option<TypeId>
Extract type argument from a type alias that expands to a Promise type.
For example, given type MyPromise<T> = Promise<T>, this extracts
the type argument from MyPromise.
Sourcepub fn promise_like_type_argument_from_class(
&mut self,
sym_id: SymbolId,
args: &[TypeId],
visited_aliases: &mut Vec<SymbolId>,
) -> Option<TypeId>
pub fn promise_like_type_argument_from_class( &mut self, sym_id: SymbolId, args: &[TypeId], visited_aliases: &mut Vec<SymbolId>, ) -> Option<TypeId>
Extract type argument from a class that extends Promise.
For example, given class MyPromise<T> extends Promise<T>, this extracts
the type argument from MyPromise.
Sourcepub fn requires_return_value(&self, return_type: TypeId) -> bool
pub fn requires_return_value(&self, return_type: TypeId) -> bool
Check if a return type requires a return value.
Returns false for void, undefined, any, never, unknown, error types, and unions containing void/undefined. Returns true for all other types.
Sourcepub fn should_skip_no_implicit_return_check(
&self,
return_type: TypeId,
has_type_annotation: bool,
) -> bool
pub fn should_skip_no_implicit_return_check( &self, return_type: TypeId, has_type_annotation: bool, ) -> bool
Check if TS7030 (noImplicitReturns) should be skipped for this return type.
TSC skips TS7030 for functions whose return type is or contains void or any.
Top-level undefined also causes a skip, but undefined in a union does NOT.
For unannotated functions, we only check top-level types because our inferred
return types use void for implicit fall-through (TSC uses undefined).
Sourcepub fn return_type_for_implicit_return_check(
&mut self,
return_type: TypeId,
is_async: bool,
is_generator: bool,
) -> TypeId
pub fn return_type_for_implicit_return_check( &mut self, return_type: TypeId, is_async: bool, is_generator: bool, ) -> TypeId
Get the return type for implicit return checking.
For async functions, this unwraps Promise
Sourcepub fn return_type_annotation_looks_like_promise(
&self,
type_annotation: NodeIndex,
) -> bool
pub fn return_type_annotation_looks_like_promise( &self, type_annotation: NodeIndex, ) -> bool
Check if a return type annotation syntactically looks like Promise
This is a fallback for when the type can’t be resolved but the syntax is clearly Promise. Used for better error messages when Promise types are not available.
Sourcepub fn is_null_or_undefined_only(&self, return_type: TypeId) -> bool
pub fn is_null_or_undefined_only(&self, return_type: TypeId) -> bool
Check if a type is null or undefined only.
Returns true for the null type, undefined type, or unions that only contain null and/or undefined.
Sourcepub fn get_generator_return_type_argument(
&mut self,
type_id: TypeId,
) -> Option<TypeId>
pub fn get_generator_return_type_argument( &mut self, type_id: TypeId, ) -> Option<TypeId>
Extract the TReturn type argument from Generator<Y, R, N> or AsyncGenerator<Y, R, N>.
For generator functions with explicit return types, the return statement
should be checked against TReturn (the second type argument), not the full
Generator/AsyncGenerator type.
Returns Some(TReturn) if the type is a Generator/AsyncGenerator/Iterator/AsyncIterator
type application with at least 2 type arguments, otherwise None.
Sourcepub fn get_generator_yield_type_argument(
&mut self,
type_id: TypeId,
) -> Option<TypeId>
pub fn get_generator_yield_type_argument( &mut self, type_id: TypeId, ) -> Option<TypeId>
Extract the TYield type argument from Generator<Y, R, N> or AsyncGenerator<Y, R, N>.
For yield expr in a generator with an explicit return annotation,
expr must be assignable to TYield (the first type argument).
Sourcepub fn unwrap_promise_type(&mut self, type_id: TypeId) -> Option<TypeId>
pub fn unwrap_promise_type(&mut self, type_id: TypeId) -> Option<TypeId>
Unwrap Promise
For async functions with declared return type Promise<T>, the function body
should return values of type T (which get auto-wrapped in Promise).
This function extracts T from Promise
Returns None if the type is not a Promise type or if T cannot be extracted.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_abstract_ctor(&self, type_id: TypeId) -> bool
pub fn is_abstract_ctor(&self, type_id: TypeId) -> bool
Check if a type is an abstract constructor type.
Abstract constructors cannot be instantiated directly with new.
Sourcepub fn is_private_ctor(&self, type_id: TypeId) -> bool
pub fn is_private_ctor(&self, type_id: TypeId) -> bool
Check if a type is a private constructor.
Private constructors can only be called from within the class.
Sourcepub fn is_protected_ctor(&self, type_id: TypeId) -> bool
pub fn is_protected_ctor(&self, type_id: TypeId) -> bool
Check if a type is a protected constructor.
Protected constructors can be called from the class and its subclasses.
Sourcepub fn is_public_ctor(&self, type_id: TypeId) -> bool
pub fn is_public_ctor(&self, type_id: TypeId) -> bool
Check if a type is a public constructor.
Public constructors have no access restrictions.
Sourcepub fn has_construct_sig(&self, type_id: TypeId) -> bool
pub fn has_construct_sig(&self, type_id: TypeId) -> bool
Check if a type has any construct signature.
Construct signatures allow a type to be called with new.
Sourcepub fn construct_signature_count(&self, type_id: TypeId) -> usize
pub fn construct_signature_count(&self, type_id: TypeId) -> usize
Get the number of construct signatures for a type.
Multiple construct signatures indicate constructor overloading.
Sourcepub fn can_instantiate(&self, constructor_type: TypeId) -> bool
pub fn can_instantiate(&self, constructor_type: TypeId) -> bool
Check if a constructor can be instantiated.
Returns false for abstract constructors which cannot be instantiated.
Sourcepub fn can_use_new(&self, type_id: TypeId) -> bool
pub fn can_use_new(&self, type_id: TypeId) -> bool
Check if new can be applied to a type.
This is a convenience check combining constructor type detection with abstract constructor checking.
Sourcepub fn is_class_constructor_type(&self, type_id: TypeId) -> bool
pub fn is_class_constructor_type(&self, type_id: TypeId) -> bool
Check if a type is a class constructor (typeof Class).
Returns true for Callable types with only construct signatures (no call signatures).
This is used to detect when a class constructor is being called without new.
Sourcepub fn ctor_access_compatible(&self, source: TypeId, target: TypeId) -> bool
pub fn ctor_access_compatible(&self, source: TypeId, target: TypeId) -> bool
Check if two constructor types have compatible accessibility.
Returns true if source can be assigned to target based on their constructor accessibility.
- Public constructors are compatible with everything
- Private constructors are only compatible with the same private constructor
- Protected constructors are compatible with protected or public targets
Sourcepub fn is_newable(&self, type_id: TypeId) -> bool
pub fn is_newable(&self, type_id: TypeId) -> bool
Check if a type should be treated as a constructor in new expressions.
This determines if a type can be used with the new operator.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn check_flow_usage(
&mut self,
idx: NodeIndex,
declared_type: TypeId,
sym_id: SymbolId,
) -> TypeId
pub fn check_flow_usage( &mut self, idx: NodeIndex, declared_type: TypeId, sym_id: SymbolId, ) -> TypeId
Check flow-aware usage of a variable (definite assignment + type narrowing).
This is the main entry point for flow analysis when variables are used. It combines two critical TypeScript features:
- Definite Assignment Analysis: Catches use-before-assignment errors
- Type Narrowing: Refines types based on control flow
§Definite Assignment Checking:
- Block-scoped variables (let/const) without initializers are checked
- Variables are tracked through all code paths
- TS2454 error emitted if variable might not be assigned
- Error: “Variable ‘x’ is used before being assigned”
§Type Narrowing:
- If definitely assigned, applies flow-based type narrowing
- typeof guards, discriminant checks, null checks refine types
- Returns narrowed type for precise type checking
§Rule #42 Integration:
- If inside a closure and variable is mutable (let/var): Returns declared type
- If inside a closure and variable is const: Applies narrowing
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn new(
arena: &'a NodeArena,
binder: &'a BinderState,
types: &'a dyn QueryDatabase,
file_name: String,
compiler_options: CheckerOptions,
) -> CheckerState<'a>
pub fn new( arena: &'a NodeArena, binder: &'a BinderState, types: &'a dyn QueryDatabase, file_name: String, compiler_options: CheckerOptions, ) -> CheckerState<'a>
Create a new CheckerState.
§Arguments
arena- The AST node arenabinder- The binder state with symbolstypes- The shared type interner (for thread-safe type deduplication)file_name- The source file namecompiler_options- Compiler options for type checking
Create a new CheckerState with a shared DefinitionStore.
This ensures that all type definitions (interfaces, type aliases, etc.) across
different files and lib contexts share the same DefId namespace, preventing
DefId collisions.
§Arguments
definition_store- SharedDefinitionStore(wrapped in Arc for thread-safety)- Other args same as
new()
Sourcepub fn with_cache(
arena: &'a NodeArena,
binder: &'a BinderState,
types: &'a dyn QueryDatabase,
file_name: String,
cache: TypeCache,
compiler_options: CheckerOptions,
) -> CheckerState<'a>
pub fn with_cache( arena: &'a NodeArena, binder: &'a BinderState, types: &'a dyn QueryDatabase, file_name: String, cache: TypeCache, compiler_options: CheckerOptions, ) -> CheckerState<'a>
Create a new CheckerState with a persistent cache.
This allows reusing type checking results from previous queries.
§Arguments
arena- The AST node arenabinder- The binder state with symbolstypes- The shared type internerfile_name- The source file namecache- The persistent type cache from previous queriescompiler_options- Compiler options for type checking
Sourcepub fn with_parent_cache(
arena: &'a NodeArena,
binder: &'a BinderState,
types: &'a dyn QueryDatabase,
file_name: String,
compiler_options: CheckerOptions,
parent: &CheckerState<'a>,
) -> CheckerState<'a>
pub fn with_parent_cache( arena: &'a NodeArena, binder: &'a BinderState, types: &'a dyn QueryDatabase, file_name: String, compiler_options: CheckerOptions, parent: &CheckerState<'a>, ) -> CheckerState<'a>
Create a child CheckerState that shares the parent’s caches.
This is used for temporary checkers (e.g., cross-file symbol resolution)
to ensure cache results are not lost (fixes Cache Isolation Bug).
Sourcepub fn with_options(
arena: &'a NodeArena,
binder: &'a BinderState,
types: &'a dyn QueryDatabase,
file_name: String,
compiler_options: &CheckerOptions,
) -> CheckerState<'a>
pub fn with_options( arena: &'a NodeArena, binder: &'a BinderState, types: &'a dyn QueryDatabase, file_name: String, compiler_options: &CheckerOptions, ) -> CheckerState<'a>
Create a new CheckerState with explicit compiler options.
§Arguments
arena- The AST node arenabinder- The binder state with symbolstypes- The shared type internerfile_name- The source file namecompiler_options- Compiler options for type checking
Create a new CheckerState with explicit compiler options and a shared DefinitionStore.
This is used in parallel checking to ensure all files share the same DefId namespace.
Sourcepub fn with_cache_and_options(
arena: &'a NodeArena,
binder: &'a BinderState,
types: &'a dyn QueryDatabase,
file_name: String,
cache: TypeCache,
compiler_options: &CheckerOptions,
) -> CheckerState<'a>
pub fn with_cache_and_options( arena: &'a NodeArena, binder: &'a BinderState, types: &'a dyn QueryDatabase, file_name: String, cache: TypeCache, compiler_options: &CheckerOptions, ) -> CheckerState<'a>
Create a new CheckerState with explicit compiler options and a persistent cache.
Sourcepub fn extract_cache(self) -> TypeCache
pub fn extract_cache(self) -> TypeCache
Extract the persistent cache from this checker. This allows saving type checking results for future queries.
Sourcepub fn push_return_type(&mut self, return_type: TypeId)
pub fn push_return_type(&mut self, return_type: TypeId)
Push an expected return type onto the stack when entering a function.
This function is called when entering a function to track the expected return type. The stack is used to validate that all return statements are compatible with the function’s declared return type.
Return Type Stack:
- Functions can be nested (inner functions, closures)
- Stack tracks return type for each nesting level
- Pushed when entering function, popped when exiting
Use Cases:
- Function declarations:
function foo(): string {} - Function expressions:
const f = function(): number {} - Arrow functions:
const f = (): boolean => {} - Method declarations
Validation:
- Return statements are checked against the top of stack
- Enables early error detection for mismatched return types
Sourcepub fn pop_return_type(&mut self)
pub fn pop_return_type(&mut self)
Pop an expected return type from the stack when exiting a function.
This function is called when exiting a function to remove the expected return type from the stack. This restores the previous return type for nested functions.
Stack Management:
- Pops the most recently pushed return type
- Restores previous return type (for nested functions)
- Must be called once per push (balanced push/pop)
Sourcepub fn current_return_type(&self) -> Option<TypeId>
pub fn current_return_type(&self) -> Option<TypeId>
Get the current expected return type if in a function.
Returns the return type at the top of the return type stack. Returns None if not inside a function (stack is empty).
Use Cases:
- Validating return statements:
return value; - Checking function body completeness
- Contextual typing for return expressions
Nesting:
- Returns the innermost function’s return type
- Handles nested functions and closures correctly
Sourcepub fn error(&mut self, start: u32, length: u32, message: String, code: u32)
pub fn error(&mut self, start: u32, length: u32, message: String, code: u32)
Add an error diagnostic to the diagnostics collection.
This is the main entry point for reporting type errors. All error reporting flows through this function (directly or through helper functions).
Diagnostic Components:
- start: Byte offset of error start in file
- length: Length of the error span in bytes
- message: Human-readable error message
- code: TypeScript error code (
TSxxxx)
Error Categories:
- Error: Type errors that prevent compilation
- Warning: Potential issues that don’t prevent compilation
- Suggestion: Code quality suggestions
Error Codes:
- TS2304: Cannot find name
- TS2322: Type is not assignable
- TS2339: Property does not exist
- And many more…
Use Cases:
- Direct error emission:
self.error(start, length, message, 2304) - Through helper functions:
error_cannot_find_name_at,error_type_not_assignable_at, etc. - Error messages are formatted with type information
Sourcepub fn get_node_span(&self, idx: NodeIndex) -> Option<(u32, u32)>
pub fn get_node_span(&self, idx: NodeIndex) -> Option<(u32, u32)>
Get the (start, end) span of a node for error reporting.
This function retrieves the position information of an AST node, which is used for error reporting and IDE features.
Span Information:
- Returns
(start, end)tuple of byte offsets - Start is the byte offset of the node’s first character
- End is the byte offset of the node’s last character
- Returns None if node doesn’t exist in arena
Use Cases:
- Error reporting:
self.error(start, end - start, message, code) - Diagnostic spans: Point to the problematic code
- Quick info: Hover information for IDE
- Code navigation: Jump to definition references
Sourcepub fn emit_error_at(
&mut self,
start: u32,
length: u32,
message: &str,
code: u32,
)
pub fn emit_error_at( &mut self, start: u32, length: u32, message: &str, code: u32, )
Emit an error diagnostic at a specific source position.
Sourcepub fn get_symbol_at_node(&self, idx: NodeIndex) -> Option<SymbolId>
pub fn get_symbol_at_node(&self, idx: NodeIndex) -> Option<SymbolId>
Get the symbol for a node index.
Sourcepub fn get_symbol_by_name(&self, name: &str) -> Option<SymbolId>
pub fn get_symbol_by_name(&self, name: &str) -> Option<SymbolId>
Get the symbol by name from file locals.
Sourcepub fn get_type_of_node(&mut self, idx: NodeIndex) -> TypeId
pub fn get_type_of_node(&mut self, idx: NodeIndex) -> TypeId
Get the type of a node. Get the type of an AST node with caching and circular reference detection.
This is the main entry point for type computation. All type checking ultimately flows through this function to get the type of AST nodes.
§Caching:
- Types are cached in
ctx.node_typesby node index - Subsequent calls for the same node return the cached type
- Cache is checked first before computation
§Fuel Management:
- Consumes fuel on each call to prevent infinite loops
- Returns ERROR if fuel is exhausted (prevents type checker timeout)
- Fuel is reset between file check operations
§Circular Reference Detection:
- Tracks currently resolving nodes in
ctx.node_resolution_set - Returns ERROR if a circular reference is detected
- Helps expose type resolution bugs early
§Examples:
let x = 42; // Type: number
let y = x; // Type: number (from cache)
let z = x + y; // Types: x=number, y=number, result=number§Performance:
- Caching prevents redundant type computation
- Circular reference detection prevents infinite recursion
- Fuel management ensures termination even for malformed code
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn check_source_file(&mut self, root_idx: NodeIndex)
pub fn check_source_file(&mut self, root_idx: NodeIndex)
Check a source file and populate diagnostics (main entry point).
This is the primary entry point for type checking after parsing and binding. It traverses the entire AST and performs all type checking operations.
§Checking Process:
- Initializes the type environment
- Traverses all top-level declarations
- Checks all statements and expressions
- Populates diagnostics with errors and warnings
§What Gets Checked:
- Type annotations
- Assignments (variable, property, return)
- Function calls
- Property access
- Type compatibility (extends, implements)
- Flow analysis (definite assignment, type narrowing)
- Generic constraints
- And much more…
§Diagnostics:
- Errors are added to
ctx.diagnostics - Includes error codes (
TSxxxx) and messages - Spans point to the problematic code
§Compilation Flow:
- Parser: Source code → AST
- Binder: AST → Symbols (scopes, declarations)
- Checker (this function): AST + Symbols → Types + Diagnostics
§TypeScript Example:
// File: example.ts
let x: string = 42; // Type error: number not assignable to string
function foo(a: number): string {
return a; // Type error: number not assignable to string
}
interface User {
name: string;
}
const user: User = { age: 25 }; // Type error: missing 'name' property
// check_source_file() would find all three errors aboveSource§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn get_type_of_symbol(&mut self, sym_id: SymbolId) -> TypeId
pub fn get_type_of_symbol(&mut self, sym_id: SymbolId) -> TypeId
Get type of a symbol with caching and circular reference detection.
This is the main entry point for resolving the type of symbols (variables, functions, classes, interfaces, type aliases, etc.). All type resolution ultimately flows through this function.
§Caching:
- Symbol types are cached in
ctx.symbol_typesby symbol ID - Subsequent calls for the same symbol return the cached type
- Cache is populated on first successful resolution
§Fuel Management:
- Consumes fuel on each call to prevent infinite loops
- Returns ERROR if fuel is exhausted (prevents type checker timeout)
§Circular Reference Detection:
- Tracks currently resolving symbols in
ctx.symbol_resolution_set - Returns ERROR if a circular reference is detected
- Uses a stack to track resolution depth
§Type Environment Population:
- After resolution, populates the type environment for generic type expansion
- For classes: Handles instance type with type parameters specially
- For generic types: Stores both the type and its type parameters
- Skips ANY/ERROR types (don’t populate environment for errors)
§Symbol Dependency Tracking:
- Records symbol dependencies for incremental type checking
- Pushes/pops from dependency stack during resolution
§TypeScript Examples:
let x = 42; // get_type_of_symbol(x) → number
function foo(): void {} // get_type_of_symbol(foo) → () => void
class C {} // get_type_of_symbol(C) → typeof C (constructor)
interface I {} // get_type_of_symbol(I) → I (interface type)
type T = string; // get_type_of_symbol(T) → stringSource§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn build_type_environment(&mut self) -> TypeEnvironment
pub fn build_type_environment(&mut self) -> TypeEnvironment
Create a TypeEnvironment populated with resolved symbol types.
This can be passed to is_assignable_to_with_env for type checking
that needs to resolve type references.
Sourcepub fn get_union_type(&self, types: Vec<TypeId>) -> TypeId
pub fn get_union_type(&self, types: Vec<TypeId>) -> TypeId
Create a union type from multiple types.
Handles empty (→ NEVER), single (→ that type), and multi-member cases. Automatically normalizes: flattens nested unions, deduplicates, sorts.
Sourcepub fn get_type_from_type_node(&mut self, idx: NodeIndex) -> TypeId
pub fn get_type_from_type_node(&mut self, idx: NodeIndex) -> TypeId
Get type from a type node.
Uses compile-time constant TypeIds for intrinsic types (O(1) lookup).
Get the type representation of a type annotation node.
This is the main entry point for converting type annotation AST nodes into
TypeId representations. Handles all TypeScript type syntax.
§Special Node Handling:
TypeReference: Validates existence before lowering (catches missing types)TypeQuery(typeof X): Resolves via binder for proper symbol resolutionUnionType: Handles specially for nested typeof expression resolutionTypeLiteral: Uses checker resolution for type parameter support- Other nodes: Delegated to
TypeLowering
§Type Parameter Bindings:
- Uses current type parameter bindings from scope
- Allows type parameters to resolve correctly in generic contexts
§Symbol Resolvers:
- Provides type/value symbol resolvers to
TypeLowering - Resolves type references and value references (for typeof)
§Error Reporting:
- Checks for missing names before lowering
- Emits appropriate errors for undefined types
§TypeScript Examples:
// Primitive types
let x: string; // → STRING
let y: number | boolean; // → Union(NUMBER, BOOLEAN)
// Type references
interface Foo {}
let z: Foo; // → Ref to Foo symbol
// Generic types
let a: Array<string>; // → Application(Array, [STRING])
// Type queries
let value = 42;
let b: typeof value; // → TypeQuery(value symbol)
// Type literals
let c: { x: number }; // → Object type with property x: numberSourcepub fn get_source_location(&self, idx: NodeIndex) -> Option<SourceLocation>
pub fn get_source_location(&self, idx: NodeIndex) -> Option<SourceLocation>
Get a source location for a node.
Sourcepub fn format_type(&self, type_id: TypeId) -> String
pub fn format_type(&self, type_id: TypeId) -> String
Format a type as a human-readable string for error messages and diagnostics.
This is the main entry point for converting TypeId representations into
human-readable type strings. Used throughout the type checker for error
messages, quick info, and IDE features.
§Formatting Strategy:
- Delegates to the solver’s
TypeFormatter - Provides symbol table for resolving symbol names
- Handles all type constructs (primitives, generics, unions, etc.)
§Type Formatting Rules:
- Primitives: Display as intrinsic names (string, number, etc.)
- Literals: Display as literal values (“hello”, 42, true)
- Arrays: Display as T[] or Array
- Tuples: Display as [T, U, V]
- Unions: Display as T | U | V (with parentheses when needed)
- Intersections: Display as T & U & V (with parentheses when needed)
- Functions: Display as (args) => return
- Objects: Display as { prop: Type; … }
- Type Parameters: Display as T, U, V (short names)
- Type References: Display as
RefName
§Use Cases:
- Error messages: “Type X is not assignable to Y”
- Quick info (hover): Type information for IDE
- Completion: Type hints in autocomplete
- Diagnostics: All type-related error messages
§TypeScript Examples (Formatted Output):
// Primitives
let x: string; // format_type → "string"
let y: number; // format_type → "number"
// Literals
let a: "hello"; // format_type → "\"hello\""
let b: 42; // format_type → "42"
// Composed types
type Pair = [string, number];
// format_type(Pair) → "[string, number]"
type Union = string | number | boolean;
// format_type(Union) → "string | number | boolean"
// Generics
type Map<K, V> = Record<K, V>;
// format_type(Map<string, number>) → "Record<string, number>"
// Functions
type Handler = (data: string) => void;
// format_type(Handler) → "(data: string) => void"
// Objects
type User = { name: string; age: number };
// format_type(User) → "{ name: string; age: number }"
// Complex
type Complex = Array<{ id: number } | null>;
// format_type(Complex) → "Array<{ id: number } | null>"Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn resolve_lazy_type(&mut self, type_id: TypeId) -> TypeId
pub fn resolve_lazy_type(&mut self, type_id: TypeId) -> TypeId
Resolve a lazy type (type alias) to its body type.
This function resolves TypeData::Lazy(DefId) types by looking up the
definition’s body in the definition store. This is necessary for
type aliases like type Tuple = [string, number] where the reference
to Tuple is stored as a lazy type.
The function handles recursive type aliases by checking if the body is itself a lazy type and resolving it recursively.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn get_symbol_type(&mut self, sym_id: SymbolId) -> TypeId
pub fn get_symbol_type(&mut self, sym_id: SymbolId) -> TypeId
Get the type of a symbol with caching.
This is a convenience wrapper around get_type_of_symbol that
provides a clearer name for the operation.
Sourcepub fn is_global_intrinsic(&self, name: &str) -> bool
pub fn is_global_intrinsic(&self, name: &str) -> bool
Check if a name refers to a global intrinsic value.
Returns true for names like undefined, NaN, Infinity, etc.
Sourcepub fn is_global_constructor(&self, name: &str) -> bool
pub fn is_global_constructor(&self, name: &str) -> bool
Check if a name refers to a global constructor.
Returns true for built-in constructor names like Object, Array, etc.
Sourcepub fn get_symbol_name(&self, sym_id: SymbolId) -> Option<String>
pub fn get_symbol_name(&self, sym_id: SymbolId) -> Option<String>
Get the name of a symbol.
Returns the symbol’s name as a string, or None if the symbol doesn’t exist.
Sourcepub fn is_symbol_exported(&self, sym_id: SymbolId) -> bool
pub fn is_symbol_exported(&self, sym_id: SymbolId) -> bool
Check if a symbol is exported.
Returns true if the symbol has the exported flag set.
Sourcepub fn is_symbol_type_only(&self, sym_id: SymbolId) -> bool
pub fn is_symbol_type_only(&self, sym_id: SymbolId) -> bool
Check if a symbol is type-only (e.g., from import type).
Returns true if the symbol has the type-only flag set.
Sourcepub fn get_symbol_value_declaration(
&self,
sym_id: SymbolId,
) -> Option<NodeIndex>
pub fn get_symbol_value_declaration( &self, sym_id: SymbolId, ) -> Option<NodeIndex>
Get the value declaration of a symbol.
Returns the primary value declaration node for the symbol, if any.
Sourcepub fn get_symbol_declarations(&self, sym_id: SymbolId) -> Vec<NodeIndex>
pub fn get_symbol_declarations(&self, sym_id: SymbolId) -> Vec<NodeIndex>
Get all declarations for a symbol.
Returns all declaration nodes associated with the symbol.
Sourcepub fn symbol_has_flag(&self, sym_id: SymbolId, flag: u32) -> bool
pub fn symbol_has_flag(&self, sym_id: SymbolId, flag: u32) -> bool
Check if a symbol has a specific flag.
Returns true if the symbol has the specified flag bit set. Returns false if the symbol doesn’t exist.
Sourcepub fn symbol_flags_safe(&self, sym_id: SymbolId) -> u32
pub fn symbol_flags_safe(&self, sym_id: SymbolId) -> u32
Safely get symbol flags, returning 0 if symbol doesn’t exist.
This defensive accessor prevents crashes when symbol IDs are invalid or reference symbols that don’t exist in any binder.
Sourcepub fn symbol_flags_with_libs(
&self,
sym_id: SymbolId,
lib_binders: &[Arc<BinderState>],
) -> u32
pub fn symbol_flags_with_libs( &self, sym_id: SymbolId, lib_binders: &[Arc<BinderState>], ) -> u32
Safely get symbol flags with lib binders fallback.
Returns 0 if the symbol doesn’t exist in any binder.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn get_object_property_type(
&self,
object_type: TypeId,
property_name: &str,
) -> Option<TypeId>
pub fn get_object_property_type( &self, object_type: TypeId, property_name: &str, ) -> Option<TypeId>
Get the type of a property by name.
Returns the property type if found, or None otherwise.
Sourcepub fn object_has_property(
&self,
object_type: TypeId,
property_name: &str,
) -> bool
pub fn object_has_property( &self, object_type: TypeId, property_name: &str, ) -> bool
Check if an object has a specific property.
Returns true if the property exists on the object.
Sourcepub fn is_property_optional(
&self,
object_type: TypeId,
property_name: &str,
) -> bool
pub fn is_property_optional( &self, object_type: TypeId, property_name: &str, ) -> bool
Check if a property is optional.
Returns true if the property is marked as optional.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn is_in_namespace_context(&self, func_idx: NodeIndex) -> bool
pub fn is_in_namespace_context(&self, func_idx: NodeIndex) -> bool
Check if a function is within a namespace or module context.
Uses AST-based parent traversal to detect ModuleDeclaration in the parent chain.
§Parameters
func_idx: The function node index
Returns true if the function is inside a namespace/module declaration.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn prime_boxed_types(&mut self)
pub fn prime_boxed_types(&mut self)
Prime boxed and Array base types before checking files.
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
pub fn function_body_falls_through(&mut self, body_idx: NodeIndex) -> bool
Source§impl<'a> CheckerState<'a>
impl<'a> CheckerState<'a>
Sourcepub fn get_type_of_node_or(
&mut self,
idx: NodeIndex,
fallback: TypeId,
) -> TypeId
pub fn get_type_of_node_or( &mut self, idx: NodeIndex, fallback: TypeId, ) -> TypeId
Get the type of a node with a fallback.
Returns the computed type, or the fallback if the computed type is ERROR.
Trait Implementations§
Source§impl<'a> StatementCheckCallbacks for CheckerState<'a>
Implementation of StatementCheckCallbacks for CheckerState.
impl<'a> StatementCheckCallbacks for CheckerState<'a>
Implementation of StatementCheckCallbacks for CheckerState.
This provides the actual implementation of statement checking operations
that StatementChecker delegates to. Each callback method calls the
corresponding method on CheckerState.
Source§fn get_type_of_node(&mut self, idx: NodeIndex) -> TypeId
fn get_type_of_node(&mut self, idx: NodeIndex) -> TypeId
Source§fn get_type_of_node_no_narrowing(&mut self, idx: NodeIndex) -> TypeId
fn get_type_of_node_no_narrowing(&mut self, idx: NodeIndex) -> TypeId
Source§fn check_variable_statement(&mut self, stmt_idx: NodeIndex)
fn check_variable_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_variable_declaration_list(&mut self, list_idx: NodeIndex)
fn check_variable_declaration_list(&mut self, list_idx: NodeIndex)
Source§fn check_variable_declaration(&mut self, decl_idx: NodeIndex)
fn check_variable_declaration(&mut self, decl_idx: NodeIndex)
Source§fn check_return_statement(&mut self, stmt_idx: NodeIndex)
fn check_return_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_function_implementations(&mut self, stmts: &[NodeIndex])
fn check_function_implementations(&mut self, stmts: &[NodeIndex])
Source§fn check_function_declaration(&mut self, func_idx: NodeIndex)
fn check_function_declaration(&mut self, func_idx: NodeIndex)
Source§fn check_class_declaration(&mut self, class_idx: NodeIndex)
fn check_class_declaration(&mut self, class_idx: NodeIndex)
Source§fn check_interface_declaration(&mut self, iface_idx: NodeIndex)
fn check_interface_declaration(&mut self, iface_idx: NodeIndex)
Source§fn check_import_declaration(&mut self, import_idx: NodeIndex)
fn check_import_declaration(&mut self, import_idx: NodeIndex)
Source§fn check_import_equals_declaration(&mut self, import_idx: NodeIndex)
fn check_import_equals_declaration(&mut self, import_idx: NodeIndex)
Source§fn check_export_declaration(&mut self, export_idx: NodeIndex)
fn check_export_declaration(&mut self, export_idx: NodeIndex)
Source§fn check_type_alias_declaration(&mut self, type_alias_idx: NodeIndex)
fn check_type_alias_declaration(&mut self, type_alias_idx: NodeIndex)
Source§fn check_enum_duplicate_members(&mut self, enum_idx: NodeIndex)
fn check_enum_duplicate_members(&mut self, enum_idx: NodeIndex)
Source§fn check_module_declaration(&mut self, module_idx: NodeIndex)
fn check_module_declaration(&mut self, module_idx: NodeIndex)
Source§fn check_await_expression(&mut self, expr_idx: NodeIndex)
fn check_await_expression(&mut self, expr_idx: NodeIndex)
Source§fn check_for_await_statement(&mut self, stmt_idx: NodeIndex)
fn check_for_await_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_truthy_or_falsy(&mut self, node_idx: NodeIndex)
fn check_truthy_or_falsy(&mut self, node_idx: NodeIndex)
Source§fn check_callable_truthiness(
&mut self,
cond_expr: NodeIndex,
body: Option<NodeIndex>,
)
fn check_callable_truthiness( &mut self, cond_expr: NodeIndex, body: Option<NodeIndex>, )
Source§fn is_true_condition(&self, condition_idx: NodeIndex) -> bool
fn is_true_condition(&self, condition_idx: NodeIndex) -> bool
Source§fn is_false_condition(&self, condition_idx: NodeIndex) -> bool
fn is_false_condition(&self, condition_idx: NodeIndex) -> bool
Source§fn report_unreachable_statement(&mut self, stmt_idx: NodeIndex)
fn report_unreachable_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_for_in_expression_type(
&mut self,
expr_type: TypeId,
expression: NodeIndex,
)
fn check_for_in_expression_type( &mut self, expr_type: TypeId, expression: NodeIndex, )
Source§fn assign_for_in_of_initializer_types(
&mut self,
decl_list_idx: NodeIndex,
loop_var_type: TypeId,
is_for_in: bool,
)
fn assign_for_in_of_initializer_types( &mut self, decl_list_idx: NodeIndex, loop_var_type: TypeId, is_for_in: bool, )
is_for_in should be true for for-in loops (to emit TS2404 on type annotations).Source§fn for_of_element_type(&mut self, expr_type: TypeId) -> TypeId
fn for_of_element_type(&mut self, expr_type: TypeId) -> TypeId
Source§fn check_for_of_iterability(
&mut self,
expr_type: TypeId,
expr_idx: NodeIndex,
await_modifier: bool,
)
fn check_for_of_iterability( &mut self, expr_type: TypeId, expr_idx: NodeIndex, await_modifier: bool, )
Source§fn check_for_in_of_expression_initializer(
&mut self,
initializer: NodeIndex,
element_type: TypeId,
is_for_of: bool,
has_await_modifier: bool,
)
fn check_for_in_of_expression_initializer( &mut self, initializer: NodeIndex, element_type: TypeId, is_for_of: bool, has_await_modifier: bool, )
for (v of expr) where v is a pre-declared variable (not var v/let v/const v),
this checks: Read moreSource§fn check_for_in_destructuring_pattern(&mut self, initializer: NodeIndex)
fn check_for_in_destructuring_pattern(&mut self, initializer: NodeIndex)
Source§fn check_for_in_expression_destructuring(&mut self, initializer: NodeIndex)
fn check_for_in_expression_destructuring(&mut self, initializer: NodeIndex)
Source§fn check_statement(&mut self, stmt_idx: NodeIndex)
fn check_statement(&mut self, stmt_idx: NodeIndex)
check_statement).Source§fn check_switch_exhaustiveness(
&mut self,
_stmt_idx: NodeIndex,
expression: NodeIndex,
_case_block: NodeIndex,
has_default: bool,
)
fn check_switch_exhaustiveness( &mut self, _stmt_idx: NodeIndex, expression: NodeIndex, _case_block: NodeIndex, has_default: bool, )
Source§fn check_switch_case_comparable(
&mut self,
switch_type: TypeId,
case_type: TypeId,
switch_expr: NodeIndex,
case_expr: NodeIndex,
)
fn check_switch_case_comparable( &mut self, switch_type: TypeId, case_type: TypeId, switch_expr: NodeIndex, case_expr: NodeIndex, )
Source§fn check_with_statement(&mut self, stmt_idx: NodeIndex)
fn check_with_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_break_statement(&mut self, stmt_idx: NodeIndex)
fn check_break_statement(&mut self, stmt_idx: NodeIndex)
Source§fn check_continue_statement(&mut self, stmt_idx: NodeIndex)
fn check_continue_statement(&mut self, stmt_idx: NodeIndex)
Source§fn is_unreachable(&self) -> bool
fn is_unreachable(&self) -> bool
Source§fn set_unreachable(&mut self, value: bool)
fn set_unreachable(&mut self, value: bool)
Source§fn has_reported_unreachable(&self) -> bool
fn has_reported_unreachable(&self) -> bool
Source§fn set_reported_unreachable(&mut self, value: bool)
fn set_reported_unreachable(&mut self, value: bool)
Source§fn statement_falls_through(&mut self, stmt_idx: NodeIndex) -> bool
fn statement_falls_through(&mut self, stmt_idx: NodeIndex) -> bool
Source§fn enter_iteration_statement(&mut self)
fn enter_iteration_statement(&mut self)
iteration_depth for break/continue validation.Source§fn leave_iteration_statement(&mut self)
fn leave_iteration_statement(&mut self)
iteration_depth.Source§fn enter_switch_statement(&mut self)
fn enter_switch_statement(&mut self)
switch_depth for break validation.Source§fn leave_switch_statement(&mut self)
fn leave_switch_statement(&mut self)
switch_depth.Source§fn save_and_reset_control_flow_context(&mut self) -> (u32, u32, bool)
fn save_and_reset_control_flow_context(&mut self) -> (u32, u32, bool)
iteration_depth, switch_depth, had_outer_loop).Source§fn restore_control_flow_context(&mut self, saved: (u32, u32, bool))
fn restore_control_flow_context(&mut self, saved: (u32, u32, bool))
Source§fn enter_labeled_statement(&mut self, label: String, is_iteration: bool)
fn enter_labeled_statement(&mut self, label: String, is_iteration: bool)
is_iteration should be true if the labeled statement wraps an iteration statement.Source§fn leave_labeled_statement(&mut self)
fn leave_labeled_statement(&mut self)
Source§fn get_node_text(&self, idx: NodeIndex) -> Option<String>
fn get_node_text(&self, idx: NodeIndex) -> Option<String>
Source§fn check_declaration_in_statement_position(&mut self, stmt_idx: NodeIndex)
fn check_declaration_in_statement_position(&mut self, stmt_idx: NodeIndex)
Source§fn check_label_on_declaration(
&mut self,
label_idx: NodeIndex,
statement_idx: NodeIndex,
)
fn check_label_on_declaration( &mut self, label_idx: NodeIndex, statement_idx: NodeIndex, )
label_idx is the label identifier,
statement_idx is the inner statement.Auto Trait Implementations§
impl<'a> !Freeze for CheckerState<'a>
impl<'a> !RefUnwindSafe for CheckerState<'a>
impl<'a> !Send for CheckerState<'a>
impl<'a> !Sync for CheckerState<'a>
impl<'a> Unpin for CheckerState<'a>
impl<'a> UnsafeUnpin for CheckerState<'a>
impl<'a> !UnwindSafe for CheckerState<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more