-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Conversation
src/compiler/checker.ts
Outdated
@@ -5481,6 +5481,12 @@ namespace ts { | |||
} | |||
} | |||
else { | |||
if (getObjectFlags(type) & ObjectFlags.InstantiationExpressionType) { |
There was a problem hiding this comment.
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);
}
There was a problem hiding this comment.
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
>"" : ""
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oke
src/compiler/checker.ts
Outdated
if (context.visitedTypes?.has(typeId)) { | ||
return createElidedInformationPlaceholder(context); | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this 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.
src/compiler/checker.ts
Outdated
if (isInstantiationExpressionType) { | ||
const instantiationExpressionType = type as InstantiationExpressionType; | ||
if (isTypeQueryNode(instantiationExpressionType.node)) { | ||
return factory.cloneNode(instantiationExpressionType.node); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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;
}
}
}
}
There was a problem hiding this comment.
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?
Would you mind stealing the tests from #52789 as well? There are more cases than just the return type. |
@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.) |
@typescript-bot test this |
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! |
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! |
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! |
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! |
Heya @jakebailey, I've started to run the extended test suite on this PR at 389e1e2. You can monitor the build here. |
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! |
@jakebailey Here are the results of running the user test suite comparing Everything looks good! |
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. |
@jakebailey Here they are:Comparison Report - main..51214
System
Hosts
Scenarios
Developer Information: |
@jakebailey Here are the results of running the user test suite comparing Everything looks good! |
@jakebailey Here are the results of running the top-repos suite comparing Everything looks good! |
1 similar comment
@jakebailey Here are the results of running the top-repos suite comparing Everything looks good! |
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. |
Fixes #51202
Fixes #52757