From c7d496c90a9de12d74785e620cb9231e6656af18 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Sat, 20 Apr 2019 01:45:01 +0300 Subject: [PATCH 01/10] Support template literals in enum declarations --- src/compiler/checker.ts | 8 +- ...stantMemberWithTemplateLiterals.errors.txt | 59 +++++++ .../enumConstantMemberWithTemplateLiterals.js | 85 ++++++++++ ...ConstantMemberWithTemplateLiterals.symbols | 102 ++++++++++++ ...umConstantMemberWithTemplateLiterals.types | 152 ++++++++++++++++++ ...mberWithTemplateLiteralsEmitDeclaration.js | 113 +++++++++++++ ...ithTemplateLiteralsEmitDeclaration.symbols | 88 ++++++++++ ...rWithTemplateLiteralsEmitDeclaration.types | 129 +++++++++++++++ .../enumConstantMemberWithTemplateLiterals.ts | 43 +++++ ...mberWithTemplateLiteralsEmitDeclaration.ts | 40 +++++ 10 files changed, 816 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiterals.errors.txt create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiterals.js create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiterals.symbols create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.js create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.symbols create mode 100644 tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.types create mode 100644 tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts create mode 100644 tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f3c1cfc43d16..ce6d6044b71f3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6599,7 +6599,7 @@ namespace ts { } function isStringConcatExpression(expr: Node): boolean { - if (expr.kind === SyntaxKind.StringLiteral) { + if (isStringLiteralLike(expr)) { return true; } else if (expr.kind === SyntaxKind.BinaryExpression) { @@ -6616,6 +6616,7 @@ namespace ts { switch (expr.kind) { case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: return true; case SyntaxKind.PrefixUnaryExpression: return (expr).operator === SyntaxKind.MinusToken && @@ -6638,7 +6639,7 @@ namespace ts { for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.EnumDeclaration) { for (const member of (declaration).members) { - if (member.initializer && member.initializer.kind === SyntaxKind.StringLiteral) { + if (member.initializer && isStringLiteralLike(member.initializer)) { return links.enumKind = EnumKind.Literal; } if (!isLiteralEnumMember(member)) { @@ -30232,7 +30233,8 @@ namespace ts { } break; case SyntaxKind.StringLiteral: - return (expr).text; + case SyntaxKind.NoSubstitutionTemplateLiteral: + return (expr).text; case SyntaxKind.NumericLiteral: checkGrammarNumericLiteral(expr); return +(expr).text; diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.errors.txt b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.errors.txt new file mode 100644 index 0000000000000..e07f2ae26e0e0 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.errors.txt @@ -0,0 +1,59 @@ +tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts(28,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts(29,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts(30,9): error TS2553: Computed values are not permitted in an enum with string valued members. +tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts(31,9): error TS2553: Computed values are not permitted in an enum with string valued members. + + +==== tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts (4 errors) ==== + enum T1 { + a = `1` + } + + enum T2 { + a = `1`, + b = "2", + c = 3 + } + + enum T3 { + a = `1` + `1` + } + + enum T4 { + a = `1`, + b = `1` + `1`, + c = `1` + "2", + d = "2" + `1`, + e = "2" + `1` + `1` + } + + enum T5 { + a = `1`, + b = `1` + `2`, + c = `1` + `2` + `3`, + d = 1, + e = `1` - `1`, + ~~~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + f = `1` + 1, + ~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + g = `1${"2"}3`, + ~~~~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + h = `1`.length + ~~~~~~~~~~ +!!! error TS2553: Computed values are not permitted in an enum with string valued members. + } + + enum T6 { + a = 1, + b = `12`.length + } + + declare enum T7 { + a = `1`, + b = `1` + `1`, + c = "2" + `1` + } + \ No newline at end of file diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.js b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.js new file mode 100644 index 0000000000000..ebce0721df9f1 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.js @@ -0,0 +1,85 @@ +//// [enumConstantMemberWithTemplateLiterals.ts] +enum T1 { + a = `1` +} + +enum T2 { + a = `1`, + b = "2", + c = 3 +} + +enum T3 { + a = `1` + `1` +} + +enum T4 { + a = `1`, + b = `1` + `1`, + c = `1` + "2", + d = "2" + `1`, + e = "2" + `1` + `1` +} + +enum T5 { + a = `1`, + b = `1` + `2`, + c = `1` + `2` + `3`, + d = 1, + e = `1` - `1`, + f = `1` + 1, + g = `1${"2"}3`, + h = `1`.length +} + +enum T6 { + a = 1, + b = `12`.length +} + +declare enum T7 { + a = `1`, + b = `1` + `1`, + c = "2" + `1` +} + + +//// [enumConstantMemberWithTemplateLiterals.js] +var T1; +(function (T1) { + T1["a"] = "1"; +})(T1 || (T1 = {})); +var T2; +(function (T2) { + T2["a"] = "1"; + T2["b"] = "2"; + T2[T2["c"] = 3] = "c"; +})(T2 || (T2 = {})); +var T3; +(function (T3) { + T3["a"] = "11"; +})(T3 || (T3 = {})); +var T4; +(function (T4) { + T4["a"] = "1"; + T4["b"] = "11"; + T4["c"] = "12"; + T4["d"] = "21"; + T4["e"] = "211"; +})(T4 || (T4 = {})); +var T5; +(function (T5) { + T5["a"] = "1"; + T5["b"] = "12"; + T5["c"] = "123"; + T5[T5["d"] = 1] = "d"; + T5[T5["e"] = 0] = "e"; + T5[T5["f"] = 0] = "f"; + T5[T5["g"] = 0] = "g"; + T5[T5["h"] = 0] = "h"; +})(T5 || (T5 = {})); +var T6; +(function (T6) { + T6[T6["a"] = 1] = "a"; + T6[T6["b"] = "12".length] = "b"; +})(T6 || (T6 = {})); diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.symbols b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.symbols new file mode 100644 index 0000000000000..ca16707dcb64d --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.symbols @@ -0,0 +1,102 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts === +enum T1 { +>T1 : Symbol(T1, Decl(enumConstantMemberWithTemplateLiterals.ts, 0, 0)) + + a = `1` +>a : Symbol(T1.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 0, 9)) +} + +enum T2 { +>T2 : Symbol(T2, Decl(enumConstantMemberWithTemplateLiterals.ts, 2, 1)) + + a = `1`, +>a : Symbol(T2.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 4, 9)) + + b = "2", +>b : Symbol(T2.b, Decl(enumConstantMemberWithTemplateLiterals.ts, 5, 12)) + + c = 3 +>c : Symbol(T2.c, Decl(enumConstantMemberWithTemplateLiterals.ts, 6, 12)) +} + +enum T3 { +>T3 : Symbol(T3, Decl(enumConstantMemberWithTemplateLiterals.ts, 8, 1)) + + a = `1` + `1` +>a : Symbol(T3.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 10, 9)) +} + +enum T4 { +>T4 : Symbol(T4, Decl(enumConstantMemberWithTemplateLiterals.ts, 12, 1)) + + a = `1`, +>a : Symbol(T4.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 14, 9)) + + b = `1` + `1`, +>b : Symbol(T4.b, Decl(enumConstantMemberWithTemplateLiterals.ts, 15, 12)) + + c = `1` + "2", +>c : Symbol(T4.c, Decl(enumConstantMemberWithTemplateLiterals.ts, 16, 18)) + + d = "2" + `1`, +>d : Symbol(T4.d, Decl(enumConstantMemberWithTemplateLiterals.ts, 17, 18)) + + e = "2" + `1` + `1` +>e : Symbol(T4.e, Decl(enumConstantMemberWithTemplateLiterals.ts, 18, 18)) +} + +enum T5 { +>T5 : Symbol(T5, Decl(enumConstantMemberWithTemplateLiterals.ts, 20, 1)) + + a = `1`, +>a : Symbol(T5.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 22, 9)) + + b = `1` + `2`, +>b : Symbol(T5.b, Decl(enumConstantMemberWithTemplateLiterals.ts, 23, 12)) + + c = `1` + `2` + `3`, +>c : Symbol(T5.c, Decl(enumConstantMemberWithTemplateLiterals.ts, 24, 18)) + + d = 1, +>d : Symbol(T5.d, Decl(enumConstantMemberWithTemplateLiterals.ts, 25, 24)) + + e = `1` - `1`, +>e : Symbol(T5.e, Decl(enumConstantMemberWithTemplateLiterals.ts, 26, 10)) + + f = `1` + 1, +>f : Symbol(T5.f, Decl(enumConstantMemberWithTemplateLiterals.ts, 27, 18)) + + g = `1${"2"}3`, +>g : Symbol(T5.g, Decl(enumConstantMemberWithTemplateLiterals.ts, 28, 16)) + + h = `1`.length +>h : Symbol(T5.h, Decl(enumConstantMemberWithTemplateLiterals.ts, 29, 19)) +>`1`.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + +enum T6 { +>T6 : Symbol(T6, Decl(enumConstantMemberWithTemplateLiterals.ts, 31, 1)) + + a = 1, +>a : Symbol(T6.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 33, 9)) + + b = `12`.length +>b : Symbol(T6.b, Decl(enumConstantMemberWithTemplateLiterals.ts, 34, 10)) +>`12`.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + +declare enum T7 { +>T7 : Symbol(T7, Decl(enumConstantMemberWithTemplateLiterals.ts, 36, 1)) + + a = `1`, +>a : Symbol(T7.a, Decl(enumConstantMemberWithTemplateLiterals.ts, 38, 17)) + + b = `1` + `1`, +>b : Symbol(T7.b, Decl(enumConstantMemberWithTemplateLiterals.ts, 39, 12)) + + c = "2" + `1` +>c : Symbol(T7.c, Decl(enumConstantMemberWithTemplateLiterals.ts, 40, 18)) +} + diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types new file mode 100644 index 0000000000000..b750b8e8ab444 --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiterals.types @@ -0,0 +1,152 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts === +enum T1 { +>T1 : T1 + + a = `1` +>a : T1.a +>`1` : "1" +} + +enum T2 { +>T2 : T2 + + a = `1`, +>a : T2.a +>`1` : "1" + + b = "2", +>b : T2.b +>"2" : "2" + + c = 3 +>c : T2.c +>3 : 3 +} + +enum T3 { +>T3 : T3 + + a = `1` + `1` +>a : T3.a +>`1` + `1` : string +>`1` : "1" +>`1` : "1" +} + +enum T4 { +>T4 : T4 + + a = `1`, +>a : T4.a +>`1` : "1" + + b = `1` + `1`, +>b : T4.b +>`1` + `1` : string +>`1` : "1" +>`1` : "1" + + c = `1` + "2", +>c : T4.c +>`1` + "2" : string +>`1` : "1" +>"2" : "2" + + d = "2" + `1`, +>d : T4.d +>"2" + `1` : string +>"2" : "2" +>`1` : "1" + + e = "2" + `1` + `1` +>e : T4.e +>"2" + `1` + `1` : string +>"2" + `1` : string +>"2" : "2" +>`1` : "1" +>`1` : "1" +} + +enum T5 { +>T5 : T5 + + a = `1`, +>a : T5.a +>`1` : "1" + + b = `1` + `2`, +>b : T5.b +>`1` + `2` : string +>`1` : "1" +>`2` : "2" + + c = `1` + `2` + `3`, +>c : T5.c +>`1` + `2` + `3` : string +>`1` + `2` : string +>`1` : "1" +>`2` : "2" +>`3` : "3" + + d = 1, +>d : T5.d +>1 : 1 + + e = `1` - `1`, +>e : T5.e +>`1` - `1` : number +>`1` : "1" +>`1` : "1" + + f = `1` + 1, +>f : T5.e +>`1` + 1 : string +>`1` : "1" +>1 : 1 + + g = `1${"2"}3`, +>g : T5.e +>`1${"2"}3` : string +>"2" : "2" + + h = `1`.length +>h : T5.e +>`1`.length : number +>`1` : "1" +>length : number +} + +enum T6 { +>T6 : T6 + + a = 1, +>a : T6 +>1 : 1 + + b = `12`.length +>b : T6 +>`12`.length : number +>`12` : "12" +>length : number +} + +declare enum T7 { +>T7 : T7 + + a = `1`, +>a : T7.a +>`1` : "1" + + b = `1` + `1`, +>b : T7.b +>`1` + `1` : string +>`1` : "1" +>`1` : "1" + + c = "2" + `1` +>c : T7.c +>"2" + `1` : string +>"2" : "2" +>`1` : "1" +} + diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.js b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.js new file mode 100644 index 0000000000000..64e93dd62318f --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.js @@ -0,0 +1,113 @@ +//// [enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts] +enum T1 { + a = `1` +} + +enum T2 { + a = `1`, + b = "2", + c = 3 +} + +enum T3 { + a = `1` + `1` +} + +enum T4 { + a = `1`, + b = `1` + `1`, + c = `1` + "2", + d = "2" + `1`, + e = "2" + `1` + `1` +} + +enum T5 { + a = `1`, + b = `1` + `2`, + c = `1` + `2` + `3`, + d = 1 +} + +enum T6 { + a = 1, + b = `12`.length +} + +declare enum T7 { + a = `1`, + b = `1` + `1`, + c = "2" + `1` +} + + +//// [enumConstantMemberWithTemplateLiteralsEmitDeclaration.js] +var T1; +(function (T1) { + T1["a"] = "1"; +})(T1 || (T1 = {})); +var T2; +(function (T2) { + T2["a"] = "1"; + T2["b"] = "2"; + T2[T2["c"] = 3] = "c"; +})(T2 || (T2 = {})); +var T3; +(function (T3) { + T3["a"] = "11"; +})(T3 || (T3 = {})); +var T4; +(function (T4) { + T4["a"] = "1"; + T4["b"] = "11"; + T4["c"] = "12"; + T4["d"] = "21"; + T4["e"] = "211"; +})(T4 || (T4 = {})); +var T5; +(function (T5) { + T5["a"] = "1"; + T5["b"] = "12"; + T5["c"] = "123"; + T5[T5["d"] = 1] = "d"; +})(T5 || (T5 = {})); +var T6; +(function (T6) { + T6[T6["a"] = 1] = "a"; + T6[T6["b"] = "12".length] = "b"; +})(T6 || (T6 = {})); + + +//// [enumConstantMemberWithTemplateLiteralsEmitDeclaration.d.ts] +declare enum T1 { + a = "1" +} +declare enum T2 { + a = "1", + b = "2", + c = 3 +} +declare enum T3 { + a = "11" +} +declare enum T4 { + a = "1", + b = "11", + c = "12", + d = "21", + e = "211" +} +declare enum T5 { + a = "1", + b = "12", + c = "123", + d = 1 +} +declare enum T6 { + a = 1, + b +} +declare enum T7 { + a = "1", + b = "11", + c = "21" +} diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.symbols b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.symbols new file mode 100644 index 0000000000000..c1a8f52f005ad --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.symbols @@ -0,0 +1,88 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts === +enum T1 { +>T1 : Symbol(T1, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 0, 0)) + + a = `1` +>a : Symbol(T1.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 0, 9)) +} + +enum T2 { +>T2 : Symbol(T2, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 2, 1)) + + a = `1`, +>a : Symbol(T2.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 4, 9)) + + b = "2", +>b : Symbol(T2.b, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 5, 12)) + + c = 3 +>c : Symbol(T2.c, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 6, 12)) +} + +enum T3 { +>T3 : Symbol(T3, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 8, 1)) + + a = `1` + `1` +>a : Symbol(T3.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 10, 9)) +} + +enum T4 { +>T4 : Symbol(T4, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 12, 1)) + + a = `1`, +>a : Symbol(T4.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 14, 9)) + + b = `1` + `1`, +>b : Symbol(T4.b, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 15, 12)) + + c = `1` + "2", +>c : Symbol(T4.c, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 16, 18)) + + d = "2" + `1`, +>d : Symbol(T4.d, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 17, 18)) + + e = "2" + `1` + `1` +>e : Symbol(T4.e, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 18, 18)) +} + +enum T5 { +>T5 : Symbol(T5, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 20, 1)) + + a = `1`, +>a : Symbol(T5.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 22, 9)) + + b = `1` + `2`, +>b : Symbol(T5.b, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 23, 12)) + + c = `1` + `2` + `3`, +>c : Symbol(T5.c, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 24, 18)) + + d = 1 +>d : Symbol(T5.d, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 25, 24)) +} + +enum T6 { +>T6 : Symbol(T6, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 27, 1)) + + a = 1, +>a : Symbol(T6.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 29, 9)) + + b = `12`.length +>b : Symbol(T6.b, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 30, 10)) +>`12`.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +} + +declare enum T7 { +>T7 : Symbol(T7, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 32, 1)) + + a = `1`, +>a : Symbol(T7.a, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 34, 17)) + + b = `1` + `1`, +>b : Symbol(T7.b, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 35, 12)) + + c = "2" + `1` +>c : Symbol(T7.c, Decl(enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts, 36, 18)) +} + diff --git a/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.types b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.types new file mode 100644 index 0000000000000..78111d51aff6e --- /dev/null +++ b/tests/baselines/reference/enumConstantMemberWithTemplateLiteralsEmitDeclaration.types @@ -0,0 +1,129 @@ +=== tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts === +enum T1 { +>T1 : T1 + + a = `1` +>a : T1.a +>`1` : "1" +} + +enum T2 { +>T2 : T2 + + a = `1`, +>a : T2.a +>`1` : "1" + + b = "2", +>b : T2.b +>"2" : "2" + + c = 3 +>c : T2.c +>3 : 3 +} + +enum T3 { +>T3 : T3 + + a = `1` + `1` +>a : T3.a +>`1` + `1` : string +>`1` : "1" +>`1` : "1" +} + +enum T4 { +>T4 : T4 + + a = `1`, +>a : T4.a +>`1` : "1" + + b = `1` + `1`, +>b : T4.b +>`1` + `1` : string +>`1` : "1" +>`1` : "1" + + c = `1` + "2", +>c : T4.c +>`1` + "2" : string +>`1` : "1" +>"2" : "2" + + d = "2" + `1`, +>d : T4.d +>"2" + `1` : string +>"2" : "2" +>`1` : "1" + + e = "2" + `1` + `1` +>e : T4.e +>"2" + `1` + `1` : string +>"2" + `1` : string +>"2" : "2" +>`1` : "1" +>`1` : "1" +} + +enum T5 { +>T5 : T5 + + a = `1`, +>a : T5.a +>`1` : "1" + + b = `1` + `2`, +>b : T5.b +>`1` + `2` : string +>`1` : "1" +>`2` : "2" + + c = `1` + `2` + `3`, +>c : T5.c +>`1` + `2` + `3` : string +>`1` + `2` : string +>`1` : "1" +>`2` : "2" +>`3` : "3" + + d = 1 +>d : T5.d +>1 : 1 +} + +enum T6 { +>T6 : T6 + + a = 1, +>a : T6 +>1 : 1 + + b = `12`.length +>b : T6 +>`12`.length : number +>`12` : "12" +>length : number +} + +declare enum T7 { +>T7 : T7 + + a = `1`, +>a : T7.a +>`1` : "1" + + b = `1` + `1`, +>b : T7.b +>`1` + `1` : string +>`1` : "1" +>`1` : "1" + + c = "2" + `1` +>c : T7.c +>"2" + `1` : string +>"2" : "2" +>`1` : "1" +} + diff --git a/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts b/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts new file mode 100644 index 0000000000000..f76cf3f20f7d9 --- /dev/null +++ b/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiterals.ts @@ -0,0 +1,43 @@ +enum T1 { + a = `1` +} + +enum T2 { + a = `1`, + b = "2", + c = 3 +} + +enum T3 { + a = `1` + `1` +} + +enum T4 { + a = `1`, + b = `1` + `1`, + c = `1` + "2", + d = "2" + `1`, + e = "2" + `1` + `1` +} + +enum T5 { + a = `1`, + b = `1` + `2`, + c = `1` + `2` + `3`, + d = 1, + e = `1` - `1`, + f = `1` + 1, + g = `1${"2"}3`, + h = `1`.length +} + +enum T6 { + a = 1, + b = `12`.length +} + +declare enum T7 { + a = `1`, + b = `1` + `1`, + c = "2" + `1` +} diff --git a/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts b/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts new file mode 100644 index 0000000000000..ddd4e3e3d826f --- /dev/null +++ b/tests/cases/conformance/enums/enumConstantMemberWithTemplateLiteralsEmitDeclaration.ts @@ -0,0 +1,40 @@ +// @declaration: true +enum T1 { + a = `1` +} + +enum T2 { + a = `1`, + b = "2", + c = 3 +} + +enum T3 { + a = `1` + `1` +} + +enum T4 { + a = `1`, + b = `1` + `1`, + c = `1` + "2", + d = "2" + `1`, + e = "2" + `1` + `1` +} + +enum T5 { + a = `1`, + b = `1` + `2`, + c = `1` + `2` + `3`, + d = 1 +} + +enum T6 { + a = 1, + b = `12`.length +} + +declare enum T7 { + a = `1`, + b = `1` + `1`, + c = "2" + `1` +} From e906e39133f34751c0fd68e19ebe479f66e6e8f5 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Thu, 25 Jul 2019 23:30:49 +0300 Subject: [PATCH 02/10] Support template literals in const enum access --- src/compiler/checker.ts | 4 +- src/compiler/transformers/ts.ts | 7 +- .../reference/constEnumErrors.errors.txt | 18 +- tests/baselines/reference/constEnumErrors.js | 4 +- .../reference/constEnumErrors.symbols | 55 ++-- .../baselines/reference/constEnumErrors.types | 9 +- .../constEnumSyntheticNodesComments.js | 36 ++ .../constEnumSyntheticNodesComments.symbols | 60 ++++ .../constEnumSyntheticNodesComments.types | 64 ++++ tests/baselines/reference/constEnums.js | 6 +- tests/baselines/reference/constEnums.symbols | 307 +++++++++--------- tests/baselines/reference/constEnums.types | 26 +- tests/cases/compiler/constEnumErrors.ts | 3 +- .../constEnumSyntheticNodesComments.ts | 18 + tests/cases/compiler/constEnums.ts | 4 +- 15 files changed, 429 insertions(+), 192 deletions(-) create mode 100644 tests/baselines/reference/constEnumSyntheticNodesComments.js create mode 100644 tests/baselines/reference/constEnumSyntheticNodesComments.symbols create mode 100644 tests/baselines/reference/constEnumSyntheticNodesComments.types create mode 100644 tests/cases/compiler/constEnumSyntheticNodesComments.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce6d6044b71f3..c6b35684f4e5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21557,7 +21557,7 @@ namespace ts { return objectType; } - if (isConstEnumObjectType(objectType) && indexExpression.kind !== SyntaxKind.StringLiteral) { + if (isConstEnumObjectType(objectType) && !isStringLiteralLike(indexExpression)) { error(indexExpression, Diagnostics.A_const_enum_member_can_only_be_accessed_using_a_string_literal); return errorType; } @@ -30287,7 +30287,7 @@ namespace ts { return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression && isConstantMemberAccess((node).expression) || node.kind === SyntaxKind.ElementAccessExpression && isConstantMemberAccess((node).expression) && - (node).argumentExpression.kind === SyntaxKind.StringLiteral; + isStringLiteralLike((node).argumentExpression); } function checkEnumDeclaration(node: EnumDeclaration) { diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 06b3fb53ec180..8bc226a47e136 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -3249,9 +3249,10 @@ namespace ts { const substitute = createLiteral(constantValue); if (!compilerOptions.removeComments) { - const propertyName = isPropertyAccessExpression(node) - ? declarationNameToString(node.name) - : getTextOfNode(node.argumentExpression); + const originalNode = getOriginalNode(node, isAccessExpression); + const propertyName = isPropertyAccessExpression(originalNode) + ? declarationNameToString(originalNode.name) + : getTextOfNode(originalNode.argumentExpression); addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${propertyName} `); } diff --git a/tests/baselines/reference/constEnumErrors.errors.txt b/tests/baselines/reference/constEnumErrors.errors.txt index 0d278197c9bf5..abfd41c6faa7c 100644 --- a/tests/baselines/reference/constEnumErrors.errors.txt +++ b/tests/baselines/reference/constEnumErrors.errors.txt @@ -5,15 +5,16 @@ tests/cases/compiler/constEnumErrors.ts(14,9): error TS2474: const enum member i tests/cases/compiler/constEnumErrors.ts(15,10): error TS2474: const enum member initializers can only contain literal values and other computed enum values. tests/cases/compiler/constEnumErrors.ts(22,13): error TS2476: A const enum member can only be accessed using a string literal. tests/cases/compiler/constEnumErrors.ts(24,13): error TS2476: A const enum member can only be accessed using a string literal. -tests/cases/compiler/constEnumErrors.ts(26,9): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. -tests/cases/compiler/constEnumErrors.ts(27,10): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. -tests/cases/compiler/constEnumErrors.ts(32,5): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. -tests/cases/compiler/constEnumErrors.ts(40,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/compiler/constEnumErrors.ts(25,13): error TS2476: A const enum member can only be accessed using a string literal. +tests/cases/compiler/constEnumErrors.ts(27,9): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. +tests/cases/compiler/constEnumErrors.ts(28,10): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. +tests/cases/compiler/constEnumErrors.ts(33,5): error TS2475: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. tests/cases/compiler/constEnumErrors.ts(41,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. -tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. +tests/cases/compiler/constEnumErrors.ts(42,9): error TS2477: 'const' enum member initializer was evaluated to a non-finite value. +tests/cases/compiler/constEnumErrors.ts(43,9): error TS2478: 'const' enum member initializer was evaluated to disallowed value 'NaN'. -==== tests/cases/compiler/constEnumErrors.ts (13 errors) ==== +==== tests/cases/compiler/constEnumErrors.ts (14 errors) ==== const enum E { ~ !!! error TS2567: Enum declarations can only merge with namespace or other enum declarations. @@ -29,7 +30,7 @@ tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member const enum E1 { // illegal case // forward reference to the element of the same enum - X = Y, + X = Y, ~ !!! error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums. // forward reference to the element of the same enum @@ -52,6 +53,9 @@ tests/cases/compiler/constEnumErrors.ts(42,9): error TS2478: 'const' enum member var y1 = E2[name]; ~~~~ !!! error TS2476: A const enum member can only be accessed using a string literal. + var y2 = E2[`${name}`]; + ~~~~~~~~~ +!!! error TS2476: A const enum member can only be accessed using a string literal. var x = E2; ~~ diff --git a/tests/baselines/reference/constEnumErrors.js b/tests/baselines/reference/constEnumErrors.js index 4afd98982f014..3614059d62942 100644 --- a/tests/baselines/reference/constEnumErrors.js +++ b/tests/baselines/reference/constEnumErrors.js @@ -10,7 +10,7 @@ module E { const enum E1 { // illegal case // forward reference to the element of the same enum - X = Y, + X = Y, // forward reference to the element of the same enum Y = E1.Z, Y1 = E1["Z"] @@ -23,6 +23,7 @@ const enum E2 { var y0 = E2[1] var name = "A"; var y1 = E2[name]; +var y2 = E2[`${name}`]; var x = E2; var y = [E2]; @@ -51,6 +52,7 @@ var E; var y0 = E2[1]; var name = "A"; var y1 = E2[name]; +var y2 = E2["" + name]; var x = E2; var y = [E2]; function foo(t) { diff --git a/tests/baselines/reference/constEnumErrors.symbols b/tests/baselines/reference/constEnumErrors.symbols index 727cecb67551e..d3d37e379ef5c 100644 --- a/tests/baselines/reference/constEnumErrors.symbols +++ b/tests/baselines/reference/constEnumErrors.symbols @@ -18,7 +18,7 @@ const enum E1 { // illegal case // forward reference to the element of the same enum - X = Y, + X = Y, >X : Symbol(E1.X, Decl(constEnumErrors.ts, 8, 15)) >Y : Symbol(E1.Y, Decl(constEnumErrors.ts, 11, 10)) @@ -51,57 +51,62 @@ var y1 = E2[name]; >E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1)) >name : Symbol(name, Decl(constEnumErrors.ts, 22, 3)) +var y2 = E2[`${name}`]; +>y2 : Symbol(y2, Decl(constEnumErrors.ts, 24, 3)) +>E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1)) +>name : Symbol(name, Decl(constEnumErrors.ts, 22, 3)) + var x = E2; ->x : Symbol(x, Decl(constEnumErrors.ts, 25, 3)) +>x : Symbol(x, Decl(constEnumErrors.ts, 26, 3)) >E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1)) var y = [E2]; ->y : Symbol(y, Decl(constEnumErrors.ts, 26, 3)) +>y : Symbol(y, Decl(constEnumErrors.ts, 27, 3)) >E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1)) function foo(t: any): void { ->foo : Symbol(foo, Decl(constEnumErrors.ts, 26, 13)) ->t : Symbol(t, Decl(constEnumErrors.ts, 28, 13)) +>foo : Symbol(foo, Decl(constEnumErrors.ts, 27, 13)) +>t : Symbol(t, Decl(constEnumErrors.ts, 29, 13)) } foo(E2); ->foo : Symbol(foo, Decl(constEnumErrors.ts, 26, 13)) +>foo : Symbol(foo, Decl(constEnumErrors.ts, 27, 13)) >E2 : Symbol(E2, Decl(constEnumErrors.ts, 15, 1)) const enum NaNOrInfinity { ->NaNOrInfinity : Symbol(NaNOrInfinity, Decl(constEnumErrors.ts, 31, 8)) +>NaNOrInfinity : Symbol(NaNOrInfinity, Decl(constEnumErrors.ts, 32, 8)) A = 9007199254740992, ->A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26)) +>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26)) B = A * A, ->B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25)) ->A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26)) ->A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 33, 26)) +>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25)) +>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26)) +>A : Symbol(NaNOrInfinity.A, Decl(constEnumErrors.ts, 34, 26)) C = B * B, ->C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14)) ->B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25)) ->B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 34, 25)) +>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14)) +>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25)) +>B : Symbol(NaNOrInfinity.B, Decl(constEnumErrors.ts, 35, 25)) D = C * C, ->D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14)) ->C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14)) ->C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 35, 14)) +>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14)) +>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14)) +>C : Symbol(NaNOrInfinity.C, Decl(constEnumErrors.ts, 36, 14)) E = D * D, ->E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14)) ->D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14)) ->D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 36, 14)) +>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14)) +>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14)) +>D : Symbol(NaNOrInfinity.D, Decl(constEnumErrors.ts, 37, 14)) F = E * E, // overflow ->F : Symbol(NaNOrInfinity.F, Decl(constEnumErrors.ts, 38, 14)) ->E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14)) ->E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 37, 14)) +>F : Symbol(NaNOrInfinity.F, Decl(constEnumErrors.ts, 39, 14)) +>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14)) +>E : Symbol(NaNOrInfinity.E, Decl(constEnumErrors.ts, 38, 14)) G = 1 / 0, // overflow ->G : Symbol(NaNOrInfinity.G, Decl(constEnumErrors.ts, 39, 14)) +>G : Symbol(NaNOrInfinity.G, Decl(constEnumErrors.ts, 40, 14)) H = 0 / 0 // NaN ->H : Symbol(NaNOrInfinity.H, Decl(constEnumErrors.ts, 40, 14)) +>H : Symbol(NaNOrInfinity.H, Decl(constEnumErrors.ts, 41, 14)) } diff --git a/tests/baselines/reference/constEnumErrors.types b/tests/baselines/reference/constEnumErrors.types index f0ebb60815c32..d2d65e3196877 100644 --- a/tests/baselines/reference/constEnumErrors.types +++ b/tests/baselines/reference/constEnumErrors.types @@ -19,7 +19,7 @@ const enum E1 { // illegal case // forward reference to the element of the same enum - X = Y, + X = Y, >X : E1 >Y : E1 @@ -60,6 +60,13 @@ var y1 = E2[name]; >E2 : typeof E2 >name : string +var y2 = E2[`${name}`]; +>y2 : any +>E2[`${name}`] : any +>E2 : typeof E2 +>`${name}` : string +>name : string + var x = E2; >x : typeof E2 >E2 : typeof E2 diff --git a/tests/baselines/reference/constEnumSyntheticNodesComments.js b/tests/baselines/reference/constEnumSyntheticNodesComments.js new file mode 100644 index 0000000000000..511b5127e5a76 --- /dev/null +++ b/tests/baselines/reference/constEnumSyntheticNodesComments.js @@ -0,0 +1,36 @@ +//// [constEnumSyntheticNodesComments.ts] +const enum En { A, B, C, D } + +function assert(x: T) { + return x; +} + +function verify(a: En) { + switch (a) { + case En.A: + return assert<0>(a); + case En["B"]: + return assert<1>(a); + case En[`C`]: + return assert<2>(a); + case En["\u{44}"]: + return assert<3>(a); + } +} + +//// [constEnumSyntheticNodesComments.js] +function assert(x) { + return x; +} +function verify(a) { + switch (a) { + case 0 /* A */: + return assert(a); + case 1 /* "B" */: + return assert(a); + case 2 /* `C` */: + return assert(a); + case 3 /* "\u{44}" */: + return assert(a); + } +} diff --git a/tests/baselines/reference/constEnumSyntheticNodesComments.symbols b/tests/baselines/reference/constEnumSyntheticNodesComments.symbols new file mode 100644 index 0000000000000..cfd2e9bf75b9d --- /dev/null +++ b/tests/baselines/reference/constEnumSyntheticNodesComments.symbols @@ -0,0 +1,60 @@ +=== tests/cases/compiler/constEnumSyntheticNodesComments.ts === +const enum En { A, B, C, D } +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) +>A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15)) +>B : Symbol(En.B, Decl(constEnumSyntheticNodesComments.ts, 0, 18)) +>C : Symbol(En.C, Decl(constEnumSyntheticNodesComments.ts, 0, 21)) +>D : Symbol(En.D, Decl(constEnumSyntheticNodesComments.ts, 0, 24)) + +function assert(x: T) { +>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28)) +>T : Symbol(T, Decl(constEnumSyntheticNodesComments.ts, 2, 16)) +>x : Symbol(x, Decl(constEnumSyntheticNodesComments.ts, 2, 19)) +>T : Symbol(T, Decl(constEnumSyntheticNodesComments.ts, 2, 16)) + + return x; +>x : Symbol(x, Decl(constEnumSyntheticNodesComments.ts, 2, 19)) +} + +function verify(a: En) { +>verify : Symbol(verify, Decl(constEnumSyntheticNodesComments.ts, 4, 1)) +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) + + switch (a) { +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) + + case En.A: +>En.A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15)) +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) +>A : Symbol(En.A, Decl(constEnumSyntheticNodesComments.ts, 0, 15)) + + return assert<0>(a); +>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28)) +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) + + case En["B"]: +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) +>"B" : Symbol(En.B, Decl(constEnumSyntheticNodesComments.ts, 0, 18)) + + return assert<1>(a); +>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28)) +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) + + case En[`C`]: +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) +>`C` : Symbol(En.C, Decl(constEnumSyntheticNodesComments.ts, 0, 21)) + + return assert<2>(a); +>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28)) +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) + + case En["\u{44}"]: +>En : Symbol(En, Decl(constEnumSyntheticNodesComments.ts, 0, 0)) +>"\u{44}" : Symbol(En.D, Decl(constEnumSyntheticNodesComments.ts, 0, 24)) + + return assert<3>(a); +>assert : Symbol(assert, Decl(constEnumSyntheticNodesComments.ts, 0, 28)) +>a : Symbol(a, Decl(constEnumSyntheticNodesComments.ts, 6, 16)) + } +} diff --git a/tests/baselines/reference/constEnumSyntheticNodesComments.types b/tests/baselines/reference/constEnumSyntheticNodesComments.types new file mode 100644 index 0000000000000..c02880ffdb53b --- /dev/null +++ b/tests/baselines/reference/constEnumSyntheticNodesComments.types @@ -0,0 +1,64 @@ +=== tests/cases/compiler/constEnumSyntheticNodesComments.ts === +const enum En { A, B, C, D } +>En : En +>A : En.A +>B : En.B +>C : En.C +>D : En.D + +function assert(x: T) { +>assert : (x: T) => T +>x : T + + return x; +>x : T +} + +function verify(a: En) { +>verify : (a: En) => 0 | 1 | 2 | 3 +>a : En + + switch (a) { +>a : En + + case En.A: +>En.A : En.A +>En : typeof En +>A : En.A + + return assert<0>(a); +>assert<0>(a) : 0 +>assert : (x: T) => T +>a : En.A + + case En["B"]: +>En["B"] : En.B +>En : typeof En +>"B" : "B" + + return assert<1>(a); +>assert<1>(a) : 1 +>assert : (x: T) => T +>a : En.B + + case En[`C`]: +>En[`C`] : En.C +>En : typeof En +>`C` : "C" + + return assert<2>(a); +>assert<2>(a) : 2 +>assert : (x: T) => T +>a : En.C + + case En["\u{44}"]: +>En["\u{44}"] : En.D +>En : typeof En +>"\u{44}" : "D" + + return assert<3>(a); +>assert<3>(a) : 3 +>assert : (x: T) => T +>a : En.D + } +} diff --git a/tests/baselines/reference/constEnums.js b/tests/baselines/reference/constEnums.js index 893872b410082..dc48951f7f57f 100644 --- a/tests/baselines/reference/constEnums.js +++ b/tests/baselines/reference/constEnums.js @@ -35,6 +35,7 @@ const enum Enum1 { W2 = Enum1.A0, W3 = Enum1["A0"], W4 = Enum1["W"], + W5 = Enum1[`V`], } @@ -54,6 +55,7 @@ module A { export module C { export const enum E { V3 = A.B.C.E["V2"] & 200, + V4 = A.B.C.E[`V1`] << 1, } } } @@ -134,7 +136,7 @@ function foo(x: Enum1) { case Enum1.R: case Enum1.S: case Enum1["T"]: - case Enum1.U: + case Enum1[`U`]: case Enum1.V: case Enum1.W: case Enum1.W1: @@ -207,7 +209,7 @@ function foo(x) { case 0 /* R */: case 0 /* S */: case 11 /* "T" */: - case 11 /* U */: + case 11 /* `U` */: case 11 /* V */: case 11 /* W */: case 100 /* W1 */: diff --git a/tests/baselines/reference/constEnums.symbols b/tests/baselines/reference/constEnums.symbols index 0046d08f37d4e..0f0536734a044 100644 --- a/tests/baselines/reference/constEnums.symbols +++ b/tests/baselines/reference/constEnums.symbols @@ -128,220 +128,236 @@ const enum Enum1 { >W4 : Symbol(Enum1.W4, Decl(constEnums.ts, 34, 21)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) >"W" : Symbol(Enum1.W, Decl(constEnums.ts, 28, 15)) + + W5 = Enum1[`V`], +>W5 : Symbol(Enum1.W5, Decl(constEnums.ts, 35, 20)) +>Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) +>`V` : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) } module A { ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) V1 = 1, ->V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) V2 = A.B.C.E.V1 | 100 ->V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) ->A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) ->A.B.C.E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->A.B.C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->A.B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) +>A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) +>A.B.C.E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) } } } } module A { ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) +>B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) +>C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) V3 = A.B.C.E["V2"] & 200, ->V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) ->A.B.C.E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->A.B.C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->A.B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(E, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->"V2" : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>V3 : Symbol(I.V3, Decl(constEnums.ts, 54, 33)) +>A.B.C.E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>"V2" : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) + + V4 = A.B.C.E[`V1`] << 1, +>V4 : Symbol(I.V4, Decl(constEnums.ts, 55, 41)) +>A.B.C.E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(E, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>`V1` : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) } } } } module A1 { ->A1 : Symbol(A1, Decl(constEnums.ts, 58, 1)) +>A1 : Symbol(A1, Decl(constEnums.ts, 60, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 60, 11)) +>B : Symbol(B, Decl(constEnums.ts, 62, 11)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 61, 21)) +>C : Symbol(C, Decl(constEnums.ts, 63, 21)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 62, 25)) +>E : Symbol(E, Decl(constEnums.ts, 64, 25)) V1 = 10, ->V1 : Symbol(E.V1, Decl(constEnums.ts, 63, 33)) +>V1 : Symbol(E.V1, Decl(constEnums.ts, 65, 33)) V2 = 110, ->V2 : Symbol(E.V2, Decl(constEnums.ts, 64, 24)) +>V2 : Symbol(E.V2, Decl(constEnums.ts, 66, 24)) } } } } module A2 { ->A2 : Symbol(A2, Decl(constEnums.ts, 69, 1)) +>A2 : Symbol(A2, Decl(constEnums.ts, 71, 1)) export module B { ->B : Symbol(B, Decl(constEnums.ts, 71, 11)) +>B : Symbol(B, Decl(constEnums.ts, 73, 11)) export module C { ->C : Symbol(C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>C : Symbol(C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) export const enum E { ->E : Symbol(E, Decl(constEnums.ts, 73, 25)) +>E : Symbol(E, Decl(constEnums.ts, 75, 25)) V1 = 10, ->V1 : Symbol(E.V1, Decl(constEnums.ts, 74, 33)) +>V1 : Symbol(E.V1, Decl(constEnums.ts, 76, 33)) V2 = 110, ->V2 : Symbol(E.V2, Decl(constEnums.ts, 75, 24)) +>V2 : Symbol(E.V2, Decl(constEnums.ts, 77, 24)) } } // module C will be classified as value export module C { ->C : Symbol(C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) +>C : Symbol(C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) var x = 1 ->x : Symbol(x, Decl(constEnums.ts, 81, 15)) +>x : Symbol(x, Decl(constEnums.ts, 83, 15)) } } } import I = A.B.C.E; ->I : Symbol(I, Decl(constEnums.ts, 84, 1)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>I : Symbol(I, Decl(constEnums.ts, 86, 1)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) import I1 = A1.B; ->I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) ->A1 : Symbol(A1, Decl(constEnums.ts, 58, 1)) ->B : Symbol(I1, Decl(constEnums.ts, 60, 11)) +>I1 : Symbol(I1, Decl(constEnums.ts, 88, 19)) +>A1 : Symbol(A1, Decl(constEnums.ts, 60, 1)) +>B : Symbol(I1, Decl(constEnums.ts, 62, 11)) import I2 = A2.B; ->I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) ->A2 : Symbol(A2, Decl(constEnums.ts, 69, 1)) ->B : Symbol(I2, Decl(constEnums.ts, 71, 11)) +>I2 : Symbol(I2, Decl(constEnums.ts, 89, 17)) +>A2 : Symbol(A2, Decl(constEnums.ts, 71, 1)) +>B : Symbol(I2, Decl(constEnums.ts, 73, 11)) function foo0(e: I): void { ->foo0 : Symbol(foo0, Decl(constEnums.ts, 88, 17)) ->e : Symbol(e, Decl(constEnums.ts, 90, 14)) ->I : Symbol(I, Decl(constEnums.ts, 84, 1)) +>foo0 : Symbol(foo0, Decl(constEnums.ts, 90, 17)) +>e : Symbol(e, Decl(constEnums.ts, 92, 14)) +>I : Symbol(I, Decl(constEnums.ts, 86, 1)) if (e === I.V1) { ->e : Symbol(e, Decl(constEnums.ts, 90, 14)) ->I.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) ->I : Symbol(I, Decl(constEnums.ts, 84, 1)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>e : Symbol(e, Decl(constEnums.ts, 92, 14)) +>I.V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) +>I : Symbol(I, Decl(constEnums.ts, 86, 1)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) } else if (e === I.V2) { ->e : Symbol(e, Decl(constEnums.ts, 90, 14)) ->I.V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) ->I : Symbol(I, Decl(constEnums.ts, 84, 1)) ->V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>e : Symbol(e, Decl(constEnums.ts, 92, 14)) +>I.V2 : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) +>I : Symbol(I, Decl(constEnums.ts, 86, 1)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) } } function foo1(e: I1.C.E): void { ->foo1 : Symbol(foo1, Decl(constEnums.ts, 95, 1)) ->e : Symbol(e, Decl(constEnums.ts, 97, 14)) ->I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) +>foo1 : Symbol(foo1, Decl(constEnums.ts, 97, 1)) +>e : Symbol(e, Decl(constEnums.ts, 99, 14)) +>I1 : Symbol(I1, Decl(constEnums.ts, 88, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 63, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 64, 25)) if (e === I1.C.E.V1) { ->e : Symbol(e, Decl(constEnums.ts, 97, 14)) ->I1.C.E.V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 63, 33)) ->I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) ->I1.C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) ->I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) ->V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 63, 33)) +>e : Symbol(e, Decl(constEnums.ts, 99, 14)) +>I1.C.E.V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 65, 33)) +>I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 64, 25)) +>I1.C : Symbol(I1.C, Decl(constEnums.ts, 63, 21)) +>I1 : Symbol(I1, Decl(constEnums.ts, 88, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 63, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 64, 25)) +>V1 : Symbol(I1.C.E.V1, Decl(constEnums.ts, 65, 33)) } else if (e === I1.C.E.V2) { ->e : Symbol(e, Decl(constEnums.ts, 97, 14)) ->I1.C.E.V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 64, 24)) ->I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) ->I1.C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) ->I1 : Symbol(I1, Decl(constEnums.ts, 86, 19)) ->C : Symbol(I1.C, Decl(constEnums.ts, 61, 21)) ->E : Symbol(I1.C.E, Decl(constEnums.ts, 62, 25)) ->V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 64, 24)) +>e : Symbol(e, Decl(constEnums.ts, 99, 14)) +>I1.C.E.V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 66, 24)) +>I1.C.E : Symbol(I1.C.E, Decl(constEnums.ts, 64, 25)) +>I1.C : Symbol(I1.C, Decl(constEnums.ts, 63, 21)) +>I1 : Symbol(I1, Decl(constEnums.ts, 88, 19)) +>C : Symbol(I1.C, Decl(constEnums.ts, 63, 21)) +>E : Symbol(I1.C.E, Decl(constEnums.ts, 64, 25)) +>V2 : Symbol(I1.C.E.V2, Decl(constEnums.ts, 66, 24)) } } function foo2(e: I2.C.E): void { ->foo2 : Symbol(foo2, Decl(constEnums.ts, 102, 1)) ->e : Symbol(e, Decl(constEnums.ts, 104, 14)) ->I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) +>foo2 : Symbol(foo2, Decl(constEnums.ts, 104, 1)) +>e : Symbol(e, Decl(constEnums.ts, 106, 14)) +>I2 : Symbol(I2, Decl(constEnums.ts, 89, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 75, 25)) if (e === I2.C.E.V1) { ->e : Symbol(e, Decl(constEnums.ts, 104, 14)) ->I2.C.E.V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 74, 33)) ->I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) ->I2.C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) ->I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) ->V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 74, 33)) +>e : Symbol(e, Decl(constEnums.ts, 106, 14)) +>I2.C.E.V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 76, 33)) +>I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 75, 25)) +>I2.C : Symbol(I2.C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) +>I2 : Symbol(I2, Decl(constEnums.ts, 89, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 75, 25)) +>V1 : Symbol(I2.C.E.V1, Decl(constEnums.ts, 76, 33)) } else if (e === I2.C.E.V2) { ->e : Symbol(e, Decl(constEnums.ts, 104, 14)) ->I2.C.E.V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 75, 24)) ->I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) ->I2.C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) ->I2 : Symbol(I2, Decl(constEnums.ts, 87, 17)) ->C : Symbol(I2.C, Decl(constEnums.ts, 72, 21), Decl(constEnums.ts, 78, 9)) ->E : Symbol(I2.C.E, Decl(constEnums.ts, 73, 25)) ->V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 75, 24)) +>e : Symbol(e, Decl(constEnums.ts, 106, 14)) +>I2.C.E.V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 77, 24)) +>I2.C.E : Symbol(I2.C.E, Decl(constEnums.ts, 75, 25)) +>I2.C : Symbol(I2.C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) +>I2 : Symbol(I2, Decl(constEnums.ts, 89, 17)) +>C : Symbol(I2.C, Decl(constEnums.ts, 74, 21), Decl(constEnums.ts, 80, 9)) +>E : Symbol(I2.C.E, Decl(constEnums.ts, 75, 25)) +>V2 : Symbol(I2.C.E.V2, Decl(constEnums.ts, 77, 24)) } } function foo(x: Enum1) { ->foo : Symbol(foo, Decl(constEnums.ts, 109, 1)) ->x : Symbol(x, Decl(constEnums.ts, 112, 13)) +>foo : Symbol(foo, Decl(constEnums.ts, 111, 1)) +>x : Symbol(x, Decl(constEnums.ts, 114, 13)) >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) switch (x) { ->x : Symbol(x, Decl(constEnums.ts, 112, 13)) +>x : Symbol(x, Decl(constEnums.ts, 114, 13)) case Enum1.A: >Enum1.A : Symbol(Enum1.A, Decl(constEnums.ts, 4, 18)) @@ -447,10 +463,9 @@ function foo(x: Enum1) { >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) >"T" : Symbol(Enum1.T, Decl(constEnums.ts, 25, 14)) - case Enum1.U: ->Enum1.U : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) + case Enum1[`U`]: >Enum1 : Symbol(Enum1, Decl(constEnums.ts, 0, 0), Decl(constEnums.ts, 2, 1)) ->U : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) +>`U` : Symbol(Enum1.U, Decl(constEnums.ts, 26, 14)) case Enum1.V: >Enum1.V : Symbol(Enum1.V, Decl(constEnums.ts, 27, 14)) @@ -487,47 +502,47 @@ function foo(x: Enum1) { } function bar(e: A.B.C.E): number { ->bar : Symbol(bar, Decl(constEnums.ts, 144, 1)) ->e : Symbol(e, Decl(constEnums.ts, 146, 13)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) +>bar : Symbol(bar, Decl(constEnums.ts, 146, 1)) +>e : Symbol(e, Decl(constEnums.ts, 148, 13)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) switch (e) { ->e : Symbol(e, Decl(constEnums.ts, 146, 13)) +>e : Symbol(e, Decl(constEnums.ts, 148, 13)) case A.B.C.E.V1: return 1; ->A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->V1 : Symbol(I.V1, Decl(constEnums.ts, 42, 33)) +>A.B.C.E.V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>V1 : Symbol(I.V1, Decl(constEnums.ts, 43, 33)) case A.B.C.E.V2: return 1; ->A.B.C.E.V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->V2 : Symbol(I.V2, Decl(constEnums.ts, 43, 23)) +>A.B.C.E.V2 : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>V2 : Symbol(I.V2, Decl(constEnums.ts, 44, 23)) case A.B.C.E.V3: return 1; ->A.B.C.E.V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) ->A.B.C.E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->A.B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->A : Symbol(A, Decl(constEnums.ts, 36, 1), Decl(constEnums.ts, 48, 1)) ->B : Symbol(A.B, Decl(constEnums.ts, 39, 10), Decl(constEnums.ts, 50, 10)) ->C : Symbol(A.B.C, Decl(constEnums.ts, 40, 21), Decl(constEnums.ts, 51, 21)) ->E : Symbol(I, Decl(constEnums.ts, 41, 25), Decl(constEnums.ts, 52, 25)) ->V3 : Symbol(I.V3, Decl(constEnums.ts, 53, 33)) +>A.B.C.E.V3 : Symbol(I.V3, Decl(constEnums.ts, 54, 33)) +>A.B.C.E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>A.B.C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>A.B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>A : Symbol(A, Decl(constEnums.ts, 37, 1), Decl(constEnums.ts, 49, 1)) +>B : Symbol(A.B, Decl(constEnums.ts, 40, 10), Decl(constEnums.ts, 51, 10)) +>C : Symbol(A.B.C, Decl(constEnums.ts, 41, 21), Decl(constEnums.ts, 52, 21)) +>E : Symbol(I, Decl(constEnums.ts, 42, 25), Decl(constEnums.ts, 53, 25)) +>V3 : Symbol(I.V3, Decl(constEnums.ts, 54, 33)) } } diff --git a/tests/baselines/reference/constEnums.types b/tests/baselines/reference/constEnums.types index c85f5f3836ce0..fc3caf5514dab 100644 --- a/tests/baselines/reference/constEnums.types +++ b/tests/baselines/reference/constEnums.types @@ -172,6 +172,12 @@ const enum Enum1 { >Enum1["W"] : Enum1 >Enum1 : typeof Enum1 >"W" : "W" + + W5 = Enum1[`V`], +>W5 : Enum1 +>Enum1[`V`] : Enum1 +>Enum1 : typeof Enum1 +>`V` : "V" } @@ -222,6 +228,20 @@ module A { >E : typeof E >"V2" : "V2" >200 : 200 + + V4 = A.B.C.E[`V1`] << 1, +>V4 : E +>A.B.C.E[`V1`] << 1 : number +>A.B.C.E[`V1`] : E +>A.B.C.E : typeof E +>A.B.C : typeof C +>A.B : typeof B +>A : typeof A +>B : typeof B +>C : typeof C +>E : typeof E +>`V1` : "V1" +>1 : 1 } } } @@ -485,10 +505,10 @@ function foo(x: Enum1) { >Enum1 : typeof Enum1 >"T" : "T" - case Enum1.U: ->Enum1.U : Enum1 + case Enum1[`U`]: +>Enum1[`U`] : Enum1 >Enum1 : typeof Enum1 ->U : Enum1 +>`U` : "U" case Enum1.V: >Enum1.V : Enum1 diff --git a/tests/cases/compiler/constEnumErrors.ts b/tests/cases/compiler/constEnumErrors.ts index be45ed8363221..ca2289ef3bf33 100644 --- a/tests/cases/compiler/constEnumErrors.ts +++ b/tests/cases/compiler/constEnumErrors.ts @@ -10,7 +10,7 @@ module E { const enum E1 { // illegal case // forward reference to the element of the same enum - X = Y, + X = Y, // forward reference to the element of the same enum Y = E1.Z, Y1 = E1["Z"] @@ -23,6 +23,7 @@ const enum E2 { var y0 = E2[1] var name = "A"; var y1 = E2[name]; +var y2 = E2[`${name}`]; var x = E2; var y = [E2]; diff --git a/tests/cases/compiler/constEnumSyntheticNodesComments.ts b/tests/cases/compiler/constEnumSyntheticNodesComments.ts new file mode 100644 index 0000000000000..dfa66ed4679d4 --- /dev/null +++ b/tests/cases/compiler/constEnumSyntheticNodesComments.ts @@ -0,0 +1,18 @@ +const enum En { A, B, C, D } + +function assert(x: T) { + return x; +} + +function verify(a: En) { + switch (a) { + case En.A: + return assert<0>(a); + case En["B"]: + return assert<1>(a); + case En[`C`]: + return assert<2>(a); + case En["\u{44}"]: + return assert<3>(a); + } +} \ No newline at end of file diff --git a/tests/cases/compiler/constEnums.ts b/tests/cases/compiler/constEnums.ts index 617b89e2ba866..0b30fd8983135 100644 --- a/tests/cases/compiler/constEnums.ts +++ b/tests/cases/compiler/constEnums.ts @@ -34,6 +34,7 @@ const enum Enum1 { W2 = Enum1.A0, W3 = Enum1["A0"], W4 = Enum1["W"], + W5 = Enum1[`V`], } @@ -53,6 +54,7 @@ module A { export module C { export const enum E { V3 = A.B.C.E["V2"] & 200, + V4 = A.B.C.E[`V1`] << 1, } } } @@ -133,7 +135,7 @@ function foo(x: Enum1) { case Enum1.R: case Enum1.S: case Enum1["T"]: - case Enum1.U: + case Enum1[`U`]: case Enum1.V: case Enum1.W: case Enum1.W1: From 79ce806c9853e087c85b217565664e86224ac921 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Fri, 21 Jun 2019 01:05:25 +0300 Subject: [PATCH 03/10] Support template literals in swith with typeof narrowing --- src/compiler/checker.ts | 4 +- .../reference/narrowingByTypeofInSwitch.js | 118 +++++++++++- .../narrowingByTypeofInSwitch.symbols | 141 ++++++++++++++ .../reference/narrowingByTypeofInSwitch.types | 173 ++++++++++++++++++ .../compiler/narrowingByTypeofInSwitch.ts | 50 +++++ 5 files changed, 483 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c6b35684f4e5d..61ce0547f8f1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16989,8 +16989,8 @@ namespace ts { const witnesses: (string | undefined)[] = []; for (const clause of switchStatement.caseBlock.clauses) { if (clause.kind === SyntaxKind.CaseClause) { - if (clause.expression.kind === SyntaxKind.StringLiteral) { - witnesses.push((clause.expression as StringLiteral).text); + if (isStringLiteralLike(clause.expression)) { + witnesses.push(clause.expression.text); continue; } return emptyArray; diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.js b/tests/baselines/reference/narrowingByTypeofInSwitch.js index 2b99da05e1357..f2b4d26c56e54 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.js +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.js @@ -249,7 +249,56 @@ function narrowingNarrows(x: {} | undefined) { default: const _y: {} = x; return; } } - + +/* Template literals */ + +function testUnionWithTempalte(x: Basic) { + switch (typeof x) { + case `number`: assertNumber(x); return; + case `boolean`: assertBoolean(x); return; + case `function`: assertFunction(x); return; + case `symbol`: assertSymbol(x); return; + case `object`: assertObject(x); return; + case `string`: assertString(x); return; + case `undefined`: assertUndefined(x); return; + } + assertNever(x); +} + +function fallThroughTestWithTempalte(x: string | number | boolean | object) { + switch (typeof x) { + case `number`: + assertNumber(x) + case `string`: + assertStringOrNumber(x) + break; + default: + assertObject(x); + case `number`: + case `boolean`: + assertBooleanOrObject(x); + break; + } +} + +function keyofNarrowingWithTemplate(k: keyof S) { + function assertKeyofS(k1: keyof S) { } + switch (typeof k) { + case `number`: assertNumber(k); assertKeyofS(k); return; + case `symbol`: assertSymbol(k); assertKeyofS(k); return; + case `string`: assertString(k); assertKeyofS(k); return; + } +} + +/* Both string literals and template literals */ + +function multipleGenericFuseWithBoth(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] { + switch (typeof xy) { + case `function`: return [xy, 1]; + case 'object': return [xy, 'two']; + case `number`: return [xy] + } +} //// [narrowingByTypeofInSwitch.js] function assertNever(x) { @@ -585,3 +634,70 @@ function narrowingNarrows(x) { return; } } +/* Template literals */ +function testUnionWithTempalte(x) { + switch (typeof x) { + case "number": + assertNumber(x); + return; + case "boolean": + assertBoolean(x); + return; + case "function": + assertFunction(x); + return; + case "symbol": + assertSymbol(x); + return; + case "object": + assertObject(x); + return; + case "string": + assertString(x); + return; + case "undefined": + assertUndefined(x); + return; + } + assertNever(x); +} +function fallThroughTestWithTempalte(x) { + switch (typeof x) { + case "number": + assertNumber(x); + case "string": + assertStringOrNumber(x); + break; + default: + assertObject(x); + case "number": + case "boolean": + assertBooleanOrObject(x); + break; + } +} +function keyofNarrowingWithTemplate(k) { + function assertKeyofS(k1) { } + switch (typeof k) { + case "number": + assertNumber(k); + assertKeyofS(k); + return; + case "symbol": + assertSymbol(k); + assertKeyofS(k); + return; + case "string": + assertString(k); + assertKeyofS(k); + return; + } +} +/* Both string literals and template literals */ +function multipleGenericFuseWithBoth(xy) { + switch (typeof xy) { + case "function": return [xy, 1]; + case 'object': return [xy, 'two']; + case "number": return [xy]; + } +} diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.symbols b/tests/baselines/reference/narrowingByTypeofInSwitch.symbols index f1ff39725b39f..2feb98164ea6d 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.symbols +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.symbols @@ -715,3 +715,144 @@ function narrowingNarrows(x: {} | undefined) { } } +/* Template literals */ + +function testUnionWithTempalte(x: Basic) { +>testUnionWithTempalte : Symbol(testUnionWithTempalte, Decl(narrowingByTypeofInSwitch.ts, 249, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) +>Basic : Symbol(Basic, Decl(narrowingByTypeofInSwitch.ts, 46, 1)) + + switch (typeof x) { +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `number`: assertNumber(x); return; +>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `boolean`: assertBoolean(x); return; +>assertBoolean : Symbol(assertBoolean, Decl(narrowingByTypeofInSwitch.ts, 6, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `function`: assertFunction(x); return; +>assertFunction : Symbol(assertFunction, Decl(narrowingByTypeofInSwitch.ts, 18, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `symbol`: assertSymbol(x); return; +>assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `object`: assertObject(x); return; +>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `string`: assertString(x); return; +>assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + + case `undefined`: assertUndefined(x); return; +>assertUndefined : Symbol(assertUndefined, Decl(narrowingByTypeofInSwitch.ts, 30, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) + } + assertNever(x); +>assertNever : Symbol(assertNever, Decl(narrowingByTypeofInSwitch.ts, 0, 0)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 253, 31)) +} + +function fallThroughTestWithTempalte(x: string | number | boolean | object) { +>fallThroughTestWithTempalte : Symbol(fallThroughTestWithTempalte, Decl(narrowingByTypeofInSwitch.ts, 264, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + switch (typeof x) { +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + case `number`: + assertNumber(x) +>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + case `string`: + assertStringOrNumber(x) +>assertStringOrNumber : Symbol(assertStringOrNumber, Decl(narrowingByTypeofInSwitch.ts, 38, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + break; + default: + assertObject(x); +>assertObject : Symbol(assertObject, Decl(narrowingByTypeofInSwitch.ts, 22, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + case `number`: + case `boolean`: + assertBooleanOrObject(x); +>assertBooleanOrObject : Symbol(assertBooleanOrObject, Decl(narrowingByTypeofInSwitch.ts, 42, 1)) +>x : Symbol(x, Decl(narrowingByTypeofInSwitch.ts, 266, 37)) + + break; + } +} + +function keyofNarrowingWithTemplate(k: keyof S) { +>keyofNarrowingWithTemplate : Symbol(keyofNarrowingWithTemplate, Decl(narrowingByTypeofInSwitch.ts, 280, 1)) +>S : Symbol(S, Decl(narrowingByTypeofInSwitch.ts, 282, 36)) +>K : Symbol(K, Decl(narrowingByTypeofInSwitch.ts, 282, 49)) +>S : Symbol(S, Decl(narrowingByTypeofInSwitch.ts, 282, 36)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) +>S : Symbol(S, Decl(narrowingByTypeofInSwitch.ts, 282, 36)) + + function assertKeyofS(k1: keyof S) { } +>assertKeyofS : Symbol(assertKeyofS, Decl(narrowingByTypeofInSwitch.ts, 282, 87)) +>k1 : Symbol(k1, Decl(narrowingByTypeofInSwitch.ts, 283, 26)) +>S : Symbol(S, Decl(narrowingByTypeofInSwitch.ts, 282, 36)) + + switch (typeof k) { +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) + + case `number`: assertNumber(k); assertKeyofS(k); return; +>assertNumber : Symbol(assertNumber, Decl(narrowingByTypeofInSwitch.ts, 2, 1)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) +>assertKeyofS : Symbol(assertKeyofS, Decl(narrowingByTypeofInSwitch.ts, 282, 87)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) + + case `symbol`: assertSymbol(k); assertKeyofS(k); return; +>assertSymbol : Symbol(assertSymbol, Decl(narrowingByTypeofInSwitch.ts, 14, 1)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) +>assertKeyofS : Symbol(assertKeyofS, Decl(narrowingByTypeofInSwitch.ts, 282, 87)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) + + case `string`: assertString(k); assertKeyofS(k); return; +>assertString : Symbol(assertString, Decl(narrowingByTypeofInSwitch.ts, 10, 1)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) +>assertKeyofS : Symbol(assertKeyofS, Decl(narrowingByTypeofInSwitch.ts, 282, 87)) +>k : Symbol(k, Decl(narrowingByTypeofInSwitch.ts, 282, 74)) + } +} + +/* Both string literals and template literals */ + +function multipleGenericFuseWithBoth(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] { +>multipleGenericFuseWithBoth : Symbol(multipleGenericFuseWithBoth, Decl(narrowingByTypeofInSwitch.ts, 289, 1)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 293, 37)) +>L : Symbol(L, Decl(narrowingByTypeofInSwitch.ts, 132, 1)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 293, 58)) +>R : Symbol(R, Decl(narrowingByTypeofInSwitch.ts, 134, 31)) +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 293, 81)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 293, 37)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 293, 58)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 293, 37)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 293, 58)) +>X : Symbol(X, Decl(narrowingByTypeofInSwitch.ts, 293, 37)) +>Y : Symbol(Y, Decl(narrowingByTypeofInSwitch.ts, 293, 58)) + + switch (typeof xy) { +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 293, 81)) + + case `function`: return [xy, 1]; +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 293, 81)) + + case 'object': return [xy, 'two']; +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 293, 81)) + + case `number`: return [xy] +>xy : Symbol(xy, Decl(narrowingByTypeofInSwitch.ts, 293, 81)) + } +} diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index f823c57770c3a..616dae2922590 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -869,3 +869,176 @@ function narrowingNarrows(x: {} | undefined) { } } +/* Template literals */ + +function testUnionWithTempalte(x: Basic) { +>testUnionWithTempalte : (x: Basic) => void +>x : Basic + + switch (typeof x) { +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : Basic + + case `number`: assertNumber(x); return; +>`number` : "number" +>assertNumber(x) : number +>assertNumber : (x: number) => number +>x : number + + case `boolean`: assertBoolean(x); return; +>`boolean` : "boolean" +>assertBoolean(x) : boolean +>assertBoolean : (x: boolean) => boolean +>x : boolean + + case `function`: assertFunction(x); return; +>`function` : "function" +>assertFunction(x) : Function +>assertFunction : (x: Function) => Function +>x : Function + + case `symbol`: assertSymbol(x); return; +>`symbol` : "symbol" +>assertSymbol(x) : symbol +>assertSymbol : (x: symbol) => symbol +>x : symbol + + case `object`: assertObject(x); return; +>`object` : "object" +>assertObject(x) : object +>assertObject : (x: object) => object +>x : object + + case `string`: assertString(x); return; +>`string` : "string" +>assertString(x) : string +>assertString : (x: string) => string +>x : string + + case `undefined`: assertUndefined(x); return; +>`undefined` : "undefined" +>assertUndefined(x) : undefined +>assertUndefined : (x: undefined) => undefined +>x : undefined + } + assertNever(x); +>assertNever(x) : never +>assertNever : (x: never) => never +>x : never +} + +function fallThroughTestWithTempalte(x: string | number | boolean | object) { +>fallThroughTestWithTempalte : (x: string | number | boolean | object) => void +>x : string | number | boolean | object + + switch (typeof x) { +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number | boolean | object + + case `number`: +>`number` : "number" + + assertNumber(x) +>assertNumber(x) : number +>assertNumber : (x: number) => number +>x : number + + case `string`: +>`string` : "string" + + assertStringOrNumber(x) +>assertStringOrNumber(x) : string | number +>assertStringOrNumber : (x: string | number) => string | number +>x : string | number + + break; + default: + assertObject(x); +>assertObject(x) : object +>assertObject : (x: object) => object +>x : object + + case `number`: +>`number` : "number" + + case `boolean`: +>`boolean` : "boolean" + + assertBooleanOrObject(x); +>assertBooleanOrObject(x) : boolean | object +>assertBooleanOrObject : (x: boolean | object) => boolean | object +>x : boolean | object + + break; + } +} + +function keyofNarrowingWithTemplate(k: keyof S) { +>keyofNarrowingWithTemplate : (k: keyof S) => void +>k : keyof S + + function assertKeyofS(k1: keyof S) { } +>assertKeyofS : (k1: keyof S) => void +>k1 : keyof S + + switch (typeof k) { +>typeof k : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>k : keyof S + + case `number`: assertNumber(k); assertKeyofS(k); return; +>`number` : "number" +>assertNumber(k) : number +>assertNumber : (x: number) => number +>k : keyof S & number +>assertKeyofS(k) : void +>assertKeyofS : (k1: keyof S) => void +>k : keyof S & number + + case `symbol`: assertSymbol(k); assertKeyofS(k); return; +>`symbol` : "symbol" +>assertSymbol(k) : symbol +>assertSymbol : (x: symbol) => symbol +>k : keyof S & symbol +>assertKeyofS(k) : void +>assertKeyofS : (k1: keyof S) => void +>k : keyof S & symbol + + case `string`: assertString(k); assertKeyofS(k); return; +>`string` : "string" +>assertString(k) : string +>assertString : (x: string) => string +>k : keyof S & string +>assertKeyofS(k) : void +>assertKeyofS : (k1: keyof S) => void +>k : keyof S & string + } +} + +/* Both string literals and template literals */ + +function multipleGenericFuseWithBoth(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] { +>multipleGenericFuseWithBoth : (xy: X | Y) => [X, number] | [Y, string] | [X | Y] +>xy : X | Y + + switch (typeof xy) { +>typeof xy : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>xy : X | Y + + case `function`: return [xy, 1]; +>`function` : "function" +>[xy, 1] : [X, 1] +>xy : X +>1 : 1 + + case 'object': return [xy, 'two']; +>'object' : "object" +>[xy, 'two'] : [Y, string] +>xy : Y +>'two' : "two" + + case `number`: return [xy] +>`number` : "number" +>[xy] : [(X & number) | (Y & number)] +>xy : (X & number) | (Y & number) + } +} diff --git a/tests/cases/compiler/narrowingByTypeofInSwitch.ts b/tests/cases/compiler/narrowingByTypeofInSwitch.ts index 39f04168684d1..cd726827456e3 100644 --- a/tests/cases/compiler/narrowingByTypeofInSwitch.ts +++ b/tests/cases/compiler/narrowingByTypeofInSwitch.ts @@ -251,3 +251,53 @@ function narrowingNarrows(x: {} | undefined) { default: const _y: {} = x; return; } } + +/* Template literals */ + +function testUnionWithTempalte(x: Basic) { + switch (typeof x) { + case `number`: assertNumber(x); return; + case `boolean`: assertBoolean(x); return; + case `function`: assertFunction(x); return; + case `symbol`: assertSymbol(x); return; + case `object`: assertObject(x); return; + case `string`: assertString(x); return; + case `undefined`: assertUndefined(x); return; + } + assertNever(x); +} + +function fallThroughTestWithTempalte(x: string | number | boolean | object) { + switch (typeof x) { + case `number`: + assertNumber(x) + case `string`: + assertStringOrNumber(x) + break; + default: + assertObject(x); + case `number`: + case `boolean`: + assertBooleanOrObject(x); + break; + } +} + +function keyofNarrowingWithTemplate(k: keyof S) { + function assertKeyofS(k1: keyof S) { } + switch (typeof k) { + case `number`: assertNumber(k); assertKeyofS(k); return; + case `symbol`: assertSymbol(k); assertKeyofS(k); return; + case `string`: assertString(k); assertKeyofS(k); return; + } +} + +/* Both string literals and template literals */ + +function multipleGenericFuseWithBoth(xy: X | Y): [X, number] | [Y, string] | [(X | Y)] { + switch (typeof xy) { + case `function`: return [xy, 1]; + case 'object': return [xy, 'two']; + case `number`: return [xy] + } +} \ No newline at end of file From cc0a28c94dd43049996e9b5dfa699694d142aade Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Fri, 21 Jun 2019 04:34:56 +0300 Subject: [PATCH 04/10] Support template literals in element access discriminant --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 2 +- .../discriminantElementAccessCheck.js | 94 ++++++++++++ .../discriminantElementAccessCheck.symbols | 132 +++++++++++++++++ .../discriminantElementAccessCheck.types | 140 ++++++++++++++++++ .../discriminantElementAccessCheck.ts | 52 +++++++ 6 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/discriminantElementAccessCheck.js create mode 100644 tests/baselines/reference/discriminantElementAccessCheck.symbols create mode 100644 tests/baselines/reference/discriminantElementAccessCheck.types create mode 100644 tests/cases/compiler/discriminantElementAccessCheck.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1d6627987e151..d23141571f631 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -789,7 +789,7 @@ namespace ts { return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) || isElementAccessExpression(expr) && - (isStringLiteral(expr.argumentExpression) || isNumericLiteral(expr.argumentExpression)) && + isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 61ce0547f8f1b..c000d939322de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16591,7 +16591,7 @@ namespace ts { function getAccessedPropertyName(access: AccessExpression): __String | undefined { return access.kind === SyntaxKind.PropertyAccessExpression ? access.name.escapedText : - isStringLiteral(access.argumentExpression) || isNumericLiteral(access.argumentExpression) ? escapeLeadingUnderscores(access.argumentExpression.text) : + isStringOrNumericLiteralLike(access.argumentExpression) ? escapeLeadingUnderscores(access.argumentExpression.text) : undefined; } diff --git a/tests/baselines/reference/discriminantElementAccessCheck.js b/tests/baselines/reference/discriminantElementAccessCheck.js new file mode 100644 index 0000000000000..7501d007f1f4a --- /dev/null +++ b/tests/baselines/reference/discriminantElementAccessCheck.js @@ -0,0 +1,94 @@ +//// [discriminantElementAccessCheck.ts] +type U = TypeA | TypeB; + +interface TypeA { + kind: 'A'; + a: number; +} +interface TypeB { + kind: 'B'; + b: string; +} + +function assertNever(x: never) { + return x; +} + +function IfWithString(val: U) { + if (val['kind'] === 'B') { + return val.b; + } else { + return val.a; + } +} + +function SwitchWithString(val: U) { + switch (val['kind']) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} + +function IfWithTemplate(val: U) { + if (val[`kind`] === 'B') { + return val.b; + } else { + return val.a; + } +} + +function SwitchWithTemplate(val: U) { + switch (val[`kind`]) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} + +//// [discriminantElementAccessCheck.js] +function assertNever(x) { + return x; +} +function IfWithString(val) { + if (val['kind'] === 'B') { + return val.b; + } + else { + return val.a; + } +} +function SwitchWithString(val) { + switch (val['kind']) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} +function IfWithTemplate(val) { + if (val["kind"] === 'B') { + return val.b; + } + else { + return val.a; + } +} +function SwitchWithTemplate(val) { + switch (val["kind"]) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} diff --git a/tests/baselines/reference/discriminantElementAccessCheck.symbols b/tests/baselines/reference/discriminantElementAccessCheck.symbols new file mode 100644 index 0000000000000..e7e681861e6a0 --- /dev/null +++ b/tests/baselines/reference/discriminantElementAccessCheck.symbols @@ -0,0 +1,132 @@ +=== tests/cases/compiler/discriminantElementAccessCheck.ts === +type U = TypeA | TypeB; +>U : Symbol(U, Decl(discriminantElementAccessCheck.ts, 0, 0)) +>TypeA : Symbol(TypeA, Decl(discriminantElementAccessCheck.ts, 0, 23)) +>TypeB : Symbol(TypeB, Decl(discriminantElementAccessCheck.ts, 5, 1)) + +interface TypeA { +>TypeA : Symbol(TypeA, Decl(discriminantElementAccessCheck.ts, 0, 23)) + + kind: 'A'; +>kind : Symbol(TypeA.kind, Decl(discriminantElementAccessCheck.ts, 2, 17)) + + a: number; +>a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) +} +interface TypeB { +>TypeB : Symbol(TypeB, Decl(discriminantElementAccessCheck.ts, 5, 1)) + + kind: 'B'; +>kind : Symbol(TypeB.kind, Decl(discriminantElementAccessCheck.ts, 6, 17)) + + b: string; +>b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) +} + +function assertNever(x: never) { +>assertNever : Symbol(assertNever, Decl(discriminantElementAccessCheck.ts, 9, 1)) +>x : Symbol(x, Decl(discriminantElementAccessCheck.ts, 11, 21)) + + return x; +>x : Symbol(x, Decl(discriminantElementAccessCheck.ts, 11, 21)) +} + +function IfWithString(val: U) { +>IfWithString : Symbol(IfWithString, Decl(discriminantElementAccessCheck.ts, 13, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 15, 22)) +>U : Symbol(U, Decl(discriminantElementAccessCheck.ts, 0, 0)) + + if (val['kind'] === 'B') { +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 15, 22)) +>'kind' : Symbol(kind, Decl(discriminantElementAccessCheck.ts, 2, 17), Decl(discriminantElementAccessCheck.ts, 6, 17)) + + return val.b; +>val.b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 15, 22)) +>b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) + + } else { + return val.a; +>val.a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 15, 22)) +>a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) + } +} + +function SwitchWithString(val: U) { +>SwitchWithString : Symbol(SwitchWithString, Decl(discriminantElementAccessCheck.ts, 21, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 23, 26)) +>U : Symbol(U, Decl(discriminantElementAccessCheck.ts, 0, 0)) + + switch (val['kind']) { +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 23, 26)) +>'kind' : Symbol(kind, Decl(discriminantElementAccessCheck.ts, 2, 17), Decl(discriminantElementAccessCheck.ts, 6, 17)) + + case 'A': + return val.a; +>val.a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 23, 26)) +>a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) + + case 'B': + return val.b; +>val.b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 23, 26)) +>b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) + + default: + return assertNever(val); +>assertNever : Symbol(assertNever, Decl(discriminantElementAccessCheck.ts, 9, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 23, 26)) + } +} + +function IfWithTemplate(val: U) { +>IfWithTemplate : Symbol(IfWithTemplate, Decl(discriminantElementAccessCheck.ts, 32, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 34, 24)) +>U : Symbol(U, Decl(discriminantElementAccessCheck.ts, 0, 0)) + + if (val[`kind`] === 'B') { +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 34, 24)) +>`kind` : Symbol(kind, Decl(discriminantElementAccessCheck.ts, 2, 17), Decl(discriminantElementAccessCheck.ts, 6, 17)) + + return val.b; +>val.b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 34, 24)) +>b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) + + } else { + return val.a; +>val.a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 34, 24)) +>a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) + } +} + +function SwitchWithTemplate(val: U) { +>SwitchWithTemplate : Symbol(SwitchWithTemplate, Decl(discriminantElementAccessCheck.ts, 40, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 42, 28)) +>U : Symbol(U, Decl(discriminantElementAccessCheck.ts, 0, 0)) + + switch (val[`kind`]) { +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 42, 28)) +>`kind` : Symbol(kind, Decl(discriminantElementAccessCheck.ts, 2, 17), Decl(discriminantElementAccessCheck.ts, 6, 17)) + + case 'A': + return val.a; +>val.a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 42, 28)) +>a : Symbol(TypeA.a, Decl(discriminantElementAccessCheck.ts, 3, 14)) + + case 'B': + return val.b; +>val.b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 42, 28)) +>b : Symbol(TypeB.b, Decl(discriminantElementAccessCheck.ts, 7, 14)) + + default: + return assertNever(val); +>assertNever : Symbol(assertNever, Decl(discriminantElementAccessCheck.ts, 9, 1)) +>val : Symbol(val, Decl(discriminantElementAccessCheck.ts, 42, 28)) + } +} diff --git a/tests/baselines/reference/discriminantElementAccessCheck.types b/tests/baselines/reference/discriminantElementAccessCheck.types new file mode 100644 index 0000000000000..357173b8a0f40 --- /dev/null +++ b/tests/baselines/reference/discriminantElementAccessCheck.types @@ -0,0 +1,140 @@ +=== tests/cases/compiler/discriminantElementAccessCheck.ts === +type U = TypeA | TypeB; +>U : U + +interface TypeA { + kind: 'A'; +>kind : "A" + + a: number; +>a : number +} +interface TypeB { + kind: 'B'; +>kind : "B" + + b: string; +>b : string +} + +function assertNever(x: never) { +>assertNever : (x: never) => never +>x : never + + return x; +>x : never +} + +function IfWithString(val: U) { +>IfWithString : (val: U) => string | number +>val : U + + if (val['kind'] === 'B') { +>val['kind'] === 'B' : boolean +>val['kind'] : "A" | "B" +>val : U +>'kind' : "kind" +>'B' : "B" + + return val.b; +>val.b : string +>val : TypeB +>b : string + + } else { + return val.a; +>val.a : number +>val : TypeA +>a : number + } +} + +function SwitchWithString(val: U) { +>SwitchWithString : (val: U) => string | number +>val : U + + switch (val['kind']) { +>val['kind'] : "A" | "B" +>val : U +>'kind' : "kind" + + case 'A': +>'A' : "A" + + return val.a; +>val.a : number +>val : TypeA +>a : number + + case 'B': +>'B' : "B" + + return val.b; +>val.b : string +>val : TypeB +>b : string + + default: + return assertNever(val); +>assertNever(val) : never +>assertNever : (x: never) => never +>val : never + } +} + +function IfWithTemplate(val: U) { +>IfWithTemplate : (val: U) => string | number +>val : U + + if (val[`kind`] === 'B') { +>val[`kind`] === 'B' : boolean +>val[`kind`] : "A" | "B" +>val : U +>`kind` : "kind" +>'B' : "B" + + return val.b; +>val.b : string +>val : TypeB +>b : string + + } else { + return val.a; +>val.a : number +>val : TypeA +>a : number + } +} + +function SwitchWithTemplate(val: U) { +>SwitchWithTemplate : (val: U) => string | number +>val : U + + switch (val[`kind`]) { +>val[`kind`] : "A" | "B" +>val : U +>`kind` : "kind" + + case 'A': +>'A' : "A" + + return val.a; +>val.a : number +>val : TypeA +>a : number + + case 'B': +>'B' : "B" + + return val.b; +>val.b : string +>val : TypeB +>b : string + + default: + return assertNever(val); +>assertNever(val) : never +>assertNever : (x: never) => never +>val : never + } +} diff --git a/tests/cases/compiler/discriminantElementAccessCheck.ts b/tests/cases/compiler/discriminantElementAccessCheck.ts new file mode 100644 index 0000000000000..ded752f968892 --- /dev/null +++ b/tests/cases/compiler/discriminantElementAccessCheck.ts @@ -0,0 +1,52 @@ +type U = TypeA | TypeB; + +interface TypeA { + kind: 'A'; + a: number; +} +interface TypeB { + kind: 'B'; + b: string; +} + +function assertNever(x: never) { + return x; +} + +function IfWithString(val: U) { + if (val['kind'] === 'B') { + return val.b; + } else { + return val.a; + } +} + +function SwitchWithString(val: U) { + switch (val['kind']) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} + +function IfWithTemplate(val: U) { + if (val[`kind`] === 'B') { + return val.b; + } else { + return val.a; + } +} + +function SwitchWithTemplate(val: U) { + switch (val[`kind`]) { + case 'A': + return val.a; + case 'B': + return val.b; + default: + return assertNever(val); + } +} \ No newline at end of file From 8e80e4b3bb24e7c91da7161a9ef1235b2396d2fd Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Fri, 26 Jul 2019 00:19:36 +0300 Subject: [PATCH 05/10] Support template literals in ambient module declaration --- src/compiler/checker.ts | 2 +- .../ambientModuleWithTemplateLiterals.js | 28 ++++++++ .../ambientModuleWithTemplateLiterals.symbols | 65 +++++++++++++++++ .../ambientModuleWithTemplateLiterals.types | 72 +++++++++++++++++++ .../ambientModuleWithTemplateLiterals.ts | 20 ++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/ambientModuleWithTemplateLiterals.js create mode 100644 tests/baselines/reference/ambientModuleWithTemplateLiterals.symbols create mode 100644 tests/baselines/reference/ambientModuleWithTemplateLiterals.types create mode 100644 tests/cases/compiler/ambientModuleWithTemplateLiterals.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c000d939322de..6801f2076ef68 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33840,7 +33840,7 @@ namespace ts { } function isStringOrNumberLiteralExpression(expr: Expression) { - return expr.kind === SyntaxKind.StringLiteral || expr.kind === SyntaxKind.NumericLiteral || + return isStringOrNumericLiteralLike(expr) || expr.kind === SyntaxKind.PrefixUnaryExpression && (expr).operator === SyntaxKind.MinusToken && (expr).operand.kind === SyntaxKind.NumericLiteral; } diff --git a/tests/baselines/reference/ambientModuleWithTemplateLiterals.js b/tests/baselines/reference/ambientModuleWithTemplateLiterals.js new file mode 100644 index 0000000000000..e9c55fe7ca055 --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithTemplateLiterals.js @@ -0,0 +1,28 @@ +//// [ambientModuleWithTemplateLiterals.ts] +declare module Foo { + enum Bar { + a = `1`, + b = '2', + c = '3' + } + + export const a = 'string'; + export const b = `template`; + + export const c = Bar.a; + export const d = Bar['b']; + export const e = Bar[`c`]; +} + +Foo.a; +Foo.b; +Foo.c; +Foo.d; +Foo.e; + +//// [ambientModuleWithTemplateLiterals.js] +Foo.a; +Foo.b; +Foo.c; +Foo.d; +Foo.e; diff --git a/tests/baselines/reference/ambientModuleWithTemplateLiterals.symbols b/tests/baselines/reference/ambientModuleWithTemplateLiterals.symbols new file mode 100644 index 0000000000000..25086b1918e4c --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithTemplateLiterals.symbols @@ -0,0 +1,65 @@ +=== tests/cases/compiler/ambientModuleWithTemplateLiterals.ts === +declare module Foo { +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) + + enum Bar { +>Bar : Symbol(Bar, Decl(ambientModuleWithTemplateLiterals.ts, 0, 20)) + + a = `1`, +>a : Symbol(Bar.a, Decl(ambientModuleWithTemplateLiterals.ts, 1, 14)) + + b = '2', +>b : Symbol(Bar.b, Decl(ambientModuleWithTemplateLiterals.ts, 2, 16)) + + c = '3' +>c : Symbol(Bar.c, Decl(ambientModuleWithTemplateLiterals.ts, 3, 16)) + } + + export const a = 'string'; +>a : Symbol(a, Decl(ambientModuleWithTemplateLiterals.ts, 7, 16)) + + export const b = `template`; +>b : Symbol(b, Decl(ambientModuleWithTemplateLiterals.ts, 8, 16)) + + export const c = Bar.a; +>c : Symbol(c, Decl(ambientModuleWithTemplateLiterals.ts, 10, 16)) +>Bar.a : Symbol(Bar.a, Decl(ambientModuleWithTemplateLiterals.ts, 1, 14)) +>Bar : Symbol(Bar, Decl(ambientModuleWithTemplateLiterals.ts, 0, 20)) +>a : Symbol(Bar.a, Decl(ambientModuleWithTemplateLiterals.ts, 1, 14)) + + export const d = Bar['b']; +>d : Symbol(d, Decl(ambientModuleWithTemplateLiterals.ts, 11, 16)) +>Bar : Symbol(Bar, Decl(ambientModuleWithTemplateLiterals.ts, 0, 20)) +>'b' : Symbol(Bar.b, Decl(ambientModuleWithTemplateLiterals.ts, 2, 16)) + + export const e = Bar[`c`]; +>e : Symbol(e, Decl(ambientModuleWithTemplateLiterals.ts, 12, 16)) +>Bar : Symbol(Bar, Decl(ambientModuleWithTemplateLiterals.ts, 0, 20)) +>`c` : Symbol(Bar.c, Decl(ambientModuleWithTemplateLiterals.ts, 3, 16)) +} + +Foo.a; +>Foo.a : Symbol(Foo.a, Decl(ambientModuleWithTemplateLiterals.ts, 7, 16)) +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) +>a : Symbol(Foo.a, Decl(ambientModuleWithTemplateLiterals.ts, 7, 16)) + +Foo.b; +>Foo.b : Symbol(Foo.b, Decl(ambientModuleWithTemplateLiterals.ts, 8, 16)) +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) +>b : Symbol(Foo.b, Decl(ambientModuleWithTemplateLiterals.ts, 8, 16)) + +Foo.c; +>Foo.c : Symbol(Foo.c, Decl(ambientModuleWithTemplateLiterals.ts, 10, 16)) +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) +>c : Symbol(Foo.c, Decl(ambientModuleWithTemplateLiterals.ts, 10, 16)) + +Foo.d; +>Foo.d : Symbol(Foo.d, Decl(ambientModuleWithTemplateLiterals.ts, 11, 16)) +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) +>d : Symbol(Foo.d, Decl(ambientModuleWithTemplateLiterals.ts, 11, 16)) + +Foo.e; +>Foo.e : Symbol(Foo.e, Decl(ambientModuleWithTemplateLiterals.ts, 12, 16)) +>Foo : Symbol(Foo, Decl(ambientModuleWithTemplateLiterals.ts, 0, 0)) +>e : Symbol(Foo.e, Decl(ambientModuleWithTemplateLiterals.ts, 12, 16)) + diff --git a/tests/baselines/reference/ambientModuleWithTemplateLiterals.types b/tests/baselines/reference/ambientModuleWithTemplateLiterals.types new file mode 100644 index 0000000000000..05882261f2d0b --- /dev/null +++ b/tests/baselines/reference/ambientModuleWithTemplateLiterals.types @@ -0,0 +1,72 @@ +=== tests/cases/compiler/ambientModuleWithTemplateLiterals.ts === +declare module Foo { +>Foo : typeof Foo + + enum Bar { +>Bar : Bar + + a = `1`, +>a : Bar.a +>`1` : "1" + + b = '2', +>b : Bar.b +>'2' : "2" + + c = '3' +>c : Bar.c +>'3' : "3" + } + + export const a = 'string'; +>a : "string" +>'string' : "string" + + export const b = `template`; +>b : "template" +>`template` : "template" + + export const c = Bar.a; +>c : Bar.a +>Bar.a : Bar.a +>Bar : typeof Bar +>a : Bar.a + + export const d = Bar['b']; +>d : Bar.b +>Bar['b'] : Bar.b +>Bar : typeof Bar +>'b' : "b" + + export const e = Bar[`c`]; +>e : Bar.c +>Bar[`c`] : Bar.c +>Bar : typeof Bar +>`c` : "c" +} + +Foo.a; +>Foo.a : "string" +>Foo : typeof Foo +>a : "string" + +Foo.b; +>Foo.b : "template" +>Foo : typeof Foo +>b : "template" + +Foo.c; +>Foo.c : Foo.Bar.a +>Foo : typeof Foo +>c : Foo.Bar.a + +Foo.d; +>Foo.d : Foo.Bar.b +>Foo : typeof Foo +>d : Foo.Bar.b + +Foo.e; +>Foo.e : Foo.Bar.c +>Foo : typeof Foo +>e : Foo.Bar.c + diff --git a/tests/cases/compiler/ambientModuleWithTemplateLiterals.ts b/tests/cases/compiler/ambientModuleWithTemplateLiterals.ts new file mode 100644 index 0000000000000..74c1b29e52dce --- /dev/null +++ b/tests/cases/compiler/ambientModuleWithTemplateLiterals.ts @@ -0,0 +1,20 @@ +declare module Foo { + enum Bar { + a = `1`, + b = '2', + c = '3' + } + + export const a = 'string'; + export const b = `template`; + + export const c = Bar.a; + export const d = Bar['b']; + export const e = Bar[`c`]; +} + +Foo.a; +Foo.b; +Foo.c; +Foo.d; +Foo.e; \ No newline at end of file From 378032aa7df5930f4e57046db0ce40b3fa60dde0 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Mon, 24 Jun 2019 03:11:23 +0300 Subject: [PATCH 06/10] Unify symbols for template literals in computed properties --- src/compiler/utilities.ts | 2 +- tests/baselines/reference/computedPropertyNames10_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames10_ES6.symbols | 1 + tests/baselines/reference/computedPropertyNames11_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames11_ES6.symbols | 1 + tests/baselines/reference/computedPropertyNames12_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames12_ES6.symbols | 1 + tests/baselines/reference/computedPropertyNames13_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames13_ES6.symbols | 1 + tests/baselines/reference/computedPropertyNames16_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames16_ES6.symbols | 1 + tests/baselines/reference/computedPropertyNames4_ES5.symbols | 1 + tests/baselines/reference/computedPropertyNames4_ES6.symbols | 1 + .../computerPropertiesInES5ShouldBeTransformed.symbols | 1 + 14 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6b48cb80625ee..0fc04937673da 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2556,7 +2556,7 @@ namespace ts { } export function isLiteralComputedPropertyDeclarationName(node: Node) { - return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) && + return isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName && isDeclaration(node.parent.parent); } diff --git a/tests/baselines/reference/computedPropertyNames10_ES5.symbols b/tests/baselines/reference/computedPropertyNames10_ES5.symbols index a63bac47a2858..8a93cbac50846 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames10_ES5.symbols @@ -50,6 +50,7 @@ var v = { [`hello bye`]() { }, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames10_ES5.ts, 12, 22)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames10_ES5.ts, 12, 22)) [`hello ${a} bye`]() { } >[`hello ${a} bye`] : Symbol([`hello ${a} bye`], Decl(computedPropertyNames10_ES5.ts, 13, 24)) diff --git a/tests/baselines/reference/computedPropertyNames10_ES6.symbols b/tests/baselines/reference/computedPropertyNames10_ES6.symbols index bbfe8d3808da2..73a97d7c003dd 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames10_ES6.symbols @@ -50,6 +50,7 @@ var v = { [`hello bye`]() { }, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames10_ES6.ts, 12, 22)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames10_ES6.ts, 12, 22)) [`hello ${a} bye`]() { } >[`hello ${a} bye`] : Symbol([`hello ${a} bye`], Decl(computedPropertyNames10_ES6.ts, 13, 24)) diff --git a/tests/baselines/reference/computedPropertyNames11_ES5.symbols b/tests/baselines/reference/computedPropertyNames11_ES5.symbols index e1c7d7231f4fa..b030d727921e9 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames11_ES5.symbols @@ -54,6 +54,7 @@ var v = { set [`hello bye`](v) { }, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames11_ES5.ts, 12, 36)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames11_ES5.ts, 12, 36)) >v : Symbol(v, Decl(computedPropertyNames11_ES5.ts, 13, 22)) get [`hello ${a} bye`]() { return 0; } diff --git a/tests/baselines/reference/computedPropertyNames11_ES6.symbols b/tests/baselines/reference/computedPropertyNames11_ES6.symbols index fcd142feac68a..04273804fda27 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames11_ES6.symbols @@ -54,6 +54,7 @@ var v = { set [`hello bye`](v) { }, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames11_ES6.ts, 12, 36)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames11_ES6.ts, 12, 36)) >v : Symbol(v, Decl(computedPropertyNames11_ES6.ts, 13, 22)) get [`hello ${a} bye`]() { return 0; } diff --git a/tests/baselines/reference/computedPropertyNames12_ES5.symbols b/tests/baselines/reference/computedPropertyNames12_ES5.symbols index 40f5989b9c024..6746b115bedf5 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames12_ES5.symbols @@ -52,6 +52,7 @@ class C { [`hello bye`] = 0; >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames12_ES5.ts, 12, 31)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames12_ES5.ts, 12, 31)) static [`hello ${a} bye`] = 0 >[`hello ${a} bye`] : Symbol(C[`hello ${a} bye`], Decl(computedPropertyNames12_ES5.ts, 13, 22)) diff --git a/tests/baselines/reference/computedPropertyNames12_ES6.symbols b/tests/baselines/reference/computedPropertyNames12_ES6.symbols index 9ea89571d8267..8ab0d06f8f9f1 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames12_ES6.symbols @@ -52,6 +52,7 @@ class C { [`hello bye`] = 0; >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames12_ES6.ts, 12, 31)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames12_ES6.ts, 12, 31)) static [`hello ${a} bye`] = 0 >[`hello ${a} bye`] : Symbol(C[`hello ${a} bye`], Decl(computedPropertyNames12_ES6.ts, 13, 22)) diff --git a/tests/baselines/reference/computedPropertyNames13_ES5.symbols b/tests/baselines/reference/computedPropertyNames13_ES5.symbols index 4d80f861952ea..7df3db735a9fb 100644 --- a/tests/baselines/reference/computedPropertyNames13_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames13_ES5.symbols @@ -50,6 +50,7 @@ class C { [`hello bye`]() { } >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames13_ES5.ts, 12, 28)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames13_ES5.ts, 12, 28)) static [`hello ${a} bye`]() { } >[`hello ${a} bye`] : Symbol(C[`hello ${a} bye`], Decl(computedPropertyNames13_ES5.ts, 13, 23)) diff --git a/tests/baselines/reference/computedPropertyNames13_ES6.symbols b/tests/baselines/reference/computedPropertyNames13_ES6.symbols index 088522617a7ec..5da1dfd1705af 100644 --- a/tests/baselines/reference/computedPropertyNames13_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames13_ES6.symbols @@ -50,6 +50,7 @@ class C { [`hello bye`]() { } >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames13_ES6.ts, 12, 28)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames13_ES6.ts, 12, 28)) static [`hello ${a} bye`]() { } >[`hello ${a} bye`] : Symbol(C[`hello ${a} bye`], Decl(computedPropertyNames13_ES6.ts, 13, 23)) diff --git a/tests/baselines/reference/computedPropertyNames16_ES5.symbols b/tests/baselines/reference/computedPropertyNames16_ES5.symbols index 1099ece10012a..ffd0c0594a820 100644 --- a/tests/baselines/reference/computedPropertyNames16_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames16_ES5.symbols @@ -54,6 +54,7 @@ class C { set [`hello bye`](v) { } >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames16_ES5.ts, 12, 42)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames16_ES5.ts, 12, 42)) >v : Symbol(v, Decl(computedPropertyNames16_ES5.ts, 13, 22)) get [`hello ${a} bye`]() { return 0; } diff --git a/tests/baselines/reference/computedPropertyNames16_ES6.symbols b/tests/baselines/reference/computedPropertyNames16_ES6.symbols index 11511eb577460..09e585e3b98c7 100644 --- a/tests/baselines/reference/computedPropertyNames16_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames16_ES6.symbols @@ -54,6 +54,7 @@ class C { set [`hello bye`](v) { } >[`hello bye`] : Symbol(C[`hello bye`], Decl(computedPropertyNames16_ES6.ts, 12, 42)) +>`hello bye` : Symbol(C[`hello bye`], Decl(computedPropertyNames16_ES6.ts, 12, 42)) >v : Symbol(v, Decl(computedPropertyNames16_ES6.ts, 13, 22)) get [`hello ${a} bye`]() { return 0; } diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.symbols b/tests/baselines/reference/computedPropertyNames4_ES5.symbols index ccb9481831047..e321bf2e956ee 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.symbols +++ b/tests/baselines/reference/computedPropertyNames4_ES5.symbols @@ -52,6 +52,7 @@ var v = { [`hello bye`]: 0, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames4_ES5.ts, 12, 19)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames4_ES5.ts, 12, 19)) [`hello ${a} bye`]: 0 >[`hello ${a} bye`] : Symbol([`hello ${a} bye`], Decl(computedPropertyNames4_ES5.ts, 13, 21)) diff --git a/tests/baselines/reference/computedPropertyNames4_ES6.symbols b/tests/baselines/reference/computedPropertyNames4_ES6.symbols index aeb3e59789780..542e75218735d 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES6.symbols +++ b/tests/baselines/reference/computedPropertyNames4_ES6.symbols @@ -52,6 +52,7 @@ var v = { [`hello bye`]: 0, >[`hello bye`] : Symbol([`hello bye`], Decl(computedPropertyNames4_ES6.ts, 12, 19)) +>`hello bye` : Symbol([`hello bye`], Decl(computedPropertyNames4_ES6.ts, 12, 19)) [`hello ${a} bye`]: 0 >[`hello ${a} bye`] : Symbol([`hello ${a} bye`], Decl(computedPropertyNames4_ES6.ts, 13, 21)) diff --git a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.symbols b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.symbols index c118c1d0eff73..3ca78b256c575 100644 --- a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.symbols +++ b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.symbols @@ -1,6 +1,7 @@ === tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts === const b = ({ [`key`]: renamed }) => renamed; >b : Symbol(b, Decl(computerPropertiesInES5ShouldBeTransformed.ts, 0, 5)) +>`key` : Symbol(renamed, Decl(computerPropertiesInES5ShouldBeTransformed.ts, 0, 12)) >renamed : Symbol(renamed, Decl(computerPropertiesInES5ShouldBeTransformed.ts, 0, 12)) >renamed : Symbol(renamed, Decl(computerPropertiesInES5ShouldBeTransformed.ts, 0, 12)) From c941ae3988ef6afb8075aa458b8a99810e521da0 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Mon, 24 Jun 2019 04:51:16 +0300 Subject: [PATCH 07/10] Unify expression position checks for template literals --- src/compiler/utilities.ts | 2 +- .../reference/noSubstitutionTemplateStringLiteralTypes.types | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0fc04937673da..8572d6e717f22 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1692,7 +1692,6 @@ namespace ts { case SyntaxKind.ConditionalExpression: case SyntaxKind.SpreadElement: case SyntaxKind.TemplateExpression: - case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.OmittedExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: @@ -1715,6 +1714,7 @@ namespace ts { case SyntaxKind.NumericLiteral: case SyntaxKind.BigIntLiteral: case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.ThisKeyword: return isInExpressionContext(node); default: diff --git a/tests/baselines/reference/noSubstitutionTemplateStringLiteralTypes.types b/tests/baselines/reference/noSubstitutionTemplateStringLiteralTypes.types index 2274e703ddcc1..945dee6a4d119 100644 --- a/tests/baselines/reference/noSubstitutionTemplateStringLiteralTypes.types +++ b/tests/baselines/reference/noSubstitutionTemplateStringLiteralTypes.types @@ -1,6 +1,5 @@ === tests/cases/compiler/noSubstitutionTemplateStringLiteralTypes.ts === const x: `foo` = "foo"; >x : "foo" ->`foo` : "foo" >"foo" : "foo" From a97f8f6eb941deaf9486406e559f09201b12feef Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Wed, 18 Sep 2019 01:34:31 +0300 Subject: [PATCH 08/10] Support template literals in rename and find all references --- src/compiler/utilities.ts | 10 ++++- src/services/findAllReferences.ts | 5 ++- src/services/rename.ts | 3 +- src/services/services.ts | 1 + src/services/utilities.ts | 2 +- ...enameTemplateLiteralsComputedProperties.ts | 42 +++++++++++++++++++ .../renameTemplateLiteralsDefinePropertyJs.ts | 18 ++++++++ 7 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/renameTemplateLiteralsComputedProperties.ts create mode 100644 tests/cases/fourslash/renameTemplateLiteralsDefinePropertyJs.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8572d6e717f22..c57b8f73125db 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3220,18 +3220,24 @@ namespace ts { } /** - * Strip off existed single quotes or double quotes from a given string + * Strip off existed surrounding single quotes, double quotes, or backticks from a given string * * @return non-quoted string */ export function stripQuotes(name: string) { const length = name.length; - if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && startsWithQuote(name)) { + if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && isQuoteOrBacktick(name.charCodeAt(0))) { return name.substring(1, length - 1); } return name; } + function isQuoteOrBacktick(charCode: number) { + return charCode === CharacterCodes.singleQuote || + charCode === CharacterCodes.doubleQuote || + charCode === CharacterCodes.backtick; + } + export function startsWithQuote(name: string): boolean { return isSingleOrDoubleQuote(name.charCodeAt(0)); } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index f98fb2f75b8d8..143a2a4c5da2b 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -448,7 +448,7 @@ namespace ts.FindAllReferences { function getTextSpan(node: Node, sourceFile: SourceFile, endNode?: Node): TextSpan { let start = node.getStart(sourceFile); let end = (endNode || node).getEnd(); - if (node.kind === SyntaxKind.StringLiteral) { + if (isStringLiteralLike(node)) { Debug.assert(endNode === undefined); start += 1; end -= 1; @@ -1234,8 +1234,9 @@ namespace ts.FindAllReferences.Core { case SyntaxKind.Identifier: return (node as Identifier).text.length === searchSymbolName.length; + case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: { - const str = node as StringLiteral; + const str = node as StringLiteralLike; return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node) || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) && node.parent.arguments[1] === node)) && str.text.length === searchSymbolName.length; } diff --git a/src/services/rename.ts b/src/services/rename.ts index 484349acc8683..775051a8364c3 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -81,7 +81,7 @@ namespace ts.Rename { function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { let start = node.getStart(sourceFile); let width = node.getWidth(sourceFile); - if (node.kind === SyntaxKind.StringLiteral) { + if (isStringLiteralLike(node)) { // Exclude the quotes start += 1; width -= 2; @@ -93,6 +93,7 @@ namespace ts.Rename { switch (node.kind) { case SyntaxKind.Identifier: case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.ThisKeyword: return true; case SyntaxKind.NumericLiteral: diff --git a/src/services/services.ts b/src/services/services.ts index fb5c35d8f5d48..d55ab679e5eca 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2233,6 +2233,7 @@ namespace ts { function getContainingObjectLiteralElementWorker(node: Node): ObjectLiteralElement | undefined { switch (node.kind) { case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.NumericLiteral: if (node.parent.kind === SyntaxKind.ComputedPropertyName) { return isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 91b0a7a19914b..934eb8f4f4624 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -267,7 +267,7 @@ namespace ts { isFunctionLike(node.parent) && (node.parent).name === node; } - export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral): boolean { + export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral): boolean { switch (node.parent.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: diff --git a/tests/cases/fourslash/renameTemplateLiteralsComputedProperties.ts b/tests/cases/fourslash/renameTemplateLiteralsComputedProperties.ts new file mode 100644 index 0000000000000..f6353d1a3d7ac --- /dev/null +++ b/tests/cases/fourslash/renameTemplateLiteralsComputedProperties.ts @@ -0,0 +1,42 @@ +/// + +// @Filename: a.ts +////interface Obj { +//// [|[`[|{| "contextRangeIndex": 0 |}num|]`]: number;|] +//// [|['[|{| "contextRangeIndex": 2 |}bool|]']: boolean;|] +////} +//// +////let o: Obj = { +//// [|[`[|{| "contextRangeIndex": 4 |}num|]`]: 0|], +//// [|['[|{| "contextRangeIndex": 6 |}bool|]']: true|], +////}; +//// +////o = { +//// [|['[|{| "contextRangeIndex": 8 |}num|]']: 1|], +//// [|[`[|{| "contextRangeIndex": 10 |}bool|]`]: false|], +////}; +//// +////o.[|num|]; +////o['[|num|]']; +////o["[|num|]"]; +////o[`[|num|]`]; +//// +////o.[|bool|]; +////o['[|bool|]']; +////o["[|bool|]"]; +////o[`[|bool|]`]; +//// +////export { o }; + +// @allowJs: true +// @Filename: b.js +////import { o as obj } from './a'; +//// +////obj.[|num|]; +////obj[`[|num|]`]; +//// +////obj.[|bool|]; +////obj[`[|bool|]`]; + +verify.rangesWithSameTextAreRenameLocations("num"); +verify.rangesWithSameTextAreRenameLocations("bool"); diff --git a/tests/cases/fourslash/renameTemplateLiteralsDefinePropertyJs.ts b/tests/cases/fourslash/renameTemplateLiteralsDefinePropertyJs.ts new file mode 100644 index 0000000000000..ade3a8bf0be60 --- /dev/null +++ b/tests/cases/fourslash/renameTemplateLiteralsDefinePropertyJs.ts @@ -0,0 +1,18 @@ +/// + +// @allowJs: true +// @Filename: a.js +////let obj = {}; +//// +////Object.defineProperty(obj, `[|prop|]`, { value: 0 }); +//// +////obj = { +//// [|[`[|{| "contextRangeIndex": 1 |}prop|]`]: 1|] +////}; +//// +////obj.[|prop|]; +////obj['[|prop|]']; +////obj["[|prop|]"]; +////obj[`[|prop|]`]; + +verify.rangesWithSameTextAreRenameLocations('prop'); From 11086c9b89391110e9feda96de6db02f94af52f9 Mon Sep 17 00:00:00 2001 From: IllusionMH Date: Tue, 24 Sep 2019 05:10:43 +0300 Subject: [PATCH 09/10] Mark computed properties with template literals as write access --- src/compiler/utilities.ts | 1 + .../cases/fourslash/findAllRefsWriteAccess.ts | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/cases/fourslash/findAllRefsWriteAccess.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c57b8f73125db..06f6285ee87c5 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2529,6 +2529,7 @@ namespace ts { const parent = name.parent; switch (name.kind) { case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.NumericLiteral: if (isComputedPropertyName(parent)) return parent.parent; // falls through diff --git a/tests/cases/fourslash/findAllRefsWriteAccess.ts b/tests/cases/fourslash/findAllRefsWriteAccess.ts new file mode 100644 index 0000000000000..550938a7c0f55 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsWriteAccess.ts @@ -0,0 +1,21 @@ +/// + +////interface Obj { +//// [|[`[|{| "isDefinition": true, "contextRangeIndex": 0 |}num|]`]: number;|] +////} +//// +////let o: Obj = { +//// [|[`[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}num|]`]: 0|] +////}; +//// +////o = { +//// [|['[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}num|]']: 1|] +////}; +//// +////o['[|num|]'] = 2; +////o[`[|num|]`] = 3; +//// +////o['[|num|]']; +////o[`[|num|]`]; + +verify.singleReferenceGroup("(property) Obj[`num`]: number", "num"); From 169566a34923c10097cfe30e82491e68b1d3b9ab Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 27 Sep 2019 10:36:39 -0700 Subject: [PATCH 10/10] Inline startsWithQuote --- src/compiler/utilities.ts | 4 ---- src/services/completions.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 06f6285ee87c5..9a4535da514e9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3239,10 +3239,6 @@ namespace ts { charCode === CharacterCodes.backtick; } - export function startsWithQuote(name: string): boolean { - return isSingleOrDoubleQuote(name.charCodeAt(0)); - } - function getReplacement(c: string, offset: number, input: string) { if (c.charCodeAt(0) === CharacterCodes.nullCharacter) { const lookAhead = input.charCodeAt(offset + c.length); diff --git a/src/services/completions.ts b/src/services/completions.ts index d2d7c3362642f..ccf3e4e4402d9 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -2086,7 +2086,7 @@ namespace ts.Completions { if (name === undefined // If the symbol is external module, don't show it in the completion list // (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there) - || symbol.flags & SymbolFlags.Module && startsWithQuote(name) + || symbol.flags & SymbolFlags.Module && isSingleOrDoubleQuote(name.charCodeAt(0)) // If the symbol is the internal name of an ES symbol, it is not a valid entry. Internal names for ES symbols start with "__@" || isKnownSymbol(symbol)) { return undefined;