From c51749a5cf80dee6ac35092e5a2533ad5b86db3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 9 Jun 2024 22:23:09 +0200 Subject: [PATCH 1/3] Fixed declaration emit issue related to a qualifier being reused cross-file --- src/compiler/checker.ts | 2 +- ...clarationEmitTopLevelNodeFromCrossFile2.js | 43 +++++++++++++++++ ...tionEmitTopLevelNodeFromCrossFile2.symbols | 47 ++++++++++++++++++ ...rationEmitTopLevelNodeFromCrossFile2.types | 48 +++++++++++++++++++ ...clarationEmitTopLevelNodeFromCrossFile2.ts | 24 ++++++++++ 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.js create mode 100644 tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.symbols create mode 100644 tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.types create mode 100644 tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5cefd7aa08717..606c9f14b3341 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8840,7 +8840,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node, factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)), node.attributes, - node.qualifier, + visitNode(node.qualifier, visitExistingNodeTreeSymbols, isEntityName), visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode), node.isTypeOf, ); diff --git a/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.js b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.js new file mode 100644 index 0000000000000..751daef54ab9e --- /dev/null +++ b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.js @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts] //// + +//// [a.ts] +import { boxedBox } from "./boxedBox"; + +export const _ = boxedBox; + +// At index 83 +/** + * wat + */ + +//// [boxedBox.d.ts] +export declare const boxedBox: import("./box").Box<{ + boxed: import("./box").Box; +}>; // ^This is index 83 in this file + +//// [box.d.ts] +export declare class Box { + value: T; + constructor(value: T); +} +export declare function box(value: T): Box; + +//// [a.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports._ = void 0; +var boxedBox_1 = require("./boxedBox"); +exports._ = boxedBox_1.boxedBox; +// At index 83 +/** + * wat + */ + + +//// [a.d.ts] +export declare const _: import("./box").Box<{ + boxed: import("./box").Box; +}>; +/** + * wat + */ diff --git a/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.symbols b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.symbols new file mode 100644 index 0000000000000..eb5891fdfbe81 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.symbols @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts] //// + +=== a.ts === +import { boxedBox } from "./boxedBox"; +>boxedBox : Symbol(boxedBox, Decl(a.ts, 0, 8)) + +export const _ = boxedBox; +>_ : Symbol(_, Decl(a.ts, 2, 12)) +>boxedBox : Symbol(boxedBox, Decl(a.ts, 0, 8)) + +// At index 83 +/** + * wat + */ + +=== boxedBox.d.ts === +export declare const boxedBox: import("./box").Box<{ +>boxedBox : Symbol(boxedBox, Decl(boxedBox.d.ts, 0, 20)) +>Box : Symbol(Box, Decl(box.d.ts, 0, 0)) + + boxed: import("./box").Box; +>boxed : Symbol(boxed, Decl(boxedBox.d.ts, 0, 52)) +>Box : Symbol(Box, Decl(box.d.ts, 0, 0)) + +}>; // ^This is index 83 in this file + +=== box.d.ts === +export declare class Box { +>Box : Symbol(Box, Decl(box.d.ts, 0, 0)) +>T : Symbol(T, Decl(box.d.ts, 0, 25)) + + value: T; +>value : Symbol(Box.value, Decl(box.d.ts, 0, 29)) +>T : Symbol(T, Decl(box.d.ts, 0, 25)) + + constructor(value: T); +>value : Symbol(value, Decl(box.d.ts, 2, 16)) +>T : Symbol(T, Decl(box.d.ts, 0, 25)) +} +export declare function box(value: T): Box; +>box : Symbol(box, Decl(box.d.ts, 3, 1)) +>T : Symbol(T, Decl(box.d.ts, 4, 28)) +>value : Symbol(value, Decl(box.d.ts, 4, 31)) +>T : Symbol(T, Decl(box.d.ts, 4, 28)) +>Box : Symbol(Box, Decl(box.d.ts, 0, 0)) +>T : Symbol(T, Decl(box.d.ts, 4, 28)) + diff --git a/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.types b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.types new file mode 100644 index 0000000000000..5cc1c050264f5 --- /dev/null +++ b/tests/baselines/reference/declarationEmitTopLevelNodeFromCrossFile2.types @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts] //// + +=== a.ts === +import { boxedBox } from "./boxedBox"; +>boxedBox : import("box").Box<{ boxed: import("box").Box; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ + +export const _ = boxedBox; +>_ : import("box").Box<{ boxed: import("box").Box; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ +>boxedBox : import("box").Box<{ boxed: import("box").Box; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ + +// At index 83 +/** + * wat + */ + +=== boxedBox.d.ts === +export declare const boxedBox: import("./box").Box<{ +>boxedBox : import("box").Box<{ boxed: import("./box").Box; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ + + boxed: import("./box").Box; +>boxed : import("box").Box +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +}>; // ^This is index 83 in this file + +=== box.d.ts === +export declare class Box { +>Box : Box +> : ^^^^^^ + + value: T; +>value : T +> : ^ + + constructor(value: T); +>value : T +> : ^ +} +export declare function box(value: T): Box; +>box : (value: T) => Box +> : ^ ^^ ^^ ^^^^^ +>value : T +> : ^ + diff --git a/tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts b/tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts new file mode 100644 index 0000000000000..14c4fce85a721 --- /dev/null +++ b/tests/cases/compiler/declarationEmitTopLevelNodeFromCrossFile2.ts @@ -0,0 +1,24 @@ +// @strict: true +// @declaration: true + +// @filename: a.ts +import { boxedBox } from "./boxedBox"; + +export const _ = boxedBox; + +// At index 83 +/** + * wat + */ + +// @filename: boxedBox.d.ts +export declare const boxedBox: import("./box").Box<{ + boxed: import("./box").Box; +}>; // ^This is index 83 in this file + +// @filename: box.d.ts +export declare class Box { + value: T; + constructor(value: T); +} +export declare function box(value: T): Box; \ No newline at end of file From 68a0fcf94bb2640a9fa0ca1e86361d7e80ff3a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 12 Jun 2024 20:56:11 +0200 Subject: [PATCH 2/3] clone more nodes --- src/compiler/checker.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 606c9f14b3341..5b429cb612900 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8726,7 +8726,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isJSDocTypeLiteral(node)) { return factory.createTypeLiteralNode(map(node.jsDocPropertyTags, t => { - const name = isIdentifier(t.name) ? t.name : t.name.right; + const name = visitNode(isIdentifier(t.name) ? t.name : t.name.right, visitExistingNodeTreeSymbols, isIdentifier)!; const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(context, node), name.escapedText); const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(context, t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined; @@ -8765,7 +8765,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), setTextRange(context, factory.createIdentifier(getNameForJSDocFunctionParameter(p, i)), p), - p.questionToken, + p.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined, )), @@ -8780,7 +8780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), setTextRange(context, factory.createIdentifier(getNameForJSDocFunctionParameter(p, i)), p), - p.questionToken, + p.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined, )), @@ -8798,7 +8798,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTypeParameterDeclaration(node)) { return factory.updateTypeParameterDeclaration( node, - node.modifiers, + visitNodes(node.modifiers, visitExistingNodeTreeSymbols, isModifier), setTextRange(context, typeParameterToName(getDeclaredTypeOfSymbol(getSymbolOfDeclaration(node)), context), node), visitNode(node.constraint, visitExistingNodeTreeSymbols, isTypeNode), visitNode(node.default, visitExistingNodeTreeSymbols, isTypeNode), @@ -8839,7 +8839,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.updateImportTypeNode( node, factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)), - node.attributes, + visitNode(node.attributes, visitExistingNodeTreeSymbols, isImportAttributes), visitNode(node.qualifier, visitExistingNodeTreeSymbols, isEntityName), visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode), node.isTypeOf, @@ -8904,9 +8904,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { parameterName = result; } else { - parameterName = node.parameterName; + parameterName = factory.cloneNode(node.parameterName); } - return factory.updateTypePredicateNode(node, node.assertsModifier, parameterName, visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode)); + return factory.updateTypePredicateNode(node, node.assertsModifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, parameterName, visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode)); } if (isTupleTypeNode(node) || isTypeLiteralNode(node) || isMappedTypeNode(node)) { From 2a217f0d3c0eae3e2c6bac265499d9eee362c743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 12 Jun 2024 21:56:46 +0200 Subject: [PATCH 3/3] try with `cloneNode` --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5b429cb612900..ceaedaa36c512 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8765,7 +8765,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), setTextRange(context, factory.createIdentifier(getNameForJSDocFunctionParameter(p, i)), p), - p.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + factory.cloneNode(p.questionToken), visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined, )), @@ -8780,7 +8780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), setTextRange(context, factory.createIdentifier(getNameForJSDocFunctionParameter(p, i)), p), - p.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + factory.cloneNode(p.questionToken), visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined, )), @@ -8906,7 +8906,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { parameterName = factory.cloneNode(node.parameterName); } - return factory.updateTypePredicateNode(node, node.assertsModifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, parameterName, visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode)); + return factory.updateTypePredicateNode(node, factory.cloneNode(node.assertsModifier), parameterName, visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode)); } if (isTupleTypeNode(node) || isTypeLiteralNode(node) || isMappedTypeNode(node)) {