From 451f65332c40fe93ccd703f075dfb85f46d162dc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Feb 2019 07:02:37 -1000 Subject: [PATCH] Improve contextual typing by generic rest parameter --- src/compiler/checker.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3bd089aff6f..6711d56fe30 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10669,9 +10669,9 @@ namespace ts { return !!(mapper).typeParameters; } - function cloneTypeMapper(mapper: TypeMapper): TypeMapper { + function cloneTypeMapper(mapper: TypeMapper, extraFlags: InferenceFlags = 0): TypeMapper { return mapper && isInferenceContext(mapper) ? - createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) : + createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | extraFlags, mapper.compareTypes, mapper.inferences) : mapper; } @@ -19984,7 +19984,7 @@ namespace ts { // 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 instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node))); + const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node), InferenceFlags.NoDefault)); // If the contextual type is a generic function type with a single call signature, we // instantiate the type with its own type parameters and type arguments. This ensures that // the type parameters are not erased to type any during type inference such that they can @@ -21652,6 +21652,17 @@ namespace ts { } } } + const restType = getEffectiveRestType(context); + if (restType && restType.flags & TypeFlags.TypeParameter) { + // The contextual signature has a generic rest parameter. We first instantiate the contextual + // signature (without fixing type parameters) and assign types to contextually typed parameters. + const instantiatedContext = instantiateSignature(context, cloneTypeMapper(mapper)); + assignContextualParameterTypes(signature, instantiatedContext); + // We then infer from a tuple type representing the parameters that correspond to the contextual + // rest parameter. + const restPos = getParameterCount(context) - 1; + inferTypes((mapper).inferences, getRestTypeAtPosition(signature, restPos), restType); + } } function assignContextualParameterTypes(signature: Signature, context: Signature) {