Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Unified Diff: pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart

Issue 2942623004: Fuse top level type inference with dependency generation. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 818c6d89c662ab6647fe6a5f79b5a07d04fb3f76..0bae538671e43a06d1417928b108621f674be8db 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -13,6 +13,21 @@ import 'package:kernel/ast.dart'
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
+/// Enum tracking the type inference state of a field.
+enum FieldState {
+ /// The field's type has not been inferred yet.
+ NotInferredYet,
+
+ /// Type inference is in progress for the field.
+ ///
+ /// This means that code is currently on the stackwhich is attempting to
Siggi Cherem (dart-lang) 2017/06/15 22:12:32 stackwhich => stack which
Paul Berry 2017/06/15 22:16:52 Done.
+ /// determine the type of the field.
+ Inferring,
+
+ /// The field's type has been inferred.
+ Inferred
+}
+
/// Data structure for tracking dependencies between fields that require type
/// inference.
///
@@ -22,14 +37,23 @@ import 'package:kernel/core_types.dart';
class FieldNode extends dependencyWalker.Node<FieldNode> {
final TypeInferenceEngineImpl _typeInferenceEngine;
- final KernelField _field;
+ final KernelField field;
bool isImmediatelyEvident = false;
- FieldNode(this._typeInferenceEngine, this._field);
+ FieldState state = FieldState.NotInferredYet;
+
+ /// If [state] is [FieldState.Inferring], and type inference for this field
+ /// is waiting on type inference of some other field, the field that is being
+ /// waited on.
+ ///
+ /// Otherwise `null`.
+ FieldNode currentDependency;
+
+ FieldNode(this._typeInferenceEngine, this.field);
@override
- bool get isEvaluated => _typeInferenceEngine.isFieldInferred(_field);
+ bool get isEvaluated => state == FieldState.Inferred;
@override
List<FieldNode> computeDependencies() {
@@ -37,7 +61,7 @@ class FieldNode extends dependencyWalker.Node<FieldNode> {
}
@override
- String toString() => _field.toString();
+ String toString() => field.toString();
}
/// Keeps track of the global state for the type inference that occurs outside
@@ -94,6 +118,21 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
/// further work. TODO(paulberry): fix this.
static const bool expandedTopLevelInference = true;
+ /// Enables "fused top level inference", which fuses dependency collection and
+ /// type inference of a field into a single step (a dependency is detected at
+ /// the time type inference attempts to read the depended-upon type, and this
+ /// triggers a recursive evaluation of the depended-upon type).
+ ///
+ /// This avoids some unnecessary dependencies, since we now know for sure
+ /// whether a dependency will be needed at the time we evaluate it.
+ ///
+ /// Requires [expandedTopLevelInference] to be `true`.
+ ///
+ /// Note that setting this value to `true` does not yet allow top level
+ /// inference to depend on field and property accesses; that will require
+ /// further work. TODO(paulberry): fix this.
+ static const bool fusedTopLevelInference = true;
+
final Instrumentation instrumentation;
final bool strongMode;
@@ -122,15 +161,15 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
// In expanded top level inference, we determine the dependencies by
// doing a "dry run" of top level inference and recording which static
// fields were accessed.
- var typeInferrer = getFieldTypeInferrer(fieldNode._field);
+ var typeInferrer = getFieldTypeInferrer(fieldNode.field);
if (typeInferrer == null) {
// This can happen when there are errors in the field declaration.
return const [];
} else {
typeInferrer.startDryRun();
- typeInferrer.listener.dryRunEnter(fieldNode._field.initializer);
- typeInferrer.inferFieldTopLevel(fieldNode._field, null, true);
- typeInferrer.listener.dryRunExit(fieldNode._field.initializer);
+ typeInferrer.listener.dryRunEnter(fieldNode.field.initializer);
+ typeInferrer.inferFieldTopLevel(fieldNode.field, null, true);
+ typeInferrer.listener.dryRunExit(fieldNode.field.initializer);
fieldNode.isImmediatelyEvident = true;
return typeInferrer.finishDryRun();
}
@@ -141,7 +180,7 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
// TODO(paulberry): get rid of this mode once we are sure we no longer
// need it.
var collector = new KernelDependencyCollector();
- collector.collectDependencies(fieldNode._field.initializer);
+ collector.collectDependencies(fieldNode.field.initializer);
fieldNode.isImmediatelyEvident = collector.isImmediatelyEvident;
return collector.dependencies;
}
@@ -153,8 +192,13 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
@override
void finishTopLevel() {
for (var fieldNode in fieldNodes) {
- if (fieldNode.isEvaluated) continue;
- new _FieldWalker().walk(fieldNode);
+ if (fusedTopLevelInference) {
+ assert(expandedTopLevelInference);
+ inferFieldFused(fieldNode, null);
+ } else {
+ if (fieldNode.isEvaluated) continue;
+ new _FieldWalker().walk(fieldNode);
+ }
}
for (var formal in initializingFormals) {
formal.type = _inferInitializingFormalType(formal);
@@ -169,9 +213,41 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
/// a previous call to [createTopLevelTypeInferrer].
TypeInferrerImpl getFieldTypeInferrer(KernelField field);
+ /// Performs fused type inference on the given [field].
+ void inferFieldFused(FieldNode fieldNode, FieldNode dependant) {
+ switch (fieldNode.state) {
+ case FieldState.Inferred:
+ // Already inferred. Nothing to do.
+ break;
+ case FieldState.Inferring:
+ // A field depends on itself (possibly by way of intermediate fields).
+ // Mark all fields involved as circular and infer a type of `dynamic`
+ // for them.
+ var node = fieldNode;
+ while (node != null) {
+ var nextNode = node.currentDependency;
+ inferFieldCircular(node);
+ node.currentDependency = null;
+ node = nextNode;
+ }
+ break;
+ case FieldState.NotInferredYet:
+ // Mark the "dependant" field (if any) as depending on this one, and
+ // invoke field inference for this node.
+ dependant?.currentDependency = fieldNode;
+ // All fields are "immediately evident" when doing fused inference.
+ fieldNode.isImmediatelyEvident = true;
+ inferField(fieldNode);
+ dependant?.currentDependency = null;
+ break;
+ }
+ }
+
/// Performs type inference on the given [field].
void inferField(FieldNode fieldNode) {
- var field = fieldNode._field;
+ assert(fieldNode.state == FieldState.NotInferredYet);
+ fieldNode.state = FieldState.Inferring;
+ var field = fieldNode.field;
var typeInferrer = getFieldTypeInferrer(field);
if (strongMode) {
typeInferrer.isImmediatelyEvident = true;
@@ -179,6 +255,11 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
? typeInferrer.inferDeclarationType(
typeInferrer.inferFieldTopLevel(field, null, true))
: const DynamicType();
+ if (fieldNode.state == FieldState.Inferred) {
+ // A circularity must have been detected; at the time it was detected,
+ // inference for this node was completed.
+ return;
+ }
if (!typeInferrer.isImmediatelyEvident) {
inferredType = const DynamicType();
}
@@ -187,8 +268,9 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
getFieldOffset(field),
'topType',
new InstrumentationValueForType(inferredType));
- setFieldInferredType(field, inferredType);
+ field.type = inferredType;
}
+ fieldNode.state = FieldState.Inferred;
// 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
@@ -199,18 +281,17 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
/// Makes a note that the given [field] is part of a circularity, so its type
/// can't be inferred.
- void inferFieldCircular(KernelField field) {
+ void inferFieldCircular(FieldNode fieldNode) {
+ var field = fieldNode.field;
// TODO(paulberry): report the appropriate error.
var uri = getFieldTypeInferrer(field).uri;
var inferredType = const DynamicType();
instrumentation?.record(Uri.parse(uri), getFieldOffset(field), 'topType',
new InstrumentationValueForType(inferredType));
- setFieldInferredType(field, inferredType);
+ fieldNode.state = FieldState.Inferred;
+ field.type = inferredType;
}
- /// Determines if top level type inference has been completed for [field].
- bool isFieldInferred(KernelField field);
-
@override
void prepareTopLevel(CoreTypes coreTypes, ClassHierarchy hierarchy) {
this.coreTypes = coreTypes;
@@ -229,9 +310,6 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
initializingFormals.add(formal);
}
- /// Stores [inferredType] as the inferred type of [field].
- void setFieldInferredType(KernelField field, DartType inferredType);
-
DartType _inferInitializingFormalType(KernelVariableDeclaration formal) {
assert(KernelVariableDeclaration.isImplicitlyTyped(formal));
Class enclosingClass = formal.parent.parent.parent;
@@ -259,7 +337,7 @@ class _FieldWalker extends dependencyWalker.DependencyWalker<FieldNode> {
void evaluateScc(List<FieldNode> scc) {
// Mark every field as part of a circularity.
for (var f in scc) {
- f._typeInferenceEngine.inferFieldCircular(f._field);
+ f._typeInferenceEngine.inferFieldCircular(f);
}
}
}

Powered by Google App Engine
This is Rietveld 408576698