Skip to content

Commit

Permalink
Fixes CR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
tinganho committed Jun 6, 2015
1 parent fa9a914 commit 487dff5
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 58 deletions.
54 changes: 37 additions & 17 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5642,13 +5642,13 @@ module ts {
}

if (targetType) {
return getOptionalNarrowedType(type, targetType);
return getNarrowedType(type, targetType);
}

return type;
}

function getOptionalNarrowedType(originalType: Type, narrowedTypeCandidate: Type) {
function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type) {
// Narrow to the target type if it's a subtype of the current type
if (isTypeSubtypeOf(narrowedTypeCandidate, originalType)) {
return narrowedTypeCandidate;
Expand All @@ -5675,7 +5675,7 @@ module ts {
}
return type;
}
return getOptionalNarrowedType(type, signature.typePredicate.type);
return getNarrowedType(type, signature.typePredicate.type);
}
return type;
}
Expand Down Expand Up @@ -8601,6 +8601,19 @@ module ts {
}
}

function isInATypePredicateCompatiblePosition(node: Node): boolean {
switch (node.parent.kind) {
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionType:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return true;
}
return false;
}

function checkSignatureDeclaration(node: SignatureDeclaration) {
// Grammar checking
if (node.kind === SyntaxKind.IndexSignature) {
Expand All @@ -8621,22 +8634,28 @@ module ts {
if (node.type.kind === SyntaxKind.TypePredicate) {
let typePredicate = getSignatureFromDeclaration(node).typePredicate;
let typePredicateNode = <TypePredicateNode>node.type;
if (typePredicateNode.type.kind === SyntaxKind.TypePredicate) {
error(typePredicateNode.type,
Diagnostics.Type_predicates_are_only_allowed_in_return_type_position);
}
else {
if (isInATypePredicateCompatiblePosition(typePredicateNode)) {
if (typePredicate.parameterIndex >= 0) {
checkTypeAssignableTo(typePredicate.type,
getTypeAtLocation(node.parameters[typePredicate.parameterIndex]),
typePredicateNode.type);
if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) {
error(typePredicateNode.parameterName,
Diagnostics.Type_predicate_cannot_reference_a_spread_parameter);
}
else {
checkTypeAssignableTo(typePredicate.type,
getTypeAtLocation(node.parameters[typePredicate.parameterIndex]),
typePredicateNode.type);
}
}
else if (typePredicateNode.parameterName) {
error(typePredicateNode.parameterName,
Diagnostics.Cannot_find_parameter_0,
typePredicate.parameterName);
}
}
else {
error(typePredicateNode,
Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations);
}
}
else {
checkSourceElement(node.type);
Expand Down Expand Up @@ -11275,6 +11294,12 @@ module ts {
}
}

function checkTypePredicate(node: TypePredicateNode) {
if(!isInATypePredicateCompatiblePosition(node)) {
error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations);
}
}

function checkSourceElement(node: Node): void {
if (!node) return;
switch (node.kind) {
Expand Down Expand Up @@ -11303,12 +11328,7 @@ module ts {
case SyntaxKind.TypeReference:
return checkTypeReferenceNode(<TypeReferenceNode>node);
case SyntaxKind.TypePredicate:
// Issue an error every time we encounter a type predicate. They are only allowed
// in return type positions in signature declarations. checkSignatureDeclaration(..)
// already have a specific check for type predicates, so every time we encounter a type
// predicate in checkSourceElement it must be in a non return type position.
error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position);
return;
return checkTypePredicate(<TypePredicateNode>node);
case SyntaxKind.TypeQuery:
return checkTypeQuery(<TypeQueryNode>node);
case SyntaxKind.TypeLiteral:
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ module ts {
Cannot_find_parameter_0: { code: 1225, category: DiagnosticCategory.Error, key: "Cannot find parameter '{0}'." },
Type_predicate_0_is_not_assignable_to_1: { code: 1226, category: DiagnosticCategory.Error, key: "Type predicate '{0}' is not assignable to '{1}'." },
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}'." },
Type_predicates_are_only_allowed_in_return_type_position: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position." },
Type_predicates_are_only_allowed_in_return_type_position_for_arrow_functions_function_expressions_function_declarations_function_types_and_method_declarations: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations." },
Type_predicate_cannot_reference_a_spread_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a spread parameter." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
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." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -719,10 +719,14 @@
"category": "Error",
"code": 1227
},
"Type predicates are only allowed in return type position.": {
"Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations.": {
"category": "Error",
"code": 1228
},
"Type predicate cannot reference a spread parameter.": {
"category": "Error",
"code": 1229
},


"Duplicate identifier '{0}'.": {
Expand Down
51 changes: 45 additions & 6 deletions tests/baselines/reference/typeGuardFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ declare function retC(): C;
var a: A;
var b: B;

// Basic.
// Basic
if (isC(a)) {
a.propC;
}

// Sub type.
// Sub type
var subType: C;
if(isA(subType)) {
subType.propC;
}

// Union type.
// Union type
var union: A | B;
if(isA(union)) {
union.propA;
Expand All @@ -45,6 +45,27 @@ if (isC_multipleParams(a, 0)) {
a.propC;
}

// Methods
var obj: {
func1(p1: A): p1 is C;
}
class D {
method1(p1: A): p1 is C {
return true;
}
}

// Arrow function
let f1 = (p1: A): p1 is C => false;

// Function type
declare function f2(p1: (p1: A) => p1 is C);

// Function expressions
f2(function(p1: A): p1 is C {
return true;
});

// Evaluations are asssignable to boolean.
declare function acceptingBoolean(a: boolean);
acceptingBoolean(isA(a));
Expand All @@ -53,6 +74,7 @@ acceptingBoolean(isA(a));
declare function acceptingTypeGuardFunction(p1: (item) => item is A);
acceptingTypeGuardFunction(isA);

// Binary expressions
let union2: C | B;
let union3: boolean | B = isA(union2) || union2;

Expand Down Expand Up @@ -82,24 +104,41 @@ var C = (function (_super) {
})(A);
var a;
var b;
// Basic.
// Basic
if (isC(a)) {
a.propC;
}
// Sub type.
// Sub type
var subType;
if (isA(subType)) {
subType.propC;
}
// Union type.
// Union type
var union;
if (isA(union)) {
union.propA;
}
if (isC_multipleParams(a, 0)) {
a.propC;
}
// Methods
var obj;
var D = (function () {
function D() {
}
D.prototype.method1 = function (p1) {
return true;
};
return D;
})();
// Arrow function
var f1 = function (p1) { return false; };
// Function expressions
f2(function (p1) {
return true;
});
acceptingBoolean(isA(a));
acceptingTypeGuardFunction(isA);
// Binary expressions
var union2;
var union3 = isA(union2) || union2;
77 changes: 63 additions & 14 deletions tests/baselines/reference/typeGuardFunction.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var b: B;
>b : Symbol(b, Decl(typeGuardFunction.ts, 20, 3))
>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1))

// Basic.
// Basic
if (isC(a)) {
>isC : Symbol(isC, Decl(typeGuardFunction.ts, 14, 39))
>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3))
Expand All @@ -60,7 +60,7 @@ if (isC(a)) {
>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19))
}

// Sub type.
// Sub type
var subType: C;
>subType : Symbol(subType, Decl(typeGuardFunction.ts, 28, 3))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))
Expand All @@ -75,7 +75,7 @@ if(isA(subType)) {
>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19))
}

// Union type.
// Union type
var union: A | B;
>union : Symbol(union, Decl(typeGuardFunction.ts, 34, 3))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
Expand Down Expand Up @@ -109,36 +109,85 @@ if (isC_multipleParams(a, 0)) {
>propC : Symbol(C.propC, Decl(typeGuardFunction.ts, 9, 19))
}

// Methods
var obj: {
>obj : Symbol(obj, Decl(typeGuardFunction.ts, 47, 3))

func1(p1: A): p1 is C;
>func1 : Symbol(func1, Decl(typeGuardFunction.ts, 47, 10))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 48, 10))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))
}
class D {
>D : Symbol(D, Decl(typeGuardFunction.ts, 49, 1))

method1(p1: A): p1 is C {
>method1 : Symbol(method1, Decl(typeGuardFunction.ts, 50, 9))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 12))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

return true;
}
}

// Arrow function
let f1 = (p1: A): p1 is C => false;
>f1 : Symbol(f1, Decl(typeGuardFunction.ts, 57, 3))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 57, 10))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

// Function type
declare function f2(p1: (p1: A) => p1 is C);
>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 20))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 60, 25))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

// Function expressions
f2(function(p1: A): p1 is C {
>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 57, 35))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 63, 12))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

return true;
});

// Evaluations are asssignable to boolean.
declare function acceptingBoolean(a: boolean);
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1))
>a : Symbol(a, Decl(typeGuardFunction.ts, 47, 34))
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3))
>a : Symbol(a, Decl(typeGuardFunction.ts, 68, 34))

acceptingBoolean(isA(a));
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 44, 1))
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3))
>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1))
>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3))

// Type predicates with different parameter name.
declare function acceptingTypeGuardFunction(p1: (item) => item is A);
>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 51, 44))
>item : Symbol(item, Decl(typeGuardFunction.ts, 51, 49))
>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 72, 44))
>item : Symbol(item, Decl(typeGuardFunction.ts, 72, 49))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))

acceptingTypeGuardFunction(isA);
>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 48, 25))
>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 69, 25))
>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1))

// Binary expressions
let union2: C | B;
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))
>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1))

let union3: boolean | B = isA(union2) || union2;
>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 55, 3))
>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 77, 3))
>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1))
>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 54, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))

Loading

0 comments on commit 487dff5

Please sign in to comment.