Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer from context sensitive return expressions #60909

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Jan 3, 2025

fixes #60720
fixes #57021

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Jan 3, 2025
inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!);
}
}
if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) {
const returnType = getReturnTypeFromBody(node, checkMode);
let contextualReturnType: Type;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I literally wrote this code in August so I need to take another look at this, self-review it and add more tests. In the meantime though, it could be helpful for me to learn what the extended test suite thinks about this. cc @jakebailey :p

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, damn self-check :p I need to fix this first: repro

@jakebailey
Copy link
Member

@typescript-bot test it

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 3, 2025

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

Command Status 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

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

Everything looks the same!

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/60909/merge:

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 34 34 ~ ~ ~ p=1.000 n=6
Symbols 62,363 62,363 ~ ~ ~ p=1.000 n=6
Types 50,395 50,395 ~ ~ ~ p=1.000 n=6
Memory used 194,872k (± 1.03%) 194,231k (± 0.97%) ~ 192,991k 196,730k p=0.173 n=6
Parse Time 1.31s (± 0.39%) 1.31s (± 0.62%) ~ 1.30s 1.32s p=0.929 n=6
Bind Time 0.72s 0.72s (± 0.57%) ~ 0.71s 0.72s p=0.405 n=6
Check Time 9.79s (± 0.42%) 9.78s (± 0.14%) ~ 9.76s 9.80s p=0.747 n=6
Emit Time 2.73s (± 0.49%) 2.74s (± 0.58%) ~ 2.72s 2.76s p=0.328 n=6
Total Time 14.54s (± 0.21%) 14.55s (± 0.17%) ~ 14.51s 14.57s p=1.000 n=6
angular-1 - node (v18.15.0, x64)
Errors 37 37 ~ ~ ~ p=1.000 n=6
Symbols 947,936 947,936 ~ ~ ~ p=1.000 n=6
Types 410,955 410,955 ~ ~ ~ p=1.000 n=6
Memory used 1,225,835k (± 0.00%) 1,225,834k (± 0.00%) ~ 1,225,790k 1,225,899k p=1.000 n=6
Parse Time 6.63s (± 0.79%) 6.62s (± 0.51%) ~ 6.57s 6.66s p=0.872 n=6
Bind Time 1.89s (± 0.40%) 1.89s (± 0.40%) ~ 1.88s 1.90s p=1.000 n=6
Check Time 31.94s (± 0.47%) 32.01s (± 0.30%) ~ 31.88s 32.13s p=0.470 n=6
Emit Time 15.14s (± 0.30%) 15.13s (± 0.24%) ~ 15.06s 15.16s p=0.936 n=6
Total Time 55.59s (± 0.36%) 55.65s (± 0.17%) ~ 55.56s 55.80s p=1.000 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,446,528 2,446,529 +1 (+ 0.00%) ~ ~ p=0.001 n=6
Types 897,081 897,086 +5 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,311,164k (± 0.00%) 2,311,148k (± 0.00%) ~ 2,311,106k 2,311,176k p=0.810 n=6
Parse Time 8.97s (± 0.42%) 8.96s (± 0.26%) ~ 8.93s 8.99s p=0.936 n=6
Bind Time 2.12s (± 0.86%) 2.12s (± 0.42%) ~ 2.11s 2.13s p=0.676 n=6
Check Time 73.40s (± 0.76%) 73.40s (± 0.36%) ~ 73.03s 73.72s p=0.689 n=6
Emit Time 0.28s (± 2.67%) 0.28s (± 2.67%) ~ 0.27s 0.29s p=1.000 n=6
Total Time 84.77s (± 0.70%) 84.77s (± 0.33%) ~ 84.37s 85.11s p=0.689 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,226,880 1,226,905 +25 (+ 0.00%) ~ ~ p=0.001 n=6
Types 266,745 266,755 +10 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 2,600,204k (±14.43%) 2,479,005k (± 7.56%) ~ 2,357,573k 2,721,436k p=0.936 n=6
Parse Time 5.23s (± 2.62%) 5.19s (± 1.68%) ~ 5.12s 5.33s p=0.630 n=6
Bind Time 1.77s (± 1.42%) 1.77s (± 0.85%) ~ 1.75s 1.79s p=0.681 n=6
Check Time 35.34s (± 0.51%) 35.20s (± 0.71%) ~ 34.86s 35.37s p=0.378 n=6
Emit Time 2.97s (± 0.59%) 2.98s (± 1.03%) ~ 2.94s 3.02s p=0.575 n=6
Total Time 45.31s (± 0.60%) 45.16s (± 0.40%) ~ 44.88s 45.37s p=0.575 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,226,880 1,226,905 +25 (+ 0.00%) ~ ~ p=0.001 n=6
Types 266,745 266,755 +10 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 3,033,243k (± 9.77%) 2,670,364k (±14.03%) ~ 2,427,019k 3,154,800k p=0.298 n=6
Parse Time 6.95s (± 1.66%) 6.86s (± 1.91%) ~ 6.74s 7.04s p=0.575 n=6
Bind Time 2.15s (± 1.92%) 2.16s (± 1.80%) ~ 2.13s 2.23s p=1.000 n=6
Check Time 42.77s (± 0.41%) 42.76s (± 0.51%) ~ 42.46s 43.00s p=0.936 n=6
Emit Time 3.48s (± 2.20%) 3.53s (± 4.48%) ~ 3.39s 3.78s p=0.689 n=6
Total Time 55.36s (± 0.52%) 55.33s (± 0.67%) ~ 54.76s 55.62s p=0.936 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 262,439 262,445 +6 (+ 0.00%) ~ ~ p=0.001 n=6
Types 106,628 106,630 +2 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 440,230k (± 0.01%) 440,322k (± 0.02%) ~ 440,206k 440,416k p=0.093 n=6
Parse Time 3.54s (± 0.61%) 3.54s (± 1.41%) ~ 3.45s 3.59s p=0.373 n=6
Bind Time 1.33s (± 1.04%) 1.33s (± 0.61%) ~ 1.32s 1.34s p=0.605 n=6
Check Time 18.97s (± 0.71%) 19.05s (± 0.32%) ~ 18.97s 19.13s p=0.173 n=6
Emit Time 1.52s (± 0.68%) 1.53s (± 1.14%) ~ 1.51s 1.56s p=0.323 n=6
Total Time 25.36s (± 0.56%) 25.46s (± 0.34%) ~ 25.30s 25.56s p=0.148 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 70 70 ~ ~ ~ p=1.000 n=6
Symbols 226,062 226,062 ~ ~ ~ p=1.000 n=6
Types 94,488 94,488 ~ ~ ~ p=1.000 n=6
Memory used 371,583k (± 0.01%) 371,629k (± 0.03%) ~ 371,565k 371,851k p=0.936 n=6
Parse Time 2.90s (± 0.99%) 2.91s (± 1.06%) ~ 2.88s 2.97s p=0.808 n=6
Bind Time 1.60s (± 1.68%) 1.59s (± 1.76%) ~ 1.57s 1.65s p=1.000 n=6
Check Time 16.48s (± 0.28%) 16.51s (± 0.38%) ~ 16.45s 16.62s p=0.688 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 20.99s (± 0.38%) 21.01s (± 0.38%) ~ 20.93s 21.11s p=0.469 n=6
vscode - node (v18.15.0, x64)
Errors 3 3 ~ ~ ~ p=1.000 n=6
Symbols 3,230,418 3,230,429 +11 (+ 0.00%) ~ ~ p=0.001 n=6
Types 1,112,109 1,112,121 +12 (+ 0.00%) ~ ~ p=0.001 n=6
Memory used 3,294,618k (± 0.01%) 3,294,613k (± 0.01%) ~ 3,294,295k 3,295,098k p=0.936 n=6
Parse Time 14.12s (± 0.21%) 14.13s (± 0.45%) ~ 14.05s 14.21s p=0.936 n=6
Bind Time 4.54s (± 0.65%) 4.54s (± 0.48%) ~ 4.52s 4.58s p=0.745 n=6
Check Time 88.25s (± 2.78%) 89.11s (± 1.86%) ~ 87.37s 91.21s p=0.173 n=6
Emit Time 28.56s (± 3.29%) 28.59s (± 2.90%) ~ 27.43s 29.37s p=0.873 n=6
Total Time 135.47s (± 1.59%) 136.36s (± 0.95%) ~ 135.35s 138.71s p=0.173 n=6
webpack - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 291,562 291,631 +69 (+ 0.02%) ~ ~ p=0.001 n=6
Types 118,971 118,980 +9 (+ 0.01%) ~ ~ p=0.001 n=6
Memory used 445,342k (± 0.03%) 445,300k (± 0.03%) ~ 445,138k 445,509k p=0.471 n=6
Parse Time 4.13s (± 0.87%) 4.07s (± 1.01%) -0.06s (- 1.45%) 4.02s 4.12s p=0.024 n=6
Bind Time 1.79s (± 2.07%) 1.76s (± 1.55%) ~ 1.72s 1.80s p=0.296 n=6
Check Time 18.76s (± 0.51%) 18.75s (± 0.45%) ~ 18.65s 18.89s p=0.936 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 24.68s (± 0.47%) 24.58s (± 0.40%) ~ 24.48s 24.73s p=0.261 n=6
xstate-main - node (v18.15.0, x64)
Errors 5 5 ~ ~ ~ p=1.000 n=6
Symbols 555,017 555,098 +81 (+ 0.01%) ~ ~ p=0.001 n=6
Types 186,115 186,132 +17 (+ 0.01%) ~ ~ p=0.001 n=6
Memory used 493,984k (± 0.03%) 494,119k (± 0.01%) +135k (+ 0.03%) 494,085k 494,212k p=0.005 n=6
Parse Time 4.22s (± 0.66%) 4.23s (± 0.49%) ~ 4.22s 4.27s p=0.464 n=6
Bind Time 1.47s (± 0.56%) 1.45s (± 1.28%) ~ 1.42s 1.47s p=0.183 n=6
Check Time 24.39s (± 1.00%) 24.24s (± 0.45%) ~ 24.07s 24.35s p=0.199 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 30.08s (± 0.78%) 29.92s (± 0.35%) ~ 29.75s 30.03s p=0.198 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/60909/merge:

Everything looks good!

@Andarist
Copy link
Contributor Author

Andarist commented Jan 6, 2025

Ok, I think this one is in good shape for review. I've only made a small change to the code - I don't think it will impact any code in the wild but it might be good to rerun the extended tests.

@@ -1329,11 +1329,14 @@ export const enum CheckMode {
Inferential = 1 << 1, // Inferential typing
SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions
SkipGenericFunctions = 1 << 3, // Skip single signature generic functions
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
RestBindingElement = 1 << 5, // Checking a type that is going to be used to determine the type of a rest binding element
SkipReturnTypeFromBodyInference = 1 << 4, // Skip inferring from return types of context sensitive functions
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's separate from SkipGenericFunctions because getReturnTypeFromBody removes SkipGenericFunctions bit - so when the compiler gets to a function node with type parameters within a context-sensitive function's return it can't just use SkipGenericFunctions to skip over inferring its own return type from body.

The goal of SkipReturnTypeFromBodyInference is to persist through getReturnTypeFromBody.

const inferenceContext = getInferenceContext(node);
const isReturnContextSensitive = !!node.body && (node.body.kind === SyntaxKind.Block ? forEachReturnStatement(node.body as Block, statement => !!statement.expression && isContextSensitive(statement.expression)) : isContextSensitive(node.body));
returnType = getReturnTypeFromBody(node, checkMode | (isReturnContextSensitive ? CheckMode.SkipContextSensitive : 0));
inferTypes(inferenceContext!.inferences, returnType, contextualReturnType);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

alternatively, this could be handled by intra expression inference but that is order-sensitive and traditionally simple cases like this one aren't:

declare function test<T>(_: {
  stuff: T,
  consume: (arg: T) => void
}): void

test({
  consume: (arg) => {},
  stuff: 'foo' // this can come after `consume`
})

So the reason I put this logic here is that it allows for the same order-independence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Status: Not started
3 participants