[analyzer,cfe] Introduce TypeAnalyzerOperations.isUnknownType

The method is introduced as a preliminary step in sharing constraint
gathering and solving engine between the Analyzer and the CFE.

Change-Id: I321a931908054bc08dff0626adcd23deb046230f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/343781
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Chloe Stefantsova 2024-01-10 11:58:27 +00:00 committed by Commit Queue
parent 507297562c
commit cd3240eb55
25 changed files with 95 additions and 10 deletions

View file

@ -81,6 +81,9 @@ abstract interface class TypeAnalyzerOperations<Variable extends Object,
/// Returns `true` if [type] is the type `dynamic`.
bool isDynamic(Type type);
/// Returns `true` if [type] is the unknown type context (`?`).
bool isUnknownType(Type type);
/// Returns whether [node] is final.
bool isVariableFinal(Variable node);

View file

@ -2842,6 +2842,9 @@ class MiniAstOperations implements TypeAnalyzerOperations<Var, Type> {
@override
bool isTypeParameterType(Type type) => type is PromotedTypeVariableType;
@override
bool isUnknownType(Type type) => type is UnknownType;
@override
bool isVariableFinal(Var node) {
return node.isFinal;

View file

@ -108,6 +108,7 @@ class ExtensionMemberContributor extends DartCompletionContributor {
var applicableExtensions = extensions.applicableTo(
targetLibrary: request.libraryElement,
targetType: type,
strictCasts: false,
);
for (var instantiatedExtension in applicableExtensions) {
var extendedType = instantiatedExtension.extendedType;

View file

@ -568,6 +568,15 @@ abstract class _AbstractCorrectionProducer<T extends ParsedUnitResult> {
AnalysisSessionHelper get sessionHelper => _context.sessionHelper;
bool get strictCasts {
var file = _context.dartFixContext?.resolveResult.file;
// TODO(pq): can this ever happen?
if (file == null) return false;
var analysisOptions = _context.session.analysisContext
.getAnalysisOptionsForFile(file) as AnalysisOptionsImpl;
return analysisOptions.strictCasts;
}
Token get token => _context.token;
CompilationUnit get unit => _context.unit;

View file

@ -186,6 +186,7 @@ class ImportLibrary extends MultiCorrectionProducer {
.applicableTo(
targetLibrary: libraryElement,
targetType: targetType,
strictCasts: strictCasts,
);
for (var instantiatedExtension in instantiatedExtensions) {
// If the import has a combinator that needs to be updated, then offer
@ -462,6 +463,7 @@ class _ImportLibraryContainingExtension extends ResolvedCorrectionProducer {
.applicableTo(
targetLibrary: libraryElement,
targetType: targetType,
strictCasts: strictCasts,
);
if (instantiatedExtensions.isNotEmpty) {
await builder.addDartFileEdit(file, (builder) {

View file

@ -136,6 +136,7 @@ class LibraryAnalyzer {
featureSet: _libraryElement.featureSet,
nameScope: _libraryElement.scope,
strictInference: _analysisOptions.strictInference,
strictCasts: _analysisOptions.strictCasts,
elementWalker: ElementWalker.forCompilationUnit(
unitElement,
libraryFilePath: _library.file.path,
@ -796,6 +797,7 @@ class LibraryAnalyzer {
featureSet: unit.featureSet,
nameScope: unitElement.enclosingElement.scope,
strictInference: _analysisOptions.strictInference,
strictCasts: _analysisOptions.strictCasts,
elementWalker: ElementWalker.forCompilationUnit(
unitElement,
libraryFilePath: _library.file.path,

View file

@ -25,6 +25,7 @@ import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/error/codes.dart'
show CompileTimeErrorCode, WarningCode;
import 'package:analyzer/src/utilities/extensions/collection.dart';
@ -99,12 +100,17 @@ class GenericInferrer {
/// implicit runtime checks).
final Map<TypeParameterElement, DartType> _typesInferredSoFar = {};
final TypeSystemOperations _typeSystemOperations;
GenericInferrer(this._typeSystem, this._typeFormals,
{this.errorReporter,
this.errorNode,
required this.genericMetadataIsEnabled,
required bool strictInference})
: _strictInference = strictInference {
required bool strictInference,
required bool strictCasts})
: _strictInference = strictInference,
_typeSystemOperations =
TypeSystemOperations(_typeSystem, strictCasts: strictCasts) {
if (errorReporter != null) {
assert(errorNode != null);
}
@ -646,7 +652,9 @@ class GenericInferrer {
DartType t1, DartType t2, _TypeConstraintOrigin origin,
{required bool covariant}) {
var gatherer = TypeConstraintGatherer(
typeSystem: _typeSystem, typeParameters: _typeParameters);
typeSystem: _typeSystem,
typeParameters: _typeParameters,
typeSystemOperations: _typeSystemOperations);
var success = gatherer.trySubtypeMatch(t1, t2, !covariant);
if (success) {
var constraints = gatherer.computeConstraints();

View file

@ -10,6 +10,7 @@ import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
/// A constraint on the type [parameter] that we're inferring.
/// We require that `lower <: parameter <: upper`.
@ -39,11 +40,14 @@ class TypeConstraintGatherer {
final TypeSystemImpl _typeSystem;
final Set<TypeParameterElement> _typeParameters = Set.identity();
final List<TypeConstraint> _constraints = [];
final TypeSystemOperations _typeSystemOperations;
TypeConstraintGatherer({
required TypeSystemImpl typeSystem,
required Iterable<TypeParameterElement> typeParameters,
}) : _typeSystem = typeSystem {
required TypeSystemOperations typeSystemOperations,
}) : _typeSystem = typeSystem,
_typeSystemOperations = typeSystemOperations {
_typeParameters.addAll(typeParameters);
}
@ -95,12 +99,12 @@ class TypeConstraintGatherer {
/// constraints is unchanged.
bool trySubtypeMatch(DartType P, DartType Q, bool leftSchema) {
// If `P` is `_` then the match holds with no constraints.
if (identical(P, UnknownInferredType.instance)) {
if (_typeSystemOperations.isUnknownType(P)) {
return true;
}
// If `Q` is `_` then the match holds with no constraints.
if (identical(Q, UnknownInferredType.instance)) {
if (_typeSystemOperations.isUnknownType(Q)) {
return true;
}

View file

@ -689,6 +689,7 @@ class TypeSystemImpl implements TypeSystem {
AstNode? errorNode,
required bool genericMetadataIsEnabled,
required bool strictInference,
required bool strictCasts,
}) {
if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) {
return const <DartType>[];
@ -702,7 +703,8 @@ class TypeSystemImpl implements TypeSystem {
errorReporter: errorReporter,
errorNode: errorNode,
genericMetadataIsEnabled: genericMetadataIsEnabled,
strictInference: strictInference);
strictInference: strictInference,
strictCasts: strictCasts);
inferrer.constrainGenericFunctionInContext(fnType, contextType);
// Infer and instantiate the resulting type.
@ -1585,10 +1587,12 @@ class TypeSystemImpl implements TypeSystem {
List<DartType> destTypes, {
required bool genericMetadataIsEnabled,
required bool strictInference,
required bool strictCasts,
}) {
var inferrer = GenericInferrer(this, typeParameters,
genericMetadataIsEnabled: genericMetadataIsEnabled,
strictInference: strictInference);
strictInference: strictInference,
strictCasts: strictCasts);
for (int i = 0; i < srcTypes.length; i++) {
inferrer.constrainReturnType(srcTypes[i], destTypes[i]);
inferrer.constrainReturnType(destTypes[i], srcTypes[i]);
@ -1869,6 +1873,7 @@ class TypeSystemImpl implements TypeSystem {
required bool genericMetadataIsEnabled,
bool isConst = false,
required bool strictInference,
required bool strictCasts,
}) {
// Create a GenericInferrer that will allow certain type parameters to be
// inferred. It will optimistically assume these type parameters can be
@ -1878,7 +1883,8 @@ class TypeSystemImpl implements TypeSystem {
errorReporter: errorReporter,
errorNode: errorNode,
genericMetadataIsEnabled: genericMetadataIsEnabled,
strictInference: strictInference);
strictInference: strictInference,
strictCasts: strictCasts);
if (contextReturnType != null) {
if (isConst) {

View file

@ -107,10 +107,12 @@ extension ExtensionsExtensions on Iterable<ExtensionElement> {
List<InstantiatedExtensionWithoutMember> applicableTo({
required LibraryElement targetLibrary,
required DartType targetType,
required bool strictCasts,
}) {
return map((e) => _NotInstantiatedExtensionWithoutMember(e)).applicableTo(
targetLibrary: targetLibrary,
targetType: targetType,
strictCasts: strictCasts,
);
}
@ -174,6 +176,7 @@ extension NotInstantiatedExtensionsExtensions<R>
List<R> applicableTo({
required LibraryElement targetLibrary,
required DartType targetType,
required bool strictCasts,
}) {
if (identical(targetType, NeverTypeImpl.instance)) {
return <R>[];
@ -199,6 +202,7 @@ extension NotInstantiatedExtensionsExtensions<R>
freshTypeParameters,
genericMetadataIsEnabled: genericMetadataIsEnabled,
strictInference: false,
strictCasts: strictCasts,
);
inferrer.constrainArgument(
targetType,

View file

@ -93,6 +93,7 @@ class ExtensionMemberResolver {
.applicableTo(
targetLibrary: _resolver.definingLibrary,
targetType: type,
strictCasts: _resolver.analysisOptions.strictCasts,
);
if (extensions.isEmpty) {
@ -350,6 +351,7 @@ class ExtensionMemberResolver {
errorNode: SimpleIdentifierImpl(node.name),
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: _resolver.analysisOptions.strictInference,
strictCasts: _resolver.analysisOptions.strictCasts,
);
inferrer.constrainArgument(
receiverType,

View file

@ -493,6 +493,11 @@ class TypeSystemOperations
@override
bool isTypeParameterType(DartType type) => type is TypeParameterType;
@override
bool isUnknownType(DartType type) {
return identical(type, UnknownInferredType.instance);
}
@override
bool isVariableFinal(PromotableElement element) {
return element.isFinal;

View file

@ -129,6 +129,7 @@ class InvocationInferenceHelper {
errorNode: expression,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: _resolver.analysisOptions.strictInference,
strictCasts: _resolver.analysisOptions.strictCasts,
);
identifier.tearOffTypeArgumentTypes = typeArguments;
if (typeArguments.isNotEmpty) {

View file

@ -197,6 +197,7 @@ abstract class FullInvocationInferrer<Node extends AstNodeImpl>
errorNode: _errorNode,
genericMetadataIsEnabled: resolver.genericMetadataIsEnabled,
strictInference: resolver.analysisOptions.strictInference,
strictCasts: resolver.analysisOptions.strictCasts,
);
substitution = Substitution.fromPairs(

View file

@ -27,6 +27,7 @@ class NamedTypeResolver with ScopeHelpers {
final LibraryElementImpl _libraryElement;
final TypeSystemImpl typeSystem;
final bool isNonNullableByDefault;
final bool strictCasts;
final bool strictInference;
@override
@ -61,7 +62,7 @@ class NamedTypeResolver with ScopeHelpers {
NamedTypeResolver(
this._libraryElement, this.isNonNullableByDefault, this.errorReporter,
{required this.strictInference})
{required this.strictInference, required this.strictCasts})
: typeSystem = _libraryElement.typeSystem;
bool get _genericMetadataIsEnabled =>
@ -182,6 +183,7 @@ class NamedTypeResolver with ScopeHelpers {
contextReturnType: enclosingClass!.thisType,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: strictInference,
strictCasts: strictCasts,
);
var typeArguments = inferrer.chooseFinalTypes();
return element.instantiate(

View file

@ -20,6 +20,7 @@ import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/scope.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/named_type_resolver.dart';
import 'package:analyzer/src/dart/resolver/record_type_annotation_resolver.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
@ -102,12 +103,16 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
typeProvider: _typeProvider,
);
/// The set of required operations on types.
final TypeSystemOperations typeSystemOperations;
factory ResolutionVisitor({
required CompilationUnitElementImpl unitElement,
required AnalysisErrorListener errorListener,
required FeatureSet featureSet,
required Scope nameScope,
required bool strictInference,
required bool strictCasts,
ElementWalker? elementWalker,
}) {
var libraryElement = unitElement.library;
@ -125,6 +130,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
isNonNullableByDefault,
errorReporter,
strictInference: strictInference,
strictCasts: strictCasts,
);
final recordTypeResolver = RecordTypeAnnotationResolver(
@ -132,6 +138,11 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
errorReporter: errorReporter,
);
final typeSystemOperations = TypeSystemOperations(
unitElement.library.typeSystem,
strictCasts: strictCasts,
);
return ResolutionVisitor._(
libraryElement,
typeProvider,
@ -144,6 +155,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
nameScope,
elementWalker,
ElementHolder(unitElement),
typeSystemOperations,
);
}
@ -159,6 +171,7 @@ class ResolutionVisitor extends RecursiveAstVisitor<void> {
this._nameScope,
this._elementWalker,
this._elementHolder,
this.typeSystemOperations,
);
DartType get _dynamicType => _typeProvider.dynamicType;

View file

@ -453,6 +453,7 @@ class TypedLiteralResolver {
errorNode: node,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: _resolver.analysisOptions.strictInference,
strictCasts: _resolver.analysisOptions.strictCasts,
);
}
@ -501,6 +502,7 @@ class TypedLiteralResolver {
isConst: node.isConst,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: _resolver.analysisOptions.strictInference,
strictCasts: _resolver.analysisOptions.strictCasts,
);
}
@ -589,6 +591,7 @@ class TypedLiteralResolver {
isConst: node.isConst,
genericMetadataIsEnabled: _genericMetadataIsEnabled,
strictInference: _resolver.analysisOptions.strictInference,
strictCasts: _resolver.analysisOptions.strictCasts,
);
}

View file

@ -219,6 +219,7 @@ class LiteralElementVerifier {
errorNode: expression,
genericMetadataIsEnabled: true,
strictInference: _errorVerifier.options.strictInference,
strictCasts: _errorVerifier.options.strictCasts,
);
if (typeArguments.isNotEmpty) {
tearoffType = tearoffType.instantiate(typeArguments);

View file

@ -2772,6 +2772,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
errorNode: node.iterable,
genericMetadataIsEnabled: true,
strictInference: options.strictInference,
strictCasts: options.strictCasts,
);
if (typeArguments.isNotEmpty) {
tearoffType = tearoffType.instantiate(typeArguments);

View file

@ -1209,6 +1209,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
// generic-metadata.
genericMetadataIsEnabled: true,
strictInference: analysisOptions.strictInference,
strictCasts: analysisOptions.strictCasts,
);
if (typeArgumentTypes.isNotEmpty) {
staticType = staticType.instantiate(typeArgumentTypes);
@ -3669,6 +3670,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
errorNode: errorNode,
genericMetadataIsEnabled: genericMetadataIsEnabled,
strictInference: analysisOptions.strictInference,
strictCasts: analysisOptions.strictCasts,
);
inferrer.constrainReturnType(declaredType, contextType);
return inferrer.chooseFinalTypes();
@ -3713,6 +3715,7 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
// generic-metadata.
genericMetadataIsEnabled: true,
strictInference: analysisOptions.strictInference,
strictCasts: analysisOptions.strictCasts,
);
if (typeArgumentTypes.isNotEmpty) {
callMethodType = callMethodType.instantiate(typeArgumentTypes);

View file

@ -32,6 +32,7 @@ class AstResolver {
nameScope: _nameScope,
errorListener: _errorListener,
strictInference: analysisOptions.strictInference,
strictCasts: analysisOptions.strictCasts,
);
late final _scopeResolverVisitor = ScopeResolverVisitor(
_unitElement.library,

View file

@ -652,6 +652,7 @@ class _MixinInference {
matchingInterfaceTypes,
genericMetadataIsEnabled: featureSet.isEnabled(Feature.generic_metadata),
strictInference: false,
strictCasts: false,
);
if (inferredTypeArguments == null) {
return mixinType;

View file

@ -656,6 +656,7 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
),
genericMetadataIsEnabled: true,
strictInference: false,
strictCasts: false,
);
inferrer.constrainArguments(
parameters: ft.parameters, argumentTypes: arguments);

View file

@ -5,6 +5,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_constraint_gatherer.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -1330,6 +1331,8 @@ class TypeConstraintGathererTest extends AbstractTypeSystemTest {
var gatherer = TypeConstraintGatherer(
typeSystem: typeSystem,
typeParameters: typeParameters,
typeSystemOperations:
TypeSystemOperations(typeSystem, strictCasts: false),
);
var isMatch = gatherer.trySubtypeMatch(P, Q, leftSchema);
@ -1354,6 +1357,8 @@ class TypeConstraintGathererTest extends AbstractTypeSystemTest {
var gatherer = TypeConstraintGatherer(
typeSystem: typeSystem,
typeParameters: typeParameters,
typeSystemOperations:
TypeSystemOperations(typeSystem, strictCasts: false),
);
var isMatch = gatherer.trySubtypeMatch(P, Q, leftSchema);

View file

@ -723,6 +723,9 @@ class OperationsCfe
@override
bool isError(DartType type) => type is InvalidType;
@override
bool isUnknownType(DartType type) => type is UnknownType;
@override
bool isVariableFinal(VariableDeclaration node) {
return node.isFinal;