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

Fixed a crash when inferring return type of an accessor with errors in its return statement #56258

Merged

Conversation

Andarist
Copy link
Contributor

fixes what has been reported here

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Oct 30, 2023
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@@ -7312,7 +7312,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

if (propertySymbol.flags & SymbolFlags.Accessor) {
const writeType = getWriteTypeOfSymbol(propertySymbol);
if (propertyType !== writeType) {
if (propertyType !== writeType && !isErrorType(propertyType) && !isErrorType(writeType)) {
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 feel like it might be seen as a little bit of an ad-hoc fix. The problem is that a resolved type of a position with a cycle usually is anyType but when we are resolving the type initially that type is returned as an error type when the cycle is detected.

So there is some small mismatch between the return values of functions like getTypeOfAccessors - one that depends on the timing of the call to them. I assume that this is intentional.

I noticed that getWriteTypeOfAccessors could accidentally-ish return the errorType and cache it. So I tried to fix it with:

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 074c3d3034..59c538e298 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -11758,7 +11758,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
                 writeType = anyType;
             }
             // Absent an explicit setter type annotation we use the read type of the accessor.
-            links.writeType = writeType || getTypeOfAccessors(symbol);
+            if (!writeType) {
+                const readType = getTypeOfAccessors(symbol);
+                writeType = readType !== errorType ? readType : anyType;
+            }
+            links.writeType = writeType;
         }
         return links.writeType;
     }

That didn't fix the issue though because when this line (the one that I'm changing here) was hit for the first time we had a situation like this:

propertyType // errorType
writeType // anyType

So the mismatch was still here - it just happened sooner. Originally, the mismatch could happen later when the property type already had a chance to "settle" as anyType but the writeType was already cached as the errorType.

I think this fix is quite fine since errorType being returned while resolving the type initially is expected and when that happens we don't quite need to serialize the property as one with divergent accessors. Maybe some further fine-tuning can be done here. I imagine that maybe there is some value in cases that could be serialized as:

export declare var basePrototype: {
    get primaryPath(): string;
    set primaryPath(v: any); // coming from the error
};

I don't have a test case for that at hand though. This whole issue that is being fixed by this PR is a regression so it's worth fixing it sooner than later 😉

I also think that maybe the patch that I posted above might still be worth pulling in since caching errorType here looks like something that is not intended. I don't have any test case that would prove it though.

Copy link
Member

Choose a reason for hiding this comment

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

The problem is that a resolved type of a position with a cycle usually is anyType

Maybe my memory is shot, but I kinda thought that we always returned errorType whenever a cycle occurred? Maybe that's just in the push/pop resolution world?

Copy link
Member

@DanielRosenwasser DanielRosenwasser Nov 14, 2023

Choose a reason for hiding this comment

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

I don't think there is anything wrong with letting an errorType propagate further (or get cached or whatever). It exists to act as an any and to specially handle more permissively in other cases.

(I could be wrong!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps this is just somewhat inconsistent across different callers. I see that some similar ones are returning errorType just fine. However, for example here the cycle is detected and errorType is returned immediately but when we climb up the stack to the first "visitor" of this type that errorType is converted to anyType here. A similar situation ("converting" errorType to anyType) can be seen in getTypeOfAccessors here and in getWriteTypeOfAccessors here.

I don't think there is anything wrong with letting an errorType propagate further (or get cached or whatever). It exists to act as an any and to specially handle more permissively in other cases.

Ye, it might not be a problem at all. I just tried to follow the pre-existing conventions in other 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.

I'll prepare an experiment later that will just return/cache errorType in all of those locations that detect the cycle.

@Andarist Andarist changed the title Fixed a crash when inferring return type of an accessor with errors in its return statetement Fixed a crash when inferring return type of an accessor with errors in its return statement Nov 13, 2023
@jakebailey
Copy link
Member

@typescript-bot test top200
@typescript-bot user test this
@typescript-bot run dt

@typescript-bot perf test this
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 14, 2023

Heya @jakebailey, I've started to run the diff-based top-repos suite on this PR at 3802cbe. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 14, 2023

Heya @jakebailey, I've started to run the tarball bundle task on this PR at 3802cbe. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 14, 2023

Heya @jakebailey, I've started to run the parallelized Definitely Typed test suite on this PR at 3802cbe. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 14, 2023

Heya @jakebailey, I've started to run the regular perf test suite on this PR at 3802cbe. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 14, 2023

Heya @jakebailey, I've started to run the diff-based user code test suite on this PR at 3802cbe. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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/158586/artifacts?artifactName=tgz&fileId=87066A8BCA66B8EE26BD12594FADBDE17762947288735EF839E565FE69496E0502&fileName=/typescript-5.4.0-insiders.20231114.tgz"
    }
}

and then running npm install.

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the user test suite comparing main and refs/pull/56258/merge:

There were infrastructure failures potentially unrelated to your change:

  • 2 instances of "Package install failed"

Otherwise...

Something interesting changed - please have a look.

Details

puppeteer

packages/browsers/test/src/tsconfig.json

@typescript-bot
Copy link
Collaborator

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

Here they are:

Compiler

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Angular - node (v18.15.0, x64)
Memory used 295,162k (± 0.01%) 295,197k (± 0.01%) +35k (+ 0.01%) 295,163k 295,216k p=0.020 n=6
Parse Time 2.64s (± 0.31%) 2.65s (± 0.37%) ~ 2.64s 2.66s p=0.498 n=6
Bind Time 0.82s (± 1.20%) 0.83s (± 1.01%) ~ 0.82s 0.84s p=0.445 n=6
Check Time 8.04s (± 0.23%) 8.03s (± 0.35%) ~ 8.00s 8.08s p=0.624 n=6
Emit Time 7.07s (± 0.17%) 7.09s (± 0.21%) ~ 7.07s 7.11s p=0.073 n=6
Total Time 18.57s (± 0.16%) 18.59s (± 0.16%) ~ 18.56s 18.63s p=0.416 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 190,700k (± 0.01%) 192,626k (± 1.54%) ~ 190,687k 196,473k p=0.471 n=6
Parse Time 1.36s (± 0.98%) 1.35s (± 1.01%) ~ 1.34s 1.38s p=0.282 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.57%) ~ 0.72s 0.73s p=0.405 n=6
Check Time 9.17s (± 0.29%) 9.18s (± 0.21%) ~ 9.15s 9.20s p=0.681 n=6
Emit Time 2.63s (± 0.62%) 2.62s (± 0.56%) ~ 2.60s 2.64s p=0.413 n=6
Total Time 13.88s (± 0.28%) 13.87s (± 0.17%) ~ 13.83s 13.89s p=0.808 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,355k (± 0.00%) 347,356k (± 0.00%) ~ 347,328k 347,377k p=1.000 n=6
Parse Time 2.45s (± 0.54%) 2.46s (± 0.21%) ~ 2.45s 2.46s p=0.546 n=6
Bind Time 0.92s (± 0.59%) 0.92s (± 0.59%) ~ 0.92s 0.93s p=1.000 n=6
Check Time 6.94s (± 0.50%) 6.92s (± 0.41%) ~ 6.88s 6.97s p=0.683 n=6
Emit Time 4.07s (± 0.57%) 4.05s (± 0.43%) ~ 4.02s 4.07s p=0.106 n=6
Total Time 14.38s (± 0.36%) 14.35s (± 0.25%) ~ 14.32s 14.41s p=0.297 n=6
TFS - node (v18.15.0, x64)
Memory used 302,652k (± 0.01%) 302,667k (± 0.01%) ~ 302,618k 302,731k p=0.471 n=6
Parse Time 2.00s (± 1.08%) 1.99s (± 1.13%) ~ 1.96s 2.03s p=0.413 n=6
Bind Time 1.00s (± 0.41%) 1.00s (± 0.41%) ~ 0.99s 1.00s p=1.000 n=6
Check Time 6.27s (± 0.55%) 6.28s (± 0.60%) ~ 6.23s 6.32s p=0.809 n=6
Emit Time 3.58s (± 0.54%) 3.58s (± 0.70%) ~ 3.55s 3.62s p=0.515 n=6
Total Time 12.85s (± 0.39%) 12.86s (± 0.38%) ~ 12.79s 12.92s p=0.872 n=6
material-ui - node (v18.15.0, x64)
Memory used 470,551k (± 0.01%) 470,536k (± 0.01%) ~ 470,501k 470,574k p=0.520 n=6
Parse Time 2.57s (± 0.58%) 2.58s (± 0.57%) ~ 2.56s 2.60s p=0.676 n=6
Bind Time 0.98s (± 1.23%) 0.99s (± 0.99%) ~ 0.98s 1.01s p=0.340 n=6
Check Time 16.67s (± 0.30%) 16.64s (± 0.61%) ~ 16.47s 16.76s p=0.748 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.22s (± 0.24%) 20.21s (± 0.54%) ~ 20.03s 20.33s p=1.000 n=6
xstate - node (v18.15.0, x64)
Memory used 512,838k (± 0.01%) 512,820k (± 0.01%) ~ 512,743k 512,908k p=0.689 n=6
Parse Time 3.27s (± 0.23%) 3.27s (± 0.16%) ~ 3.27s 3.28s p=0.241 n=6
Bind Time 1.54s (± 0.53%) 1.54s (± 0.90%) ~ 1.51s 1.55s p=0.932 n=6
Check Time 2.85s (± 0.44%) 2.86s (± 0.69%) ~ 2.83s 2.89s p=0.868 n=6
Emit Time 0.08s (± 4.99%) 0.08s (± 0.00%) ~ 0.08s 0.08s p=0.405 n=6
Total Time 7.73s (± 0.18%) 7.74s (± 0.29%) ~ 7.72s 7.77s p=0.686 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

tsserver

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,362ms (± 0.53%) 2,373ms (± 0.57%) ~ 2,353ms 2,389ms p=0.336 n=6
Req 2 - geterr 5,369ms (± 1.31%) 5,385ms (± 1.54%) ~ 5,310ms 5,493ms p=0.575 n=6
Req 3 - references 326ms (± 0.94%) 326ms (± 0.61%) ~ 323ms 329ms p=1.000 n=6
Req 4 - navto 278ms (± 1.20%) 277ms (± 1.17%) ~ 273ms 280ms p=0.615 n=6
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) ~ 1,356 1,356 p=1.000 n=6
Req 5 - completionInfo 83ms (± 6.81%) 82ms (± 8.03%) ~ 75ms 90ms p=0.466 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,504ms (± 0.71%) 2,484ms (± 0.82%) ~ 2,455ms 2,519ms p=0.173 n=6
Req 2 - geterr 4,059ms (± 1.52%) 4,149ms (± 1.19%) ~ 4,049ms 4,184ms p=0.066 n=6
Req 3 - references 342ms (± 1.31%) 336ms (± 1.43%) ~ 332ms 345ms p=0.145 n=6
Req 4 - navto 283ms (± 0.27%) 282ms (± 0.48%) ~ 280ms 284ms p=0.273 n=6
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) ~ 1,518 1,518 p=1.000 n=6
Req 5 - completionInfo 88ms (± 5.01%) 80ms (± 6.43%) 🟩-8ms (- 9.30%) 77ms 90ms p=0.029 n=6
xstateTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,598ms (± 0.25%) 2,593ms (± 0.22%) ~ 2,585ms 2,602ms p=0.289 n=6
Req 2 - geterr 1,733ms (± 1.84%) 1,708ms (± 2.17%) ~ 1,663ms 1,746ms p=0.335 n=6
Req 3 - references 114ms (± 9.27%) 116ms (± 9.17%) ~ 101ms 123ms p=0.935 n=6
Req 4 - navto 367ms (± 1.12%) 366ms (± 0.44%) ~ 364ms 368ms p=1.000 n=6
Req 5 - completionInfo count 2,073 (± 0.00%) 2,073 (± 0.00%) ~ 2,073 2,073 p=1.000 n=6
Req 5 - completionInfo 310ms (± 1.70%) 311ms (± 1.50%) ~ 305ms 316ms p=0.686 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstateTSServer - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Startup

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
tsc-startup - node (v18.15.0, x64)
Execution time 152.48ms (± 0.17%) 152.54ms (± 0.17%) +0.06ms (+ 0.04%) 151.15ms 154.61ms p=0.022 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time 227.81ms (± 0.14%) 227.64ms (± 0.17%) -0.17ms (- 0.08%) 226.16ms 232.00ms p=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time 228.76ms (± 0.17%) 228.81ms (± 0.24%) ~ 227.13ms 246.63ms p=0.620 n=600
typescript-startup - node (v18.15.0, x64)
Execution time 228.97ms (± 0.18%) 228.85ms (± 0.16%) -0.12ms (- 0.05%) 227.41ms 231.99ms p=0.006 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@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 top-repos suite comparing main and refs/pull/56258/merge:

Everything looks good!

@DanielRosenwasser DanielRosenwasser merged commit 32b618c into microsoft:main Nov 16, 2023
19 checks passed
DanielRosenwasser pushed a commit that referenced this pull request Nov 16, 2023
DanielRosenwasser pushed a commit that referenced this pull request Nov 16, 2023
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
None yet
Development

Successfully merging this pull request may close these issues.

4 participants