Add missing MetaProperty stuffs
Add missing parts in the binder and the checker to enable CFA + narrowing of `import.meta` values. Fixes #41468
This commit is contained in:
parent
87d10eb055
commit
d495957065
|
@ -882,11 +882,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isNarrowableReference(expr: Expression): boolean {
|
||||
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PrivateIdentifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
|
||||
(isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) ||
|
||||
isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right) ||
|
||||
isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression) ||
|
||||
isAssignmentExpression(expr) && isNarrowableReference(expr.left);
|
||||
return isDottedName(expr)
|
||||
|| (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression)
|
||||
|| isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right)
|
||||
|| isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression)
|
||||
|| isAssignmentExpression(expr) && isNarrowableReference(expr.left);
|
||||
}
|
||||
|
||||
function containsNarrowableReference(expr: Expression): boolean {
|
||||
|
@ -1369,7 +1369,7 @@ namespace ts {
|
|||
// is potentially an assertion and is therefore included in the control flow.
|
||||
if (node.kind === SyntaxKind.CallExpression) {
|
||||
const call = <CallExpression>node;
|
||||
if (isDottedName(call.expression) && call.expression.kind !== SyntaxKind.SuperKeyword) {
|
||||
if (call.expression.kind !== SyntaxKind.SuperKeyword && isDottedName(call.expression)) {
|
||||
currentFlow = createFlowCall(currentFlow, call);
|
||||
}
|
||||
}
|
||||
|
@ -2542,6 +2542,7 @@ namespace ts {
|
|||
node.flowNode = currentFlow;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.MetaProperty:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
node.flowNode = currentFlow;
|
||||
break;
|
||||
|
|
|
@ -21320,6 +21320,12 @@ namespace ts {
|
|||
(isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right));
|
||||
}
|
||||
switch (source.kind) {
|
||||
case SyntaxKind.MetaProperty:
|
||||
return target.kind === SyntaxKind.MetaProperty
|
||||
&& (source as MetaProperty).keywordToken === SyntaxKind.ImportKeyword
|
||||
&& (target as MetaProperty).keywordToken === SyntaxKind.ImportKeyword
|
||||
&& (source as MetaProperty).name.escapedText === "meta"
|
||||
&& (target as MetaProperty).name.escapedText === "meta";
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.PrivateIdentifier:
|
||||
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||
|
||||
|
|
|
@ -4836,9 +4836,12 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function isDottedName(node: Expression): boolean {
|
||||
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword ||
|
||||
node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((<PropertyAccessExpression>node).expression) ||
|
||||
node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((<ParenthesizedExpression>node).expression);
|
||||
return node.kind === SyntaxKind.Identifier
|
||||
|| node.kind === SyntaxKind.ThisKeyword
|
||||
|| node.kind === SyntaxKind.SuperKeyword
|
||||
|| node.kind === SyntaxKind.MetaProperty
|
||||
|| node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((<PropertyAccessExpression>node).expression)
|
||||
|| node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((<ParenthesizedExpression>node).expression);
|
||||
}
|
||||
|
||||
export function isPropertyAccessEntityNameExpression(node: Node): node is PropertyAccessEntityNameExpression {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
//// [importMetaNarrowing.ts]
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
||||
|
||||
|
||||
//// [importMetaNarrowing.js]
|
||||
;
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
||||
export {};
|
|
@ -0,0 +1,15 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : Symbol(global, Decl(importMetaNarrowing.ts, 0, 0))
|
||||
>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(importMetaNarrowing.ts, 0, 16))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : (() => void) | undefined
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo() : void
|
||||
>import.meta.foo : () => void
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : () => void
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
//// [importMetaNarrowing.ts]
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
||||
|
||||
|
||||
//// [importMetaNarrowing.js]
|
||||
;
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
||||
export {};
|
|
@ -0,0 +1,15 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : Symbol(global, Decl(importMetaNarrowing.ts, 0, 0))
|
||||
>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(importMetaNarrowing.ts, 0, 16))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : (() => void) | undefined
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo() : void
|
||||
>import.meta.foo : () => void
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : () => void
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//// [importMetaNarrowing.ts]
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
||||
|
||||
|
||||
//// [importMetaNarrowing.js]
|
||||
System.register([], function (exports_1, context_1) {
|
||||
"use strict";
|
||||
var __moduleName = context_1 && context_1.id;
|
||||
return {
|
||||
setters: [],
|
||||
execute: function () {
|
||||
;
|
||||
if (context_1.meta.foo) {
|
||||
context_1.meta.foo();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : Symbol(global, Decl(importMetaNarrowing.ts, 0, 0))
|
||||
>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(importMetaNarrowing.ts, 0, 16))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
>global : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
if (import.meta.foo) {
|
||||
>import.meta.foo : (() => void) | undefined
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : (() => void) | undefined
|
||||
|
||||
import.meta.foo();
|
||||
>import.meta.foo() : void
|
||||
>import.meta.foo : () => void
|
||||
>import.meta : ImportMeta
|
||||
>meta : any
|
||||
>foo : () => void
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// @module: esnext,system,es2020
|
||||
// @strict: true
|
||||
|
||||
declare global { interface ImportMeta {foo?: () => void} };
|
||||
|
||||
if (import.meta.foo) {
|
||||
import.meta.foo();
|
||||
}
|
Loading…
Reference in a new issue