diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4aee170f195d4..38d3a97a2874d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16883,6 +16883,7 @@ namespace ts { let hasDuplicateDefaultClause = false; const expressionType = checkExpression(node.expression); + const expressionIsLiteral = isLiteralType(expressionType); forEach(node.caseBlock.clauses, clause => { // Grammar check for duplicate default clauses, skip if we already report duplicate default clause if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) { @@ -16903,10 +16904,16 @@ namespace ts { // TypeScript 1.0 spec (April 2014): 5.9 // In a 'switch' statement, each 'case' expression must be of a type that is comparable // to or from the type of the 'switch' expression. - const caseType = checkExpression(caseClause.expression); - if (!isTypeEqualityComparableTo(expressionType, caseType)) { + let caseType = checkExpression(caseClause.expression); + const caseIsLiteral = isLiteralType(caseType); + let comparedExpressionType = expressionType; + if (!caseIsLiteral || !expressionIsLiteral) { + caseType = caseIsLiteral ? getBaseTypeOfLiteralType(caseType) : caseType; + comparedExpressionType = getBaseTypeOfLiteralType(expressionType); + } + if (!isTypeEqualityComparableTo(comparedExpressionType, caseType)) { // expressionType is not comparable to caseType, try the reversed check and report errors if it fails - checkTypeComparableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined); + checkTypeComparableTo(caseType, comparedExpressionType, caseClause.expression, /*headMessage*/ undefined); } } forEach(clause.statements, checkSourceElement); diff --git a/tests/baselines/reference/switchAssignmentCompat.errors.txt b/tests/baselines/reference/switchAssignmentCompat.errors.txt index 46c89fa5b52d2..747a1035b6846 100644 --- a/tests/baselines/reference/switchAssignmentCompat.errors.txt +++ b/tests/baselines/reference/switchAssignmentCompat.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/switchAssignmentCompat.ts(4,10): error TS2678: Type 'typeof Foo' is not comparable to type '0'. +tests/cases/compiler/switchAssignmentCompat.ts(4,10): error TS2678: Type 'typeof Foo' is not comparable to type 'number'. ==== tests/cases/compiler/switchAssignmentCompat.ts (1 errors) ==== @@ -7,6 +7,6 @@ tests/cases/compiler/switchAssignmentCompat.ts(4,10): error TS2678: Type 'typeof switch (0) { case Foo: break; // Error expected ~~~ -!!! error TS2678: Type 'typeof Foo' is not comparable to type '0'. +!!! error TS2678: Type 'typeof Foo' is not comparable to type 'number'. } \ No newline at end of file diff --git a/tests/baselines/reference/switchCaseCircularRefeference.errors.txt b/tests/baselines/reference/switchCaseCircularRefeference.errors.txt index 9ee571de468ce..bc576f8e723b8 100644 --- a/tests/baselines/reference/switchCaseCircularRefeference.errors.txt +++ b/tests/baselines/reference/switchCaseCircularRefeference.errors.txt @@ -1,6 +1,5 @@ -tests/cases/compiler/switchCaseCircularRefeference.ts(5,10): error TS2678: Type '{ a: "A"; b: any; } | { a: "C"; e: any; }' is not comparable to type '"A" | "C"'. - Type '{ a: "C"; e: any; }' is not comparable to type '"A" | "C"'. - Type '{ a: "C"; e: any; }' is not comparable to type '"C"'. +tests/cases/compiler/switchCaseCircularRefeference.ts(5,10): error TS2678: Type '{ a: "A"; b: any; } | { a: "C"; e: any; }' is not comparable to type 'string'. + Type '{ a: "C"; e: any; }' is not comparable to type 'string'. ==== tests/cases/compiler/switchCaseCircularRefeference.ts (1 errors) ==== @@ -10,9 +9,8 @@ tests/cases/compiler/switchCaseCircularRefeference.ts(5,10): error TS2678: Type switch (x.a) { case x: ~ -!!! error TS2678: Type '{ a: "A"; b: any; } | { a: "C"; e: any; }' is not comparable to type '"A" | "C"'. -!!! error TS2678: Type '{ a: "C"; e: any; }' is not comparable to type '"A" | "C"'. -!!! error TS2678: Type '{ a: "C"; e: any; }' is not comparable to type '"C"'. +!!! error TS2678: Type '{ a: "A"; b: any; } | { a: "C"; e: any; }' is not comparable to type 'string'. +!!! error TS2678: Type '{ a: "C"; e: any; }' is not comparable to type 'string'. break; } } \ No newline at end of file diff --git a/tests/baselines/reference/switchCasesExpressionTypeMismatch.errors.txt b/tests/baselines/reference/switchCasesExpressionTypeMismatch.errors.txt index 3ea12e2460f65..7a5fd12182e4e 100644 --- a/tests/baselines/reference/switchCasesExpressionTypeMismatch.errors.txt +++ b/tests/baselines/reference/switchCasesExpressionTypeMismatch.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(4,10): error TS2678: Type 'typeof Foo' is not comparable to type '0'. +tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(4,10): error TS2678: Type 'typeof Foo' is not comparable to type 'number'. tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(5,10): error TS2678: Type '"sss"' is not comparable to type '0'. tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(6,10): error TS2678: Type '123' is not comparable to type '0'. tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(7,10): error TS2678: Type 'true' is not comparable to type '0'. @@ -10,11 +10,11 @@ tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(7,10): error TS2678: T switch (0) { case Foo: break; // Error ~~~ -!!! error TS2678: Type 'typeof Foo' is not comparable to type '0'. +!!! error TS2678: Type 'typeof Foo' is not comparable to type 'number'. case "sss": break; // Error ~~~~~ !!! error TS2678: Type '"sss"' is not comparable to type '0'. - case 123: break; // No Error + case 123: break; // Error ~~~ !!! error TS2678: Type '123' is not comparable to type '0'. case true: break; // Error @@ -30,4 +30,5 @@ tests/cases/compiler/switchCasesExpressionTypeMismatch.ts(7,10): error TS2678: T case "sss": break; case 123: break; case true: break; - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/switchCasesExpressionTypeMismatch.js b/tests/baselines/reference/switchCasesExpressionTypeMismatch.js index ba929691d2536..43a4322457938 100644 --- a/tests/baselines/reference/switchCasesExpressionTypeMismatch.js +++ b/tests/baselines/reference/switchCasesExpressionTypeMismatch.js @@ -4,7 +4,7 @@ class Foo { } switch (0) { case Foo: break; // Error case "sss": break; // Error - case 123: break; // No Error + case 123: break; // Error case true: break; // Error } @@ -16,7 +16,8 @@ switch (s) { case "sss": break; case 123: break; case true: break; -} +} + //// [switchCasesExpressionTypeMismatch.js] var Foo = (function () { @@ -27,7 +28,7 @@ var Foo = (function () { switch (0) { case Foo: break; // Error case "sss": break; // Error - case 123: break; // No Error + case 123: break; // Error case true: break; // Error } var s = 0; diff --git a/tests/baselines/reference/switchComparableCompatForBrands.js b/tests/baselines/reference/switchComparableCompatForBrands.js new file mode 100644 index 0000000000000..316edfc9c31b1 --- /dev/null +++ b/tests/baselines/reference/switchComparableCompatForBrands.js @@ -0,0 +1,29 @@ +//// [switchComparableCompatForBrands.ts] +class MyBrand +{ + private _a: number; +} + +function test(strInput: string & MyBrand) { + switch(strInput) + { + case "a": + return 1; + } + return 0; +} + + +//// [switchComparableCompatForBrands.js] +var MyBrand = (function () { + function MyBrand() { + } + return MyBrand; +}()); +function test(strInput) { + switch (strInput) { + case "a": + return 1; + } + return 0; +} diff --git a/tests/baselines/reference/switchComparableCompatForBrands.symbols b/tests/baselines/reference/switchComparableCompatForBrands.symbols new file mode 100644 index 0000000000000..adf6a5174adf3 --- /dev/null +++ b/tests/baselines/reference/switchComparableCompatForBrands.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/switchComparableCompatForBrands.ts === +class MyBrand +>MyBrand : Symbol(MyBrand, Decl(switchComparableCompatForBrands.ts, 0, 0)) +{ + private _a: number; +>_a : Symbol(MyBrand._a, Decl(switchComparableCompatForBrands.ts, 1, 1)) +} + +function test(strInput: string & MyBrand) { +>test : Symbol(test, Decl(switchComparableCompatForBrands.ts, 3, 1)) +>strInput : Symbol(strInput, Decl(switchComparableCompatForBrands.ts, 5, 14)) +>MyBrand : Symbol(MyBrand, Decl(switchComparableCompatForBrands.ts, 0, 0)) + + switch(strInput) +>strInput : Symbol(strInput, Decl(switchComparableCompatForBrands.ts, 5, 14)) + { + case "a": + return 1; + } + return 0; +} + diff --git a/tests/baselines/reference/switchComparableCompatForBrands.types b/tests/baselines/reference/switchComparableCompatForBrands.types new file mode 100644 index 0000000000000..5e479ee29dc2e --- /dev/null +++ b/tests/baselines/reference/switchComparableCompatForBrands.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/switchComparableCompatForBrands.ts === +class MyBrand +>MyBrand : MyBrand +{ + private _a: number; +>_a : number +} + +function test(strInput: string & MyBrand) { +>test : (strInput: string & MyBrand) => 1 | 0 +>strInput : string & MyBrand +>MyBrand : MyBrand + + switch(strInput) +>strInput : string & MyBrand + { + case "a": +>"a" : "a" + + return 1; +>1 : 1 + } + return 0; +>0 : 0 +} + diff --git a/tests/cases/compiler/switchCasesExpressionTypeMismatch.ts b/tests/cases/compiler/switchCasesExpressionTypeMismatch.ts index 4de01ebba175c..ee547705b84d2 100644 --- a/tests/cases/compiler/switchCasesExpressionTypeMismatch.ts +++ b/tests/cases/compiler/switchCasesExpressionTypeMismatch.ts @@ -3,7 +3,7 @@ class Foo { } switch (0) { case Foo: break; // Error case "sss": break; // Error - case 123: break; // No Error + case 123: break; // Error case true: break; // Error } @@ -15,4 +15,4 @@ switch (s) { case "sss": break; case 123: break; case true: break; -} \ No newline at end of file +} diff --git a/tests/cases/compiler/switchComparableCompatForBrands.ts b/tests/cases/compiler/switchComparableCompatForBrands.ts new file mode 100644 index 0000000000000..4b90db40e1db8 --- /dev/null +++ b/tests/cases/compiler/switchComparableCompatForBrands.ts @@ -0,0 +1,13 @@ +class MyBrand +{ + private _a: number; +} + +function test(strInput: string & MyBrand) { + switch(strInput) + { + case "a": + return 1; + } + return 0; +}