From d8ecd8cdc6653eae3059ebfbfbe66c7de8f5d797 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 24 Nov 2014 08:31:04 -0800 Subject: [PATCH] Fixed bug in union type identity comparison --- src/compiler/checker.ts | 61 +++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 00968b255a2..0ffb7917500 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3352,12 +3352,9 @@ module ts { // Ternary.False if they are not related. function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary { var result: Ternary; - if (relation === identityRelation) { - // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases - if (source === target) return Ternary.True; - } - else { - if (source === target) return Ternary.True; + // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases + if (source === target) return Ternary.True; + if (relation !== identityRelation) { if (target.flags & TypeFlags.Any) return Ternary.True; if (source === undefinedType) return Ternary.True; if (source === nullType && target !== undefinedType) return Ternary.True; @@ -3368,14 +3365,37 @@ module ts { if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; } } - if (source.flags & TypeFlags.Union) { - if (result = unionTypeRelatedToType(source, target, reportErrors)) { - return result; + if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) { + if (relation === identityRelation) { + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToUnionType(source, target)) { + if (result &= unionTypeRelatedToUnionType(target, source)) { + return result; + } + } + } + else if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = unionTypeRelatedToType(target, source, reportErrors)) { + return result; + } + } } - } - else if (target.flags & TypeFlags.Union) { - if (result = typeRelatedToUnionType(source, target, reportErrors)) { - return result; + else { + if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = typeRelatedToUnionType(source, target, reportErrors)) { + return result; + } + } } } else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) { @@ -3409,6 +3429,19 @@ module ts { return Ternary.False; } + function unionTypeRelatedToUnionType(source: UnionType, target: UnionType): Ternary { + var result = Ternary.True; + var sourceTypes = source.types; + for (var i = 0, len = sourceTypes.length; i < len; i++) { + var related = typeRelatedToUnionType(sourceTypes[i], target, false); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary { var targetTypes = target.types; for (var i = 0, len = targetTypes.length; i < len; i++) { @@ -3479,7 +3512,7 @@ module ts { if (overflow) { return Ternary.False; } - var id = source.id + "," + target.id; + var id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id; var related = relation[id]; if (related !== undefined) { return related ? Ternary.True : Ternary.False;