mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 21:06:50 -05:00
Merge pull request #1035 from Microsoft/improvedTypeInference
Improved type inference (fixes #1011)
This commit is contained in:
@@ -4007,8 +4007,10 @@ module ts {
|
||||
}
|
||||
|
||||
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
|
||||
var inferences: Type[][] = [];
|
||||
for (var i = 0; i < typeParameters.length; i++) inferences.push([]);
|
||||
var inferences: TypeInferences[] = [];
|
||||
for (var i = 0; i < typeParameters.length; i++) {
|
||||
inferences.push({ primary: undefined, secondary: undefined });
|
||||
}
|
||||
return {
|
||||
typeParameters: typeParameters,
|
||||
inferUnionTypes: inferUnionTypes,
|
||||
@@ -4022,6 +4024,7 @@ module ts {
|
||||
var sourceStack: Type[];
|
||||
var targetStack: Type[];
|
||||
var depth = 0;
|
||||
var inferiority = 0;
|
||||
inferFromTypes(source, target);
|
||||
|
||||
function isInProcess(source: Type, target: Type) {
|
||||
@@ -4050,9 +4053,11 @@ module ts {
|
||||
var typeParameters = context.typeParameters;
|
||||
for (var i = 0; i < typeParameters.length; i++) {
|
||||
if (target === typeParameters[i]) {
|
||||
context.inferenceCount++;
|
||||
var inferences = context.inferences[i];
|
||||
if (!contains(inferences, source)) inferences.push(source);
|
||||
var candidates = inferiority ?
|
||||
inferences.secondary || (inferences.secondary = []) :
|
||||
inferences.primary || (inferences.primary = []);
|
||||
if (!contains(candidates, source)) candidates.push(source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4067,7 +4072,6 @@ module ts {
|
||||
}
|
||||
else if (target.flags & TypeFlags.Union) {
|
||||
var targetTypes = (<UnionType>target).types;
|
||||
var startCount = context.inferenceCount;
|
||||
var typeParameterCount = 0;
|
||||
var typeParameter: TypeParameter;
|
||||
// First infer to each type in union that isn't a type parameter
|
||||
@@ -4081,9 +4085,11 @@ module ts {
|
||||
inferFromTypes(source, t);
|
||||
}
|
||||
}
|
||||
// If no inferences were produced above and union contains a single naked type parameter, infer to that type parameter
|
||||
if (context.inferenceCount === startCount && typeParameterCount === 1) {
|
||||
// If union contains a single naked type parameter, make a secondary inference to that type parameter
|
||||
if (typeParameterCount === 1) {
|
||||
inferiority++;
|
||||
inferFromTypes(source, typeParameter);
|
||||
inferiority--;
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.Union) {
|
||||
@@ -4153,10 +4159,15 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getInferenceCandidates(context: InferenceContext, index: number): Type[]{
|
||||
var inferences = context.inferences[index];
|
||||
return inferences.primary || inferences.secondary || emptyArray;
|
||||
}
|
||||
|
||||
function getInferredType(context: InferenceContext, index: number): Type {
|
||||
var inferredType = context.inferredTypes[index];
|
||||
if (!inferredType) {
|
||||
var inferences = context.inferences[index];
|
||||
var inferences = getInferenceCandidates(context, index);
|
||||
if (inferences.length) {
|
||||
// Infer widened union or supertype, or the undefined type for no common supertype
|
||||
var unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
|
||||
@@ -4166,7 +4177,6 @@ module ts {
|
||||
// Infer the empty object type when no inferences were made
|
||||
inferredType = emptyObjectType;
|
||||
}
|
||||
|
||||
if (inferredType !== inferenceFailureType) {
|
||||
var constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
|
||||
inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
|
||||
@@ -5404,7 +5414,7 @@ module ts {
|
||||
else {
|
||||
Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0);
|
||||
var failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex];
|
||||
var inferenceCandidates = resultOfFailedInference.inferences[resultOfFailedInference.failedTypeParameterIndex];
|
||||
var inferenceCandidates = getInferenceCandidates(resultOfFailedInference, resultOfFailedInference.failedTypeParameterIndex);
|
||||
|
||||
var 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,
|
||||
|
||||
@@ -1041,14 +1041,18 @@ module ts {
|
||||
(t: Type): Type;
|
||||
}
|
||||
|
||||
export interface TypeInferences {
|
||||
primary: Type[]; // Inferences made directly to a type parameter
|
||||
secondary: Type[]; // Inferences made to a type parameter in a union type
|
||||
}
|
||||
|
||||
export interface InferenceContext {
|
||||
typeParameters: TypeParameter[]; // Type parameters for which inferences are made
|
||||
inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType)
|
||||
inferenceCount: number; // Incremented for every inference made (whether new or not)
|
||||
inferences: Type[][]; // Inferences made for each type parameter
|
||||
inferredTypes: Type[]; // Inferred type for each type parameter
|
||||
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
|
||||
// It is optional because in contextual signature instantiation, nothing fails
|
||||
typeParameters: TypeParameter[]; // Type parameters 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
|
||||
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
|
||||
// It is optional because in contextual signature instantiation, nothing fails
|
||||
}
|
||||
|
||||
export interface DiagnosticMessage {
|
||||
|
||||
Reference in New Issue
Block a user