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

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

Issue 2943273002: Implement type inference of getters/setters based on inheritance. (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 b21d5929a211cd9fe5fc54ce1356c1a345dbb4f8..ee4166216ede6c53cb54d942acab19886ed6dfb4 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
@@ -15,8 +15,8 @@ import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart';
-/// Data structure for tracking dependencies between fields that require type
-/// inference.
+/// Data structure for tracking dependencies among fields, getters, and setters
+/// that require type inference.
///
/// 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().
@@ -24,7 +24,7 @@ import 'package:kernel/type_algebra.dart';
class FieldNode extends dependencyWalker.Node<FieldNode> {
final TypeInferenceEngineImpl _typeInferenceEngine;
- final KernelField field;
+ final KernelMember member;
bool isImmediatelyEvident = false;
@@ -39,7 +39,7 @@ class FieldNode extends dependencyWalker.Node<FieldNode> {
final overrides = <Member>[];
- FieldNode(this._typeInferenceEngine, this.field);
+ FieldNode(this._typeInferenceEngine, this.member);
@override
bool get isEvaluated => state == FieldState.Inferred;
@@ -50,7 +50,7 @@ class FieldNode extends dependencyWalker.Node<FieldNode> {
}
@override
- String toString() => field.toString();
+ String toString() => member.toString();
}
/// Enum tracking the type inference state of a field.
@@ -87,7 +87,7 @@ abstract class TypeInferenceEngine {
/// Creates a [TypeInferrer] object which is ready to perform type inference
/// on the given [field].
TypeInferrer createTopLevelTypeInferrer(TypeInferenceListener listener,
- InterfaceType thisType, KernelField field);
+ InterfaceType thisType, KernelMember member);
/// Performs the second phase of top level initializer inference, which is to
/// visit all fields and top level variables that were passed to [recordField]
@@ -98,12 +98,12 @@ abstract class TypeInferenceEngine {
/// [hierarchy], using the given [coreTypes].
void prepareTopLevel(CoreTypes coreTypes, ClassHierarchy hierarchy);
- /// Records that the given [field] will need top level type inference.
- void recordField(KernelField field);
-
/// Records that the given initializing [formal] will need top level type
/// inference.
void recordInitializingFormal(KernelVariableDeclaration formal);
+
+ /// Records that the given [member] will need top level type inference.
+ void recordMember(KernelMember member);
}
/// Derived class containing generic implementations of
@@ -154,9 +154,6 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
TypeInferenceEngineImpl(this.instrumentation, this.strongMode);
- /// Clears the initializer of [field].
- void clearFieldInitializer(KernelField field);
-
/// Computes type inference dependencies for the given [field].
List<FieldNode> computeFieldDependencies(FieldNode fieldNode) {
// If the field's type is going to be determined by inheritance, then its
@@ -165,41 +162,47 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
var dependencies = <FieldNode>[];
for (var override in fieldNode.overrides) {
// TODO(paulberry): support dependencies on getters/setters too.
- if (override is Field) {
- dependencies.add(KernelField.getFieldNode(override));
- }
+ var dep = KernelMember.getFieldNode(override);
+ if (dep != null) dependencies.add(dep);
}
fieldNode.isImmediatelyEvident = true;
return dependencies;
}
// Otherwise its dependencies are based on the initializer expression.
- if (expandedTopLevelInference) {
- // 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);
- if (typeInferrer == null) {
- // This can happen when there are errors in the field declaration.
- return const [];
+ var member = fieldNode.member;
+ if (member is KernelField) {
+ if (expandedTopLevelInference) {
+ // 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(member);
+ if (typeInferrer == null) {
+ // This can happen when there are errors in the field declaration.
+ return const [];
+ } else {
+ typeInferrer.startDryRun();
+ typeInferrer.listener.dryRunEnter(member.initializer);
+ typeInferrer.inferFieldTopLevel(member, null, true);
+ typeInferrer.listener.dryRunExit(member.initializer);
+ fieldNode.isImmediatelyEvident = true;
+ return typeInferrer.finishDryRun();
+ }
} else {
- typeInferrer.startDryRun();
- typeInferrer.listener.dryRunEnter(fieldNode.field.initializer);
- typeInferrer.inferFieldTopLevel(fieldNode.field, null, true);
- typeInferrer.listener.dryRunExit(fieldNode.field.initializer);
- fieldNode.isImmediatelyEvident = true;
- return typeInferrer.finishDryRun();
+ // In non-expanded top level inference, we determine the dependencies by
+ // calling `collectDependencies`; as a side effect this flags any
+ // expressions that are not "immediately evident".
+ // TODO(paulberry): get rid of this mode once we are sure we no longer
+ // need it.
+ var collector = new KernelDependencyCollector();
+ collector.collectDependencies(member.initializer);
+ fieldNode.isImmediatelyEvident = collector.isImmediatelyEvident;
+ return collector.dependencies;
}
} else {
- // In non-expanded top level inference, we determine the dependencies by
- // calling `collectDependencies`; as a side effect this flags any
- // expressions that are not "immediately evident".
- // 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);
- fieldNode.isImmediatelyEvident = collector.isImmediatelyEvident;
- return collector.dependencies;
+ // Member is a getter/setter that doesn't override anything, so we can't
+ // infer a type for it; therefore it has no dependencies.
+ return const [];
}
}
@@ -222,29 +225,29 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
}
}
- /// Gets the character offset of the declaration of [field] within its
- /// compilation unit.
- int getFieldOffset(KernelField field);
-
- /// Retrieve the [TypeInferrer] for the given [field], which was created by
+ /// Retrieve the [TypeInferrer] for the given [member], which was created by
/// a previous call to [createTopLevelTypeInferrer].
- TypeInferrerImpl getFieldTypeInferrer(KernelField field);
+ TypeInferrerImpl getFieldTypeInferrer(KernelMember member);
/// Performs type inference on the given [field].
void inferField(FieldNode fieldNode) {
assert(fieldNode.state == FieldState.NotInferredYet);
fieldNode.state = FieldState.Inferring;
- var field = fieldNode.field;
+ var member = fieldNode.member;
if (strongMode) {
var inferredType = tryInferFieldByInheritance(fieldNode);
- var typeInferrer = getFieldTypeInferrer(field);
+ var typeInferrer = getFieldTypeInferrer(member);
if (inferredType == null) {
- typeInferrer.isImmediatelyEvident = true;
- inferredType = fieldNode.isImmediatelyEvident
- ? typeInferrer.inferDeclarationType(
- typeInferrer.inferFieldTopLevel(field, null, true))
- : const DynamicType();
- if (!typeInferrer.isImmediatelyEvident) {
+ if (member is KernelField) {
+ typeInferrer.isImmediatelyEvident = true;
+ inferredType = fieldNode.isImmediatelyEvident
+ ? typeInferrer.inferDeclarationType(
+ typeInferrer.inferFieldTopLevel(member, null, true))
+ : const DynamicType();
+ if (!typeInferrer.isImmediatelyEvident) {
+ inferredType = const DynamicType();
+ }
+ } else {
inferredType = const DynamicType();
}
}
@@ -253,12 +256,7 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
// inference for this node was completed.
return;
}
- instrumentation?.record(
- Uri.parse(typeInferrer.uri),
- getFieldOffset(field),
- 'topType',
- new InstrumentationValueForType(inferredType));
- field.type = inferredType;
+ member.setInferredType(this, typeInferrer.uri, inferredType);
}
fieldNode.state = FieldState.Inferred;
// TODO(paulberry): if type != null, then check that the type of the
@@ -266,20 +264,25 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
// 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);
+ if (member is KernelField) {
+ member.initializer = null;
+ }
}
/// Makes a note that the given [field] is part of a circularity, so its type
/// can't be inferred.
void inferFieldCircular(FieldNode fieldNode) {
- var field = fieldNode.field;
+ var member = fieldNode.member;
// 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));
+ var uri = getFieldTypeInferrer(member).uri;
fieldNode.state = FieldState.Inferred;
- field.type = inferredType;
+ member.setInferredType(this, uri, const DynamicType());
+ // 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.
+ if (member is KernelField) {
+ member.initializer = null;
+ }
}
/// Performs fused type inference on the given [field].
@@ -321,13 +324,13 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
}
@override
- void recordField(KernelField field) {
- fieldNodes.add(createFieldNode(field));
+ void recordInitializingFormal(KernelVariableDeclaration formal) {
+ initializingFormals.add(formal);
}
@override
- void recordInitializingFormal(KernelVariableDeclaration formal) {
- initializingFormals.add(formal);
+ void recordMember(KernelMember member) {
+ fieldNodes.add(createFieldNode(member));
}
DartType tryInferFieldByInheritance(FieldNode fieldNode) {
@@ -346,14 +349,14 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
}
DartType _computeOverriddenFieldType(Member override, FieldNode fieldNode) {
+ if (fusedTopLevelInference) {
+ FieldNode dependency = KernelMember.getFieldNode(override);
+ if (dependency != null) {
+ inferFieldFused(dependency, fieldNode);
+ }
+ }
DartType overriddenType;
if (override is Field) {
- if (fusedTopLevelInference) {
- FieldNode dependency = KernelField.getFieldNode(override);
- if (dependency != null) {
- inferFieldFused(dependency, fieldNode);
- }
- }
overriddenType = override.type;
} else if (override is Procedure) {
// TODO(paulberry): handle the case where override needs its type
@@ -369,7 +372,7 @@ abstract class TypeInferenceEngineImpl extends TypeInferenceEngine {
}
var superclass = override.enclosingClass;
if (superclass.typeParameters.isEmpty) return overriddenType;
- var thisClass = fieldNode.field.enclosingClass;
+ var thisClass = fieldNode.member.enclosingClass;
var superclassInstantiation = classHierarchy
.getClassAsInstanceOf(thisClass, superclass)
.asInterfaceType;

Powered by Google App Engine
This is Rietveld 408576698