From bc07511c19359d0586dcfdfe2229012dab5957c7 Mon Sep 17 00:00:00 2001 From: Chloe Stefantsova Date: Thu, 28 Nov 2024 06:27:59 +0000 Subject: [PATCH] [analyzer] Define constraint types specific for the Analyzer Part of https://github.com/dart-lang/sdk/issues/54902 Change-Id: I564f355e8fd8f036ee821968b5b094f37dc52b62 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/397820 Reviewed-by: Paul Berry Commit-Queue: Chloe Stefantsova --- .../src/dart/element/generic_inferrer.dart | 159 ++++-------------- .../element/type_constraint_gatherer.dart | 104 ++++++++---- .../type_constraint_generation_test.dart | 65 ++----- 3 files changed, 122 insertions(+), 206 deletions(-) diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart index 9ceb8359ea62..23352ae267df 100644 --- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart +++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart @@ -5,7 +5,6 @@ import 'dart:math' as math; import 'package:_fe_analyzer_shared/src/type_inference/shared_inference_log.dart'; -import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart'; import 'package:_fe_analyzer_shared/src/types/shared_type.dart'; import 'package:analyzer/dart/ast/ast.dart' show @@ -60,15 +59,7 @@ import 'package:collection/collection.dart'; class GenericInferrer { final TypeSystemImpl _typeSystem; final Set _typeParameters = Set.identity(); - final Map< - TypeParameterElement, - List< - MergedTypeConstraint< - DartType, - TypeParameterElement, - PromotableElement, - InterfaceType, - InterfaceElement>>> _constraints = {}; + final Map> _constraints = {}; /// The list of type parameters being inferred. final List _typeFormals; @@ -159,8 +150,7 @@ class GenericInferrer { void constrainArgument( DartType argumentType, DartType parameterType, String parameterName, {InterfaceElement? genericClass, required AstNode? nodeForTesting}) { - var origin = TypeConstraintFromArgument( + var origin = TypeConstraintFromArgument( argumentType: SharedTypeView(argumentType), parameterType: SharedTypeView(parameterType), parameterName: parameterName, @@ -199,14 +189,8 @@ class GenericInferrer { void constrainGenericFunctionInContext( FunctionType fnType, DartType contextType, {required AstNode? nodeForTesting}) { - var origin = TypeConstraintFromFunctionContext< - DartType, - DartType, - DartType, - PromotableElement, - TypeParameterElement, - InterfaceType, - InterfaceElement>(functionType: fnType, contextType: contextType); + var origin = TypeConstraintFromFunctionContext( + functionType: fnType, contextType: contextType); // Since we're trying to infer the instantiation, we want to ignore type // formals as we check the parameters and return type. @@ -229,14 +213,8 @@ class GenericInferrer { /// is a subtype of the [contextType]. void constrainReturnType(DartType declaredType, DartType contextType, {required AstNode? nodeForTesting}) { - var origin = TypeConstraintFromReturnType< - DartType, - DartType, - DartType, - PromotableElement, - TypeParameterElement, - InterfaceType, - InterfaceElement>(declaredType: declaredType, contextType: contextType); + var origin = TypeConstraintFromReturnType( + declaredType: declaredType, contextType: contextType); inferenceLogWriter?.enterConstraintGeneration( ConstraintGenerationSource.returnType, declaredType, contextType); _tryMatchSubtypeOf(declaredType, contextType, origin, @@ -267,12 +245,7 @@ class GenericInferrer { var parameterBound = Substitution.fromPairs(_typeFormals, inferredTypes) .substituteType(parameterBoundRaw); - var extendsConstraint = MergedTypeConstraint< - DartType, - TypeParameterElement, - PromotableElement, - InterfaceType, - InterfaceElement>.fromExtends( + var extendsConstraint = MergedTypeConstraint.fromExtends( typeParameterName: parameter.name, boundType: SharedTypeView(parameterBoundRaw), extendsType: SharedTypeView(parameterBound), @@ -445,10 +418,7 @@ class GenericInferrer { /// type parameter which means we choose the upper bound rather than the /// lower bound for normally covariant type parameters. DartType _chooseTypeFromConstraints( - Iterable< - MergedTypeConstraint> - constraints, + Iterable constraints, {bool toKnownType = false, required bool isContravariant}) { var (:lower, :upper) = @@ -503,12 +473,10 @@ class GenericInferrer { // TODO(kallentu): : Clean up TypeParameterElementImpl casting once // variance is added to the interface. var typeParam = _typeFormals[i] as TypeParameterElementImpl; - MergedTypeConstraint? extendsClause; + MergedTypeConstraint? extendsClause; var bound = typeParam.bound; if (bound != null) { - extendsClause = MergedTypeConstraint.fromExtends( + extendsClause = MergedTypeConstraint.fromExtends( typeParameterName: typeParam.name, boundType: SharedTypeView(bound), extendsType: SharedTypeView( @@ -546,10 +514,7 @@ class GenericInferrer { } ({DartType lower, DartType upper}) _computeLowerAndUpperBoundsOfConstraints( - Iterable< - MergedTypeConstraint> - constraints) { + Iterable constraints) { DartType lower = UnknownInferredType.instance; DartType upper = UnknownInferredType.instance; for (var constraint in constraints) { @@ -584,30 +549,20 @@ class GenericInferrer { return element.getDisplayString(); } - String _formatError( - TypeParameterElement typeParam, - DartType inferred, - Iterable< - MergedTypeConstraint> - constraints) { + String _formatError(TypeParameterElement typeParam, DartType inferred, + Iterable constraints) { var inferredStr = inferred.getDisplayString(); var intro = "Tried to infer '$inferredStr' for '${typeParam.name}'" " which doesn't work:"; - var constraintsByOrigin = , - List< - MergedTypeConstraint>>{}; + var constraintsByOrigin = + >{}; for (var c in constraints) { constraintsByOrigin.putIfAbsent(c.origin, () => []).add(c); } // Only report unique constraint origins. - Iterable< - MergedTypeConstraint> isSatisfied(bool expected) => + Iterable isSatisfied(bool expected) => constraintsByOrigin.values .where((l) => l.every((c) => c.isSatisfiedBy( @@ -629,28 +584,17 @@ class GenericInferrer { 'Consider passing explicit type argument(s) to the generic.\n\n'; } - DartType _inferTypeParameterFromAll( - List< - MergedTypeConstraint> - constraints, - MergedTypeConstraint? - extendsClause, + DartType _inferTypeParameterFromAll(List constraints, + MergedTypeConstraint? extendsClause, {required bool isContravariant, required TypeParameterElement typeParameterToInfer, - required Map< - TypeParameterElement, - List< - MergedTypeConstraint>> + required Map> inferencePhaseConstraints}) { if (extendsClause != null) { var (:lower, upper: _) = _computeLowerAndUpperBoundsOfConstraints(constraints); - MergedTypeConstraint? boundConstraint; + MergedTypeConstraint? boundConstraint; if (inferenceUsingBoundsIsEnabled) { if (!identical(lower, UnknownInferredType.instance)) { boundConstraint = _mergeInConstraintsFromBound( @@ -675,20 +619,11 @@ class GenericInferrer { } DartType _inferTypeParameterFromContext( - Iterable< - MergedTypeConstraint> - constraints, - MergedTypeConstraint? - extendsClause, + Iterable constraints, + MergedTypeConstraint? extendsClause, {required bool isContravariant, required TypeParameterElement typeParameterToInfer, - required Map< - TypeParameterElement, - List< - MergedTypeConstraint>> + required Map> inferencePhaseConstraints}) { // Both bits of the bound information should be available at the same time. assert(extendsClause == null || typeParameterToInfer.bound != null); @@ -710,8 +645,7 @@ class GenericInferrer { var (:lower, upper: _) = _computeLowerAndUpperBoundsOfConstraints(constraints); - MergedTypeConstraint? boundConstraint; + MergedTypeConstraint? boundConstraint; if (inferenceUsingBoundsIsEnabled) { if (!identical(lower, UnknownInferredType.instance)) { boundConstraint = _mergeInConstraintsFromBound( @@ -734,17 +668,11 @@ class GenericInferrer { return t; } - MergedTypeConstraint - _mergeInConstraintsFromBound( - {required TypeParameterElement typeParameterToInfer, - required DartType lower, - required Map< - TypeParameterElement, - List< - MergedTypeConstraint>> - inferencePhaseConstraints}) { + MergedTypeConstraint _mergeInConstraintsFromBound( + {required TypeParameterElement typeParameterToInfer, + required DartType lower, + required Map> + 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 @@ -877,14 +805,8 @@ class GenericInferrer { /// 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}) { + bool _tryMatchSubtypeOf(DartType t1, DartType t2, TypeConstraintOrigin origin, + {required bool covariant, required AstNode? nodeForTesting}) { var gatherer = TypeConstraintGatherer( typeParameters: _typeParameters, typeSystemOperations: _typeSystemOperations, @@ -911,21 +833,12 @@ class GenericInferrer { return type.getDisplayString(); } - static String _formatConstraints( - Iterable< - MergedTypeConstraint> - constraints, + static String _formatConstraints(Iterable constraints, TypeSystemOperations typeSystemOperations) { - List> lineParts = Set< - TypeConstraintOrigin< - DartType, - PromotableElement, - TypeParameterElement, - InterfaceType, - InterfaceElement>>.from(constraints.map((c) => c.origin)) - .map((o) => o.formatError(typeSystemOperations)) - .toList(); + List> lineParts = + Set.from(constraints.map((c) => c.origin)) + .map((o) => o.formatError(typeSystemOperations)) + .toList(); int prefixMax = lineParts.map((p) => p[0].length).fold(0, math.max); 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 3a78ee32202c..3fd69427bdef 100644 --- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart +++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart @@ -8,7 +8,17 @@ import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations. TypeConstraintGenerator, TypeConstraintGeneratorMixin, TypeConstraintGeneratorState; -import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart'; +import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart' + as shared + show + GeneratedTypeConstraint, + MergedTypeConstraint, + TypeConstraintFromArgument, + TypeConstraintFromExtendsClause, + TypeConstraintFromFunctionContext, + TypeConstraintFromReturnType, + TypeConstraintOrigin, + UnknownTypeConstraintOrigin; import 'package:_fe_analyzer_shared/src/types/shared_type.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; @@ -18,6 +28,56 @@ import 'package:analyzer/src/dart/element/type_algebra.dart'; import 'package:analyzer/src/dart/element/type_schema.dart'; import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart'; +/// Instance of [shared.GeneratedTypeConstraint] specific to the Analyzer. +typedef GeneratedTypeConstraint = shared + .GeneratedTypeConstraint; + +/// Instance of [shared.MergedTypeConstraint] specific to the Analyzer. +typedef MergedTypeConstraint = shared.MergedTypeConstraint; + +/// Instance of [shared.TypeConstraintFromArgument] specific to the Analyzer. +typedef TypeConstraintFromArgument = shared.TypeConstraintFromArgument; + +/// Instance of [shared.TypeConstraintFromExtendsClause] specific to the Analyzer. +typedef TypeConstraintFromExtendsClause + = shared.TypeConstraintFromExtendsClause; + +/// Instance of [shared.TypeConstraintFromFunctionContext] specific to the Analyzer. +typedef TypeConstraintFromFunctionContext + = shared.TypeConstraintFromFunctionContext< + DartType, + DartType, + DartType, + PromotableElement, + TypeParameterElement, + InterfaceType, + InterfaceElement>; + +/// Instance of [shared.TypeConstraintFromReturnType] specific to the Analyzer. +typedef TypeConstraintFromReturnType = shared.TypeConstraintFromReturnType< + DartType, + DartType, + DartType, + PromotableElement, + TypeParameterElement, + InterfaceType, + InterfaceElement>; + +/// Instance of [shared.TypeConstraintOrigin] specific to the Analyzer. +typedef TypeConstraintOrigin = shared.TypeConstraintOrigin; + +/// Instance of [shared.UnknownTypeConstraintOrigin] specific to the Analyzer. +typedef UnknownTypeConstraintOrigin = shared.UnknownTypeConstraintOrigin< + DartType, + PromotableElement, + TypeParameterElement, + InterfaceType, + InterfaceElement>; + /// Creates sets of [GeneratedTypeConstraint]s for type parameters, based on an /// attempt to make one type schema a subtype of another. class TypeConstraintGatherer extends shared.TypeConstraintGenerator< @@ -40,9 +100,7 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator< @override final Set typeParametersToConstrain = Set.identity(); - final List< - GeneratedTypeConstraint> _constraints = []; + final List _constraints = []; final TypeSystemOperations _typeSystemOperations; final TypeConstraintGenerationDataForTesting? dataForTesting; @@ -72,11 +130,8 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator< void addLowerConstraintForParameter( TypeParameterElement element, DartType lower, {required AstNode? astNodeForTesting}) { - GeneratedTypeConstraint - generatedTypeConstraint = GeneratedTypeConstraint< - DartType, - TypeParameterElement, - PromotableElement>.lower(element, SharedTypeSchemaView(lower)); + GeneratedTypeConstraint generatedTypeConstraint = + GeneratedTypeConstraint.lower(element, SharedTypeSchemaView(lower)); _constraints.add(generatedTypeConstraint); if (dataForTesting != null && astNodeForTesting != null) { (dataForTesting!.generatedTypeConstraints[astNodeForTesting] ??= []) @@ -88,11 +143,8 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator< void addUpperConstraintForParameter( TypeParameterElement element, DartType upper, {required AstNode? astNodeForTesting}) { - GeneratedTypeConstraint - generatedTypeConstraint = GeneratedTypeConstraint< - DartType, - TypeParameterElement, - PromotableElement>.upper(element, SharedTypeSchemaView(upper)); + GeneratedTypeConstraint generatedTypeConstraint = + GeneratedTypeConstraint.upper(element, SharedTypeSchemaView(upper)); _constraints.add(generatedTypeConstraint); if (dataForTesting != null && astNodeForTesting != null) { (dataForTesting!.generatedTypeConstraints[astNodeForTesting] ??= []) @@ -101,16 +153,10 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator< } /// Returns the set of type constraints that was gathered. - Map< - TypeParameterElement, - MergedTypeConstraint> computeConstraints() { - var result = >{}; + Map computeConstraints() { + var result = {}; for (var parameter in typeParametersToConstrain) { - result[parameter] = MergedTypeConstraint( + result[parameter] = MergedTypeConstraint( lower: SharedTypeSchemaView(UnknownInferredType.instance), upper: SharedTypeSchemaView(UnknownInferredType.instance), origin: const UnknownTypeConstraintOrigin(), @@ -214,11 +260,8 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator< class TypeConstraintGenerationDataForTesting { /// Map from nodes requiring type inference to the generated type constraints /// for the node. - final Map< - AstNode, - List< - GeneratedTypeConstraint>> generatedTypeConstraints = {}; + final Map> generatedTypeConstraints = + {}; /// Merges [other] into the receiver, combining the constraints. /// @@ -228,9 +271,8 @@ class TypeConstraintGenerationDataForTesting { /// [other]. void mergeIn(TypeConstraintGenerationDataForTesting other) { for (AstNode node in other.generatedTypeConstraints.keys) { - List< - GeneratedTypeConstraint>? constraints = generatedTypeConstraints[node]; + List? constraints = + generatedTypeConstraints[node]; if (constraints != null) { constraints.addAll(other.generatedTypeConstraints[node]!); } else { diff --git a/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart b/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart index 72e4e740dbf7..de956c6e4fb4 100644 --- a/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart +++ b/pkg/analyzer/test/id_tests/type_constraint_generation_test.dart @@ -6,10 +6,7 @@ import 'dart:io'; import 'package:_fe_analyzer_shared/src/testing/id.dart' show ActualData, Id; import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'; -import 'package:_fe_analyzer_shared/src/type_inference/type_constraint.dart'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/src/dart/analysis/testing_data.dart'; import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart'; import 'package:analyzer/src/util/ast_data_extractor.dart'; @@ -20,10 +17,7 @@ main(List args) async { Directory dataDir = Directory.fromUri( Platform.script.resolve('../../../_fe_analyzer_shared/test/inference/' 'type_constraint_generation/data')); - return runTests< - List< - GeneratedTypeConstraint>>(dataDir, + return runTests>(dataDir, args: args, createUriForFileName: createUriForFileName, onFailure: onFailure, @@ -31,33 +25,20 @@ main(List args) async { [analyzerDefaultConfig])); } -class _TypeConstraintGenerationDataComputer extends DataComputer< - List< - GeneratedTypeConstraint>> { +class _TypeConstraintGenerationDataComputer + extends DataComputer> { const _TypeConstraintGenerationDataComputer(); @override - DataInterpreter< - List< - GeneratedTypeConstraint>> get dataValidator => + DataInterpreter> get dataValidator => const _TypeConstraintGenerationDataInterpreter(); @override bool get supportsErrors => true; @override - void computeUnitData( - TestingData testingData, - CompilationUnit unit, - Map< - Id, - ActualData< - List< - GeneratedTypeConstraint>>> - actualMap) { + void computeUnitData(TestingData testingData, CompilationUnit unit, + Map>> actualMap) { _TypeConstraintGenerationDataExtractor( testingData.uriToTypeConstraintGenerationData[ unit.declaredElement!.source.uri]!, @@ -67,37 +48,25 @@ class _TypeConstraintGenerationDataComputer extends DataComputer< } } -class _TypeConstraintGenerationDataExtractor extends AstDataExtractor< - List< - GeneratedTypeConstraint>> { +class _TypeConstraintGenerationDataExtractor + extends AstDataExtractor> { final TypeConstraintGenerationDataForTesting dataForTesting; _TypeConstraintGenerationDataExtractor( this.dataForTesting, super.uri, super.actualMap); @override - List< - GeneratedTypeConstraint>? computeNodeValue(Id id, AstNode node) { + List? computeNodeValue(Id id, AstNode node) { return dataForTesting.generatedTypeConstraints[node]; } } class _TypeConstraintGenerationDataInterpreter - implements - DataInterpreter< - List< - GeneratedTypeConstraint>> { + implements DataInterpreter> { const _TypeConstraintGenerationDataInterpreter(); @override - String getText( - List< - GeneratedTypeConstraint> - actualData, + String getText(List actualData, [String? indentation]) { StringBuffer sb = StringBuffer(); if (actualData.isNotEmpty) { @@ -119,11 +88,7 @@ class _TypeConstraintGenerationDataInterpreter @override String? isAsExpected( - List< - GeneratedTypeConstraint> - actualData, - String? expectedData) { + List actualData, String? expectedData) { var actualDataText = getText(actualData); if (actualDataText == expectedData) { return null; @@ -133,10 +98,6 @@ class _TypeConstraintGenerationDataInterpreter } @override - bool isEmpty( - List< - GeneratedTypeConstraint>? - actualData) => + bool isEmpty(List? actualData) => actualData == null || actualData.isEmpty; }