From 81750ed9c27a0f16f67908a98094fec97a4a967f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Sun, 3 Jan 2016 06:10:47 -0500 Subject: [PATCH 1/2] Add test --- .../typeGuards/typeGuardOfFormFunctionEquality.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts diff --git a/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts new file mode 100644 index 0000000000000..baff942bb8e10 --- /dev/null +++ b/tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts @@ -0,0 +1,14 @@ +declare function isString1(a: number, b: Object): b is string; + +declare function isString2(a: Object): a is string; + +switch (isString1(0, "")) { + case isString2(""): + default: +} + +var x = isString1(0, "") === isString2(""); + +function isString3(a: number, b: number, c: Object): c is string { + return isString1(0, c); +} From 2dac8ccc6b11e803b3b59ba8b6614bd09739e7f1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Sun, 3 Jan 2016 06:29:47 -0500 Subject: [PATCH 2/2] Fix #6311 by moving predicate argument placement up to signature comparison --- src/compiler/checker.ts | 30 ++++++----- .../typeGuardOfFormFunctionEquality.js | 26 +++++++++ .../typeGuardOfFormFunctionEquality.symbols | 41 ++++++++++++++ .../typeGuardOfFormFunctionEquality.types | 54 +++++++++++++++++++ 4 files changed, 139 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/typeGuardOfFormFunctionEquality.js create mode 100644 tests/baselines/reference/typeGuardOfFormFunctionEquality.symbols create mode 100644 tests/baselines/reference/typeGuardOfFormFunctionEquality.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d57e9d202874..2c5454f0cff3e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5103,17 +5103,6 @@ namespace ts { } return Ternary.False; } - if (sourcePredicate.predicate.kind === TypePredicateKind.Identifier) { - const sourceIdentifierPredicate = sourcePredicate.predicate as IdentifierTypePredicate; - const targetIdentifierPredicate = targetPredicate.predicate as IdentifierTypePredicate; - if (sourceIdentifierPredicate.parameterIndex !== targetIdentifierPredicate.parameterIndex) { - if (reportErrors) { - reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceIdentifierPredicate.parameterName, targetIdentifierPredicate.parameterName); - reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(source), typeToString(target)); - } - return Ternary.False; - } - } const related = isRelatedTo(sourcePredicate.predicate.type, targetPredicate.predicate.type, reportErrors, headMessage); if (related === Ternary.False && reportErrors) { reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(source), typeToString(target)); @@ -5666,7 +5655,24 @@ namespace ts { } } - return result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors); + result = result & isRelatedTo(sourceReturnType, targetReturnType, reportErrors); + if (!(sourceReturnType.flags & TypeFlags.PredicateType && targetReturnType.flags & TypeFlags.PredicateType)) { + return result; + } + const sourcePredicate = sourceReturnType as PredicateType; + const targetPredicate = targetReturnType as PredicateType; + if (sourcePredicate.predicate.kind === TypePredicateKind.Identifier) { + const sourceIdentifierPredicate = sourcePredicate.predicate as IdentifierTypePredicate; + const targetIdentifierPredicate = targetPredicate.predicate as IdentifierTypePredicate; + if (sourceIdentifierPredicate.parameterIndex !== targetIdentifierPredicate.parameterIndex) { + if (reportErrors) { + reportError(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceIdentifierPredicate.parameterName, targetIdentifierPredicate.parameterName); + reportError(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typeToString(sourceReturnType), typeToString(targetReturnType)); + } + return Ternary.False; + } + } + return result; } function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { diff --git a/tests/baselines/reference/typeGuardOfFormFunctionEquality.js b/tests/baselines/reference/typeGuardOfFormFunctionEquality.js new file mode 100644 index 0000000000000..c15c1a739a9e5 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormFunctionEquality.js @@ -0,0 +1,26 @@ +//// [typeGuardOfFormFunctionEquality.ts] +declare function isString1(a: number, b: Object): b is string; + +declare function isString2(a: Object): a is string; + +switch (isString1(0, "")) { + case isString2(""): + default: +} + +var x = isString1(0, "") === isString2(""); + +function isString3(a: number, b: number, c: Object): c is string { + return isString1(0, c); +} + + +//// [typeGuardOfFormFunctionEquality.js] +switch (isString1(0, "")) { + case isString2(""): + default: +} +var x = isString1(0, "") === isString2(""); +function isString3(a, b, c) { + return isString1(0, c); +} diff --git a/tests/baselines/reference/typeGuardOfFormFunctionEquality.symbols b/tests/baselines/reference/typeGuardOfFormFunctionEquality.symbols new file mode 100644 index 0000000000000..f13840501769b --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormFunctionEquality.symbols @@ -0,0 +1,41 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts === +declare function isString1(a: number, b: Object): b is string; +>isString1 : Symbol(isString1, Decl(typeGuardOfFormFunctionEquality.ts, 0, 0)) +>a : Symbol(a, Decl(typeGuardOfFormFunctionEquality.ts, 0, 27)) +>b : Symbol(b, Decl(typeGuardOfFormFunctionEquality.ts, 0, 37)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>b : Symbol(b, Decl(typeGuardOfFormFunctionEquality.ts, 0, 37)) + +declare function isString2(a: Object): a is string; +>isString2 : Symbol(isString2, Decl(typeGuardOfFormFunctionEquality.ts, 0, 62)) +>a : Symbol(a, Decl(typeGuardOfFormFunctionEquality.ts, 2, 27)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>a : Symbol(a, Decl(typeGuardOfFormFunctionEquality.ts, 2, 27)) + +switch (isString1(0, "")) { +>isString1 : Symbol(isString1, Decl(typeGuardOfFormFunctionEquality.ts, 0, 0)) + + case isString2(""): +>isString2 : Symbol(isString2, Decl(typeGuardOfFormFunctionEquality.ts, 0, 62)) + + default: +} + +var x = isString1(0, "") === isString2(""); +>x : Symbol(x, Decl(typeGuardOfFormFunctionEquality.ts, 9, 3)) +>isString1 : Symbol(isString1, Decl(typeGuardOfFormFunctionEquality.ts, 0, 0)) +>isString2 : Symbol(isString2, Decl(typeGuardOfFormFunctionEquality.ts, 0, 62)) + +function isString3(a: number, b: number, c: Object): c is string { +>isString3 : Symbol(isString3, Decl(typeGuardOfFormFunctionEquality.ts, 9, 43)) +>a : Symbol(a, Decl(typeGuardOfFormFunctionEquality.ts, 11, 19)) +>b : Symbol(b, Decl(typeGuardOfFormFunctionEquality.ts, 11, 29)) +>c : Symbol(c, Decl(typeGuardOfFormFunctionEquality.ts, 11, 40)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>c : Symbol(c, Decl(typeGuardOfFormFunctionEquality.ts, 11, 40)) + + return isString1(0, c); +>isString1 : Symbol(isString1, Decl(typeGuardOfFormFunctionEquality.ts, 0, 0)) +>c : Symbol(c, Decl(typeGuardOfFormFunctionEquality.ts, 11, 40)) +} + diff --git a/tests/baselines/reference/typeGuardOfFormFunctionEquality.types b/tests/baselines/reference/typeGuardOfFormFunctionEquality.types new file mode 100644 index 0000000000000..5e5c391107228 --- /dev/null +++ b/tests/baselines/reference/typeGuardOfFormFunctionEquality.types @@ -0,0 +1,54 @@ +=== tests/cases/conformance/expressions/typeGuards/typeGuardOfFormFunctionEquality.ts === +declare function isString1(a: number, b: Object): b is string; +>isString1 : (a: number, b: Object) => b is string +>a : number +>b : Object +>Object : Object +>b : any + +declare function isString2(a: Object): a is string; +>isString2 : (a: Object) => a is string +>a : Object +>Object : Object +>a : any + +switch (isString1(0, "")) { +>isString1(0, "") : b is string +>isString1 : (a: number, b: Object) => b is string +>0 : number +>"" : string + + case isString2(""): +>isString2("") : a is string +>isString2 : (a: Object) => a is string +>"" : string + + default: +} + +var x = isString1(0, "") === isString2(""); +>x : boolean +>isString1(0, "") === isString2("") : boolean +>isString1(0, "") : b is string +>isString1 : (a: number, b: Object) => b is string +>0 : number +>"" : string +>isString2("") : a is string +>isString2 : (a: Object) => a is string +>"" : string + +function isString3(a: number, b: number, c: Object): c is string { +>isString3 : (a: number, b: number, c: Object) => c is string +>a : number +>b : number +>c : Object +>Object : Object +>c : any + + return isString1(0, c); +>isString1(0, c) : b is string +>isString1 : (a: number, b: Object) => b is string +>0 : number +>c : Object +} +