Skip to content

Commit da61231

Browse files
authored
Include super.XXX(...) assertion method calls in CFA (#36293)
* Support super.XXX in assertions * Add tests
1 parent c8e2f58 commit da61231

12 files changed

+337
-47
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19075,6 +19075,8 @@ namespace ts {
1907519075
return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, diagnostic);
1907619076
case SyntaxKind.ThisKeyword:
1907719077
return getExplicitThisType(node);
19078+
case SyntaxKind.SuperKeyword:
19079+
return checkSuperExpression(node);
1907819080
case SyntaxKind.PropertyAccessExpression:
1907919081
const type = getTypeOfDottedName((<PropertyAccessExpression>node).expression, diagnostic);
1908019082
const prop = type && getPropertyOfType(type, (<PropertyAccessExpression>node).name.escapedText);

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4278,7 +4278,7 @@ namespace ts {
42784278
}
42794279

42804280
export function isDottedName(node: Expression): boolean {
4281-
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword ||
4281+
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword ||
42824282
node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((<PropertyAccessExpression>node).expression) ||
42834283
node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((<ParenthesizedExpression>node).expression);
42844284
}

tests/baselines/reference/assertionTypePredicates1.errors.txt

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(39,9): error TS7
22
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(43,9): error TS7027: Unreachable code detected.
33
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(87,9): error TS7027: Unreachable code detected.
44
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(122,9): error TS7027: Unreachable code detected.
5-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(132,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
6-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
7-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(134,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
8-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(137,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
9-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(138,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
10-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(139,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
11-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(140,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
12-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(145,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
13-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(147,5): error TS2776: Assertions require the call target to be an identifier or qualified name.
14-
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
5+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(137,9): error TS7027: Unreachable code detected.
6+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(143,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
7+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(144,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
8+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(145,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
9+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(148,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
10+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
11+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(150,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
12+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(151,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
13+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(156,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
14+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(158,5): error TS2776: Assertions require the call target to be an identifier or qualified name.
15+
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
1516

1617

17-
==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (14 errors) ====
18+
==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (15 errors) ====
1819
declare function isString(value: unknown): value is string;
1920
declare function isArrayOfStrings(value: unknown): value is string[];
2021

@@ -152,6 +153,19 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS
152153
z = 0;
153154
}
154155

156+
class Derived extends Test {
157+
foo(x: unknown) {
158+
super.assert(typeof x === "string");
159+
x.length;
160+
}
161+
baz(x: number) {
162+
super.assert(false);
163+
x; // Unreachable
164+
~~
165+
!!! error TS7027: Unreachable code detected.
166+
}
167+
}
168+
155169
// Invalid constructs
156170

157171
declare let Q1: new (x: unknown) => x is string;
@@ -184,7 +198,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS
184198
assert(typeof x === "string"); // Error
185199
~~~~~~
186200
!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
187-
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:144:11: 'assert' needs an explicit type annotation.
201+
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:155:11: 'assert' needs an explicit type annotation.
188202
const a = [assert];
189203
a[0](typeof x === "string"); // Error
190204
~~~~
@@ -193,7 +207,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS
193207
t1.assert(typeof x === "string"); // Error
194208
~~~~~~~~~
195209
!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
196-
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:148:11: 't1' needs an explicit type annotation.
210+
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:159:11: 't1' needs an explicit type annotation.
197211
const t2: Test = new Test();
198212
t2.assert(typeof x === "string");
199213
}

tests/baselines/reference/assertionTypePredicates1.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,17 @@ class Test2 extends Test {
128128
z = 0;
129129
}
130130

131+
class Derived extends Test {
132+
foo(x: unknown) {
133+
super.assert(typeof x === "string");
134+
x.length;
135+
}
136+
baz(x: number) {
137+
super.assert(false);
138+
x; // Unreachable
139+
}
140+
}
141+
131142
// Invalid constructs
132143

133144
declare let Q1: new (x: unknown) => x is string;
@@ -293,6 +304,21 @@ var Test2 = /** @class */ (function (_super) {
293304
}
294305
return Test2;
295306
}(Test));
307+
var Derived = /** @class */ (function (_super) {
308+
__extends(Derived, _super);
309+
function Derived() {
310+
return _super !== null && _super.apply(this, arguments) || this;
311+
}
312+
Derived.prototype.foo = function (x) {
313+
_super.prototype.assert.call(this, typeof x === "string");
314+
x.length;
315+
};
316+
Derived.prototype.baz = function (x) {
317+
_super.prototype.assert.call(this, false);
318+
x; // Unreachable
319+
};
320+
return Derived;
321+
}(Test));
296322
function f20(x) {
297323
var assert = function (value) { };
298324
assert(typeof x === "string"); // Error
@@ -332,6 +358,10 @@ declare class Test {
332358
declare class Test2 extends Test {
333359
z: number;
334360
}
361+
declare class Derived extends Test {
362+
foo(x: unknown): void;
363+
baz(x: number): void;
364+
}
335365
declare let Q1: new (x: unknown) => x is string;
336366
declare let Q2: new (x: boolean) => asserts x;
337367
declare let Q3: new (x: unknown) => asserts x is string;

tests/baselines/reference/assertionTypePredicates1.symbols

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -359,81 +359,114 @@ class Test2 extends Test {
359359
>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26))
360360
}
361361

362+
class Derived extends Test {
363+
>Derived : Symbol(Derived, Decl(assertionTypePredicates1.ts, 127, 1))
364+
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
365+
366+
foo(x: unknown) {
367+
>foo : Symbol(Derived.foo, Decl(assertionTypePredicates1.ts, 129, 28))
368+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8))
369+
370+
super.assert(typeof x === "string");
371+
>super.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
372+
>super : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
373+
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
374+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8))
375+
376+
x.length;
377+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
378+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8))
379+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
380+
}
381+
baz(x: number) {
382+
>baz : Symbol(Derived.baz, Decl(assertionTypePredicates1.ts, 133, 5))
383+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 134, 8))
384+
385+
super.assert(false);
386+
>super.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
387+
>super : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
388+
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
389+
390+
x; // Unreachable
391+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 134, 8))
392+
}
393+
}
394+
362395
// Invalid constructs
363396

364397
declare let Q1: new (x: unknown) => x is string;
365-
>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 131, 11))
366-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21))
367-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21))
398+
>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 142, 11))
399+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21))
400+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21))
368401

369402
declare let Q2: new (x: boolean) => asserts x;
370-
>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 132, 11))
371-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21))
372-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21))
403+
>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 143, 11))
404+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21))
405+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21))
373406

374407
declare let Q3: new (x: unknown) => asserts x is string;
375-
>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 133, 11))
376-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21))
377-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21))
408+
>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 144, 11))
409+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21))
410+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21))
378411

379412
declare class Wat {
380-
>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 133, 56))
413+
>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 144, 56))
381414

382415
get p1(): this is string;
383-
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29))
416+
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29))
384417

385418
set p1(x: this is string);
386-
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29))
387-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 137, 11))
419+
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29))
420+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 148, 11))
388421

389422
get p2(): asserts this is string;
390-
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37))
423+
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37))
391424

392425
set p2(x: asserts this is string);
393-
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37))
394-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 139, 11))
426+
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37))
427+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 150, 11))
395428
}
396429

397430
function f20(x: unknown) {
398-
>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 140, 1))
399-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13))
431+
>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 151, 1))
432+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
400433

401434
const assert = (value: unknown): asserts value => {}
402-
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9))
403-
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20))
404-
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20))
435+
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
436+
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20))
437+
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20))
405438

406439
assert(typeof x === "string"); // Error
407-
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9))
408-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13))
440+
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
441+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
409442

410443
const a = [assert];
411-
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9))
412-
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9))
444+
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9))
445+
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
413446

414447
a[0](typeof x === "string"); // Error
415-
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9))
416-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13))
448+
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9))
449+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
417450

418451
const t1 = new Test();
419-
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9))
452+
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9))
420453
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
421454

422455
t1.assert(typeof x === "string"); // Error
423456
>t1.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
424-
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9))
457+
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9))
425458
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
426-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13))
459+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
427460

428461
const t2: Test = new Test();
429-
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 9))
462+
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9))
430463
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
431464
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
432465

433466
t2.assert(typeof x === "string");
434467
>t2.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
435-
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 9))
468+
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9))
436469
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
437-
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13))
470+
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
438471
}
439472

tests/baselines/reference/assertionTypePredicates1.types

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,45 @@ class Test2 extends Test {
463463
>0 : 0
464464
}
465465

466+
class Derived extends Test {
467+
>Derived : Derived
468+
>Test : Test
469+
470+
foo(x: unknown) {
471+
>foo : (x: unknown) => void
472+
>x : unknown
473+
474+
super.assert(typeof x === "string");
475+
>super.assert(typeof x === "string") : void
476+
>super.assert : (value: unknown) => asserts value
477+
>super : Test
478+
>assert : (value: unknown) => asserts value
479+
>typeof x === "string" : boolean
480+
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
481+
>x : unknown
482+
>"string" : "string"
483+
484+
x.length;
485+
>x.length : number
486+
>x : string
487+
>length : number
488+
}
489+
baz(x: number) {
490+
>baz : (x: number) => void
491+
>x : number
492+
493+
super.assert(false);
494+
>super.assert(false) : void
495+
>super.assert : (value: unknown) => asserts value
496+
>super : Test
497+
>assert : (value: unknown) => asserts value
498+
>false : false
499+
500+
x; // Unreachable
501+
>x : number
502+
}
503+
}
504+
466505
// Invalid constructs
467506

468507
declare let Q1: new (x: unknown) => x is string;

tests/baselines/reference/neverReturningFunctions1.errors.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,21 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS
301301
return f * this.data.num * this.system!.data.counter;
302302
}
303303
});
304+
305+
// Repro from #36147
306+
307+
class MyThrowable {
308+
throw(): never {
309+
throw new Error();
310+
}
311+
}
312+
313+
class SuperThrowable extends MyThrowable {
314+
err(msg: string): never {
315+
super.throw()
316+
}
317+
ok(): never {
318+
this.throw()
319+
}
320+
}
304321

0 commit comments

Comments
 (0)