Skip to content

Commit bba0047

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[analyzer][cfe] Share constraint generation for generic functions
Part of #54902 Change-Id: Ic025cdc36a266d35094626df175346ccac6f99fe Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/393860 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent be6ca13 commit bba0047

File tree

12 files changed

+432
-292
lines changed

12 files changed

+432
-292
lines changed

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

Lines changed: 246 additions & 109 deletions
Large diffs are not rendered by default.

pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ abstract interface class SharedTypeParameterStructure<
8383
TypeStructure extends SharedTypeStructure<TypeStructure>> {
8484
/// The name of the type parameter, for display to the user.
8585
String get displayName;
86+
87+
/// The bound of the type parameter.
88+
TypeStructure? get bound;
8689
}
8790

8891
/// Common interface for data structures used by the implementations to

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,6 +3281,13 @@ class MiniAstOperations
32813281
// TODO(paulberry): Implement greatest closure of types in mini ast.
32823282
throw UnimplementedError();
32833283
}
3284+
3285+
@override
3286+
Type leastClosureOfTypeInternal(Type type,
3287+
List<SharedTypeParameterStructure<Type>> typeParametersToEliminate) {
3288+
// TODO(paulberry): Implement greatest closure of types in mini ast.
3289+
throw UnimplementedError();
3290+
}
32843291
}
32853292

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

pkg/_fe_analyzer_shared/test/mini_types.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ sealed class TypeNameInfo {
513513
class TypeParameter extends TypeNameInfo
514514
implements SharedTypeParameterStructure<Type> {
515515
/// The type variable's bound. Defaults to `Object?`.
516+
@override
516517
Type bound;
517518

518519
TypeParameter._(super.name) : bound = Type('Object?');

pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,4 +879,26 @@ class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
879879
{required Node? nodeForTesting}) {
880880
_constraints.add('$lower <: $typeParameter');
881881
}
882+
883+
@override
884+
void eliminateTypeParametersInGeneratedConstraints(
885+
Object eliminator, TypeConstraintGeneratorState eliminationStartState,
886+
{required Node? astNodeForTesting}) {
887+
// TODO(paulberry): implement eliminateTypeParametersInGeneratedConstraints
888+
}
889+
890+
@override
891+
(
892+
Type,
893+
Type, {
894+
List<TypeParameter> typeParametersToEliminate
895+
}) instantiateFunctionTypesAndProvideFreshTypeParameters(
896+
SharedFunctionTypeStructure<Type, TypeParameter, NamedFunctionParameter>
897+
p,
898+
SharedFunctionTypeStructure<Type, TypeParameter, NamedFunctionParameter>
899+
q,
900+
{required bool leftSchema}) {
901+
// TODO(paulberry): implement instantiateFunctionTypesAndProvideEliminator
902+
throw UnimplementedError();
903+
}
882904
}

pkg/analyzer/lib/dart/element/element.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2517,6 +2517,7 @@ abstract class TypeParameterElement
25172517
/// if this parameter does not have an explicit bound. Being able to
25182518
/// distinguish between an implicit and explicit bound is needed by the
25192519
/// instantiate to bounds algorithm.
2520+
@override
25202521
DartType? get bound;
25212522

25222523
@override

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

Lines changed: 64 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,30 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
130130
return result;
131131
}
132132

133+
@override
134+
void eliminateTypeParametersInGeneratedConstraints(
135+
covariant List<TypeParameterElement> eliminator,
136+
shared.TypeConstraintGeneratorState eliminationStartState,
137+
{required AstNode? astNodeForTesting}) {
138+
var constraints = _constraints.sublist(eliminationStartState.count);
139+
_constraints.length = eliminationStartState.count;
140+
for (var constraint in constraints) {
141+
if (constraint.isUpper) {
142+
addUpperConstraintForParameter(
143+
constraint.typeParameter,
144+
typeAnalyzerOperations.leastClosureOfTypeInternal(
145+
constraint.constraint.unwrapTypeSchemaView(), eliminator),
146+
nodeForTesting: astNodeForTesting);
147+
} else {
148+
addLowerConstraintForParameter(
149+
constraint.typeParameter,
150+
typeAnalyzerOperations.greatestClosureOfTypeInternal(
151+
constraint.constraint.unwrapTypeSchemaView(), eliminator),
152+
nodeForTesting: astNodeForTesting);
153+
}
154+
}
155+
}
156+
133157
@override
134158
List<DartType>? getTypeArgumentsAsInstanceOf(
135159
InterfaceType type, InterfaceElement typeDeclaration) {
@@ -144,6 +168,43 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
144168
return null;
145169
}
146170

171+
@override
172+
(DartType, DartType, {List<TypeParameterElement> typeParametersToEliminate})
173+
instantiateFunctionTypesAndProvideFreshTypeParameters(
174+
covariant FunctionType P, covariant FunctionType Q,
175+
{required bool leftSchema}) {
176+
// And `Z0...Zn` are fresh variables with bounds `B20, ..., B2n`.
177+
// Where `B2i` is `B0i[Z0/T0, ..., Zn/Tn]` if `P` is a type schema.
178+
// Or `B2i` is `B1i[Z0/S0, ..., Zn/Sn]` if `Q` is a type schema.
179+
// In other words, we choose the bounds for the fresh variables from
180+
// whichever of the two generic function types is a type schema and does
181+
// not contain any variables from `L`.
182+
var newTypeParameters = <TypeParameterElement>[];
183+
for (var i = 0; i < P.typeFormals.length; i++) {
184+
var Z = TypeParameterElementImpl('Z$i', -1);
185+
if (leftSchema) {
186+
Z.bound = P.typeFormals[i].bound;
187+
} else {
188+
Z.bound = Q.typeFormals[i].bound;
189+
}
190+
newTypeParameters.add(Z);
191+
}
192+
193+
// And `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for
194+
// `F1[Z0/S0, ..., Zn/Sn]` with respect to `L` under constraints `C0`.
195+
var typeArguments = newTypeParameters
196+
.map((e) => e.instantiate(nullabilitySuffix: NullabilitySuffix.none))
197+
.toList();
198+
var P_instantiated = P.instantiate(typeArguments);
199+
var Q_instantiated = Q.instantiate(typeArguments);
200+
201+
return (
202+
P_instantiated,
203+
Q_instantiated,
204+
typeParametersToEliminate: newTypeParameters
205+
);
206+
}
207+
147208
@override
148209
bool performSubtypeConstraintGenerationInternal(DartType p, DartType q,
149210
{required bool leftSchema, required AstNode? astNodeForTesting}) {
@@ -299,8 +360,9 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
299360
}
300361
}
301362

302-
if (P is FunctionType && Q is FunctionType) {
303-
return _functionType(P, Q, leftSchema, nodeForTesting: nodeForTesting);
363+
if (performSubtypeConstraintGenerationForFunctionTypes(P, Q,
364+
leftSchema: leftSchema, astNodeForTesting: nodeForTesting)) {
365+
return true;
304366
}
305367

306368
// A type `P` is a subtype match for `Record` with respect to `L` under no
@@ -319,96 +381,6 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
319381

320382
return false;
321383
}
322-
323-
/// Matches [P] against [Q], where [P] and [Q] are both function types.
324-
///
325-
/// If [P] is a subtype of [Q] under some constraints, the constraints making
326-
/// the relation possible are recorded to [_constraints], and `true` is
327-
/// returned. Otherwise, [_constraints] is left unchanged (or rolled back),
328-
/// and `false` is returned.
329-
bool _functionType(FunctionType P, FunctionType Q, bool leftSchema,
330-
{required AstNode? nodeForTesting}) {
331-
if (P.nullabilitySuffix != NullabilitySuffix.none) {
332-
return false;
333-
}
334-
335-
if (Q.nullabilitySuffix != NullabilitySuffix.none) {
336-
return false;
337-
}
338-
339-
var P_typeFormals = P.typeFormals;
340-
var Q_typeFormals = Q.typeFormals;
341-
if (P_typeFormals.length != Q_typeFormals.length) {
342-
return false;
343-
}
344-
345-
if (P_typeFormals.isEmpty && Q_typeFormals.isEmpty) {
346-
return performSubtypeConstraintGenerationForFunctionTypes(P, Q,
347-
leftSchema: leftSchema, astNodeForTesting: nodeForTesting);
348-
}
349-
350-
// We match two generic function types:
351-
// `<T0 extends B00, ..., Tn extends B0n>F0`
352-
// `<S0 extends B10, ..., Sn extends B1n>F1`
353-
// with respect to `L` under constraint set `C2`:
354-
var rewind = _constraints.length;
355-
356-
// If `B0i` is a subtype match for `B1i` with constraint set `Ci0`.
357-
// If `B1i` is a subtype match for `B0i` with constraint set `Ci1`.
358-
// And `Ci2` is `Ci0 + Ci1`.
359-
for (var i = 0; i < P_typeFormals.length; i++) {
360-
var B0 = P_typeFormals[i].bound ?? _typeSystem.objectQuestion;
361-
var B1 = Q_typeFormals[i].bound ?? _typeSystem.objectQuestion;
362-
if (!trySubtypeMatch(B0, B1, leftSchema,
363-
nodeForTesting: nodeForTesting)) {
364-
_constraints.length = rewind;
365-
return false;
366-
}
367-
if (!trySubtypeMatch(B1, B0, !leftSchema,
368-
nodeForTesting: nodeForTesting)) {
369-
_constraints.length = rewind;
370-
return false;
371-
}
372-
}
373-
374-
// And `Z0...Zn` are fresh variables with bounds `B20, ..., B2n`.
375-
// Where `B2i` is `B0i[Z0/T0, ..., Zn/Tn]` if `P` is a type schema.
376-
// Or `B2i` is `B1i[Z0/S0, ..., Zn/Sn]` if `Q` is a type schema.
377-
// In other words, we choose the bounds for the fresh variables from
378-
// whichever of the two generic function types is a type schema and does
379-
// not contain any variables from `L`.
380-
var newTypeParameters = <TypeParameterElement>[];
381-
for (var i = 0; i < P_typeFormals.length; i++) {
382-
var Z = TypeParameterElementImpl('Z$i', -1);
383-
if (leftSchema) {
384-
Z.bound = P_typeFormals[i].bound;
385-
} else {
386-
Z.bound = Q_typeFormals[i].bound;
387-
}
388-
newTypeParameters.add(Z);
389-
}
390-
391-
// And `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for
392-
// `F1[Z0/S0, ..., Zn/Sn]` with respect to `L` under constraints `C0`.
393-
var typeArguments = newTypeParameters
394-
.map((e) => e.instantiate(nullabilitySuffix: NullabilitySuffix.none))
395-
.toList();
396-
var P_instantiated = P.instantiate(typeArguments);
397-
var Q_instantiated = Q.instantiate(typeArguments);
398-
if (!performSubtypeConstraintGenerationForFunctionTypes(
399-
P_instantiated, Q_instantiated,
400-
leftSchema: leftSchema, astNodeForTesting: nodeForTesting)) {
401-
_constraints.length = rewind;
402-
return false;
403-
}
404-
405-
// And `C1` is `C02 + ... + Cn2 + C0`.
406-
// And `C2` is `C1` with each constraint replaced with its closure
407-
// with respect to `[Z0, ..., Zn]`.
408-
// TODO(scheglov): do closure
409-
410-
return true;
411-
}
412384
}
413385

414386
/// Data structure maintaining intermediate type inference results, such as

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,6 @@ class TypeSystemOperations
520520
@override
521521
DartType greatestClosureOfTypeInternal(DartType type,
522522
List<SharedTypeParameterStructure<DartType>> typeParametersToEliminate) {
523-
typeParametersToEliminate.first;
524523
return typeSystem.greatestClosure(
525524
type, typeParametersToEliminate.cast<TypeParameterElement>());
526525
}
@@ -624,6 +623,13 @@ class TypeSystemOperations
624623
.iterableType(elementTypeSchema.unwrapTypeSchemaView()));
625624
}
626625

626+
@override
627+
DartType leastClosureOfTypeInternal(DartType type,
628+
List<SharedTypeParameterStructure<DartType>> typeParametersToEliminate) {
629+
return typeSystem.leastClosure(
630+
type, typeParametersToEliminate.cast<TypeParameterElement>());
631+
}
632+
627633
@override
628634
DartType listTypeInternal(DartType elementType) {
629635
return typeSystem.typeProvider.listType(elementType);

0 commit comments

Comments
 (0)