Skip to content

Commit a2b2751

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[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 #54902 Change-Id: I2cfafef6a87b9bde8d1c94f6618e7f633debec0f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/424040 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent b23efe4 commit a2b2751

File tree

8 files changed

+197
-25
lines changed

8 files changed

+197
-25
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,21 @@ abstract interface class TypeAnalyzerOperations<Variable extends Object,
691691

692692
/// Converts a type into a corresponding type schema.
693693
SharedTypeSchemaView typeToSchema(SharedTypeView type);
694+
695+
/// Determines whether a type schema contains the unknown type.
696+
///
697+
/// Examples of known types:
698+
///
699+
/// * `int`,
700+
/// * `List<String>`,
701+
/// * `bool Function(double)`.
702+
///
703+
/// Examples of types that are not known:
704+
///
705+
/// * `_`,
706+
/// * `List<_>`,
707+
/// * `_ Function(_)`.
708+
bool isKnownType(SharedTypeSchemaView typeSchema);
694709
}
695710

696711
mixin TypeAnalyzerOperationsMixin<Variable extends Object,

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3236,6 +3236,63 @@ class MiniAstOperations
32363236
PropertyNonPromotabilityReason? whyPropertyIsNotPromotable(
32373237
covariant _PropertyElement property) =>
32383238
property.whyNotPromotable;
3239+
3240+
@override
3241+
bool isKnownType(SharedTypeSchemaView typeSchema) {
3242+
var unwrapped = typeSchema.unwrapTypeSchemaView<Type>();
3243+
switch (unwrapped) {
3244+
case FutureOrType(:var typeArgument):
3245+
return isKnownType(SharedTypeSchemaView(typeArgument));
3246+
case PrimaryType(:var args):
3247+
for (var arg in args) {
3248+
if (!isKnownType(SharedTypeSchemaView(arg))) {
3249+
return false;
3250+
}
3251+
}
3252+
return true;
3253+
case FunctionType(
3254+
:var returnType,
3255+
:var typeParametersShared,
3256+
:var positionalParameters,
3257+
:var namedParameters
3258+
):
3259+
if (!isKnownType(SharedTypeSchemaView(returnType))) {
3260+
return false;
3261+
}
3262+
for (var typeParameter in typeParametersShared) {
3263+
if (!isKnownType(SharedTypeSchemaView(typeParameter.bound))) {
3264+
return false;
3265+
}
3266+
}
3267+
for (var positionalParameter in positionalParameters) {
3268+
if (!isKnownType(SharedTypeSchemaView(positionalParameter))) {
3269+
return false;
3270+
}
3271+
}
3272+
for (var namedParameter in namedParameters) {
3273+
if (!isKnownType(SharedTypeSchemaView(namedParameter.type))) {
3274+
return false;
3275+
}
3276+
}
3277+
return true;
3278+
case RecordType(:var positionalTypes, :var namedTypes):
3279+
for (var positionalType in positionalTypes) {
3280+
if (!isKnownType(SharedTypeSchemaView(positionalType))) {
3281+
return false;
3282+
}
3283+
}
3284+
for (var namedType in namedTypes) {
3285+
if (!isKnownType(SharedTypeSchemaView(namedType.type))) {
3286+
return false;
3287+
}
3288+
}
3289+
return true;
3290+
case UnknownType():
3291+
return false;
3292+
default:
3293+
return true;
3294+
}
3295+
}
32393296
}
32403297

32413298
/// Representation of an expression or statement in the pseudo-Dart language

pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart';
6+
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
67
import 'package:checks/checks.dart';
78
import 'package:test/scaffolding.dart';
89

@@ -855,4 +856,80 @@ main() {
855856
check(tcg.constraints).unorderedEquals(['num <: T']);
856857
});
857858
});
859+
860+
group('isKnownType', () {
861+
test('Simple types', () {
862+
var tcg = TypeConstraintGatherer({'T'});
863+
check(tcg.typeAnalyzerOperations
864+
.isKnownType(SharedTypeSchemaView(Type('String'))))
865+
.isTrue();
866+
check(tcg.typeAnalyzerOperations
867+
.isKnownType(SharedTypeSchemaView(Type('dynamic'))))
868+
.isTrue();
869+
check(tcg.typeAnalyzerOperations
870+
.isKnownType(SharedTypeSchemaView(Type('Object'))))
871+
.isTrue();
872+
check(tcg.typeAnalyzerOperations
873+
.isKnownType(SharedTypeSchemaView(Type('void'))))
874+
.isTrue();
875+
check(tcg.typeAnalyzerOperations
876+
.isKnownType(SharedTypeSchemaView(Type('T'))))
877+
.isTrue();
878+
check(tcg.typeAnalyzerOperations
879+
.isKnownType(SharedTypeSchemaView(Type('_'))))
880+
.isFalse();
881+
});
882+
883+
test('Compound types', () {
884+
var tcg = TypeConstraintGatherer({'T'});
885+
check(tcg.typeAnalyzerOperations
886+
.isKnownType(SharedTypeSchemaView(Type('List<String>'))))
887+
.isTrue();
888+
check(tcg.typeAnalyzerOperations
889+
.isKnownType(SharedTypeSchemaView(Type('List<_>'))))
890+
.isFalse();
891+
check(tcg.typeAnalyzerOperations
892+
.isKnownType(SharedTypeSchemaView(Type('List<List<int>>'))))
893+
.isTrue();
894+
check(tcg.typeAnalyzerOperations
895+
.isKnownType(SharedTypeSchemaView(Type('List<List<_>>'))))
896+
.isFalse();
897+
check(tcg.typeAnalyzerOperations
898+
.isKnownType(SharedTypeSchemaView(Type('dynamic Function()'))))
899+
.isTrue();
900+
check(tcg.typeAnalyzerOperations
901+
.isKnownType(SharedTypeSchemaView(Type('_ Function()'))))
902+
.isFalse();
903+
check(tcg.typeAnalyzerOperations
904+
.isKnownType(SharedTypeSchemaView(Type('int Function(int)'))))
905+
.isTrue();
906+
check(tcg.typeAnalyzerOperations
907+
.isKnownType(SharedTypeSchemaView(Type('int Function(_)'))))
908+
.isFalse();
909+
check(tcg.typeAnalyzerOperations.isKnownType(
910+
SharedTypeSchemaView(Type('int Function({String named})'))))
911+
.isTrue();
912+
check(tcg.typeAnalyzerOperations.isKnownType(
913+
SharedTypeSchemaView(Type('int Function({_ named})'))))
914+
.isFalse();
915+
check(tcg.typeAnalyzerOperations
916+
.isKnownType(SharedTypeSchemaView(Type('(int, String, Object)'))))
917+
.isTrue();
918+
check(tcg.typeAnalyzerOperations
919+
.isKnownType(SharedTypeSchemaView(Type('(int, String, _)'))))
920+
.isFalse();
921+
check(tcg.typeAnalyzerOperations.isKnownType(
922+
SharedTypeSchemaView(Type('(int, String, {dynamic named})'))))
923+
.isTrue();
924+
check(tcg.typeAnalyzerOperations.isKnownType(
925+
SharedTypeSchemaView(Type('(int, String, {_ named})'))))
926+
.isFalse();
927+
check(tcg.typeAnalyzerOperations.isKnownType(SharedTypeSchemaView(
928+
Type('(int, String, {List<dynamic> Function(int) named})'))))
929+
.isTrue();
930+
check(tcg.typeAnalyzerOperations.isKnownType(SharedTypeSchemaView(
931+
Type('(int, String, {List<_> Function(int) named})'))))
932+
.isFalse();
933+
});
934+
});
858935
}

pkg/analyzer/lib/src/dart/element/generic_inferrer.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ class GenericInferrer {
371371
);
372372
}
373373

374-
if (UnknownInferredType.isKnown(inferred)) {
374+
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(inferred))) {
375375
knownTypes[parameter] = inferred;
376376
} else if (_strictInference) {
377377
// [typeParam] could not be inferred. A result will still be returned
@@ -519,10 +519,10 @@ class GenericInferrer {
519519
// For both of those, prefer the lower bound (arbitrary heuristic) or upper
520520
// bound if [isContravariant] is `true`
521521
if (isContravariant) {
522-
if (UnknownInferredType.isKnown(upper)) {
522+
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(upper))) {
523523
return upper;
524524
}
525-
if (UnknownInferredType.isKnown(lower)) {
525+
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(lower))) {
526526
return lower;
527527
}
528528
if (!identical(UnknownInferredType.instance, upper)) {
@@ -533,10 +533,10 @@ class GenericInferrer {
533533
}
534534
return upper;
535535
} else {
536-
if (UnknownInferredType.isKnown(lower)) {
536+
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(lower))) {
537537
return lower;
538538
}
539-
if (UnknownInferredType.isKnown(upper)) {
539+
if (_typeSystemOperations.isKnownType(SharedTypeSchemaView(upper))) {
540540
return upper;
541541
}
542542
if (!identical(UnknownInferredType.instance, lower)) {
@@ -596,7 +596,9 @@ class GenericInferrer {
596596

597597
inferredTypes[i] = inferredType;
598598
if (typeParam.isLegacyCovariant &&
599-
UnknownInferredType.isKnown(inferredType)) {
599+
_typeSystemOperations.isKnownType(
600+
SharedTypeSchemaView(inferredType),
601+
)) {
600602
_typesInferredSoFar[typeParam] = inferredType;
601603
}
602604
} else {
@@ -730,7 +732,7 @@ class GenericInferrer {
730732
constraint,
731733
isContravariant: isContravariant,
732734
);
733-
if (UnknownInferredType.isUnknown(t)) {
735+
if (!_typeSystemOperations.isKnownType(SharedTypeSchemaView(t))) {
734736
return t;
735737
}
736738

pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,13 @@ class TypeSystemOperations
667667
type.element3 is! ExtensionTypeElement;
668668
}
669669

670+
@override
671+
bool isKnownType(SharedTypeSchemaView typeSchema) {
672+
return UnknownInferredType.isKnown(
673+
typeSchema.unwrapTypeSchemaView<TypeImpl>(),
674+
);
675+
}
676+
670677
@override
671678
bool isNonNullableInternal(TypeImpl type) {
672679
return typeSystem.isNonNullable(type);

pkg/front_end/lib/src/type_inference/type_inference_engine.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,11 @@ class OperationsCfe
10431043
inferenceResultForTesting: null,
10441044
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
10451045
}
1046+
1047+
@override
1048+
bool isKnownType(SharedTypeSchemaView typeSchema) {
1049+
return isKnown(typeSchema.unwrapTypeSchemaView());
1050+
}
10461051
}
10471052

10481053
/// Type inference results used for testing.

pkg/front_end/lib/src/type_inference/type_schema_environment.dart

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import 'standard_bounds.dart' show TypeSchemaStandardBounds;
2020
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
2121
import 'type_demotion.dart';
2222
import 'type_inference_engine.dart';
23-
import 'type_schema.dart' show UnknownType, isKnown;
23+
import 'type_schema.dart' show UnknownType;
2424
import 'type_schema_elimination.dart' show greatestClosure, leastClosure;
2525

2626
typedef GeneratedTypeConstraint
@@ -236,7 +236,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
236236
new TypeParameterType.withDefaultNullability(
237237
helperTypeParameters[i]);
238238
} else {
239-
assert(isKnown(inferredTypes[i]));
239+
assert(operations
240+
.isKnownType(new SharedTypeSchemaView(inferredTypes[i])));
240241
inferredSubstitution[helperTypeParameters[i]] = inferredTypes[i];
241242
}
242243
}
@@ -344,13 +345,15 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
344345
/// type parameter which means we choose the upper bound rather than the
345346
/// lower bound for normally covariant type parameters.
346347
DartType solveTypeConstraint(MergedTypeConstraint constraint,
347-
{bool grounded = false, bool isContravariant = false}) {
348+
{bool grounded = false,
349+
bool isContravariant = false,
350+
required covariant OperationsCfe operations}) {
348351
if (!isContravariant) {
349352
// Prefer the known bound, if any.
350-
if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
353+
if (operations.isKnownType(constraint.lower)) {
351354
return constraint.lower.unwrapTypeSchemaView();
352355
}
353-
if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
356+
if (operations.isKnownType(constraint.upper)) {
354357
return constraint.upper.unwrapTypeSchemaView();
355358
}
356359

@@ -361,27 +364,28 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
361364
? leastClosure(constraint.lower.unwrapTypeSchemaView(),
362365
coreTypes: coreTypes)
363366
: constraint.lower.unwrapTypeSchemaView();
364-
} else if (constraint.upper is! UnknownType) {
367+
} else if (constraint.upper is! SharedUnknownTypeSchemaView) {
365368
return grounded
366369
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
367370
topType: coreTypes.objectNullableRawType)
368371
: constraint.upper.unwrapTypeSchemaView();
369372
} else {
370-
return const UnknownType();
373+
assert(constraint.lower is SharedUnknownTypeSchemaView);
374+
return constraint.lower.unwrapTypeSchemaView();
371375
}
372376
} else {
373377
// Prefer the known bound, if any.
374-
if (isKnown(constraint.upper.unwrapTypeSchemaView())) {
378+
if (operations.isKnownType(constraint.upper)) {
375379
// Coverage-ignore-block(suite): Not run.
376380
return constraint.upper.unwrapTypeSchemaView();
377381
}
378-
if (isKnown(constraint.lower.unwrapTypeSchemaView())) {
382+
if (operations.isKnownType(constraint.lower)) {
379383
return constraint.lower.unwrapTypeSchemaView();
380384
}
381385

382386
// Otherwise take whatever bound has partial information,
383387
// e.g. `Iterable<?>`
384-
if (constraint.upper is! UnknownType) {
388+
if (constraint.upper is! SharedUnknownTypeSchemaView) {
385389
// Coverage-ignore-block(suite): Not run.
386390
return grounded
387391
? greatestClosure(constraint.upper.unwrapTypeSchemaView(),
@@ -395,7 +399,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
395399
// Coverage-ignore(suite): Not run.
396400
constraint.lower.unwrapTypeSchemaView();
397401
} else {
398-
return const UnknownType();
402+
assert(constraint.upper is SharedUnknownTypeSchemaView);
403+
return constraint.upper.unwrapTypeSchemaView();
399404
}
400405
}
401406
}
@@ -464,7 +469,8 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
464469
// false.
465470
if (typeFromPreviousInference != null &&
466471
isLegacyCovariant &&
467-
isKnown(typeFromPreviousInference)) {
472+
operations
473+
.isKnownType(new SharedTypeSchemaView(typeFromPreviousInference))) {
468474
return typeFromPreviousInference;
469475
}
470476

@@ -492,7 +498,9 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
492498
}
493499

494500
return solveTypeConstraint(constraint,
495-
grounded: true, isContravariant: isContravariant);
501+
grounded: true,
502+
isContravariant: isContravariant,
503+
operations: operations);
496504
}
497505

498506
DartType _inferTypeParameterFromContext(DartType? typeFromPreviousInference,
@@ -509,12 +517,13 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
509517
// false.
510518
if (isLegacyCovariant &&
511519
typeFromPreviousInference != null &&
512-
isKnown(typeFromPreviousInference)) {
520+
operations
521+
.isKnownType(new SharedTypeSchemaView(typeFromPreviousInference))) {
513522
return typeFromPreviousInference;
514523
}
515524

516-
DartType t = solveTypeConstraint(constraint);
517-
if (!isKnown(t)) {
525+
DartType t = solveTypeConstraint(constraint, operations: operations);
526+
if (!operations.isKnownType(new SharedTypeSchemaView(t))) {
518527
return t;
519528
}
520529

@@ -548,7 +557,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
548557
constraint = constraint.clone();
549558
constraint.mergeInTypeSchemaUpper(
550559
new SharedTypeSchemaView(extendsConstraint), operations);
551-
return solveTypeConstraint(constraint);
560+
return solveTypeConstraint(constraint, operations: operations);
552561
}
553562

554563
return t;

pkg/front_end/test/type_inference/type_schema_environment_test_base.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ abstract class TypeSchemaEnvironmentTestBase {
6868
{required bool grounded}) {
6969
expect(
7070
typeSchemaEnvironment.solveTypeConstraint(parseConstraint(constraint),
71-
grounded: grounded),
71+
grounded: grounded, operations: _operations),
7272
parseType(expected));
7373
}
7474

0 commit comments

Comments
 (0)