Skip to content

Commit d495957

Browse files
committed
Add missing MetaProperty stuffs
Add missing parts in the binder and the checker to enable CFA + narrowing of `import.meta` values. Fixes #41468
1 parent 87d10eb commit d495957

13 files changed

+179
-9
lines changed

src/compiler/binder.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -882,11 +882,11 @@ namespace ts {
882882
}
883883

884884
function isNarrowableReference(expr: Expression): boolean {
885-
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PrivateIdentifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
886-
(isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) ||
887-
isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right) ||
888-
isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression) ||
889-
isAssignmentExpression(expr) && isNarrowableReference(expr.left);
885+
return isDottedName(expr)
886+
|| (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression)
887+
|| isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right)
888+
|| isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression)
889+
|| isAssignmentExpression(expr) && isNarrowableReference(expr.left);
890890
}
891891

892892
function containsNarrowableReference(expr: Expression): boolean {
@@ -1369,7 +1369,7 @@ namespace ts {
13691369
// is potentially an assertion and is therefore included in the control flow.
13701370
if (node.kind === SyntaxKind.CallExpression) {
13711371
const call = <CallExpression>node;
1372-
if (isDottedName(call.expression) && call.expression.kind !== SyntaxKind.SuperKeyword) {
1372+
if (call.expression.kind !== SyntaxKind.SuperKeyword && isDottedName(call.expression)) {
13731373
currentFlow = createFlowCall(currentFlow, call);
13741374
}
13751375
}
@@ -2542,6 +2542,7 @@ namespace ts {
25422542
node.flowNode = currentFlow;
25432543
}
25442544
break;
2545+
case SyntaxKind.MetaProperty:
25452546
case SyntaxKind.SuperKeyword:
25462547
node.flowNode = currentFlow;
25472548
break;

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21320,6 +21320,12 @@ namespace ts {
2132021320
(isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right));
2132121321
}
2132221322
switch (source.kind) {
21323+
case SyntaxKind.MetaProperty:
21324+
return target.kind === SyntaxKind.MetaProperty
21325+
&& (source as MetaProperty).keywordToken === SyntaxKind.ImportKeyword
21326+
&& (target as MetaProperty).keywordToken === SyntaxKind.ImportKeyword
21327+
&& (source as MetaProperty).name.escapedText === "meta"
21328+
&& (target as MetaProperty).name.escapedText === "meta";
2132321329
case SyntaxKind.Identifier:
2132421330
case SyntaxKind.PrivateIdentifier:
2132521331
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||

src/compiler/utilities.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4836,9 +4836,12 @@ namespace ts {
48364836
}
48374837

48384838
export function isDottedName(node: Expression): boolean {
4839-
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword ||
4840-
node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((<PropertyAccessExpression>node).expression) ||
4841-
node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((<ParenthesizedExpression>node).expression);
4839+
return node.kind === SyntaxKind.Identifier
4840+
|| node.kind === SyntaxKind.ThisKeyword
4841+
|| node.kind === SyntaxKind.SuperKeyword
4842+
|| node.kind === SyntaxKind.MetaProperty
4843+
|| node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((<PropertyAccessExpression>node).expression)
4844+
|| node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((<ParenthesizedExpression>node).expression);
48424845
}
48434846

48444847
export function isPropertyAccessEntityNameExpression(node: Node): node is PropertyAccessEntityNameExpression {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [importMetaNarrowing.ts]
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
4+
if (import.meta.foo) {
5+
import.meta.foo();
6+
}
7+
8+
9+
//// [importMetaNarrowing.js]
10+
;
11+
if (import.meta.foo) {
12+
import.meta.foo();
13+
}
14+
export {};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
>global : Symbol(global, Decl(importMetaNarrowing.ts, 0, 0))
4+
>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(importMetaNarrowing.ts, 0, 16))
5+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
6+
7+
if (import.meta.foo) {
8+
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
9+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
10+
11+
import.meta.foo();
12+
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
13+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
14+
}
15+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
>global : any
4+
>foo : (() => void) | undefined
5+
6+
if (import.meta.foo) {
7+
>import.meta.foo : (() => void) | undefined
8+
>import.meta : ImportMeta
9+
>meta : any
10+
>foo : (() => void) | undefined
11+
12+
import.meta.foo();
13+
>import.meta.foo() : void
14+
>import.meta.foo : () => void
15+
>import.meta : ImportMeta
16+
>meta : any
17+
>foo : () => void
18+
}
19+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [importMetaNarrowing.ts]
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
4+
if (import.meta.foo) {
5+
import.meta.foo();
6+
}
7+
8+
9+
//// [importMetaNarrowing.js]
10+
;
11+
if (import.meta.foo) {
12+
import.meta.foo();
13+
}
14+
export {};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
>global : Symbol(global, Decl(importMetaNarrowing.ts, 0, 0))
4+
>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(importMetaNarrowing.ts, 0, 16))
5+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
6+
7+
if (import.meta.foo) {
8+
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
9+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
10+
11+
import.meta.foo();
12+
>import.meta.foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
13+
>foo : Symbol(ImportMeta.foo, Decl(importMetaNarrowing.ts, 0, 39))
14+
}
15+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/es2019/importMeta/importMetaNarrowing.ts ===
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
>global : any
4+
>foo : (() => void) | undefined
5+
6+
if (import.meta.foo) {
7+
>import.meta.foo : (() => void) | undefined
8+
>import.meta : ImportMeta
9+
>meta : any
10+
>foo : (() => void) | undefined
11+
12+
import.meta.foo();
13+
>import.meta.foo() : void
14+
>import.meta.foo : () => void
15+
>import.meta : ImportMeta
16+
>meta : any
17+
>foo : () => void
18+
}
19+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [importMetaNarrowing.ts]
2+
declare global { interface ImportMeta {foo?: () => void} };
3+
4+
if (import.meta.foo) {
5+
import.meta.foo();
6+
}
7+
8+
9+
//// [importMetaNarrowing.js]
10+
System.register([], function (exports_1, context_1) {
11+
"use strict";
12+
var __moduleName = context_1 && context_1.id;
13+
return {
14+
setters: [],
15+
execute: function () {
16+
;
17+
if (context_1.meta.foo) {
18+
context_1.meta.foo();
19+
}
20+
}
21+
};
22+
});

0 commit comments

Comments
 (0)