Skip to content

Commit 3514184

Browse files
committed
Switch to parser-based expression usage calculation
1 parent 1044c5c commit 3514184

File tree

9 files changed

+318
-28
lines changed

9 files changed

+318
-28
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,12 +1865,7 @@ namespace ts {
18651865
}
18661866

18671867
function checkSymbolUsageInExpressionContext(symbol: Symbol, name: __String, useSite: Node) {
1868-
if (
1869-
!(useSite.flags & NodeFlags.Ambient) &&
1870-
!isPartOfTypeQuery(useSite) &&
1871-
!isPartOfPossiblyValidComputedPropertyNameExpression(useSite) &&
1872-
isExpressionNode(useSite)
1873-
) {
1868+
if (!(useSite.flags & (NodeFlags.Ambient | NodeFlags.InNonEmittingNode)) && useSite.parent.kind !== SyntaxKind.ExportSpecifier) {
18741869
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(symbol);
18751870
if (typeOnlyDeclaration) {
18761871
const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier

src/compiler/parser.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,7 +3362,10 @@ namespace ts {
33623362
function parseType(): TypeNode {
33633363
// The rules about 'yield' only apply to actual code/expression contexts. They don't
33643364
// apply to 'type' contexts. So we disable these parameters here before moving on.
3365-
return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker);
3365+
return doOutsideOfContext(
3366+
NodeFlags.TypeExcludesFlags,
3367+
() => doInsideOfContext(NodeFlags.InNonEmittingNode, parseTypeWorker)
3368+
);
33663369
}
33673370

33683371
function parseTypeWorker(noConditionalTypes?: boolean): TypeNode {
@@ -5658,6 +5661,10 @@ namespace ts {
56585661
return modifier.kind === SyntaxKind.DeclareKeyword;
56595662
}
56605663

5664+
function isAbstractModifier(modifier: Modifier) {
5665+
return modifier.kind === SyntaxKind.AbstractKeyword;
5666+
}
5667+
56615668
function parseDeclaration(): Statement {
56625669
const modifiers = lookAhead(() => (parseDecorators(), parseModifiers()));
56635670
// `parseListElement` attempted to get the reused node at this position,
@@ -5705,9 +5712,9 @@ namespace ts {
57055712
case SyntaxKind.ClassKeyword:
57065713
return parseClassDeclaration(<ClassDeclaration>node);
57075714
case SyntaxKind.InterfaceKeyword:
5708-
return parseInterfaceDeclaration(<InterfaceDeclaration>node);
5715+
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseInterfaceDeclaration(<InterfaceDeclaration>node));
57095716
case SyntaxKind.TypeKeyword:
5710-
return parseTypeAliasDeclaration(<TypeAliasDeclaration>node);
5717+
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseTypeAliasDeclaration(<TypeAliasDeclaration>node));
57115718
case SyntaxKind.EnumKeyword:
57125719
return parseEnumDeclaration(<EnumDeclaration>node);
57135720
case SyntaxKind.GlobalKeyword:
@@ -5946,7 +5953,13 @@ namespace ts {
59465953

59475954
function parsePropertyOrMethodDeclaration(node: PropertyDeclaration | MethodDeclaration): PropertyDeclaration | MethodDeclaration {
59485955
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
5949-
node.name = parsePropertyName();
5956+
if (node.modifiers && some(node.modifiers, isAbstractModifier)) {
5957+
node.name = doInsideOfContext(NodeFlags.InNonEmittingNode, parsePropertyName);
5958+
}
5959+
else {
5960+
node.name = parsePropertyName();
5961+
}
5962+
59505963
// Note: this is not legal as per the grammar. But we allow it in the parser and
59515964
// report an error in the grammar checker.
59525965
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
@@ -6383,23 +6396,35 @@ namespace ts {
63836396
(isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())
63846397
) {
63856398
isTypeOnly = true;
6386-
identifier = isIdentifier() ? parseIdentifier() : undefined;
6399+
identifier = isIdentifier() ? doInsideOfContext(NodeFlags.InNonEmittingNode, parseIdentifier) : undefined;
6400+
node.flags |= NodeFlags.InNonEmittingNode;
63876401
}
63886402

63896403
if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {
63906404
return parseImportEqualsDeclaration(<ImportEqualsDeclaration>node, identifier, isTypeOnly);
63916405
}
63926406

63936407
// Import statement
6408+
if (isTypeOnly) {
6409+
return doInsideOfContext(
6410+
NodeFlags.InNonEmittingNode,
6411+
() => parseImportDeclarationRest(node as ImportDeclaration, afterImportPos, identifier, isTypeOnly)
6412+
);
6413+
}
6414+
6415+
return parseImportDeclarationRest(node as ImportDeclaration, afterImportPos, identifier, isTypeOnly);
6416+
}
6417+
6418+
function parseImportDeclarationRest(node: ImportDeclaration, afterImportPos: number, name: Identifier | undefined, isTypeOnly: boolean): ImportDeclaration {
63946419
node.kind = SyntaxKind.ImportDeclaration;
63956420
// ImportDeclaration:
63966421
// import ImportClause from ModuleSpecifier ;
63976422
// import ModuleSpecifier;
6398-
if (identifier || // import id
6423+
if (name || // import id
63996424
token() === SyntaxKind.AsteriskToken || // import *
64006425
token() === SyntaxKind.OpenBraceToken // import {
64016426
) {
6402-
(<ImportDeclaration>node).importClause = parseImportClause(identifier, afterImportPos, isTypeOnly);
6427+
(<ImportDeclaration>node).importClause = parseImportClause(name, afterImportPos, isTypeOnly);
64036428
parseExpected(SyntaxKind.FromKeyword);
64046429
}
64056430

@@ -6562,6 +6587,13 @@ namespace ts {
65626587
function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration {
65636588
node.kind = SyntaxKind.ExportDeclaration;
65646589
node.isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
6590+
if (node.isTypeOnly) {
6591+
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseExportDeclarationWorker(node));
6592+
}
6593+
return parseExportDeclarationWorker(node);
6594+
}
6595+
6596+
function parseExportDeclarationWorker(node: ExportDeclaration): ExportDeclaration {
65656597
if (parseOptional(SyntaxKind.AsteriskToken)) {
65666598
if (parseOptional(SyntaxKind.AsKeyword)) {
65676599
node.exportClause = parseNamespaceExport();

src/compiler/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ namespace ts {
546546
ContainsThis = 1 << 7, // Interface contains references to "this"
547547
HasImplicitReturn = 1 << 8, // If function implicitly returns on one of codepaths (initialized by binding)
548548
HasExplicitReturn = 1 << 9, // If function has explicit reachable return on one of codepaths (initialized by binding)
549-
GlobalAugmentation = 1 << 10, // Set if module declaration is an augmentation for the global scope
549+
GlobalAugmentation = 1 << 10, // Set if module declaration is an augmentation for the global scope
550550
HasAsyncFunctions = 1 << 11, // If the file has async functions (initialized by binding)
551551
DisallowInContext = 1 << 12, // If node was parsed in a context where 'in-expressions' are not allowed
552552
YieldContext = 1 << 13, // If node was parsed in the 'yield' context created when parsing a generator
@@ -574,6 +574,7 @@ namespace ts {
574574
/* @internal */ InWithStatement = 1 << 24, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
575575
JsonFile = 1 << 25, // If node was parsed in a Json
576576
/* @internal */ TypeCached = 1 << 26, // If a type was cached for node at any point
577+
/* @internal */ InNonEmittingNode = 1 << 27, // If a node was in a context where expressions are never emitted: type queries, abstract members, computed property names of types.
577578

578579
BlockScoped = Let | Const,
579580

src/compiler/utilities.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,20 +1771,6 @@ namespace ts {
17711771
}
17721772
}
17731773

1774-
export function isPartOfTypeQuery(node: Node) {
1775-
while (node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.Identifier) {
1776-
node = node.parent;
1777-
}
1778-
return node.kind === SyntaxKind.TypeQuery;
1779-
}
1780-
1781-
export function isPartOfPossiblyValidComputedPropertyNameExpression(node: Node) {
1782-
while (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) {
1783-
node = node.parent;
1784-
}
1785-
return node.kind === SyntaxKind.ComputedPropertyName;
1786-
}
1787-
17881774
export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } {
17891775
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
17901776
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
tests/cases/conformance/externalModules/typeOnly/component.ts(12,4): error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
2+
tests/cases/conformance/externalModules/typeOnly/component.ts(16,4): error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
3+
tests/cases/conformance/externalModules/typeOnly/component.ts(20,4): error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
4+
tests/cases/conformance/externalModules/typeOnly/component.ts(24,4): error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
5+
6+
7+
==== tests/cases/conformance/externalModules/typeOnly/framework-hooks.ts (0 errors) ====
8+
export const onInit = Symbol("onInit");
9+
10+
==== tests/cases/conformance/externalModules/typeOnly/component.ts (4 errors) ====
11+
import type { onInit } from "./framework-hooks";
12+
13+
interface Component {
14+
[onInit]?(): void;
15+
}
16+
17+
type T = {
18+
[onInit]: any;
19+
}
20+
21+
const o = {
22+
[onInit]: 0 // Error
23+
~~~~~~
24+
!!! error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
25+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/component.ts:1:15: 'onInit' was imported here.
26+
};
27+
28+
class C {
29+
[onInit]: any; // Error (because class fields)
30+
~~~~~~
31+
!!! error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
32+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/component.ts:1:15: 'onInit' was imported here.
33+
}
34+
35+
class D {
36+
[onInit] = 0; // Error
37+
~~~~~~
38+
!!! error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
39+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/component.ts:1:15: 'onInit' was imported here.
40+
}
41+
42+
class E {
43+
[onInit]() {} // Error
44+
~~~~~~
45+
!!! error TS1361: 'onInit' cannot be used as a value because it was imported using 'import type'.
46+
!!! related TS1376 tests/cases/conformance/externalModules/typeOnly/component.ts:1:15: 'onInit' was imported here.
47+
}
48+
49+
abstract class F {
50+
abstract [onInit](): void;
51+
}
52+
53+
class G {
54+
declare [onInit]: any;
55+
}
56+
57+
declare class H {
58+
[onInit]: any;
59+
}
60+

tests/baselines/reference/computedPropertyName.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,59 @@ import type { onInit } from "./framework-hooks";
99
interface Component {
1010
[onInit]?(): void;
1111
}
12+
13+
type T = {
14+
[onInit]: any;
15+
}
16+
17+
const o = {
18+
[onInit]: 0 // Error
19+
};
20+
21+
class C {
22+
[onInit]: any; // Error (because class fields)
23+
}
24+
25+
class D {
26+
[onInit] = 0; // Error
27+
}
28+
29+
class E {
30+
[onInit]() {} // Error
31+
}
32+
33+
abstract class F {
34+
abstract [onInit](): void;
35+
}
36+
37+
class G {
38+
declare [onInit]: any;
39+
}
40+
41+
declare class H {
42+
[onInit]: any;
43+
}
1244

1345

1446
//// [framework-hooks.js]
1547
export const onInit = Symbol("onInit");
1648
//// [component.js]
49+
var _a;
50+
const o = {
51+
[onInit]: 0 // Error
52+
};
53+
class C {
54+
}
55+
class D {
56+
constructor() {
57+
this[_a] = 0; // Error
58+
}
59+
}
60+
_a = onInit;
61+
class E {
62+
[onInit]() { } // Error
63+
}
64+
class F {
65+
}
66+
class G {
67+
}

tests/baselines/reference/computedPropertyName.symbols

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,68 @@ interface Component {
1515
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
1616
}
1717

18+
type T = {
19+
>T : Symbol(T, Decl(component.ts, 4, 1))
20+
21+
[onInit]: any;
22+
>[onInit] : Symbol([onInit], Decl(component.ts, 6, 10))
23+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
24+
}
25+
26+
const o = {
27+
>o : Symbol(o, Decl(component.ts, 10, 5))
28+
29+
[onInit]: 0 // Error
30+
>[onInit] : Symbol([onInit], Decl(component.ts, 10, 11))
31+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
32+
33+
};
34+
35+
class C {
36+
>C : Symbol(C, Decl(component.ts, 12, 2))
37+
38+
[onInit]: any; // Error (because class fields)
39+
>[onInit] : Symbol(C[onInit], Decl(component.ts, 14, 9))
40+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
41+
}
42+
43+
class D {
44+
>D : Symbol(D, Decl(component.ts, 16, 1))
45+
46+
[onInit] = 0; // Error
47+
>[onInit] : Symbol(D[onInit], Decl(component.ts, 18, 9))
48+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
49+
}
50+
51+
class E {
52+
>E : Symbol(E, Decl(component.ts, 20, 1))
53+
54+
[onInit]() {} // Error
55+
>[onInit] : Symbol(E[onInit], Decl(component.ts, 22, 9))
56+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
57+
}
58+
59+
abstract class F {
60+
>F : Symbol(F, Decl(component.ts, 24, 1))
61+
62+
abstract [onInit](): void;
63+
>[onInit] : Symbol(F[onInit], Decl(component.ts, 26, 18))
64+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
65+
}
66+
67+
class G {
68+
>G : Symbol(G, Decl(component.ts, 28, 1))
69+
70+
declare [onInit]: any;
71+
>[onInit] : Symbol(G[onInit], Decl(component.ts, 30, 9))
72+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
73+
}
74+
75+
declare class H {
76+
>H : Symbol(H, Decl(component.ts, 32, 1))
77+
78+
[onInit]: any;
79+
>[onInit] : Symbol(H[onInit], Decl(component.ts, 34, 17))
80+
>onInit : Symbol(onInit, Decl(component.ts, 0, 13))
81+
}
82+

0 commit comments

Comments
 (0)