Skip to content

Commit fa9a914

Browse files
committed
Adds error for non-return positioned type predicates and changed parse type predicate logic
1 parent a73bf31 commit fa9a914

File tree

8 files changed

+65
-32
lines changed

8 files changed

+65
-32
lines changed

src/compiler/checker.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -8623,8 +8623,7 @@ module ts {
86238623
let typePredicateNode = <TypePredicateNode>node.type;
86248624
if (typePredicateNode.type.kind === SyntaxKind.TypePredicate) {
86258625
error(typePredicateNode.type,
8626-
Diagnostics.Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate,
8627-
getTextOfNode(typePredicateNode.type));
8626+
Diagnostics.Type_predicates_are_only_allowed_in_return_type_position);
86288627
}
86298628
else {
86308629
if (typePredicate.parameterIndex >= 0) {
@@ -11303,6 +11302,13 @@ module ts {
1130311302
return checkAccessorDeclaration(<AccessorDeclaration>node);
1130411303
case SyntaxKind.TypeReference:
1130511304
return checkTypeReferenceNode(<TypeReferenceNode>node);
11305+
case SyntaxKind.TypePredicate:
11306+
// Issue an error every time we encounter a type predicate. They are only allowed
11307+
// in return type positions in signature declarations. checkSignatureDeclaration(..)
11308+
// already have a specific check for type predicates, so every time we encounter a type
11309+
// predicate in checkSourceElement it must be in a non return type position.
11310+
error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position);
11311+
return;
1130611312
case SyntaxKind.TypeQuery:
1130711313
return checkTypeQuery(<TypeQueryNode>node);
1130811314
case SyntaxKind.TypeLiteral:

src/compiler/diagnosticInformationMap.generated.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ module ts {
183183
Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." },
184184
Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." },
185185
Parameter_0_is_not_in_the_same_position_as_parameter_1: { code: 1227, category: DiagnosticCategory.Error, key: "Parameter '{0}' is not in the same position as parameter '{1}'." },
186-
Cannot_define_type_predicate_0_as_a_type_to_a_type_predicate: { code: 1228, category: DiagnosticCategory.Error, key: "Cannot define type predicate '{0}' as a type to a type predicate." },
186+
Type_predicates_are_only_allowed_in_return_type_position: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position." },
187187
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
188188
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
189189
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@
719719
"category": "Error",
720720
"code": 1227
721721
},
722-
"Cannot define type predicate '{0}' as a type to a type predicate.": {
722+
"Type predicates are only allowed in return type position.": {
723723
"category": "Error",
724724
"code": 1228
725725
},

src/compiler/parser.ts

+14-22
Original file line numberDiff line numberDiff line change
@@ -1900,9 +1900,17 @@ module ts {
19001900

19011901
// TYPES
19021902

1903-
function parseTypeReference(): TypeReferenceNode {
1904-
let node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference);
1905-
node.typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected);
1903+
function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode {
1904+
let typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected);
1905+
if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword) {
1906+
nextToken();
1907+
let node = <TypePredicateNode>createNode(SyntaxKind.TypePredicate, typeName.pos);
1908+
node.parameterName = <Identifier>typeName;
1909+
node.type = parseType();
1910+
return finishNode(node);
1911+
}
1912+
let node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference, typeName.pos);
1913+
node.typeName = typeName;
19061914
if (!scanner.hasPrecedingLineBreak() && token === SyntaxKind.LessThanToken) {
19071915
node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
19081916
}
@@ -2339,7 +2347,7 @@ module ts {
23392347
case SyntaxKind.SymbolKeyword:
23402348
// If these are followed by a dot, then parse these out as a dotted type reference instead.
23412349
let node = tryParse(parseKeywordAndNoDot);
2342-
return node || parseTypeReference();
2350+
return node || parseTypeReferenceOrTypePredicate();
23432351
case SyntaxKind.VoidKeyword:
23442352
return parseTokenNode<TypeNode>();
23452353
case SyntaxKind.TypeOfKeyword:
@@ -2351,7 +2359,7 @@ module ts {
23512359
case SyntaxKind.OpenParenToken:
23522360
return parseParenthesizedType();
23532361
default:
2354-
return parseTypeReference();
2362+
return parseTypeReferenceOrTypePredicate();
23552363
}
23562364
}
23572365

@@ -2464,22 +2472,6 @@ module ts {
24642472

24652473
return result;
24662474
}
2467-
2468-
function parseTypePredicateOrHigher(): TypeNode {
2469-
let type = parseUnionTypeOrHigher();
2470-
if (token === SyntaxKind.IsKeyword &&
2471-
type.kind === SyntaxKind.TypeReference &&
2472-
(<TypeReferenceNode>type).typeName.kind === SyntaxKind.Identifier) {
2473-
2474-
nextToken();
2475-
2476-
let typePredicate = <TypePredicateNode>createNode(SyntaxKind.TypePredicate, type.pos);
2477-
typePredicate.parameterName = <Identifier>(<TypeReferenceNode>type).typeName;
2478-
typePredicate.type = parseType();
2479-
return finishNode(typePredicate);
2480-
}
2481-
return type;
2482-
}
24832475

24842476
function parseTypeWorker(): TypeNode {
24852477
if (isStartOfFunctionType()) {
@@ -2488,7 +2480,7 @@ module ts {
24882480
if (token === SyntaxKind.NewKeyword) {
24892481
return parseFunctionOrConstructorType(SyntaxKind.ConstructorType);
24902482
}
2491-
return parseTypePredicateOrHigher();
2483+
return parseUnionTypeOrHigher();
24922484
}
24932485

24942486
function parseTypeAnnotation(): TypeNode {

src/compiler/types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,6 @@ module ts {
464464
typeParameters?: NodeArray<TypeParameterDeclaration>;
465465
parameters: NodeArray<ParameterDeclaration>;
466466
type?: TypeNode;
467-
typePredicate?: TypePredicateNode;
468467
}
469468

470469
// SyntaxKind.VariableDeclaration

tests/baselines/reference/typeGuardFunctionErrors.errors.txt

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'boolean'.
2-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate.
2+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS1228: Type predicates are only allowed in return type position.
33
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'.
44
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,10): error TS2391: Function implementation is missing or not immediately following the declaration.
55
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(27,5): error TS1131: Property or signature expected.
@@ -22,9 +22,12 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1):
2222
Parameter 'p2' is not in the same position as parameter 'p1'.
2323
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any, p3: any) => boolean' is not assignable to type '(p1: any, p2: any) => boolean'.
2424
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56): error TS1225: Cannot find parameter 'p1'.
25+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS1228: Type predicates are only allowed in return type position.
26+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS1228: Type predicates are only allowed in return type position.
27+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS1228: Type predicates are only allowed in return type position.
2528

2629

27-
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (18 errors) ====
30+
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (21 errors) ====
2831

2932
class A {
3033
propA: number;
@@ -46,7 +49,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56)
4649

4750
function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A {
4851
~~~~~~
49-
!!! error TS1228: Cannot define type predicate 'x is A' as a type to a type predicate.
52+
!!! error TS1228: Type predicates are only allowed in return type position.
5053
return true;
5154
}
5255

@@ -159,4 +162,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(92,56)
159162
declare function destructureParameter({ p1, p2, p3 }): p1 is A;
160163
~~
161164
!!! error TS1225: Cannot find parameter 'p1'.
162-
165+
166+
// Type predicates in non-return type positions
167+
var b1: b is A;
168+
~~~~~~
169+
!!! error TS1228: Type predicates are only allowed in return type position.
170+
function b2(a: b is A) {};
171+
~~~~~~
172+
!!! error TS1228: Type predicates are only allowed in return type position.
173+
function b3(): A | b is A {
174+
~~~~~~
175+
!!! error TS1228: Type predicates are only allowed in return type position.
176+
return true;
177+
};

tests/baselines/reference/typeGuardFunctionErrors.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ assign3 = function(p1, p2, p3): p1 is A {
9191

9292
// Type guard paramater referring to a binding pattern
9393
declare function destructureParameter({ p1, p2, p3 }): p1 is A;
94-
94+
95+
// Type predicates in non-return type positions
96+
var b1: b is A;
97+
function b2(a: b is A) {};
98+
function b3(): A | b is A {
99+
return true;
100+
};
95101

96102
//// [typeGuardFunctionErrors.js]
97103
var __extends = (this && this.__extends) || function (d, b) {
@@ -169,3 +175,11 @@ var assign3;
169175
assign3 = function (p1, p2, p3) {
170176
return true;
171177
};
178+
// Type predicates in non-return type positions
179+
var b1;
180+
function b2(a) { }
181+
;
182+
function b3() {
183+
return true;
184+
}
185+
;

tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts

+7
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,10 @@ assign3 = function(p1, p2, p3): p1 is A {
9090

9191
// Type guard paramater referring to a binding pattern
9292
declare function destructureParameter({ p1, p2, p3 }): p1 is A;
93+
94+
// Type predicates in non-return type positions
95+
var b1: b is A;
96+
function b2(a: b is A) {};
97+
function b3(): A | b is A {
98+
return true;
99+
};

0 commit comments

Comments
 (0)