Skip to content

Commit d75fe77

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[anlyzer][cfe] Use bounds to restrict choices during inference
Closes dart-lang/language#1194 Change-Id: I6866b6ab6f29cddbb293122e09588f705aaea1c1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/387020 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 82592f2 commit d75fe77

File tree

63 files changed

+2024
-1512
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2024
-1512
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,15 @@ abstract interface class TypeAnalyzerOperations<
658658
SharedTypeSchemaView<TypeStructure> typeSchema1,
659659
SharedTypeSchemaView<TypeStructure> typeSchema2);
660660

661+
/// Computes the greatest closure of a type.
662+
///
663+
/// Computing the greatest closure of a type is described here:
664+
/// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md#type-variable-elimination-least-and-greatest-closure-of-a-type
665+
TypeStructure greatestClosureOfTypeInternal(
666+
TypeStructure type,
667+
List<SharedTypeParameterStructure<TypeStructure>>
668+
typeParametersToEliminate);
669+
661670
/// Converts a type into a corresponding type schema.
662671
SharedTypeSchemaView<TypeStructure> typeToSchema(
663672
SharedTypeView<TypeStructure> type);
@@ -888,10 +897,15 @@ abstract class TypeConstraintGenerator<
888897
/// https://github.com/dart-lang/sdk/issues/51156#issuecomment-2158825417.
889898
bool get enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr;
890899

900+
/// True if the language feature inference-using-bounds is enabled.
901+
final bool inferenceUsingBoundsIsEnabled;
902+
891903
/// Abstract type operations to be used in the matching methods.
892904
TypeAnalyzerOperations<TypeStructure, Variable, TypeParameterStructure,
893905
TypeDeclarationType, TypeDeclaration> get typeAnalyzerOperations;
894906

907+
TypeConstraintGenerator({required this.inferenceUsingBoundsIsEnabled});
908+
895909
/// Returns the type arguments of the supertype of [type] that is an
896910
/// instantiation of [typeDeclaration]. If none of the supertypes of [type]
897911
/// are instantiations of [typeDeclaration], returns null.

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3271,6 +3271,13 @@ class MiniAstOperations
32713271
SharedTypeView<Type> type, NullabilitySuffix modifier) {
32723272
return SharedTypeView(type.unwrapTypeView().withNullability(modifier));
32733273
}
3274+
3275+
@override
3276+
Type greatestClosureOfTypeInternal(Type type,
3277+
List<SharedTypeParameterStructure<Type>> typeParametersToEliminate) {
3278+
// TODO(paulberry): Implement greatest closure of types in mini ast.
3279+
throw UnimplementedError();
3280+
}
32743281
}
32753282

32763283
/// 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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,8 @@ class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
544544
final _constraints = <String>[];
545545

546546
_TypeConstraintGatherer(Set<String> typeVariablesBeingConstrained,
547-
{this.enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr =
548-
false}) {
547+
{this.enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr = false})
548+
: super(inferenceUsingBoundsIsEnabled: false) {
549549
for (var typeVariableName in typeVariablesBeingConstrained) {
550550
_typeVariablesBeingConstrained
551551
.add(TypeRegistry.addTypeParameter(typeVariableName));

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ class GenericInferrer {
772772
typeSystem: _typeSystem,
773773
typeSystemOperations: _typeSystemOperations,
774774
typeParameters: _typeFormals,
775+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
775776
dataForTesting: null);
776777
typeConstraintGatherer.trySubtypeMatch(
777778
lower, typeParameterToInferBound, /* leftSchema */ true,
@@ -889,6 +890,7 @@ class GenericInferrer {
889890
typeSystem: _typeSystem,
890891
typeParameters: _typeParameters,
891892
typeSystemOperations: _typeSystemOperations,
893+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
892894
dataForTesting: dataForTesting);
893895
var success = gatherer.trySubtypeMatch(t1, t2, !covariant,
894896
nodeForTesting: nodeForTesting);

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
5151
required TypeSystemImpl typeSystem,
5252
required Iterable<TypeParameterElement> typeParameters,
5353
required TypeSystemOperations typeSystemOperations,
54+
required super.inferenceUsingBoundsIsEnabled,
5455
required this.dataForTesting,
5556
}) : _typeSystem = typeSystem,
5657
_typeSystemOperations = typeSystemOperations {
@@ -157,7 +158,13 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
157158
if (_typeSystemOperations.matchInferableParameter(SharedTypeView(Q))
158159
case var Q_element?
159160
when Q_nullability == NullabilitySuffix.none &&
160-
_typeParameters.contains(Q_element)) {
161+
_typeParameters.contains(Q_element) &&
162+
(!inferenceUsingBoundsIsEnabled ||
163+
(Q_element.bound == null ||
164+
_typeSystemOperations.isSubtypeOfInternal(
165+
P,
166+
_typeSystemOperations.greatestClosureOfTypeInternal(
167+
Q_element.bound!, [..._typeParameters]))))) {
161168
_addLower(Q_element, P, nodeForTesting: nodeForTesting);
162169
return true;
163170
}
@@ -315,7 +322,9 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
315322
}
316323

317324
if (P is FunctionType && Q is FunctionType) {
318-
return _functionType(P, Q, leftSchema, nodeForTesting: nodeForTesting);
325+
return _functionType(P, Q, leftSchema,
326+
nodeForTesting: nodeForTesting,
327+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
319328
}
320329

321330
// A type `P` is a subtype match for `Record` with respect to `L` under no
@@ -330,6 +339,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
330339
if (P is SharedRecordTypeStructure<DartType> &&
331340
Q is SharedRecordTypeStructure<DartType>) {
332341
return _recordType(P as RecordTypeImpl, Q as RecordTypeImpl, leftSchema,
342+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
333343
nodeForTesting: nodeForTesting);
334344
}
335345

@@ -371,7 +381,8 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
371381
/// returned. Otherwise, [_constraints] is left unchanged (or rolled back),
372382
/// and `false` is returned.
373383
bool _functionType(FunctionType P, FunctionType Q, bool leftSchema,
374-
{required AstNode? nodeForTesting}) {
384+
{required bool inferenceUsingBoundsIsEnabled,
385+
required AstNode? nodeForTesting}) {
375386
if (P.nullabilitySuffix != NullabilitySuffix.none) {
376387
return false;
377388
}
@@ -461,7 +472,8 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
461472
/// returned. Otherwise, [_constraints] is left unchanged (or rolled back),
462473
/// and `false` is returned.
463474
bool _recordType(RecordTypeImpl P, RecordTypeImpl Q, bool leftSchema,
464-
{required AstNode? nodeForTesting}) {
475+
{required bool inferenceUsingBoundsIsEnabled,
476+
required AstNode? nodeForTesting}) {
465477
// If `P` is `(M0, ..., Mk)` and `Q` is `(N0, ..., Nk)`, then the match
466478
// holds under constraints `C0 + ... + Ck`:
467479
// If `Mi` is a subtype match for `Ni` with respect to L under

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,14 @@ class TypeSystemOperations
517517
typeSystem.greatestClosureOfSchema(schema.unwrapTypeSchemaView()));
518518
}
519519

520+
@override
521+
DartType greatestClosureOfTypeInternal(DartType type,
522+
List<SharedTypeParameterStructure<DartType>> typeParametersToEliminate) {
523+
typeParametersToEliminate.first;
524+
return typeSystem.greatestClosure(
525+
type, typeParametersToEliminate.cast<TypeParameterElement>());
526+
}
527+
520528
@override
521529
bool isAlwaysExhaustiveType(SharedTypeView<DartType> type) {
522530
return typeSystem.isAlwaysExhaustive(type.unwrapTypeView());

pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
189189
// Something invalid...
190190
_assertTypes(
191191
_inferCall(clone, [stringNone, numNone], expectError: true),
192-
[objectNone],
192+
[
193+
interfaceTypeNone(A, typeArguments: [objectQuestion]),
194+
],
193195
);
194196
}
195197

pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,7 @@ class TypeConstraintGathererTest extends AbstractTypeSystemTest {
12711271
typeParameters: typeParameters,
12721272
typeSystemOperations:
12731273
TypeSystemOperations(typeSystem, strictCasts: false),
1274+
inferenceUsingBoundsIsEnabled: false,
12741275
dataForTesting: null,
12751276
);
12761277

@@ -1299,6 +1300,7 @@ class TypeConstraintGathererTest extends AbstractTypeSystemTest {
12991300
typeParameters: typeParameters,
13001301
typeSystemOperations:
13011302
TypeSystemOperations(typeSystem, strictCasts: false),
1303+
inferenceUsingBoundsIsEnabled: false,
13021304
dataForTesting: null,
13031305
);
13041306

pkg/front_end/lib/src/source/source_library_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
17251725
}
17261726
} else {
17271727
if (issueInferred) {
1728+
// Coverage-ignore-block(suite): Not run.
17281729
message = templateIncorrectTypeArgumentInstantiationInferred
17291730
.withArguments(argument, typeParameter.bound,
17301731
typeParameter.name!, targetReceiver);

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2864,6 +2864,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
28642864
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
28652865
listType, typeParametersToInfer, typeContext,
28662866
isConst: node.isConst,
2867+
inferenceUsingBoundsIsEnabled:
2868+
libraryFeatures.inferenceUsingBounds.isEnabled,
28672869
typeOperations: operations,
28682870
inferenceResultForTesting: dataForTesting
28692871
// Coverage-ignore(suite): Not run.
@@ -5294,6 +5296,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
52945296
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
52955297
mapType, typeParametersToInfer, typeContext,
52965298
isConst: node.isConst,
5299+
inferenceUsingBoundsIsEnabled:
5300+
libraryFeatures.inferenceUsingBounds.isEnabled,
52975301
typeOperations: operations,
52985302
inferenceResultForTesting: dataForTesting
52995303
// Coverage-ignore(suite): Not run.
@@ -5376,6 +5380,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
53765380
typeSchemaEnvironment.setupGenericTypeInference(
53775381
setType, typeParametersToInfer, typeContext,
53785382
isConst: node.isConst,
5383+
inferenceUsingBoundsIsEnabled:
5384+
libraryFeatures.inferenceUsingBounds.isEnabled,
53795385
typeOperations: operations,
53805386
inferenceResultForTesting: dataForTesting
53815387
// Coverage-ignore(suite): Not run.
@@ -8670,6 +8676,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
86708676
gatherer = typeSchemaEnvironment.setupGenericTypeInference(
86718677
setType, typeParametersToInfer, typeContext,
86728678
isConst: node.isConst,
8679+
inferenceUsingBoundsIsEnabled:
8680+
libraryFeatures.inferenceUsingBounds.isEnabled,
86738681
typeOperations: operations,
86748682
inferenceResultForTesting: dataForTesting
86758683
// Coverage-ignore(suite): Not run.
@@ -11796,6 +11804,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
1179611804
TypeConstraintGatherer gatherer =
1179711805
typeSchemaEnvironment.setupGenericTypeInference(
1179811806
declaredType, typeParametersToInfer, contextType,
11807+
inferenceUsingBoundsIsEnabled:
11808+
libraryFeatures.inferenceUsingBounds.isEnabled,
1179911809
typeOperations: operations,
1180011810
inferenceResultForTesting: dataForTesting
1180111811
// Coverage-ignore(suite): Not run.

0 commit comments

Comments
 (0)