Skip to content

Commit

Permalink
Make type guard function types invariant in the type guarded for.
Browse files Browse the repository at this point in the history
Fix one break in the compiler, and add a workaround to test case
thisPredicateFunctionQuickInfo01, which used a code pattern that no
longer works.

Fixes microsoft#26981.
  • Loading branch information
mattmccutchen committed Oct 16, 2018
1 parent eb2297d commit 7702c41
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 206 deletions.
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11098,7 +11098,10 @@ namespace ts {
}
}

const related = compareTypes(source.type, target.type, reportErrors);
let related = compareTypes(source.type, target.type, reportErrors);
if (related) {
related &= compareTypes(target.type, source.type, reportErrors);
}
if (related === Ternary.False && reportErrors) {
errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target));
}
Expand Down
2 changes: 1 addition & 1 deletion src/services/documentHighlights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace ts.DocumentHighlights {
case SyntaxKind.SetKeyword:
return getFromAllDeclarations(isAccessor, [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]);
case SyntaxKind.AwaitKeyword:
return useParent(node.parent, isAwaitExpression, getAsyncAndAwaitOccurrences);
return useParent<AwaitExpression>(node.parent, isAwaitExpression, getAsyncAndAwaitOccurrences);
case SyntaxKind.AsyncKeyword:
return highlightSpans(getAsyncAndAwaitOccurrences(node));
case SyntaxKind.YieldKeyword:
Expand Down
108 changes: 59 additions & 49 deletions tests/baselines/reference/typeGuardFunctionErrors.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,60 +17,63 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(41,56)
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(45,56): error TS2677: A type predicate's type must be assignable to its parameter's type.
Type 'T[]' is not assignable to type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(59,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(64,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(69,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(74,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
Type predicate 'p1 is C' is not assignable to 'p1 is B'.
Type 'C' is not assignable to type 'B'.
Property 'propB' is missing in type 'C'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(78,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(60,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(65,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is A'.
Type predicate 'p1 is C' is not assignable to 'p1 is A'.
Type 'A' is not assignable to type 'C'.
Property 'propC' is missing in type 'A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(77,47): error TS2345: Argument of type '(p1: any) => p1 is A' is not assignable to parameter of type '(p1: any) => p1 is C'.
Type predicate 'p1 is A' is not assignable to 'p1 is C'.
Type 'A' is not assignable to type 'C'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'.
Signature '(p1: any, p2: any): boolean' must be a type predicate.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(84,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
Type predicate 'p2 is A' is not assignable to 'p1 is A'.
Parameter 'p2' is not in the same position as parameter 'p1'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(90,1): error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,11): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,14): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,14): error TS2300: Duplicate identifier 'A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,18): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,21): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,22): error TS1144: '{' or ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,25): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,27): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,25): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,9): error TS2322: Type 'true' is not assignable to type 'D'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,9): error TS2409: Return type of constructor signature must be assignable to the instance type of the class.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,1): error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,9): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,11): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,14): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,14): error TS2300: Duplicate identifier 'A'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,16): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,18): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,21): error TS1005: ',' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,20): error TS2304: Cannot find name 'b'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,22): error TS1144: '{' or ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,27): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,25): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,9): error TS2322: Type 'true' is not assignable to type 'D'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,9): error TS2409: Return type of constructor signature must be assignable to the instance type of the class.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(109,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,9): error TS2408: Setters cannot return a value.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,18): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,22): error TS2304: Cannot find name 'p1'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,25): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,28): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,1): error TS1128: Declaration or statement expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(123,20): error TS1229: A type predicate cannot reference a rest parameter.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(128,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(132,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(152,68): error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(113,9): error TS2408: Setters cannot return a value.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(118,18): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,22): error TS2304: Cannot find name 'p1'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,25): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,28): error TS1005: ';' expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(123,1): error TS1128: Declaration or statement expected.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(126,20): error TS1229: A type predicate cannot reference a rest parameter.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(131,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(135,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(139,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(155,68): error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'.
Type '"d"' is not assignable to type 'Keys'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(159,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(162,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
Types of property ''a'' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(162,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(163,35): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(164,51): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(165,51): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,45): error TS2677: A type predicate's type must be assignable to its parameter's type.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(165,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,35): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(167,51): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(168,51): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(169,45): error TS2677: A type predicate's type must be assignable to its parameter's type.
Type 'NeedsFoo<number>' is not assignable to type 'number'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(169,54): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.


==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (56 errors) ====
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (57 errors) ====
class A {
~
!!! error TS2300: Duplicate identifier 'A'.
Expand Down Expand Up @@ -156,6 +159,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54
let a: A;
let b: B;

declare function isA(p1): p1 is A;
declare function isB(p1): p1 is B;
declare function isC(p1): p1 is C;
declare function funA(p1: any, p2: any): p1 is B;
Expand Down Expand Up @@ -186,13 +190,19 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54
}

// Type predicate type is not assignable
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B);
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is A);
acceptingDifferentSignatureTypeGuardFunction(isC);
~~~
!!! error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is B'.
!!! error TS2345: Type 'C' is not assignable to type 'B'.
!!! error TS2345: Property 'propB' is missing in type 'C'.
!!! error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is A'.
!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is A'.
!!! error TS2345: Type 'A' is not assignable to type 'C'.
!!! error TS2345: Property 'propC' is missing in type 'A'.
declare function acceptingDifferentSignatureTypeGuardFunction2(p1: (p1) => p1 is C);
acceptingDifferentSignatureTypeGuardFunction2(isA);
~~~
!!! error TS2345: Argument of type '(p1: any) => p1 is A' is not assignable to parameter of type '(p1: any) => p1 is C'.
!!! error TS2345: Type predicate 'p1 is A' is not assignable to 'p1 is C'.
!!! error TS2345: Type 'A' is not assignable to type 'C'.

// Boolean not assignable to type guard
var assign1: (p1, p2) => p1 is A;
Expand Down
6 changes: 5 additions & 1 deletion tests/baselines/reference/typeGuardFunctionErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function hasNonMathcingGenericType<T>(a: string): a is T[] {
let a: A;
let b: B;

declare function isA(p1): p1 is A;
declare function isB(p1): p1 is B;
declare function isC(p1): p1 is C;
declare function funA(p1: any, p2: any): p1 is B;
Expand All @@ -71,8 +72,10 @@ if (hasNoTypeGuard(a)) {
}

// Type predicate type is not assignable
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B);
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is A);
acceptingDifferentSignatureTypeGuardFunction(isC);
declare function acceptingDifferentSignatureTypeGuardFunction2(p1: (p1) => p1 is C);
acceptingDifferentSignatureTypeGuardFunction2(isA);

// Boolean not assignable to type guard
var assign1: (p1, p2) => p1 is A;
Expand Down Expand Up @@ -240,6 +243,7 @@ if (hasNoTypeGuard(a)) {
a.propB;
}
acceptingDifferentSignatureTypeGuardFunction(isC);
acceptingDifferentSignatureTypeGuardFunction2(isA);
// Boolean not assignable to type guard
var assign1;
assign1 = function (p1, p2) {
Expand Down
Loading

0 comments on commit 7702c41

Please sign in to comment.