Skip to content

Conversation

@Andarist
Copy link
Contributor

@Andarist Andarist commented Aug 9, 2025

implements @RyanCavanaugh's suggestion from #47599 :

As a stopgap, consider an object literal method to not be context-sensitive if it doesn't reference this. I believe we already have code for this and it would fix another large class of surprises.

fixes #62204
fixes #60986
fixes #58630
fixes #57572
fixes #56067
fixes #55489
fixes #55124
fixes #53924
fixes #50258

Copilot AI review requested due to automatic review settings August 9, 2025 19:05
@github-project-automation github-project-automation bot moved this to Not started in PR Backlog Aug 9, 2025
@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Aug 9, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves TypeScript's type inference by making functions that don't reference this not context-sensitive. Previously, all object literal methods were considered context-sensitive, causing poor inference when type parameters depended on inferring from these methods first. The change helps TypeScript better infer types in common patterns involving object literals with functions.

Key Changes:

  • Modified hasContextSensitiveParameters to check for actual this usage rather than assuming all function-like declarations are context-sensitive
  • Updated binder to track this keyword usage with NodeFlags.ContainsThis flag
  • Extended context-sensitive checking to include yield expressions in generators

Reviewed Changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/compiler/binder.ts Adds tracking of this keyword usage and sets ContainsThis flag on functions
src/compiler/checker.ts Updates context-sensitive checking to include yield expressions and generators
src/compiler/utilities.ts Modifies hasContextSensitiveParameters and forEachYieldExpression to support new logic
tests/cases/compiler/*.ts New test cases demonstrating improved inference for thisless functions
tests/baselines/reference/. Updated baselines showing improved type inference results

(node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow;
}
if (seenThisKeyword) {
node.flags |= NodeFlags.ContainsThis;
Copy link

Copilot AI Aug 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's trailing whitespace at the end of this line. Remove the extra spaces.

Suggested change
node.flags |= NodeFlags.ContainsThis;
node.flags |= NodeFlags.ContainsThis;

Copilot uses AI. Check for mistakes.
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructSignature:
case SyntaxKind.ConstructorType:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type-level AST nodes had ContainerFlags.IsControlFlowContainer here. This was messing up some of the changes I made since it was interfering with the implemented seenThisKeyword tracking. I don't see why those would be considered control flow containers and there are no tests proving it was needed.

Other changes in this function are basically of the same kind - I just removed ContainerFlags.IsControlFlowContainer from the type-level nodes.

Copy link
Member

@gabritto gabritto Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We seem to have added at least one of those on purpose:
#8941
So I'm wondering why it's not needed anymore. @ahejlsberg do you remember why this was needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As to SyntaxKind.PropertyDeclaration - given the test from the referenced PR still works just OK, I'd assume that its needs are covered by arrow functions being treated as flow containers (arrows were used as property declaration initializers in that test).


function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node);
return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node) || !!(getFunctionFlags(node) & FunctionFlags.Generator && node.body && forEachYieldExpression(node.body as Block, isContextSensitive));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously generators were always context-sensitive as they can't even be arrow functions. At times, they are truly context-sensitive in cases like:

declare function test(
  gen: () => Generator<(arg: number) => string, void, void>,
): void;

test(function* () {
  yield (arg) => String(arg);
});

So I had to add this extra forEachYieldExpression to cover for this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in terms of readability, maybe this would be better as its own function, then it can have a descriptive name like hasContextSensitiveYieldExpression and that example can be its documentation.

// in that traversal terminates in the event that 'visitor' supplies a truthy value.
/** @internal */
export function forEachYieldExpression(body: Block, visitor: (expr: YieldExpression) => void): void {
export function forEachYieldExpression<T>(body: Block, visitor: (expr: YieldExpression) => T): T | undefined {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this basically changes this function to work in the same way as forEachReturnStatement defined above

const myStoreConnect: Connect = function(
>myStoreConnect : Connect
> : ^^^^^^^
>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>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this just changes the inferred type to match the type inferred from the equivalent arrow function with type parameters, it's purely a result of making a thisless function context-insensitive

> : ^^^^^^^^^^^^^^^
>strategy("Nothing", function* (state: State) { yield ; return state; // `return`/`TReturn` isn't supported by `strategy`, so this should error.}) : (a: State) => IterableIterator<State, void>
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>strategy("Nothing", function* (state: State) { yield ; return state; // `return`/`TReturn` isn't supported by `strategy`, so this should error.}) : (a: any) => IterableIterator<any, void>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly here, this is a result of inferSignatureInstantiationForOverloadFailure no longer skipping the generator function on the basis it's context-sensitive (inferSignatureInstantiationForOverloadFailure uses CheckMode.SkipContextSensitive)

},
}
impl.explicitVoid1 = function () { return 12; };
>impl.explicitVoid1 = function () { return 12; } : (this: void) => number
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those this parameters were not used by the assigned implementation - they were just auto-assigned to it based on the this parameter in the contextual signature

@jakebailey
Copy link
Member

@typescript-bot test it
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 9, 2025

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
pack this ✅ Started ✅ Results
test top400 ✅ Started 👀 Results
user test this ✅ Started 👀 Results
run dt ✅ Started 👀 Results
perf test this faster ✅ Started 👀 Results

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 9, 2025

Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/165836/artifacts?artifactName=tgz&fileId=13B4C26B69BE38B41CF288EF1AA02FC1EA994BAF88B23E179E9D52E418EE347402&fileName=/typescript-6.0.0-insiders.20250809.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, the results of running the DT tests are ready.

There were interesting changes:

Branch only errors:

Package: jqrangeslider
Error:

Error: 
/mnt/vss/_work/1/DefinitelyTyped/types/jqrangeslider/jqrangeslider-tests.ts
  160:20  error  TypeScript@local compile error: 
Function expression, which lacks return-type annotation, implicitly has an 'any' return type  @definitelytyped/expect

✖ 1 problem (1 error, 0 warnings)

    at combineErrorsAndWarnings (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:199:28)
    at runTests (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:191:20)

You can check the log here.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the user tests with tsc comparing main and refs/pull/62243/merge:

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Git clone failed"

Otherwise...

Something interesting changed - please have a look.

Details

effect

tsconfig.json

tsconfig.build.json

@typescript-bot
Copy link
Collaborator

@jakebailey
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - node (v18.15.0, x64)
Errors 34 34 ~ ~ ~ p=1.000 n=6
Symbols 62,370 62,370 ~ ~ ~ p=1.000 n=6
Types 50,386 50,386 ~ ~ ~ p=1.000 n=6
Memory used 192,921k (± 0.01%) 194,706k (± 0.99%) ~ 192,783k 196,638k p=0.378 n=6
Parse Time 1.30s (± 0.94%) 1.31s (± 0.62%) ~ 1.29s 1.31s p=1.000 n=6
Bind Time 0.73s 0.73s ~ ~ ~ p=1.000 n=6
Check Time 9.74s (± 0.27%) 9.71s (± 0.31%) ~ 9.67s 9.76s p=0.107 n=6
Emit Time 2.73s (± 0.85%) 2.73s (± 0.98%) ~ 2.68s 2.76s p=0.737 n=6
Total Time 14.51s (± 0.26%) 14.48s (± 0.29%) ~ 14.41s 14.53s p=0.259 n=6
angular-1 - node (v18.15.0, x64)
Errors 56 56 ~ ~ ~ p=1.000 n=6
Symbols 948,914 948,687 -227 (- 0.02%) ~ ~ p=0.001 n=6
Types 410,884 410,829 -55 (- 0.01%) ~ ~ p=0.001 n=6
Memory used 1,226,420k (± 0.00%) 1,225,226k (± 0.01%) -1,194k (- 0.10%) 1,225,099k 1,225,315k p=0.005 n=6
Parse Time 6.51s (± 0.76%) 6.54s (± 0.75%) ~ 6.48s 6.61s p=0.295 n=6
Bind Time 1.87s (± 0.28%) 1.88s (± 0.22%) +0.01s (+ 0.44%) 1.88s 1.89s p=0.022 n=6
Check Time 32.02s (± 0.51%) 31.97s (± 0.26%) ~ 31.86s 32.07s p=0.298 n=6
Emit Time 14.67s (± 1.19%) 14.85s (± 0.47%) ~ 14.74s 14.92s p=0.092 n=6
Total Time 55.07s (± 0.48%) 55.24s (± 0.19%) ~ 55.06s 55.34s p=0.298 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,548,622 2,548,597 -25 (- 0.00%) ~ ~ p=0.001 n=6
Types 903,221 903,206 -15 (- 0.00%) ~ ~ p=0.001 n=6
Memory used 2,833,313k (± 0.00%) 2,832,160k (± 0.00%) -1,153k (- 0.04%) 2,832,066k 2,832,299k p=0.005 n=6
Parse Time 8.77s (± 0.32%) 8.77s (± 0.17%) ~ 8.74s 8.78s p=0.935 n=6
Bind Time 2.25s (± 0.61%) 2.26s (± 0.23%) ~ 2.25s 2.26s p=0.928 n=6
Check Time 85.83s (± 0.60%) 85.84s (± 0.52%) ~ 85.29s 86.48s p=0.936 n=6
Emit Time 2.32s (± 3.91%) 2.23s (± 9.27%) ~ 2.04s 2.48s p=0.574 n=6
Total Time 99.16s (± 0.53%) 99.10s (± 0.40%) ~ 98.38s 99.51s p=0.810 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,227,066 1,227,058 -8 (- 0.00%) ~ ~ p=0.001 n=6
Types 267,480 267,484 +4 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,363,039k (± 0.03%) 2,418,908k (± 6.14%) ~ 2,357,778k 2,722,466k p=0.066 n=6
Parse Time 5.19s (± 0.86%) 5.24s (± 0.93%) ~ 5.18s 5.31s p=0.128 n=6
Bind Time 1.78s (± 0.61%) 1.81s (± 0.73%) +0.03s (+ 1.59%) 1.79s 1.83s p=0.009 n=6
Check Time 35.41s (± 0.33%) 35.31s (± 0.64%) ~ 34.99s 35.64s p=0.471 n=6
Emit Time 2.99s (± 2.39%) 3.05s (± 2.72%) ~ 2.98s 3.21s p=0.149 n=6
Total Time 45.39s (± 0.43%) 45.41s (± 0.54%) ~ 45.11s 45.77s p=0.936 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,227,066 1,227,058 -8 (- 0.00%) ~ ~ p=0.001 n=6
Types 267,480 267,484 +4 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,824,370k (±13.26%) 2,940,432k (±11.52%) ~ 2,428,471k 3,157,631k p=0.575 n=6
Parse Time 6.83s (± 1.55%) 6.82s (± 1.38%) ~ 6.69s 6.90s p=0.521 n=6
Bind Time 2.18s (± 2.34%) 2.21s (± 1.13%) ~ 2.18s 2.25s p=0.148 n=6
Check Time 42.73s (± 0.81%) 42.93s (± 0.84%) ~ 42.21s 43.22s p=0.378 n=6
Emit Time 3.56s (± 1.53%) 3.58s (± 2.67%) ~ 3.44s 3.67s p=0.575 n=6
Total Time 55.30s (± 0.80%) 55.55s (± 0.83%) ~ 54.65s 55.98s p=0.471 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 262,555 262,559 +4 (+ 0.00%) ~ ~ p=0.001 n=6
Types 107,165 107,177 +12 (+ 0.01%) ~ ~ p=0.001 n=6
Memory used 441,956k (± 0.01%) 441,608k (± 0.01%) -348k (- 0.08%) 441,571k 441,667k p=0.005 n=6
Parse Time 4.38s (± 0.72%) 4.38s (± 0.64%) ~ 4.34s 4.42s p=0.935 n=6
Bind Time 1.62s (± 0.75%) 1.63s (± 1.19%) ~ 1.61s 1.66s p=0.868 n=6
Check Time 23.48s (± 0.23%) 23.49s (± 0.30%) ~ 23.41s 23.58s p=0.936 n=6
Emit Time 1.91s (± 0.97%) 1.91s (± 0.63%) ~ 1.89s 1.92s p=0.625 n=6
Total Time 31.39s (± 0.16%) 31.40s (± 0.19%) ~ 31.33s 31.48s p=0.810 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 71 71 ~ ~ ~ p=1.000 n=6
Symbols 225,367 225,367 ~ ~ ~ p=1.000 n=6
Types 94,290 94,290 ~ ~ ~ p=1.000 n=6
Memory used 371,100k (± 0.01%) 370,813k (± 0.02%) -287k (- 0.08%) 370,749k 370,919k p=0.005 n=6
Parse Time 2.89s (± 1.00%) 2.90s (± 1.36%) ~ 2.84s 2.94s p=0.573 n=6
Bind Time 1.59s (± 0.47%) 1.64s (± 1.76%) +0.04s (+ 2.72%) 1.60s 1.68s p=0.007 n=6
Check Time 16.45s (± 0.36%) 16.44s (± 0.33%) ~ 16.37s 16.51s p=0.689 n=6
Emit Time 0.00s (±244.70%) 0.00s ~ ~ ~ p=0.405 n=6
Total Time 20.93s (± 0.36%) 20.96s (± 0.34%) ~ 20.86s 21.05s p=0.520 n=6
vscode - node (v18.15.0, x64)
Errors 1 6 🔻+5 (+500.00%) ~ ~ p=0.001 n=6
Symbols 3,843,514 3,839,554 -3,960 (- 0.10%) ~ ~ p=0.001 n=6
Types 1,211,401 1,210,628 -773 (- 0.06%) ~ ~ p=0.001 n=6
Memory used 3,677,122k (± 0.00%) 3,674,086k (± 0.00%) -3,036k (- 0.08%) 3,673,905k 3,674,201k p=0.005 n=6
Parse Time 15.27s (± 0.69%) 15.30s (± 0.56%) ~ 15.20s 15.45s p=0.423 n=6
Bind Time 4.94s (± 0.50%) 5.04s (± 2.69%) ~ 4.95s 5.23s p=0.064 n=6
Check Time 101.40s (± 1.96%) 103.38s (± 3.10%) ~ 100.01s 109.50s p=0.230 n=6
Emit Time 34.63s (±26.92%) 32.00s (± 8.83%) ~ 30.52s 37.76s p=1.000 n=6
Total Time 156.24s (± 6.40%) 155.74s (± 2.41%) ~ 151.55s 160.88s p=0.297 n=6
webpack - node (v18.15.0, x64)
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 320,272 320,263 -9 (- 0.00%) ~ ~ p=0.001 n=6
Types 139,137 139,125 -12 (- 0.01%) ~ ~ p=0.001 n=6
Memory used 476,591k (± 0.03%) 476,019k (± 0.02%) -572k (- 0.12%) 475,920k 476,167k p=0.005 n=6
Parse Time 4.33s (± 0.45%) 4.34s (± 0.27%) ~ 4.33s 4.36s p=0.618 n=6
Bind Time 1.85s (± 0.95%) 1.84s (± 1.22%) ~ 1.82s 1.87s p=0.413 n=6
Check Time 21.10s (± 0.61%) 21.14s (± 0.28%) ~ 21.07s 21.21s p=0.521 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 27.27s (± 0.49%) 27.31s (± 0.28%) ~ 27.23s 27.42s p=0.520 n=6
xstate-main - node (v18.15.0, x64)
Errors 30 30 ~ ~ ~ p=1.000 n=6
Symbols 663,630 663,455 -175 (- 0.03%) ~ ~ p=0.001 n=6
Types 198,311 198,165 -146 (- 0.07%) ~ ~ p=0.001 n=6
Memory used 570,537k (± 0.02%) 569,637k (± 0.03%) -900k (- 0.16%) 569,437k 569,810k p=0.005 n=6
Parse Time 4.28s (± 0.79%) 4.28s (± 0.65%) ~ 4.24s 4.32s p=1.000 n=6
Bind Time 1.33s (± 0.77%) 1.32s (± 0.88%) ~ 1.31s 1.34s p=0.117 n=6
Check Time 20.07s (± 1.90%) 20.21s (± 1.70%) ~ 19.87s 20.60s p=0.298 n=6
Emit Time 0.00s 0.00s (±244.70%) ~ 0.00s 0.01s p=0.405 n=6
Total Time 25.68s (± 1.56%) 25.81s (± 1.43%) ~ 25.46s 26.25s p=0.470 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the top 400 repos with tsc comparing main and refs/pull/62243/merge:

Something interesting changed - please have a look.

Details

reduxjs/reselect

test/tsconfig.json

steven-tey/novel

1 of 2 projects failed to build with the old tsc and were ignored

packages/headless/tsconfig.json

ueberdosis/tiptap

3 of 8 projects failed to build with the old tsc and were ignored

tests/cypress/tsconfig.json

@Andarist
Copy link
Contributor Author

Andarist commented Aug 10, 2025

  1. jqrangeslider break - I'm not concerned about it. It already behaves quite weirdly today: TS playground
  2. novel break - this is an improvement. The current code only works because it infers any for the extension's options: TS playground. It's not great that using this in addOptions makes it to infer any again - but that's not a new problem.
  3. tiptap break - this is basically the same as above (the above uses tiptap). This code only works now because it infers any for the options: TS playground
  4. reselect break - this is just a moved error position (the new position matches the position reported when an arrow function is used instead of a function expression): TS playground. It's worth noting those were changed in tests that inentionally use invalid arguments to test that a runtime error is thrown when the function receives them
  5. effect break - this one is actually bad for their users: TS playground. Without this change they are able to benefit from the return type inference. With this change, they could benefit from it but some earlier inferences made from returnOnlyType prevent that. This type was never created before for generators as they were always considered to have a context-sensitive parameter. THIS IS FIXED

@jakebailey
Copy link
Member

@typescript-bot test it
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 11, 2025

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
pack this ✅ Started ✅ Results
test top400 ✅ Started 👀 Results
user test this ✅ Started 👀 Results
run dt ✅ Started 👀 Results
perf test this faster ✅ Started 👀 Results

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 11, 2025

Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/165850/artifacts?artifactName=tgz&fileId=8C27070A12055925406C680737D02B67824D8D3CFB34BD5BC89B4B93A679A97B02&fileName=/typescript-6.0.0-insiders.20250811.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, the results of running the DT tests are ready.

There were interesting changes:

Branch only errors:

Package: jqrangeslider
Error:

Error: 
/mnt/vss/_work/1/DefinitelyTyped/types/jqrangeslider/jqrangeslider-tests.ts
  160:20  error  TypeScript@local compile error: 
Function expression, which lacks return-type annotation, implicitly has an 'any' return type  @definitelytyped/expect

✖ 1 problem (1 error, 0 warnings)

    at combineErrorsAndWarnings (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:199:28)
    at runTests (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:191:20)

You can check the log here.

@Andarist Andarist force-pushed the no-context-sensitivity-for-this-less-functions branch from 76c7aa0 to 73d04f5 Compare December 5, 2025 17:41
@jakebailey
Copy link
Member

@typescript-bot test it
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 8, 2025

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
pack this ✅ Started
test top400 ✅ Started
user test this ✅ Started
run dt ✅ Started ❌ Results
perf test this faster ✅ Started ❌ Results

@typescript-bot
Copy link
Collaborator

@jakebailey, the perf run you requested failed. You can check the log here.

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, it looks like the DT test run failed. Please check the log for more details.

You can check the log here.

@jakebailey
Copy link
Member

@typescript-bot test it
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 8, 2025

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
pack this ✅ Started ✅ Results
test top400 ✅ Started 👀 Results
user test this ✅ Started ✅ Results
run dt ✅ Started 👀 Results
perf test this faster ✅ Started 👀 Results

@typescript-bot
Copy link
Collaborator

typescript-bot commented Dec 8, 2025

Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/166739/artifacts?artifactName=tgz&fileId=86587C675AD6127B0E0146726795B3D2E400DC1F37BBF515B290B45E73BEC4FF02&fileName=/typescript-6.0.0-insiders.20251208.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;

@typescript-bot
Copy link
Collaborator

Hey @jakebailey, the results of running the DT tests are ready.

There were interesting changes:

Branch only errors:

Package: jqrangeslider
Error:

Error: 
/mnt/vss/_work/1/DefinitelyTyped/types/jqrangeslider/jqrangeslider-tests.ts
  160:20  error  TypeScript@local compile error: 
Function expression, which lacks return-type annotation, implicitly has an 'any' return type  @definitelytyped/expect

✖ 1 problem (1 error, 0 warnings)

    at combineErrorsAndWarnings (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:199:28)
    at runTests (/mnt/vss/_work/1/DefinitelyTyped/node_modules/.pnpm/@[email protected][email protected]/node_modules/@definitelytyped/dtslint/dist/index.js:191:20)

You can check the log here.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the user tests with tsc comparing main and refs/pull/62243/merge:

There were infrastructure failures potentially unrelated to your change:

  • 1 instance of "Git clone failed"

Otherwise...

Everything looks good!

@typescript-bot
Copy link
Collaborator

@jakebailey
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - node (v18.15.0, x64)
Errors 1 1 ~ ~ ~ p=1.000 n=6
Symbols 62,370 62,370 ~ ~ ~ p=1.000 n=6
Types 50,387 50,387 ~ ~ ~ p=1.000 n=6
Memory used 195,575k (± 0.83%) 196,297k (± 0.06%) ~ 196,081k 196,399k p=0.173 n=6
Parse Time 1.59s (± 1.08%) 1.60s (± 1.04%) ~ 1.59s 1.63s p=0.459 n=6
Bind Time 0.91s (± 0.90%) 0.93s (± 1.62%) +0.02s (+ 2.21%) 0.90s 0.94s p=0.040 n=6
Check Time 11.95s (± 0.42%) 11.93s (± 0.64%) ~ 11.87s 12.05s p=0.629 n=6
Emit Time 3.38s (± 5.10%) 3.35s (± 4.11%) ~ 3.27s 3.63s p=0.809 n=6
Total Time 17.83s (± 1.15%) 17.81s (± 0.78%) ~ 17.64s 18.03s p=1.000 n=6
angular-1 - node (v18.15.0, x64)
Errors 2 2 ~ ~ ~ p=1.000 n=6
Symbols 956,050 955,823 -227 (- 0.02%) ~ ~ p=0.001 n=6
Types 415,908 415,853 -55 (- 0.01%) ~ ~ p=0.001 n=6
Memory used 1,255,043k (± 0.01%) 1,253,924k (± 0.00%) -1,119k (- 0.09%) 1,253,850k 1,253,997k p=0.005 n=6
Parse Time 6.53s (± 0.59%) 6.54s (± 0.57%) ~ 6.49s 6.57s p=1.000 n=6
Bind Time 1.96s (± 0.21%) 1.96s (± 0.21%) ~ 1.96s 1.97s p=1.000 n=6
Check Time 32.40s (± 0.34%) 32.32s (± 0.28%) ~ 32.21s 32.45s p=0.173 n=6
Emit Time 14.95s (± 0.78%) 15.01s (± 0.20%) ~ 14.97s 15.04s p=0.065 n=6
Total Time 55.84s (± 0.36%) 55.83s (± 0.17%) ~ 55.76s 56.02s p=0.572 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,722,230 2,722,197 -33 (- 0.00%) ~ ~ p=0.001 n=6
Types 937,537 937,522 -15 (- 0.00%) ~ ~ p=0.001 n=6
Memory used 3,051,497k (± 0.01%) 3,050,285k (± 0.00%) -1,212k (- 0.04%) 3,049,994k 3,050,376k p=0.005 n=6
Parse Time 10.46s (± 0.41%) 10.42s (± 0.46%) ~ 10.35s 10.48s p=0.090 n=6
Bind Time 2.80s (± 0.49%) 2.79s (± 0.77%) ~ 2.75s 2.81s p=0.160 n=6
Check Time 112.03s (± 0.98%) 111.46s (± 0.71%) ~ 110.29s 112.43s p=0.471 n=6
Emit Time 0.38s (± 2.60%) 0.37s (± 3.14%) ~ 0.36s 0.39s p=0.314 n=6
Total Time 125.68s (± 0.84%) 125.04s (± 0.63%) ~ 123.82s 125.96s p=0.471 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,252,070 1,252,063 -7 (- 0.00%) ~ ~ p=0.001 n=6
Types 259,846 259,850 +4 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,639,539k (±14.22%) 3,119,127k (± 0.02%) ~ 3,117,898k 3,119,791k p=0.378 n=6
Parse Time 6.57s (± 1.58%) 6.66s (± 1.02%) ~ 6.61s 6.79s p=0.230 n=6
Bind Time 2.24s (± 2.28%) 2.25s (± 0.93%) ~ 2.23s 2.28s p=1.000 n=6
Check Time 42.93s (± 0.55%) 43.03s (± 0.26%) ~ 42.89s 43.20s p=0.471 n=6
Emit Time 3.49s (± 3.70%) 3.48s (± 2.16%) ~ 3.36s 3.55s p=0.872 n=6
Total Time 55.22s (± 0.67%) 55.41s (± 0.25%) ~ 55.24s 55.61s p=0.521 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,252,070 1,252,063 -7 (- 0.00%) ~ ~ p=0.001 n=6
Types 259,846 259,850 +4 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 3,067,692k (± 9.66%) 3,061,904k (± 9.66%) -5,789k (- 0.19%) 2,457,340k 3,183,092k p=0.045 n=6
Parse Time 6.75s (± 1.26%) 6.79s (± 0.99%) ~ 6.69s 6.89s p=0.471 n=6
Bind Time 2.26s (± 1.08%) 2.26s (± 1.46%) ~ 2.23s 2.32s p=0.872 n=6
Check Time 43.14s (± 0.43%) 43.07s (± 0.32%) ~ 42.82s 43.25s p=0.378 n=6
Emit Time 3.55s (± 2.19%) 3.46s (± 0.60%) ~ 3.44s 3.50s p=0.093 n=6
Total Time 55.69s (± 0.30%) 55.59s (± 0.29%) ~ 55.29s 55.75s p=0.689 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 264,682 264,687 +5 (+ 0.00%) ~ ~ p=0.001 n=6
Types 104,051 104,063 +12 (+ 0.01%) ~ ~ p=0.001 n=6
Memory used 443,421k (± 0.01%) 443,094k (± 0.02%) -327k (- 0.07%) 442,955k 443,263k p=0.005 n=6
Parse Time 3.54s (± 0.99%) 3.52s (± 0.71%) ~ 3.49s 3.56s p=0.332 n=6
Bind Time 1.38s (± 1.09%) 1.39s (± 0.59%) ~ 1.38s 1.40s p=0.190 n=6
Check Time 19.21s (± 0.48%) 19.26s (± 0.30%) ~ 19.19s 19.35s p=0.298 n=6
Emit Time 1.55s (± 0.97%) 1.55s (± 1.22%) ~ 1.53s 1.58s p=0.934 n=6
Total Time 25.68s (± 0.42%) 25.71s (± 0.23%) ~ 25.65s 25.81s p=0.470 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 72 72 ~ ~ ~ p=1.000 n=6
Symbols 225,493 225,493 ~ ~ ~ p=1.000 n=6
Types 94,373 94,373 ~ ~ ~ p=1.000 n=6
Memory used 370,231k (± 0.04%) 369,890k (± 0.04%) -341k (- 0.09%) 369,778k 370,112k p=0.008 n=6
Parse Time 2.85s (± 0.57%) 2.83s (± 1.81%) ~ 2.75s 2.88s p=0.936 n=6
Bind Time 1.64s (± 1.59%) 1.64s (± 1.46%) ~ 1.61s 1.67s p=0.935 n=6
Check Time 16.61s (± 0.36%) 16.62s (± 0.35%) ~ 16.54s 16.71s p=0.688 n=6
Emit Time 0.00s 0.00s (±244.70%) ~ 0.00s 0.01s p=0.405 n=6
Total Time 21.10s (± 0.25%) 21.09s (± 0.27%) ~ 21.00s 21.16s p=1.000 n=6
vscode - node (v18.15.0, x64)
Errors 11 16 🔻+5 (+45.45%) ~ ~ p=0.001 n=6
Symbols 4,080,607 4,076,020 -4,587 (- 0.11%) ~ ~ p=0.001 n=6
Types 1,285,827 1,284,796 -1,031 (- 0.08%) ~ ~ p=0.001 n=6
Memory used 3,866,631k (± 0.00%) 3,863,297k (± 0.00%) -3,334k (- 0.09%) 3,863,115k 3,863,498k p=0.005 n=6
Parse Time 15.63s (± 0.32%) 15.64s (± 0.39%) ~ 15.53s 15.70s p=0.744 n=6
Bind Time 5.26s (± 0.33%) 5.28s (± 0.68%) ~ 5.22s 5.33s p=0.145 n=6
Check Time 116.06s (± 3.07%) 116.47s (± 4.48%) ~ 110.88s 123.66s p=0.936 n=6
Emit Time 43.06s (±13.56%) 49.20s (±21.64%) ~ 38.46s 63.46s p=0.810 n=6
Total Time 180.01s (± 4.88%) 186.60s (± 7.02%) ~ 170.30s 201.88s p=0.378 n=6
webpack - node (v18.15.0, x64)
Errors 40 40 ~ ~ ~ p=1.000 n=6
Symbols 380,702 380,693 -9 (- 0.00%) ~ ~ p=0.001 n=6
Types 166,804 166,792 -12 (- 0.01%) ~ ~ p=0.001 n=6
Memory used 540,875k (± 0.02%) 540,195k (± 0.03%) -680k (- 0.13%) 539,972k 540,366k p=0.005 n=6
Parse Time 4.74s (± 0.35%) 4.72s (± 0.45%) ~ 4.70s 4.76s p=0.192 n=6
Bind Time 2.04s (± 0.60%) 2.04s (± 2.04%) ~ 1.97s 2.08s p=0.869 n=6
Check Time 22.96s (± 0.60%) 22.99s (± 0.53%) ~ 22.82s 23.16s p=1.000 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 29.75s (± 0.51%) 29.75s (± 0.49%) ~ 29.58s 29.95s p=0.936 n=6
xstate-main - node (v18.15.0, x64)
Errors 30 30 ~ ~ ~ p=1.000 n=6
Symbols 693,751 693,576 -175 (- 0.03%) ~ ~ p=0.001 n=6
Types 210,636 210,490 -146 (- 0.07%) ~ ~ p=0.001 n=6
Memory used 589,451k (± 0.04%) 588,516k (± 0.02%) -935k (- 0.16%) 588,405k 588,659k p=0.005 n=6
Parse Time 4.21s (± 0.28%) 4.19s (± 0.53%) ~ 4.16s 4.23s p=0.111 n=6
Bind Time 1.42s (± 1.21%) 1.42s (± 1.46%) ~ 1.39s 1.45s p=0.746 n=6
Check Time 21.30s (± 1.62%) 21.34s (± 1.85%) ~ 20.82s 21.68s p=0.471 n=6
Emit Time 0.01s (±109.43%) 0.00s (±244.70%) ~ 0.00s 0.01s p=0.282 n=6
Total Time 26.93s (± 1.24%) 26.95s (± 1.45%) ~ 26.40s 27.27s p=0.688 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

Copy link
Member

@gabritto gabritto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far, I just had some questions about some implementation details. Still need to go through some of the breaks/regression tests.


function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node);
return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node) || !!(getFunctionFlags(node) & FunctionFlags.Generator && node.body && forEachYieldExpression(node.body as Block, isContextSensitive));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in terms of readability, maybe this would be better as its own function, then it can have a descriptive name like hasContextSensitiveYieldExpression and that example can be its documentation.

// 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 instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper);
const type = instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Contributor Author

@Andarist Andarist Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addresses an effect break caught here. You can take a deeper look at the added test tests/cases/compiler/returnTypeInferenceContextualParameterTypesInGenerator1.ts. Without this the test runs into:

    export const layerServerHandlers = Rpcs.toLayer(
      gen(function* () {
        return {
          Register: (id) => String(id),
                     ~~
!!! error TS7006: Parameter 'id' implicitly has an 'any' type.
        };
      })
    );

In a way, this is a targeted fix that might address a fair chunk of real world scenarios. The problem with instantiateContextualType is, unfortunately, that its "lossy" at times (at least that can happen when return mappers are involved) - it can lose meaningful information for some nodes deeper in the tree. any/unknown don't provide any useful contextual information so this helps by keeping the contextual type in its uninstantiated form.

If you don't feel this approach is right, I'd have to dig into this again to refresh my memory on it to provide a better explanation.

Copy link
Contributor Author

@Andarist Andarist Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so I refreshed myself a little bit on this. As I mentioned, instantiateContextualType is tricky. I could probably easily find at least 5 issues related to it. Conceptually, the best contextual type might be one of the following:

  • uninstantiated contextual type (its constraints might end up being useful)
  • instantiated contextual type using inferred types and/or default
  • instantiated contextual type using return mapper

Only one of those survives instantiateContextualType though and at the time it gets called it's not exactly which one might be best (usually for nodes deeper in the AST). So given the current implementation, it's guaranteed there might be cases when this loses some useful information and it already happens today.

The above fix is targeted at the mentioned effect-related break but it should benefit more than that. Given the changes in this PR, a returnOnlyType was created: () => Generator<never, { Register: anyFunctionType; }, any>. That type is only created when hasContextSensitiveParameters(node) and this PR doesn't consider thisless generators to automatically have a context sensitive parameter. It's worth noting that returnOnlyType itself has ObjectFlags.NonInferrableType but its parts doesnt have that so inferences can be made from them. In fact, that's kinda the goal - as per the code comment:

// Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage

So an early inference is made from never into Eff and that makes the first branch in instantiateContextualType to kick in. But the instantiated type isn't all that useful - it's just unknown - and a better candidate can be discovered based on the returnMapper: HandlersFrom<Rpc<"Register", number, string>>.

So this PR just ignores those simple intrinsic types here as they won't benefit any contextual typing anyway (tbf, we could also ignore never). This allows the logic to try the other source of instantiation - the returnMapper. And, in there, it discovers the more interesting/useful type (HandlersFrom<Rpc<"Register", number, string>>). In fact, this branch could also ignore any/unknown and let the type to trickle down to the uninstantiated T. I pushed this out in ec8f425

case SyntaxKind.JSDocFunctionType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructSignature:
case SyntaxKind.ConstructorType:
Copy link
Member

@gabritto gabritto Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We seem to have added at least one of those on purpose:
#8941
So I'm wondering why it's not needed anymore. @ahejlsberg do you remember why this was needed?

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the top 400 repos with tsc comparing main and refs/pull/62243/merge:

Something interesting changed - please have a look.

Details

steven-tey/novel

1 of 2 projects failed to build with the old tsc and were ignored

packages/headless/tsconfig.json

@Andarist
Copy link
Contributor Author

Andarist commented Dec 8, 2025

@gabritto in case you have missed it, I commented on the breaks here

@jakebailey
Copy link
Member

The perf run shows 5 new errors in vscode; I am not sure why they are not showing up in the top or user tests...

@Andarist
Copy link
Contributor Author

Andarist commented Dec 8, 2025

@jakebailey thanks for noticing, I'll look into it

@Andarist
Copy link
Contributor Author

Andarist commented Dec 9, 2025

microsoft/vscode#282223 should address VS Code break. A general fix for this issue could be a performant version of #57421 .

I have prototyped locally a version of contextuallyCheckFunctionExpressionOrObjectLiteralMethod that could address the vscode break without changing their project but I'd consider it to be something out of the scope of this PR here. It would also only address the issue in a subset of scenarios (a solution to #57421 would still be required to fix it altogether)

@Andarist Andarist requested a review from gabritto December 9, 2025 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment