From 5ab6f360553cb85eb2cdd2320df329ae9ee69cee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:53:19 +0000 Subject: [PATCH 1/4] Initial plan From c6bfbe89542e7d908e4e8d5a2154cab3c5429083 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 00:24:28 +0000 Subject: [PATCH 2/4] Port TypeScript PR #62243: Improve inference by not considering thisless functions context-sensitive Changes: - Binder: Add PropagatesThisKeyword container flag for signatures and arrow functions - Binder: Track seenThisKeyword in control flow containers, set ContainsThis on function-like nodes - Binder: Set seenThisKeyword for ThisKeyword expression nodes - Binder: Remove PropertyDeclaration case from GetContainerFlags - AST utilities: HasContextSensitiveParameters checks ContainsThis flag instead of always true - Checker: Add YieldExpression to isContextSensitive - Checker: Add hasContextSensitiveYieldExpression function - Checker: Update forEachYieldExpression to support early exit (return bool) - Checker: Skip any/unknown results in instantiateContextualType Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- internal/ast/utilities.go | 2 +- internal/binder/binder.go | 35 +++++++++++++++++++++-------------- internal/checker/checker.go | 29 +++++++++++++++++++++-------- internal/checker/utilities.go | 17 ++++++++++------- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 2cc3520e9a9..fbc59d31bac 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -3969,7 +3969,7 @@ func HasContextSensitiveParameters(node *Node) bool { // an implicit 'this' parameter which is subject to contextual typing. parameter := core.FirstOrNil(node.Parameters()) if parameter == nil || !IsThisParameter(parameter) { - return true + return node.Flags&NodeFlagsContainsThis != 0 } } } diff --git a/internal/binder/binder.go b/internal/binder/binder.go index f44ff210738..ccec8813dc6 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -39,6 +39,7 @@ const ( ContainerFlagsIsInterface ContainerFlags = 1 << 6 ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor ContainerFlags = 1 << 7 ContainerFlagsIsThisContainer ContainerFlags = 1 << 8 + ContainerFlagsPropagatesThisKeyword ContainerFlags = 1 << 9 ) type ExpandoAssignmentInfo struct { @@ -615,6 +616,9 @@ func (b *Binder) bind(node *ast.Node) bool { node.AsIdentifier().FlowNode = b.currentFlow b.checkContextualIdentifier(node) case ast.KindThisKeyword, ast.KindSuperKeyword: + if node.Kind == ast.KindThisKeyword { + b.seenThisKeyword = true + } node.AsKeywordExpression().FlowNode = b.currentFlow case ast.KindQualifiedName: if b.currentFlow != nil && ast.IsPartOfTypeQuery(node) { @@ -1520,6 +1524,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { saveExceptionTarget := b.currentExceptionTarget saveActiveLabelList := b.activeLabelList saveHasExplicitReturn := b.hasExplicitReturn + saveSeenThisKeyword := b.seenThisKeyword isImmediatelyInvoked := (containerFlags&ContainerFlagsIsFunctionExpression != 0 && !ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync) && !isGeneratorFunctionExpression(node) && @@ -1545,9 +1550,10 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { b.currentContinueTarget = nil b.activeLabelList = nil b.hasExplicitReturn = false + b.seenThisKeyword = false b.bindChildren(node) - // Reset all reachability check related flags on node (for incremental scenarios) - node.Flags &= ^ast.NodeFlagsReachabilityCheckFlags + // Reset flags (for incremental scenarios) + node.Flags &= ^(ast.NodeFlagsReachabilityCheckFlags | ast.NodeFlagsContainsThis) if b.currentFlow.Flags&ast.FlowFlagsUnreachable == 0 && containerFlags&ContainerFlagsIsFunctionLike != 0 { bodyData := node.BodyData() if bodyData != nil && ast.NodeIsPresent(bodyData.Body) { @@ -1558,11 +1564,13 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { bodyData.EndFlowNode = b.currentFlow } } + if b.seenThisKeyword { + node.Flags |= ast.NodeFlagsContainsThis + } if node.Kind == ast.KindSourceFile { node.Flags |= b.emitFlags node.AsSourceFile().EndFlowNode = b.currentFlow } - if b.currentReturnTarget != nil { b.addAntecedent(b.currentReturnTarget, b.currentFlow) b.currentFlow = b.finishFlowLabel(b.currentReturnTarget) @@ -1579,7 +1587,13 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { b.currentExceptionTarget = saveExceptionTarget b.activeLabelList = saveActiveLabelList b.hasExplicitReturn = saveHasExplicitReturn + if containerFlags&ContainerFlagsPropagatesThisKeyword != 0 { + b.seenThisKeyword = saveSeenThisKeyword || b.seenThisKeyword + } else { + b.seenThisKeyword = saveSeenThisKeyword + } } else if containerFlags&ContainerFlagsIsInterface != 0 { + saveSeenThisKeyword := b.seenThisKeyword b.seenThisKeyword = false b.bindChildren(node) // ContainsThis cannot overlap with HasExtendedUnicodeEscape on Identifier @@ -1588,6 +1602,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { } else { node.Flags &= ^ast.NodeFlagsContainsThis } + b.seenThisKeyword = saveSeenThisKeyword } else { b.bindChildren(node) } @@ -2525,24 +2540,16 @@ func GetContainerFlags(node *ast.Node) ContainerFlags { return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor | ContainerFlagsIsThisContainer } fallthrough - case ast.KindConstructor, ast.KindClassStaticBlockDeclaration: + case ast.KindConstructor, ast.KindFunctionDeclaration, ast.KindClassStaticBlockDeclaration: return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer case ast.KindMethodSignature, ast.KindCallSignature, ast.KindFunctionType, ast.KindConstructSignature, ast.KindConstructorType: - return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike - case ast.KindFunctionDeclaration: - return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer + return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsPropagatesThisKeyword case ast.KindFunctionExpression: return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression | ContainerFlagsIsThisContainer case ast.KindArrowFunction: - return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression + return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression | ContainerFlagsPropagatesThisKeyword case ast.KindModuleBlock: return ContainerFlagsIsControlFlowContainer - case ast.KindPropertyDeclaration: - if node.Initializer() != nil { - return ContainerFlagsIsControlFlowContainer | ContainerFlagsIsThisContainer - } else { - return ContainerFlagsNone - } case ast.KindCatchClause, ast.KindForStatement, ast.KindForInStatement, ast.KindForOfStatement, ast.KindCaseBlock: return ContainerFlagsIsBlockScopedContainer | ContainerFlagsHasLocals case ast.KindBlock: diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 96d1b4a1574..aac5c46145c 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -19849,7 +19849,7 @@ func mayReturnNever(fn *ast.Node) bool { func (c *Checker) checkAndAggregateYieldOperandTypes(fn *ast.Node, checkMode CheckMode) (yieldTypes []*Type, nextTypes []*Type) { isAsync := (getFunctionFlags(fn) & FunctionFlagsAsync) != 0 - forEachYieldExpression(fn.Body(), func(yieldExpr *ast.Node) { + forEachYieldExpression(fn.Body(), func(yieldExpr *ast.Node) bool { yieldExprType := c.undefinedWideningType if yieldExpr.Expression() != nil { yieldExprType = c.checkExpressionEx(yieldExpr.Expression(), checkMode) @@ -19868,6 +19868,7 @@ func (c *Checker) checkAndAggregateYieldOperandTypes(fn *ast.Node, checkMode Che if nextType != nil { nextTypes = core.AppendIfUnique(nextTypes, nextType) } + return false }) return yieldTypes, nextTypes } @@ -29953,7 +29954,10 @@ func (c *Checker) instantiateContextualType(contextualType *Type, node *ast.Node if contextFlags&ContextFlagsSignature != 0 && core.Some(inferenceContext.inferences, hasInferenceCandidatesOrDefault) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. - return c.instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper) + t := c.instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper) + if t.flags&TypeFlagsAnyOrUnknown == 0 { + return t + } } if inferenceContext.returnMapper != nil { // For other purposes (e.g. determining whether to produce literal types) we only @@ -29961,12 +29965,14 @@ func (c *Checker) instantiateContextualType(contextualType *Type, node *ast.Node // the 'boolean' type from the contextual type such that contextually typed boolean // literals actually end up widening to 'boolean' (see #48363). t := c.instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper) - if t.flags&TypeFlagsUnion != 0 && containsType(t.Types(), c.regularFalseType) && containsType(t.Types(), c.regularTrueType) { - return c.filterType(t, func(t *Type) bool { - return t != c.regularFalseType && t != c.regularTrueType - }) + if t.flags&TypeFlagsAnyOrUnknown == 0 { + if t.flags&TypeFlagsUnion != 0 && containsType(t.Types(), c.regularFalseType) && containsType(t.Types(), c.regularTrueType) { + return c.filterType(t, func(t *Type) bool { + return t != c.regularFalseType && t != c.regularTrueType + }) + } + return t } - return t } } } @@ -30045,12 +30051,15 @@ func (c *Checker) isContextSensitive(node *ast.Node) bool { // It is possible to that node.expression is undefined (e.g
) expression := node.Expression() return expression != nil && c.isContextSensitive(expression) + case ast.KindYieldExpression: + expression := node.Expression() + return expression != nil && c.isContextSensitive(expression) } return false } func (c *Checker) isContextSensitiveFunctionLikeDeclaration(node *ast.Node) bool { - return ast.HasContextSensitiveParameters(node) || c.hasContextSensitiveReturnExpression(node) + return ast.HasContextSensitiveParameters(node) || c.hasContextSensitiveReturnExpression(node) || c.hasContextSensitiveYieldExpression(node) } func (c *Checker) hasContextSensitiveReturnExpression(node *ast.Node) bool { @@ -30069,6 +30078,10 @@ func (c *Checker) hasContextSensitiveReturnExpression(node *ast.Node) bool { }) } +func (c *Checker) hasContextSensitiveYieldExpression(node *ast.Node) bool { + return getFunctionFlags(node)&FunctionFlagsGenerator != 0 && node.Body() != nil && forEachYieldExpression(node.Body(), c.isContextSensitive) +} + func (c *Checker) pushInferenceContext(node *ast.Node, context *InferenceContext) { c.inferenceContextInfos = append(c.inferenceContextInfos, InferenceContextInfo{node, context}) } diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index 41c4901e661..873b1f76d23 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -1195,16 +1195,19 @@ func getSuperContainer(node *ast.Node, stopOnFunctions bool) *ast.Node { } } -func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) { +func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node) bool) bool { var traverse func(*ast.Node) bool traverse = func(node *ast.Node) bool { switch node.Kind { case ast.KindYieldExpression: - visitor(node) + if visitor(node) { + return true + } operand := node.Expression() - if operand != nil { - traverse(operand) + if operand == nil { + return false } + return traverse(operand) case ast.KindEnumDeclaration, ast.KindInterfaceDeclaration, ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration: // These are not allowed inside a generator now, but eventually they may be allowed // as local types. Regardless, skip them to avoid the work. @@ -1213,17 +1216,17 @@ func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) { if node.Name() != nil && ast.IsComputedPropertyName(node.Name()) { // Note that we will not include methods/accessors of a class because they would require // first descending into the class. This is by design. - traverse(node.Name().Expression()) + return traverse(node.Name().Expression()) } } else if !ast.IsPartOfTypeNode(node) { // This is the general case, which should include mostly expressions and statements. // Also includes NodeArrays. - node.ForEachChild(traverse) + return node.ForEachChild(traverse) } } return false } - traverse(body) + return traverse(body) } func getEnclosingContainer(node *ast.Node) *ast.Node { From fe2dfcd8fe092ed1836bf9ff14c91ff3bcc080fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 00:38:38 +0000 Subject: [PATCH 3/4] Accept baseline changes for TypeScript PR #62243 port Tests pass with net reduction of ~800 lines in diff files: - Deleted: circularlySimplifyingConditionalTypesNoCrash, redefineArray, returnTypeInferenceContextualTypeIgnoreAnyUnknown1, thisTypeInFunctions, thislessFunctionsNotContextSensitive1-3 (partial), vueLikeDataAndPropsInference1-2 diffs - Reduced: thislessFunctionsNotContextSensitive1, thislessFunctionsNotContextSensitive3, vueLikeDataAndPropsInference, genericCallAtYieldExpressionInGenericCall3 - Slightly increased: classFieldSuperNotAccessibleJs (pre-existing JS property binding issue) Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- ...lySimplifyingConditionalTypesNoCrash.types | 2 +- ...plifyingConditionalTypesNoCrash.types.diff | 11 - .../classFieldSuperNotAccessibleJs.errors.txt | 8 +- ...sFieldSuperNotAccessibleJs.errors.txt.diff | 27 +- .../classFieldSuperNotAccessibleJs.symbols | 4 - ...lassFieldSuperNotAccessibleJs.symbols.diff | 20 +- .../classFieldSuperNotAccessibleJs.types | 10 +- .../classFieldSuperNotAccessibleJs.types.diff | 27 +- ...AtYieldExpressionInGenericCall3.errors.txt | 55 ++++ ...ldExpressionInGenericCall3.errors.txt.diff | 59 +++++ ...cCallAtYieldExpressionInGenericCall3.types | 2 +- ...AtYieldExpressionInGenericCall3.types.diff | 8 +- .../compiler/redefineArray.errors.txt | 4 +- .../compiler/redefineArray.errors.txt.diff | 12 - .../submodule/compiler/redefineArray.types | 4 +- .../compiler/redefineArray.types.diff | 14 - ...ContextualTypeIgnoreAnyUnknown1.errors.txt | 36 --- ...xtualTypeIgnoreAnyUnknown1.errors.txt.diff | 40 --- ...renceContextualTypeIgnoreAnyUnknown1.types | 24 +- ...ContextualTypeIgnoreAnyUnknown1.types.diff | 45 ---- ...ssFunctionsNotContextSensitive1.errors.txt | 32 +-- ...ctionsNotContextSensitive1.errors.txt.diff | 100 ------- ...slessFunctionsNotContextSensitive1.symbols | 4 + ...FunctionsNotContextSensitive1.symbols.diff | 22 -- ...hislessFunctionsNotContextSensitive1.types | 114 ++++---- ...ssFunctionsNotContextSensitive1.types.diff | 247 +----------------- ...hislessFunctionsNotContextSensitive2.types | 72 ++--- ...ssFunctionsNotContextSensitive2.types.diff | 176 ------------- ...ssFunctionsNotContextSensitive3.errors.txt | 9 +- ...ctionsNotContextSensitive3.errors.txt.diff | 33 --- ...slessFunctionsNotContextSensitive3.symbols | 2 + ...FunctionsNotContextSensitive3.symbols.diff | 14 - ...hislessFunctionsNotContextSensitive3.types | 40 +-- ...ssFunctionsNotContextSensitive3.types.diff | 97 +------ .../vueLikeDataAndPropsInference.types | 4 +- .../vueLikeDataAndPropsInference.types.diff | 15 +- .../vueLikeDataAndPropsInference2.types | 4 +- .../vueLikeDataAndPropsInference2.types.diff | 15 +- .../conformance/thisTypeInFunctions.types | 10 +- .../thisTypeInFunctions.types.diff | 43 --- 40 files changed, 365 insertions(+), 1100 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types.diff create mode 100644 testdata/baselines/reference/submodule/compiler/genericCallAtYieldExpressionInGenericCall3.errors.txt create mode 100644 testdata/baselines/reference/submodule/compiler/genericCallAtYieldExpressionInGenericCall3.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/redefineArray.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/redefineArray.types.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/returnTypeInferenceContextualTypeIgnoreAnyUnknown1.errors.txt delete mode 100644 testdata/baselines/reference/submodule/compiler/returnTypeInferenceContextualTypeIgnoreAnyUnknown1.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/returnTypeInferenceContextualTypeIgnoreAnyUnknown1.types.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/thislessFunctionsNotContextSensitive1.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/thislessFunctionsNotContextSensitive1.symbols.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/thislessFunctionsNotContextSensitive2.types.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/thislessFunctionsNotContextSensitive3.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/compiler/thislessFunctionsNotContextSensitive3.symbols.diff delete mode 100644 testdata/baselines/reference/submodule/conformance/thisTypeInFunctions.types.diff diff --git a/testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types b/testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types index 69f8bc39df0..8179ec3240b 100644 --- a/testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types +++ b/testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types @@ -56,7 +56,7 @@ declare var connect: Connect; const myStoreConnect: Connect = function( >myStoreConnect : Connect ->function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} :