From 996c2af28d9a9654882b9017c3822296e9d011c2 Mon Sep 17 00:00:00 2001 From: Zzzen Date: Mon, 14 Jun 2021 20:58:06 +0800 Subject: [PATCH] support generic type when checking implicit conversion of symbol to string --- src/compiler/checker.ts | 17 +++- .../noImplicitSymbolToString.errors.txt | 65 +++++++++++++- .../reference/noImplicitSymbolToString.js | 56 ++++++++++++ .../noImplicitSymbolToString.symbols | 83 +++++++++++++++++ .../reference/noImplicitSymbolToString.types | 89 +++++++++++++++++++ .../compiler/noImplicitSymbolToString.ts | 33 +++++++ 6 files changed, 338 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb1d53714f44d..aada6843de3f6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31317,7 +31317,7 @@ namespace ts { case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: checkNonNullType(operandType, node.operand); - if (maybeTypeOfKind(operandType, TypeFlags.ESSymbolLike)) { + if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) { error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); } if (node.operator === SyntaxKind.PlusToken) { @@ -31378,6 +31378,15 @@ namespace ts { return numberType; } + function maybeTypeOfKindConsideringBaseConstraint(type: Type, kind: TypeFlags): boolean { + if (maybeTypeOfKind(type, kind)) { + return true; + } + + const baseConstraint = getBaseConstraintOrType(type); + return !!baseConstraint && maybeTypeOfKind(baseConstraint, kind); + } + // Return true if type might be of the given kind. A union or intersection type might be of a given // kind if at least one constituent type is of the given kind. function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean { @@ -32147,8 +32156,8 @@ namespace ts { // Return true if there was no error, false if there was an error. function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { const offendingSymbolOperand = - maybeTypeOfKind(leftType, TypeFlags.ESSymbolLike) ? left : - maybeTypeOfKind(rightType, TypeFlags.ESSymbolLike) ? right : + maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : + maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : undefined; if (offendingSymbolOperand) { @@ -32372,7 +32381,7 @@ namespace ts { const types = []; for (const span of node.templateSpans) { const type = checkExpression(span.expression); - if (maybeTypeOfKind(type, TypeFlags.ESSymbolLike)) { + if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) { error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String); } texts.push(span.literal.text); diff --git a/tests/baselines/reference/noImplicitSymbolToString.errors.txt b/tests/baselines/reference/noImplicitSymbolToString.errors.txt index cb664d9a8b93e..b90cf982dd398 100644 --- a/tests/baselines/reference/noImplicitSymbolToString.errors.txt +++ b/tests/baselines/reference/noImplicitSymbolToString.errors.txt @@ -3,9 +3,19 @@ tests/cases/compiler/noImplicitSymbolToString.ts(7,30): error TS2469: The '+' op tests/cases/compiler/noImplicitSymbolToString.ts(8,8): error TS2469: The '+=' operator cannot be applied to type 'symbol'. tests/cases/compiler/noImplicitSymbolToString.ts(13,47): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. tests/cases/compiler/noImplicitSymbolToString.ts(13,90): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +tests/cases/compiler/noImplicitSymbolToString.ts(21,15): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +tests/cases/compiler/noImplicitSymbolToString.ts(26,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +tests/cases/compiler/noImplicitSymbolToString.ts(27,5): error TS2469: The '+' operator cannot be applied to type 'symbol'. +tests/cases/compiler/noImplicitSymbolToString.ts(28,6): error TS2469: The '+' operator cannot be applied to type 'symbol'. +tests/cases/compiler/noImplicitSymbolToString.ts(31,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +tests/cases/compiler/noImplicitSymbolToString.ts(32,5): error TS2469: The '+' operator cannot be applied to type 'symbol'. +tests/cases/compiler/noImplicitSymbolToString.ts(33,6): error TS2469: The '+' operator cannot be applied to type 'symbol'. +tests/cases/compiler/noImplicitSymbolToString.ts(43,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. +tests/cases/compiler/noImplicitSymbolToString.ts(44,5): error TS2469: The '+' operator cannot be applied to type 'symbol'. +tests/cases/compiler/noImplicitSymbolToString.ts(45,6): error TS2469: The '+' operator cannot be applied to type 'symbol'. -==== tests/cases/compiler/noImplicitSymbolToString.ts (5 errors) ==== +==== tests/cases/compiler/noImplicitSymbolToString.ts (15 errors) ==== // Fix #19666 let symbol!: symbol; @@ -29,4 +39,57 @@ tests/cases/compiler/noImplicitSymbolToString.ts(13,90): error TS2731: Implicit !!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. ~~~~~~~~~~~~~~~~~ !!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. + + + // Fix #44462 + + type StringOrSymbol = string | symbol; + + function getKey(key: S) { + return `${key} is the key`; + ~~~ +!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. + } + + function getKey1(key: S) { + let s1!: S; + `${s1}`; + ~~ +!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. + s1 + ''; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + +s1; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + + let s2!: S | string; + `${s2}`; + ~~ +!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. + s2 + ''; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + +s2; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + } + + function getKey2(key: S) { + let s1!: S; + `${s1}`; + s1 + ''; + +s1; + + let s2!: S | symbol; + `${s2}`; + ~~ +!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'. + s2 + ''; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + +s2; + ~~ +!!! error TS2469: The '+' operator cannot be applied to type 'symbol'. + } \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitSymbolToString.js b/tests/baselines/reference/noImplicitSymbolToString.js index 836d5abe8a9d8..b13deb56ea754 100644 --- a/tests/baselines/reference/noImplicitSymbolToString.js +++ b/tests/baselines/reference/noImplicitSymbolToString.js @@ -12,6 +12,39 @@ let symbolUnionNumber!: symbol | number; let symbolUnionString!: symbol | string; const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`; + + +// Fix #44462 + +type StringOrSymbol = string | symbol; + +function getKey(key: S) { + return `${key} is the key`; +} + +function getKey1(key: S) { + let s1!: S; + `${s1}`; + s1 + ''; + +s1; + + let s2!: S | string; + `${s2}`; + s2 + ''; + +s2; +} + +function getKey2(key: S) { + let s1!: S; + `${s1}`; + s1 + ''; + +s1; + + let s2!: S | symbol; + `${s2}`; + s2 + ''; + +s2; +} //// [noImplicitSymbolToString.js] @@ -24,3 +57,26 @@ str += symbol; var symbolUnionNumber; var symbolUnionString; var templateStrUnion = "union with number " + symbolUnionNumber + " and union with string " + symbolUnionString; +function getKey(key) { + return key + " is the key"; +} +function getKey1(key) { + var s1; + "" + s1; + s1 + ''; + +s1; + var s2; + "" + s2; + s2 + ''; + +s2; +} +function getKey2(key) { + var s1; + "" + s1; + s1 + ''; + +s1; + var s2; + "" + s2; + s2 + ''; + +s2; +} diff --git a/tests/baselines/reference/noImplicitSymbolToString.symbols b/tests/baselines/reference/noImplicitSymbolToString.symbols index b2a08e151ab64..4922e1a112c99 100644 --- a/tests/baselines/reference/noImplicitSymbolToString.symbols +++ b/tests/baselines/reference/noImplicitSymbolToString.symbols @@ -30,3 +30,86 @@ const templateStrUnion = `union with number ${symbolUnionNumber} and union with >symbolUnionNumber : Symbol(symbolUnionNumber, Decl(noImplicitSymbolToString.ts, 9, 3)) >symbolUnionString : Symbol(symbolUnionString, Decl(noImplicitSymbolToString.ts, 10, 3)) + +// Fix #44462 + +type StringOrSymbol = string | symbol; +>StringOrSymbol : Symbol(StringOrSymbol, Decl(noImplicitSymbolToString.ts, 12, 109)) + +function getKey(key: S) { +>getKey : Symbol(getKey, Decl(noImplicitSymbolToString.ts, 17, 38)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 19, 16)) +>StringOrSymbol : Symbol(StringOrSymbol, Decl(noImplicitSymbolToString.ts, 12, 109)) +>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 19, 42)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 19, 16)) + + return `${key} is the key`; +>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 19, 42)) +} + +function getKey1(key: S) { +>getKey1 : Symbol(getKey1, Decl(noImplicitSymbolToString.ts, 21, 1)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17)) +>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 23, 35)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17)) + + let s1!: S; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17)) + + `${s1}`; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7)) + + s1 + ''; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7)) + + +s1; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7)) + + let s2!: S | string; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17)) + + `${s2}`; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7)) + + s2 + ''; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7)) + + +s2; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7)) +} + +function getKey2(key: S) { +>getKey2 : Symbol(getKey2, Decl(noImplicitSymbolToString.ts, 33, 1)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17)) +>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 35, 35)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17)) + + let s1!: S; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17)) + + `${s1}`; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7)) + + s1 + ''; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7)) + + +s1; +>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7)) + + let s2!: S | symbol; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7)) +>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17)) + + `${s2}`; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7)) + + s2 + ''; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7)) + + +s2; +>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7)) +} + diff --git a/tests/baselines/reference/noImplicitSymbolToString.types b/tests/baselines/reference/noImplicitSymbolToString.types index c21c0e07bfded..7111542c4a318 100644 --- a/tests/baselines/reference/noImplicitSymbolToString.types +++ b/tests/baselines/reference/noImplicitSymbolToString.types @@ -36,3 +36,92 @@ const templateStrUnion = `union with number ${symbolUnionNumber} and union with >symbolUnionNumber : number | symbol >symbolUnionString : string | symbol + +// Fix #44462 + +type StringOrSymbol = string | symbol; +>StringOrSymbol : StringOrSymbol + +function getKey(key: S) { +>getKey : (key: S) => string +>key : S + + return `${key} is the key`; +>`${key} is the key` : string +>key : S +} + +function getKey1(key: S) { +>getKey1 : (key: S) => void +>key : S + + let s1!: S; +>s1 : S + + `${s1}`; +>`${s1}` : string +>s1 : S + + s1 + ''; +>s1 + '' : string +>s1 : S +>'' : "" + + +s1; +>+s1 : number +>s1 : S + + let s2!: S | string; +>s2 : string | S + + `${s2}`; +>`${s2}` : string +>s2 : string | S + + s2 + ''; +>s2 + '' : string +>s2 : string | S +>'' : "" + + +s2; +>+s2 : number +>s2 : string | S +} + +function getKey2(key: S) { +>getKey2 : (key: S) => void +>key : S + + let s1!: S; +>s1 : S + + `${s1}`; +>`${s1}` : string +>s1 : S + + s1 + ''; +>s1 + '' : string +>s1 : S +>'' : "" + + +s1; +>+s1 : number +>s1 : S + + let s2!: S | symbol; +>s2 : symbol | S + + `${s2}`; +>`${s2}` : string +>s2 : symbol | S + + s2 + ''; +>s2 + '' : string +>s2 : symbol | S +>'' : "" + + +s2; +>+s2 : number +>s2 : symbol | S +} + diff --git a/tests/cases/compiler/noImplicitSymbolToString.ts b/tests/cases/compiler/noImplicitSymbolToString.ts index 16690d6d845cb..a3a797c5f67a8 100644 --- a/tests/cases/compiler/noImplicitSymbolToString.ts +++ b/tests/cases/compiler/noImplicitSymbolToString.ts @@ -11,3 +11,36 @@ let symbolUnionNumber!: symbol | number; let symbolUnionString!: symbol | string; const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`; + + +// Fix #44462 + +type StringOrSymbol = string | symbol; + +function getKey(key: S) { + return `${key} is the key`; +} + +function getKey1(key: S) { + let s1!: S; + `${s1}`; + s1 + ''; + +s1; + + let s2!: S | string; + `${s2}`; + s2 + ''; + +s2; +} + +function getKey2(key: S) { + let s1!: S; + `${s1}`; + s1 + ''; + +s1; + + let s2!: S | symbol; + `${s2}`; + s2 + ''; + +s2; +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy