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

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

Issue 2828253003: Add top level type inference logic for integer literals. (Closed)
Patch Set: Clean up, bug fix, and remove unintentional expectations changes Created 3 years, 8 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_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 b7fc20688edb94a371bcabb89d8b83f0fb15c2a6..70a4d54ba8a01e432c3c5de594a4e2a533b21e97 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,10 +3,35 @@
// BSD-style license that can be found in the LICENSE.md file.
import 'package:front_end/src/base/instrumentation.dart';
-import 'package:kernel/ast.dart' show DartType;
+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:kernel/core_types.dart';
+/// Data structure for tracking dependencies between fields 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().
+/// (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).
///
@@ -17,27 +42,59 @@ import 'package:kernel/core_types.dart';
/// statements, expressions, variable declarations, and field declarations,
/// respectively.
abstract class TypeInferrer<S, E, V, F> {
- final CoreTypes coreTypes;
-
- final ClassHierarchy classHierarchy;
-
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.
- Uri uri;
+ String uri;
+
+ /// Indicates whether we are currently performing top level inference.
+ bool isTopLevel = false;
+
+ TypeInferrer(this.instrumentation, this.strongMode);
+
+ /// Cleares the initializer of [field].
+ void clearFieldInitializer(F field);
+
+ /// Creates a [FieldNode] to track dependencies of the given [field].
+ FieldNode<F> createFieldNode(F field);
+
+ /// Gets the declared type of the given [field], or `nul` if the type is
karlklose 2017/04/21 11:11:01 'nul' -> 'null'.
Paul Berry 2017/04/21 11:32:25 Done.
+ /// implicit.
+ DartType getFieldDeclaredType(F field);
- TypeInferrer(this.coreTypes, this.classHierarchy, this.instrumentation,
- this.strongMode);
+ /// Gets the list of top level type inference dependencies of the given
+ /// [field].
+ List<FieldNode<F>> getFieldDependencies(F field);
+
+ /// 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;
+ this.uri = uri.toString();
inferStatement(body);
}
@@ -52,6 +109,41 @@ 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): 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());
+ }
karlklose 2017/04/21 11:11:01 Add an TODO to do type-checking.
Paul Berry 2017/04/21 11:32:25 Done. (Actually the comment belongs in inferField
+ }
+
/// Performs the core type inference algorithm for integer literals.
///
/// [typeContext], [typeNeeded], and the return value behave as described in
@@ -66,6 +158,18 @@ abstract class TypeInferrer<S, E, V, F> {
/// 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
+ /// [inferExpression].
+ ///
+ /// [getterType] is the type of the field being referenced, or the return type
+ /// of the getter.
+ DartType inferStaticGet(
+ DartType typeContext, bool typeNeeded, DartType getterType) {
+ return typeNeeded ? getterType : null;
+ }
+
/// Performs the core type inference algorithm for variable declarations.
///
/// [declaredType] is the declared type of the variable, or `null` if the type
@@ -79,9 +183,51 @@ abstract class TypeInferrer<S, E, V, F> {
var inferredType =
inferExpression(initializer, declaredType, declaredType == null);
if (strongMode && declaredType == null) {
- instrumentation?.record(
- 'type', uri, offset, new InstrumentationValueForType(inferredType));
+ instrumentation?.record('type', Uri.parse(uri), offset,
+ new InstrumentationValueForType(inferredType));
setType(inferredType);
}
}
+
+ /// Determines if the given [field] has completed top level type inference
karlklose 2017/04/21 11:11:01 Rephrase it as 'Determines if top level type infer
Paul Berry 2017/04/21 11:32:26 Done.
+ /// yet.
+ 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);
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698