[model] Define common helper isKnownType and use in inference
This CL is another step towards the unification between TypeSchemaEnvironment.solveTypeConstraint in the CFE and GenericInferrer._chooseTypeFromConstraint in the Analyzer. Part of https://github.com/dart-lang/sdk/issues/54902 Change-Id: I2cfafef6a87b9bde8d1c94f6618e7f633debec0f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/424040 Reviewed-by: Paul Berry <paulberry@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
committed by
Commit Queue
parent
b23efe44e8
commit
a2b2751d7d
@@ -691,6 +691,21 @@ abstract interface class TypeAnalyzerOperations<Variable extends Object,
|
||||
|
||||
/// Converts a type into a corresponding type schema.
|
||||
SharedTypeSchemaView typeToSchema(SharedTypeView type);
|
||||
|
||||
/// Determines whether a type schema contains the unknown type.
|
||||
///
|
||||
/// Examples of known types:
|
||||
///
|
||||
/// * `int`,
|
||||
/// * `List<String>`,
|
||||
/// * `bool Function(double)`.
|
||||
///
|
||||
/// Examples of types that are not known:
|
||||
///
|
||||
/// * `_`,
|
||||
/// * `List<_>`,
|
||||
/// * `_ Function(_)`.
|
||||
bool isKnownType(SharedTypeSchemaView typeSchema);
|
||||
}
|
||||
|
||||
mixin TypeAnalyzerOperationsMixin<Variable extends Object,
|
||||
|
||||
@@ -3236,6 +3236,63 @@ class MiniAstOperations
|
||||
PropertyNonPromotabilityReason? whyPropertyIsNotPromotable(
|
||||
covariant _PropertyElement property) =>
|
||||
property.whyNotPromotable;
|
||||
|
||||
@override
|
||||
bool isKnownType(SharedTypeSchemaView typeSchema) {
|
||||
var unwrapped = typeSchema.unwrapTypeSchemaView<Type>();
|
||||
switch (unwrapped) {
|
||||
case FutureOrType(:var typeArgument):
|
||||
return isKnownType(SharedTypeSchemaView(typeArgument));
|
||||
case PrimaryType(:var args):
|
||||
for (var arg in args) {
|
||||
if (!isKnownType(SharedTypeSchemaView(arg))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case FunctionType(
|
||||
:var returnType,
|
||||
:var typeParametersShared,
|
||||
:var positionalParameters,
|
||||
:var namedParameters
|
||||
):
|
||||
if (!isKnownType(SharedTypeSchemaView(returnType))) {
|
||||
return false;
|
||||
}
|
||||
for (var typeParameter in typeParametersShared) {
|
||||
if (!isKnownType(SharedTypeSchemaView(typeParameter.bound))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var positionalParameter in positionalParameters) {
|
||||
if (!isKnownType(SharedTypeSchemaView(positionalParameter))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var namedParameter in namedParameters) {
|
||||
if (!isKnownType(SharedTypeSchemaView(namedParameter.type))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case RecordType(:var positionalTypes, :var namedTypes):
|
||||
for (var positionalType in positionalTypes) {
|
||||
if (!isKnownType(SharedTypeSchemaView(positionalType))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var namedType in namedTypes) {
|
||||
if (!isKnownType(SharedTypeSchemaView(namedType.type))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case UnknownType():
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of an expression or statement in the pseudo-Dart language
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart';
|
||||
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
|
||||
import 'package:checks/checks.dart';
|
||||
import 'package:test/scaffolding.dart';
|
||||
|
||||
@@ -855,4 +856,80 @@ main() {
|
||||
check(tcg.constraints).unorderedEquals(['num <: T']);
|
||||
});
|
||||
});
|
||||
|
||||
group('isKnownType', () {
|
||||
test('Simple types', () {
|
||||
var tcg = TypeConstraintGatherer({'T'});
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('String'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('dynamic'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('Object'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('void'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('T'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('_'))))
|
||||
.isFalse();
|
||||
});
|
||||
|
||||
test('Compound types', () {
|
||||
var tcg = TypeConstraintGatherer({'T'});
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('List<String>'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('List<_>'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('List<List<int>>'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('List<List<_>>'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('dynamic Function()'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('_ Function()'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('int Function(int)'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('int Function(_)'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(
|
||||
SharedTypeSchemaView(Type('int Function({String named})'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(
|
||||
SharedTypeSchemaView(Type('int Function({_ named})'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('(int, String, Object)'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations
|
||||
.isKnownType(SharedTypeSchemaView(Type('(int, String, _)'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(
|
||||
SharedTypeSchemaView(Type('(int, String, {dynamic named})'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(
|
||||
SharedTypeSchemaView(Type('(int, String, {_ named})'))))
|
||||
.isFalse();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(SharedTypeSchemaView(
|
||||
Type('(int, String, {List<dynamic> Function(int) named})'))))
|
||||
.isTrue();
|
||||
check(tcg.typeAnalyzerOperations.isKnownType(SharedTypeSchemaView(
|
||||
Type('(int, String, {List<_> Function(int) named})'))))
|
||||
.isFalse();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ class GenericInferrer {
|
||||
);
|
||||
}
|
||||
|
||||
if (UnknownInferredType.isKnown(inferred)) {
|
||||
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(inferred))) {
|
||||
knownTypes[parameter] = inferred;
|
||||
} else if (_strictInference) {
|
||||
// [typeParam] could not be inferred. A result will still be returned
|
||||
@@ -519,10 +519,10 @@ class GenericInferrer {
|
||||
// For both of those, prefer the lower bound (arbitrary heuristic) or upper
|
||||
// bound if [isContravariant] is `true`
|
||||
if (isContravariant) {
|
||||
if (UnknownInferredType.isKnown(upper)) {
|
||||
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(upper))) {
|
||||
return upper;
|
||||
}
|
||||
if (UnknownInferredType.isKnown(lower)) {
|
||||
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(lower))) {
|
||||
return lower;
|
||||
}
|
||||
if (!identical(UnknownInferredType.instance, upper)) {
|
||||
@@ -533,10 +533,10 @@ class GenericInferrer {
|
||||
}
|
||||
return upper;
|
||||
} else {
|
||||
if (UnknownInferredType.isKnown(lower)) {
|
||||
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(lower))) {
|
||||
return lower;
|
||||
}
|
||||
if (UnknownInferredType.isKnown(upper)) {
|
||||
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(upper))) {
|
||||
return upper;
|
||||
}
|
||||
if (!identical(UnknownInferredType.instance, lower)) {
|
||||
@@ -596,7 +596,9 @@ class GenericInferrer {
|
||||
|
||||
inferredTypes[i] = inferredType;
|
||||
if (typeParam.isLegacyCovariant &&
|
||||
UnknownInferredType.isKnown(inferredType)) {
|
||||
_typeSystemOperations.isKnownType(
|
||||
SharedTypeSchemaView(inferredType),
|
||||
)) {
|
||||
_typesInferredSoFar[typeParam] = inferredType;
|
||||
}
|
||||
} else {
|
||||
@@ -730,7 +732,7 @@ class GenericInferrer {
|
||||
constraint,
|
||||
isContravariant: isContravariant,
|
||||
);
|
||||
if (UnknownInferredType.isUnknown(t)) {
|
||||
if (!_typeSystemOperations.isKnownType(SharedTypeSchemaView(t))) {
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -667,6 +667,13 @@ class TypeSystemOperations
|
||||
type.element3 is! ExtensionTypeElement;
|
||||
}
|
||||
|
||||
@override
|
||||
bool isKnownType(SharedTypeSchemaView typeSchema) {
|
||||
return UnknownInferredType.isKnown(
|
||||
typeSchema.unwrapTypeSchemaView<TypeImpl>(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isNonNullableInternal(TypeImpl type) {
|
||||
return typeSystem.isNonNullable(type);
|
||||
|
||||
@@ -1043,6 +1043,11 @@ class OperationsCfe
|
||||
inferenceResultForTesting: null,
|
||||
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isKnownType(SharedTypeSchemaView typeSchema) {
|
||||
return isKnown(typeSchema.unwrapTypeSchemaView());
|
||||
}
|
||||
}
|
||||
|
||||
/// Type inference results used for testing.
|
||||
|
||||
@@ -20,7 +20,7 @@ import 'standard_bounds.dart' show TypeSchemaStandardBounds;
|
||||
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
|
||||
import 'type_demotion.dart';
|
||||
import 'type_inference_engine.dart';
|
||||
import 'type_schema.dart' show UnknownType, isKnown;
|
||||
import 'type_schema.dart' show UnknownType;
|
||||
import 'type_schema_elimination.dart' show greatestClosure, leastClosure;
|
||||
|
||||
typedef GeneratedTypeConstraint
|
||||
@@ -236,7 +236,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
new TypeParameterType.withDefaultNullability(
|
||||
helperTypeParameters[i]);
|
||||
} else {
|
||||
assert(isKnown(inferredTypes[i]));
|
||||
assert(operations
|
||||
.isKnownType(new SharedTypeSchemaView(inferredTypes[i])));
|
||||
inferredSubstitution[helperTypeParameters[i]] = inferredTypes[i];
|
||||
}
|
||||
}
|
||||
@@ -344,13 +345,15 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
/// type parameter which means we choose the upper bound rather than the
|
||||
/// lower bound for normally covariant type parameters.
|
||||
DartType solveTypeConstraint(MergedTypeConstraint constraint,
|
||||
{bool grounded = false, bool isContravariant = false}) {
|
||||
{bool grounded = false,
|
||||
bool isContravariant = false,
|
||||
required covariant OperationsCfe operations}) {
|
||||
if (!isContravariant) {
|
||||
// Prefer the known bound, if any.
|
||||
if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
|
||||
if (operations.isKnownType(constraint.lower)) {
|
||||
return constraint.lower.unwrapTypeSchemaView();
|
||||
}
|
||||
if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
|
||||
if (operations.isKnownType(constraint.upper)) {
|
||||
return constraint.upper.unwrapTypeSchemaView();
|
||||
}
|
||||
|
||||
@@ -361,27 +364,28 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
? leastClosure(constraint.lower.unwrapTypeSchemaView(),
|
||||
coreTypes: coreTypes)
|
||||
: constraint.lower.unwrapTypeSchemaView();
|
||||
} else if (constraint.upper is! UnknownType) {
|
||||
} else if (constraint.upper is! SharedUnknownTypeSchemaView) {
|
||||
return grounded
|
||||
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
|
||||
topType: coreTypes.objectNullableRawType)
|
||||
: constraint.upper.unwrapTypeSchemaView();
|
||||
} else {
|
||||
return const UnknownType();
|
||||
assert(constraint.lower is SharedUnknownTypeSchemaView);
|
||||
return constraint.lower.unwrapTypeSchemaView();
|
||||
}
|
||||
} else {
|
||||
// Prefer the known bound, if any.
|
||||
if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
|
||||
if (operations.isKnownType(constraint.upper)) {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
return constraint.upper.unwrapTypeSchemaView();
|
||||
}
|
||||
if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
|
||||
if (operations.isKnownType(constraint.lower)) {
|
||||
return constraint.lower.unwrapTypeSchemaView();
|
||||
}
|
||||
|
||||
// Otherwise take whatever bound has partial information,
|
||||
// e.g. `Iterable<?>`
|
||||
if (constraint.upper is! UnknownType) {
|
||||
if (constraint.upper is! SharedUnknownTypeSchemaView) {
|
||||
// Coverage-ignore-block(suite): Not run.
|
||||
return grounded
|
||||
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
|
||||
@@ -395,7 +399,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
// Coverage-ignore(suite): Not run.
|
||||
constraint.lower.unwrapTypeSchemaView();
|
||||
} else {
|
||||
return const UnknownType();
|
||||
assert(constraint.upper is SharedUnknownTypeSchemaView);
|
||||
return constraint.upper.unwrapTypeSchemaView();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,7 +469,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
// false.
|
||||
if (typeFromPreviousInference != null &&
|
||||
isLegacyCovariant &&
|
||||
isKnown(typeFromPreviousInference)) {
|
||||
operations
|
||||
.isKnownType(new SharedTypeSchemaView(typeFromPreviousInference))) {
|
||||
return typeFromPreviousInference;
|
||||
}
|
||||
|
||||
@@ -492,7 +498,9 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
}
|
||||
|
||||
return solveTypeConstraint(constraint,
|
||||
grounded: true, isContravariant: isContravariant);
|
||||
grounded: true,
|
||||
isContravariant: isContravariant,
|
||||
operations: operations);
|
||||
}
|
||||
|
||||
DartType _inferTypeParameterFromContext(DartType? typeFromPreviousInference,
|
||||
@@ -509,12 +517,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
// false.
|
||||
if (isLegacyCovariant &&
|
||||
typeFromPreviousInference != null &&
|
||||
isKnown(typeFromPreviousInference)) {
|
||||
operations
|
||||
.isKnownType(new SharedTypeSchemaView(typeFromPreviousInference))) {
|
||||
return typeFromPreviousInference;
|
||||
}
|
||||
|
||||
DartType t = solveTypeConstraint(constraint);
|
||||
if (!isKnown(t)) {
|
||||
DartType t = solveTypeConstraint(constraint, operations: operations);
|
||||
if (!operations.isKnownType(new SharedTypeSchemaView(t))) {
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -548,7 +557,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
constraint = constraint.clone();
|
||||
constraint.mergeInTypeSchemaUpper(
|
||||
new SharedTypeSchemaView(extendsConstraint), operations);
|
||||
return solveTypeConstraint(constraint);
|
||||
return solveTypeConstraint(constraint, operations: operations);
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
@@ -68,7 +68,7 @@ abstract class TypeSchemaEnvironmentTestBase {
|
||||
{required bool grounded}) {
|
||||
expect(
|
||||
typeSchemaEnvironment.solveTypeConstraint(parseConstraint(constraint),
|
||||
grounded: grounded),
|
||||
grounded: grounded, operations: _operations),
|
||||
parseType(expected));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user