@@ -4480,6 +4480,54 @@ module ts {
4480
4480
return undefined ;
4481
4481
}
4482
4482
4483
+ // Apply a mapping function to a contextual type and return the resulting type. If the contextual type
4484
+ // is a union type, the mapping function is applied to each constituent type and a union of the resulting
4485
+ // types is returned.
Has a conversation. Original line has a conversation.
4486
+ function applyToContextualType ( type : Type , mapper : ( t : Type ) => Type ) : Type {
4487
+ if ( ! ( type . flags & TypeFlags . Union ) ) {
4488
+ return mapper ( type ) ;
4489
+ }
4490
+ var types = ( < UnionType > type ) . types ;
4491
+ var mappedType : Type ;
4492
+ var mappedTypes : Type [ ] ;
4493
+ for ( var i = 0 ; i < types . length ; i ++ ) {
4494
+ var t = mapper ( types [ i ] ) ;
4495
+ if ( t ) {
4496
+ if ( ! mappedType ) {
4497
+ mappedType = t ;
4498
+ }
4499
+ else if ( ! mappedTypes ) {
4500
+ mappedTypes = [ mappedType , t ] ;
4501
+ }
4502
+ else {
4503
+ mappedTypes . push ( t ) ;
4504
+ }
Has a conversation. Original line has a conversation.
4505
+ }
4506
+ }
4507
+ return mappedTypes ? getUnionType ( mappedTypes ) : mappedType ;
4508
+ }
4509
+
4510
+ function getTypeOfPropertyOfContextualType ( type : Type , name : string ) {
4511
+ return applyToContextualType ( type , t => {
4512
+ var prop = getPropertyOfType ( t , name ) ;
4513
+ return prop ? getTypeOfSymbol ( prop ) : undefined ;
4514
+ } ) ;
4515
+ }
4516
+
4517
+ function getIndexTypeOfContextualType ( type : Type , kind : IndexKind ) {
4518
+ return applyToContextualType ( type , t => getIndexTypeOfType ( t , kind ) ) ;
4519
+ }
4520
+
4521
+ // Return true if the given contextual type is a tuple-like type
4522
+ function contextualTypeIsTupleType ( type : Type ) : boolean {
Has a conversation. Original line has a conversation.
4523
+ return ! ! ( type . flags & TypeFlags . Union ? forEach ( ( < UnionType > type ) . types , t => getPropertyOfType ( t , "0" ) ) : getPropertyOfType ( type , "0" ) ) ;
4524
+ }
4525
+
4526
+ // Return true if the given contextual type provides an index signature of the given kind
4527
+ function contextualTypeHasIndexSignature ( type : Type , kind : IndexKind ) : boolean {
4528
+ return ! ! ( type . flags & TypeFlags . Union ? forEach ( ( < UnionType > type ) . types , t => getIndexTypeOfType ( t , kind ) ) : getIndexTypeOfType ( type , kind ) ) ;
4529
+ }
4530
+
4483
4531
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
4484
4532
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
4485
4533
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
@@ -4489,11 +4537,9 @@ module ts {
4489
4537
var type = getContextualType ( objectLiteral ) ;
4490
4538
var name = declaration . name . text ;
4491
4539
if ( type && name ) {
4492
- var prop = getPropertyOfType ( type , name ) ;
Has conversations. Original line has conversations. 4493
- if ( prop ) {
4494
- return getTypeOfSymbol ( prop ) ;
4495
- }
4496
- return isNumericName ( name ) && getIndexTypeOfType ( type , IndexKind . Number ) || getIndexTypeOfType ( type , IndexKind . String ) ;
4540
+ return getTypeOfPropertyOfContextualType ( type , name ) ||
4541
+ isNumericName ( name ) && getIndexTypeOfContextualType ( type , IndexKind . Number ) ||
4542
+ getIndexTypeOfContextualType ( type , IndexKind . String ) ;
4497
4543
}
4498
4544
return undefined ;
4499
4545
}
@@ -4506,11 +4552,7 @@ module ts {
4506
4552
var type = getContextualType ( arrayLiteral ) ;
4507
4553
if ( type ) {
4508
4554
var index = indexOf ( arrayLiteral . elements , node ) ;
4509
- var prop = getPropertyOfType ( type , "" + index ) ;
4510
- if ( prop ) {
4511
- return getTypeOfSymbol ( prop ) ;
4512
- }
4513
- return getIndexTypeOfType ( type , IndexKind . Number ) ;
4555
+ return getTypeOfPropertyOfContextualType ( type , "" + index ) || getIndexTypeOfContextualType ( type , IndexKind . Number ) ;
4514
4556
}
4515
4557
return undefined ;
4516
4558
}
@@ -4528,7 +4570,6 @@ module ts {
4528
4570
// We cannot answer semantic questions within a with block, do not proceed any further
4529
4571
return undefined ;
4530
4572
}
4531
-
4532
4573
if ( node . contextualType ) {
4533
4574
return node . contextualType ;
4534
4575
}
@@ -4558,18 +4599,45 @@ module ts {
4558
4599
return undefined ;
4559
4600
}
4560
4601
4602
+ // Return the single non-generic signature in the given type, or undefined if none exists
4603
+ function getNonGenericSignature ( type : Type ) : Signature {
Has conversations. Original line has conversations.
4604
+ var signatures = getSignaturesOfType ( type , SignatureKind . Call ) ;
4605
+ if ( signatures . length !== 1 ) {
4606
+ return undefined ;
4607
+ }
4608
+ var signature = signatures [ 0 ] ;
4609
+ if ( signature . typeParameters ) {
4610
+ return undefined ;
4611
+ }
4612
+ return signature ;
4613
+ }
4614
+
4615
+ // Return the contextual signature for a given expression node. A contextual type provides a
4616
+ // contextual signature if it has a single call signature and if that call signature is non-generic.
4617
+ // If the contextual type is a union type and each constituent type that has a contextual signature
4618
+ // provides the same contextual signature, then the union type provides that contextual signature.
Has a conversation. Original line has a conversation. 4561
4619
function getContextualSignature ( node : Expression ) : Signature {
4562
4620
var type = getContextualType ( node ) ;
4563
- if ( type ) {
4564
- var signatures = getSignaturesOfType ( type , SignatureKind . Call ) ;
4565
- if ( signatures . length === 1 ) {
4566
- var signature = signatures [ 0 ] ;
4567
- if ( ! signature . typeParameters ) {
4568
- return signature ;
4621
+ if ( ! type ) {
4622
+ return undefined ;
4623
+ }
4624
+ if ( ! ( type . flags & TypeFlags . Union ) ) {
4625
+ return getNonGenericSignature ( type ) ;
4626
+ }
4627
+ var result : Signature ;
4628
+ var types = ( < UnionType > type ) . types ;
4629
+ for ( var i = 0 ; i < types . length ; i ++ ) {
4630
+ var signature = getNonGenericSignature ( types [ i ] ) ;
4631
+ if ( signature ) {
4632
+ if ( ! result ) {
4633
+ result = signature ;
4634
+ }
4635
+ else if ( ! compareSignatures ( result , signature , /*compareReturnTypes*/ true , isTypeIdenticalTo ) ) {
Has conversations. Original line has conversations.
4636
+ return undefined ;
4569
4637
}
4570
4638
}
4571
4639
}
4572
- return undefined ;
4640
+ return result ;
4573
4641
}
4574
4642
4575
4643
// Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
@@ -4579,24 +4647,16 @@ module ts {
4579
4647
}
4580
4648
4581
4649
function checkArrayLiteral ( node : ArrayLiteral , contextualMapper ?: TypeMapper ) : Type {
4582
- var contextualType = getContextualType ( node ) ;
4583
4650
var elements = node . elements ;
4584
- var elementTypes : Type [ ] = [ ] ;
4585
- var isTupleLiteral : boolean = false ;
4586
- for ( var i = 0 ; i < elements . length ; i ++ ) {
4587
- if ( contextualType && getPropertyOfType ( contextualType , "" + i ) ) {
4588
- isTupleLiteral = true ;
4589
- }
4590
- var element = elements [ i ] ;
4591
- var type = element . kind !== SyntaxKind . OmittedExpression ? checkExpression ( element , contextualMapper ) : undefinedType ;
4592
- elementTypes . push ( type ) ;
4651
+ if ( ! elements . length ) {
4652
+ return createArrayType ( undefinedType ) ;
4593
4653
}
4594
- if ( isTupleLiteral ) {
4654
+ var elementTypes = map ( elements , e => checkExpression ( e , contextualMapper ) ) ;
4655
+ var contextualType = getContextualType ( node ) ;
4656
+ if ( contextualType && contextualTypeIsTupleType ( contextualType ) ) {
Has conversations. Original line has conversations. 4595
4657
return createTupleType ( elementTypes ) ;
4596
4658
}
4597
- var contextualElementType = contextualType && ! isInferentialContext ( contextualMapper ) ? getIndexTypeOfType ( contextualType , IndexKind . Number ) : undefined ;
4598
- var elementType = elements . length || contextualElementType ? getBestCommonType ( elementTypes , contextualElementType ) : undefinedType ;
4599
- return createArrayType ( elementType ) ;
4659
+ return createArrayType ( getUnionType ( elementTypes ) ) ;
4600
4660
}
4601
4661
4602
4662
function isNumericName ( name : string ) {
@@ -4607,7 +4667,6 @@ module ts {
4607
4667
var members = node . symbol . members ;
4608
4668
var properties : SymbolTable = { } ;
4609
4669
var contextualType = getContextualType ( node ) ;
4610
-
4611
4670
for ( var id in members ) {
4612
4671
if ( hasProperty ( members , id ) ) {
4613
4672
var member = members [ id ] ;
@@ -4645,21 +4704,19 @@ module ts {
4645
4704
return createAnonymousType ( node . symbol , properties , emptyArray , emptyArray , stringIndexType , numberIndexType ) ;
4646
4705
4647
4706
function getIndexType ( kind : IndexKind ) {
4648
- if ( contextualType ) {
Has a conversation. Original line has a conversation. 4649
- var indexType = getIndexTypeOfType ( contextualType , kind ) ;
4650
- if ( indexType ) {
4651
- var propTypes : Type [ ] = [ ] ;
4652
- for ( var id in properties ) {
4653
- if ( hasProperty ( properties , id ) ) {
4654
- if ( kind === IndexKind . String || isNumericName ( id ) ) {
4655
- var type = getTypeOfSymbol ( properties [ id ] ) ;
4656
- if ( ! contains ( propTypes , type ) ) propTypes . push ( type ) ;
4657
- }
4707
+ if ( contextualType && contextualTypeHasIndexSignature ( contextualType , kind ) ) {
4708
+ var propTypes : Type [ ] = [ ] ;
4709
+ for ( var id in properties ) {
4710
+ if ( hasProperty ( properties , id ) ) {
4711
+ if ( kind === IndexKind . String || isNumericName ( id ) ) {
4712
+ var type = getTypeOfSymbol ( properties [ id ] ) ;
4713
+ if ( ! contains ( propTypes , type ) ) propTypes . push ( type ) ;
4658
4714
}
4659
4715
}
4660
- return getBestCommonType ( propTypes , isInferentialContext ( contextualMapper ) ? undefined : indexType ) ;
4661
4716
}
4717
+ return propTypes . length ? getUnionType ( propTypes ) : undefinedType ;
4662
4718
}
4719
+ return undefined ;
4663
4720
}
4664
4721
}
4665
4722
@@ -5249,11 +5306,12 @@ module ts {
5249
5306
}
5250
5307
5251
5308
function getReturnTypeFromBody ( func : FunctionDeclaration , contextualMapper ?: TypeMapper ) : Type {
5309
+ var contextualSignature = getContextualSignature ( func ) ;
5252
5310
if ( func . body . kind !== SyntaxKind . FunctionBlock ) {
5253
5311
var unwidenedType = checkAndMarkExpression ( func . body , contextualMapper ) ;
5254
5312
var widenedType = getWidenedType ( unwidenedType ) ;
5255
5313
5256
- if ( fullTypeCheck && compilerOptions . noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
5314
+ if ( fullTypeCheck && compilerOptions . noImplicitAny && ! contextualSignature && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
Has a conversation. Original line has a conversation. 5257
5315
error ( func , Diagnostics . Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type , typeToString ( widenedType ) ) ;
5258
5316
}
5259
5317
@@ -5267,7 +5325,7 @@ module ts {
5267
5325
if ( types . length > 0 ) {
5268
5326
// When return statements are contextually typed we allow the return type to be a union type. Otherwise we require the
5269
5327
// return expressions to have a best common supertype.
5270
- var commonType = getContextualSignature ( func ) ? getUnionType ( types ) : getCommonSupertype ( types ) ;
5328
+ var commonType = contextualSignature ? getUnionType ( types ) : getCommonSupertype ( types ) ;
5271
5329
if ( ! commonType ) {
5272
5330
error ( func , Diagnostics . No_best_common_type_exists_among_return_expressions ) ;
5273
5331
@@ -5277,7 +5335,7 @@ module ts {
5277
5335
var widenedType = getWidenedType ( commonType ) ;
5278
5336
5279
5337
// Check and report for noImplicitAny if the best common type implicitly gets widened to an 'any'/arrays-of-'any' type.
5280
- if ( fullTypeCheck && compilerOptions . noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
5338
+ if ( fullTypeCheck && compilerOptions . noImplicitAny && ! contextualSignature && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
Has a conversation. Original line has a conversation. 5281
5339
var typeName = typeToString ( widenedType ) ;
5282
5340
5283
5341
if ( func . name ) {
@@ -5776,6 +5834,8 @@ module ts {
5776
5834
return checkBinaryExpression ( < BinaryExpression > node , contextualMapper ) ;
5777
5835
case SyntaxKind . ConditionalExpression :
5778
5836
return checkConditionalExpression ( < ConditionalExpression > node , contextualMapper ) ;
5837
+ case SyntaxKind . OmittedExpression :
5838
+ return undefinedType ;
5779
5839
}
5780
5840
return unknownType ;
5781
5841
}