Skip to content

Commit

Permalink
Fix assertion functions accessed via wildcard imports (#51324)
Browse files Browse the repository at this point in the history
* Add test

* Resolve alias of property in getTypeOfDottedName

* Always resolve

* Update tests
  • Loading branch information
jakebailey committed Oct 28, 2022
1 parent 64d0d5a commit 3d2b401
Show file tree
Hide file tree
Showing 9 changed files with 380 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -24490,6 +24490,7 @@ namespace ts {
}

function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) {
symbol = resolveSymbol(symbol);
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) {
return getTypeOfSymbol(symbol);
}
Expand Down Expand Up @@ -24529,7 +24530,7 @@ namespace ts {
switch (node.kind) {
case SyntaxKind.Identifier:
const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node as Identifier));
return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, diagnostic);
return getExplicitTypeOfSymbol(symbol, diagnostic);
case SyntaxKind.ThisKeyword:
return getExplicitThisType(node);
case SyntaxKind.SuperKeyword:
Expand Down
71 changes: 71 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport1.js
@@ -0,0 +1,71 @@
//// [tests/cases/compiler/assertionFunctionWildcardImport1.ts] ////

//// [ts.ts]
import * as Debug from "../debug";
export { Debug };

//// [debug.ts]
export declare function assert(expression: unknown): asserts expression;


//// [foo.ts]
import * as ts from "./_namespaces/ts";
import { Debug } from "./_namespaces/ts";

ts.Debug.assert(true);
Debug.assert(true);


//// [ts.ts]
export * from "../../core/_namespaces/ts"


//// [bar.ts]
import * as ts from "./_namespaces/ts";
import { Debug } from "./_namespaces/ts";

ts.Debug.assert(true);
Debug.assert(true);


//// [debug.js]
"use strict";
exports.__esModule = true;
//// [ts.js]
"use strict";
exports.__esModule = true;
exports.Debug = void 0;
var Debug = require("../debug");
exports.Debug = Debug;
//// [foo.js]
"use strict";
exports.__esModule = true;
var ts = require("./_namespaces/ts");
var ts_1 = require("./_namespaces/ts");
ts.Debug.assert(true);
ts_1.Debug.assert(true);
//// [ts.js]
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
exports.__esModule = true;
__exportStar(require("../../core/_namespaces/ts"), exports);
//// [bar.js]
"use strict";
exports.__esModule = true;
var ts = require("./_namespaces/ts");
var ts_1 = require("./_namespaces/ts");
ts.Debug.assert(true);
ts_1.Debug.assert(true);
58 changes: 58 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport1.symbols
@@ -0,0 +1,58 @@
=== tests/cases/compiler/src/core/_namespaces/ts.ts ===
import * as Debug from "../debug";
>Debug : Symbol(Debug, Decl(ts.ts, 0, 6))

export { Debug };
>Debug : Symbol(Debug, Decl(ts.ts, 1, 8))

=== tests/cases/compiler/src/core/debug.ts ===
export declare function assert(expression: unknown): asserts expression;
>assert : Symbol(assert, Decl(debug.ts, 0, 0))
>expression : Symbol(expression, Decl(debug.ts, 0, 31))
>expression : Symbol(expression, Decl(debug.ts, 0, 31))


=== tests/cases/compiler/src/core/foo.ts ===
import * as ts from "./_namespaces/ts";
>ts : Symbol(ts, Decl(foo.ts, 0, 6))

import { Debug } from "./_namespaces/ts";
>Debug : Symbol(Debug, Decl(foo.ts, 1, 8))

ts.Debug.assert(true);
>ts.Debug.assert : Symbol(ts.Debug.assert, Decl(debug.ts, 0, 0))
>ts.Debug : Symbol(ts.Debug, Decl(ts.ts, 1, 8))
>ts : Symbol(ts, Decl(foo.ts, 0, 6))
>Debug : Symbol(ts.Debug, Decl(ts.ts, 1, 8))
>assert : Symbol(ts.Debug.assert, Decl(debug.ts, 0, 0))

Debug.assert(true);
>Debug.assert : Symbol(ts.Debug.assert, Decl(debug.ts, 0, 0))
>Debug : Symbol(Debug, Decl(foo.ts, 1, 8))
>assert : Symbol(ts.Debug.assert, Decl(debug.ts, 0, 0))


=== tests/cases/compiler/src/other/_namespaces/ts.ts ===

export * from "../../core/_namespaces/ts"


=== tests/cases/compiler/src/other/bar.ts ===
import * as ts from "./_namespaces/ts";
>ts : Symbol(ts, Decl(bar.ts, 0, 6))

import { Debug } from "./_namespaces/ts";
>Debug : Symbol(Debug, Decl(bar.ts, 1, 8))

ts.Debug.assert(true);
>ts.Debug.assert : Symbol(Debug.assert, Decl(debug.ts, 0, 0))
>ts.Debug : Symbol(ts.Debug, Decl(ts.ts, 1, 8))
>ts : Symbol(ts, Decl(bar.ts, 0, 6))
>Debug : Symbol(ts.Debug, Decl(ts.ts, 1, 8))
>assert : Symbol(Debug.assert, Decl(debug.ts, 0, 0))

Debug.assert(true);
>Debug.assert : Symbol(Debug.assert, Decl(debug.ts, 0, 0))
>Debug : Symbol(Debug, Decl(bar.ts, 1, 8))
>assert : Symbol(Debug.assert, Decl(debug.ts, 0, 0))

65 changes: 65 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport1.types
@@ -0,0 +1,65 @@
=== tests/cases/compiler/src/core/_namespaces/ts.ts ===
import * as Debug from "../debug";
>Debug : typeof Debug

export { Debug };
>Debug : typeof Debug

=== tests/cases/compiler/src/core/debug.ts ===
export declare function assert(expression: unknown): asserts expression;
>assert : (expression: unknown) => asserts expression
>expression : unknown


=== tests/cases/compiler/src/core/foo.ts ===
import * as ts from "./_namespaces/ts";
>ts : typeof ts

import { Debug } from "./_namespaces/ts";
>Debug : typeof ts.Debug

ts.Debug.assert(true);
>ts.Debug.assert(true) : void
>ts.Debug.assert : (expression: unknown) => asserts expression
>ts.Debug : typeof ts.Debug
>ts : typeof ts
>Debug : typeof ts.Debug
>assert : (expression: unknown) => asserts expression
>true : true

Debug.assert(true);
>Debug.assert(true) : void
>Debug.assert : (expression: unknown) => asserts expression
>Debug : typeof ts.Debug
>assert : (expression: unknown) => asserts expression
>true : true


=== tests/cases/compiler/src/other/_namespaces/ts.ts ===

export * from "../../core/_namespaces/ts"


=== tests/cases/compiler/src/other/bar.ts ===
import * as ts from "./_namespaces/ts";
>ts : typeof ts

import { Debug } from "./_namespaces/ts";
>Debug : typeof ts.Debug

ts.Debug.assert(true);
>ts.Debug.assert(true) : void
>ts.Debug.assert : (expression: unknown) => asserts expression
>ts.Debug : typeof ts.Debug
>ts : typeof ts
>Debug : typeof ts.Debug
>assert : (expression: unknown) => asserts expression
>true : true

Debug.assert(true);
>Debug.assert(true) : void
>Debug.assert : (expression: unknown) => asserts expression
>Debug : typeof ts.Debug
>assert : (expression: unknown) => asserts expression
>true : true

40 changes: 40 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport2.js
@@ -0,0 +1,40 @@
//// [tests/cases/compiler/assertionFunctionWildcardImport2.ts] ////

//// [asserts.ts]
function isNonNullable<T>(obj: T): asserts obj is NonNullable<T> {
if (obj === undefined || obj === null) {
throw new Error("Must not be a nullable value");
}
}

export {
isNonNullable
};

//// [test.ts]
import * as asserts from "./asserts";

function test(obj: string | null): void {
asserts.isNonNullable(obj);
obj.trim();
}


//// [asserts.js]
"use strict";
exports.__esModule = true;
exports.isNonNullable = void 0;
function isNonNullable(obj) {
if (obj === undefined || obj === null) {
throw new Error("Must not be a nullable value");
}
}
exports.isNonNullable = isNonNullable;
//// [test.js]
"use strict";
exports.__esModule = true;
var asserts = require("./asserts");
function test(obj) {
asserts.isNonNullable(obj);
obj.trim();
}
46 changes: 46 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport2.symbols
@@ -0,0 +1,46 @@
=== tests/cases/compiler/asserts.ts ===
function isNonNullable<T>(obj: T): asserts obj is NonNullable<T> {
>isNonNullable : Symbol(isNonNullable, Decl(asserts.ts, 0, 0))
>T : Symbol(T, Decl(asserts.ts, 0, 23))
>obj : Symbol(obj, Decl(asserts.ts, 0, 26))
>T : Symbol(T, Decl(asserts.ts, 0, 23))
>obj : Symbol(obj, Decl(asserts.ts, 0, 26))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(asserts.ts, 0, 23))

if (obj === undefined || obj === null) {
>obj : Symbol(obj, Decl(asserts.ts, 0, 26))
>undefined : Symbol(undefined)
>obj : Symbol(obj, Decl(asserts.ts, 0, 26))

throw new Error("Must not be a nullable value");
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
}

export {
isNonNullable
>isNonNullable : Symbol(isNonNullable, Decl(asserts.ts, 6, 8))

};

=== tests/cases/compiler/test.ts ===
import * as asserts from "./asserts";
>asserts : Symbol(asserts, Decl(test.ts, 0, 6))

function test(obj: string | null): void {
>test : Symbol(test, Decl(test.ts, 0, 37))
>obj : Symbol(obj, Decl(test.ts, 2, 14))

asserts.isNonNullable(obj);
>asserts.isNonNullable : Symbol(asserts.isNonNullable, Decl(asserts.ts, 6, 8))
>asserts : Symbol(asserts, Decl(test.ts, 0, 6))
>isNonNullable : Symbol(asserts.isNonNullable, Decl(asserts.ts, 6, 8))
>obj : Symbol(obj, Decl(test.ts, 2, 14))

obj.trim();
>obj.trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --))
>obj : Symbol(obj, Decl(test.ts, 2, 14))
>trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --))
}

50 changes: 50 additions & 0 deletions tests/baselines/reference/assertionFunctionWildcardImport2.types
@@ -0,0 +1,50 @@
=== tests/cases/compiler/asserts.ts ===
function isNonNullable<T>(obj: T): asserts obj is NonNullable<T> {
>isNonNullable : <T>(obj: T) => asserts obj is NonNullable<T>
>obj : T

if (obj === undefined || obj === null) {
>obj === undefined || obj === null : boolean
>obj === undefined : boolean
>obj : T
>undefined : undefined
>obj === null : boolean
>obj : T & ({} | null)
>null : null

throw new Error("Must not be a nullable value");
>new Error("Must not be a nullable value") : Error
>Error : ErrorConstructor
>"Must not be a nullable value" : "Must not be a nullable value"
}
}

export {
isNonNullable
>isNonNullable : <T>(obj: T) => asserts obj is NonNullable<T>

};

=== tests/cases/compiler/test.ts ===
import * as asserts from "./asserts";
>asserts : typeof asserts

function test(obj: string | null): void {
>test : (obj: string | null) => void
>obj : string | null
>null : null

asserts.isNonNullable(obj);
>asserts.isNonNullable(obj) : void
>asserts.isNonNullable : <T>(obj: T) => asserts obj is NonNullable<T>
>asserts : typeof asserts
>isNonNullable : <T>(obj: T) => asserts obj is NonNullable<T>
>obj : string | null

obj.trim();
>obj.trim() : string
>obj.trim : () => string
>obj : string
>trim : () => string
}

28 changes: 28 additions & 0 deletions tests/cases/compiler/assertionFunctionWildcardImport1.ts
@@ -0,0 +1,28 @@
// @strict: true

// @filename: src/core/_namespaces/ts.ts
import * as Debug from "../debug";
export { Debug };

// @filename: src/core/debug.ts
export declare function assert(expression: unknown): asserts expression;


// @filename: src/core/foo.ts
import * as ts from "./_namespaces/ts";
import { Debug } from "./_namespaces/ts";

ts.Debug.assert(true);
Debug.assert(true);


// @filename: src/other/_namespaces/ts.ts
export * from "../../core/_namespaces/ts"


// @filename: src/other/bar.ts
import * as ts from "./_namespaces/ts";
import { Debug } from "./_namespaces/ts";

ts.Debug.assert(true);
Debug.assert(true);

0 comments on commit 3d2b401

Please sign in to comment.