From 24a25fd79c515050574d94818f7a1d5e65be55b5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 08:46:47 -0700 Subject: [PATCH 01/11] Revise type inference data structures --- src/compiler/checker.ts | 145 +++++++++++++++++++++------------------- src/compiler/types.ts | 26 ++++--- 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7040314648983..1bba954971afb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7921,10 +7921,10 @@ namespace ts { function getInferenceMapper(context: InferenceContext): TypeMapper { if (!context.mapper) { const mapper: TypeMapper = t => { - const typeParameters = context.signature.typeParameters; - for (let i = 0; i < typeParameters.length; i++) { - if (t === typeParameters[i]) { - context.inferences[i].isFixed = true; + const inferences = context.inferences; + for (let i = 0; i < inferences.length; i++) { + if (t === inferences[i].typeParameter) { + inferences[i].isFixed = true; return getInferredType(context, i); } } @@ -10131,22 +10131,22 @@ namespace ts { } function createInferenceContext(signature: Signature, inferUnionTypes: boolean, useAnyForNoInferences: boolean): InferenceContext { - const inferences = map(signature.typeParameters, createTypeInferencesObject); return { signature, + inferences: map(signature.typeParameters, createInferenceInfo), inferUnionTypes, - inferences, - inferredTypes: new Array(signature.typeParameters.length), useAnyForNoInferences }; } - function createTypeInferencesObject(): TypeInferences { + function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { return { - primary: undefined, - secondary: undefined, + typeParameter, + candidates: undefined, + inferredType: undefined, + priority: undefined, topLevel: true, - isFixed: false, + isFixed: false }; } @@ -10183,10 +10183,9 @@ namespace ts { if (properties.length === 0 && !indexInfo) { return undefined; } - const typeVariable = getIndexedAccessType((getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target)); - const typeVariableArray = [typeVariable]; - const typeInferences = createTypeInferencesObject(); - const typeInferencesArray = [typeInferences]; + const typeParameter = getIndexedAccessType((getConstraintTypeFromMappedType(target)).type, getTypeParameterFromMappedType(target)); + const inference = createInferenceInfo(typeParameter); + const inferences = [inference]; const templateType = getTemplateTypeFromMappedType(target); const readonlyMask = target.declaration.readonlyToken ? false : true; const optionalMask = target.declaration.questionToken ? 0 : SymbolFlags.Optional; @@ -10212,22 +10211,20 @@ namespace ts { return createAnonymousType(undefined, members, emptyArray, emptyArray, indexInfo, undefined); function inferTargetType(sourceType: Type): Type { - typeInferences.primary = undefined; - typeInferences.secondary = undefined; - inferTypes(typeVariableArray, typeInferencesArray, sourceType, templateType); - const inferences = typeInferences.primary || typeInferences.secondary; - return inferences && getUnionType(inferences, /*subtypeReduction*/ true); + inference.candidates = undefined; + inferTypes(inferences, sourceType, templateType); + return inference.candidates && getUnionType(inference.candidates, /*subtypeReduction*/ true); } } function inferTypesWithContext(context: InferenceContext, originalSource: Type, originalTarget: Type) { - inferTypes(context.signature.typeParameters, context.inferences, originalSource, originalTarget); + inferTypes(context.inferences, originalSource, originalTarget); } - function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) { + function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type) { let symbolStack: Symbol[]; let visited: Map; - let inferiority = 0; + let priority = 0; inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type) { @@ -10291,24 +10288,24 @@ namespace ts { if (source.flags & TypeFlags.ContainsAnyFunctionType) { return; } - for (let i = 0; i < typeVariables.length; i++) { - if (target === typeVariables[i]) { - const inferences = typeInferences[i]; - if (!inferences.isFixed) { + for (const inference of inferences) { + if (target === inference.typeParameter) { + if (!inference.isFixed) { // Any inferences that are made to a type parameter in a union type are inferior // to inferences made to a flat (non-union) type. This is because if we infer to // T | string[], we really don't know if we should be inferring to T or not (because // the correct constituent on the target side could be string[]). Therefore, we put // such inferior inferences into a secondary bucket, and only use them if the primary // bucket is empty. - const candidates = inferiority ? - inferences.secondary || (inferences.secondary = []) : - inferences.primary || (inferences.primary = []); - if (!contains(candidates, source)) { - candidates.push(source); + if (!inference.candidates || priority < inference.priority) { + inference.candidates = [source]; + inference.priority = priority; + } + else if (priority === inference.priority) { + inference.candidates.push(source); } if (target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { - inferences.topLevel = false; + inference.topLevel = false; } } return; @@ -10330,7 +10327,7 @@ namespace ts { let typeVariable: TypeVariable; // First infer to each type in union or intersection that isn't a type variable for (const t of targetTypes) { - if (t.flags & TypeFlags.TypeVariable && contains(typeVariables, t)) { + if (getInferenceInfoForType(t)) { typeVariable = t; typeVariableCount++; } @@ -10342,9 +10339,10 @@ namespace ts { // variable. This gives meaningful results for union types in co-variant positions and intersection // types in contra-variant positions (such as callback parameters). if (typeVariableCount === 1) { - inferiority++; + const savePriority = priority; + priority |= InferencePriority.NakedTypeVariable; inferFromTypes(source, typeVariable); - inferiority--; + priority = savePriority; } } else if (source.flags & TypeFlags.UnionOrIntersection) { @@ -10384,6 +10382,17 @@ namespace ts { } } + function getInferenceInfoForType(type: Type) { + if (type.flags & TypeFlags.TypeVariable) { + for (const inference of inferences) { + if (type === inference.typeParameter) { + return inference; + } + } + } + return undefined; + } + function inferFromObjectTypes(source: Type, target: Type) { if (getObjectFlags(target) & ObjectFlags.Mapped) { const constraintType = getConstraintTypeFromMappedType(target); @@ -10392,13 +10401,14 @@ namespace ts { // where T is a type variable. Use inferTypeForHomomorphicMappedType to infer a suitable source // type and then make a secondary inference from that type to T. We make a secondary inference // such that direct inferences to T get priority over inferences to Partial, for example. - const index = indexOf(typeVariables, (constraintType).type); - if (index >= 0 && !typeInferences[index].isFixed) { + const inference = getInferenceInfoForType((constraintType).type); + if (inference && !inference.isFixed) { const inferredType = inferTypeForHomomorphicMappedType(source, target); if (inferredType) { - inferiority++; - inferFromTypes(inferredType, typeVariables[index]); - inferiority--; + const savePriority = priority; + priority |= InferencePriority.MappedType; + inferFromTypes(inferredType, inference.typeParameter); + priority = savePriority; } } return; @@ -10497,33 +10507,29 @@ namespace ts { return type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes); } - function getInferenceCandidates(context: InferenceContext, index: number): Type[] { - const inferences = context.inferences[index]; - return inferences.primary || inferences.secondary || emptyArray; - } - function hasPrimitiveConstraint(type: TypeParameter): boolean { const constraint = getConstraintOfTypeParameter(type); return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index); } function getInferredType(context: InferenceContext, index: number): Type { - let inferredType = context.inferredTypes[index]; + const inference = context.inferences[index]; + let inferredType = inference.inferredType; let inferenceSucceeded: boolean; if (!inferredType) { - const inferences = getInferenceCandidates(context, index); - if (inferences.length) { + const candidates = inference.candidates; + if (candidates) { // We widen inferred literal types if // all inferences were made to top-level ocurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. const signature = context.signature; - const widenLiteralTypes = context.inferences[index].topLevel && - !hasPrimitiveConstraint(signature.typeParameters[index]) && - (context.inferences[index].isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), signature.typeParameters[index])); - const baseInferences = widenLiteralTypes ? sameMap(inferences, getWidenedLiteralType) : inferences; + const widenLiteralTypes = inference.topLevel && + !hasPrimitiveConstraint(inference.typeParameter) && + (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); + const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; // Infer widened union or supertype, or the unknown type for no common supertype - const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseInferences, /*subtypeReduction*/ true) : getCommonSupertype(baseInferences); + const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; inferenceSucceeded = !!unionOrSuperType; } @@ -10533,7 +10539,7 @@ namespace ts { // succeeds, meaning there is no error for not having inference candidates. An // inference error only occurs when there are *conflicting* candidates, i.e. // candidates with no common supertype. - const defaultType = getDefaultFromTypeParameter(context.signature.typeParameters[index]); + const defaultType = getDefaultFromTypeParameter(inference.typeParameter); if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. @@ -10548,7 +10554,7 @@ namespace ts { inferenceSucceeded = true; } - context.inferredTypes[index] = inferredType; + inference.inferredType = inferredType; // Only do the constraint check if inference succeeded (to prevent cascading errors) if (inferenceSucceeded) { @@ -10556,7 +10562,7 @@ namespace ts { if (constraint) { const instantiatedConstraint = instantiateType(constraint, getInferenceMapper(context)); if (!isTypeAssignableTo(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { - context.inferredTypes[index] = inferredType = instantiatedConstraint; + inference.inferredType = inferredType = instantiatedConstraint; } } } @@ -10571,10 +10577,11 @@ namespace ts { } function getInferredTypes(context: InferenceContext): Type[] { - for (let i = 0; i < context.inferredTypes.length; i++) { - getInferredType(context, i); + let result = []; + for (let i = 0; i < context.inferences.length; i++) { + result.push(getInferredType(context, i)); } - return context.inferredTypes; + return result; } // EXPRESSION TYPE CHECKING @@ -14837,18 +14844,18 @@ namespace ts { return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): void { - const typeParameters = signature.typeParameters; + function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): Type[] { + const inferences = context.inferences; const inferenceMapper = getInferenceMapper(context); // Clear out all the inference results from the last time inferTypeArguments was called on this context - for (let i = 0; i < typeParameters.length; i++) { + for (let i = 0; i < inferences.length; i++) { // As an optimization, we don't have to clear (and later recompute) inferred types // for type parameters that have already been fixed on the previous call to inferTypeArguments. // It would be just as correct to reset all of them. But then we'd be repeating the same work // for the type parameters that were fixed, namely the work done by getInferredType. - if (!context.inferences[i].isFixed) { - context.inferredTypes[i] = undefined; + if (!inferences[i].isFixed) { + inferences[i].inferredType = undefined; } } @@ -14908,8 +14915,7 @@ namespace ts { } } } - - getInferredTypes(context); + return getInferredTypes(context); } function checkTypeArguments(signature: Signature, typeArgumentNodes: TypeNode[], typeArgumentTypes: Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): boolean { @@ -15491,7 +15497,7 @@ namespace ts { else { Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); const failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex]; - const inferenceCandidates = getInferenceCandidates(resultOfFailedInference, resultOfFailedInference.failedTypeParameterIndex); + const inferenceCandidates = resultOfFailedInference.inferences[resultOfFailedInference.failedTypeParameterIndex].candidates; let diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, // details will be provided by call to reportNoCommonSupertypeError Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly, @@ -15576,8 +15582,7 @@ namespace ts { typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false); } else { - inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); - typeArgumentTypes = inferenceContext.inferredTypes; + typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined; } if (!typeArgumentsAreValid) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4b95c957f74ce..34aada91f7c53 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3341,25 +3341,29 @@ namespace ts { // The identity mapper and regular instantiation mappers do not need it. } - /* @internal */ - export interface TypeInferences { - primary: Type[]; // Inferences made directly to a type parameter - secondary: Type[]; // Inferences made to a type parameter in a union type - topLevel: boolean; // True if all inferences were made from top-level (not nested in object type) locations - isFixed: boolean; // Whether the type parameter is fixed, as defined in section 4.12.2 of the TypeScript spec - // If a type parameter is fixed, no more inferences can be made for the type parameter + export const enum InferencePriority { + NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type + MappedType = 1 << 1, // Reverse inference for mapped type + } + + export interface InferenceInfo { + typeParameter: TypeParameter; + candidates: Type[]; + inferredType: Type; + priority: InferencePriority; + topLevel: boolean; + isFixed: boolean; } /* @internal */ export interface InferenceContext { signature: Signature; // Generic signature for which inferences are made - inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) - inferences: TypeInferences[]; // Inferences made for each type parameter - inferredTypes: Type[]; // Inferred type for each type parameter + inferences: InferenceInfo[]; // Inferences made for each type parameter mapper?: TypeMapper; // Type mapper for this inference context + inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) + useAnyForNoInferences: boolean; // Use any instead of {} for no inferences failedTypeParameterIndex?: number; // Index of type parameter for which inference failed // It is optional because in contextual signature instantiation, nothing fails - useAnyForNoInferences?: boolean; // Use any instead of {} for no inferences } /* @internal */ From e19d934b7300125807ab5d4df1b8aff215803476 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 11:59:25 -0700 Subject: [PATCH 02/11] Initial implementation of return type inference --- src/compiler/checker.ts | 60 ++++++++++++++++++++++++++++++++--------- src/compiler/types.ts | 4 ++- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1bba954971afb..5bd708a2fbc50 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7937,6 +7937,10 @@ namespace ts { return context.mapper; } + function cloneTypeMapper(mapper: TypeMapper): TypeMapper { + return mapper && mapper.context ? getInferenceMapper(cloneInferenceContext(mapper.context)) : mapper; + } + function identityMapper(type: Type): Type { return type; } @@ -10130,12 +10134,13 @@ namespace ts { } } - function createInferenceContext(signature: Signature, inferUnionTypes: boolean, useAnyForNoInferences: boolean): InferenceContext { + function createInferenceContext(callNode: CallLikeExpression, signature: Signature, inferUnionTypes: boolean, noInferenceType: Type): InferenceContext { return { + callNode, signature, inferences: map(signature.typeParameters, createInferenceInfo), inferUnionTypes, - useAnyForNoInferences + noInferenceType }; } @@ -10150,6 +10155,27 @@ namespace ts { }; } + function cloneInferenceContext(context: InferenceContext): InferenceContext { + return { + callNode: context.callNode, + signature: context.signature, + inferences: map(context.inferences, cloneInferenceInfo), + inferUnionTypes: context.inferUnionTypes, + noInferenceType: silentNeverType + } + } + + function cloneInferenceInfo(inference: InferenceInfo): InferenceInfo { + return { + typeParameter: inference.typeParameter, + candidates: inference.candidates && inference.candidates.slice(), + inferredType: inference.inferredType, + priority: inference.priority, + topLevel: inference.topLevel, + isFixed: inference.isFixed + }; + } + // Return true if the given type could possibly reference a type parameter for which // we perform type inference (i.e. a type parameter of a generic function). We cache // results for union and intersection types for performance reasons. @@ -10221,10 +10247,9 @@ namespace ts { inferTypes(context.inferences, originalSource, originalTarget); } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type) { + function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) { let symbolStack: Symbol[]; let visited: Map; - let priority = 0; inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type) { @@ -10285,7 +10310,7 @@ namespace ts { // it as an inference candidate. Hopefully, a better candidate will come along that does // not contain anyFunctionType when we come back to this argument for its second round // of inference. - if (source.flags & TypeFlags.ContainsAnyFunctionType) { + if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { return; } for (const inference of inferences) { @@ -10517,8 +10542,19 @@ namespace ts { let inferredType = inference.inferredType; let inferenceSucceeded: boolean; if (!inferredType) { - const candidates = inference.candidates; - if (candidates) { + if (!inference.candidates && context.callNode && isExpression(context.callNode)) { + const contextualType = getContextualType(context.callNode); + if (contextualType) { + const mapper = cloneTypeMapper(getContextualMapper(context.callNode)); + const instantiatedType = instantiateType(contextualType, mapper); + const returnType = getReturnTypeOfSignature(context.signature); + const saveFixed = inference.isFixed; + inference.isFixed = false; + inferTypes([inference], instantiatedType, returnType, InferencePriority.ReturnType); + inference.isFixed = saveFixed; + } + } + if (inference.candidates) { // We widen inferred literal types if // all inferences were made to top-level ocurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and @@ -10527,7 +10563,7 @@ namespace ts { const widenLiteralTypes = inference.topLevel && !hasPrimitiveConstraint(inference.typeParameter) && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; + const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; // Infer widened union or supertype, or the unknown type for no common supertype const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; @@ -10539,7 +10575,7 @@ namespace ts { // succeeds, meaning there is no error for not having inference candidates. An // inference error only occurs when there are *conflicting* candidates, i.e. // candidates with no common supertype. - const defaultType = getDefaultFromTypeParameter(inference.typeParameter); + const defaultType = context.noInferenceType === silentNeverType ? undefined : getDefaultFromTypeParameter(inference.typeParameter); if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. @@ -10549,7 +10585,7 @@ namespace ts { getInferenceMapper(context))); } else { - inferredType = context.useAnyForNoInferences ? anyType : emptyObjectType; + inferredType = context.noInferenceType; } inferenceSucceeded = true; @@ -14836,7 +14872,7 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature { - const context = createInferenceContext(signature, /*inferUnionTypes*/ true, /*useAnyForNoInferences*/ false); + const context = createInferenceContext(/*callNode*/ undefined, signature, /*inferUnionTypes*/ true, /*noInferenceType*/ emptyObjectType); forEachMatchingParameterType(contextualSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type inferTypesWithContext(context, instantiateType(source, contextualMapper), target); @@ -15570,7 +15606,7 @@ namespace ts { let candidate: Signature; let typeArgumentsAreValid: boolean; const inferenceContext = originalCandidate.typeParameters - ? createInferenceContext(originalCandidate, /*inferUnionTypes*/ false, /*useAnyForNoInferences*/ isInJavaScriptFile(node)) + ? createInferenceContext(node, originalCandidate, /*inferUnionTypes*/ false, /*noInferenceType*/ isInJavaScriptFile(node) ? anyType : emptyObjectType) : undefined; while (true) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 34aada91f7c53..5e5c2851bf81c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3344,6 +3344,7 @@ namespace ts { export const enum InferencePriority { NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type MappedType = 1 << 1, // Reverse inference for mapped type + ReturnType = 1 << 2, // Inference made from return type of generic function } export interface InferenceInfo { @@ -3357,11 +3358,12 @@ namespace ts { /* @internal */ export interface InferenceContext { + callNode: CallLikeExpression; // Call expression node for which inferences are made signature: Signature; // Generic signature for which inferences are made inferences: InferenceInfo[]; // Inferences made for each type parameter mapper?: TypeMapper; // Type mapper for this inference context inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) - useAnyForNoInferences: boolean; // Use any instead of {} for no inferences + noInferenceType: Type; // Type to use for no inferences failedTypeParameterIndex?: number; // Index of type parameter for which inference failed // It is optional because in contextual signature instantiation, nothing fails } From 68056d52c43e8a04c68980049a60aaa9e92329da Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 14:55:27 -0700 Subject: [PATCH 03/11] Clean up implementation --- src/compiler/checker.ts | 92 +++++++++++++++++++++-------------------- src/compiler/types.ts | 9 +++- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5bd708a2fbc50..222eb4601d903 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10134,13 +10134,12 @@ namespace ts { } } - function createInferenceContext(callNode: CallLikeExpression, signature: Signature, inferUnionTypes: boolean, noInferenceType: Type): InferenceContext { + function createInferenceContext(callNode: CallLikeExpression, signature: Signature, flags: InferenceFlags): InferenceContext { return { callNode, signature, inferences: map(signature.typeParameters, createInferenceInfo), - inferUnionTypes, - noInferenceType + flags, }; } @@ -10160,8 +10159,7 @@ namespace ts { callNode: context.callNode, signature: context.signature, inferences: map(context.inferences, cloneInferenceInfo), - inferUnionTypes: context.inferUnionTypes, - noInferenceType: silentNeverType + flags: context.flags | InferenceFlags.NoDefault, } } @@ -10243,10 +10241,6 @@ namespace ts { } } - function inferTypesWithContext(context: InferenceContext, originalSource: Type, originalTarget: Type) { - inferTypes(context.inferences, originalSource, originalTarget); - } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) { let symbolStack: Symbol[]; let visited: Map; @@ -10315,13 +10309,10 @@ namespace ts { } for (const inference of inferences) { if (target === inference.typeParameter) { - if (!inference.isFixed) { - // Any inferences that are made to a type parameter in a union type are inferior - // to inferences made to a flat (non-union) type. This is because if we infer to - // T | string[], we really don't know if we should be inferring to T or not (because - // the correct constituent on the target side could be string[]). Therefore, we put - // such inferior inferences into a secondary bucket, and only use them if the primary - // bucket is empty. + // Even if an inference is marked as fixed, we can add candidates from inferences made + // from the return type of generic functions (which only happens when no other candidates + // are present). + if (!inference.isFixed || priority & InferencePriority.ReturnType) { if (!inference.candidates || priority < inference.priority) { inference.candidates = [source]; inference.priority = priority; @@ -10543,15 +10534,21 @@ namespace ts { let inferenceSucceeded: boolean; if (!inferredType) { if (!inference.candidates && context.callNode && isExpression(context.callNode)) { + // We have no inference candidates. Now attempt to get the contextual type for the call + // expression associated with the context, and if a contextual type is available, infer + // from that type to the return type of the call expression. For example, given a + // 'function wrap(cb: (x: T) => U): (x: T) => U' and a call expression + // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type + // of 'f' to the return type of 'wrap'. const contextualType = getContextualType(context.callNode); if (contextualType) { + // We clone the contextual mapper to avoid disturbing a resolution in progress for an + // outer call expression. Effectively we just want a snapshot of whatever has been + // inferred for any outer call expression so far. const mapper = cloneTypeMapper(getContextualMapper(context.callNode)); const instantiatedType = instantiateType(contextualType, mapper); const returnType = getReturnTypeOfSignature(context.signature); - const saveFixed = inference.isFixed; - inference.isFixed = false; inferTypes([inference], instantiatedType, returnType, InferencePriority.ReturnType); - inference.isFixed = saveFixed; } } if (inference.candidates) { @@ -10564,30 +10561,37 @@ namespace ts { !hasPrimitiveConstraint(inference.typeParameter) && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; - // Infer widened union or supertype, or the unknown type for no common supertype - const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); + // Infer widened union or supertype, or the unknown type for no common supertype. We infer union types + // for inferences coming from return types in order to avoid common supertype failures. + const unionOrSuperType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? + getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates); inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType; inferenceSucceeded = !!unionOrSuperType; } else { - // Infer either the default or the empty object type when no inferences were - // made. It is important to remember that in this case, inference still - // succeeds, meaning there is no error for not having inference candidates. An - // inference error only occurs when there are *conflicting* candidates, i.e. - // candidates with no common supertype. - const defaultType = context.noInferenceType === silentNeverType ? undefined : getDefaultFromTypeParameter(inference.typeParameter); - if (defaultType) { - // Instantiate the default type. Any forward reference to a type - // parameter should be instantiated to the empty object type. - inferredType = instantiateType(defaultType, - combineTypeMappers( - createBackreferenceMapper(context.signature.typeParameters, index), - getInferenceMapper(context))); + if (context.flags & InferenceFlags.NoDefault) { + // We use silentNeverType as the wildcard that signals no inferences. + inferredType = silentNeverType; } else { - inferredType = context.noInferenceType; + // Infer either the default or the empty object type when no inferences were + // made. It is important to remember that in this case, inference still + // succeeds, meaning there is no error for not having inference candidates. An + // inference error only occurs when there are *conflicting* candidates, i.e. + // candidates with no common supertype. + const defaultType = getDefaultFromTypeParameter(inference.typeParameter); + if (defaultType) { + // Instantiate the default type. Any forward reference to a type + // parameter should be instantiated to the empty object type. + inferredType = instantiateType(defaultType, + combineTypeMappers( + createBackreferenceMapper(context.signature.typeParameters, index), + getInferenceMapper(context))); + } + else { + inferredType = context.flags & InferenceFlags.AnyDefault ? anyType : emptyObjectType; + } } - inferenceSucceeded = true; } inference.inferredType = inferredType; @@ -14872,10 +14876,10 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature { - const context = createInferenceContext(/*callNode*/ undefined, signature, /*inferUnionTypes*/ true, /*noInferenceType*/ emptyObjectType); + const context = createInferenceContext(/*callNode*/ undefined, signature, InferenceFlags.InferUnionTypes); forEachMatchingParameterType(contextualSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type - inferTypesWithContext(context, instantiateType(source, contextualMapper), target); + inferTypes(context.inferences, instantiateType(source, contextualMapper), target); }); return getSignatureInstantiation(signature, getInferredTypes(context)); } @@ -14910,7 +14914,7 @@ namespace ts { if (thisType) { const thisArgumentNode = getThisArgumentOfCall(node); const thisArgumentType = thisArgumentNode ? checkExpression(thisArgumentNode) : voidType; - inferTypesWithContext(context, thisArgumentType, thisType); + inferTypes(context.inferences, thisArgumentType, thisType); } // We perform two passes over the arguments. In the first pass we infer from all arguments, but use @@ -14932,7 +14936,7 @@ namespace ts { argType = checkExpressionWithContextualType(arg, paramType, mapper); } - inferTypesWithContext(context, argType, paramType); + inferTypes(context.inferences, argType, paramType); } } @@ -14947,7 +14951,7 @@ namespace ts { if (excludeArgument[i] === false) { const arg = args[i]; const paramType = getTypeAtPosition(signature, i); - inferTypesWithContext(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); + inferTypes(context.inferences, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); } } } @@ -15606,7 +15610,7 @@ namespace ts { let candidate: Signature; let typeArgumentsAreValid: boolean; const inferenceContext = originalCandidate.typeParameters - ? createInferenceContext(node, originalCandidate, /*inferUnionTypes*/ false, /*noInferenceType*/ isInJavaScriptFile(node) ? anyType : emptyObjectType) + ? createInferenceContext(node, originalCandidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : 0) : undefined; while (true) { @@ -16192,7 +16196,7 @@ namespace ts { for (let i = 0; i < len; i++) { const declaration = signature.parameters[i].valueDeclaration; if (declaration.type) { - inferTypesWithContext(mapper.context, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i)); + inferTypes(mapper.context.inferences, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i)); } } } @@ -16278,7 +16282,7 @@ namespace ts { // T in the second overload so that we do not infer Base as a candidate for T // (inferring Base would make type argument inference inconsistent between the two // overloads). - inferTypesWithContext(mapper.context, links.type, instantiateType(contextualType, mapper)); + inferTypes(mapper.context.inferences, links.type, instantiateType(contextualType, mapper)); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5e5c2851bf81c..08cccd35d7a97 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3356,14 +3356,19 @@ namespace ts { isFixed: boolean; } + export const enum InferenceFlags { + InferUnionTypes = 1 << 0, // Infer union types for disjoint candidates (otherwise unknownType) + NoDefault = 1 << 1, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType) + AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType) + } + /* @internal */ export interface InferenceContext { callNode: CallLikeExpression; // Call expression node for which inferences are made signature: Signature; // Generic signature for which inferences are made inferences: InferenceInfo[]; // Inferences made for each type parameter + flags: InferenceFlags; // Infer union types for disjoint candidates (otherwise undefinedType) mapper?: TypeMapper; // Type mapper for this inference context - inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType) - noInferenceType: Type; // Type to use for no inferences failedTypeParameterIndex?: number; // Index of type parameter for which inference failed // It is optional because in contextual signature instantiation, nothing fails } From 7dd9e2156cb410ecad0d40787e96bf814c467e6d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 14:56:20 -0700 Subject: [PATCH 04/11] Accept new baselines --- tests/baselines/reference/implicitAnyGenerics.types | 2 +- .../reference/recursiveTypeComparison2.errors.txt | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/implicitAnyGenerics.types b/tests/baselines/reference/implicitAnyGenerics.types index 1202c73c51a86..e6237e9f3a2e1 100644 --- a/tests/baselines/reference/implicitAnyGenerics.types +++ b/tests/baselines/reference/implicitAnyGenerics.types @@ -26,7 +26,7 @@ var c3 = new C(); var c4: C = new C(); >c4 : C >C : C ->new C() : C<{}> +>new C() : C >C : typeof C class D { diff --git a/tests/baselines/reference/recursiveTypeComparison2.errors.txt b/tests/baselines/reference/recursiveTypeComparison2.errors.txt index 71f337ad15fb4..5c1200ceec61f 100644 --- a/tests/baselines/reference/recursiveTypeComparison2.errors.txt +++ b/tests/baselines/reference/recursiveTypeComparison2.errors.txt @@ -1,9 +1,7 @@ tests/cases/compiler/recursiveTypeComparison2.ts(13,80): error TS2304: Cannot find name 'StateValue'. -tests/cases/compiler/recursiveTypeComparison2.ts(30,5): error TS2322: Type 'Bus<{}>' is not assignable to type 'Bus'. - Type '{}' is not assignable to type 'number'. -==== tests/cases/compiler/recursiveTypeComparison2.ts (2 errors) ==== +==== tests/cases/compiler/recursiveTypeComparison2.ts (1 errors) ==== // Before fix this would cause compiler to hang (#1170) declare module Bacon { @@ -35,7 +33,4 @@ tests/cases/compiler/recursiveTypeComparison2.ts(30,5): error TS2322: Type 'Bus< var Bus: new () => Bus; } - var stuck: Bacon.Bus = new Bacon.Bus(); - ~~~~~ -!!! error TS2322: Type 'Bus<{}>' is not assignable to type 'Bus'. -!!! error TS2322: Type '{}' is not assignable to type 'number'. \ No newline at end of file + var stuck: Bacon.Bus = new Bacon.Bus(); \ No newline at end of file From 0b37adc3a7fe1cbfa8685818ef92a436e53af773 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 16:48:45 -0700 Subject: [PATCH 05/11] Fix fourslash test --- tests/cases/fourslash/genericCombinators2.ts | 37 ++++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/cases/fourslash/genericCombinators2.ts b/tests/cases/fourslash/genericCombinators2.ts index a5cea18678915..aedadfa301e0a 100644 --- a/tests/cases/fourslash/genericCombinators2.ts +++ b/tests/cases/fourslash/genericCombinators2.ts @@ -1,48 +1,48 @@ /// ////interface Collection { -//// length: number; -//// add(x: T, y: U): void ; -//// remove(x: T, y: U): boolean; -////} +//// length: number; +//// add(x: T, y: U): void ; +//// remove(x: T, y: U): boolean; ////} +//// ////interface Combinators { -//// map(c: Collection, f: (x: T, y: U) => V): Collection; -//// map(c: Collection, f: (x: T, y: U) => any): Collection; -////} +//// map(c: Collection, f: (x: T, y: U) => V): Collection; +//// map(c: Collection, f: (x: T, y: U) => any): Collection; ////} +//// ////class A { -//// foo(): T { return null; } -////} +//// foo(): T { return null; } ////} +//// ////class B { -//// foo(x: T): T { return null; } -////} +//// foo(x: T): T { return null; } ////} +//// ////var c1: Collection; ////var c2: Collection; ////var c3: Collection, string>; ////var c4: Collection; ////var c5: Collection>; -////} +//// ////var _: Combinators; ////// param help on open paren for arg 2 should show 'number' not T or 'any' ////// x should be contextually typed to number ////var rf1 = (x: number, y: string) => { return x.toFixed() }; ////var rf2 = (x: Collection, y: string) => { return x.length }; ////var rf3 = (x: number, y: A) => { return y.foo() }; -////} +//// ////var /*9*/r1a = _.map/*1c*/(c2, (/*1a*/x, /*1b*/y) => { return x.toFixed() }); ////var /*10*/r1b = _.map(c2, rf1); -////} +//// ////var /*11*/r2a = _.map(c3, (/*2a*/x, /*2b*/y) => { return x.length }); ////var /*12*/r2b = _.map(c3, rf2); -////} +//// ////var /*13*/r3a = _.map(c4, (/*3a*/x, /*3b*/y) => { return y.foo() }); ////var /*14*/r3b = _.map(c4, rf3); -////} +//// ////var /*15*/r4a = _.map(c5, (/*4a*/x, /*4b*/y) => { return y.foo() }); -////} +//// ////var /*17*/r5a = _.map(c2, /*17error1*/(/*5a*/x, /*5b*/y) => { return x.toFixed() }/*17error2*/); ////var rf1b = (x: number, y: string) => { return new Date() }; ////var /*18*/r5b = _.map(c2, rf1b); @@ -51,7 +51,7 @@ ////var rf2b = (x: Collection, y: string) => { return new Date(); }; ////var /*20*/r6b = _.map, string, Date>(c3, rf2b); //// -////var /*21*/r7a = _.map(c4, /*21error1*/(/*7a*/x,/*7b*/y) => { return y.foo() }/*21error2*/); +////var /*21*/r7a = _.map(c4, (/*7a*/x,/*7b*/y) => { return y.foo() }); ////var /*22*/r7b = _.map(c4, /*22error1*/rf3/*22error2*/); //// ////var /*23*/r8a = _.map(c5, (/*8a*/x,/*8b*/y) => { return y.foo() }); @@ -89,5 +89,4 @@ verify.quickInfos({ verify.errorExistsBetweenMarkers('error1', 'error2'); verify.errorExistsBetweenMarkers('17error1', '17error2'); -verify.errorExistsBetweenMarkers('21error1', '21error2'); verify.errorExistsBetweenMarkers('22error1', '22error2'); \ No newline at end of file From 501d92a0494412ead4728502eb63c226664cb071 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 22 May 2017 16:48:57 -0700 Subject: [PATCH 06/11] Fix linting errors --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8c42d8906659b..de0feae2f08e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10159,8 +10159,8 @@ namespace ts { callNode: context.callNode, signature: context.signature, inferences: map(context.inferences, cloneInferenceInfo), - flags: context.flags | InferenceFlags.NoDefault, - } + flags: context.flags | InferenceFlags.NoDefault + }; } function cloneInferenceInfo(inference: InferenceInfo): InferenceInfo { @@ -10617,7 +10617,7 @@ namespace ts { } function getInferredTypes(context: InferenceContext): Type[] { - let result = []; + const result: Type[] = []; for (let i = 0; i < context.inferences.length; i++) { result.push(getInferredType(context, i)); } From 77e2f097c36ee66239a1715ac3154c79f457f5e4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 May 2017 10:44:19 -0700 Subject: [PATCH 07/11] InferenceContext is-a TypeMapper instead of has-a TypeMapper --- src/compiler/checker.ts | 71 +++++++++++++++++------------------------ src/compiler/types.ts | 8 ++--- 2 files changed, 32 insertions(+), 47 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de0feae2f08e6..e323d97d78192 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7918,27 +7918,14 @@ namespace ts { return mapper; } - function getInferenceMapper(context: InferenceContext): TypeMapper { - if (!context.mapper) { - const mapper: TypeMapper = t => { - const inferences = context.inferences; - for (let i = 0; i < inferences.length; i++) { - if (t === inferences[i].typeParameter) { - inferences[i].isFixed = true; - return getInferredType(context, i); - } - } - return t; - }; - mapper.mappedTypes = context.signature.typeParameters; - mapper.context = context; - context.mapper = mapper; - } - return context.mapper; + function isInferenceContext(mapper: TypeMapper): mapper is InferenceContext { + return !!(mapper).signature; } function cloneTypeMapper(mapper: TypeMapper): TypeMapper { - return mapper && mapper.context ? getInferenceMapper(cloneInferenceContext(mapper.context)) : mapper; + return mapper && isInferenceContext(mapper) ? + createInferenceContext(mapper.callNode, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.inferences) : + mapper; } function identityMapper(type: Type): Type { @@ -10134,13 +10121,25 @@ namespace ts { } } - function createInferenceContext(callNode: CallLikeExpression, signature: Signature, flags: InferenceFlags): InferenceContext { - return { - callNode, - signature, - inferences: map(signature.typeParameters, createInferenceInfo), - flags, - }; + function createInferenceContext(callNode: CallLikeExpression, signature: Signature, flags: InferenceFlags, baseInferences?: InferenceInfo[]): InferenceContext { + const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo); + const context = mapper as InferenceContext; + context.mappedTypes = signature.typeParameters; + context.callNode = callNode; + context.signature = signature; + context.inferences = inferences; + context.flags = flags; + return context; + + function mapper(t: Type): Type { + for (let i = 0; i < inferences.length; i++) { + if (t === inferences[i].typeParameter) { + inferences[i].isFixed = true; + return getInferredType(context, i); + } + } + return t; + } } function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { @@ -10154,15 +10153,6 @@ namespace ts { }; } - function cloneInferenceContext(context: InferenceContext): InferenceContext { - return { - callNode: context.callNode, - signature: context.signature, - inferences: map(context.inferences, cloneInferenceInfo), - flags: context.flags | InferenceFlags.NoDefault - }; - } - function cloneInferenceInfo(inference: InferenceInfo): InferenceInfo { return { typeParameter: inference.typeParameter, @@ -10586,7 +10576,7 @@ namespace ts { inferredType = instantiateType(defaultType, combineTypeMappers( createBackreferenceMapper(context.signature.typeParameters, index), - getInferenceMapper(context))); + context)); } else { inferredType = context.flags & InferenceFlags.AnyDefault ? anyType : emptyObjectType; @@ -10600,7 +10590,7 @@ namespace ts { if (inferenceSucceeded) { const constraint = getConstraintOfTypeParameter(context.signature.typeParameters[index]); if (constraint) { - const instantiatedConstraint = instantiateType(constraint, getInferenceMapper(context)); + const instantiatedConstraint = instantiateType(constraint, context); if (!isTypeAssignableTo(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { inference.inferredType = inferredType = instantiatedConstraint; } @@ -14886,7 +14876,6 @@ namespace ts { function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: Expression[], excludeArgument: boolean[], context: InferenceContext): Type[] { const inferences = context.inferences; - const inferenceMapper = getInferenceMapper(context); // Clear out all the inference results from the last time inferTypeArguments was called on this context for (let i = 0; i < inferences.length; i++) { @@ -14932,7 +14921,7 @@ namespace ts { if (argType === undefined) { // For context sensitive arguments we pass the identityMapper, which is a signal to treat all // context sensitive function expressions as wildcards - const mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper; + const mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : context; argType = checkExpressionWithContextualType(arg, paramType, mapper); } @@ -14951,7 +14940,7 @@ namespace ts { if (excludeArgument[i] === false) { const arg = args[i]; const paramType = getTypeAtPosition(signature, i); - inferTypes(context.inferences, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType); + inferTypes(context.inferences, checkExpressionWithContextualType(arg, paramType, context), paramType); } } } @@ -16196,7 +16185,7 @@ namespace ts { for (let i = 0; i < len; i++) { const declaration = signature.parameters[i].valueDeclaration; if (declaration.type) { - inferTypes(mapper.context.inferences, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i)); + inferTypes((mapper).inferences, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i)); } } } @@ -16282,7 +16271,7 @@ namespace ts { // T in the second overload so that we do not infer Base as a candidate for T // (inferring Base would make type argument inference inconsistent between the two // overloads). - inferTypes(mapper.context.inferences, links.type, instantiateType(contextualType, mapper)); + inferTypes((mapper).inferences, links.type, instantiateType(contextualType, mapper)); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 08cccd35d7a97..9a36f0b285fcf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3336,9 +3336,6 @@ namespace ts { (t: TypeParameter): Type; mappedTypes?: Type[]; // Types mapped by this mapper instantiations?: Type[]; // Cache of instantiations created using this type mapper. - context?: InferenceContext; // The inference context this mapper was created from. - // Only inference mappers have this set (in createInferenceMapper). - // The identity mapper and regular instantiation mappers do not need it. } export const enum InferencePriority { @@ -3363,12 +3360,11 @@ namespace ts { } /* @internal */ - export interface InferenceContext { + export interface InferenceContext extends TypeMapper { callNode: CallLikeExpression; // Call expression node for which inferences are made signature: Signature; // Generic signature for which inferences are made inferences: InferenceInfo[]; // Inferences made for each type parameter - flags: InferenceFlags; // Infer union types for disjoint candidates (otherwise undefinedType) - mapper?: TypeMapper; // Type mapper for this inference context + flags: InferenceFlags; // Inference flags failedTypeParameterIndex?: number; // Index of type parameter for which inference failed // It is optional because in contextual signature instantiation, nothing fails } From b8d5eff8ace9ee4c6dc46a0c80be126c51983756 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 May 2017 15:31:10 -0700 Subject: [PATCH 08/11] Move return type inference to inferTypeArguments function --- src/compiler/checker.ts | 49 ++++++++++++++++++++--------------------- src/compiler/types.ts | 1 - 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e323d97d78192..30100332210cb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7924,7 +7924,7 @@ namespace ts { function cloneTypeMapper(mapper: TypeMapper): TypeMapper { return mapper && isInferenceContext(mapper) ? - createInferenceContext(mapper.callNode, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.inferences) : + createInferenceContext(mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.inferences) : mapper; } @@ -10121,11 +10121,10 @@ namespace ts { } } - function createInferenceContext(callNode: CallLikeExpression, signature: Signature, flags: InferenceFlags, baseInferences?: InferenceInfo[]): InferenceContext { + function createInferenceContext(signature: Signature, flags: InferenceFlags, baseInferences?: InferenceInfo[]): InferenceContext { const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo); const context = mapper as InferenceContext; context.mappedTypes = signature.typeParameters; - context.callNode = callNode; context.signature = signature; context.inferences = inferences; context.flags = flags; @@ -10302,7 +10301,7 @@ namespace ts { // Even if an inference is marked as fixed, we can add candidates from inferences made // from the return type of generic functions (which only happens when no other candidates // are present). - if (!inference.isFixed || priority & InferencePriority.ReturnType) { + if (!inference.isFixed) { if (!inference.candidates || priority < inference.priority) { inference.candidates = [source]; inference.priority = priority; @@ -10310,7 +10309,7 @@ namespace ts { else if (priority === inference.priority) { inference.candidates.push(source); } - if (target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { + if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { inference.topLevel = false; } } @@ -10523,24 +10522,6 @@ namespace ts { let inferredType = inference.inferredType; let inferenceSucceeded: boolean; if (!inferredType) { - if (!inference.candidates && context.callNode && isExpression(context.callNode)) { - // We have no inference candidates. Now attempt to get the contextual type for the call - // expression associated with the context, and if a contextual type is available, infer - // from that type to the return type of the call expression. For example, given a - // 'function wrap(cb: (x: T) => U): (x: T) => U' and a call expression - // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type - // of 'f' to the return type of 'wrap'. - const contextualType = getContextualType(context.callNode); - if (contextualType) { - // We clone the contextual mapper to avoid disturbing a resolution in progress for an - // outer call expression. Effectively we just want a snapshot of whatever has been - // inferred for any outer call expression so far. - const mapper = cloneTypeMapper(getContextualMapper(context.callNode)); - const instantiatedType = instantiateType(contextualType, mapper); - const returnType = getReturnTypeOfSignature(context.signature); - inferTypes([inference], instantiatedType, returnType, InferencePriority.ReturnType); - } - } if (inference.candidates) { // We widen inferred literal types if // all inferences were made to top-level ocurrences of the type parameter, and @@ -14866,7 +14847,7 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature { - const context = createInferenceContext(/*callNode*/ undefined, signature, InferenceFlags.InferUnionTypes); + const context = createInferenceContext(signature, InferenceFlags.InferUnionTypes); forEachMatchingParameterType(contextualSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type inferTypes(context.inferences, instantiateType(source, contextualMapper), target); @@ -14899,6 +14880,24 @@ namespace ts { context.failedTypeParameterIndex = undefined; } + // If a contextual type is available, infer from that type to the return type of the call expression. For + // example, given a 'function wrap(cb: (x: T) => U): (x: T) => U' and a call expression + // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the + // return type of 'wrap'. + if (isExpression(node)) { + const contextualType = getContextualType(node); + if (contextualType) { + // We clone the contextual mapper to avoid disturbing a resolution in progress for an + // outer call expression. Effectively we just want a snapshot of whatever has been + // inferred for any outer call expression so far. + const mapper = cloneTypeMapper(getContextualMapper(node)); + const instantiatedType = instantiateType(contextualType, mapper); + const returnType = getReturnTypeOfSignature(signature); + // Inferences made from return types have lower priority than all other inferences. + inferTypes(context.inferences, instantiatedType, returnType, InferencePriority.ReturnType); + } + } + const thisType = getThisTypeOfSignature(signature); if (thisType) { const thisArgumentNode = getThisArgumentOfCall(node); @@ -15599,7 +15598,7 @@ namespace ts { let candidate: Signature; let typeArgumentsAreValid: boolean; const inferenceContext = originalCandidate.typeParameters - ? createInferenceContext(node, originalCandidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : 0) + ? createInferenceContext(originalCandidate, /*flags*/ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : 0) : undefined; while (true) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9a36f0b285fcf..d42f975f682d2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3361,7 +3361,6 @@ namespace ts { /* @internal */ export interface InferenceContext extends TypeMapper { - callNode: CallLikeExpression; // Call expression node for which inferences are made signature: Signature; // Generic signature for which inferences are made inferences: InferenceInfo[]; // Inferences made for each type parameter flags: InferenceFlags; // Inference flags From f29d7df5d150070eb0e3e4cf49d76560d72ea63b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 May 2017 15:50:30 -0700 Subject: [PATCH 09/11] Add tests --- .../inferFromGenericFunctionReturnTypes1.ts | 70 ++++++++++++++ .../inferFromGenericFunctionReturnTypes2.ts | 94 +++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts create mode 100644 tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts diff --git a/tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts b/tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts new file mode 100644 index 0000000000000..3fb454ec7e5eb --- /dev/null +++ b/tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts @@ -0,0 +1,70 @@ +// Repro from #15680 + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { + _store: A[]; + + add(a: A) { + this._store.push(a); + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { + return transformer(this); + } + + forEach(fn: (a: A, index: number) => void) { + this._store.forEach((a, i) => fn(a, i)); + } +} + +function compose( + fnA: (a: SetOf) => SetOf, + fnB: (b: SetOf) => SetOf, + fnC: (c: SetOf) => SetOf, + fnD: (c: SetOf) => SetOf, +):(x: SetOf) => SetOf; +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { + return (a: SetOf) => { + const b: SetOf = new SetOf(); + a.forEach(x => b.add(fn(x))); + return b; + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { + return (a: SetOf) => { + const result = new SetOf(); + a.forEach(x => { + if (predicate(x)) result.add(x); + }); + return result; + } +} + +const testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); + +testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) + +testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => 123), // Whoops a bug + map(x => x.toUpperCase()) // causes an error! + ) +) diff --git a/tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts b/tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts new file mode 100644 index 0000000000000..314159d363c74 --- /dev/null +++ b/tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts @@ -0,0 +1,94 @@ +type Mapper = (x: T) => U; + +declare function wrap(cb: Mapper): Mapper; + +declare function arrayize(cb: Mapper): Mapper; + +declare function combine(f: (x: A) => B, g: (x: B) => C): (x: A) => C; + +declare function foo(f: Mapper): void; + +let f1: Mapper = s => s.length; +let f2: Mapper = wrap(s => s.length); +let f3: Mapper = arrayize(wrap(s => s.length)); +let f4: Mapper = combine(wrap(s => s.length), wrap(n => n >= 10)); + +foo(wrap(s => s.length)); + +let a1 = ["a", "b"].map(s => s.length); +let a2 = ["a", "b"].map(wrap(s => s.length)); +let a3 = ["a", "b"].map(wrap(arrayize(s => s.length))); +let a4 = ["a", "b"].map(combine(wrap(s => s.length), wrap(n => n > 10))); +let a5 = ["a", "b"].map(combine(identity, wrap(s => s.length))); +let a6 = ["a", "b"].map(combine(wrap(s => s.length), identity)); + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { + _store: A[]; + + add(a: A) { + this._store.push(a); + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { + return transformer(this); + } + + forEach(fn: (a: A, index: number) => void) { + this._store.forEach((a, i) => fn(a, i)); + } +} + +function compose( + fnA: (a: SetOf) => SetOf, + fnB: (b: SetOf) => SetOf, + fnC: (c: SetOf) => SetOf, + fnD: (c: SetOf) => SetOf, +):(x: SetOf) => SetOf; +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { + return (a: SetOf) => { + const b: SetOf = new SetOf(); + a.forEach(x => b.add(fn(x))); + return b; + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { + return (a: SetOf) => { + const result = new SetOf(); + a.forEach(x => { + if (predicate(x)) result.add(x); + }); + return result; + } +} + +const testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); + +const t1 = testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) + +declare function identity(x: T): T; + +const t2 = testSet.transform( + compose( + filter(x => x % 1 === 0), + identity, + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) From 5fa0fb46d181f8ad0895884f6d2a0698c868ef21 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 May 2017 15:50:39 -0700 Subject: [PATCH 10/11] Accept new baselines --- ...FromGenericFunctionReturnTypes1.errors.txt | 77 +++ .../inferFromGenericFunctionReturnTypes1.js | 123 ++++ .../inferFromGenericFunctionReturnTypes2.js | 155 +++++ ...ferFromGenericFunctionReturnTypes2.symbols | 480 ++++++++++++++ ...inferFromGenericFunctionReturnTypes2.types | 600 ++++++++++++++++++ 5 files changed, 1435 insertions(+) create mode 100644 tests/baselines/reference/inferFromGenericFunctionReturnTypes1.errors.txt create mode 100644 tests/baselines/reference/inferFromGenericFunctionReturnTypes1.js create mode 100644 tests/baselines/reference/inferFromGenericFunctionReturnTypes2.js create mode 100644 tests/baselines/reference/inferFromGenericFunctionReturnTypes2.symbols create mode 100644 tests/baselines/reference/inferFromGenericFunctionReturnTypes2.types diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.errors.txt b/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.errors.txt new file mode 100644 index 0000000000000..4ed8bdd81c63f --- /dev/null +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.errors.txt @@ -0,0 +1,77 @@ +tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts(68,16): error TS2339: Property 'toUpperCase' does not exist on type 'number'. + + +==== tests/cases/compiler/inferFromGenericFunctionReturnTypes1.ts (1 errors) ==== + // Repro from #15680 + + // This is a contrived class. We could do the same thing with Observables, etc. + class SetOf { + _store: A[]; + + add(a: A) { + this._store.push(a); + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { + return transformer(this); + } + + forEach(fn: (a: A, index: number) => void) { + this._store.forEach((a, i) => fn(a, i)); + } + } + + function compose( + fnA: (a: SetOf) => SetOf, + fnB: (b: SetOf) => SetOf, + fnC: (c: SetOf) => SetOf, + fnD: (c: SetOf) => SetOf, + ):(x: SetOf) => SetOf; + /* ... etc ... */ + function compose(...fns: ((x: T) => T)[]): (x: T) => T { + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); + } + + function map(fn: (a: A) => B): (s: SetOf) => SetOf { + return (a: SetOf) => { + const b: SetOf = new SetOf(); + a.forEach(x => b.add(fn(x))); + return b; + } + } + + function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { + return (a: SetOf) => { + const result = new SetOf(); + a.forEach(x => { + if (predicate(x)) result.add(x); + }); + return result; + } + } + + const testSet = new SetOf(); + testSet.add(1); + testSet.add(2); + testSet.add(3); + + testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) + ) + + testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => 123), // Whoops a bug + map(x => x.toUpperCase()) // causes an error! + ~~~~~~~~~~~ +!!! error TS2339: Property 'toUpperCase' does not exist on type 'number'. + ) + ) + \ No newline at end of file diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.js b/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.js new file mode 100644 index 0000000000000..0c3cf4b0cbeb6 --- /dev/null +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes1.js @@ -0,0 +1,123 @@ +//// [inferFromGenericFunctionReturnTypes1.ts] +// Repro from #15680 + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { + _store: A[]; + + add(a: A) { + this._store.push(a); + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { + return transformer(this); + } + + forEach(fn: (a: A, index: number) => void) { + this._store.forEach((a, i) => fn(a, i)); + } +} + +function compose( + fnA: (a: SetOf) => SetOf, + fnB: (b: SetOf) => SetOf, + fnC: (c: SetOf) => SetOf, + fnD: (c: SetOf) => SetOf, +):(x: SetOf) => SetOf; +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { + return (a: SetOf) => { + const b: SetOf = new SetOf(); + a.forEach(x => b.add(fn(x))); + return b; + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { + return (a: SetOf) => { + const result = new SetOf(); + a.forEach(x => { + if (predicate(x)) result.add(x); + }); + return result; + } +} + +const testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); + +testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) + +testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => 123), // Whoops a bug + map(x => x.toUpperCase()) // causes an error! + ) +) + + +//// [inferFromGenericFunctionReturnTypes1.js] +// Repro from #15680 +// This is a contrived class. We could do the same thing with Observables, etc. +var SetOf = (function () { + function SetOf() { + } + SetOf.prototype.add = function (a) { + this._store.push(a); + }; + SetOf.prototype.transform = function (transformer) { + return transformer(this); + }; + SetOf.prototype.forEach = function (fn) { + this._store.forEach(function (a, i) { return fn(a, i); }); + }; + return SetOf; +}()); +/* ... etc ... */ +function compose() { + var fns = []; + for (var _i = 0; _i < arguments.length; _i++) { + fns[_i] = arguments[_i]; + } + return function (x) { return fns.reduce(function (prev, fn) { return fn(prev); }, x); }; +} +function map(fn) { + return function (a) { + var b = new SetOf(); + a.forEach(function (x) { return b.add(fn(x)); }); + return b; + }; +} +function filter(predicate) { + return function (a) { + var result = new SetOf(); + a.forEach(function (x) { + if (predicate(x)) + result.add(x); + }); + return result; + }; +} +var testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); +testSet.transform(compose(filter(function (x) { return x % 1 === 0; }), map(function (x) { return x + x; }), map(function (x) { return x + '!!!'; }), map(function (x) { return x.toUpperCase(); }))); +testSet.transform(compose(filter(function (x) { return x % 1 === 0; }), map(function (x) { return x + x; }), map(function (x) { return 123; }), // Whoops a bug +map(function (x) { return x.toUpperCase(); }) // causes an error! +)); diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.js b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.js new file mode 100644 index 0000000000000..3f95b10d08a08 --- /dev/null +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.js @@ -0,0 +1,155 @@ +//// [inferFromGenericFunctionReturnTypes2.ts] +type Mapper = (x: T) => U; + +declare function wrap(cb: Mapper): Mapper; + +declare function arrayize(cb: Mapper): Mapper; + +declare function combine(f: (x: A) => B, g: (x: B) => C): (x: A) => C; + +declare function foo(f: Mapper): void; + +let f1: Mapper = s => s.length; +let f2: Mapper = wrap(s => s.length); +let f3: Mapper = arrayize(wrap(s => s.length)); +let f4: Mapper = combine(wrap(s => s.length), wrap(n => n >= 10)); + +foo(wrap(s => s.length)); + +let a1 = ["a", "b"].map(s => s.length); +let a2 = ["a", "b"].map(wrap(s => s.length)); +let a3 = ["a", "b"].map(wrap(arrayize(s => s.length))); +let a4 = ["a", "b"].map(combine(wrap(s => s.length), wrap(n => n > 10))); +let a5 = ["a", "b"].map(combine(identity, wrap(s => s.length))); +let a6 = ["a", "b"].map(combine(wrap(s => s.length), identity)); + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { + _store: A[]; + + add(a: A) { + this._store.push(a); + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { + return transformer(this); + } + + forEach(fn: (a: A, index: number) => void) { + this._store.forEach((a, i) => fn(a, i)); + } +} + +function compose( + fnA: (a: SetOf) => SetOf, + fnB: (b: SetOf) => SetOf, + fnC: (c: SetOf) => SetOf, + fnD: (c: SetOf) => SetOf, +):(x: SetOf) => SetOf; +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { + return (a: SetOf) => { + const b: SetOf = new SetOf(); + a.forEach(x => b.add(fn(x))); + return b; + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { + return (a: SetOf) => { + const result = new SetOf(); + a.forEach(x => { + if (predicate(x)) result.add(x); + }); + return result; + } +} + +const testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); + +const t1 = testSet.transform( + compose( + filter(x => x % 1 === 0), + map(x => x + x), + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) + +declare function identity(x: T): T; + +const t2 = testSet.transform( + compose( + filter(x => x % 1 === 0), + identity, + map(x => x + '!!!'), + map(x => x.toUpperCase()) + ) +) + + +//// [inferFromGenericFunctionReturnTypes2.js] +var f1 = function (s) { return s.length; }; +var f2 = wrap(function (s) { return s.length; }); +var f3 = arrayize(wrap(function (s) { return s.length; })); +var f4 = combine(wrap(function (s) { return s.length; }), wrap(function (n) { return n >= 10; })); +foo(wrap(function (s) { return s.length; })); +var a1 = ["a", "b"].map(function (s) { return s.length; }); +var a2 = ["a", "b"].map(wrap(function (s) { return s.length; })); +var a3 = ["a", "b"].map(wrap(arrayize(function (s) { return s.length; }))); +var a4 = ["a", "b"].map(combine(wrap(function (s) { return s.length; }), wrap(function (n) { return n > 10; }))); +var a5 = ["a", "b"].map(combine(identity, wrap(function (s) { return s.length; }))); +var a6 = ["a", "b"].map(combine(wrap(function (s) { return s.length; }), identity)); +// This is a contrived class. We could do the same thing with Observables, etc. +var SetOf = (function () { + function SetOf() { + } + SetOf.prototype.add = function (a) { + this._store.push(a); + }; + SetOf.prototype.transform = function (transformer) { + return transformer(this); + }; + SetOf.prototype.forEach = function (fn) { + this._store.forEach(function (a, i) { return fn(a, i); }); + }; + return SetOf; +}()); +/* ... etc ... */ +function compose() { + var fns = []; + for (var _i = 0; _i < arguments.length; _i++) { + fns[_i] = arguments[_i]; + } + return function (x) { return fns.reduce(function (prev, fn) { return fn(prev); }, x); }; +} +function map(fn) { + return function (a) { + var b = new SetOf(); + a.forEach(function (x) { return b.add(fn(x)); }); + return b; + }; +} +function filter(predicate) { + return function (a) { + var result = new SetOf(); + a.forEach(function (x) { + if (predicate(x)) + result.add(x); + }); + return result; + }; +} +var testSet = new SetOf(); +testSet.add(1); +testSet.add(2); +testSet.add(3); +var t1 = testSet.transform(compose(filter(function (x) { return x % 1 === 0; }), map(function (x) { return x + x; }), map(function (x) { return x + '!!!'; }), map(function (x) { return x.toUpperCase(); }))); +var t2 = testSet.transform(compose(filter(function (x) { return x % 1 === 0; }), identity, map(function (x) { return x + '!!!'; }), map(function (x) { return x.toUpperCase(); }))); diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.symbols b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.symbols new file mode 100644 index 0000000000000..79a855badb5a8 --- /dev/null +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.symbols @@ -0,0 +1,480 @@ +=== tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts === +type Mapper = (x: T) => U; +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 12)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 14)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 21)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 12)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 14)) + +declare function wrap(cb: Mapper): Mapper; +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 22)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 24)) +>cb : Symbol(cb, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 28)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 22)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 24)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 22)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 24)) + +declare function arrayize(cb: Mapper): Mapper; +>arrayize : Symbol(arrayize, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 60)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 26)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 28)) +>cb : Symbol(cb, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 32)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 26)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 28)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 26)) +>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 28)) + +declare function combine(f: (x: A) => B, g: (x: B) => C): (x: A) => C; +>combine : Symbol(combine, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 66)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 25)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 27)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 30)) +>f : Symbol(f, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 34)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 38)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 25)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 27)) +>g : Symbol(g, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 49)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 54)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 27)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 30)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 68)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 25)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 30)) + +declare function foo(f: Mapper): void; +>foo : Symbol(foo, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 79)) +>f : Symbol(f, Decl(inferFromGenericFunctionReturnTypes2.ts, 8, 21)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) + +let f1: Mapper = s => s.length; +>f1 : Symbol(f1, Decl(inferFromGenericFunctionReturnTypes2.ts, 10, 3)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 10, 32)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 10, 32)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let f2: Mapper = wrap(s => s.length); +>f2 : Symbol(f2, Decl(inferFromGenericFunctionReturnTypes2.ts, 11, 3)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 11, 38)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 11, 38)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let f3: Mapper = arrayize(wrap(s => s.length)); +>f3 : Symbol(f3, Decl(inferFromGenericFunctionReturnTypes2.ts, 12, 3)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>arrayize : Symbol(arrayize, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 60)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 12, 49)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 12, 49)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let f4: Mapper = combine(wrap(s => s.length), wrap(n => n >= 10)); +>f4 : Symbol(f4, Decl(inferFromGenericFunctionReturnTypes2.ts, 13, 3)) +>Mapper : Symbol(Mapper, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 0)) +>combine : Symbol(combine, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 66)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 13, 47)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 13, 47)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>n : Symbol(n, Decl(inferFromGenericFunctionReturnTypes2.ts, 13, 68)) +>n : Symbol(n, Decl(inferFromGenericFunctionReturnTypes2.ts, 13, 68)) + +foo(wrap(s => s.length)); +>foo : Symbol(foo, Decl(inferFromGenericFunctionReturnTypes2.ts, 6, 79)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 15, 9)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 15, 9)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let a1 = ["a", "b"].map(s => s.length); +>a1 : Symbol(a1, Decl(inferFromGenericFunctionReturnTypes2.ts, 17, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 17, 24)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 17, 24)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let a2 = ["a", "b"].map(wrap(s => s.length)); +>a2 : Symbol(a2, Decl(inferFromGenericFunctionReturnTypes2.ts, 18, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 18, 29)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 18, 29)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let a3 = ["a", "b"].map(wrap(arrayize(s => s.length))); +>a3 : Symbol(a3, Decl(inferFromGenericFunctionReturnTypes2.ts, 19, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>arrayize : Symbol(arrayize, Decl(inferFromGenericFunctionReturnTypes2.ts, 2, 60)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 19, 38)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 19, 38)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let a4 = ["a", "b"].map(combine(wrap(s => s.length), wrap(n => n > 10))); +>a4 : Symbol(a4, Decl(inferFromGenericFunctionReturnTypes2.ts, 20, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>combine : Symbol(combine, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 66)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 20, 37)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 20, 37)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>n : Symbol(n, Decl(inferFromGenericFunctionReturnTypes2.ts, 20, 58)) +>n : Symbol(n, Decl(inferFromGenericFunctionReturnTypes2.ts, 20, 58)) + +let a5 = ["a", "b"].map(combine(identity, wrap(s => s.length))); +>a5 : Symbol(a5, Decl(inferFromGenericFunctionReturnTypes2.ts, 21, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>combine : Symbol(combine, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 66)) +>identity : Symbol(identity, Decl(inferFromGenericFunctionReturnTypes2.ts, 82, 1)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 21, 47)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 21, 47)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +let a6 = ["a", "b"].map(combine(wrap(s => s.length), identity)); +>a6 : Symbol(a6, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 3)) +>["a", "b"].map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>combine : Symbol(combine, Decl(inferFromGenericFunctionReturnTypes2.ts, 4, 66)) +>wrap : Symbol(wrap, Decl(inferFromGenericFunctionReturnTypes2.ts, 0, 32)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 37)) +>s.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 37)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>identity : Symbol(identity, Decl(inferFromGenericFunctionReturnTypes2.ts, 82, 1)) + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 12)) + + _store: A[]; +>_store : Symbol(SetOf._store, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 16)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 12)) + + add(a: A) { +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 28, 6)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 12)) + + this._store.push(a); +>this._store.push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>this._store : Symbol(SetOf._store, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 16)) +>this : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>_store : Symbol(SetOf._store, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 16)) +>push : Symbol(Array.push, Decl(lib.d.ts, --, --)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 28, 6)) + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { +>transform : Symbol(SetOf.transform, Decl(inferFromGenericFunctionReturnTypes2.ts, 30, 3)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 12)) +>transformer : Symbol(transformer, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 15)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 29)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 12)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 12)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 12)) + + return transformer(this); +>transformer : Symbol(transformer, Decl(inferFromGenericFunctionReturnTypes2.ts, 32, 15)) +>this : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) + } + + forEach(fn: (a: A, index: number) => void) { +>forEach : Symbol(SetOf.forEach, Decl(inferFromGenericFunctionReturnTypes2.ts, 34, 3)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 36, 10)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 36, 15)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 12)) +>index : Symbol(index, Decl(inferFromGenericFunctionReturnTypes2.ts, 36, 20)) + + this._store.forEach((a, i) => fn(a, i)); +>this._store.forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>this._store : Symbol(SetOf._store, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 16)) +>this : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>_store : Symbol(SetOf._store, Decl(inferFromGenericFunctionReturnTypes2.ts, 25, 16)) +>forEach : Symbol(Array.forEach, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 37, 27)) +>i : Symbol(i, Decl(inferFromGenericFunctionReturnTypes2.ts, 37, 29)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 36, 10)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 37, 27)) +>i : Symbol(i, Decl(inferFromGenericFunctionReturnTypes2.ts, 37, 29)) + } +} + +function compose( +>compose : Symbol(compose, Decl(inferFromGenericFunctionReturnTypes2.ts, 39, 1), Decl(inferFromGenericFunctionReturnTypes2.ts, 46, 28)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 17)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 19)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 22)) +>D : Symbol(D, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 25)) +>E : Symbol(E, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 28)) + + fnA: (a: SetOf) => SetOf, +>fnA : Symbol(fnA, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 32)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 42, 8)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 17)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 19)) + + fnB: (b: SetOf) => SetOf, +>fnB : Symbol(fnB, Decl(inferFromGenericFunctionReturnTypes2.ts, 42, 33)) +>b : Symbol(b, Decl(inferFromGenericFunctionReturnTypes2.ts, 43, 8)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 19)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 22)) + + fnC: (c: SetOf) => SetOf, +>fnC : Symbol(fnC, Decl(inferFromGenericFunctionReturnTypes2.ts, 43, 33)) +>c : Symbol(c, Decl(inferFromGenericFunctionReturnTypes2.ts, 44, 8)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>C : Symbol(C, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 22)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>D : Symbol(D, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 25)) + + fnD: (c: SetOf) => SetOf, +>fnD : Symbol(fnD, Decl(inferFromGenericFunctionReturnTypes2.ts, 44, 33)) +>c : Symbol(c, Decl(inferFromGenericFunctionReturnTypes2.ts, 45, 8)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>D : Symbol(D, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 25)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>E : Symbol(E, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 28)) + +):(x: SetOf) => SetOf; +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 46, 3)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 17)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>E : Symbol(E, Decl(inferFromGenericFunctionReturnTypes2.ts, 41, 28)) + +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { +>compose : Symbol(compose, Decl(inferFromGenericFunctionReturnTypes2.ts, 39, 1), Decl(inferFromGenericFunctionReturnTypes2.ts, 46, 28)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) +>fns : Symbol(fns, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 20)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 30)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 47)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) + + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 10)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 17)) +>fns.reduce : Symbol(Array.reduce, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>fns : Symbol(fns, Decl(inferFromGenericFunctionReturnTypes2.ts, 48, 20)) +>reduce : Symbol(Array.reduce, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>prev : Symbol(prev, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 31)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 36)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 36)) +>prev : Symbol(prev, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 31)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 49, 10)) +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 13)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 15)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 19)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 24)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 13)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 15)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 38)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 13)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 15)) + + return (a: SetOf) => { +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 53, 10)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 13)) + + const b: SetOf = new SetOf(); +>b : Symbol(b, Decl(inferFromGenericFunctionReturnTypes2.ts, 54, 9)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>B : Symbol(B, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 15)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) + + a.forEach(x => b.add(fn(x))); +>a.forEach : Symbol(SetOf.forEach, Decl(inferFromGenericFunctionReturnTypes2.ts, 34, 3)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 53, 10)) +>forEach : Symbol(SetOf.forEach, Decl(inferFromGenericFunctionReturnTypes2.ts, 34, 3)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 55, 14)) +>b.add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>b : Symbol(b, Decl(inferFromGenericFunctionReturnTypes2.ts, 54, 9)) +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes2.ts, 52, 19)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 55, 14)) + + return b; +>b : Symbol(b, Decl(inferFromGenericFunctionReturnTypes2.ts, 54, 9)) + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { +>filter : Symbol(filter, Decl(inferFromGenericFunctionReturnTypes2.ts, 58, 1)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) +>predicate : Symbol(predicate, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 19)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 31)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) +>s : Symbol(s, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 51)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) + + return (a: SetOf) => { +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 61, 10)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) + + const result = new SetOf(); +>result : Symbol(result, Decl(inferFromGenericFunctionReturnTypes2.ts, 62, 9)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) +>A : Symbol(A, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 16)) + + a.forEach(x => { +>a.forEach : Symbol(SetOf.forEach, Decl(inferFromGenericFunctionReturnTypes2.ts, 34, 3)) +>a : Symbol(a, Decl(inferFromGenericFunctionReturnTypes2.ts, 61, 10)) +>forEach : Symbol(SetOf.forEach, Decl(inferFromGenericFunctionReturnTypes2.ts, 34, 3)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 63, 14)) + + if (predicate(x)) result.add(x); +>predicate : Symbol(predicate, Decl(inferFromGenericFunctionReturnTypes2.ts, 60, 19)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 63, 14)) +>result.add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>result : Symbol(result, Decl(inferFromGenericFunctionReturnTypes2.ts, 62, 9)) +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 63, 14)) + + }); + return result; +>result : Symbol(result, Decl(inferFromGenericFunctionReturnTypes2.ts, 62, 9)) + } +} + +const testSet = new SetOf(); +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>SetOf : Symbol(SetOf, Decl(inferFromGenericFunctionReturnTypes2.ts, 22, 64)) + +testSet.add(1); +>testSet.add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) + +testSet.add(2); +>testSet.add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) + +testSet.add(3); +>testSet.add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>add : Symbol(SetOf.add, Decl(inferFromGenericFunctionReturnTypes2.ts, 26, 14)) + +const t1 = testSet.transform( +>t1 : Symbol(t1, Decl(inferFromGenericFunctionReturnTypes2.ts, 75, 5)) +>testSet.transform : Symbol(SetOf.transform, Decl(inferFromGenericFunctionReturnTypes2.ts, 30, 3)) +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>transform : Symbol(SetOf.transform, Decl(inferFromGenericFunctionReturnTypes2.ts, 30, 3)) + + compose( +>compose : Symbol(compose, Decl(inferFromGenericFunctionReturnTypes2.ts, 39, 1), Decl(inferFromGenericFunctionReturnTypes2.ts, 46, 28)) + + filter(x => x % 1 === 0), +>filter : Symbol(filter, Decl(inferFromGenericFunctionReturnTypes2.ts, 58, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 77, 11)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 77, 11)) + + map(x => x + x), +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 78, 8)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 78, 8)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 78, 8)) + + map(x => x + '!!!'), +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 79, 8)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 79, 8)) + + map(x => x.toUpperCase()) +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 80, 8)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 80, 8)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.d.ts, --, --)) + + ) +) + +declare function identity(x: T): T; +>identity : Symbol(identity, Decl(inferFromGenericFunctionReturnTypes2.ts, 82, 1)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 84, 26)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 84, 29)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 84, 26)) +>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes2.ts, 84, 26)) + +const t2 = testSet.transform( +>t2 : Symbol(t2, Decl(inferFromGenericFunctionReturnTypes2.ts, 86, 5)) +>testSet.transform : Symbol(SetOf.transform, Decl(inferFromGenericFunctionReturnTypes2.ts, 30, 3)) +>testSet : Symbol(testSet, Decl(inferFromGenericFunctionReturnTypes2.ts, 70, 5)) +>transform : Symbol(SetOf.transform, Decl(inferFromGenericFunctionReturnTypes2.ts, 30, 3)) + + compose( +>compose : Symbol(compose, Decl(inferFromGenericFunctionReturnTypes2.ts, 39, 1), Decl(inferFromGenericFunctionReturnTypes2.ts, 46, 28)) + + filter(x => x % 1 === 0), +>filter : Symbol(filter, Decl(inferFromGenericFunctionReturnTypes2.ts, 58, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 88, 11)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 88, 11)) + + identity, +>identity : Symbol(identity, Decl(inferFromGenericFunctionReturnTypes2.ts, 82, 1)) + + map(x => x + '!!!'), +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 90, 8)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 90, 8)) + + map(x => x.toUpperCase()) +>map : Symbol(map, Decl(inferFromGenericFunctionReturnTypes2.ts, 50, 1)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 91, 8)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes2.ts, 91, 8)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.d.ts, --, --)) + + ) +) + diff --git a/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.types b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.types new file mode 100644 index 0000000000000..a07c5ea4db810 --- /dev/null +++ b/tests/baselines/reference/inferFromGenericFunctionReturnTypes2.types @@ -0,0 +1,600 @@ +=== tests/cases/compiler/inferFromGenericFunctionReturnTypes2.ts === +type Mapper = (x: T) => U; +>Mapper : Mapper +>T : T +>U : U +>x : T +>T : T +>U : U + +declare function wrap(cb: Mapper): Mapper; +>wrap : (cb: Mapper) => Mapper +>T : T +>U : U +>cb : Mapper +>Mapper : Mapper +>T : T +>U : U +>Mapper : Mapper +>T : T +>U : U + +declare function arrayize(cb: Mapper): Mapper; +>arrayize : (cb: Mapper) => Mapper +>T : T +>U : U +>cb : Mapper +>Mapper : Mapper +>T : T +>U : U +>Mapper : Mapper +>T : T +>U : U + +declare function combine(f: (x: A) => B, g: (x: B) => C): (x: A) => C; +>combine : (f: (x: A) => B, g: (x: B) => C) => (x: A) => C +>A : A +>B : B +>C : C +>f : (x: A) => B +>x : A +>A : A +>B : B +>g : (x: B) => C +>x : B +>B : B +>C : C +>x : A +>A : A +>C : C + +declare function foo(f: Mapper): void; +>foo : (f: Mapper) => void +>f : Mapper +>Mapper : Mapper + +let f1: Mapper = s => s.length; +>f1 : Mapper +>Mapper : Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let f2: Mapper = wrap(s => s.length); +>f2 : Mapper +>Mapper : Mapper +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let f3: Mapper = arrayize(wrap(s => s.length)); +>f3 : Mapper +>Mapper : Mapper +>arrayize(wrap(s => s.length)) : Mapper +>arrayize : (cb: Mapper) => Mapper +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let f4: Mapper = combine(wrap(s => s.length), wrap(n => n >= 10)); +>f4 : Mapper +>Mapper : Mapper +>combine(wrap(s => s.length), wrap(n => n >= 10)) : (x: string) => boolean +>combine : (f: (x: A) => B, g: (x: B) => C) => (x: A) => C +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number +>wrap(n => n >= 10) : Mapper +>wrap : (cb: Mapper) => Mapper +>n => n >= 10 : (n: number) => boolean +>n : number +>n >= 10 : boolean +>n : number +>10 : 10 + +foo(wrap(s => s.length)); +>foo(wrap(s => s.length)) : void +>foo : (f: Mapper) => void +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let a1 = ["a", "b"].map(s => s.length); +>a1 : number[] +>["a", "b"].map(s => s.length) : number[] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>s => s.length : (this: void, s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let a2 = ["a", "b"].map(wrap(s => s.length)); +>a2 : number[] +>["a", "b"].map(wrap(s => s.length)) : number[] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let a3 = ["a", "b"].map(wrap(arrayize(s => s.length))); +>a3 : number[][] +>["a", "b"].map(wrap(arrayize(s => s.length))) : number[][] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>wrap(arrayize(s => s.length)) : Mapper +>wrap : (cb: Mapper) => Mapper +>arrayize(s => s.length) : Mapper +>arrayize : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let a4 = ["a", "b"].map(combine(wrap(s => s.length), wrap(n => n > 10))); +>a4 : boolean[] +>["a", "b"].map(combine(wrap(s => s.length), wrap(n => n > 10))) : boolean[] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>combine(wrap(s => s.length), wrap(n => n > 10)) : (x: string) => boolean +>combine : (f: (x: A) => B, g: (x: B) => C) => (x: A) => C +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number +>wrap(n => n > 10) : Mapper +>wrap : (cb: Mapper) => Mapper +>n => n > 10 : (n: number) => boolean +>n : number +>n > 10 : boolean +>n : number +>10 : 10 + +let a5 = ["a", "b"].map(combine(identity, wrap(s => s.length))); +>a5 : number[] +>["a", "b"].map(combine(identity, wrap(s => s.length))) : number[] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>combine(identity, wrap(s => s.length)) : (x: string) => number +>combine : (f: (x: A) => B, g: (x: B) => C) => (x: A) => C +>identity : (x: T) => T +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number + +let a6 = ["a", "b"].map(combine(wrap(s => s.length), identity)); +>a6 : number[] +>["a", "b"].map(combine(wrap(s => s.length), identity)) : number[] +>["a", "b"].map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>["a", "b"] : string[] +>"a" : "a" +>"b" : "b" +>map : { (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U, U]; (this: [string, string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U, U]; (this: [string, string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U, U]; (this: [string, string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U, U]; (this: [string, string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U): [U, U]; (this: [string, string], callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): [U, U]; (this: [string, string], callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): [U, U]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U): U[]; (callbackfn: (this: void, value: string, index: number, array: string[]) => U, thisArg: undefined): U[]; (callbackfn: (this: Z, value: string, index: number, array: string[]) => U, thisArg: Z): U[]; } +>combine(wrap(s => s.length), identity) : (x: string) => number +>combine : (f: (x: A) => B, g: (x: B) => C) => (x: A) => C +>wrap(s => s.length) : Mapper +>wrap : (cb: Mapper) => Mapper +>s => s.length : (s: string) => number +>s : string +>s.length : number +>s : string +>length : number +>identity : (x: T) => T + +// This is a contrived class. We could do the same thing with Observables, etc. +class SetOf { +>SetOf : SetOf +>A : A + + _store: A[]; +>_store : A[] +>A : A + + add(a: A) { +>add : (a: A) => void +>a : A +>A : A + + this._store.push(a); +>this._store.push(a) : number +>this._store.push : (...items: A[]) => number +>this._store : A[] +>this : this +>_store : A[] +>push : (...items: A[]) => number +>a : A + } + + transform(transformer: (a: SetOf) => SetOf): SetOf { +>transform : (transformer: (a: SetOf) => SetOf) => SetOf +>B : B +>transformer : (a: SetOf) => SetOf +>a : SetOf +>SetOf : SetOf +>A : A +>SetOf : SetOf +>B : B +>SetOf : SetOf +>B : B + + return transformer(this); +>transformer(this) : SetOf +>transformer : (a: SetOf) => SetOf +>this : this + } + + forEach(fn: (a: A, index: number) => void) { +>forEach : (fn: (a: A, index: number) => void) => void +>fn : (a: A, index: number) => void +>a : A +>A : A +>index : number + + this._store.forEach((a, i) => fn(a, i)); +>this._store.forEach((a, i) => fn(a, i)) : void +>this._store.forEach : { (callbackfn: (this: void, value: A, index: number, array: A[]) => void): void; (callbackfn: (this: void, value: A, index: number, array: A[]) => void, thisArg: undefined): void; (callbackfn: (this: Z, value: A, index: number, array: A[]) => void, thisArg: Z): void; } +>this._store : A[] +>this : this +>_store : A[] +>forEach : { (callbackfn: (this: void, value: A, index: number, array: A[]) => void): void; (callbackfn: (this: void, value: A, index: number, array: A[]) => void, thisArg: undefined): void; (callbackfn: (this: Z, value: A, index: number, array: A[]) => void, thisArg: Z): void; } +>(a, i) => fn(a, i) : (this: void, a: A, i: number) => void +>a : A +>i : number +>fn(a, i) : void +>fn : (a: A, index: number) => void +>a : A +>i : number + } +} + +function compose( +>compose : (fnA: (a: SetOf) => SetOf, fnB: (b: SetOf) => SetOf, fnC: (c: SetOf) => SetOf, fnD: (c: SetOf) => SetOf) => (x: SetOf) => SetOf +>A : A +>B : B +>C : C +>D : D +>E : E + + fnA: (a: SetOf) => SetOf, +>fnA : (a: SetOf) => SetOf +>a : SetOf +>SetOf : SetOf +>A : A +>SetOf : SetOf +>B : B + + fnB: (b: SetOf) => SetOf, +>fnB : (b: SetOf) => SetOf +>b : SetOf +>SetOf : SetOf +>B : B +>SetOf : SetOf +>C : C + + fnC: (c: SetOf) => SetOf, +>fnC : (c: SetOf) => SetOf +>c : SetOf +>SetOf : SetOf +>C : C +>SetOf : SetOf +>D : D + + fnD: (c: SetOf) => SetOf, +>fnD : (c: SetOf) => SetOf +>c : SetOf +>SetOf : SetOf +>D : D +>SetOf : SetOf +>E : E + +):(x: SetOf) => SetOf; +>x : SetOf +>SetOf : SetOf +>A : A +>SetOf : SetOf +>E : E + +/* ... etc ... */ +function compose(...fns: ((x: T) => T)[]): (x: T) => T { +>compose : (fnA: (a: SetOf) => SetOf, fnB: (b: SetOf) => SetOf, fnC: (c: SetOf) => SetOf, fnD: (c: SetOf) => SetOf) => (x: SetOf) => SetOf +>T : T +>fns : ((x: T) => T)[] +>x : T +>T : T +>T : T +>x : T +>T : T +>T : T + + return (x: T) => fns.reduce((prev, fn) => fn(prev), x); +>(x: T) => fns.reduce((prev, fn) => fn(prev), x) : (x: T) => T +>x : T +>T : T +>fns.reduce((prev, fn) => fn(prev), x) : T +>fns.reduce : { (callbackfn: (previousValue: (x: T) => T, currentValue: (x: T) => T, currentIndex: number, array: ((x: T) => T)[]) => (x: T) => T, initialValue?: (x: T) => T): (x: T) => T; (callbackfn: (previousValue: U, currentValue: (x: T) => T, currentIndex: number, array: ((x: T) => T)[]) => U, initialValue: U): U; } +>fns : ((x: T) => T)[] +>reduce : { (callbackfn: (previousValue: (x: T) => T, currentValue: (x: T) => T, currentIndex: number, array: ((x: T) => T)[]) => (x: T) => T, initialValue?: (x: T) => T): (x: T) => T; (callbackfn: (previousValue: U, currentValue: (x: T) => T, currentIndex: number, array: ((x: T) => T)[]) => U, initialValue: U): U; } +>(prev, fn) => fn(prev) : (prev: T, fn: (x: T) => T) => T +>prev : T +>fn : (x: T) => T +>fn(prev) : T +>fn : (x: T) => T +>prev : T +>x : T +} + +function map(fn: (a: A) => B): (s: SetOf) => SetOf { +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>A : A +>B : B +>fn : (a: A) => B +>a : A +>A : A +>B : B +>s : SetOf +>SetOf : SetOf +>A : A +>SetOf : SetOf +>B : B + + return (a: SetOf) => { +>(a: SetOf) => { const b: SetOf = new SetOf(); a.forEach(x => b.add(fn(x))); return b; } : (a: SetOf) => SetOf +>a : SetOf +>SetOf : SetOf +>A : A + + const b: SetOf = new SetOf(); +>b : SetOf +>SetOf : SetOf +>B : B +>new SetOf() : SetOf +>SetOf : typeof SetOf + + a.forEach(x => b.add(fn(x))); +>a.forEach(x => b.add(fn(x))) : void +>a.forEach : (fn: (a: A, index: number) => void) => void +>a : SetOf +>forEach : (fn: (a: A, index: number) => void) => void +>x => b.add(fn(x)) : (x: A) => void +>x : A +>b.add(fn(x)) : void +>b.add : (a: B) => void +>b : SetOf +>add : (a: B) => void +>fn(x) : B +>fn : (a: A) => B +>x : A + + return b; +>b : SetOf + } +} + +function filter(predicate: (a: A) => boolean): (s: SetOf) => SetOf { +>filter : (predicate: (a: A) => boolean) => (s: SetOf) => SetOf +>A : A +>predicate : (a: A) => boolean +>a : A +>A : A +>s : SetOf +>SetOf : SetOf +>A : A +>SetOf : SetOf +>A : A + + return (a: SetOf) => { +>(a: SetOf) => { const result = new SetOf(); a.forEach(x => { if (predicate(x)) result.add(x); }); return result; } : (a: SetOf) => SetOf +>a : SetOf +>SetOf : SetOf +>A : A + + const result = new SetOf(); +>result : SetOf +>new SetOf() : SetOf +>SetOf : typeof SetOf +>A : A + + a.forEach(x => { +>a.forEach(x => { if (predicate(x)) result.add(x); }) : void +>a.forEach : (fn: (a: A, index: number) => void) => void +>a : SetOf +>forEach : (fn: (a: A, index: number) => void) => void +>x => { if (predicate(x)) result.add(x); } : (x: A) => void +>x : A + + if (predicate(x)) result.add(x); +>predicate(x) : boolean +>predicate : (a: A) => boolean +>x : A +>result.add(x) : void +>result.add : (a: A) => void +>result : SetOf +>add : (a: A) => void +>x : A + + }); + return result; +>result : SetOf + } +} + +const testSet = new SetOf(); +>testSet : SetOf +>new SetOf() : SetOf +>SetOf : typeof SetOf + +testSet.add(1); +>testSet.add(1) : void +>testSet.add : (a: number) => void +>testSet : SetOf +>add : (a: number) => void +>1 : 1 + +testSet.add(2); +>testSet.add(2) : void +>testSet.add : (a: number) => void +>testSet : SetOf +>add : (a: number) => void +>2 : 2 + +testSet.add(3); +>testSet.add(3) : void +>testSet.add : (a: number) => void +>testSet : SetOf +>add : (a: number) => void +>3 : 3 + +const t1 = testSet.transform( +>t1 : SetOf +>testSet.transform( compose( filter(x => x % 1 === 0), map(x => x + x), map(x => x + '!!!'), map(x => x.toUpperCase()) )) : SetOf +>testSet.transform : (transformer: (a: SetOf) => SetOf) => SetOf +>testSet : SetOf +>transform : (transformer: (a: SetOf) => SetOf) => SetOf + + compose( +>compose( filter(x => x % 1 === 0), map(x => x + x), map(x => x + '!!!'), map(x => x.toUpperCase()) ) : (x: SetOf) => SetOf +>compose : (fnA: (a: SetOf) => SetOf, fnB: (b: SetOf) => SetOf, fnC: (c: SetOf) => SetOf, fnD: (c: SetOf) => SetOf) => (x: SetOf) => SetOf + + filter(x => x % 1 === 0), +>filter(x => x % 1 === 0) : (s: SetOf) => SetOf +>filter : (predicate: (a: A) => boolean) => (s: SetOf) => SetOf +>x => x % 1 === 0 : (x: number) => boolean +>x : number +>x % 1 === 0 : boolean +>x % 1 : number +>x : number +>1 : 1 +>0 : 0 + + map(x => x + x), +>map(x => x + x) : (s: SetOf) => SetOf +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>x => x + x : (x: number) => number +>x : number +>x + x : number +>x : number +>x : number + + map(x => x + '!!!'), +>map(x => x + '!!!') : (s: SetOf) => SetOf +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>x => x + '!!!' : (x: number) => string +>x : number +>x + '!!!' : string +>x : number +>'!!!' : "!!!" + + map(x => x.toUpperCase()) +>map(x => x.toUpperCase()) : (s: SetOf) => SetOf +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>x => x.toUpperCase() : (x: string) => string +>x : string +>x.toUpperCase() : string +>x.toUpperCase : () => string +>x : string +>toUpperCase : () => string + + ) +) + +declare function identity(x: T): T; +>identity : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +const t2 = testSet.transform( +>t2 : SetOf +>testSet.transform( compose( filter(x => x % 1 === 0), identity, map(x => x + '!!!'), map(x => x.toUpperCase()) )) : SetOf +>testSet.transform : (transformer: (a: SetOf) => SetOf) => SetOf +>testSet : SetOf +>transform : (transformer: (a: SetOf) => SetOf) => SetOf + + compose( +>compose( filter(x => x % 1 === 0), identity, map(x => x + '!!!'), map(x => x.toUpperCase()) ) : (x: SetOf) => SetOf +>compose : (fnA: (a: SetOf) => SetOf, fnB: (b: SetOf) => SetOf, fnC: (c: SetOf) => SetOf, fnD: (c: SetOf) => SetOf) => (x: SetOf) => SetOf + + filter(x => x % 1 === 0), +>filter(x => x % 1 === 0) : (s: SetOf) => SetOf +>filter : (predicate: (a: A) => boolean) => (s: SetOf) => SetOf +>x => x % 1 === 0 : (x: number) => boolean +>x : number +>x % 1 === 0 : boolean +>x % 1 : number +>x : number +>1 : 1 +>0 : 0 + + identity, +>identity : (x: T) => T + + map(x => x + '!!!'), +>map(x => x + '!!!') : (s: SetOf) => SetOf +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>x => x + '!!!' : (x: number) => string +>x : number +>x + '!!!' : string +>x : number +>'!!!' : "!!!" + + map(x => x.toUpperCase()) +>map(x => x.toUpperCase()) : (s: SetOf) => SetOf +>map : (fn: (a: A) => B) => (s: SetOf) => SetOf +>x => x.toUpperCase() : (x: string) => string +>x : string +>x.toUpperCase() : string +>x.toUpperCase : () => string +>x : string +>toUpperCase : () => string + + ) +) + From 7ca91f86a7960d5464de669f71ec8d950c63f4fc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 26 May 2017 10:44:11 -0700 Subject: [PATCH 11/11] Address CR feedback --- src/compiler/checker.ts | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30100332210cb..91ee22471aa80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10292,29 +10292,26 @@ namespace ts { // Because the anyFunctionType is internal, it should not be exposed to the user by adding // it as an inference candidate. Hopefully, a better candidate will come along that does // not contain anyFunctionType when we come back to this argument for its second round - // of inference. + // of inference. Also, we exclude inferences for silentNeverType which is used as a wildcard + // when constructing types from type parameters that had no inference candidates. if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { return; } - for (const inference of inferences) { - if (target === inference.typeParameter) { - // Even if an inference is marked as fixed, we can add candidates from inferences made - // from the return type of generic functions (which only happens when no other candidates - // are present). - if (!inference.isFixed) { - if (!inference.candidates || priority < inference.priority) { - inference.candidates = [source]; - inference.priority = priority; - } - else if (priority === inference.priority) { - inference.candidates.push(source); - } - if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { - inference.topLevel = false; - } + const inference = getInferenceInfoForType(target); + if (inference) { + if (!inference.isFixed) { + if (!inference.candidates || priority < inference.priority) { + inference.candidates = [source]; + inference.priority = priority; + } + else if (priority === inference.priority) { + inference.candidates.push(source); + } + if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { + inference.topLevel = false; } - return; } + return; } } else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) {