Propagate type comparer function in contextual signature instantiation

This commit is contained in:
Anders Hejlsberg
2017-08-05 12:32:56 -07:00
parent 48d5485379
commit d0a195a3c5
3 changed files with 26 additions and 21 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 */