@@ -1157,7 +1157,7 @@ module ts {
11571157 }
11581158 }
11591159
1160- function writeTypeList ( types : Type [ ] , union ? : boolean ) {
1160+ function writeTypeList ( types : Type [ ] , union : boolean ) {
11611161 for ( var i = 0 ; i < types . length ; i ++ ) {
11621162 if ( i > 0 ) {
11631163 if ( union ) {
@@ -1166,6 +1166,8 @@ module ts {
11661166 writePunctuation ( writer , union ? SyntaxKind . BarToken : SyntaxKind . CommaToken ) ;
11671167 writeSpace ( writer ) ;
11681168 }
1169+ // Don't output function type literals in unions because '() => string | () => number' would be parsed
1170+ // as a function type that returns a union type. Instead output '{ (): string; } | { (): number; }'.
11691171 writeType ( types [ i ] , /*allowFunctionOrConstructorTypeLiteral*/ ! union ) ;
11701172 }
11711173 }
@@ -1181,14 +1183,14 @@ module ts {
11811183 else {
11821184 writeSymbol ( type . target . symbol , writer , enclosingDeclaration , SymbolFlags . Type ) ;
11831185 writePunctuation ( writer , SyntaxKind . LessThanToken ) ;
1184- writeTypeList ( type . typeArguments ) ;
1186+ writeTypeList ( type . typeArguments , /*union*/ false ) ;
11851187 writePunctuation ( writer , SyntaxKind . GreaterThanToken ) ;
11861188 }
11871189 }
11881190
11891191 function writeTupleType ( type : TupleType ) {
11901192 writePunctuation ( writer , SyntaxKind . OpenBracketToken ) ;
1191- writeTypeList ( type . elementTypes ) ;
1193+ writeTypeList ( type . elementTypes , /*union*/ false ) ;
11921194 writePunctuation ( writer , SyntaxKind . CloseBracketToken ) ;
11931195 }
11941196
@@ -1744,7 +1746,7 @@ module ts {
17441746 function getTypeOfUnionProperty ( symbol : Symbol ) : Type {
17451747 var links = getSymbolLinks ( symbol ) ;
17461748 if ( ! links . type ) {
1747- var types = map ( links . unionType . types , t => getTypeOfSymbol ( getPropertyOfType ( getApparentType ( t ) , symbol . name ) || undefinedSymbol ) ) ;
1749+ var types = map ( links . unionType . types , t => getTypeOfSymbol ( getPropertyOfType ( getApparentType ( t ) , symbol . name ) ) ) ;
17481750 links . type = getUnionType ( types ) ;
17491751 }
17501752 return links . type ;
@@ -2069,25 +2071,37 @@ module ts {
20692071 }
20702072
20712073 function signatureListsIdentical ( s : Signature [ ] , t : Signature [ ] ) : boolean {
2072- if ( s . length !== t . length ) return false ;
2074+ if ( s . length !== t . length ) {
2075+ return false ;
2076+ }
20732077 for ( var i = 0 ; i < s . length ; i ++ ) {
2074- if ( ! compareSignatures ( s [ i ] , t [ i ] , false , isTypeIdenticalTo ) ) return false ;
2078+ if ( ! compareSignatures ( s [ i ] , t [ i ] , /*compareReturnTypes*/ false , isTypeIdenticalTo ) ) {
2079+ return false ;
2080+ }
20752081 }
20762082 return true ;
20772083 }
20782084
2085+ // If the lists of call or construct signatures in the given types are all identical except for return types,
2086+ // and if none of the signatures are generic, return a list of signatures that has substitutes a union of the
2087+ // return types of the corresponding signatures in each resulting signature.
20792088 function getUnionSignatures ( types : Type [ ] , kind : SignatureKind ) : Signature [ ] {
20802089 var signatureLists = map ( types , t => getSignaturesOfType ( t , kind ) ) ;
2081- var baseSignatures = signatureLists [ 0 ] ;
2082- for ( var i = 0 ; i < baseSignatures . length ; i ++ ) {
2083- if ( baseSignatures [ i ] . typeParameters ) return emptyArray ;
2090+ var signatures = signatureLists [ 0 ] ;
2091+ for ( var i = 0 ; i < signatures . length ; i ++ ) {
2092+ if ( signatures [ i ] . typeParameters ) {
2093+ return emptyArray ;
2094+ }
20842095 }
20852096 for ( var i = 1 ; i < signatureLists . length ; i ++ ) {
2086- if ( ! signatureListsIdentical ( baseSignatures , signatureLists [ i ] ) ) return emptyArray ;
2097+ if ( ! signatureListsIdentical ( signatures , signatureLists [ i ] ) ) {
2098+ return emptyArray ;
2099+ }
20872100 }
2088- var result = map ( baseSignatures , cloneSignature ) ;
2101+ var result = map ( signatures , cloneSignature ) ;
20892102 for ( var i = 0 ; i < result . length ; i ++ ) {
20902103 var s = result [ i ] ;
2104+ // Clear resolved return type we possibly got from cloneSignature
20912105 s . resolvedReturnType = undefined ;
20922106 s . unionSignatures = map ( signatureLists , signatures => signatures [ i ] ) ;
20932107 }
@@ -2098,7 +2112,9 @@ module ts {
20982112 var indexTypes : Type [ ] = [ ] ;
20992113 for ( var i = 0 ; i < types . length ; i ++ ) {
21002114 var indexType = getIndexTypeOfType ( types [ i ] , kind ) ;
2101- if ( ! indexType ) return undefined ;
2115+ if ( ! indexType ) {
2116+ return undefined ;
2117+ }
21022118 indexTypes . push ( indexType ) ;
21032119 }
21042120 return getUnionType ( indexTypes ) ;
@@ -2113,14 +2129,16 @@ module ts {
21132129 }
21142130 } ) ;
21152131 if ( types . length <= 1 ) {
2116- var res = types . length ? resolveObjectTypeMembers ( types [ 0 ] ) : emptyObjectType ;
2117- setObjectTypeMembers ( type , res . members , res . callSignatures , res . constructSignatures , res . stringIndexType , res . numberIndexType ) ;
2132+ var resolved = types . length ? resolveObjectTypeMembers ( types [ 0 ] ) : emptyObjectType ;
2133+ setObjectTypeMembers ( type , resolved . members , resolved . callSignatures , resolved . constructSignatures , resolved . stringIndexType , resolved . numberIndexType ) ;
21182134 return ;
21192135 }
21202136 var members : SymbolTable = { } ;
21212137 forEach ( getPropertiesOfType ( types [ 0 ] ) , prop => {
21222138 for ( var i = 1 ; i < types . length ; i ++ ) {
2123- if ( ! getPropertyOfType ( types [ i ] , prop . name ) ) return ;
2139+ if ( ! getPropertyOfType ( types [ i ] , prop . name ) ) {
2140+ return ;
2141+ }
21242142 }
21252143 var symbol = < TransientSymbol > createSymbol ( SymbolFlags . UnionProperty | SymbolFlags . Transient , prop . name ) ;
21262144 symbol . unionType = type ;
@@ -2662,7 +2680,9 @@ module ts {
26622680 else {
26632681 var i = 0 ;
26642682 var id = type . id ;
2665- while ( i < sortedSet . length && sortedSet [ i ] . id < id ) i ++ ;
2683+ while ( i < sortedSet . length && sortedSet [ i ] . id < id ) {
2684+ i ++ ;
2685+ }
26662686 if ( i === sortedSet . length || sortedSet [ i ] . id !== id ) {
26672687 sortedSet . splice ( i , 0 , type ) ;
26682688 }
@@ -2677,7 +2697,9 @@ module ts {
26772697
26782698 function isSubtypeOfAny ( candidate : Type , types : Type [ ] ) : boolean {
26792699 for ( var i = 0 , len = types . length ; i < len ; i ++ ) {
2680- if ( candidate !== types [ i ] && isTypeSubtypeOf ( candidate , types [ i ] ) ) return true ;
2700+ if ( candidate !== types [ i ] && isTypeSubtypeOf ( candidate , types [ i ] ) ) {
2701+ return true ;
2702+ }
26812703 }
26822704 return false ;
26832705 }
@@ -3467,7 +3489,7 @@ module ts {
34673489 return false ;
34683490 }
34693491 for ( var i = 0 , len = sourceSignatures . length ; i < len ; ++ i ) {
3470- if ( ! compareSignatures ( sourceSignatures [ i ] , targetSignatures [ i ] , /*returnTypes */ true , isRelatedTo ) ) {
3492+ if ( ! compareSignatures ( sourceSignatures [ i ] , targetSignatures [ i ] , /*compareReturnTypes */ true , isRelatedTo ) ) {
34713493 return false ;
34723494 }
34733495 }
@@ -3535,7 +3557,7 @@ module ts {
35353557 }
35363558 }
35373559
3538- function compareSignatures ( source : Signature , target : Signature , returnTypes : boolean , compareTypes : ( s : Type , t : Type ) => boolean ) : boolean {
3560+ function compareSignatures ( source : Signature , target : Signature , compareReturnTypes : boolean , compareTypes : ( s : Type , t : Type ) => boolean ) : boolean {
35393561 if ( source === target ) {
35403562 return true ;
35413563 }
@@ -3568,7 +3590,7 @@ module ts {
35683590 return false ;
35693591 }
35703592 }
3571- return ! returnTypes || compareTypes ( getReturnTypeOfSignature ( source ) , getReturnTypeOfSignature ( target ) ) ;
3593+ return ! compareReturnTypes || compareTypes ( getReturnTypeOfSignature ( source ) , getReturnTypeOfSignature ( target ) ) ;
35723594 }
35733595
35743596 function isSupertypeOfEach ( candidate : Type , types : Type [ ] ) : boolean {
@@ -3876,20 +3898,14 @@ module ts {
38763898 if ( type . flags & TypeFlags . Union ) {
38773899 var types = ( < UnionType > type ) . types ;
38783900 if ( forEach ( types , t => t . flags & subtractMask ) ) {
3879- var newTypes : Type [ ] = [ ] ;
3880- forEach ( types , t => {
3881- if ( ! ( t . flags & subtractMask ) ) {
3882- newTypes . push ( t ) ;
3883- }
3884- } ) ;
3885- return getUnionType ( newTypes ) ;
3901+ return getUnionType ( filter ( types , t => ! ( t . flags & subtractMask ) ) ) ;
38863902 }
38873903 }
38883904 return type ;
38893905 }
38903906
38913907 // Check if a given variable is assigned within a given syntax node
3892- function IsVariableAssignedWithin ( symbol : Symbol , node : Node ) : boolean {
3908+ function isVariableAssignedWithin ( symbol : Symbol , node : Node ) : boolean {
38933909 var links = getNodeLinks ( node ) ;
38943910 if ( links . assignmentChecks ) {
38953911 var cachedResult = links . assignmentChecks [ symbol . id ] ;
@@ -3981,29 +3997,32 @@ module ts {
39813997 case SyntaxKind . IfStatement :
39823998 // In a branch of an if statement, narrow based on controlling expression
39833999 if ( child !== ( < IfStatement > node ) . expression ) {
3984- narrowedType = narrowType ( type , ( < IfStatement > node ) . expression , child === ( < IfStatement > node ) . thenStatement ) ;
4000+ narrowedType = narrowType ( type , ( < IfStatement > node ) . expression , /*assumeTrue*/ child === ( < IfStatement > node ) . thenStatement ) ;
39854001 }
39864002 break ;
39874003 case SyntaxKind . ConditionalExpression :
39884004 // In a branch of a conditional expression, narrow based on controlling condition
39894005 if ( child !== ( < ConditionalExpression > node ) . condition ) {
3990- narrowedType = narrowType ( type , ( < ConditionalExpression > node ) . condition , child === ( < ConditionalExpression > node ) . whenTrue ) ;
4006+ narrowedType = narrowType ( type , ( < ConditionalExpression > node ) . condition , /*assumeTrue*/ child === ( < ConditionalExpression > node ) . whenTrue ) ;
39914007 }
39924008 break ;
39934009 case SyntaxKind . BinaryExpression :
39944010 // In the right operand of an && or ||, narrow based on left operand
39954011 if ( child === ( < BinaryExpression > node ) . right ) {
39964012 if ( ( < BinaryExpression > node ) . operator === SyntaxKind . AmpersandAmpersandToken ) {
3997- narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , true ) ;
4013+ narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , /*assumeTrue*/ true ) ;
39984014 }
39994015 else if ( ( < BinaryExpression > node ) . operator === SyntaxKind . BarBarToken ) {
4000- narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , false ) ;
4016+ narrowedType = narrowType ( type , ( < BinaryExpression > node ) . left , /*assumeTrue*/ false ) ;
40014017 }
40024018 }
40034019 break ;
40044020 }
40054021 // Only use narrowed type if construct contains no assignments to variable
4006- if ( narrowedType !== type && ! IsVariableAssignedWithin ( symbol , node ) ) {
4022+ if ( narrowedType !== type ) {
4023+ if ( isVariableAssignedWithin ( symbol , node ) ) {
4024+ break ;
4025+ }
40074026 type = narrowedType ;
40084027 }
40094028 }
@@ -4039,30 +4058,36 @@ module ts {
40394058 function narrowTypeByAnd ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
40404059 if ( assumeTrue ) {
40414060 // The assumed result is true, therefore we narrow assuming each operand to be true.
4042- return narrowType ( narrowType ( type , expr . left , true ) , expr . right , true ) ;
4061+ return narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ true ) , expr . right , /*assumeTrue*/ true ) ;
40434062 }
40444063 else {
4045- // The assumed result is true . This means either the first operand was false, or the first operand was true
4064+ // The assumed result is false . This means either the first operand was false, or the first operand was true
40464065 // and the second operand was false. We narrow with those assumptions and union the two resulting types.
4047- return getUnionType ( [ narrowType ( type , expr . left , false ) , narrowType ( narrowType ( type , expr . left , true ) , expr . right , false ) ] ) ;
4066+ return getUnionType ( [
4067+ narrowType ( type , expr . left , /*assumeTrue*/ false ) ,
4068+ narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ true ) , expr . right , /*assumeTrue*/ false )
4069+ ] ) ;
40484070 }
40494071 }
40504072
40514073 function narrowTypeByOr ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
40524074 if ( assumeTrue ) {
40534075 // The assumed result is true. This means either the first operand was true, or the first operand was false
40544076 // and the second operand was true. We narrow with those assumptions and union the two resulting types.
4055- return getUnionType ( [ narrowType ( type , expr . left , true ) , narrowType ( narrowType ( type , expr . left , false ) , expr . right , true ) ] ) ;
4077+ return getUnionType ( [
4078+ narrowType ( type , expr . left , /*assumeTrue*/ true ) ,
4079+ narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ false ) , expr . right , /*assumeTrue*/ true )
4080+ ] ) ;
40564081 }
40574082 else {
40584083 // The assumed result is false, therefore we narrow assuming each operand to be false.
4059- return narrowType ( narrowType ( type , expr . left , false ) , expr . right , false ) ;
4084+ return narrowType ( narrowType ( type , expr . left , /*assumeTrue*/ false ) , expr . right , /*assumeTrue*/ false ) ;
40604085 }
40614086 }
40624087
40634088 function narrowTypeByInstanceof ( type : Type , expr : BinaryExpression , assumeTrue : boolean ) : Type {
4064- // Check that we have variable symbol on the left
4065- if ( expr . left . kind !== SyntaxKind . Identifier || getResolvedSymbol ( < Identifier > expr . left ) !== symbol ) {
4089+ // Check that assumed result is true and we have variable symbol on the left
4090+ if ( ! assumeTrue || expr . left . kind !== SyntaxKind . Identifier || getResolvedSymbol ( < Identifier > expr . left ) !== symbol ) {
40664091 return type ;
40674092 }
40684093 // Check that right operand is a function type with a prototype property
@@ -7198,7 +7223,7 @@ module ts {
71987223 return checkArrayType ( < ArrayTypeNode > node ) ;
71997224 case SyntaxKind . TupleType :
72007225 return checkTupleType ( < TupleTypeNode > node ) ;
7201- case SyntaxKind . TupleType :
7226+ case SyntaxKind . UnionType :
72027227 return checkUnionType ( < UnionTypeNode > node ) ;
72037228 case SyntaxKind . FunctionDeclaration :
72047229 return checkFunctionDeclaration ( < FunctionDeclaration > node ) ;
0 commit comments