@@ -14636,18 +14636,18 @@ namespace ts {
1463614636 }
1463714637
1463814638 function inferFromProperties(source: Type, target: Type) {
14639- if (isTupleType(source)) {
14639+ if (isArrayType(source) || isTupleType(source)) {
1464014640 if (isTupleType(target)) {
14641- const sourceLength = getLengthOfTupleType(source);
14641+ const sourceLength = isTupleType(source) ? getLengthOfTupleType(source) : 0 ;
1464214642 const targetLength = getLengthOfTupleType(target);
14643- const sourceRestType = getRestTypeOfTupleType(source);
14643+ const sourceRestType = isTupleType(source) ? getRestTypeOfTupleType(source) : getElementTypeOfArrayType (source);
1464414644 const targetRestType = getRestTypeOfTupleType(target);
1464514645 const fixedLength = targetLength < sourceLength || sourceRestType ? targetLength : sourceLength;
1464614646 for (let i = 0; i < fixedLength; i++) {
14647- inferFromTypes(i < sourceLength ? source.typeArguments![i] : sourceRestType!, target.typeArguments![i]);
14647+ inferFromTypes(i < sourceLength ? (<TypeReference> source) .typeArguments![i] : sourceRestType!, target.typeArguments![i]);
1464814648 }
1464914649 if (targetRestType) {
14650- const types = fixedLength < sourceLength ? source.typeArguments!.slice(fixedLength, sourceLength) : [];
14650+ const types = fixedLength < sourceLength ? (<TypeReference> source) .typeArguments!.slice(fixedLength, sourceLength) : [];
1465114651 if (sourceRestType) {
1465214652 types.push(sourceRestType);
1465314653 }
@@ -17759,19 +17759,49 @@ namespace ts {
1775917759 // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
1776017760 // be "pushed" onto a node using the contextualType property.
1776117761 function getApparentTypeOfContextualType(node: Expression): Type | undefined {
17762- let contextualType = getContextualType(node);
17763- contextualType = contextualType && mapType(contextualType, getApparentType);
17764- if (contextualType && contextualType.flags & TypeFlags.Union) {
17765- if (isObjectLiteralExpression(node)) {
17766- return discriminateContextualTypeByObjectMembers(node, contextualType as UnionType);
17762+ const contextualType = instantiateContextualType(getContextualType(node), node);
17763+ if (contextualType) {
17764+ const apparentType = mapType(contextualType, getApparentType, /*noReductions*/ true);
17765+ if (apparentType.flags & TypeFlags.Union) {
17766+ if (isObjectLiteralExpression(node)) {
17767+ return discriminateContextualTypeByObjectMembers(node, apparentType as UnionType);
17768+ }
17769+ else if (isJsxAttributes(node)) {
17770+ return discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType);
17771+ }
1776717772 }
17768- else if (isJsxAttributes(node)) {
17769- return discriminateContextualTypeByJSXAttributes(node, contextualType as UnionType);
17773+ return apparentType;
17774+ }
17775+ }
17776+
17777+ // If the given contextual type contains instantiable types and if a mapper representing
17778+ // return type inferences is available, instantiate those types using that mapper.
17779+ function instantiateContextualType(contextualType: Type | undefined, node: Expression): Type | undefined {
17780+ if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) {
17781+ const returnMapper = (<InferenceContext>getContextualMapper(node)).returnMapper;
17782+ if (returnMapper) {
17783+ return instantiateInstantiableTypes(contextualType, returnMapper);
1777017784 }
1777117785 }
1777217786 return contextualType;
1777317787 }
1777417788
17789+ // This function is similar to instantiateType, except that (a) it only instantiates types that
17790+ // are classified as instantiable (i.e. it doesn't instantiate object types), and (b) it performs
17791+ // no reductions on instantiated union types.
17792+ function instantiateInstantiableTypes(type: Type, mapper: TypeMapper): Type {
17793+ if (type.flags & TypeFlags.Instantiable) {
17794+ return instantiateType(type, mapper);
17795+ }
17796+ if (type.flags & TypeFlags.Union) {
17797+ return getUnionType(map((<UnionType>type).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None);
17798+ }
17799+ if (type.flags & TypeFlags.Intersection) {
17800+ return getIntersectionType(map((<IntersectionType>type).types, t => instantiateInstantiableTypes(t, mapper)));
17801+ }
17802+ return type;
17803+ }
17804+
1777517805 /**
1777617806 * Woah! Do you really want to use this function?
1777717807 *
@@ -19910,6 +19940,9 @@ namespace ts {
1991019940 const inferenceTargetType = getReturnTypeOfSignature(signature);
1991119941 // Inferences made from return types have lower priority than all other inferences.
1991219942 inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType);
19943+ // Create a type mapper for instantiating generic contextual types using the inferences made
19944+ // from the return type.
19945+ context.returnMapper = cloneTypeMapper(context);
1991319946 }
1991419947 }
1991519948
@@ -23020,7 +23053,12 @@ namespace ts {
2302023053 context.contextualMapper = contextualMapper;
2302123054 const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive :
2302223055 contextualMapper ? CheckMode.Inferential : CheckMode.Contextual;
23023- const result = checkExpression(node, checkMode);
23056+ const type = checkExpression(node, checkMode);
23057+ // We strip literal freshness when an appropriate contextual type is present such that contextually typed
23058+ // literals always preserve their literal types (otherwise they might widen during type inference). An alternative
23059+ // here would be to not mark contextually typed literals as fresh in the first place.
23060+ const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node)) ?
23061+ getRegularTypeOfLiteralType(type) : type;
2302423062 context.contextualType = saveContextualType;
2302523063 context.contextualMapper = saveContextualMapper;
2302623064 return result;
@@ -23104,13 +23142,10 @@ namespace ts {
2310423142 }
2310523143
2310623144 function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type {
23107- if (arguments.length === 2) {
23108- contextualType = getContextualType(node);
23109- }
2311023145 const type = checkExpression(node, checkMode, forceTuple);
2311123146 return isConstContext(node) ? getRegularTypeOfLiteralType(type) :
2311223147 isTypeAssertion(node) ? type :
23113- getWidenedLiteralLikeTypeForContextualType(type, contextualType);
23148+ getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node) : contextualType, node) );
2311423149 }
2311523150
2311623151 function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
0 commit comments