[analyzer][cfe] Share inference-using-bounds routines
Part of https://github.com/dart-lang/sdk/issues/54902
Change-Id: I12282c2492ed9f1220b47fcf8b0d73c93bbfc432
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/401660
Reviewed-by: Erik Ernst <eernst@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
index 09e3103..d4eaf4d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart
@@ -5,6 +5,7 @@
import '../flow_analysis/flow_analysis_operations.dart';
import '../types/shared_type.dart';
import 'nullability_suffix.dart';
+import 'type_constraint.dart';
/// Callback API used by the shared type analyzer to query and manipulate the
/// client's representation of variables and types.
@@ -698,6 +699,40 @@
/// Returns [type] suffixed with the [suffix].
TypeStructure withNullabilitySuffixInternal(
TypeStructure type, NullabilitySuffix suffix);
+
+ TypeConstraintGenerator<
+ TypeStructure,
+ SharedNamedFunctionParameterStructure<TypeStructure>,
+ Variable,
+ TypeParameterStructure,
+ TypeDeclarationType,
+ TypeDeclaration,
+ Object>
+ createTypeConstraintGenerator(
+ {required TypeConstraintGenerationDataForTesting<TypeStructure,
+ TypeParameterStructure, Variable, Object>?
+ typeConstraintGenerationDataForTesting,
+ required List<TypeParameterStructure> typeParametersToInfer,
+ required TypeAnalyzerOperations<TypeStructure, Variable,
+ TypeParameterStructure, TypeDeclarationType, TypeDeclaration>
+ typeAnalyzerOperations,
+ required bool inferenceUsingBoundsIsEnabled});
+
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable,
+ TypeDeclarationType, TypeDeclaration>
+ mergeInConstraintsFromBound(
+ {required TypeParameterStructure typeParameterToInfer,
+ required List<TypeParameterStructure> typeParametersToInfer,
+ required TypeStructure lower,
+ required Map<
+ TypeParameterStructure,
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure,
+ Variable, TypeDeclarationType, TypeDeclaration>>
+ inferencePhaseConstraints,
+ required TypeConstraintGenerationDataForTesting<TypeStructure,
+ TypeParameterStructure, Variable, Object>?
+ dataForTesting,
+ required bool inferenceUsingBoundsIsEnabled});
}
mixin TypeAnalyzerOperationsMixin<
@@ -893,6 +928,96 @@
SharedTypeView<TypeStructure> type) {
return new SharedTypeSchemaView(type.unwrapTypeView());
}
+
+ @override
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable,
+ TypeDeclarationType, TypeDeclaration>
+ mergeInConstraintsFromBound(
+ {required TypeParameterStructure typeParameterToInfer,
+ required List<TypeParameterStructure> typeParametersToInfer,
+ required TypeStructure lower,
+ required Map<
+ TypeParameterStructure,
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure,
+ Variable, TypeDeclarationType, TypeDeclaration>>
+ inferencePhaseConstraints,
+ required TypeConstraintGenerationDataForTesting<TypeStructure,
+ TypeParameterStructure, Variable, Object>?
+ dataForTesting,
+ required bool inferenceUsingBoundsIsEnabled}) {
+ // The type parameter's bound may refer to itself (or other type
+ // parameters), so we might have to create an additional constraint.
+ // Consider this example from
+ // https://github.com/dart-lang/language/issues/3009:
+ //
+ // class A<X extends A<X>> {}
+ // class B extends A<B> {}
+ // class C extends B {}
+ // void f<X extends A<X>>(X x) {}
+ // void main() {
+ // f(C()); // should infer f<B>(C()).
+ // }
+ //
+ // In order for `f(C())` to be inferred as `f<B>(C())`, we need to
+ // generate the constraint `X <: B`. To do this, we first take the lower
+ // constraint we've accumulated so far (which, in this example, is `C`,
+ // due to the presence of the actual argument `C()`), and use subtype
+ // constraint generation to match it against the explicit bound (which
+ // is `A<X>`; hence we perform `C <# A<X>`). If this produces any
+ // constraints (i.e. `X <: B` in this example), then they are added to
+ // the set of constraints just before choosing the final type.
+
+ TypeStructure typeParameterToInferBound = typeParameterToInfer.bound!;
+
+ // TODO(cstefantsova): Pass [dataForTesting] when
+ // [InferenceDataForTesting] is merged with [TypeInferenceResultForTesting].
+ TypeConstraintGenerator<
+ TypeStructure,
+ SharedNamedFunctionParameterStructure<TypeStructure>,
+ Variable,
+ TypeParameterStructure,
+ TypeDeclarationType,
+ TypeDeclaration,
+ Object> typeConstraintGatherer =
+ createTypeConstraintGenerator(
+ typeConstraintGenerationDataForTesting: null,
+ typeParametersToInfer: typeParametersToInfer,
+ typeAnalyzerOperations: this,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
+ typeConstraintGatherer.performSubtypeConstraintGenerationInternal(
+ lower, typeParameterToInferBound,
+ leftSchema: true, astNodeForTesting: null);
+ Map<
+ TypeParameterStructure,
+ MergedTypeConstraint<
+ TypeStructure,
+ TypeParameterStructure,
+ Variable,
+ TypeDeclarationType,
+ TypeDeclaration>> constraintsPerTypeVariable =
+ typeConstraintGatherer.computeConstraints();
+ for (TypeParameterStructure typeParameter
+ in constraintsPerTypeVariable.keys) {
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable,
+ TypeDeclarationType, TypeDeclaration> constraint =
+ constraintsPerTypeVariable[typeParameter]!;
+ constraint.origin = new TypeConstraintFromExtendsClause(
+ typeParameterName: typeParameterToInfer.displayName,
+ boundType: new SharedTypeView(typeParameterToInferBound),
+ extendsType: new SharedTypeView(typeParameterToInferBound));
+ if (!constraint.isEmpty(this)) {
+ MergedTypeConstraint? constraintForParameter =
+ inferencePhaseConstraints[typeParameter];
+ if (constraintForParameter == null) {
+ inferencePhaseConstraints[typeParameter] = constraint;
+ } else {
+ constraintForParameter.mergeInTypeSchemaUpper(constraint.upper, this);
+ constraintForParameter.mergeInTypeSchemaLower(constraint.lower, this);
+ }
+ }
+ }
+ return constraintsPerTypeVariable[typeParameterToInfer]!;
+ }
}
/// Abstract interface of a type constraint generator.
@@ -1832,6 +1957,12 @@
return false;
}
+
+ /// Returns the set of type constraints that was gathered.
+ Map<
+ TypeParameterStructure,
+ MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable,
+ TypeDeclarationType, TypeDeclaration>> computeConstraints();
}
mixin TypeConstraintGeneratorMixin<
diff --git a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
index 58beeed..7a8a79d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/type_inference/type_constraint.dart
@@ -365,3 +365,41 @@
return <String>[];
}
}
+
+/// Data structure maintaining intermediate type inference results, such as
+/// type constraints, for testing purposes. Under normal execution, no
+/// instance of this class should be created.
+class TypeConstraintGenerationDataForTesting<
+ TypeStructure extends SharedTypeStructure<TypeStructure>,
+ TypeParameterStructure extends SharedTypeParameterStructure<TypeStructure>,
+ Variable extends Object,
+ AstNode extends Object> {
+ /// Map from nodes requiring type inference to the generated type constraints
+ /// for the node.
+ final Map<
+ AstNode,
+ List<
+ GeneratedTypeConstraint<TypeStructure, TypeParameterStructure,
+ Variable>>> generatedTypeConstraints = {};
+
+ /// Merges [other] into the receiver, combining the constraints.
+ ///
+ /// The method reuses data structures from [other] whenever possible, to
+ /// avoid extra memory allocations. This process is destructive to [other]
+ /// because the changes made to the reused structures will be visible to
+ /// [other].
+ void mergeIn(
+ TypeConstraintGenerationDataForTesting<TypeStructure,
+ TypeParameterStructure, Variable, AstNode>
+ other) {
+ for (AstNode node in other.generatedTypeConstraints.keys) {
+ List<GeneratedTypeConstraint>? constraints =
+ generatedTypeConstraints[node];
+ if (constraints != null) {
+ constraints.addAll(other.generatedTypeConstraints[node]!);
+ } else {
+ generatedTypeConstraints[node] = other.generatedTypeConstraints[node]!;
+ }
+ }
+ }
+}
diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
index 264acd1..e9b5c31 100644
--- a/pkg/_fe_analyzer_shared/test/mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -28,11 +28,14 @@
as shared;
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer.dart'
hide MapPatternEntry, RecordPatternField;
+import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart';
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart';
import 'package:_fe_analyzer_shared/src/type_inference/variable_bindings.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:test/test.dart';
+import 'type_inference/type_constraint_gatherer_test.dart';
+
import 'mini_ir.dart';
import 'mini_types.dart';
@@ -3225,6 +3228,21 @@
Type withNullabilitySuffixInternal(Type type, NullabilitySuffix modifier) {
return type.withNullability(modifier);
}
+
+ @override
+ TypeConstraintGenerator<Type, NamedFunctionParameter, Var, TypeParameter,
+ Type, String, Node>
+ createTypeConstraintGenerator(
+ {required TypeConstraintGenerationDataForTesting?
+ typeConstraintGenerationDataForTesting,
+ required List<TypeParameter> typeParametersToInfer,
+ required TypeAnalyzerOperations<Type, Var, TypeParameter, Type,
+ String>
+ typeAnalyzerOperations,
+ required bool inferenceUsingBoundsIsEnabled}) {
+ return TypeConstraintGatherer(
+ {for (var typeParameter in typeParametersToInfer) typeParameter.name});
+ }
}
/// Representation of an expression or statement in the pseudo-Dart language
diff --git a/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart b/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart
index a9ab92d..57d600a 100644
--- a/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart
+++ b/pkg/_fe_analyzer_shared/test/type_inference/type_constraint_gatherer_test.dart
@@ -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/type_inference/type_constraint.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:checks/checks.dart';
import 'package:test/scaffolding.dart';
@@ -25,7 +26,7 @@
group('performSubtypeConstraintGenerationForFunctionTypes:', () {
test('Matching functions with no parameters', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function()'), Type('void Function()'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -35,7 +36,7 @@
group('Matching functions with positional parameters:', () {
test('None optional', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, String)'), Type('void Function(T, U)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -44,7 +45,7 @@
});
test('Some optional on LHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, [String])'),
Type('void Function(T, U)'),
@@ -57,7 +58,7 @@
group('Non-matching functions with positional parameters:', () {
test('Non-matching due to return types', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('int Function(int)'), Type('String Function(int)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -66,7 +67,7 @@
});
test('Non-matching due to parameter types', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int)'), Type('void Function(String)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -75,7 +76,7 @@
});
test('Non-matching due to optional parameters on RHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function()'), Type('void Function([int])'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -84,7 +85,7 @@
});
test('Non-matching due to more parameters being required on LHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int)'), Type('void Function([int])'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -95,7 +96,7 @@
group('Matching functions with named parameters:', () {
test('None optional', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({required int x, required String y})'),
Type('void Function({required T x, required U y})'),
@@ -106,7 +107,7 @@
});
test('Some optional on LHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({required int x, String y})'),
Type('void Function({required T x, required U y})'),
@@ -117,7 +118,7 @@
});
test('Optional named parameter on LHS', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, {String x})'),
Type('void Function(T)'),
@@ -128,7 +129,7 @@
});
test('Extra optional named parameter on LHS', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({String x, int y})'),
Type('void Function({T y})'),
@@ -141,7 +142,7 @@
group('Non-matching functions with named parameters:', () {
test('Non-matching due to return types', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('int Function({int x})'), Type('String Function({int x})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -150,7 +151,7 @@
});
test('Non-matching due to named parameter types', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({int x})'),
Type('void Function({String x})'),
@@ -161,7 +162,7 @@
});
test('Non-matching due to required named parameter on LHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({required int x})'),
Type('void Function()'),
@@ -172,7 +173,7 @@
});
test('Non-matching due to optional named parameter on RHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function()'), Type('void Function({int x})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -182,7 +183,7 @@
test('Non-matching due to named parameter on RHS, with decoys on LHS',
() {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function({int x, int y})'),
Type('void Function({int z})'),
@@ -194,7 +195,7 @@
});
test('Matching functions with named and positional parameters', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, {String y})'),
Type('void Function(T, {U y})'),
@@ -208,7 +209,7 @@
test(
'Non-matching due to LHS not accepting optional positional parameter',
() {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, {String x})'),
Type('void Function(int, [String])'),
@@ -219,7 +220,7 @@
});
test('Non-matching due to positional parameter length mismatch', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('void Function(int, {String x})'),
Type('void Function(int, String)'),
@@ -233,7 +234,7 @@
group('performSubtypeConstraintGenerationForRecordTypes:', () {
test('Matching empty records', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('()'), Type('()'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -243,7 +244,7 @@
group('Matching records:', () {
test('Without named parameters', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('(int, String)'), Type('(T, U)'),
leftSchema: true, astNodeForTesting: Node.placeholder()))
@@ -252,7 +253,7 @@
});
test('With named parameters', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('(int, {String foo})'), Type('(T, {U foo})'),
leftSchema: true, astNodeForTesting: Node.placeholder()))
@@ -263,7 +264,7 @@
group('Non-matching records without named parameters:', () {
test('Non-matching due to positional types', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('(int,)'), Type('(String,)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -272,7 +273,7 @@
});
test('Non-matching due to parameter numbers', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('()'), Type('(int,)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -281,7 +282,7 @@
});
test('Non-matching due to more parameters on LHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForFunctionTypes(
Type('(int,)'), Type('()'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -292,7 +293,7 @@
group('Matching records with named parameters:', () {
test('No type parameter occurrences', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({int x, String y})'), Type('({int x, String y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -301,7 +302,7 @@
});
test('Type parameters in RHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({int x, String y})'), Type('({T x, U y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -310,7 +311,7 @@
});
test('Type parameters in LHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({T x, U y})'), Type('({int x, String y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -321,7 +322,7 @@
group('Matching records with named parameters:', () {
test('No type parameter occurrences', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({int x, String y})'), Type('({int x, String y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -330,7 +331,7 @@
});
test('Type parameters in RHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({int x, String y})'), Type('({T x, U y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -339,7 +340,7 @@
});
test('Type parameters in LHS', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({T x, U y})'), Type('({int x, String y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -350,7 +351,7 @@
group('Non-matching records with named parameters:', () {
test('Non-matching due to positional parameter numbers', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('(num, num, {T x, U y})'),
Type('(num, {int x, String y})'),
@@ -361,7 +362,7 @@
});
test('Non-matching due to named parameter numbers', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('({T x, U y, num z})'), Type('({int x, String y})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -370,7 +371,7 @@
});
test('Non-matching due to named parameter names', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForRecordTypes(
Type('(num, {T x, U y})'), Type('(num, {int x, String x2})'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -383,7 +384,7 @@
group('performSubtypeConstraintGenerationForFutureOr:', () {
test('FutureOr matches FutureOr with constraints based on arguments', () {
// `FutureOr<T> <# FutureOr<int>` reduces to `T <# int`
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<T>'), Type('FutureOr<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -394,7 +395,7 @@
test('FutureOr does not match FutureOr because arguments fail to match',
() {
// `FutureOr<int> <# FutureOr<String>` reduces to `int <# String`
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<int>'), Type('FutureOr<String>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -410,7 +411,7 @@
// producing `Future<int> <: T`
// In cases where both branches produce a constraint, the "Future" branch
// is favored.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('Future<int>'), Type('FutureOr<T>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -426,7 +427,7 @@
// producing `Future<_> <: T`
// In cases where only one branch produces a constraint, that branch is
// favored.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('Future<_>'), Type('FutureOr<T>'),
leftSchema: true, astNodeForTesting: Node.placeholder()))
@@ -442,7 +443,7 @@
// producing `T <: int`
// In cases where both branches produce a constraint, the "Future" branch
// is favored.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('T'), Type('FutureOr<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -451,7 +452,7 @@
});
test('Testing FutureOr as the lower bound of the constraint', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftFutureOr(
Type('FutureOr<T>'), Type('dynamic'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -463,7 +464,7 @@
// `FutureOr<P0> <# Q` if `Future<P0> <# Q` and `P0 <# Q`. This test case
// verifies that if `Future<P0> <# Q` matches but `P0 <# Q` does not, then
// the match fails.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftFutureOr(
Type('FutureOr<(T,)>'), Type('Future<(int,)>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -472,7 +473,7 @@
});
test('Testing nested FutureOr as the lower bound of the constraint', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftFutureOr(
Type('FutureOr<FutureOr<T>>'), Type('FutureOr<dynamic>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -483,7 +484,7 @@
test('Future matches FutureOr with no constraints', () {
// `Future<int> <# FutureOr<int>` matches (taking the "Future" branch of
// the FutureOr) without generating any constraints.
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('Future<int>'), Type('FutureOr<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -495,7 +496,7 @@
// `List<T> <# FutureOr<List<int>>` could only match by taking the
// "non-Future" branch of the FutureOr, so the constraint `T <: int` is
// produced.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('List<T>'), Type('FutureOr<List<int>>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -505,7 +506,7 @@
group('Nullable FutureOr on RHS:', () {
test('Does not match, according to spec', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<T>'), Type('FutureOr<int>?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -514,7 +515,7 @@
});
test('Matches, according to CFE discrepancy', () {
- var tcg = _TypeConstraintGatherer({'T'},
+ var tcg = TypeConstraintGatherer({'T'},
enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true);
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<T>'), Type('FutureOr<int>?'),
@@ -526,7 +527,7 @@
group('Nullable FutureOr on LHS:', () {
test('Does not match, according to spec', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<T>?'), Type('FutureOr<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -535,7 +536,7 @@
});
test('Matches, according to CFE discrepancy', () {
- var tcg = _TypeConstraintGatherer({'T'},
+ var tcg = TypeConstraintGatherer({'T'},
enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr: true);
check(tcg.performSubtypeConstraintGenerationForRightFutureOr(
Type('FutureOr<T>?'), Type('FutureOr<int>'),
@@ -549,7 +550,7 @@
group('performSubtypeConstraintGenerationForLeftNullableType:', () {
test('Nullable matches nullable with constraints based on base types', () {
// `T? <# int?` reduces to `T <# int?`
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftNullableType(
Type('T?'), Type('Null'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -560,7 +561,7 @@
test('Nullable does not match Nullable because base types fail to match',
() {
// `int? <# String?` reduces to `int <# String`
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForLeftNullableType(
Type('int?'), Type('String?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -570,7 +571,7 @@
test('Nullable does not match non-nullable', () {
// `(int, T)? <# (int, String)` does not match
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForLeftNullableType(
Type('(int, T)?'), Type('(int, String)'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -579,7 +580,7 @@
});
test('Both LHS and RHS nullable, matching', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('T?'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -588,7 +589,7 @@
});
test('Both LHS and RHS nullable, not matching', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('(T, int)?'), Type('(int, String)?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -606,7 +607,7 @@
// producing `Null <: T`
// In cases where both branches produce a constraint, the "non-Null"
// branch is favored.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('Null'), Type('T?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -622,7 +623,7 @@
// producing `T <: int`
// In cases where both branches produce a constraint, the "non-Null"
// branch is favored.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('T'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -633,7 +634,7 @@
test('Null matches Nullable with no constraints', () {
// `Null <# int?` matches (taking the "Null" branch of
// the Nullable) without generating any constraints.
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('Null'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -642,7 +643,7 @@
});
test('Dynamic matches Object?', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('dynamic'), Type('Object?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -651,7 +652,7 @@
});
test('void matches Object?', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('void'), Type('Object?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -660,7 +661,7 @@
});
test('LHS not nullable, matches with no constraints', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForRightNullableType(
Type('int'), Type('int?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -672,7 +673,7 @@
group('performSubtypeConstraintGenerationForTypeDeclarationTypes', () {
group('Same base type on both sides:', () {
test('Covariant, matching', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('Map<T, U>'), Type('Map<int, String>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -681,7 +682,7 @@
});
test('Covariant, not matching', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('Map<T, int>'), Type('Map<int, String>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -690,7 +691,7 @@
});
test('Contravariant, matching', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
tcg.typeAnalyzerOperations.addVariance(
'Contravariant', [Variance.contravariant, Variance.contravariant]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -701,7 +702,7 @@
});
test('Contravariant, not matching', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
tcg.typeAnalyzerOperations.addVariance(
'Contravariant', [Variance.contravariant, Variance.contravariant]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -714,7 +715,7 @@
});
test('Invariant, matching', () {
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
tcg.typeAnalyzerOperations
.addVariance('Invariant', [Variance.invariant, Variance.invariant]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -726,7 +727,7 @@
});
test('Invariant, not matching', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
tcg.typeAnalyzerOperations
.addVariance('Invariant', [Variance.invariant, Variance.invariant]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -739,7 +740,7 @@
test('Unrelated, matchable', () {
// When the variance is "unrelated", type inference doesn't even try to
// match up the type parameters; they are always considered to match.
- var tcg = _TypeConstraintGatherer({'T', 'U'});
+ var tcg = TypeConstraintGatherer({'T', 'U'});
tcg.typeAnalyzerOperations
.addVariance('Unrelated', [Variance.unrelated, Variance.unrelated]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -752,7 +753,7 @@
test('Unrelated, not matchable', () {
// When the variance is "unrelated", type inference doesn't even try to
// match up the type parameters; they are always considered to match.
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
tcg.typeAnalyzerOperations
.addVariance('Unrelated', [Variance.unrelated, Variance.unrelated]);
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
@@ -765,7 +766,7 @@
group('Related types on both sides:', () {
test('No change in type args', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('List<T>'), Type('Iterable<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -774,7 +775,7 @@
});
test('Change in type args', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('MyListOfInt'), Type('List<T>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -787,7 +788,7 @@
// performSubtypeConstraintGenerationForTypeDeclarationTypes considers
// it not to match (this is handled by other parts of the subtyping
// algorithm)
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('List<T>?'), Type('Iterable<int>'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -800,7 +801,7 @@
// performSubtypeConstraintGenerationForTypeDeclarationTypes considers
// it not to match (this is handled by other parts of the subtyping
// algorithm)
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('List<T>'), Type('Iterable<int>?'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -810,7 +811,7 @@
});
test('Non-interface type on LHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('void Function()'), Type('int'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -819,7 +820,7 @@
});
test('Non-interface type on RHS', () {
- var tcg = _TypeConstraintGatherer({});
+ var tcg = TypeConstraintGatherer({});
check(tcg.performSubtypeConstraintGenerationForTypeDeclarationTypes(
Type('int'), Type('void Function()'),
leftSchema: false, astNodeForTesting: Node.placeholder()))
@@ -830,7 +831,7 @@
group('matchTypeParameterBoundInternal', () {
test('Non-promoted parameter on LHS', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationInternal(
TypeParameterType(TypeRegistry.addTypeParameter('X')
..explicitBound = Type('Future<String>')),
@@ -842,7 +843,7 @@
});
test('Promoted parameter on LHS', () {
- var tcg = _TypeConstraintGatherer({'T'});
+ var tcg = TypeConstraintGatherer({'T'});
check(tcg.performSubtypeConstraintGenerationInternal(
TypeParameterType(
TypeRegistry.addTypeParameter('X')
@@ -857,7 +858,7 @@
});
}
-class _TypeConstraintGatherer extends TypeConstraintGenerator<Type,
+class TypeConstraintGatherer extends TypeConstraintGenerator<Type,
NamedFunctionParameter, Var, TypeParameter, Type, String, Node>
with
TypeConstraintGeneratorMixin<Type, NamedFunctionParameter, Var,
@@ -873,7 +874,7 @@
final _constraints = <String>[];
- _TypeConstraintGatherer(Set<String> typeVariablesBeingConstrained,
+ TypeConstraintGatherer(Set<String> typeVariablesBeingConstrained,
{this.enableDiscrepantObliviousnessOfNullabilitySuffixOfFutureOr = false})
: super(inferenceUsingBoundsIsEnabled: false) {
for (var typeVariableName in typeVariablesBeingConstrained) {
@@ -949,4 +950,12 @@
// TODO(paulberry): implement instantiateFunctionTypesAndProvideEliminator
throw UnimplementedError();
}
+
+ @override
+ Map<TypeParameter,
+ MergedTypeConstraint<Type, TypeParameter, Var, Type, String>>
+ computeConstraints() {
+ // TODO(cstefantsova): implement computeConstraints
+ throw UnimplementedError();
+ }
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/testing_data.dart b/pkg/analyzer/lib/src/dart/analysis/testing_data.dart
index 706e67d..fb93ab9 100644
--- a/pkg/analyzer/lib/src/dart/analysis/testing_data.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/testing_data.dart
@@ -39,10 +39,14 @@
void recordTypeConstraintGenerationDataForTesting(
Uri uri, TypeConstraintGenerationDataForTesting result) {
TypeConstraintGenerationDataForTesting? existing =
+ // ignore: analyzer_use_new_elements
uriToTypeConstraintGenerationData[uri];
+ // ignore: analyzer_use_new_elements
if (existing != null) {
+ // ignore: analyzer_use_new_elements
existing.mergeIn(result);
} else {
+ // ignore: analyzer_use_new_elements
uriToTypeConstraintGenerationData[uri] = result;
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index d97a017..aa57418 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -6,20 +6,12 @@
import 'package:_fe_analyzer_shared/src/type_inference/shared_inference_log.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
-import 'package:analyzer/dart/ast/ast.dart'
- show
- Annotation,
- AsExpression,
- AstNode,
- ConstructorName,
- Expression,
- InvocationExpression,
- SimpleIdentifier;
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart' show ErrorReporter;
+import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -154,7 +146,7 @@
/// type is a subtype of the [parameterType].
void constrainArgument(
DartType argumentType, DartType parameterType, String parameterName,
- {InterfaceElement? genericClass, required AstNode? nodeForTesting}) {
+ {InterfaceElement? genericClass, required AstNodeImpl? nodeForTesting}) {
var origin = TypeConstraintFromArgument(
argumentType: SharedTypeView(argumentType),
parameterType: SharedTypeView(parameterType),
@@ -175,7 +167,7 @@
{InterfaceElement? genericClass,
required List<ParameterElement> parameters,
required List<DartType> argumentTypes,
- required AstNode? nodeForTesting}) {
+ required AstNodeImpl? nodeForTesting}) {
for (int i = 0; i < argumentTypes.length; i++) {
// Try to pass each argument to each parameter, recording any type
// parameter bounds that were implied by this assignment.
@@ -193,7 +185,7 @@
/// [contextType].
void constrainGenericFunctionInContext(
FunctionType fnType, DartType contextType,
- {required AstNode? nodeForTesting}) {
+ {required AstNodeImpl? nodeForTesting}) {
var origin = TypeConstraintFromFunctionContext(
functionType: fnType, contextType: contextType);
@@ -217,7 +209,7 @@
/// Apply a return type constraint, which asserts that the [declaredType]
/// is a subtype of the [contextType].
void constrainReturnType(DartType declaredType, DartType contextType,
- {required AstNode? nodeForTesting}) {
+ {required AstNodeImpl? nodeForTesting}) {
var origin = TypeConstraintFromReturnType(
declaredType: declaredType, contextType: contextType);
inferenceLogWriter?.enterConstraintGeneration(
@@ -426,13 +418,10 @@
/// If [isContravariant] is `true`, then we are solving for a contravariant
/// type parameter which means we choose the upper bound rather than the
/// lower bound for normally covariant type parameters.
- DartType _chooseTypeFromConstraints(
- Iterable<MergedTypeConstraint> constraints,
- {bool toKnownType = false,
- required bool isContravariant}) {
- var (:lower, :upper) =
- _computeLowerAndUpperBoundsOfConstraints(constraints);
-
+ DartType _chooseTypeFromConstraint(MergedTypeConstraint constraint,
+ {bool toKnownType = false, required bool isContravariant}) {
+ DartType upper = constraint.upper.unwrapTypeSchemaView();
+ DartType lower = constraint.lower.unwrapTypeSchemaView();
// Prefer the known bound, if any.
// Otherwise take whatever bound has partial information, e.g. `Iterable<?>`
//
@@ -476,7 +465,7 @@
_typeFormals.length, UnknownInferredType.instance);
var inferencePhaseConstraints = {
for (var typeParameter in _constraints.keys)
- typeParameter: [...?_constraints[typeParameter]]
+ typeParameter: _squashConstraints(_constraints[typeParameter]!)
};
for (int i = 0; i < _typeFormals.length; i++) {
// TODO(kallentu): : Clean up TypeParameterElementImpl casting once
@@ -495,24 +484,24 @@
);
}
- var constraints = inferencePhaseConstraints[typeParam]!;
+ var constraint = inferencePhaseConstraints[typeParam]!;
var previouslyInferredType = _typesInferredSoFar[typeParam];
if (previouslyInferredType != null) {
inferredTypes[i] = previouslyInferredType;
} else if (preliminary) {
var inferredType = _inferTypeParameterFromContext(
- constraints, extendsClause,
+ constraint, extendsClause,
isContravariant: typeParam.variance.isContravariant,
typeParameterToInfer: typeParam,
inferencePhaseConstraints: inferencePhaseConstraints);
+
inferredTypes[i] = inferredType;
if (typeParam.isLegacyCovariant &&
UnknownInferredType.isKnown(inferredType)) {
_typesInferredSoFar[typeParam] = inferredType;
}
} else {
- inferredTypes[i] = _inferTypeParameterFromAll(
- constraints, extendsClause,
+ inferredTypes[i] = _inferTypeParameterFromAll(constraint, extendsClause,
isContravariant: typeParam.variance.isContravariant,
typeParameterToInfer: typeParam,
inferencePhaseConstraints: inferencePhaseConstraints);
@@ -522,32 +511,6 @@
return inferredTypes;
}
- ({DartType lower, DartType upper}) _computeLowerAndUpperBoundsOfConstraints(
- Iterable<MergedTypeConstraint> constraints) {
- DartType lower = UnknownInferredType.instance;
- DartType upper = UnknownInferredType.instance;
- for (var constraint in constraints) {
- // Given constraints:
- //
- // L1 <: T <: U1
- // L2 <: T <: U2
- //
- // These can be combined to produce:
- //
- // LUB(L1, L2) <: T <: GLB(U1, U2).
- //
- // This can then be done for all constraints in sequence.
- //
- // This resulting constraint may be unsatisfiable; in that case inference
- // will fail.
- upper = _typeSystem.greatestLowerBound(
- upper, constraint.upper.unwrapTypeSchemaView());
- lower = _typeSystem.leastUpperBound(
- lower, constraint.lower.unwrapTypeSchemaView());
- }
- return (lower: lower, upper: upper);
- }
-
void _demoteTypes(List<DartType> types) {
for (var i = 0; i < types.length; i++) {
types[i] = _typeSystem.demoteType(types[i]);
@@ -593,52 +556,52 @@
'Consider passing explicit type argument(s) to the generic.\n\n';
}
- DartType _inferTypeParameterFromAll(List<MergedTypeConstraint> constraints,
- MergedTypeConstraint? extendsClause,
+ DartType _inferTypeParameterFromAll(
+ MergedTypeConstraint constraint, MergedTypeConstraint? extendsClause,
{required bool isContravariant,
required TypeParameterElementImpl2 typeParameterToInfer,
- required Map<TypeParameterElementImpl2, List<MergedTypeConstraint>>
+ required Map<TypeParameterElementImpl2, MergedTypeConstraint>
inferencePhaseConstraints}) {
if (extendsClause != null) {
- var (:lower, upper: _) =
- _computeLowerAndUpperBoundsOfConstraints(constraints);
-
MergedTypeConstraint? boundConstraint;
if (inferenceUsingBoundsIsEnabled) {
- if (!identical(lower, UnknownInferredType.instance)) {
- boundConstraint = _mergeInConstraintsFromBound(
+ if (!identical(constraint.lower.unwrapTypeSchemaView(),
+ UnknownInferredType.instance)) {
+ boundConstraint = _typeSystemOperations.mergeInConstraintsFromBound(
typeParameterToInfer: typeParameterToInfer,
- lower: lower,
- inferencePhaseConstraints: inferencePhaseConstraints);
+ typeParametersToInfer: _typeFormals,
+ lower: constraint.lower.unwrapTypeSchemaView(),
+ inferencePhaseConstraints: inferencePhaseConstraints,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
}
}
- constraints = [
- ...constraints,
+ constraint = _squashConstraints([
+ constraint,
extendsClause,
if (boundConstraint != null &&
!boundConstraint.isEmpty(_typeSystemOperations))
boundConstraint
- ];
+ ]);
}
- var choice = _chooseTypeFromConstraints(constraints,
+ var choice = _chooseTypeFromConstraint(constraint,
toKnownType: true, isContravariant: isContravariant);
return choice;
}
DartType _inferTypeParameterFromContext(
- Iterable<MergedTypeConstraint> constraints,
- MergedTypeConstraint? extendsClause,
+ MergedTypeConstraint constraint, MergedTypeConstraint? extendsClause,
{required bool isContravariant,
required TypeParameterElementImpl2 typeParameterToInfer,
- required Map<TypeParameterElementImpl2, List<MergedTypeConstraint>>
+ required Map<TypeParameterElementImpl2, MergedTypeConstraint>
inferencePhaseConstraints}) {
// Both bits of the bound information should be available at the same time.
assert(extendsClause == null || typeParameterToInfer.bound != null);
- DartType t = _chooseTypeFromConstraints(constraints,
- isContravariant: isContravariant);
+ DartType t =
+ _chooseTypeFromConstraint(constraint, isContravariant: isContravariant);
if (UnknownInferredType.isUnknown(t)) {
return t;
}
@@ -651,83 +614,33 @@
//
// If we consider the `T extends num` we conclude `<num>`, which works.
if (extendsClause != null) {
- var (:lower, upper: _) =
- _computeLowerAndUpperBoundsOfConstraints(constraints);
-
MergedTypeConstraint? boundConstraint;
if (inferenceUsingBoundsIsEnabled) {
- if (!identical(lower, UnknownInferredType.instance)) {
- boundConstraint = _mergeInConstraintsFromBound(
+ if (!identical(constraint.lower.unwrapTypeSchemaView(),
+ UnknownInferredType.instance)) {
+ boundConstraint = _typeSystemOperations.mergeInConstraintsFromBound(
typeParameterToInfer: typeParameterToInfer,
- lower: lower,
- inferencePhaseConstraints: inferencePhaseConstraints);
+ typeParametersToInfer: _typeFormals,
+ lower: constraint.lower.unwrapTypeSchemaView(),
+ inferencePhaseConstraints: inferencePhaseConstraints,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
}
}
- constraints = [
- ...constraints,
+ constraint = _squashConstraints([
+ constraint,
extendsClause,
if (boundConstraint != null &&
!boundConstraint.isEmpty(_typeSystemOperations))
boundConstraint
- ];
- return _chooseTypeFromConstraints(constraints,
+ ]);
+ return _chooseTypeFromConstraint(constraint,
isContravariant: isContravariant);
}
return t;
}
- MergedTypeConstraint _mergeInConstraintsFromBound(
- {required TypeParameterElementImpl2 typeParameterToInfer,
- required DartType lower,
- required Map<TypeParameterElementImpl2, List<MergedTypeConstraint>>
- inferencePhaseConstraints}) {
- // The type parameter's bound may refer to itself (or other type
- // parameters), so we might have to create an additional constraint.
- // Consider this example from
- // https://github.com/dart-lang/language/issues/3009:
- //
- // class A<X extends A<X>> {}
- // class B extends A<B> {}
- // class C extends B {}
- // void f<X extends A<X>>(X x) {}
- // void main() {
- // f(C()); // should infer f<B>(C()).
- // }
- //
- // In order for `f(C())` to be inferred as `f<B>(C())`, we need to
- // generate the constraint `X <: B`. To do this, we first take the lower
- // constraint we've accumulated so far (which, in this example, is `C`,
- // due to the presence of the actual argument `C()`), and use subtype
- // constraint generation to match it against the explicit bound (which
- // is `A<X>`; hence we perform `C <# A<X>`). If this produces any
- // constraints (i.e. `X <: B` in this example), then they are added to
- // the set of constraints just before choosing the final type.
-
- DartType typeParameterToInferBound = typeParameterToInfer.bound!;
- TypeConstraintGatherer typeConstraintGatherer = TypeConstraintGatherer(
- typeSystemOperations: _typeSystemOperations,
- typeParameters: _typeFormals,
- inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
- dataForTesting: null);
- typeConstraintGatherer.performSubtypeConstraintGenerationInternal(
- lower, typeParameterToInferBound,
- leftSchema: true, astNodeForTesting: null);
- var constraintsPerTypeVariable =
- typeConstraintGatherer.computeConstraints();
- for (var typeParameter in constraintsPerTypeVariable.keys) {
- var constraint = constraintsPerTypeVariable[typeParameter]!;
- constraint.origin = TypeConstraintFromExtendsClause(
- typeParameterName: typeParameterToInfer.name3,
- boundType: SharedTypeView(typeParameterToInferBound),
- extendsType: SharedTypeView(typeParameterToInferBound));
- if (!constraint.isEmpty(_typeSystemOperations)) {
- (inferencePhaseConstraints[typeParameter] ??= []).add(constraint);
- }
- }
- return constraintsPerTypeVariable[typeParameterToInfer]!;
- }
-
/// Reports an inference failure on [errorEntity] according to its type.
void _reportInferenceFailure({
ErrorReporter? errorReporter,
@@ -809,13 +722,44 @@
}
}
+ MergedTypeConstraint _squashConstraints(
+ Iterable<MergedTypeConstraint> constraints) {
+ DartType lower = UnknownInferredType.instance;
+ DartType upper = UnknownInferredType.instance;
+ TypeConstraintOrigin origin = UnknownTypeConstraintOrigin();
+
+ for (var constraint in constraints) {
+ // Given constraints:
+ //
+ // L1 <: T <: U1
+ // L2 <: T <: U2
+ //
+ // These can be combined to produce:
+ //
+ // LUB(L1, L2) <: T <: GLB(U1, U2).
+ //
+ // This can then be done for all constraints in sequence.
+ //
+ // This resulting constraint may be unsatisfiable; in that case inference
+ // will fail.
+ upper = _typeSystem.greatestLowerBound(
+ upper, constraint.upper.unwrapTypeSchemaView());
+ lower = _typeSystem.leastUpperBound(
+ lower, constraint.lower.unwrapTypeSchemaView());
+ }
+ return MergedTypeConstraint(
+ lower: SharedTypeSchemaView(lower),
+ upper: SharedTypeSchemaView(upper),
+ origin: origin);
+ }
+
/// Tries to make [t1] a subtype of [t2] and accumulate constraints as needed.
///
/// The return value indicates whether the match was successful. If it was
/// unsuccessful, any constraints that were accumulated during the match
/// attempt have been rewound.
bool _tryMatchSubtypeOf(DartType t1, DartType t2, TypeConstraintOrigin origin,
- {required bool covariant, required AstNode? nodeForTesting}) {
+ {required bool covariant, required AstNodeImpl? nodeForTesting}) {
var gatherer = TypeConstraintGatherer(
typeParameters: _typeParameters,
typeSystemOperations: _typeSystemOperations,
diff --git a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
index 2d4829e..7dc445d 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -13,6 +13,7 @@
show
GeneratedTypeConstraint,
MergedTypeConstraint,
+ TypeConstraintGenerationDataForTesting,
TypeConstraintFromArgument,
TypeConstraintFromExtendsClause,
TypeConstraintFromFunctionContext,
@@ -74,6 +75,10 @@
InterfaceTypeImpl,
InterfaceElementImpl2>;
+typedef TypeConstraintGenerationDataForTesting
+ = shared.TypeConstraintGenerationDataForTesting<DartType,
+ TypeParameterElementImpl2, PromotableElementImpl2, AstNodeImpl>;
+
/// Instance of [shared.TypeConstraintOrigin] specific to the Analyzer.
typedef TypeConstraintOrigin = shared.TypeConstraintOrigin<
DartType,
@@ -99,7 +104,7 @@
TypeParameterElementImpl2,
InterfaceTypeImpl,
InterfaceElementImpl2,
- AstNode>
+ AstNodeImpl>
with
shared.TypeConstraintGeneratorMixin<
DartType,
@@ -108,7 +113,7 @@
TypeParameterElementImpl2,
InterfaceTypeImpl,
InterfaceElementImpl2,
- AstNode> {
+ AstNodeImpl> {
@override
final Set<TypeParameterElementImpl2> typeParametersToConstrain =
Set.identity();
@@ -142,7 +147,7 @@
@override
void addLowerConstraintForParameter(
TypeParameterElementImpl2 element, DartType lower,
- {required AstNode? astNodeForTesting}) {
+ {required AstNodeImpl? astNodeForTesting}) {
GeneratedTypeConstraint generatedTypeConstraint =
GeneratedTypeConstraint.lower(element, SharedTypeSchemaView(lower));
_constraints.add(generatedTypeConstraint);
@@ -155,7 +160,7 @@
@override
void addUpperConstraintForParameter(
TypeParameterElementImpl2 element, DartType upper,
- {required AstNode? astNodeForTesting}) {
+ {required AstNodeImpl? astNodeForTesting}) {
GeneratedTypeConstraint generatedTypeConstraint =
GeneratedTypeConstraint.upper(element, SharedTypeSchemaView(upper));
_constraints.add(generatedTypeConstraint);
@@ -165,7 +170,7 @@
}
}
- /// Returns the set of type constraints that was gathered.
+ @override
Map<TypeParameterElementImpl2, MergedTypeConstraint> computeConstraints() {
var result = <TypeParameterElementImpl2, MergedTypeConstraint>{};
for (var parameter in typeParametersToConstrain) {
@@ -190,7 +195,7 @@
void eliminateTypeParametersInGeneratedConstraints(
covariant List<TypeParameterElementImpl2> eliminator,
shared.TypeConstraintGeneratorState eliminationStartState,
- {required AstNode? astNodeForTesting}) {
+ {required AstNodeImpl? astNodeForTesting}) {
var constraints = _constraints.sublist(eliminationStartState.count);
_constraints.length = eliminationStartState.count;
for (var constraint in constraints) {
@@ -269,31 +274,3 @@
_constraints.length = state.count;
}
}
-
-/// Data structure maintaining intermediate type inference results, such as
-/// type constraints, for testing purposes. Under normal execution, no
-/// instance of this class should be created.
-class TypeConstraintGenerationDataForTesting {
- /// Map from nodes requiring type inference to the generated type constraints
- /// for the node.
- final Map<AstNode, List<GeneratedTypeConstraint>> generatedTypeConstraints =
- {};
-
- /// Merges [other] into the receiver, combining the constraints.
- ///
- /// The method reuses data structures from [other] whenever possible, to
- /// avoid extra memory allocations. This process is destructive to [other]
- /// because the changes made to the reused structures will be visible to
- /// [other].
- void mergeIn(TypeConstraintGenerationDataForTesting other) {
- for (AstNode node in other.generatedTypeConstraints.keys) {
- List<GeneratedTypeConstraint>? constraints =
- generatedTypeConstraints[node];
- if (constraints != null) {
- constraints.addAll(other.generatedTypeConstraints[node]!);
- } else {
- generatedTypeConstraints[node] = other.generatedTypeConstraints[node]!;
- }
- }
- }
-}
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index fa47fa8..0bd6189 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/error/listener.dart' show ErrorReporter;
+import 'package:analyzer/src/dart/ast/ast.dart' show AstNodeImpl;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/generic_inferrer.dart';
@@ -644,7 +645,7 @@
required bool strictInference,
required bool strictCasts,
required TypeConstraintGenerationDataForTesting? dataForTesting,
- required AstNode? nodeForTesting,
+ required AstNodeImpl? nodeForTesting,
}) {
if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) {
return const <DartType>[];
@@ -1687,7 +1688,7 @@
required bool strictCasts,
required TypeSystemOperations typeSystemOperations,
required TypeConstraintGenerationDataForTesting? dataForTesting,
- required AstNode? nodeForTesting,
+ required AstNodeImpl? nodeForTesting,
}) {
// Create a GenericInferrer that will allow certain type parameters to be
// inferred. It will optimistically assume these type parameters can be
diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index f1e34f7..06a31d0 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -337,7 +337,7 @@
List<DartType>? _inferTypeArguments(
ExtensionOverride node, DartType receiverType,
{required TypeConstraintGenerationDataForTesting? dataForTesting,
- required AstNode? nodeForTesting}) {
+ required AstNodeImpl? nodeForTesting}) {
var element = node.element2;
var typeParameters = element.typeParameters2;
var typeArguments = node.typeArguments;
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index b116388..8a09f40 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -22,6 +22,7 @@
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl;
import 'package:analyzer/src/generated/inference_log.dart';
@@ -166,7 +167,8 @@
/// the top level declaration. This is used to compute assigned variables
/// information within the body or initializer. If `null`, the entire [node]
/// will be visited.
- void bodyOrInitializer_enter(AstNode node, FormalParameterList? parameters,
+ void bodyOrInitializer_enter(
+ AstNodeImpl node, FormalParameterList? parameters,
{void Function(AstVisitor<Object?> visitor)? visit}) {
inferenceLogWriter?.enterBodyOrInitializer(node);
assert(flow == null);
@@ -349,7 +351,8 @@
/// Computes the [AssignedVariables] map for the given [node].
static AssignedVariables<AstNodeImpl, PromotableElementImpl2>
- computeAssignedVariables(AstNode node, FormalParameterList? parameters,
+ computeAssignedVariables(
+ AstNodeImpl node, FormalParameterList? parameters,
{bool retainDataForTesting = false,
void Function(AstVisitor<Object?> visitor)? visit}) {
AssignedVariables<AstNodeImpl, PromotableElementImpl2> assignedVariables =
@@ -508,6 +511,28 @@
}
@override
+ TypeConstraintGenerator<
+ DartType,
+ FormalParameterElementOrMember,
+ PromotableElementImpl2,
+ TypeParameterElementImpl2,
+ InterfaceTypeImpl,
+ InterfaceElementImpl2,
+ AstNodeImpl>
+ createTypeConstraintGenerator(
+ {required covariant TypeConstraintGenerationDataForTesting?
+ typeConstraintGenerationDataForTesting,
+ required List<TypeParameterElementImpl2> typeParametersToInfer,
+ required covariant TypeSystemOperations typeAnalyzerOperations,
+ required bool inferenceUsingBoundsIsEnabled}) {
+ return TypeConstraintGatherer(
+ typeParameters: typeParametersToInfer,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
+ typeSystemOperations: typeAnalyzerOperations,
+ dataForTesting: typeConstraintGenerationDataForTesting);
+ }
+
+ @override
SharedTypeView<DartType> extensionTypeErasure(SharedTypeView<DartType> type) {
return SharedTypeView(type.unwrapTypeView().extensionTypeErasure);
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 25d8a7c..3497b07 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -120,8 +120,8 @@
/// Given an uninstantiated generic function type, referenced by the
/// [identifier] in the tear-off [expression], try to infer the instantiated
/// generic function type from the surrounding context.
- DartType inferTearOff(Expression expression, SimpleIdentifierImpl identifier,
- DartType tearOffType,
+ DartType inferTearOff(ExpressionImpl expression,
+ SimpleIdentifierImpl identifier, DartType tearOffType,
{required DartType contextType}) {
if (contextType is FunctionType && tearOffType is FunctionType) {
var typeArguments = _typeSystem.inferFunctionTypeInstantiation(
diff --git a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
index 1a5b52f..45feb8b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
@@ -171,7 +171,7 @@
/// [enclosingClass].
InterfaceType _inferRedirectedConstructor(InterfaceElement element,
{required TypeConstraintGenerationDataForTesting? dataForTesting,
- required AstNode? nodeForTesting}) {
+ required AstNodeImpl? nodeForTesting}) {
if (element == enclosingClass) {
return element.thisType;
} else {
@@ -200,7 +200,7 @@
}
}
- DartType _instantiateElement(NamedType node, Element element,
+ DartType _instantiateElement(NamedTypeImpl node, Element element,
{required TypeConstraintGenerationDataForTesting? dataForTesting}) {
var nullability = _getNullability(node);
diff --git a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
index a7a1f545..71cc13e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
@@ -425,7 +425,7 @@
}
}
- GenericInferrer _inferListTypeDownwards(ListLiteral node,
+ GenericInferrer _inferListTypeDownwards(ListLiteralImpl node,
{required DartType contextType}) {
var element = _typeProvider.listElement2;
var typeParameters = element.typeParameters2;
@@ -493,7 +493,7 @@
}
GenericInferrer _inferMapTypeDownwards(
- SetOrMapLiteral node, DartType contextType) {
+ SetOrMapLiteralImpl node, DartType contextType) {
var element = _typeProvider.mapElement2;
inferenceLogWriter?.enterGenericInference(
// TODO(paulberry): make this cast unnecessary by changing
@@ -601,7 +601,7 @@
}
GenericInferrer _inferSetTypeDownwards(
- SetOrMapLiteral node, DartType contextType) {
+ SetOrMapLiteralImpl node, DartType contextType) {
var element = _typeProvider.setElement2;
inferenceLogWriter?.enterGenericInference(
// TODO(paulberry): make this cast unnecessary by changing
@@ -737,7 +737,7 @@
DartType _toMapType(
GenericInferrer? inferrer,
_LiteralResolution literalResolution,
- SetOrMapLiteral node,
+ SetOrMapLiteralImpl node,
List<_InferredCollectionElementTypeInformation> inferredTypes) {
inferenceLogWriter?.assertGenericInferenceState(
inProgress: inferrer != null);
@@ -787,7 +787,7 @@
DartType _toSetType(
GenericInferrer? inferrer,
_LiteralResolution literalResolution,
- SetOrMapLiteral node,
+ SetOrMapLiteralImpl node,
List<_InferredCollectionElementTypeInformation> inferredTypes) {
inferenceLogWriter?.assertGenericInferenceState(
inProgress: inferrer != null);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d167b5d..5532133 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2763,7 +2763,7 @@
}
@override
- void visitFormalParameterList(FormalParameterList node) {
+ void visitFormalParameterList(covariant FormalParameterListImpl node) {
// Formal parameter lists can contain default values, which in turn contain
// expressions, so we need flow analysis to be available to process those
// expressions.
@@ -4059,7 +4059,7 @@
required AstNode errorNode,
required DartType declaredType,
required DartType contextType,
- required AstNode? nodeForTesting,
+ required AstNodeImpl? nodeForTesting,
}) {
inferenceLogWriter?.enterGenericInference(typeParameters, declaredType);
var inferrer = GenericInferrer(
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index dcdf5fe..c66daf5 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
@@ -107,7 +107,7 @@
node = getNode();
node.accept(_scopeResolverVisitor);
_prepareEnclosingDeclarations();
- _flowAnalysis.bodyOrInitializer_enter(node.parent!, null);
+ _flowAnalysis.bodyOrInitializer_enter(node.parent as AstNodeImpl, null);
_resolverVisitor.analyzeExpression(node, SharedTypeSchemaView(contextType));
_resolverVisitor.popRewrite();
_resolverVisitor.checkIdle();
diff --git a/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
index 26b4b0f..a809b1c 100644
--- a/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/type_inference/type_constraint_gatherer.dart
@@ -186,7 +186,7 @@
return _environment.getTypeArgumentsAsInstanceOf(type, typeDeclaration);
}
- /// Returns the set of type constraints that was gathered.
+ @override
Map<StructuralParameter, MergedTypeConstraint> computeConstraints() {
Map<StructuralParameter, MergedTypeConstraint> result = {};
for (StructuralParameter parameter in typeParametersToConstrain) {
diff --git a/pkg/front_end/lib/src/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
index 5149be2..872f68d 100644
--- a/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/type_inference/type_inference_engine.dart
@@ -7,6 +7,8 @@
import 'package:_fe_analyzer_shared/src/type_inference/nullability_suffix.dart';
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
hide Variance;
+import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart'
+ as shared;
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart'
@@ -28,11 +30,11 @@
import '../source/source_library_builder.dart'
show FieldNonPromotabilityInfo, SourceLibraryBuilder;
import 'factor_type.dart';
+import 'type_constraint_gatherer.dart';
import 'type_inferrer.dart';
import 'type_schema.dart';
import 'type_schema_elimination.dart' as type_schema_elimination;
-import 'type_schema_environment.dart'
- show GeneratedTypeConstraint, TypeSchemaEnvironment;
+import 'type_schema_environment.dart' show TypeSchemaEnvironment;
/// Visitor to check whether a given type mentions any of a class's type
/// parameters in a non-covariant fashion.
@@ -392,7 +394,10 @@
}
}
-class InferenceDataForTesting {
+// TODO(cstefantsova): Merge with [TypeInferenceResultForTesting].
+class InferenceDataForTesting
+ extends shared.TypeConstraintGenerationDataForTesting<DartType,
+ StructuralParameter, VariableDeclaration, TreeNode> {
final FlowAnalysisResult flowAnalysisResult = new FlowAnalysisResult();
final TypeInferenceResultForTesting typeInferenceResult =
@@ -1010,12 +1015,31 @@
bool isNullableInternal(DartType type) {
return type.nullability == Nullability.nullable;
}
+
+ @override
+ TypeConstraintGenerator<DartType, NamedType, VariableDeclaration,
+ StructuralParameter, TypeDeclarationType, TypeDeclaration, TreeNode>
+ createTypeConstraintGenerator(
+ {required covariant TypeInferenceResultForTesting?
+ typeConstraintGenerationDataForTesting,
+ required List<StructuralParameter> typeParametersToInfer,
+ required covariant OperationsCfe typeAnalyzerOperations,
+ required bool inferenceUsingBoundsIsEnabled}) {
+ // TODO(cstefantsova): Pass [typeConstraintGenerationDataForTesting] when
+ // [InferenceDataForTesting] is merged with [TypeInferenceResultForTesting].
+ return new TypeConstraintGatherer(
+ typeAnalyzerOperations.typeEnvironment as TypeSchemaEnvironment,
+ typeParametersToInfer,
+ typeOperations: typeAnalyzerOperations,
+ inferenceResultForTesting: null,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
+ }
}
/// Type inference results used for testing.
-class TypeInferenceResultForTesting {
+class TypeInferenceResultForTesting
+ extends shared.TypeConstraintGenerationDataForTesting<DartType,
+ StructuralParameter, VariableDeclaration, TreeNode> {
final Map<TreeNode, List<DartType>> inferredTypeArguments = {};
- final Map<TreeNode, List<GeneratedTypeConstraint>> generatedTypeConstraints =
- {};
final Map<TreeNode, DartType> inferredVariableTypes = {};
}
diff --git a/pkg/front_end/lib/src/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
index 94d5bf1..ad068325 100644
--- a/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/type_inference/type_schema_environment.dart
@@ -187,6 +187,7 @@
List<DartType>? previouslyInferredTypes,
{bool preliminary = false,
required OperationsCfe operations,
+ required InferenceDataForTesting? dataForTesting,
required bool inferenceUsingBoundsIsEnabled}) {
List<DartType> inferredTypes =
previouslyInferredTypes?.toList(growable: false) ??
@@ -197,53 +198,10 @@
DartType typeParamBound = typeParam.bound;
DartType? extendsConstraint;
- Map<StructuralParameter, MergedTypeConstraint>? constraintsFromBound;
if (!hasOmittedBound(typeParam)) {
extendsConstraint = new FunctionTypeInstantiator.fromIterables(
typeParametersToInfer, inferredTypes)
.substitute(typeParamBound);
-
- MergedTypeConstraint? mergedTypeConstraint = constraints[typeParam];
- if (inferenceUsingBoundsIsEnabled) {
- // The type parameter's bound may refer to itself (or other type
- // parameters), so we might have to create an additional constraint.
- // Consider this example from
- // https://github.com/dart-lang/language/issues/3009:
- //
- // class A<X extends A<X>> {}
- // class B extends A<B> {}
- // class C extends B {}
- // void f<X extends A<X>>(X x) {}
- // void main() {
- // f(C()); // should infer f<B>(C()).
- // }
- //
- // In order for `f(C())` to be inferred as `f<B>(C())`, we need to
- // generate the constraint `X <: B`. To do this, we first take the
- // lower constraint we've accumulated so far (which, in this example,
- // is `C`, due to the presence of the actual argument `C()`), and use
- // subtype constraint generation to match it against the explicit
- // bound (which is `A<X>`; hence we perform `C <# A<X>`). If this
- // produces any constraints (i.e. `X <: B` in this example), then they
- // are added to the set of constraints just before choosing the final
- // type.
-
- if (mergedTypeConstraint != null &&
- mergedTypeConstraint.lower
- is! SharedUnknownTypeSchemaView<DartType>) {
- TypeConstraintGatherer extendsConstraintGatherer =
- new TypeConstraintGatherer(this, typeParametersToInfer,
- typeOperations: operations,
- inferenceUsingBoundsIsEnabled:
- inferenceUsingBoundsIsEnabled,
- inferenceResultForTesting: null);
- extendsConstraintGatherer.tryConstrainLower(typeParamBound,
- mergedTypeConstraint.lower.unwrapTypeSchemaView(),
- treeNodeForTesting: null);
- constraintsFromBound =
- extendsConstraintGatherer.computeConstraints();
- }
- }
}
MergedTypeConstraint constraint = constraints[typeParam]!;
@@ -252,10 +210,11 @@
previouslyInferredTypes?[i], constraint, extendsConstraint,
isLegacyCovariant: typeParam.isLegacyCovariant,
operations: operations,
- constraintsFromBound: constraintsFromBound,
constraints: constraints,
typeParameterToInfer: typeParam,
- typeParametersToInfer: typeParametersToInfer);
+ typeParametersToInfer: typeParametersToInfer,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
} else {
inferredTypes[i] = _inferTypeParameterFromAll(
previouslyInferredTypes?[i], constraint, extendsConstraint,
@@ -263,10 +222,11 @@
typeParam.variance == shared.Variance.contravariant,
isLegacyCovariant: typeParam.isLegacyCovariant,
operations: operations,
- constraintsFromBound: constraintsFromBound,
constraints: constraints,
typeParameterToInfer: typeParam,
- typeParametersToInfer: typeParametersToInfer);
+ typeParametersToInfer: typeParametersToInfer,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
}
}
@@ -490,6 +450,7 @@
previouslyInferredTypes,
preliminary: preliminary,
operations: gatherer.typeOperations,
+ dataForTesting: dataForTesting,
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
for (int i = 0; i < inferredTypes.length; i++) {
@@ -503,11 +464,11 @@
{bool isContravariant = false,
bool isLegacyCovariant = true,
required OperationsCfe operations,
- required Map<StructuralParameter, MergedTypeConstraint>?
- constraintsFromBound,
required Map<StructuralParameter, MergedTypeConstraint> constraints,
required StructuralParameter typeParameterToInfer,
- required List<StructuralParameter> typeParametersToInfer}) {
+ required List<StructuralParameter> typeParametersToInfer,
+ required InferenceDataForTesting? dataForTesting,
+ required bool inferenceUsingBoundsIsEnabled}) {
// See if we already fixed this type in a previous inference step.
// If so, then we aren't allowed to change it unless [isLegacyCovariant] is
// false.
@@ -517,13 +478,21 @@
return typeFromPreviousInference;
}
- if (constraintsFromBound != null) {
- _mergeInConstraintsFromBound(
- constraints: constraints,
- constraintsFromBound: constraintsFromBound,
- typeParametersToInfer: typeParametersToInfer,
- operations: operations);
- constraint = constraints[typeParameterToInfer]!;
+ if (inferenceUsingBoundsIsEnabled &&
+ constraint.lower is! SharedUnknownTypeSchemaView<DartType> &&
+ !hasOmittedBound(typeParameterToInfer)) {
+ // Coverage-ignore-block(suite): Not run.
+ MergedTypeConstraint constraintFromBound =
+ operations.mergeInConstraintsFromBound(
+ typeParameterToInfer: typeParameterToInfer,
+ typeParametersToInfer: typeParametersToInfer,
+ lower: constraint.lower.unwrapTypeSchemaView(),
+ inferencePhaseConstraints: constraints,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
+
+ constraint.mergeInTypeSchemaUpper(constraintFromBound.upper, operations);
+ constraint.mergeInTypeSchemaLower(constraintFromBound.lower, operations);
}
if (extendsConstraint != null) {
@@ -538,33 +507,15 @@
isContravariant: isContravariant);
}
- void _mergeInConstraintsFromBound(
- {required Map<StructuralParameter, MergedTypeConstraint>
- constraintsFromBound,
- required List<StructuralParameter> typeParametersToInfer,
- required Map<StructuralParameter, MergedTypeConstraint> constraints,
- required OperationsCfe operations}) {
- for (StructuralParameter typeParamToUpdate in typeParametersToInfer) {
- MergedTypeConstraint? constraintFromBoundForTypeParam =
- constraintsFromBound[typeParamToUpdate];
- if (constraintFromBoundForTypeParam != null) {
- constraints[typeParamToUpdate]?.mergeInTypeSchemaUpper(
- constraintFromBoundForTypeParam.upper, operations);
- constraints[typeParamToUpdate]?.mergeInTypeSchemaLower(
- constraintFromBoundForTypeParam.lower, operations);
- }
- }
- }
-
DartType _inferTypeParameterFromContext(DartType? typeFromPreviousInference,
MergedTypeConstraint constraint, DartType? extendsConstraint,
{bool isLegacyCovariant = true,
required OperationsCfe operations,
- required Map<StructuralParameter, MergedTypeConstraint>?
- constraintsFromBound,
required Map<StructuralParameter, MergedTypeConstraint> constraints,
required List<StructuralParameter> typeParametersToInfer,
- required StructuralParameter typeParameterToInfer}) {
+ required StructuralParameter typeParameterToInfer,
+ required InferenceDataForTesting? dataForTesting,
+ required bool inferenceUsingBoundsIsEnabled}) {
// See if we already fixed this type in a previous inference step.
// If so, then we aren't allowed to change it unless [isLegacyCovariant] is
// false.
@@ -588,14 +539,21 @@
//
// If we consider the `T extends num` we conclude `<num>`, which works.
- if (constraintsFromBound != null) {
+ if (inferenceUsingBoundsIsEnabled &&
+ constraint.lower is! SharedUnknownTypeSchemaView<DartType> &&
+ !hasOmittedBound(typeParameterToInfer)) {
// Coverage-ignore-block(suite): Not run.
- _mergeInConstraintsFromBound(
- constraintsFromBound: constraintsFromBound,
- typeParametersToInfer: typeParametersToInfer,
- constraints: constraints,
- operations: operations);
- constraint = constraints[typeParameterToInfer]!;
+ MergedTypeConstraint constraintFromBound =
+ operations.mergeInConstraintsFromBound(
+ typeParameterToInfer: typeParameterToInfer,
+ typeParametersToInfer: typeParametersToInfer,
+ lower: constraint.lower.unwrapTypeSchemaView(),
+ inferencePhaseConstraints: constraints,
+ dataForTesting: dataForTesting,
+ inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled);
+
+ constraint.mergeInTypeSchemaUpper(constraintFromBound.upper, operations);
+ constraint.mergeInTypeSchemaLower(constraintFromBound.lower, operations);
}
if (extendsConstraint != null) {
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 4f6203e..863a5b0 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -105,6 +105,7 @@
allocated
allocating
allocation
+allocations
allow
allowed
allowing
diff --git a/pkg/front_end/test/type_inference/type_schema_environment_test_base.dart b/pkg/front_end/test/type_inference/type_schema_environment_test_base.dart
index 6af484d..b63208c 100644
--- a/pkg/front_end/test/type_inference/type_schema_environment_test_base.dart
+++ b/pkg/front_end/test/type_inference/type_schema_environment_test_base.dart
@@ -230,6 +230,7 @@
inferredTypeNodes,
preliminary: downwardsInferPhase,
inferenceUsingBoundsIsEnabled: true,
+ dataForTesting: null,
operations: _operations);
expect(inferredTypeNodes.single, expectedTypeNode);