diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d95fcdcf2fd..1a3cb8f6663 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5479,8 +5479,8 @@ namespace ts { * Indicates whether a declaration name is definitely late-bindable. * A declaration name is only late-bindable if: * - It is a `ComputedPropertyName`. - * - Its expression is either an `Identifier` or is a `PropertyAccessExpression` consisting only of - * other `PropertyAccessExpression` or `Identifier` nodes. + * - Its expression is an `Identifier` or either a `PropertyAccessExpression` an + * `ElementAccessExpression` consisting only of these same three types of nodes. * - The type of its expression is a string or numeric literal type, or is a `unique symbol` type. */ function isLateBindableName(node: DeclarationName): node is LateBoundName { @@ -8299,13 +8299,6 @@ namespace ts { return links.resolvedType; } - function getWidenedTypeOfUniqueESSymbolType(type: Type): Type { - return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getWidenedTypeOfUniqueESSymbolType)) : - type.flags & TypeFlags.Intersection ? getIntersectionType(sameMap((type).types, getWidenedTypeOfUniqueESSymbolType)) : - type; - } - function createUniqueESSymbolType(symbol: Symbol) { const type = createType(TypeFlags.UniqueESSymbol); type.symbol = symbol; @@ -10569,12 +10562,67 @@ namespace ts { type; } + function getWidenedLiteralLikeMapper(wideningFlags: TypeFlags) { + return !(wideningFlags & TypeFlags.UniqueESSymbol) ? getWidenedLiteralType : + !(wideningFlags & TypeFlags.WidenableLiteral) ? getWidenedUniqueESSymbolType : + getWidenedLiteralLikeType; + } + + /** + * Widens string literal, number literal, boolean literal, enum literal, and unique symbol + * types, as well as unions of the same. + * + * We don't always want to widen literals in all of the same places we widen unique symbol + * types, and vice versa. However, there are some cases where we do widen both sets of + * types at the same time. + * + * In general, this function should not be called directly. Instead it should be called + * through either `getWidenedLiteralType` (which does not widen unique symbol types), + * `getWidenedUniqueESSymbolType` (which only widenes unique symbol types), or + * `getWidenedLiteralLikeType` (which widens both). + */ + function getWidenedLiteralLikeTypeWorker(type: Type, wideningFlags: TypeFlags): Type { + return type.flags & wideningFlags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type) : + type.flags & wideningFlags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : + type.flags & wideningFlags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType : + type.flags & wideningFlags & TypeFlags.BooleanLiteral ? booleanType : + type.flags & wideningFlags & TypeFlags.UniqueESSymbol ? esSymbolType : + type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getWidenedLiteralLikeMapper(wideningFlags))) : + type; + } + + /** + * Widens string literal, number literal, boolean literal, enum literal, and unique symbol + * types, as well as unions of the same. + */ + function getWidenedLiteralLikeType(type: Type): Type { + return getWidenedLiteralLikeTypeWorker(type, TypeFlags.WidenableLiteralLike); + } + + /** + * Widens string literal, number literal, boolean literal, and enum literal types, as well + * as unions of the same. + */ function getWidenedLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLiteral ? getBaseTypeOfEnumLiteralType(type) : - type.flags & TypeFlags.StringLiteral && type.flags & TypeFlags.FreshLiteral ? stringType : - type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? getUnionType(sameMap((type).types, getWidenedLiteralType)) : + return getWidenedLiteralLikeTypeWorker(type, TypeFlags.WidenableLiteral); + } + + /** + * Widens unique symbol types and unions of unique symbol types. + */ + function getWidenedUniqueESSymbolType(type: Type): Type { + return getWidenedLiteralLikeTypeWorker(type, TypeFlags.UniqueESSymbol); + } + + /** + * Widens a literal-like type when the contextual type is not literal-like. + */ + function getWidenedLiteralLikeTypeForContextualType(type: Type, contextualType: Type) { + const widenLiterals = !isLiteralContextualType(contextualType); + const widenSymbols = !isUniqueESSymbolContextualType(contextualType); + return widenLiterals && widenSymbols ? getWidenedLiteralLikeType(type) : + widenLiterals ? getWidenedLiteralType(type) : + widenSymbols ? getWidenedUniqueESSymbolType(type) : type; } @@ -11341,7 +11389,8 @@ namespace ts { } } } - return getWidenedTypeOfUniqueESSymbolType(inferredType); + + return getWidenedUniqueESSymbolType(inferredType); } function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type { @@ -13986,7 +14035,7 @@ namespace ts { else { const elementContextualType = getContextualTypeForElementExpression(contextualType, index); const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType); - elementTypes.push(getWidenedTypeOfUniqueESSymbolType(type)); + elementTypes.push(type); } hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement; } @@ -17426,7 +17475,7 @@ namespace ts { } // widen 'unique symbol' types when we infer the return type. - type = getWidenedTypeOfUniqueESSymbolType(type); + type = getWidenedUniqueESSymbolType(type); } else { let types: Type[]; @@ -17462,7 +17511,7 @@ namespace ts { type = getUnionType(types, /*subtypeReduction*/ true); // widen 'unique symbol' types when we infer the return type. - type = getWidenedTypeOfUniqueESSymbolType(type); + type = getWidenedUniqueESSymbolType(type); if (functionFlags & FunctionFlags.Generator) { // AsyncGenerator function or Generator function type = functionFlags & FunctionFlags.Async @@ -18592,13 +18641,17 @@ namespace ts { return false; } + function isUniqueESSymbolContextualType(contextualType: Type) { + return contextualType ? maybeTypeOfKind(contextualType, TypeFlags.UniqueESSymbol) : false; + } + function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode, contextualType?: Type): Type { if (arguments.length === 2) { contextualType = getContextualType(node); } const type = checkExpression(node, checkMode); - const shouldWiden = isTypeAssertion(node) || isLiteralContextualType(contextualType); - return shouldWiden ? type : getWidenedLiteralType(type); + return isTypeAssertion(node) ? type : + getWidenedLiteralLikeTypeForContextualType(type, contextualType); } function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { @@ -24392,8 +24445,7 @@ namespace ts { function isLiteralDynamicName(name: ComputedPropertyName) { name = getParseTreeNode(name, isComputedPropertyName); if (name) { - const nameType = checkComputedPropertyName(name); - return (nameType.flags & TypeFlags.StringOrNumberLiteralOrUnique) !== 0; + return isLateBindableName(name); } return false; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index eb492562961..a3a522cec27 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3246,8 +3246,8 @@ namespace ts { /* @internal */ Nullable = Undefined | Null, - Literal = StringLiteral | NumberLiteral | BooleanLiteral | UniqueESSymbol, - Unit = Literal | Nullable, + Literal = StringLiteral | NumberLiteral | BooleanLiteral, + Unit = Literal | UniqueESSymbol | Nullable, StringOrNumberLiteral = StringLiteral | NumberLiteral, /* @internal */ StringOrNumberLiteralOrUnique = StringOrNumberLiteral | UniqueESSymbol, @@ -3257,7 +3257,7 @@ namespace ts { /* @internal */ Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, /* @internal */ - Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal, + Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, StringLike = String | StringLiteral | Index, NumberLike = Number | NumberLiteral | Enum, BooleanLike = Boolean | BooleanLiteral, @@ -3275,7 +3275,10 @@ namespace ts { /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, /* @internal */ - PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType + PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType, + + WidenableLiteral = Literal | EnumLiteral, + WidenableLiteralLike = WidenableLiteral | UniqueESSymbol, } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; diff --git a/tests/baselines/reference/dynamicNames.js b/tests/baselines/reference/dynamicNames.js index 3180aa35310..6582dab44d4 100644 --- a/tests/baselines/reference/dynamicNames.js +++ b/tests/baselines/reference/dynamicNames.js @@ -135,7 +135,20 @@ export const o1_c4 = o1[c4]; export const o1_c5 = o1[c5]; export const o1_s2 = o1[s2]; -export const o2: T0 = o1; +export const o2: T0 = o1; + +// recursive declarations +declare const rI: RI; +interface RI { + x: "a"; + [rI.x]: "b"; +} + +declare const rC: RC; +declare class RC { + x: "a"; + [rC.x]: "b"; +} //// [module.js] "use strict"; diff --git a/tests/baselines/reference/dynamicNames.symbols b/tests/baselines/reference/dynamicNames.symbols index 2e0a5cadfcd..e030a9686e5 100644 --- a/tests/baselines/reference/dynamicNames.symbols +++ b/tests/baselines/reference/dynamicNames.symbols @@ -442,3 +442,35 @@ export const o2: T0 = o1; >T0 : Symbol(T0, Decl(main.ts, 0, 20)) >o1 : Symbol(o1, Decl(main.ts, 101, 12)) +// recursive declarations +declare const rI: RI; +>rI : Symbol(rI, Decl(main.ts, 115, 13)) +>RI : Symbol(RI, Decl(main.ts, 115, 21)) + +interface RI { +>RI : Symbol(RI, Decl(main.ts, 115, 21)) + + x: "a"; +>x : Symbol(RI.x, Decl(main.ts, 116, 14)) + + [rI.x]: "b"; +>rI.x : Symbol(RI.x, Decl(main.ts, 116, 14)) +>rI : Symbol(rI, Decl(main.ts, 115, 13)) +>x : Symbol(RI.x, Decl(main.ts, 116, 14)) +} + +declare const rC: RC; +>rC : Symbol(rC, Decl(main.ts, 121, 13)) +>RC : Symbol(RC, Decl(main.ts, 121, 21)) + +declare class RC { +>RC : Symbol(RC, Decl(main.ts, 121, 21)) + + x: "a"; +>x : Symbol(RC.x, Decl(main.ts, 122, 18)) + + [rC.x]: "b"; +>rC.x : Symbol(RC.x, Decl(main.ts, 122, 18)) +>rC : Symbol(rC, Decl(main.ts, 121, 13)) +>x : Symbol(RC.x, Decl(main.ts, 122, 18)) +} diff --git a/tests/baselines/reference/dynamicNames.types b/tests/baselines/reference/dynamicNames.types index a568000e13e..b2125d67306 100644 --- a/tests/baselines/reference/dynamicNames.types +++ b/tests/baselines/reference/dynamicNames.types @@ -518,3 +518,35 @@ export const o2: T0 = o1; >T0 : T0 >o1 : { [c4]: number; [c5]: string; [s2]: boolean; } +// recursive declarations +declare const rI: RI; +>rI : RI +>RI : RI + +interface RI { +>RI : RI + + x: "a"; +>x : "a" + + [rI.x]: "b"; +>rI.x : "a" +>rI : RI +>x : "a" +} + +declare const rC: RC; +>rC : RC +>RC : RC + +declare class RC { +>RC : RC + + x: "a"; +>x : "a" + + [rC.x]: "b"; +>rC.x : "a" +>rC : RC +>x : "a" +} diff --git a/tests/baselines/reference/uniqueSymbols.js b/tests/baselines/reference/uniqueSymbols.js index 7da555e6b1f..4de307ee197 100644 --- a/tests/baselines/reference/uniqueSymbols.js +++ b/tests/baselines/reference/uniqueSymbols.js @@ -111,7 +111,91 @@ const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNest // type argument inference const promiseForConstCall = Promise.resolve(constCall); -const arrayOfConstCall = [constCall]; +const arrayOfConstCall = [constCall]; + +// unique symbol widening in expressions +declare const s: unique symbol; +declare namespace N { const s: unique symbol; } +declare const o: { [s]: "a", [N.s]: "b" }; +declare function f(x: T): T; +declare function g(x: typeof s): void; +declare function g(x: typeof N.s): void; + +// widening positions +// argument inference +f(s); +f(N.s); +f(N["s"]); + +// array literal elements +[s]; +[N.s]; +[N["s"]]; + +// property assignments +const o2 = { + a: s, + b: N.s, + c: N["s"] +}; + +// property initializers +class C0 { + static readonly a = s; + static readonly b = N.s; + static readonly c = N["s"]; + + static d = s; + static e = N.s; + static f = N["s"]; + + readonly a = s; + readonly b = N.s; + readonly c = N["s"]; + + d = s; + e = N.s; + f = N["s"]; +} + +// non-widening positions + +// element access +o[s]; +o[N.s]; +o[N["s"]]; + +// arguments (no-inference) +f(s); +f(N.s); +f(N["s"]); +g(s); +g(N.s); +g(N["s"]); + +// falsy expressions +s || ""; +N.s || ""; +N["s"] || ""; + +// conditionals +Math.random() * 2 ? s : "a"; +Math.random() * 2 ? N.s : "a"; +Math.random() * 2 ? N["s"] : "a"; + +// computed property names +({ + [s]: "a", + [N.s]: "b", +}); + +class C1 { + static [s]: "a"; + static [N.s]: "b"; + + [s]: "a"; + [N.s]: "b"; +} //// [uniqueSymbols.js] // declarations with call initializer @@ -192,6 +276,65 @@ const constInitToLReadonlyNestedTypeWithIndexedAccess = l.nested.readonlyNestedT // type argument inference const promiseForConstCall = Promise.resolve(constCall); const arrayOfConstCall = [constCall]; +// widening positions +// argument inference +f(s); +f(N.s); +f(N["s"]); +// array literal elements +[s]; +[N.s]; +[N["s"]]; +// property assignments +const o2 = { + a: s, + b: N.s, + c: N["s"] +}; +// property initializers +class C0 { + constructor() { + this.a = s; + this.b = N.s; + this.c = N["s"]; + this.d = s; + this.e = N.s; + this.f = N["s"]; + } +} +C0.a = s; +C0.b = N.s; +C0.c = N["s"]; +C0.d = s; +C0.e = N.s; +C0.f = N["s"]; +// non-widening positions +// element access +o[s]; +o[N.s]; +o[N["s"]]; +// arguments (no-inference) +f(s); +f(N.s); +f(N["s"]); +g(s); +g(N.s); +g(N["s"]); +// falsy expressions +s || ""; +N.s || ""; +N["s"] || ""; +// conditionals +Math.random() * 2 ? s : "a"; +Math.random() * 2 ? N.s : "a"; +Math.random() * 2 ? N["s"] : "a"; +// computed property names +({ + [s]: "a", + [N.s]: "b", +}); +class C1 { +} //// [uniqueSymbols.d.ts] @@ -273,3 +416,39 @@ declare const constInitToLReadonlyTypeWithIndexedAccess: L["readonlyType"]; declare const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNestedType"]; declare const promiseForConstCall: Promise; declare const arrayOfConstCall: symbol[]; +declare const s: unique symbol; +declare namespace N { + const s: unique symbol; +} +declare const o: { + [s]: "a"; + [N.s]: "b"; +}; +declare function f(x: T): T; +declare function g(x: typeof s): void; +declare function g(x: typeof N.s): void; +declare const o2: { + a: symbol; + b: symbol; + c: symbol; +}; +declare class C0 { + static readonly a: symbol; + static readonly b: symbol; + static readonly c: symbol; + static d: symbol; + static e: symbol; + static f: symbol; + readonly a: symbol; + readonly b: symbol; + readonly c: symbol; + d: symbol; + e: symbol; + f: symbol; +} +declare class C1 { + static [s]: "a"; + static [N.s]: "b"; + [s]: "a"; + [N.s]: "b"; +} diff --git a/tests/baselines/reference/uniqueSymbols.symbols b/tests/baselines/reference/uniqueSymbols.symbols index 970938094ca..80c0611ce74 100644 --- a/tests/baselines/reference/uniqueSymbols.symbols +++ b/tests/baselines/reference/uniqueSymbols.symbols @@ -396,3 +396,275 @@ const arrayOfConstCall = [constCall]; >arrayOfConstCall : Symbol(arrayOfConstCall, Decl(uniqueSymbols.ts, 112, 5)) >constCall : Symbol(constCall, Decl(uniqueSymbols.ts, 1, 5)) +// unique symbol widening in expressions +declare const s: unique symbol; +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +declare namespace N { const s: unique symbol; } +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 116, 27)) + +declare const o: { [s]: "a", [N.s]: "b" }; +>o : Symbol(o, Decl(uniqueSymbols.ts, 117, 13)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +declare function f(x: T): T; +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>T : Symbol(T, Decl(uniqueSymbols.ts, 118, 19)) +>x : Symbol(x, Decl(uniqueSymbols.ts, 118, 22)) +>T : Symbol(T, Decl(uniqueSymbols.ts, 118, 19)) +>T : Symbol(T, Decl(uniqueSymbols.ts, 118, 19)) + +declare function g(x: typeof s): void; +>g : Symbol(g, Decl(uniqueSymbols.ts, 118, 31), Decl(uniqueSymbols.ts, 119, 38)) +>x : Symbol(x, Decl(uniqueSymbols.ts, 119, 19)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +declare function g(x: typeof N.s): void; +>g : Symbol(g, Decl(uniqueSymbols.ts, 118, 31), Decl(uniqueSymbols.ts, 119, 38)) +>x : Symbol(x, Decl(uniqueSymbols.ts, 120, 19)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// widening positions +// argument inference +f(s); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +f(N.s); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +f(N["s"]); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// array literal elements +[s]; +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +[N.s]; +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +[N["s"]]; +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// property assignments +const o2 = { +>o2 : Symbol(o2, Decl(uniqueSymbols.ts, 134, 5)) + + a: s, +>a : Symbol(a, Decl(uniqueSymbols.ts, 134, 12)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + b: N.s, +>b : Symbol(b, Decl(uniqueSymbols.ts, 135, 9)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + c: N["s"] +>c : Symbol(c, Decl(uniqueSymbols.ts, 136, 11)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +}; + +// property initializers +class C0 { +>C0 : Symbol(C0, Decl(uniqueSymbols.ts, 138, 2)) + + static readonly a = s; +>a : Symbol(C0.a, Decl(uniqueSymbols.ts, 141, 10)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + static readonly b = N.s; +>b : Symbol(C0.b, Decl(uniqueSymbols.ts, 142, 26)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + static readonly c = N["s"]; +>c : Symbol(C0.c, Decl(uniqueSymbols.ts, 143, 28)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + static d = s; +>d : Symbol(C0.d, Decl(uniqueSymbols.ts, 144, 31)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + static e = N.s; +>e : Symbol(C0.e, Decl(uniqueSymbols.ts, 146, 17)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + static f = N["s"]; +>f : Symbol(C0.f, Decl(uniqueSymbols.ts, 147, 19)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + readonly a = s; +>a : Symbol(C0.a, Decl(uniqueSymbols.ts, 148, 22)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + readonly b = N.s; +>b : Symbol(C0.b, Decl(uniqueSymbols.ts, 150, 19)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + readonly c = N["s"]; +>c : Symbol(C0.c, Decl(uniqueSymbols.ts, 151, 21)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + d = s; +>d : Symbol(C0.d, Decl(uniqueSymbols.ts, 152, 24)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + e = N.s; +>e : Symbol(C0.e, Decl(uniqueSymbols.ts, 154, 10)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + f = N["s"]; +>f : Symbol(C0.f, Decl(uniqueSymbols.ts, 155, 12)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +} + +// non-widening positions + +// element access +o[s]; +>o : Symbol(o, Decl(uniqueSymbols.ts, 117, 13)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +o[N.s]; +>o : Symbol(o, Decl(uniqueSymbols.ts, 117, 13)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +o[N["s"]]; +>o : Symbol(o, Decl(uniqueSymbols.ts, 117, 13)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// arguments (no-inference) +f(s); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +f(N.s); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +f(N["s"]); +>f : Symbol(f, Decl(uniqueSymbols.ts, 117, 42)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +g(s); +>g : Symbol(g, Decl(uniqueSymbols.ts, 118, 31), Decl(uniqueSymbols.ts, 119, 38)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +g(N.s); +>g : Symbol(g, Decl(uniqueSymbols.ts, 118, 31), Decl(uniqueSymbols.ts, 119, 38)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +g(N["s"]); +>g : Symbol(g, Decl(uniqueSymbols.ts, 118, 31), Decl(uniqueSymbols.ts, 119, 38)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// falsy expressions +s || ""; +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +N.s || ""; +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +N["s"] || ""; +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// conditionals +Math.random() * 2 ? s : "a"; +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + +Math.random() * 2 ? N.s : "a"; +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +Math.random() * 2 ? N["s"] : "a"; +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>"s" : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +// computed property names +({ + [s]: "a", +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + [N.s]: "b", +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + +}); + +class C1 { +>C1 : Symbol(C1, Decl(uniqueSymbols.ts, 188, 3)) + + static [s]: "a"; +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + static [N.s]: "b"; +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) + + [s]: "a"; +>s : Symbol(s, Decl(uniqueSymbols.ts, 115, 13)) + + [N.s]: "b"; +>N.s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +>N : Symbol(N, Decl(uniqueSymbols.ts, 115, 31)) +>s : Symbol(N.s, Decl(uniqueSymbols.ts, 116, 27)) +} diff --git a/tests/baselines/reference/uniqueSymbols.types b/tests/baselines/reference/uniqueSymbols.types index 495cf583294..3deaf4572f4 100644 --- a/tests/baselines/reference/uniqueSymbols.types +++ b/tests/baselines/reference/uniqueSymbols.types @@ -414,3 +414,329 @@ const arrayOfConstCall = [constCall]; >[constCall] : symbol[] >constCall : unique symbol +// unique symbol widening in expressions +declare const s: unique symbol; +>s : unique symbol + +declare namespace N { const s: unique symbol; } +>N : typeof N +>s : unique symbol + +declare const o: { [s]: "a", [N.s]: "b" }; +>o : { [s]: "a"; [N.s]: "b"; } +>s : unique symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +declare function f(x: T): T; +>f : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +declare function g(x: typeof s): void; +>g : { (x: unique symbol): void; (x: unique symbol): void; } +>x : unique symbol +>s : unique symbol + +declare function g(x: typeof N.s): void; +>g : { (x: unique symbol): void; (x: unique symbol): void; } +>x : unique symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +// widening positions +// argument inference +f(s); +>f(s) : symbol +>f : (x: T) => T +>s : unique symbol + +f(N.s); +>f(N.s) : symbol +>f : (x: T) => T +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +f(N["s"]); +>f(N["s"]) : symbol +>f : (x: T) => T +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +// array literal elements +[s]; +>[s] : symbol[] +>s : unique symbol + +[N.s]; +>[N.s] : symbol[] +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +[N["s"]]; +>[N["s"]] : symbol[] +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +// property assignments +const o2 = { +>o2 : { a: symbol; b: symbol; c: symbol; } +>{ a: s, b: N.s, c: N["s"]} : { a: symbol; b: symbol; c: symbol; } + + a: s, +>a : symbol +>s : unique symbol + + b: N.s, +>b : symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + c: N["s"] +>c : symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +}; + +// property initializers +class C0 { +>C0 : C0 + + static readonly a = s; +>a : symbol +>s : unique symbol + + static readonly b = N.s; +>b : symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + static readonly c = N["s"]; +>c : symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + + static d = s; +>d : symbol +>s : unique symbol + + static e = N.s; +>e : symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + static f = N["s"]; +>f : symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + + readonly a = s; +>a : symbol +>s : unique symbol + + readonly b = N.s; +>b : symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + readonly c = N["s"]; +>c : symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + + d = s; +>d : symbol +>s : unique symbol + + e = N.s; +>e : symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + f = N["s"]; +>f : symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" +} + +// non-widening positions + +// element access +o[s]; +>o[s] : "a" +>o : { [s]: "a"; [N.s]: "b"; } +>s : unique symbol + +o[N.s]; +>o[N.s] : "b" +>o : { [s]: "a"; [N.s]: "b"; } +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +o[N["s"]]; +>o[N["s"]] : "b" +>o : { [s]: "a"; [N.s]: "b"; } +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +// arguments (no-inference) +f(s); +>f(s) : unique symbol +>f : (x: T) => T +>s : unique symbol +>s : unique symbol + +f(N.s); +>f(N.s) : unique symbol +>f : (x: T) => T +>N.s : unique symbol +>N : typeof N +>s : unique symbol +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +f(N["s"]); +>f(N["s"]) : unique symbol +>f : (x: T) => T +>N.s : unique symbol +>N : typeof N +>s : unique symbol +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +g(s); +>g(s) : void +>g : { (x: unique symbol): void; (x: unique symbol): void; } +>s : unique symbol + +g(N.s); +>g(N.s) : void +>g : { (x: unique symbol): void; (x: unique symbol): void; } +>N.s : unique symbol +>N : typeof N +>s : unique symbol + +g(N["s"]); +>g(N["s"]) : void +>g : { (x: unique symbol): void; (x: unique symbol): void; } +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" + +// falsy expressions +s || ""; +>s || "" : unique symbol | "" +>s : unique symbol +>"" : "" + +N.s || ""; +>N.s || "" : unique symbol | "" +>N.s : unique symbol +>N : typeof N +>s : unique symbol +>"" : "" + +N["s"] || ""; +>N["s"] || "" : unique symbol | "" +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" +>"" : "" + +// conditionals +Math.random() * 2 ? s : "a"; +>Math.random() * 2 ? s : "a" : unique symbol | "a" +>Math.random() * 2 : number +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>2 : 2 +>s : unique symbol +>"a" : "a" + +Math.random() * 2 ? N.s : "a"; +>Math.random() * 2 ? N.s : "a" : unique symbol | "a" +>Math.random() * 2 : number +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>2 : 2 +>N.s : unique symbol +>N : typeof N +>s : unique symbol +>"a" : "a" + +Math.random() * 2 ? N["s"] : "a"; +>Math.random() * 2 ? N["s"] : "a" : unique symbol | "a" +>Math.random() * 2 : number +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>2 : 2 +>N["s"] : unique symbol +>N : typeof N +>"s" : "s" +>"a" : "a" + +// computed property names +({ +>({ [s]: "a", [N.s]: "b",}) : { [s]: string; [N.s]: string; } +>{ [s]: "a", [N.s]: "b",} : { [s]: string; [N.s]: string; } + + [s]: "a", +>s : unique symbol +>"a" : "a" + + [N.s]: "b", +>N.s : unique symbol +>N : typeof N +>s : unique symbol +>"b" : "b" + +}); + +class C1 { +>C1 : C1 + + static [s]: "a"; +>s : unique symbol + + static [N.s]: "b"; +>N.s : unique symbol +>N : typeof N +>s : unique symbol + + [s]: "a"; +>s : unique symbol + + [N.s]: "b"; +>N.s : unique symbol +>N : typeof N +>s : unique symbol +} diff --git a/tests/cases/compiler/dynamicNames.ts b/tests/cases/compiler/dynamicNames.ts index 2184ee73b33..9562685b08f 100644 --- a/tests/cases/compiler/dynamicNames.ts +++ b/tests/cases/compiler/dynamicNames.ts @@ -137,4 +137,17 @@ export const o1_c4 = o1[c4]; export const o1_c5 = o1[c5]; export const o1_s2 = o1[s2]; -export const o2: T0 = o1; \ No newline at end of file +export const o2: T0 = o1; + +// recursive declarations +declare const rI: RI; +interface RI { + x: "a"; + [rI.x]: "b"; +} + +declare const rC: RC; +declare class RC { + x: "a"; + [rC.x]: "b"; +} \ No newline at end of file diff --git a/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts b/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts index 66b9a081691..a804ed8d20a 100644 --- a/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts +++ b/tests/cases/conformance/types/uniqueSymbol/uniqueSymbols.ts @@ -114,4 +114,88 @@ const constInitToLReadonlyNestedTypeWithIndexedAccess: L["nested"]["readonlyNest // type argument inference const promiseForConstCall = Promise.resolve(constCall); -const arrayOfConstCall = [constCall]; \ No newline at end of file +const arrayOfConstCall = [constCall]; + +// unique symbol widening in expressions +declare const s: unique symbol; +declare namespace N { const s: unique symbol; } +declare const o: { [s]: "a", [N.s]: "b" }; +declare function f(x: T): T; +declare function g(x: typeof s): void; +declare function g(x: typeof N.s): void; + +// widening positions +// argument inference +f(s); +f(N.s); +f(N["s"]); + +// array literal elements +[s]; +[N.s]; +[N["s"]]; + +// property assignments +const o2 = { + a: s, + b: N.s, + c: N["s"] +}; + +// property initializers +class C0 { + static readonly a = s; + static readonly b = N.s; + static readonly c = N["s"]; + + static d = s; + static e = N.s; + static f = N["s"]; + + readonly a = s; + readonly b = N.s; + readonly c = N["s"]; + + d = s; + e = N.s; + f = N["s"]; +} + +// non-widening positions + +// element access +o[s]; +o[N.s]; +o[N["s"]]; + +// arguments (no-inference) +f(s); +f(N.s); +f(N["s"]); +g(s); +g(N.s); +g(N["s"]); + +// falsy expressions +s || ""; +N.s || ""; +N["s"] || ""; + +// conditionals +Math.random() * 2 ? s : "a"; +Math.random() * 2 ? N.s : "a"; +Math.random() * 2 ? N["s"] : "a"; + +// computed property names +({ + [s]: "a", + [N.s]: "b", +}); + +class C1 { + static [s]: "a"; + static [N.s]: "b"; + + [s]: "a"; + [N.s]: "b"; +} \ No newline at end of file