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

Partially reuse type nodes #58516

Merged

Conversation

dragomirtitian
Copy link
Contributor

Fixes #58515

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label May 13, 2024
@@ -16,7 +16,7 @@ var x = 1;
/** @type {NS.Nested.Inner} */
function f(space, peace) {
>f : (space: any, peace: any) => string | number
> : ^ ^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^
> : ^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
Copy link
Member

Choose a reason for hiding this comment

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

How does reuse end up being lowered here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The original version for JsDoc did fall back to type printing, but it also set the original node on this synthetic type node counting it as a reuse. Falling back to type printing should not count the node as reused in my opinion.

if (isTypeReferenceNode(node) && isInJSDoc(node) && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(node, getTypeFromTypeNode(node)) || getIntendedTypeFromJSDocTypeReference(node) || unknownSymbol === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true))) {
                    return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node);
                }
                

function serializeTypeName(context: NodeBuilderContext, node: EntityName, isTypeOf?: boolean, typeArguments?: readonly TypeNode[]) {
const meaning = isTypeOf ? SymbolFlags.Value : SymbolFlags.Type;
const symbol = resolveEntityName(node, meaning, /*ignoreErrors*/ true);
if (!symbol) return undefined;
Copy link
Member

@weswigham weswigham May 13, 2024

Choose a reason for hiding this comment

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

The default behavior here is to fall back to serializing the type node when the name doesn't resolve, and usually I'm inclined to approve of that approach, but the transpileDeclaration issues we've been getting have made me keenly aware that most names won't resolve when transpiled under that mode, and you probably want the default behavior to be copy-the-node when the name doesn't resolve rather than print-any (at least if the appropriate node builder context flag is set). This is somewhat reasonable since name-that-does-not-resolve is just any with more steps to get there.

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 actually isn't an issue the way this function is currently used. trackExistingEntityName will already not error if the symbol is not found and will just return the original name. serializeTypeName is always used as a fallback, when trackExistingEntityName fails so it will never be called if the symbol is not resolvable.

I added a test that shows that the types are reused even if the symbol is not found.

@weswigham
Copy link
Member

@dragomirtitian Do you also wanna copy your tests to the tests/cases/transpile folder to run them through the transpileDeclaration API endpoint, to ensure the output is actually what you want when global/other file context isn't present? That's particularly relevant for some of these examples that generate import type nodes (whose generation would seem to rely on the symbol actually resolving).

@dragomirtitian dragomirtitian force-pushed the isolated-declarations-partial-node-reuse branch from 1b3e65c to 4265b4e Compare May 14, 2024 16:24
@dragomirtitian
Copy link
Contributor Author

@dragomirtitian Do you also wanna copy your tests to the tests/cases/transpile folder to run them through the transpileDeclaration API endpoint, to ensure the output is actually what you want when global/other file context isn't present? That's particularly relevant for some of these examples that generate import type nodes (whose generation would seem to rely on the symbol actually resolving).

I can copy them, but these tests are not actually isolated declarations compliant and I would not expect these changes to actually work with transpileDeclaration. The use of import types and symbol resolution during node reuse will only work with the full type checker. This will only really kick in when a declaration is reused in a new location, and this should never happen with isolated declarations as if the type is not specified you get an error in isolated declarations.

@weswigham
Copy link
Member

I can copy them, but these tests are not actually isolated declarations compliant and I would not expect these changes to actually work with transpileDeclaration.

Yeah, I would just suggest the test be added to ensure there's still an --isolatedDeclarations error issued by the declaration emitter for these cases, though, and that the error itself isn't dependent on symbol or type information being available to be issued.

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

Thanks for the extra tests - from the issues we've been getting in thus far, it seems like it's probably a good idea going forward to test both the full typecheck behavior and the transpileDeclaration behavior for anything isolatedDeclarations-adjacent, so we know the two are consistent.

@weswigham weswigham merged commit 4ece0a3 into microsoft:main May 14, 2024
28 checks passed
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.

Reuse original type nodes even when part of the node is not usable
4 participants