Skip to content

Commit 23b5ddf

Browse files
Copilotjakebailey
andauthored
Port TypeScript PR #62243: Improve inference by not considering thisless functions context-sensitive (#2748)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
1 parent 28bb535 commit 23b5ddf

File tree

40 files changed

+253
-1296
lines changed

40 files changed

+253
-1296
lines changed

internal/ast/utilities.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3969,7 +3969,7 @@ func HasContextSensitiveParameters(node *Node) bool {
39693969
// an implicit 'this' parameter which is subject to contextual typing.
39703970
parameter := core.FirstOrNil(node.Parameters())
39713971
if parameter == nil || !IsThisParameter(parameter) {
3972-
return true
3972+
return node.Flags&NodeFlagsContainsThis != 0
39733973
}
39743974
}
39753975
}

internal/binder/binder.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const (
3939
ContainerFlagsIsInterface ContainerFlags = 1 << 6
4040
ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor ContainerFlags = 1 << 7
4141
ContainerFlagsIsThisContainer ContainerFlags = 1 << 8
42+
ContainerFlagsPropagatesThisKeyword ContainerFlags = 1 << 9
4243
)
4344

4445
type ExpandoAssignmentInfo struct {
@@ -615,6 +616,9 @@ func (b *Binder) bind(node *ast.Node) bool {
615616
node.AsIdentifier().FlowNode = b.currentFlow
616617
b.checkContextualIdentifier(node)
617618
case ast.KindThisKeyword, ast.KindSuperKeyword:
619+
if node.Kind == ast.KindThisKeyword {
620+
b.seenThisKeyword = true
621+
}
618622
node.AsKeywordExpression().FlowNode = b.currentFlow
619623
case ast.KindQualifiedName:
620624
if b.currentFlow != nil && ast.IsPartOfTypeQuery(node) {
@@ -1520,6 +1524,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
15201524
saveExceptionTarget := b.currentExceptionTarget
15211525
saveActiveLabelList := b.activeLabelList
15221526
saveHasExplicitReturn := b.hasExplicitReturn
1527+
saveSeenThisKeyword := b.seenThisKeyword
15231528
isImmediatelyInvoked := (containerFlags&ContainerFlagsIsFunctionExpression != 0 &&
15241529
!ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync) &&
15251530
!isGeneratorFunctionExpression(node) &&
@@ -1545,9 +1550,10 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
15451550
b.currentContinueTarget = nil
15461551
b.activeLabelList = nil
15471552
b.hasExplicitReturn = false
1553+
b.seenThisKeyword = false
15481554
b.bindChildren(node)
1549-
// Reset all reachability check related flags on node (for incremental scenarios)
1550-
node.Flags &= ^ast.NodeFlagsReachabilityCheckFlags
1555+
// Reset flags (for incremental scenarios)
1556+
node.Flags &= ^(ast.NodeFlagsReachabilityCheckFlags | ast.NodeFlagsContainsThis)
15511557
if b.currentFlow.Flags&ast.FlowFlagsUnreachable == 0 && containerFlags&ContainerFlagsIsFunctionLike != 0 {
15521558
bodyData := node.BodyData()
15531559
if bodyData != nil && ast.NodeIsPresent(bodyData.Body) {
@@ -1558,11 +1564,13 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
15581564
bodyData.EndFlowNode = b.currentFlow
15591565
}
15601566
}
1567+
if b.seenThisKeyword {
1568+
node.Flags |= ast.NodeFlagsContainsThis
1569+
}
15611570
if node.Kind == ast.KindSourceFile {
15621571
node.Flags |= b.emitFlags
15631572
node.AsSourceFile().EndFlowNode = b.currentFlow
15641573
}
1565-
15661574
if b.currentReturnTarget != nil {
15671575
b.addAntecedent(b.currentReturnTarget, b.currentFlow)
15681576
b.currentFlow = b.finishFlowLabel(b.currentReturnTarget)
@@ -1579,7 +1587,13 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
15791587
b.currentExceptionTarget = saveExceptionTarget
15801588
b.activeLabelList = saveActiveLabelList
15811589
b.hasExplicitReturn = saveHasExplicitReturn
1590+
if containerFlags&ContainerFlagsPropagatesThisKeyword != 0 {
1591+
b.seenThisKeyword = saveSeenThisKeyword || b.seenThisKeyword
1592+
} else {
1593+
b.seenThisKeyword = saveSeenThisKeyword
1594+
}
15821595
} else if containerFlags&ContainerFlagsIsInterface != 0 {
1596+
saveSeenThisKeyword := b.seenThisKeyword
15831597
b.seenThisKeyword = false
15841598
b.bindChildren(node)
15851599
// ContainsThis cannot overlap with HasExtendedUnicodeEscape on Identifier
@@ -1588,6 +1602,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
15881602
} else {
15891603
node.Flags &= ^ast.NodeFlagsContainsThis
15901604
}
1605+
b.seenThisKeyword = saveSeenThisKeyword
15911606
} else {
15921607
b.bindChildren(node)
15931608
}
@@ -2525,16 +2540,14 @@ func GetContainerFlags(node *ast.Node) ContainerFlags {
25252540
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor | ContainerFlagsIsThisContainer
25262541
}
25272542
fallthrough
2528-
case ast.KindConstructor, ast.KindClassStaticBlockDeclaration:
2543+
case ast.KindConstructor, ast.KindFunctionDeclaration, ast.KindClassStaticBlockDeclaration:
25292544
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer
25302545
case ast.KindMethodSignature, ast.KindCallSignature, ast.KindFunctionType, ast.KindConstructSignature, ast.KindConstructorType:
2531-
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike
2532-
case ast.KindFunctionDeclaration:
2533-
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer
2546+
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsPropagatesThisKeyword
25342547
case ast.KindFunctionExpression:
25352548
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression | ContainerFlagsIsThisContainer
25362549
case ast.KindArrowFunction:
2537-
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression
2550+
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression | ContainerFlagsPropagatesThisKeyword
25382551
case ast.KindModuleBlock:
25392552
return ContainerFlagsIsControlFlowContainer
25402553
case ast.KindPropertyDeclaration:

internal/checker/checker.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19850,10 +19850,10 @@ func mayReturnNever(fn *ast.Node) bool {
1985019850

1985119851
func (c *Checker) checkAndAggregateYieldOperandTypes(fn *ast.Node, checkMode CheckMode) (yieldTypes []*Type, nextTypes []*Type) {
1985219852
isAsync := (getFunctionFlags(fn) & FunctionFlagsAsync) != 0
19853-
forEachYieldExpression(fn.Body(), func(yieldExpr *ast.Node) {
19853+
forEachYieldExpression(fn.Body(), func(yieldExpr *ast.Node) bool {
1985419854
yieldExprType := c.undefinedWideningType
1985519855
if yieldExpr.Expression() != nil {
19856-
yieldExprType = c.checkExpressionEx(yieldExpr.Expression(), checkMode)
19856+
yieldExprType = c.checkExpressionEx(yieldExpr.Expression(), checkMode & ^CheckModeSkipGenericFunctions)
1985719857
}
1985819858
if yieldExpr.Expression() != nil && c.isConstContext(yieldExpr.Expression()) {
1985919859
yieldExprType = c.getRegularTypeOfLiteralType(yieldExprType)
@@ -19869,6 +19869,7 @@ func (c *Checker) checkAndAggregateYieldOperandTypes(fn *ast.Node, checkMode Che
1986919869
if nextType != nil {
1987019870
nextTypes = core.AppendIfUnique(nextTypes, nextType)
1987119871
}
19872+
return false
1987219873
})
1987319874
return yieldTypes, nextTypes
1987419875
}
@@ -29926,20 +29927,25 @@ func (c *Checker) instantiateContextualType(contextualType *Type, node *ast.Node
2992629927
if contextFlags&ContextFlagsSignature != 0 && core.Some(inferenceContext.inferences, hasInferenceCandidatesOrDefault) {
2992729928
// For contextual signatures we incorporate all inferences made so far, e.g. from return
2992829929
// types as well as arguments to the left in a function call.
29929-
return c.instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper)
29930+
t := c.instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper)
29931+
if t.flags&TypeFlagsAnyOrUnknown == 0 {
29932+
return t
29933+
}
2993029934
}
2993129935
if inferenceContext.returnMapper != nil {
2993229936
// For other purposes (e.g. determining whether to produce literal types) we only
2993329937
// incorporate inferences made from the return type in a function call. We remove
2993429938
// the 'boolean' type from the contextual type such that contextually typed boolean
2993529939
// literals actually end up widening to 'boolean' (see #48363).
2993629940
t := c.instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper)
29937-
if t.flags&TypeFlagsUnion != 0 && containsType(t.Types(), c.regularFalseType) && containsType(t.Types(), c.regularTrueType) {
29938-
return c.filterType(t, func(t *Type) bool {
29939-
return t != c.regularFalseType && t != c.regularTrueType
29940-
})
29941+
if t.flags&TypeFlagsAnyOrUnknown == 0 {
29942+
if t.flags&TypeFlagsUnion != 0 && containsType(t.Types(), c.regularFalseType) && containsType(t.Types(), c.regularTrueType) {
29943+
return c.filterType(t, func(t *Type) bool {
29944+
return t != c.regularFalseType && t != c.regularTrueType
29945+
})
29946+
}
29947+
return t
2994129948
}
29942-
return t
2994329949
}
2994429950
}
2994529951
}
@@ -30018,12 +30024,15 @@ func (c *Checker) isContextSensitive(node *ast.Node) bool {
3001830024
// It is possible to that node.expression is undefined (e.g <div x={} />)
3001930025
expression := node.Expression()
3002030026
return expression != nil && c.isContextSensitive(expression)
30027+
case ast.KindYieldExpression:
30028+
expression := node.Expression()
30029+
return expression != nil && c.isContextSensitive(expression)
3002130030
}
3002230031
return false
3002330032
}
3002430033

3002530034
func (c *Checker) isContextSensitiveFunctionLikeDeclaration(node *ast.Node) bool {
30026-
return ast.HasContextSensitiveParameters(node) || c.hasContextSensitiveReturnExpression(node)
30035+
return ast.HasContextSensitiveParameters(node) || c.hasContextSensitiveReturnExpression(node) || c.hasContextSensitiveYieldExpression(node)
3002730036
}
3002830037

3002930038
func (c *Checker) hasContextSensitiveReturnExpression(node *ast.Node) bool {
@@ -30042,6 +30051,10 @@ func (c *Checker) hasContextSensitiveReturnExpression(node *ast.Node) bool {
3004230051
})
3004330052
}
3004430053

30054+
func (c *Checker) hasContextSensitiveYieldExpression(node *ast.Node) bool {
30055+
return getFunctionFlags(node)&FunctionFlagsGenerator != 0 && node.Body() != nil && forEachYieldExpression(node.Body(), c.isContextSensitive)
30056+
}
30057+
3004530058
func (c *Checker) pushInferenceContext(node *ast.Node, context *InferenceContext) {
3004630059
c.inferenceContextInfos = append(c.inferenceContextInfos, InferenceContextInfo{node, context})
3004730060
}

internal/checker/utilities.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,16 +1195,19 @@ func getSuperContainer(node *ast.Node, stopOnFunctions bool) *ast.Node {
11951195
}
11961196
}
11971197

1198-
func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) {
1198+
func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node) bool) bool {
11991199
var traverse func(*ast.Node) bool
12001200
traverse = func(node *ast.Node) bool {
12011201
switch node.Kind {
12021202
case ast.KindYieldExpression:
1203-
visitor(node)
1203+
if visitor(node) {
1204+
return true
1205+
}
12041206
operand := node.Expression()
1205-
if operand != nil {
1206-
traverse(operand)
1207+
if operand == nil {
1208+
return false
12071209
}
1210+
return traverse(operand)
12081211
case ast.KindEnumDeclaration, ast.KindInterfaceDeclaration, ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration:
12091212
// These are not allowed inside a generator now, but eventually they may be allowed
12101213
// as local types. Regardless, skip them to avoid the work.
@@ -1213,17 +1216,17 @@ func forEachYieldExpression(body *ast.Node, visitor func(expr *ast.Node)) {
12131216
if node.Name() != nil && ast.IsComputedPropertyName(node.Name()) {
12141217
// Note that we will not include methods/accessors of a class because they would require
12151218
// first descending into the class. This is by design.
1216-
traverse(node.Name().Expression())
1219+
return traverse(node.Name().Expression())
12171220
}
12181221
} else if !ast.IsPartOfTypeNode(node) {
12191222
// This is the general case, which should include mostly expressions and statements.
12201223
// Also includes NodeArrays.
1221-
node.ForEachChild(traverse)
1224+
return node.ForEachChild(traverse)
12221225
}
12231226
}
12241227
return false
12251228
}
1226-
traverse(body)
1229+
return traverse(body)
12271230
}
12281231

12291232
func getEnclosingContainer(node *ast.Node) *ast.Node {

testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ declare var connect: Connect;
5656

5757
const myStoreConnect: Connect = function(
5858
>myStoreConnect : Connect
59-
>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : <TStateProps, TOwnProps>(mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps<TStateProps, Omit<P, Extract<keyof TStateProps, keyof P>> & TOwnProps>
59+
>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps<TStateProps, Omit<P, Extract<keyof TStateProps, keyof P>> & TOwnProps>
6060

6161
mapStateToProps?: any,
6262
>mapStateToProps : any

testdata/baselines/reference/submodule/compiler/circularlySimplifyingConditionalTypesNoCrash.types.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/genericCallAtYieldExpressionInGenericCall1.errors.txt

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
genericCallAtYieldExpressionInGenericCall1.ts(13,25): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
21
genericCallAtYieldExpressionInGenericCall1.ts(26,25): error TS2488: Type '() => T' must have a '[Symbol.iterator]()' method that returns an iterator.
3-
genericCallAtYieldExpressionInGenericCall1.ts(26,25): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
4-
genericCallAtYieldExpressionInGenericCall1.ts(42,10): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
5-
genericCallAtYieldExpressionInGenericCall1.ts(56,8): error TS2345: Argument of type '<T>(value: T) => Generator<any, void, unknown>' is not assignable to parameter of type '(value: unknown) => Generator<never, unknown, unknown>'.
6-
Type 'Generator<any, void, unknown>' is not assignable to type 'Generator<never, unknown, unknown>'.
2+
genericCallAtYieldExpressionInGenericCall1.ts(56,8): error TS2345: Argument of type '<T>(value: T) => Generator<number, void, any>' is not assignable to parameter of type '(value: unknown) => Generator<never, unknown, unknown>'.
3+
Type 'Generator<number, void, any>' is not assignable to type 'Generator<never, unknown, unknown>'.
74
The types returned by 'next(...)' are incompatible between these types.
8-
Type 'IteratorResult<any, void>' is not assignable to type 'IteratorResult<never, unknown>'.
9-
Type 'IteratorYieldResult<any>' is not assignable to type 'IteratorResult<never, unknown>'.
10-
Type 'IteratorYieldResult<any>' is not assignable to type 'IteratorYieldResult<never>'.
11-
Type 'any' is not assignable to type 'never'.
12-
genericCallAtYieldExpressionInGenericCall1.ts(57,10): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
5+
Type 'IteratorResult<number, void>' is not assignable to type 'IteratorResult<never, unknown>'.
6+
Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorResult<never, unknown>'.
7+
Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorYieldResult<never>'.
8+
Type 'number' is not assignable to type 'never'.
139
genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of type '<T>(value: T) => Generator<number, void, any>' is not assignable to parameter of type '(value: unknown) => Generator<never, unknown, unknown>'.
1410
Type 'Generator<number, void, any>' is not assignable to type 'Generator<never, unknown, unknown>'.
1511
The types returned by 'next(...)' are incompatible between these types.
@@ -19,7 +15,7 @@ genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of t
1915
Type 'number' is not assignable to type 'never'.
2016

2117

22-
==== genericCallAtYieldExpressionInGenericCall1.ts (7 errors) ====
18+
==== genericCallAtYieldExpressionInGenericCall1.ts (3 errors) ====
2319
declare const inner: {
2420
<A>(value: A): {
2521
(): A;
@@ -33,8 +29,6 @@ genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of t
3329

3430
outer(function* <T>(value: T) {
3531
const result = yield* inner(value); // ok
36-
~~~~~~~~~~~~
37-
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
3832
});
3933

4034
outer(function* <T>(value: T) {
@@ -50,8 +44,6 @@ genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of t
5044
const result = yield* inner2(value); // error
5145
~~~~~~~~~~~~~
5246
!!! error TS2488: Type '() => T' must have a '[Symbol.iterator]()' method that returns an iterator.
53-
~~~~~~~~~~~~~
54-
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
5547
});
5648

5749
declare const inner3: {
@@ -68,8 +60,6 @@ genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of t
6860
// number
6961
const result1 = outer2(function* <T>(value: T) {
7062
yield* inner3(value);
71-
~~~~~~~~~~~~~
72-
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
7363
});
7464

7565
// number
@@ -85,16 +75,14 @@ genericCallAtYieldExpressionInGenericCall1.ts(61,8): error TS2345: Argument of t
8575
// error
8676
outer3(function* <T>(value: T) {
8777
~~~~~~~~
88-
!!! error TS2345: Argument of type '<T>(value: T) => Generator<any, void, unknown>' is not assignable to parameter of type '(value: unknown) => Generator<never, unknown, unknown>'.
89-
!!! error TS2345: Type 'Generator<any, void, unknown>' is not assignable to type 'Generator<never, unknown, unknown>'.
78+
!!! error TS2345: Argument of type '<T>(value: T) => Generator<number, void, any>' is not assignable to parameter of type '(value: unknown) => Generator<never, unknown, unknown>'.
79+
!!! error TS2345: Type 'Generator<number, void, any>' is not assignable to type 'Generator<never, unknown, unknown>'.
9080
!!! error TS2345: The types returned by 'next(...)' are incompatible between these types.
91-
!!! error TS2345: Type 'IteratorResult<any, void>' is not assignable to type 'IteratorResult<never, unknown>'.
92-
!!! error TS2345: Type 'IteratorYieldResult<any>' is not assignable to type 'IteratorResult<never, unknown>'.
93-
!!! error TS2345: Type 'IteratorYieldResult<any>' is not assignable to type 'IteratorYieldResult<never>'.
94-
!!! error TS2345: Type 'any' is not assignable to type 'never'.
81+
!!! error TS2345: Type 'IteratorResult<number, void>' is not assignable to type 'IteratorResult<never, unknown>'.
82+
!!! error TS2345: Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorResult<never, unknown>'.
83+
!!! error TS2345: Type 'IteratorYieldResult<number>' is not assignable to type 'IteratorYieldResult<never>'.
84+
!!! error TS2345: Type 'number' is not assignable to type 'never'.
9585
yield* inner3(value);
96-
~~~~~~~~~~~~~
97-
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
9886
});
9987

10088
// error

0 commit comments

Comments
 (0)