Fix nomenclature around upwards/downwards/partial inference to match spec.

The spec uses the terms "upwards" vs "downwards" inference to refer to
whether type constraints come from a return type or parameter types.
Previous to this change the code used the terms "upwards" vs "partial"
inference to refer to whether the types being chosen were preliminary
(and hence might contain `?`s) or were the final inferred types.  This
led to confusion; for example the method
`downwardInferObjectPatternRequiredType` was calling `upwardsInfer`.

This change adjusts the nomenclature so that the methods that choose
types are called `choosePreliminaryTypes` and `chooseFinalTypes`, to
avoid any confusion with the direction of inference.

See discussion here:
https://dart-review.googlesource.com/c/sdk/+/290613/comment/894a767c_e269584e/.

Change-Id: Ie05dcae027ca82b2ce7e5a57f1846412d5b32d50
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290901
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry 2023-03-24 12:25:18 +00:00 committed by Commit Queue
parent c175d48343
commit f9c45af689
14 changed files with 67 additions and 63 deletions

View file

@ -112,6 +112,14 @@ class GenericInferrer {
TypeProviderImpl get typeProvider => _typeSystem.typeProvider;
/// Performs upwards inference, producing a final set of inferred types that
/// does not contain references to the "unknown type".
List<DartType> chooseFinalTypes() => tryChooseFinalTypes(failAtError: false)!;
/// Performs partial (either downwards or horizontal) inference, producing a
/// set of inferred types that may contain references to the "unknown type".
List<DartType> choosePreliminaryTypes() => _chooseTypes(preliminary: true);
/// Apply an argument constraint, which asserts that the [argument] staticType
/// is a subtype of the [parameterType].
void constrainArgument(
@ -177,15 +185,11 @@ class GenericInferrer {
_tryMatchSubtypeOf(declaredType, contextType, origin, covariant: true);
}
/// Performs partial (either downwards or horizontal) inference, producing a
/// set of inferred types that may contain references to the "unknown type".
List<DartType> partialInfer() => _chooseTypes(partial: true);
/// Same as [upwardsInfer], but if [failAtError] is `true` (the default) and
/// inference fails, returns `null` rather than trying to perform error
/// Same as [chooseFinalTypes], but if [failAtError] is `true` (the default)
/// and inference fails, returns `null` rather than trying to perform error
/// recovery.
List<DartType>? tryUpwardsInfer({bool failAtError = true}) {
var inferredTypes = _chooseTypes(partial: false);
List<DartType>? tryChooseFinalTypes({bool failAtError = true}) {
var inferredTypes = _chooseTypes(preliminary: false);
// Check the inferred types against all of the constraints.
var knownTypes = <TypeParameterElement, DartType>{};
var hasErrorReported = false;
@ -298,10 +302,6 @@ class GenericInferrer {
return result;
}
/// Performs upwards inference, producing a final set of inferred types that
/// does not contain references to the "unknown type".
List<DartType> upwardsInfer() => tryUpwardsInfer(failAtError: false)!;
/// Check that inferred [typeArguments] satisfy the [typeParameters] bounds.
void _checkArgumentsNotMatchingBounds({
required AstNode? errorNode,
@ -423,7 +423,7 @@ class GenericInferrer {
/// Computes (or recomputes) a set of [inferredTypes] based on the constraints
/// that have been recorded so far.
List<DartType> _chooseTypes({required bool partial}) {
List<DartType> _chooseTypes({required bool preliminary}) {
var inferredTypes = List<DartType>.filled(
_typeFormals.length, UnknownInferredType.instance);
for (int i = 0; i < _typeFormals.length; i++) {
@ -445,7 +445,7 @@ class GenericInferrer {
var previouslyInferredType = _typesInferredSoFar[typeParam];
if (previouslyInferredType != null) {
inferredTypes[i] = previouslyInferredType;
} else if (partial) {
} else if (preliminary) {
var inferredType = _inferTypeParameterFromContext(
constraints, extendsClause,
isContravariant: typeParam.variance.isContravariant);

View file

@ -536,7 +536,7 @@ class TypeSystemImpl implements TypeSystem {
inferrer.constrainGenericFunctionInContext(fnType, contextType);
// Infer and instantiate the resulting type.
return inferrer.upwardsInfer();
return inferrer.chooseFinalTypes();
}
@override
@ -1345,7 +1345,7 @@ class TypeSystemImpl implements TypeSystem {
}
var inferredTypes = inferrer
.upwardsInfer()
.chooseFinalTypes()
.map(_removeBoundsOfGenericFunctionTypes)
.toFixedList();
var substitution = Substitution.fromPairs(typeParameters, inferredTypes);

View file

@ -201,7 +201,7 @@ extension NotInstantiatedExtensionsExtensions<R>
rawExtendedType,
'extendedType',
);
var inferredTypes = inferrer.tryUpwardsInfer();
var inferredTypes = inferrer.tryChooseFinalTypes();
if (inferredTypes == null) {
continue;
}

View file

@ -352,7 +352,7 @@ class ExtensionMemberResolver {
element.extendedType,
'extendedType',
);
return inferrer.upwardsInfer();
return inferrer.chooseFinalTypes();
}
}

View file

@ -199,8 +199,8 @@ abstract class FullInvocationInferrer<Node extends AstNodeImpl>
genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
);
substitution =
Substitution.fromPairs(rawType.typeFormals, inferrer.partialInfer());
substitution = Substitution.fromPairs(
rawType.typeFormals, inferrer.choosePreliminaryTypes());
}
List<EqualityInfo<DartType>?>? identicalInfo = _isIdentical ? [] : null;
@ -221,7 +221,7 @@ abstract class FullInvocationInferrer<Node extends AstNodeImpl>
.planReconciliationStages()) {
if (inferrer != null && !isFirstStage) {
substitution = Substitution.fromPairs(
rawType!.typeFormals, inferrer.partialInfer());
rawType!.typeFormals, inferrer.choosePreliminaryTypes());
}
_resolveDeferredFunctionLiterals(
deferredFunctionLiterals: stage,
@ -233,7 +233,7 @@ abstract class FullInvocationInferrer<Node extends AstNodeImpl>
}
if (inferrer != null) {
typeArgumentTypes = inferrer.upwardsInfer();
typeArgumentTypes = inferrer.chooseFinalTypes();
}
FunctionType? invokeType = typeArgumentTypes != null
? rawType?.instantiate(typeArgumentTypes)

View file

@ -181,7 +181,7 @@ class NamedTypeResolver with ScopeHelpers {
contextReturnType: enclosingClass!.thisType,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
);
var typeArguments = inferrer.upwardsInfer();
var typeArguments = inferrer.chooseFinalTypes();
return element.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix,

View file

@ -108,7 +108,7 @@ class TypedLiteralResolver {
} else {
inferrer = _inferListTypeDownwards(node, contextType: contextType);
if (contextType is! UnknownInferredType) {
var typeArguments = inferrer.partialInfer();
var typeArguments = inferrer.choosePreliminaryTypes();
listType = _typeProvider.listElement.instantiate(
typeArguments: typeArguments, nullabilitySuffix: _noneOrStarSuffix);
}
@ -142,7 +142,7 @@ class TypedLiteralResolver {
} else {
inferrer = _inferSetTypeDownwards(node, literalResolution.contextType);
if (literalResolution.contextType != null) {
var typeArguments = inferrer.partialInfer();
var typeArguments = inferrer.choosePreliminaryTypes();
literalType = _typeProvider.setElement.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix);
@ -156,7 +156,7 @@ class TypedLiteralResolver {
} else {
inferrer = _inferMapTypeDownwards(node, literalResolution.contextType);
if (literalResolution.contextType != null) {
var typeArguments = inferrer.partialInfer();
var typeArguments = inferrer.choosePreliminaryTypes();
literalType = _typeProvider.mapElement.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix);
@ -499,7 +499,7 @@ class TypedLiteralResolver {
inferrer.constrainArguments(
parameters: parameters, argumentTypes: elementTypes);
var typeArguments = inferrer.upwardsInfer();
var typeArguments = inferrer.chooseFinalTypes();
return element.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix,
@ -742,7 +742,7 @@ class TypedLiteralResolver {
parameters: parameters,
argumentTypes: argumentTypes,
);
var typeArguments = inferrer.upwardsInfer();
var typeArguments = inferrer.chooseFinalTypes();
return element.instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix,
@ -776,7 +776,7 @@ class TypedLiteralResolver {
}
inferrer.constrainArguments(
parameters: parameters, argumentTypes: argumentTypes);
var typeArguments = inferrer.upwardsInfer();
var typeArguments = inferrer.chooseFinalTypes();
return element.instantiate(
typeArguments: typeArguments, nullabilitySuffix: _noneOrStarSuffix);
}

View file

@ -3676,7 +3676,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
genericMetadataIsEnabled: genericMetadataIsEnabled,
);
inferrer.constrainReturnType(declaredType, contextType);
return inferrer.upwardsInfer();
return inferrer.chooseFinalTypes();
}
/// If `expression` should be treated as `expression.call`, inserts an

View file

@ -658,7 +658,7 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
);
inferrer.constrainArguments(
parameters: ft.parameters, argumentTypes: arguments);
var typeArguments = inferrer.upwardsInfer();
var typeArguments = inferrer.chooseFinalTypes();
if (expectError) {
expect(listener.errors.map((e) => e.errorCode).toList(),

View file

@ -2580,7 +2580,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
listType, listClass.typeParameters, typeContext,
isNonNullableByDefault: isNonNullableByDefault,
isConst: node.isConst);
inferredTypes = typeSchemaEnvironment.partialInfer(
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, listClass.typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
inferredTypeArgument = inferredTypes[0];
@ -2598,7 +2598,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
if (inferenceNeeded) {
gatherer!.constrainArguments(formalTypes, actualTypes);
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, listClass.typeParameters, inferredTypes!,
isNonNullableByDefault: isNonNullableByDefault);
if (dataForTesting != null) {
@ -4614,7 +4614,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
mapType, mapClass.typeParameters, typeContext,
isNonNullableByDefault: isNonNullableByDefault,
isConst: node.isConst);
inferredTypes = typeSchemaEnvironment.partialInfer(
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, mapClass.typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
inferredKeyType = inferredTypes[0];
@ -4687,11 +4687,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
setType, coreTypes.setClass.typeParameters, typeContext,
isNonNullableByDefault: isNonNullableByDefault,
isConst: node.isConst);
List<DartType> inferredTypesForSet = typeSchemaEnvironment.partialInfer(
gatherer, coreTypes.setClass.typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
List<DartType> inferredTypesForSet =
typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, coreTypes.setClass.typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
gatherer.constrainArguments(formalTypesForSet, actualTypesForSet);
inferredTypesForSet = typeSchemaEnvironment.upwardsInfer(
inferredTypesForSet = typeSchemaEnvironment.chooseFinalTypes(
gatherer, coreTypes.setClass.typeParameters, inferredTypesForSet,
isNonNullableByDefault: isNonNullableByDefault);
DartType inferredTypeArgument = inferredTypesForSet[0];
@ -4731,7 +4732,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
NeverType.fromNullability(libraryBuilder.nonNullable), replacement);
}
gatherer!.constrainArguments(formalTypes, actualTypes);
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, mapClass.typeParameters, inferredTypes!,
isNonNullableByDefault: isNonNullableByDefault);
if (dataForTesting != null) {
@ -7899,7 +7900,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
setType, setClass.typeParameters, typeContext,
isNonNullableByDefault: isNonNullableByDefault,
isConst: node.isConst);
inferredTypes = typeSchemaEnvironment.partialInfer(
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, setClass.typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
inferredTypeArgument = inferredTypes[0];
@ -7918,7 +7919,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (inferenceNeeded) {
gatherer!.constrainArguments(formalTypes, actualTypes);
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, setClass.typeParameters, inferredTypes!,
isNonNullableByDefault: isNonNullableByDefault);
if (dataForTesting != null) {
@ -10914,7 +10915,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
TypeConstraintGatherer gatherer = typeSchemaEnvironment
.setupGenericTypeInference(declaredType, typeParameters, contextType,
isNonNullableByDefault: isNonNullableByDefault);
return typeSchemaEnvironment.upwardsInfer(gatherer, typeParameters, null,
return typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
}

View file

@ -969,7 +969,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
.setupGenericTypeInference(null, typeParameters, null,
isNonNullableByDefault: libraryBuilder.isNonNullableByDefault);
gatherer.constrainArguments([onType], [receiverType]);
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameters, inferredTypes,
isNonNullableByDefault: isNonNullableByDefault);
return inferredTypes;
@ -1829,7 +1829,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
calleeTypeParameters,
typeContext,
isNonNullableByDefault: isNonNullableByDefault);
inferredTypes = typeSchemaEnvironment.partialInfer(
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, calleeTypeParameters, null,
isNonNullableByDefault: isNonNullableByDefault);
substitution =
@ -2006,7 +2006,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
: const [])
.planReconciliationStages()) {
if (gatherer != null && !isFirstStage) {
inferredTypes = typeSchemaEnvironment.partialInfer(
inferredTypes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, calleeTypeParameters, inferredTypes,
isNonNullableByDefault: isNonNullableByDefault);
substitution =
@ -2113,7 +2113,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
}
if (inferenceNeeded) {
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer!, calleeTypeParameters, inferredTypes!,
isNonNullableByDefault: isNonNullableByDefault);
assert(inferredTypes.every((type) => isKnown(type)),
@ -3699,7 +3699,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
typeSchemaEnvironment.setupGenericTypeInference(
instantiatedType, typeParameters, context,
isNonNullableByDefault: isNonNullableByDefault);
inferredTypes = typeSchemaEnvironment.upwardsInfer(
inferredTypes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameters, inferredTypes,
isNonNullableByDefault: isNonNullableByDefault);
Substitution substitution =

View file

@ -123,13 +123,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
/// Performs partial (either downwards or horizontal) inference, producing a
/// set of inferred types that may contain references to the "unknown type".
List<DartType> partialInfer(
List<DartType> choosePreliminaryTypes(
TypeConstraintGatherer gatherer,
List<TypeParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault}) =>
_chooseTypes(gatherer, typeParametersToInfer, previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault, partial: true);
isNonNullableByDefault: isNonNullableByDefault, preliminary: true);
@override
DartType getTypeOfSpecialCasedBinaryOperator(DartType type1, DartType type2,
@ -251,17 +251,18 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
/// of types inferred by the last call to this method; it should be a list of
/// the same length.
///
/// If [partial] is `true`, then we not in the final pass of inference. This
/// means we are allowed to return `?` to precisely represent an unknown type.
/// If [preliminary] is `true`, then we not in the final pass of inference.
/// This means we are allowed to return `?` to precisely represent an unknown
/// type.
///
/// If [partial] is `false`, then we are in the final pass of inference, and
/// must not conclude `?` for any type formal.
/// If [preliminary] is `false`, then we are in the final pass of inference,
/// and must not conclude `?` for any type formal.
List<DartType> inferTypeFromConstraints(
Map<TypeParameter, TypeConstraint> constraints,
List<TypeParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault,
bool partial = false}) {
bool preliminary = false}) {
List<DartType> inferredTypes =
previouslyInferredTypes?.toList(growable: false) ??
new List.filled(typeParametersToInfer.length, const UnknownType());
@ -278,7 +279,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
}
TypeConstraint constraint = constraints[typeParam]!;
if (partial) {
if (preliminary) {
inferredTypes[i] = _inferTypeParameterFromContext(
previouslyInferredTypes?[i], constraint, extendsConstraint,
isNonNullableByDefault: isNonNullableByDefault,
@ -292,7 +293,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
}
}
if (!partial) {
if (!preliminary) {
assert(typeParametersToInfer.length == inferredTypes.length);
FreshTypeParameters freshTypeParameters =
getFreshTypeParameters(typeParametersToInfer);
@ -493,13 +494,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
/// Performs upwards inference, producing a final set of inferred types that
/// does not contain references to the "unknown type".
List<DartType> upwardsInfer(
List<DartType> chooseFinalTypes(
TypeConstraintGatherer gatherer,
List<TypeParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault}) =>
_chooseTypes(gatherer, typeParametersToInfer, previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault, partial: false);
isNonNullableByDefault: isNonNullableByDefault, preliminary: false);
/// Computes (or recomputes) a set of [inferredTypes] based on the constraints
/// that have been recorded so far.
@ -508,14 +509,14 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
List<TypeParameter> typeParametersToInfer,
List<DartType>? previouslyInferredTypes,
{required bool isNonNullableByDefault,
required bool partial}) {
required bool preliminary}) {
List<DartType> inferredTypes = inferTypeFromConstraints(
gatherer.computeConstraints(
isNonNullableByDefault: isNonNullableByDefault),
typeParametersToInfer,
previouslyInferredTypes,
isNonNullableByDefault: isNonNullableByDefault,
partial: partial);
preliminary: preliminary);
for (int i = 0; i < inferredTypes.length; i++) {
inferredTypes[i] = demoteTypeInLibrary(inferredTypes[i],

View file

@ -171,12 +171,12 @@ abstract class TypeSchemaEnvironmentTestBase {
returnContextTypeNode,
isNonNullableByDefault: isNonNullableByDefault);
if (formalTypeNodes == null) {
inferredTypeNodes = typeSchemaEnvironment.partialInfer(
inferredTypeNodes = typeSchemaEnvironment.choosePreliminaryTypes(
gatherer, typeParameterNodesToInfer, inferredTypeNodes,
isNonNullableByDefault: isNonNullableByDefault);
} else {
gatherer.constrainArguments(formalTypeNodes, actualTypeNodes!);
inferredTypeNodes = typeSchemaEnvironment.upwardsInfer(
inferredTypeNodes = typeSchemaEnvironment.chooseFinalTypes(
gatherer, typeParameterNodesToInfer, inferredTypeNodes!,
isNonNullableByDefault: isNonNullableByDefault);
}
@ -215,7 +215,7 @@ abstract class TypeSchemaEnvironmentTestBase {
[typeParameterNode],
inferredTypeNodes,
isNonNullableByDefault: isNonNullableByDefault,
partial: downwardsInferPhase);
preliminary: downwardsInferPhase);
expect(inferredTypeNodes.single, expectedTypeNode);
});

View file

@ -1095,6 +1095,7 @@ preexisted
preexisting
preferably
prefixing
preliminary
premark
preorder
prepares