| Index: pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
|
| index e32850006ba4975f8375ba40c568fa5d0fded9e3..caa08103a55fbb2c0c783274d018a83a1db49b85 100644
|
| --- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
|
| +++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
|
| @@ -3,101 +3,67 @@
|
| // BSD-style license that can be found in the LICENSE.md file.
|
|
|
| import 'package:front_end/src/base/instrumentation.dart';
|
| -import 'package:front_end/src/dependency_walker.dart' as dependencyWalker;
|
| -import 'package:kernel/ast.dart' show DartType, DynamicType, Member;
|
| -import 'package:kernel/class_hierarchy.dart';
|
| +import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
|
| +import 'package:kernel/ast.dart' show DartType, Member;
|
| import 'package:kernel/core_types.dart';
|
|
|
| -/// Data structure for tracking dependencies between fields that require type
|
| -/// inference.
|
| +/// Keeps track of the local state for the type inference that occurs during
|
| +/// compilation of a single method body or top level initializer.
|
| ///
|
| -/// TODO(paulberry): see if it's possible to make this class more lightweight
|
| -/// by changing the API so that the walker is passed to computeDependencies().
|
| -/// (This should allow us to drop the _typeInferrer field).
|
| -class FieldNode<F> extends dependencyWalker.Node<FieldNode<F>> {
|
| - final TypeInferrer _typeInferrer;
|
| -
|
| - final F _field;
|
| -
|
| - final dependencies = <FieldNode<F>>[];
|
| -
|
| - FieldNode(this._typeInferrer, this._field);
|
| -
|
| - @override
|
| - bool get isEvaluated => _typeInferrer.isFieldInferred(_field);
|
| -
|
| - @override
|
| - List<FieldNode<F>> computeDependencies() {
|
| - return dependencies;
|
| - }
|
| -}
|
| -
|
| -/// Abstract implementation of type inference which is independent of the
|
| -/// underlying AST representation (but still uses DartType from kernel).
|
| -///
|
| -/// TODO(paulberry): would it make more sense to abstract away the
|
| -/// representation of types as well?
|
| +/// This class abstracts away the representation of the underlying AST using
|
| +/// generic parameters. TODO(paulberry): would it make more sense to abstract
|
| +/// away the representation of types as well?
|
| ///
|
| /// Derived classes should set S, E, V, and F to the class they use to represent
|
| /// statements, expressions, variable declarations, and field declarations,
|
| /// respectively.
|
| +///
|
| +/// This class describes the interface for use by clients of type inference
|
| +/// (e.g. BodyBuilder). Derived classes should derive from [TypeInferrerImpl].
|
| abstract class TypeInferrer<S, E, V, F> {
|
| - final Instrumentation instrumentation;
|
| -
|
| - final bool strongMode;
|
| -
|
| - final fieldNodes = <FieldNode<F>>[];
|
| -
|
| - CoreTypes coreTypes;
|
| -
|
| - ClassHierarchy classHierarchy;
|
| -
|
| /// The URI of the code for which type inference is currently being
|
| /// performed--this is used for testing.
|
| - String uri;
|
| + String get uri;
|
|
|
| - /// Indicates whether we are currently performing top level inference.
|
| - bool isTopLevel = false;
|
| + /// Gets the [FieldNode] corresponding to the given [readTarget], if any.
|
| + FieldNode<F> getFieldNodeForReadTarget(Member readTarget);
|
|
|
| - TypeInferrer(this.instrumentation, this.strongMode);
|
| + /// Performs type inference on the given [statement].
|
| + ///
|
| + /// Derived classes should override this method with logic that dispatches on
|
| + /// the statement type and calls the appropriate specialized "infer" method.
|
| + void inferStatement(S statement);
|
| +}
|
|
|
| - /// Cleares the initializer of [field].
|
| - void clearFieldInitializer(F field);
|
| +/// Derived class containing generic implementations of [TypeInferrerImpl].
|
| +///
|
| +/// This class contains as much of the implementation of type inference as
|
| +/// possible without knowing the identity of the type parameters. It defers to
|
| +/// abstract methods for everything else.
|
| +abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
|
| + @override
|
| + final String uri;
|
| +
|
| + /// Indicates whether the construct we are currently performing inference for
|
| + /// is outside of a method body, and hence top level type inference rules
|
| + /// should apply.
|
| + final bool isTopLevel = false;
|
| +
|
| + final CoreTypes coreTypes;
|
|
|
| - /// Creates a [FieldNode] to track dependencies of the given [field].
|
| - FieldNode<F> createFieldNode(F field);
|
| + final bool strongMode;
|
|
|
| - /// Gets the declared type of the given [field], or `null` if the type is
|
| - /// implicit.
|
| - DartType getFieldDeclaredType(F field);
|
| + final Instrumentation instrumentation;
|
|
|
| - /// Gets the list of top level type inference dependencies of the given
|
| - /// [field].
|
| - List<FieldNode<F>> getFieldDependencies(F field);
|
| + TypeInferrerImpl(TypeInferenceEngineImpl<F> engine, this.uri)
|
| + : coreTypes = engine.coreTypes,
|
| + strongMode = engine.strongMode,
|
| + instrumentation = engine.instrumentation;
|
|
|
| /// Gets the initializer for the given [field], or `null` if there is no
|
| /// initializer.
|
| E getFieldInitializer(F field);
|
|
|
| - /// Gets the [FieldNode] corresponding to the given [readTarget], if any.
|
| - FieldNode<F> getFieldNodeForReadTarget(Member readTarget);
|
| -
|
| - /// Gets the character offset of the declaration of [field] within its
|
| - /// compilation unit.
|
| - int getFieldOffset(F field);
|
| -
|
| - /// Gets the URI of the compilation unit the [field] is declared in.
|
| - String getFieldUri(F field);
|
| -
|
| - /// Performs type inference on a method with the given method [body].
|
| - ///
|
| - /// [uri] is the URI of the file the method is contained in--this is used for
|
| - /// testing.
|
| - void inferBody(S body, Uri uri) {
|
| - this.uri = uri.toString();
|
| - inferStatement(body);
|
| - }
|
| -
|
| /// Performs type inference on the given [expression].
|
| ///
|
| /// [typeContext] is the expected type of the expression, based on surrounding
|
| @@ -109,42 +75,11 @@ abstract class TypeInferrer<S, E, V, F> {
|
| /// the expression type and calls the appropriate specialized "infer" method.
|
| DartType inferExpression(E expression, DartType typeContext, bool typeNeeded);
|
|
|
| - /// Performs type inference on the given [field].
|
| - void inferField(F field) {
|
| - var initializer = getFieldInitializer(field);
|
| - if (initializer != null) {
|
| - var type = getFieldDeclaredType(field);
|
| - uri = getFieldUri(field);
|
| - isTopLevel = true;
|
| - var inferredType = inferExpression(initializer, type, type == null);
|
| - if (type == null && strongMode) {
|
| - instrumentation?.record(
|
| - 'topType',
|
| - Uri.parse(uri),
|
| - getFieldOffset(field),
|
| - new InstrumentationValueForType(inferredType));
|
| - setFieldInferredType(field, inferredType);
|
| - }
|
| - // TODO(paulberry): if type != null, then check that the type of the
|
| - // initializer is assignable to it.
|
| - // TODO(paulberry): the following is a hack so that outlines don't contain
|
| - // initializers. But it means that we rebuild the initializers when doing
|
| - // a full compile. There should be a better way.
|
| - clearFieldInitializer(field);
|
| - }
|
| - }
|
| -
|
| - /// Makes a note that the given [field] is part of a circularity, so its type
|
| - /// can't be inferred.
|
| - void inferFieldCircular(F field) {
|
| - // TODO(paulberry): report the appropriate error.
|
| - if (getFieldDeclaredType(field) == null) {
|
| - var uri = getFieldUri(field);
|
| - instrumentation?.record('topType', Uri.parse(uri), getFieldOffset(field),
|
| - const InstrumentationValueLiteral('circular'));
|
| - setFieldInferredType(field, const DynamicType());
|
| - }
|
| - }
|
| + /// Performs type inference on the given [field]'s initializer expression.
|
| + ///
|
| + /// Derived classes should provide an implementation that calls
|
| + /// [inferExpression] for the given [field]'s initializer expression.
|
| + DartType inferFieldInitializer(F field, DartType type, bool typeNeeded);
|
|
|
| /// Performs the core type inference algorithm for integer literals.
|
| ///
|
| @@ -154,12 +89,6 @@ abstract class TypeInferrer<S, E, V, F> {
|
| return typeNeeded ? coreTypes.intClass.rawType : null;
|
| }
|
|
|
| - /// Performs type inference on the given [statement].
|
| - ///
|
| - /// Derived classes should override this method with logic that dispatches on
|
| - /// the statement type and calls the appropriate specialized "infer" method.
|
| - void inferStatement(S statement);
|
| -
|
| /// Performs the core type inference algorithm for static variable getters.
|
| ///
|
| /// [typeContext], [typeNeeded], and the return value behave as described in
|
| @@ -190,45 +119,4 @@ abstract class TypeInferrer<S, E, V, F> {
|
| setType(inferredType);
|
| }
|
| }
|
| -
|
| - /// Determines if top level type inference has been completed for [field].
|
| - bool isFieldInferred(F field);
|
| -
|
| - /// Performs top level type inference for all fields that have been passed to
|
| - /// [recordField].
|
| - void performInitializerInference() {
|
| - for (var fieldNode in fieldNodes) {
|
| - if (fieldNode.isEvaluated) continue;
|
| - new _FieldWalker<F>().walk(fieldNode);
|
| - }
|
| - }
|
| -
|
| - /// Records that the given [field] will need top level type inference.
|
| - void recordField(F field) {
|
| - fieldNodes.add(createFieldNode(field));
|
| - }
|
| -
|
| - /// Stores [inferredType] as the inferred type of [field].
|
| - void setFieldInferredType(F field, DartType inferredType);
|
| -}
|
| -
|
| -/// Subtype of [dependencyWalker.DependencyWalker] which is specialized to
|
| -/// perform top level type inference.
|
| -class _FieldWalker<F> extends dependencyWalker.DependencyWalker<FieldNode<F>> {
|
| - _FieldWalker();
|
| -
|
| - @override
|
| - void evaluate(FieldNode<F> f) {
|
| - f._typeInferrer.inferField(f._field);
|
| - }
|
| -
|
| - @override
|
| - void evaluateScc(List<FieldNode<F>> scc) {
|
| - for (var f in scc) {
|
| - f._typeInferrer.inferFieldCircular(f._field);
|
| - }
|
| - for (var f in scc) {
|
| - f._typeInferrer.inferField(f._field);
|
| - }
|
| - }
|
| }
|
|
|