From d0a195a3c5c6718f393071cc9a827905ac7a2f4c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 5 Aug 2017 12:32:56 -0700 Subject: [PATCH] Propagate type comparer function in contextual signature instantiation --- src/compiler/checker.ts | 15 ++++++++------- src/compiler/core.ts | 14 -------------- src/compiler/types.ts | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c0f15e27aa..f31c2573e36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8017,7 +8017,7 @@ namespace ts { function cloneTypeMapper(mapper: TypeMapper): TypeMapper { return mapper && isInferenceContext(mapper) ? - createInferenceContext(mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.inferences) : + createInferenceContext(mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) : mapper; } @@ -8458,7 +8458,7 @@ namespace ts { ignoreReturnTypes: boolean, reportErrors: boolean, errorReporter: ErrorReporter, - compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { + compareTypes: TypeComparer): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -8468,7 +8468,7 @@ namespace ts { } if (source.typeParameters) { - source = instantiateSignatureInContextOf(source, target); + source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } let result = Ternary.True; @@ -10216,13 +10216,14 @@ namespace ts { } } - function createInferenceContext(signature: Signature, flags: InferenceFlags, baseInferences?: InferenceInfo[]): InferenceContext { + function createInferenceContext(signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext { const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo); const context = mapper as InferenceContext; context.mappedTypes = signature.typeParameters; context.signature = signature; context.inferences = inferences; context.flags = flags; + context.compareTypes = compareTypes || compareTypesAssignable; return context; function mapper(t: Type): Type { @@ -10670,7 +10671,7 @@ namespace ts { const constraint = getConstraintOfTypeParameter(context.signature.typeParameters[index]); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context); - if (!isTypeAssignableTo(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + if (!context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { inference.inferredType = inferredType = instantiatedConstraint; } } @@ -15071,8 +15072,8 @@ 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, InferenceFlags.InferUnionTypes); + function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper?: TypeMapper, compareTypes?: TypeComparer): Signature { + const context = createInferenceContext(signature, InferenceFlags.InferUnionTypes, compareTypes); 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 || identityMapper), target); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 728fb433c04..262564813e9 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -11,20 +11,6 @@ namespace ts { /* @internal */ namespace ts { - /** - * Ternary values are defined such that - * x & y is False if either x or y is False. - * x & y is Maybe if either x or y is Maybe, but neither x or y is False. - * x & y is True if both x and y are True. - * x | y is False if both x and y are False. - * x | y is Maybe if either x or y is Maybe, but neither x or y is True. - * x | y is True if either x or y is True. - */ - export const enum Ternary { - False = 0, - Maybe = 1, - True = -1 - } // More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times. export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator(/*locales*/ undefined, { usage: "sort", sensitivity: "accent" }) : undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 09f1b5cfcc5..3b57608abc5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3425,11 +3425,29 @@ namespace ts { AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType) } + /** + * Ternary values are defined such that + * x & y is False if either x or y is False. + * x & y is Maybe if either x or y is Maybe, but neither x or y is False. + * x & y is True if both x and y are True. + * x | y is False if both x and y are False. + * x | y is Maybe if either x or y is Maybe, but neither x or y is True. + * x | y is True if either x or y is True. + */ + export const enum Ternary { + False = 0, + Maybe = 1, + True = -1 + } + + export type TypeComparer = (s: Type, t: Type, reportErrors?: boolean) => Ternary; + /* @internal */ export interface InferenceContext extends TypeMapper { signature: Signature; // Generic signature for which inferences are made inferences: InferenceInfo[]; // Inferences made for each type parameter flags: InferenceFlags; // Inference flags + compareTypes: TypeComparer; // Type comparer function } /* @internal */