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