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); |
- } |
- } |
} |