Skip to content

fix(51202): Circular instantiation expression crashing IDEs #51214

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

Merged
merged 12 commits into from
Feb 17, 2023

Conversation

a-tarasyuk
Copy link
Contributor

@a-tarasyuk a-tarasyuk commented Oct 18, 2022

Fixes #51202
Fixes #52757

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Oct 18, 2022
@@ -5481,6 +5481,12 @@ namespace ts {
}
}
else {
if (getObjectFlags(type) & ObjectFlags.InstantiationExpressionType) {
Copy link
Member

@DanielRosenwasser DanielRosenwasser Oct 18, 2022

Choose a reason for hiding this comment

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

I think having a fallback like this is good; still, I wonder if there's any way you can also special-case the logic here for typeof.

if (getObjectFlags(type) & ObjectFlags.InstantiationExpressionType)) {
    if (context.visitedTypes?.has(typeId)) {
        return createElidedInformationPlaceholder(context);
    }
    const instantiationExpressionType = type as InstantiationExpressionType;
    if (isTypeQueryNode(instantiationExpressionType.node)) {
        // deep clone the type query node
    }
    return visitAndTransformType(type, createTypeNodeFromObjectType);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is ok to emit

foo("");
>foo("") : typeof foo<T>
>foo : <T>(t: T) => typeof foo<T>

instead of

foo("");
>foo("") : (t: string) => any
>foo : <T>(t: T) => (t: T) => any
>"" : ""

?

Copy link
Member

Choose a reason for hiding this comment

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

Personally, I think so - other reviewers might have other thoughts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oke

Comment on lines 5490 to 5492
if (context.visitedTypes?.has(typeId)) {
return createElidedInformationPlaceholder(context);
}
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if there's a way to test this case. The current tests don't, right?

Copy link
Member

@DanielRosenwasser DanielRosenwasser left a comment

Choose a reason for hiding this comment

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

I think at least 1-2 more people should take a look.

if (isInstantiationExpressionType) {
const instantiationExpressionType = type as InstantiationExpressionType;
if (isTypeQueryNode(instantiationExpressionType.node)) {
return factory.cloneNode(instantiationExpressionType.node);
Copy link
Member

Choose a reason for hiding this comment

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

Use serializeExistingTypeNode here. Specifically, we may need to do things like remap jsdoc syntax into TS syntax in the subtree (type arguments), fixup module specifiers in import types for the new context, or track if the symbol referenced by a query is still visible within the new context.

Copy link
Member

Choose a reason for hiding this comment

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

(Specifically, you should probably do checks similar to what occur in serializeTypeForDeclaration to see if this type node is safe to reuse)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean the following checks?

if (!isErrorType(type) && enclosingDeclaration) {
    const declWithExistingAnnotation = getDeclarationWithTypeAnnotation(symbol, enclosingDeclaration);
    if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) && !isGetAccessorDeclaration(declWithExistingAnnotation)) {
        // try to reuse the existing annotation
        const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation) !;
        if (typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type)) {
            const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled);
            if (result) {
                return result;
            }
        }
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

What's the status here? I think the above is effectively what you have now in the current PR?

@jakebailey
Copy link
Member

Would you mind stealing the tests from #52789 as well? There are more cases than just the return type.

@typescript-bot typescript-bot added For Milestone Bug PRs that fix a bug with a specific milestone and removed For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Feb 16, 2023
@jakebailey
Copy link
Member

@weswigham Do you have any other feedback for this one? (I had a different fix for this via a duplicate bug, but this one seems better and it looks okay to me.)

@jakebailey
Copy link
Member

@typescript-bot test this
@typescript-bot test top100
@typescript-bot user test this
@typescript-bot user test tsserver
@typescript-bot test tsserver top100
@typescript-bot perf test this faster

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

Heya @jakebailey, I've started to run the diff-based top-repos suite (tsserver) on this PR at 389e1e2. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

Heya @jakebailey, I've started to run the extended test suite on this PR at 389e1e2. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 17, 2023

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

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@typescript-bot
Copy link
Collaborator

Heya @jakebailey, I've run the RWC suite on this PR - assuming you're on the TS core team, you can view the resulting diff here.

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - main..51214

Metric main 51214 Delta Best Worst p-value
Angular - node (v16.17.1, x64)
Memory used 359,087k (± 0.01%) 359,091k (± 0.01%) ~ 359,048k 359,135k p=0.873 n=6
Parse Time 4.15s (± 0.25%) 4.17s (± 0.39%) ~ 4.14s 4.19s p=0.138 n=6
Bind Time 1.24s (± 0.44%) 1.24s (± 0.33%) ~ 1.24s 1.25s p=0.054 n=6
Check Time 9.49s (± 0.29%) 9.51s (± 0.16%) ~ 9.49s 9.52s p=0.086 n=6
Emit Time 8.09s (± 0.74%) 8.05s (± 0.38%) ~ 8.02s 8.10s p=0.222 n=6
Total Time 22.97s (± 0.26%) 22.96s (± 0.18%) ~ 22.91s 23.03s p=0.809 n=6
Compiler-Unions - node (v16.17.1, x64)
Memory used 191,744k (± 0.01%) 192,311k (± 0.73%) ~ 191,701k 195,161k p=1.000 n=6
Parse Time 1.81s (± 0.70%) 1.80s (± 1.08%) ~ 1.77s 1.82s p=0.565 n=6
Bind Time 0.84s (± 0.48%) 0.84s (± 0.61%) ~ 0.84s 0.85s p=0.595 n=6
Check Time 10.21s (± 0.80%) 10.17s (± 0.64%) ~ 10.07s 10.25s p=0.423 n=6
Emit Time 3.07s (± 1.28%) 3.05s (± 0.92%) ~ 3.02s 3.09s p=0.257 n=6
Total Time 15.93s (± 0.43%) 15.85s (± 0.55%) ~ 15.75s 16.00s p=0.148 n=6
Monaco - node (v16.17.1, x64)
Memory used 343,555k (± 0.01%) 343,550k (± 0.01%) ~ 343,519k 343,628k p=0.689 n=6
Parse Time 3.12s (± 0.85%) 3.13s (± 0.72%) ~ 3.11s 3.17s p=0.465 n=6
Bind Time 1.12s (± 0.49%) 1.12s (± 0.67%) ~ 1.11s 1.13s p=0.476 n=6
Check Time 7.80s (± 0.26%) 7.80s (± 0.63%) ~ 7.74s 7.89s p=0.625 n=6
Emit Time 4.50s (± 0.57%) 4.53s (± 0.29%) ~ 4.51s 4.54s p=0.067 n=6
Total Time 16.55s (± 0.16%) 16.58s (± 0.36%) ~ 16.49s 16.67s p=0.227 n=6
TFS - node (v16.17.1, x64)
Memory used 299,652k (± 0.00%) 299,657k (± 0.01%) ~ 299,642k 299,678k p=0.521 n=6
Parse Time 2.45s (± 1.19%) 2.45s (± 0.42%) ~ 2.43s 2.46s p=1.000 n=6
Bind Time 1.26s (± 0.41%) 1.25s (± 0.44%) -0.01s (- 0.66%) 1.25s 1.26s p=0.038 n=6
Check Time 7.23s (± 0.57%) 7.23s (± 0.28%) ~ 7.20s 7.26s p=0.686 n=6
Emit Time 4.25s (± 1.41%) 4.23s (± 0.96%) ~ 4.18s 4.30s p=0.809 n=6
Total Time 15.19s (± 0.65%) 15.16s (± 0.36%) ~ 15.10s 15.23s p=0.470 n=6
material-ui - node (v16.17.1, x64)
Memory used 475,987k (± 0.01%) 475,966k (± 0.00%) ~ 475,943k 475,997k p=0.298 n=6
Parse Time 3.69s (± 0.20%) 3.69s (± 0.22%) ~ 3.68s 3.70s p=0.729 n=6
Bind Time 1.02s (± 0.50%) 1.02s (± 0.00%) ~ 1.02s 1.02s p=0.174 n=6
Check Time 18.17s (± 0.28%) 18.33s (± 0.69%) +0.15s (+ 0.84%) 18.23s 18.51s p=0.013 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 22.89s (± 0.22%) 23.04s (± 0.56%) +0.15s (+ 0.66%) 22.94s 23.22s p=0.024 n=6
xstate - node (v16.17.1, x64)
Memory used 546,914k (± 0.02%) 546,853k (± 0.02%) ~ 546,754k 546,960k p=0.378 n=6
Parse Time 4.78s (± 0.17%) 4.77s (± 0.49%) ~ 4.75s 4.82s p=0.325 n=6
Bind Time 1.85s (± 0.34%) 1.85s (± 0.41%) ~ 1.84s 1.86s p=0.718 n=6
Check Time 3.10s (± 0.47%) 3.07s (± 0.87%) ~ 3.05s 3.12s p=0.063 n=6
Emit Time 0.09s (± 4.45%) 0.09s (± 5.53%) ~ 0.09s 0.10s p=0.595 n=6
Total Time 9.82s (± 0.21%) 9.79s (± 0.28%) ~ 9.76s 9.83s p=0.124 n=6
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-135-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • Angular - node (v16.17.1, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Monaco - node (v16.17.1, x64)
  • TFS - node (v16.17.1, x64)
  • material-ui - node (v16.17.1, x64)
  • xstate - node (v16.17.1, x64)
Benchmark Name Iterations
Current 51214 6
Baseline main 6

Developer Information:

Download Benchmark

@typescript-bot
Copy link
Collaborator

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

Everything looks good!

@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the top-repos suite comparing main and refs/pull/51214/merge:

Everything looks good!

1 similar comment
@typescript-bot
Copy link
Collaborator

@jakebailey Here are the results of running the top-repos suite comparing main and refs/pull/51214/merge:

Everything looks good!

@jakebailey
Copy link
Member

Everything is clean; not surprising of course given it was previously a crash, though I was somewhat expecting to see the result of this PR allowing us to write more typeofs in the output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Compiler crash on some functions with self-referential types Circular instantiation expression crashing IDEs
5 participants