diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b07a0a075080e..4adea95f1f69e 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3948,6 +3948,10 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.ClassStaticBlockDeclaration: return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; + case SyntaxKind.JSDocImportTag: + // treat as a container to prevent using an enclosing effective host, ensuring import bindings are scoped correctly + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals; + case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression; diff --git a/tests/baselines/reference/importTag24.errors.txt b/tests/baselines/reference/importTag24.errors.txt new file mode 100644 index 0000000000000..5cd7499550029 --- /dev/null +++ b/tests/baselines/reference/importTag24.errors.txt @@ -0,0 +1,38 @@ +a.js(3,10): error TS6133: 'f1' is declared but its value is never read. +a.js(11,10): error TS6133: 'f3' is declared but its value is never read. +a.js(19,10): error TS6133: 'f4' is declared but its value is never read. +a.js(19,17): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== types.d.ts (0 errors) ==== + export type Foo = string; + +==== a.js (4 errors) ==== + /** @import { Foo } from './types.d.ts' */ + + function f1() { return undefined; } + ~~ +!!! error TS6133: 'f1' is declared but its value is never read. + + export function f2() { + /** @type {Set} */ + const foo = new Set([ 'a', 'b' ]); + return foo; + } + + function f3() { return undefined; } + ~~ +!!! error TS6133: 'f3' is declared but its value is never read. + + /** @type {Set} */ + export const foo = new Set([ 'a', 'b' ]); + + /** + * @returns {Foo} + */ + function f4() { return 1; } + ~~ +!!! error TS6133: 'f4' is declared but its value is never read. + ~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/importTag24.symbols b/tests/baselines/reference/importTag24.symbols new file mode 100644 index 0000000000000..1cfa53ff72210 --- /dev/null +++ b/tests/baselines/reference/importTag24.symbols @@ -0,0 +1,40 @@ +//// [tests/cases/conformance/jsdoc/importTag24.ts] //// + +=== types.d.ts === +export type Foo = string; +>Foo : Symbol(Foo, Decl(types.d.ts, 0, 0)) + +=== a.js === +/** @import { Foo } from './types.d.ts' */ + +function f1() { return undefined; } +>f1 : Symbol(f1, Decl(a.js, 0, 0)) +>undefined : Symbol(undefined) + +export function f2() { +>f2 : Symbol(f2, Decl(a.js, 2, 35)) + + /** @type {Set} */ + const foo = new Set([ 'a', 'b' ]); +>foo : Symbol(foo, Decl(a.js, 6, 9)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) + + return foo; +>foo : Symbol(foo, Decl(a.js, 6, 9)) +} + +function f3() { return undefined; } +>f3 : Symbol(f3, Decl(a.js, 8, 1)) +>undefined : Symbol(undefined) + +/** @type {Set} */ +export const foo = new Set([ 'a', 'b' ]); +>foo : Symbol(foo, Decl(a.js, 13, 12)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) + +/** + * @returns {Foo} + */ +function f4() { return 1; } +>f4 : Symbol(f4, Decl(a.js, 13, 41)) + diff --git a/tests/baselines/reference/importTag24.types b/tests/baselines/reference/importTag24.types new file mode 100644 index 0000000000000..1a4387b3d0ca8 --- /dev/null +++ b/tests/baselines/reference/importTag24.types @@ -0,0 +1,74 @@ +//// [tests/cases/conformance/jsdoc/importTag24.ts] //// + +=== Performance Stats === +Type Count: 1,000 +Instantiation count: 2,500 + +=== types.d.ts === +export type Foo = string; +>Foo : string +> : ^^^^^^ + +=== a.js === +/** @import { Foo } from './types.d.ts' */ + +function f1() { return undefined; } +>f1 : () => any +> : ^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ + +export function f2() { +>f2 : () => Set +> : ^^^^^^^^^^^^^^^^^ + + /** @type {Set} */ + const foo = new Set([ 'a', 'b' ]); +>foo : Set +> : ^^^^^^^^^^^ +>new Set([ 'a', 'b' ]) : Set +> : ^^^^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[ 'a', 'b' ] : string[] +> : ^^^^^^^^ +>'a' : "a" +> : ^^^ +>'b' : "b" +> : ^^^ + + return foo; +>foo : Set +> : ^^^^^^^^^^^ +} + +function f3() { return undefined; } +>f3 : () => any +> : ^^^^^^^^^ +>undefined : undefined +> : ^^^^^^^^^ + +/** @type {Set} */ +export const foo = new Set([ 'a', 'b' ]); +>foo : Set +> : ^^^^^^^^^^^ +>new Set([ 'a', 'b' ]) : Set +> : ^^^^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[ 'a', 'b' ] : string[] +> : ^^^^^^^^ +>'a' : "a" +> : ^^^ +>'b' : "b" +> : ^^^ + +/** + * @returns {Foo} + */ +function f4() { return 1; } +>f4 : () => Foo +> : ^^^^^^^^^ +>1 : 1 +> : ^ + diff --git a/tests/baselines/reference/importTag25.symbols b/tests/baselines/reference/importTag25.symbols new file mode 100644 index 0000000000000..2df3cd255937d --- /dev/null +++ b/tests/baselines/reference/importTag25.symbols @@ -0,0 +1,25 @@ +//// [tests/cases/conformance/jsdoc/importTag25.ts] //// + +=== types.d.ts === +export type T = { +>T : Symbol(T, Decl(types.d.ts, 0, 0)) + + a: number; +>a : Symbol(a, Decl(types.d.ts, 0, 17)) + +}; + +=== foo.js === +/** @import { T } from "./types.d.ts" */ + +export default async function f() { +>f : Symbol(f, Decl(foo.js, 0, 0)) + + /** @type {T[]} */ + const types = []; +>types : Symbol(types, Decl(foo.js, 4, 6)) + + return types; +>types : Symbol(types, Decl(foo.js, 4, 6)) +} + diff --git a/tests/baselines/reference/importTag25.types b/tests/baselines/reference/importTag25.types new file mode 100644 index 0000000000000..9e72920ba9677 --- /dev/null +++ b/tests/baselines/reference/importTag25.types @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsdoc/importTag25.ts] //// + +=== types.d.ts === +export type T = { +>T : T +> : ^ + + a: number; +>a : number +> : ^^^^^^ + +}; + +=== foo.js === +/** @import { T } from "./types.d.ts" */ + +export default async function f() { +>f : () => Promise +> : ^^^^^^^^^^^^^^^^^^ + + /** @type {T[]} */ + const types = []; +>types : T[] +> : ^^^ +>[] : undefined[] +> : ^^^^^^^^^^^ + + return types; +>types : T[] +> : ^^^ +} + diff --git a/tests/cases/conformance/jsdoc/importTag24.ts b/tests/cases/conformance/jsdoc/importTag24.ts new file mode 100644 index 0000000000000..1db1fe46b9e26 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag24.ts @@ -0,0 +1,33 @@ +// @checkJs: true +// @allowJs: true +// @noEmit: true +// @lib: esnext +// @moduleResolution: bundler +// @module: preserve +// @noUnusedLocals: true +// @noUnusedParameters: true +// @allowImportingTsExtensions: true + +// @filename: types.d.ts +export type Foo = string; + +// @filename: a.js +/** @import { Foo } from './types.d.ts' */ + +function f1() { return undefined; } + +export function f2() { + /** @type {Set} */ + const foo = new Set([ 'a', 'b' ]); + return foo; +} + +function f3() { return undefined; } + +/** @type {Set} */ +export const foo = new Set([ 'a', 'b' ]); + +/** + * @returns {Foo} + */ +function f4() { return 1; } diff --git a/tests/cases/conformance/jsdoc/importTag25.ts b/tests/cases/conformance/jsdoc/importTag25.ts new file mode 100644 index 0000000000000..423ea12b50518 --- /dev/null +++ b/tests/cases/conformance/jsdoc/importTag25.ts @@ -0,0 +1,18 @@ +// @noUnusedLocals: true +// @allowJs: true +// @checkJs: true +// @noEmit: true + +// @filename: types.d.ts +export type T = { + a: number; +}; + +// @filename: foo.js +/** @import { T } from "./types.d.ts" */ + +export default async function f() { + /** @type {T[]} */ + const types = []; + return types; +}