From 3de032fd0df1264c4e3e13a0ed0bc1fe5f67f1d9 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 27 Jan 2022 16:18:14 -0800 Subject: [PATCH] Allow usage of local value symbol merged with type-only import (#47642) --- src/compiler/checker.ts | 30 ++++++++----------- .../reference/mergedWithLocalValue.js | 19 ++++++++++++ .../reference/mergedWithLocalValue.symbols | 17 +++++++++++ .../reference/mergedWithLocalValue.types | 18 +++++++++++ .../typeOnly/mergedWithLocalValue.ts | 7 +++++ 5 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 tests/baselines/reference/mergedWithLocalValue.js create mode 100644 tests/baselines/reference/mergedWithLocalValue.symbols create mode 100644 tests/baselines/reference/mergedWithLocalValue.types create mode 100644 tests/cases/conformance/externalModules/typeOnly/mergedWithLocalValue.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 11ed55a2c79..b6e8547381e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2235,29 +2235,23 @@ namespace ts { error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), declarationNameToString(errorLocation as Identifier)); } } - if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias) { - checkSymbolUsageInExpressionContext(result, name, errorLocation); + if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) { + const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result); + if (typeOnlyDeclaration) { + const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type + : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; + const unescapedName = unescapeLeadingUnderscores(name); + addTypeOnlyDeclarationRelatedInfo( + error(errorLocation, message, unescapedName), + typeOnlyDeclaration, + unescapedName); + } } } return result; } - function checkSymbolUsageInExpressionContext(symbol: Symbol, name: __String, useSite: Node) { - if (!isValidTypeOnlyAliasUseSite(useSite)) { - const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(symbol); - if (typeOnlyDeclaration) { - const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier - ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type - : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; - const unescapedName = unescapeLeadingUnderscores(name); - addTypeOnlyDeclarationRelatedInfo( - error(useSite, message, unescapedName), - typeOnlyDeclaration, - unescapedName); - } - } - } - function addTypeOnlyDeclarationRelatedInfo(diagnostic: Diagnostic, typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, unescapedName: string) { if (!typeOnlyDeclaration) return diagnostic; return addRelatedInfo( diff --git a/tests/baselines/reference/mergedWithLocalValue.js b/tests/baselines/reference/mergedWithLocalValue.js new file mode 100644 index 00000000000..a25a4909f5a --- /dev/null +++ b/tests/baselines/reference/mergedWithLocalValue.js @@ -0,0 +1,19 @@ +//// [tests/cases/conformance/externalModules/typeOnly/mergedWithLocalValue.ts] //// + +//// [a.ts] +export type A = "a"; + +//// [b.ts] +import type { A } from "./a"; +const A: A = "a"; +A.toUpperCase(); + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; +var A = "a"; +A.toUpperCase(); diff --git a/tests/baselines/reference/mergedWithLocalValue.symbols b/tests/baselines/reference/mergedWithLocalValue.symbols new file mode 100644 index 00000000000..141cb71694e --- /dev/null +++ b/tests/baselines/reference/mergedWithLocalValue.symbols @@ -0,0 +1,17 @@ +=== tests/cases/conformance/externalModules/typeOnly/a.ts === +export type A = "a"; +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== tests/cases/conformance/externalModules/typeOnly/b.ts === +import type { A } from "./a"; +>A : Symbol(A, Decl(b.ts, 0, 13), Decl(b.ts, 1, 5)) + +const A: A = "a"; +>A : Symbol(A, Decl(b.ts, 0, 13), Decl(b.ts, 1, 5)) +>A : Symbol(A, Decl(b.ts, 0, 13), Decl(b.ts, 1, 5)) + +A.toUpperCase(); +>A.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(b.ts, 0, 13), Decl(b.ts, 1, 5)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/mergedWithLocalValue.types b/tests/baselines/reference/mergedWithLocalValue.types new file mode 100644 index 00000000000..05666f8c5b6 --- /dev/null +++ b/tests/baselines/reference/mergedWithLocalValue.types @@ -0,0 +1,18 @@ +=== tests/cases/conformance/externalModules/typeOnly/a.ts === +export type A = "a"; +>A : "a" + +=== tests/cases/conformance/externalModules/typeOnly/b.ts === +import type { A } from "./a"; +>A : "a" + +const A: A = "a"; +>A : "a" +>"a" : "a" + +A.toUpperCase(); +>A.toUpperCase() : string +>A.toUpperCase : () => string +>A : "a" +>toUpperCase : () => string + diff --git a/tests/cases/conformance/externalModules/typeOnly/mergedWithLocalValue.ts b/tests/cases/conformance/externalModules/typeOnly/mergedWithLocalValue.ts new file mode 100644 index 00000000000..489f73a11a8 --- /dev/null +++ b/tests/cases/conformance/externalModules/typeOnly/mergedWithLocalValue.ts @@ -0,0 +1,7 @@ +// @Filename: a.ts +export type A = "a"; + +// @Filename: b.ts +import type { A } from "./a"; +const A: A = "a"; +A.toUpperCase();