@@ -25,6 +25,7 @@ import (
2525 "github.com/microsoft/typescript-go/internal/modulespecifiers"
2626 "github.com/microsoft/typescript-go/internal/scanner"
2727 "github.com/microsoft/typescript-go/internal/stringutil"
28+ "github.com/microsoft/typescript-go/internal/tracing"
2829 "github.com/microsoft/typescript-go/internal/tsoptions"
2930 "github.com/microsoft/typescript-go/internal/tspath"
3031 "github.com/zeebo/xxh3"
@@ -884,14 +885,16 @@ type Checker struct {
884885 nonExistentProperties collections.Set[NonExistentPropertyKey]
885886 deferredDiagnosticCallbacks []func()
886887
887- mu sync.Mutex
888+ mu sync.Mutex
889+ tracer *Tracer // Optional tracer for trace events and type recording (for --generateTrace)
888890}
889891
890- func NewChecker(program Program) (*Checker, *sync.Mutex) {
892+ func NewChecker(program Program, tracer *Tracer ) (*Checker, *sync.Mutex) {
891893 program.BindSourceFiles()
892894
893895 c := &Checker{}
894896 c.id = nextCheckerID.Add(1)
897+ c.tracer = tracer
895898 c.program = program
896899 c.compilerOptions = program.Options()
897900 c.files = program.SourceFiles()
@@ -2139,6 +2142,9 @@ func (c *Checker) checkSourceFile(ctx context.Context, sourceFile *ast.SourceFil
21392142 links := c.sourceFileLinks.Get(sourceFile)
21402143 if !links.typeChecked {
21412144 c.saveDeferredDiagnostics = true
2145+ if tr := c.tracer; tr != nil {
2146+ defer tr.Push(tracing.PhaseCheck, "checkSourceFile", map[string]any{"path": sourceFile.FileName()}, true)()
2147+ }
21422148 // Grammar checking
21432149 c.checkGrammarSourceFile(sourceFile)
21442150 c.renamedBindingElementsInTypes = nil
@@ -2441,6 +2447,9 @@ func (c *Checker) checkDeferredNodes(context *ast.SourceFile) {
24412447}
24422448
24432449func (c *Checker) checkDeferredNode(node *ast.Node) {
2450+ if tr := c.tracer; tr != nil {
2451+ defer tr.Push(tracing.PhaseCheck, "checkDeferredNode", map[string]any{"kind": node.Kind, "pos": node.Pos(), "end": node.End(), "path": ast.GetSourceFileOfNode(node).FileName()}, false)()
2452+ }
24442453 saveCurrentNode := c.currentNode
24452454 c.currentNode = node
24462455 c.instantiationCount = 0
@@ -2570,6 +2579,9 @@ func (c *Checker) checkTypeParameterDeferred(node *ast.Node) {
25702579 if ast.IsTypeOrJSTypeAliasDeclaration(node.Parent) && c.getDeclaredTypeOfSymbol(symbol).objectFlags&(ObjectFlagsAnonymous|ObjectFlagsMapped) == 0 {
25712580 c.error(node, diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types)
25722581 } else if modifiers == ast.ModifierFlagsIn || modifiers == ast.ModifierFlagsOut {
2582+ if tr := c.tracer; tr != nil {
2583+ defer tr.Push(tracing.PhaseCheckTypes, "checkTypeParameterDeferred", map[string]any{"parent": c.getDeclaredTypeOfSymbol(symbol).id, "id": typeParameter.id}, false)()
2584+ }
25732585 source := c.createMarkerType(symbol, typeParameter, core.IfElse(modifiers == ast.ModifierFlagsOut, c.markerSubTypeForCheck, c.markerSuperTypeForCheck))
25742586 target := c.createMarkerType(symbol, typeParameter, core.IfElse(modifiers == ast.ModifierFlagsOut, c.markerSuperTypeForCheck, c.markerSubTypeForCheck))
25752587 saveVarianceTypeParameter := typeParameter
@@ -5614,6 +5626,9 @@ func (c *Checker) checkVariableDeclarationList(node *ast.Node) {
56145626}
56155627
56165628func (c *Checker) checkVariableDeclaration(node *ast.Node) {
5629+ if tr := c.tracer; tr != nil {
5630+ defer tr.Push(tracing.PhaseCheck, "checkVariableDeclaration", map[string]any{"kind": node.Kind, "pos": node.Pos(), "end": node.End(), "path": ast.GetSourceFileOfNode(node).FileName()}, false)()
5631+ }
56175632 c.checkGrammarVariableDeclaration(node.AsVariableDeclaration())
56185633 c.checkVariableLikeDeclaration(node)
56195634}
@@ -7361,6 +7376,9 @@ func (c *Checker) checkExpression(node *ast.Node) *Type {
73617376}
73627377
73637378func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type {
7379+ if tr := c.tracer; tr != nil {
7380+ defer tr.Push(tracing.PhaseCheck, "checkExpression", map[string]any{"kind": node.Kind, "pos": node.Pos(), "end": node.End(), "path": ast.GetSourceFileOfNode(node).FileName()}, false)()
7381+ }
73647382 saveCurrentNode := c.currentNode
73657383 c.currentNode = node
73667384 c.instantiationCount = 0
@@ -21663,6 +21681,9 @@ func (c *Checker) instantiateTypeWithAlias(t *Type, m *TypeMapper, alias *TypeAl
2166321681 // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement
2166421682 // or expression. There is a very high likelihood we're dealing with a combination of infinite generic types
2166521683 // that perpetually generate new type identities, so we stop the recursion here by yielding the error type.
21684+ if tr := c.tracer; tr != nil {
21685+ tr.Instant(tracing.PhaseCheckTypes, "instantiateType_DepthLimit", map[string]any{"typeId": t.id, "instantiationDepth": c.instantiationDepth, "instantiationCount": c.instantiationCount})
21686+ }
2166621687 c.error(c.currentNode, diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite)
2166721688 return c.errorType
2166821689 }
@@ -24550,6 +24571,9 @@ func (c *Checker) newType(flags TypeFlags, objectFlags ObjectFlags, data TypeDat
2455024571 t.id = TypeId(c.TypeCount)
2455124572 t.checker = c
2455224573 t.data = data
24574+ if c.tracer != nil {
24575+ c.tracer.RecordType(t)
24576+ }
2455324577 return t
2455424578}
2455524579
@@ -25491,6 +25515,9 @@ func (c *Checker) removeSubtypes(types []*Type, hasObjectTypes bool) []*Type {
2549125515 // caps union types at 1000 unique object types.
2549225516 estimatedCount := (count / (length - i)) * length
2549325517 if estimatedCount > 1000000 {
25518+ if tr := c.tracer; tr != nil {
25519+ tr.Instant(tracing.PhaseCheckTypes, "removeSubtypes_DepthLimit", map[string]any{"estimatedCount": estimatedCount})
25520+ }
2549425521 c.error(c.currentNode, diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent)
2549525522 return nil
2549625523 }
@@ -26124,6 +26151,9 @@ func compareTypeIds(t1, t2 *Type) int {
2612426151func (c *Checker) checkCrossProductUnion(types []*Type) bool {
2612526152 size := c.getCrossProductUnionSize(types)
2612626153 if size >= 100_000 {
26154+ if tr := c.tracer; tr != nil {
26155+ tr.Instant(tracing.PhaseCheckTypes, "checkCrossProductUnion_DepthLimit", map[string]any{"size": size})
26156+ }
2612726157 c.error(c.currentNode, diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent)
2612826158 return false
2612926159 }
0 commit comments