@@ -4480,6 +4480,54 @@ module ts {
44804480 return undefined ;
44814481 }
44824482
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.
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+ }
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 {
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+
44834531 // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
44844532 // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
44854533 // exists. Otherwise, it is the type of the string index signature in T, if one exists.
@@ -4489,11 +4537,9 @@ module ts {
44894537 var type = getContextualType ( objectLiteral ) ;
44904538 var name = declaration . name . text ;
44914539 if ( type && name ) {
4492- var prop = getPropertyOfType ( type , name ) ;
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 ) ;
44974543 }
44984544 return undefined ;
44994545 }
@@ -4506,11 +4552,7 @@ module ts {
45064552 var type = getContextualType ( arrayLiteral ) ;
45074553 if ( type ) {
45084554 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 ) ;
45144556 }
45154557 return undefined ;
45164558 }
@@ -4528,7 +4570,6 @@ module ts {
45284570 // We cannot answer semantic questions within a with block, do not proceed any further
45294571 return undefined ;
45304572 }
4531-
45324573 if ( node . contextualType ) {
45334574 return node . contextualType ;
45344575 }
@@ -4558,18 +4599,45 @@ module ts {
45584599 return undefined ;
45594600 }
45604601
4602+ // Return the single non-generic signature in the given type, or undefined if none exists
4603+ function getNonGenericSignature ( type : Type ) : Signature {
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.
45614619 function getContextualSignature ( node : Expression ) : Signature {
45624620 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 ) ) {
4636+ return undefined ;
45694637 }
45704638 }
45714639 }
4572- return undefined ;
4640+ return result ;
45734641 }
45744642
45754643 // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
@@ -4579,24 +4647,16 @@ module ts {
45794647 }
45804648
45814649 function checkArrayLiteral ( node : ArrayLiteral , contextualMapper ?: TypeMapper ) : Type {
4582- var contextualType = getContextualType ( node ) ;
45834650 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 ) ;
45934653 }
4594- if ( isTupleLiteral ) {
4654+ var elementTypes = map ( elements , e => checkExpression ( e , contextualMapper ) ) ;
4655+ var contextualType = getContextualType ( node ) ;
4656+ if ( contextualType && contextualTypeIsTupleType ( contextualType ) ) {
45954657 return createTupleType ( elementTypes ) ;
45964658 }
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 ) ) ;
46004660 }
46014661
46024662 function isNumericName ( name : string ) {
@@ -4607,7 +4667,6 @@ module ts {
46074667 var members = node . symbol . members ;
46084668 var properties : SymbolTable = { } ;
46094669 var contextualType = getContextualType ( node ) ;
4610-
46114670 for ( var id in members ) {
46124671 if ( hasProperty ( members , id ) ) {
46134672 var member = members [ id ] ;
@@ -4645,21 +4704,19 @@ module ts {
46454704 return createAnonymousType ( node . symbol , properties , emptyArray , emptyArray , stringIndexType , numberIndexType ) ;
46464705
46474706 function getIndexType ( kind : IndexKind ) {
4648- if ( contextualType ) {
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 ) ;
46584714 }
46594715 }
4660- return getBestCommonType ( propTypes , isInferentialContext ( contextualMapper ) ? undefined : indexType ) ;
46614716 }
4717+ return propTypes . length ? getUnionType ( propTypes ) : undefinedType ;
46624718 }
4719+ return undefined ;
46634720 }
46644721 }
46654722
@@ -5249,11 +5306,12 @@ module ts {
52495306 }
52505307
52515308 function getReturnTypeFromBody ( func : FunctionDeclaration , contextualMapper ?: TypeMapper ) : Type {
5309+ var contextualSignature = getContextualSignature ( func ) ;
52525310 if ( func . body . kind !== SyntaxKind . FunctionBlock ) {
52535311 var unwidenedType = checkAndMarkExpression ( func . body , contextualMapper ) ;
52545312 var widenedType = getWidenedType ( unwidenedType ) ;
52555313
5256- if ( fullTypeCheck && compilerOptions . noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
5314+ if ( fullTypeCheck && compilerOptions . noImplicitAny && ! contextualSignature && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes ( widenedType ) === anyType ) {
52575315 error ( func , Diagnostics . Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type , typeToString ( widenedType ) ) ;
52585316 }
52595317
@@ -5267,7 +5325,7 @@ module ts {
52675325 if ( types . length > 0 ) {
52685326 // When return statements are contextually typed we allow the return type to be a union type. Otherwise we require the
52695327 // 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 ) ;
52715329 if ( ! commonType ) {
52725330 error ( func , Diagnostics . No_best_common_type_exists_among_return_expressions ) ;
52735331
@@ -5277,7 +5335,7 @@ module ts {
52775335 var widenedType = getWidenedType ( commonType ) ;
52785336
52795337 // 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 ) {
52815339 var typeName = typeToString ( widenedType ) ;
52825340
52835341 if ( func . name ) {
@@ -5776,6 +5834,8 @@ module ts {
57765834 return checkBinaryExpression ( < BinaryExpression > node , contextualMapper ) ;
57775835 case SyntaxKind . ConditionalExpression :
57785836 return checkConditionalExpression ( < ConditionalExpression > node , contextualMapper ) ;
5837+ case SyntaxKind . OmittedExpression :
5838+ return undefinedType ;
57795839 }
57805840 return unknownType ;
57815841 }
0 commit comments