Skip to content

Commit

Permalink
Addresses CR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
tinganho committed Jun 7, 2015
1 parent 487dff5 commit 4a14e61
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 75 deletions.
41 changes: 31 additions & 10 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8601,15 +8601,16 @@ module ts {
}
}

function isInATypePredicateCompatiblePosition(node: Node): boolean {
function isInLegalTypePredicatePosition(node: Node): boolean {
switch (node.parent.kind) {
case SyntaxKind.ArrowFunction:
case SyntaxKind.CallSignature:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionType:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return true;
return node === (<SignatureDeclaration>node.parent).type;
}
return false;
}
Expand All @@ -8634,11 +8635,11 @@ module ts {
if (node.type.kind === SyntaxKind.TypePredicate) {
let typePredicate = getSignatureFromDeclaration(node).typePredicate;
let typePredicateNode = <TypePredicateNode>node.type;
if (isInATypePredicateCompatiblePosition(typePredicateNode)) {
if (isInLegalTypePredicatePosition(typePredicateNode)) {
if (typePredicate.parameterIndex >= 0) {
if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) {
error(typePredicateNode.parameterName,
Diagnostics.Type_predicate_cannot_reference_a_spread_parameter);
Diagnostics.Type_predicate_cannot_reference_a_rest_parameter);
}
else {
checkTypeAssignableTo(typePredicate.type,
Expand All @@ -8647,14 +8648,34 @@ module ts {
}
}
else if (typePredicateNode.parameterName) {
error(typePredicateNode.parameterName,
Diagnostics.Cannot_find_parameter_0,
typePredicate.parameterName);
let hasReportedError = false;
outer: for (let param of node.parameters) {
if (param.name.kind === SyntaxKind.ObjectBindingPattern ||
param.name.kind === SyntaxKind.ArrayBindingPattern) {

for (let element of (<BindingPattern>param.name).elements) {
if (element.name.kind === SyntaxKind.Identifier &&
(<Identifier>element.name).text === typePredicateNode.parameterName.text) {

error(typePredicateNode.parameterName,
Diagnostics.Type_predicate_cannot_reference_element_0_in_a_binding_pattern,
typePredicate.parameterName);
hasReportedError = true;
break outer;
}
}
}
}
if (!hasReportedError) {
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);
Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods);
}
}
else {
Expand Down Expand Up @@ -11295,8 +11316,8 @@ 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);
if(!isInLegalTypePredicatePosition(node)) {
error(node, Diagnostics.Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,9 @@ 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_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." },
Type_predicates_are_only_allowed_in_return_type_position_for_functions_and_methods: { code: 1228, category: DiagnosticCategory.Error, key: "Type predicates are only allowed in return type position for functions and methods." },
Type_predicate_cannot_reference_a_rest_parameter: { code: 1229, category: DiagnosticCategory.Error, key: "Type predicate cannot reference a rest parameter." },
Type_predicate_cannot_reference_element_0_in_a_binding_pattern: { code: 1230, category: DiagnosticCategory.Error, key: "Type predicate cannot reference element '{0}' in a binding pattern." },
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
8 changes: 6 additions & 2 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -719,14 +719,18 @@
"category": "Error",
"code": 1227
},
"Type predicates are only allowed in return type position for arrow functions, function expressions, function declarations, function types and method declarations.": {
"Type predicates are only allowed in return type position for functions and methods.": {
"category": "Error",
"code": 1228
},
"Type predicate cannot reference a spread parameter.": {
"Type predicate cannot reference a rest parameter.": {
"category": "Error",
"code": 1229
},
"Type predicate cannot reference element '{0}' in a binding pattern.": {
"category": "Error",
"code": 1230
},


"Duplicate identifier '{0}'.": {
Expand Down
5 changes: 5 additions & 0 deletions tests/baselines/reference/typeGuardFunction.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ if(isA(union)) {
union.propA;
}

// Call signature
interface I1 {
(p1: A): p1 is C;
}

// The parameter index and argument index for the type guard target is matching.
// The type predicate type is assignable to the parameter type.
declare function isC_multipleParams(p1, p2): p1 is C;
Expand Down
66 changes: 38 additions & 28 deletions tests/baselines/reference/typeGuardFunction.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,26 @@ if(isA(union)) {
>propA : Symbol(A.propA, Decl(typeGuardFunction.ts, 1, 9))
}

// Call signature
interface I1 {
>I1 : Symbol(I1, Decl(typeGuardFunction.ts, 37, 1))

(p1: A): p1 is C;
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 5))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))
}

// The parameter index and argument index for the type guard target is matching.
// The type predicate type is assignable to the parameter type.
declare function isC_multipleParams(p1, p2): p1 is C;
>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 41, 36))
>p2 : Symbol(p2, Decl(typeGuardFunction.ts, 41, 39))
>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 42, 1))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 46, 36))
>p2 : Symbol(p2, Decl(typeGuardFunction.ts, 46, 39))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

if (isC_multipleParams(a, 0)) {
>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 37, 1))
>isC_multipleParams : Symbol(isC_multipleParams, Decl(typeGuardFunction.ts, 42, 1))
>a : Symbol(a, Decl(typeGuardFunction.ts, 19, 3))

a.propC;
Expand All @@ -111,20 +121,20 @@ if (isC_multipleParams(a, 0)) {

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

func1(p1: A): p1 is C;
>func1 : Symbol(func1, Decl(typeGuardFunction.ts, 47, 10))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 48, 10))
>func1 : Symbol(func1, Decl(typeGuardFunction.ts, 52, 10))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 53, 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))
>D : Symbol(D, Decl(typeGuardFunction.ts, 54, 1))

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

Expand All @@ -134,23 +144,23 @@ class D {

// 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))
>f1 : Symbol(f1, Decl(typeGuardFunction.ts, 62, 3))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 62, 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))
>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 62, 35))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 65, 20))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 65, 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))
>f2 : Symbol(f2, Decl(typeGuardFunction.ts, 62, 35))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 68, 12))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))
>C : Symbol(C, Decl(typeGuardFunction.ts, 7, 1))

Expand All @@ -159,35 +169,35 @@ f2(function(p1: A): p1 is C {

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

acceptingBoolean(isA(a));
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 65, 3))
>acceptingBoolean : Symbol(acceptingBoolean, Decl(typeGuardFunction.ts, 70, 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, 69, 25))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 72, 44))
>item : Symbol(item, Decl(typeGuardFunction.ts, 72, 49))
>acceptingTypeGuardFunction : Symbol(acceptingTypeGuardFunction, Decl(typeGuardFunction.ts, 74, 25))
>p1 : Symbol(p1, Decl(typeGuardFunction.ts, 77, 44))
>item : Symbol(item, Decl(typeGuardFunction.ts, 77, 49))
>A : Symbol(A, Decl(typeGuardFunction.ts, 0, 0))

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

// Binary expressions
let union2: C | B;
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 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, 77, 3))
>union3 : Symbol(union3, Decl(typeGuardFunction.ts, 82, 3))
>B : Symbol(B, Decl(typeGuardFunction.ts, 3, 1))
>isA : Symbol(isA, Decl(typeGuardFunction.ts, 11, 1))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 76, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 3))
>union2 : Symbol(union2, Decl(typeGuardFunction.ts, 81, 3))

11 changes: 11 additions & 0 deletions tests/baselines/reference/typeGuardFunction.types
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ if(isA(union)) {
>propA : number
}

// Call signature
interface I1 {
>I1 : I1

(p1: A): p1 is C;
>p1 : A
>A : A
>p1 : any
>C : C
}

// The parameter index and argument index for the type guard target is matching.
// The type predicate type is assignable to the parameter type.
declare function isC_multipleParams(p1, p2): p1 is C;
Expand Down
Loading

0 comments on commit 4a14e61

Please sign in to comment.