From 4a631674569a8c9497fb8ef299f51a97c52fb565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 26 Nov 2024 21:27:55 +0100 Subject: [PATCH] Fixed syntactic nullisness semantics for tagged template expressions --- src/compiler/checker.ts | 1 + .../reference/predicateSemantics.errors.txt | 19 +++++++- .../baselines/reference/predicateSemantics.js | 20 +++++++- .../reference/predicateSemantics.symbols | 21 +++++++++ .../reference/predicateSemantics.types | 47 +++++++++++++++++++ tests/cases/compiler/predicateSemantics.ts | 11 +++++ 6 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d044fa5bf0f4..60ae188c3f5fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -39909,6 +39909,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.kind) { case SyntaxKind.AwaitExpression: case SyntaxKind.CallExpression: + case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ElementAccessExpression: case SyntaxKind.MetaProperty: case SyntaxKind.NewExpression: diff --git a/tests/baselines/reference/predicateSemantics.errors.txt b/tests/baselines/reference/predicateSemantics.errors.txt index 0dc25d43dbf2b..c80dd47d19357 100644 --- a/tests/baselines/reference/predicateSemantics.errors.txt +++ b/tests/baselines/reference/predicateSemantics.errors.txt @@ -12,9 +12,11 @@ predicateSemantics.ts(36,8): error TS2872: This kind of expression is always tru predicateSemantics.ts(51,14): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. predicateSemantics.ts(52,14): error TS2695: Left side of comma operator is unused and has no side effects. predicateSemantics.ts(52,14): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. +predicateSemantics.ts(70,1): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. +predicateSemantics.ts(71,1): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. -==== predicateSemantics.ts (14 errors) ==== +==== predicateSemantics.ts (16 errors) ==== declare let cond: any; // OK: One or other operand is possibly nullish @@ -103,4 +105,19 @@ predicateSemantics.ts(52,14): error TS2869: Right operand of ?? is unreachable b const p = new.target ?? 32; } } + + // https://github.com/microsoft/TypeScript/issues/60614 + declare function tag( + strings: TemplateStringsArray, + ...values: number[] + ): T | null; + + tag`foo${1}` ?? 32; // ok + + `foo${1}` ?? 32; // error + ~~~~~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + `foo` ?? 32; // error + ~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. \ No newline at end of file diff --git a/tests/baselines/reference/predicateSemantics.js b/tests/baselines/reference/predicateSemantics.js index f4edc198ffecd..30ada0d514d02 100644 --- a/tests/baselines/reference/predicateSemantics.js +++ b/tests/baselines/reference/predicateSemantics.js @@ -61,10 +61,25 @@ class X { const p = new.target ?? 32; } } + +// https://github.com/microsoft/TypeScript/issues/60614 +declare function tag( + strings: TemplateStringsArray, + ...values: number[] +): T | null; + +tag`foo${1}` ?? 32; // ok + +`foo${1}` ?? 32; // error +`foo` ?? 32; // error //// [predicateSemantics.js] -var _a, _b, _c, _d, _e, _f, _g, _h, _j; +var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; // OK: One or other operand is possibly nullish var test1 = (_a = (cond ? undefined : 32)) !== null && _a !== void 0 ? _a : "possibly reached"; // Not OK: Both operands nullish @@ -122,3 +137,6 @@ var X = /** @class */ (function () { } return X; }()); +(_k = tag(__makeTemplateObject(["foo", ""], ["foo", ""]), 1)) !== null && _k !== void 0 ? _k : 32; // ok +(_l = "foo".concat(1)) !== null && _l !== void 0 ? _l : 32; // error +"foo" !== null && "foo" !== void 0 ? "foo" : 32; // error diff --git a/tests/baselines/reference/predicateSemantics.symbols b/tests/baselines/reference/predicateSemantics.symbols index e5c831515a0bc..f8ddf0fe5db87 100644 --- a/tests/baselines/reference/predicateSemantics.symbols +++ b/tests/baselines/reference/predicateSemantics.symbols @@ -116,3 +116,24 @@ class X { } } +// https://github.com/microsoft/TypeScript/issues/60614 +declare function tag( +>tag : Symbol(tag, Decl(predicateSemantics.ts, 59, 1)) +>T : Symbol(T, Decl(predicateSemantics.ts, 62, 21)) + + strings: TemplateStringsArray, +>strings : Symbol(strings, Decl(predicateSemantics.ts, 62, 24)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) + + ...values: number[] +>values : Symbol(values, Decl(predicateSemantics.ts, 63, 32)) + +): T | null; +>T : Symbol(T, Decl(predicateSemantics.ts, 62, 21)) + +tag`foo${1}` ?? 32; // ok +>tag : Symbol(tag, Decl(predicateSemantics.ts, 59, 1)) + +`foo${1}` ?? 32; // error +`foo` ?? 32; // error + diff --git a/tests/baselines/reference/predicateSemantics.types b/tests/baselines/reference/predicateSemantics.types index de0c9daf76eb0..b054c66ad43e7 100644 --- a/tests/baselines/reference/predicateSemantics.types +++ b/tests/baselines/reference/predicateSemantics.types @@ -328,3 +328,50 @@ class X { } } +// https://github.com/microsoft/TypeScript/issues/60614 +declare function tag( +>tag : (strings: TemplateStringsArray, ...values: number[]) => T | null +> : ^ ^^ ^^ ^^^^^ ^^ ^^^^^ + + strings: TemplateStringsArray, +>strings : TemplateStringsArray +> : ^^^^^^^^^^^^^^^^^^^^ + + ...values: number[] +>values : number[] +> : ^^^^^^^^ + +): T | null; + +tag`foo${1}` ?? 32; // ok +>tag`foo${1}` ?? 32 : unknown +> : ^^^^^^^ +>tag`foo${1}` : unknown +> : ^^^^^^^ +>tag : (strings: TemplateStringsArray, ...values: number[]) => T | null +> : ^ ^^ ^^ ^^^^^ ^^ ^^^^^ +>`foo${1}` : string +> : ^^^^^^ +>1 : 1 +> : ^ +>32 : 32 +> : ^^ + +`foo${1}` ?? 32; // error +>`foo${1}` ?? 32 : 32 | "foo1" +> : ^^^^^^^^^^^ +>`foo${1}` : "foo1" +> : ^^^^^^ +>1 : 1 +> : ^ +>32 : 32 +> : ^^ + +`foo` ?? 32; // error +>`foo` ?? 32 : 32 | "foo" +> : ^^^^^^^^^^ +>`foo` : "foo" +> : ^^^^^ +>32 : 32 +> : ^^ + diff --git a/tests/cases/compiler/predicateSemantics.ts b/tests/cases/compiler/predicateSemantics.ts index e937b1d6182a8..a22b34341e7d5 100644 --- a/tests/cases/compiler/predicateSemantics.ts +++ b/tests/cases/compiler/predicateSemantics.ts @@ -58,3 +58,14 @@ class X { const p = new.target ?? 32; } } + +// https://github.com/microsoft/TypeScript/issues/60614 +declare function tag( + strings: TemplateStringsArray, + ...values: number[] +): T | null; + +tag`foo${1}` ?? 32; // ok + +`foo${1}` ?? 32; // error +`foo` ?? 32; // error