Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow literan enum const assertions #30700

Merged
merged 3 commits into from Apr 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -21725,6 +21725,13 @@ namespace ts {
const arg = (<PrefixUnaryExpression>node).operand;
return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) ||
op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
const expr = (<PropertyAccessExpression | ElementAccessExpression>node).expression;
if (isIdentifier(expr)) {
const symbol = getSymbolAtLocation(expr);
return !!(symbol && (symbol.flags & SymbolFlags.Enum) && getEnumKind(symbol) === EnumKind.Literal);
}
}
return false;
}
Expand All @@ -21733,7 +21740,7 @@ namespace ts {
let exprType = checkExpression(expression, checkMode);
if (isConstTypeReference(type)) {
if (!isValidConstAssertionArgument(expression)) {
error(expression, Diagnostics.A_const_assertion_can_only_be_applied_to_a_string_number_boolean_array_or_object_literal);
error(expression, Diagnostics.A_const_assertion_can_only_be_applied_to_a_string_number_boolean_array_literal_enum_or_object_literal);
}
return getRegularTypeOfLiteralType(exprType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/diagnosticMessages.json
Expand Up @@ -1023,7 +1023,7 @@
"category": "Error",
"code": 1354
},
"A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.": {
"A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "enum member" instead of "literal enum"? I don't think most people would think of A.b as a "literal" of some kind, much as we often treat it like one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about "member of literal enum"? "enum member" is also weird and cannot explain that why some enum cannot be used

BTW: Honestly, I don't know the kind of enum before.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paging @DanielRosenwasser for error message wording

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.

"category": "Error",
"code": 1355
},
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/constAssertions.errors.txt
@@ -1,7 +1,7 @@
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(44,32): error TS2540: Cannot assign to 'x' because it is a read-only property.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(61,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(62,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(63,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(61,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(62,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.
tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(63,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.


==== tests/cases/conformance/expressions/typeAssertions/constAssertions.ts (4 errors) ====
Expand Down Expand Up @@ -69,11 +69,11 @@ tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(63,10): er

let e1 = v1 as const; // Error
~~
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.
let e2 = (true ? 1 : 0) as const; // Error
~~~~~~~~~~~~~~
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.
let e3 = id(1) as const; // Error
~~~~~
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.

59 changes: 59 additions & 0 deletions tests/baselines/reference/constantEnumAssert.errors.txt
@@ -0,0 +1,59 @@
tests/cases/compiler/constantEnumAssert.ts(45,20): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.
tests/cases/compiler/constantEnumAssert.ts(49,20): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.


==== tests/cases/compiler/constantEnumAssert.ts (2 errors) ====
enum E1 {
a,
b
}

enum E2 {
a = 'a',
b = 'b'
}

enum E3 {
a = 1,
b = a << 1,
c = a << 2,
}

const enum E4 {
a,
b
}

const E5 = {
a: 'a',
b: 'b'
}

const foo1 = { a: E1.a }

const foo2 = { a: E2.a }

const foo3 = { a: E1.a } as const

const foo4 = { a: E2.a } as const

const foo5 = { a: E3.a } as const

const foo6 = { a: E4.a } as const

const foo7 = { a: E5.a } as const

const foo8 = { a: E1.a as const }

const foo9 = { a: E2.a as const }

const foo10 = { a: E3.a as const }
~~~~
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.

const foo11 = { a: E4.a as const }

const foo12 = { a: E5.a as const }
~~~~
!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, literal enum, or object literal.

85 changes: 85 additions & 0 deletions tests/baselines/reference/constantEnumAssert.js
@@ -0,0 +1,85 @@
//// [constantEnumAssert.ts]
enum E1 {
a,
b
}

enum E2 {
a = 'a',
b = 'b'
}

enum E3 {
a = 1,
b = a << 1,
c = a << 2,
}

const enum E4 {
a,
b
}

const E5 = {
a: 'a',
b: 'b'
}

const foo1 = { a: E1.a }

const foo2 = { a: E2.a }

const foo3 = { a: E1.a } as const

const foo4 = { a: E2.a } as const

const foo5 = { a: E3.a } as const

const foo6 = { a: E4.a } as const

const foo7 = { a: E5.a } as const

const foo8 = { a: E1.a as const }

const foo9 = { a: E2.a as const }

const foo10 = { a: E3.a as const }

const foo11 = { a: E4.a as const }

const foo12 = { a: E5.a as const }


//// [constantEnumAssert.js]
var E1;
(function (E1) {
E1[E1["a"] = 0] = "a";
E1[E1["b"] = 1] = "b";
})(E1 || (E1 = {}));
var E2;
(function (E2) {
E2["a"] = "a";
E2["b"] = "b";
})(E2 || (E2 = {}));
var E3;
(function (E3) {
E3[E3["a"] = 1] = "a";
E3[E3["b"] = 2] = "b";
E3[E3["c"] = 4] = "c";
})(E3 || (E3 = {}));
var E5 = {
a: 'a',
b: 'b'
};
var foo1 = { a: E1.a };
var foo2 = { a: E2.a };
var foo3 = { a: E1.a };
var foo4 = { a: E2.a };
var foo5 = { a: E3.a };
var foo6 = { a: 0 /* a */ };
var foo7 = { a: E5.a };
var foo8 = { a: E1.a };
var foo9 = { a: E2.a };
var foo10 = { a: E3.a };
var foo11 = { a: 0 /* a */ };
var foo12 = { a: E5.a };
140 changes: 140 additions & 0 deletions tests/baselines/reference/constantEnumAssert.symbols
@@ -0,0 +1,140 @@
=== tests/cases/compiler/constantEnumAssert.ts ===
enum E1 {
>E1 : Symbol(E1, Decl(constantEnumAssert.ts, 0, 0))

a,
>a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))

b
>b : Symbol(E1.b, Decl(constantEnumAssert.ts, 1, 6))
}

enum E2 {
>E2 : Symbol(E2, Decl(constantEnumAssert.ts, 3, 1))

a = 'a',
>a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))

b = 'b'
>b : Symbol(E2.b, Decl(constantEnumAssert.ts, 6, 12))
}

enum E3 {
>E3 : Symbol(E3, Decl(constantEnumAssert.ts, 8, 1))

a = 1,
>a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))

b = a << 1,
>b : Symbol(E3.b, Decl(constantEnumAssert.ts, 11, 10))
>a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))

c = a << 2,
>c : Symbol(E3.c, Decl(constantEnumAssert.ts, 12, 15))
>a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))
}

const enum E4 {
>E4 : Symbol(E4, Decl(constantEnumAssert.ts, 14, 1))

a,
>a : Symbol(E4.a, Decl(constantEnumAssert.ts, 16, 15))

b
>b : Symbol(E4.b, Decl(constantEnumAssert.ts, 17, 6))
}

const E5 = {
>E5 : Symbol(E5, Decl(constantEnumAssert.ts, 21, 5))

a: 'a',
>a : Symbol(a, Decl(constantEnumAssert.ts, 21, 12))

b: 'b'
>b : Symbol(b, Decl(constantEnumAssert.ts, 22, 11))
}

const foo1 = { a: E1.a }
>foo1 : Symbol(foo1, Decl(constantEnumAssert.ts, 26, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 26, 14))
>E1.a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))
>E1 : Symbol(E1, Decl(constantEnumAssert.ts, 0, 0))
>a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))

const foo2 = { a: E2.a }
>foo2 : Symbol(foo2, Decl(constantEnumAssert.ts, 28, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 28, 14))
>E2.a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))
>E2 : Symbol(E2, Decl(constantEnumAssert.ts, 3, 1))
>a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))

const foo3 = { a: E1.a } as const
>foo3 : Symbol(foo3, Decl(constantEnumAssert.ts, 30, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 30, 14))
>E1.a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))
>E1 : Symbol(E1, Decl(constantEnumAssert.ts, 0, 0))
>a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))

const foo4 = { a: E2.a } as const
>foo4 : Symbol(foo4, Decl(constantEnumAssert.ts, 32, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 32, 14))
>E2.a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))
>E2 : Symbol(E2, Decl(constantEnumAssert.ts, 3, 1))
>a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))

const foo5 = { a: E3.a } as const
>foo5 : Symbol(foo5, Decl(constantEnumAssert.ts, 34, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 34, 14))
>E3.a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))
>E3 : Symbol(E3, Decl(constantEnumAssert.ts, 8, 1))
>a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))

const foo6 = { a: E4.a } as const
>foo6 : Symbol(foo6, Decl(constantEnumAssert.ts, 36, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 36, 14))
>E4.a : Symbol(E4.a, Decl(constantEnumAssert.ts, 16, 15))
>E4 : Symbol(E4, Decl(constantEnumAssert.ts, 14, 1))
>a : Symbol(E4.a, Decl(constantEnumAssert.ts, 16, 15))

const foo7 = { a: E5.a } as const
>foo7 : Symbol(foo7, Decl(constantEnumAssert.ts, 38, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 38, 14))
>E5.a : Symbol(a, Decl(constantEnumAssert.ts, 21, 12))
>E5 : Symbol(E5, Decl(constantEnumAssert.ts, 21, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 21, 12))

const foo8 = { a: E1.a as const }
>foo8 : Symbol(foo8, Decl(constantEnumAssert.ts, 40, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 40, 14))
>E1.a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))
>E1 : Symbol(E1, Decl(constantEnumAssert.ts, 0, 0))
>a : Symbol(E1.a, Decl(constantEnumAssert.ts, 0, 9))

const foo9 = { a: E2.a as const }
>foo9 : Symbol(foo9, Decl(constantEnumAssert.ts, 42, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 42, 14))
>E2.a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))
>E2 : Symbol(E2, Decl(constantEnumAssert.ts, 3, 1))
>a : Symbol(E2.a, Decl(constantEnumAssert.ts, 5, 9))

const foo10 = { a: E3.a as const }
>foo10 : Symbol(foo10, Decl(constantEnumAssert.ts, 44, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 44, 15))
>E3.a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))
>E3 : Symbol(E3, Decl(constantEnumAssert.ts, 8, 1))
>a : Symbol(E3.a, Decl(constantEnumAssert.ts, 10, 9))

const foo11 = { a: E4.a as const }
>foo11 : Symbol(foo11, Decl(constantEnumAssert.ts, 46, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 46, 15))
>E4.a : Symbol(E4.a, Decl(constantEnumAssert.ts, 16, 15))
>E4 : Symbol(E4, Decl(constantEnumAssert.ts, 14, 1))
>a : Symbol(E4.a, Decl(constantEnumAssert.ts, 16, 15))

const foo12 = { a: E5.a as const }
>foo12 : Symbol(foo12, Decl(constantEnumAssert.ts, 48, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 48, 15))
>E5.a : Symbol(a, Decl(constantEnumAssert.ts, 21, 12))
>E5 : Symbol(E5, Decl(constantEnumAssert.ts, 21, 5))
>a : Symbol(a, Decl(constantEnumAssert.ts, 21, 12))