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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file. 3 // BSD-style license that can be found in the LICENSE.md file.
4 4
5 import 'package:front_end/src/base/instrumentation.dart'; 5 import 'package:front_end/src/base/instrumentation.dart';
6 import 'package:kernel/ast.dart' show DartType; 6 import 'package:front_end/src/dependency_walker.dart' as dependencyWalker;
7 import 'package:kernel/ast.dart' show DartType, DynamicType, Member;
7 import 'package:kernel/class_hierarchy.dart'; 8 import 'package:kernel/class_hierarchy.dart';
8 import 'package:kernel/core_types.dart'; 9 import 'package:kernel/core_types.dart';
9 10
11 /// Data structure for tracking dependencies between fields that require type
12 /// inference.
13 ///
14 /// TODO(paulberry): see if it's possible to make this class more lightweight
15 /// by changing the API so that the walker is passed to computeDependencies().
16 /// (This should allow us to drop the _typeInferrer field).
17 class FieldNode<F> extends dependencyWalker.Node<FieldNode<F>> {
18 final TypeInferrer _typeInferrer;
19
20 final F _field;
21
22 final dependencies = <FieldNode<F>>[];
23
24 FieldNode(this._typeInferrer, this._field);
25
26 @override
27 bool get isEvaluated => _typeInferrer.isFieldInferred(_field);
28
29 @override
30 List<FieldNode<F>> computeDependencies() {
31 return dependencies;
32 }
33 }
34
10 /// Abstract implementation of type inference which is independent of the 35 /// Abstract implementation of type inference which is independent of the
11 /// underlying AST representation (but still uses DartType from kernel). 36 /// underlying AST representation (but still uses DartType from kernel).
12 /// 37 ///
13 /// TODO(paulberry): would it make more sense to abstract away the 38 /// TODO(paulberry): would it make more sense to abstract away the
14 /// representation of types as well? 39 /// representation of types as well?
15 /// 40 ///
16 /// Derived classes should set S, E, V, and F to the class they use to represent 41 /// Derived classes should set S, E, V, and F to the class they use to represent
17 /// statements, expressions, variable declarations, and field declarations, 42 /// statements, expressions, variable declarations, and field declarations,
18 /// respectively. 43 /// respectively.
19 abstract class TypeInferrer<S, E, V, F> { 44 abstract class TypeInferrer<S, E, V, F> {
20 final CoreTypes coreTypes;
21
22 final ClassHierarchy classHierarchy;
23
24 final Instrumentation instrumentation; 45 final Instrumentation instrumentation;
25 46
26 final bool strongMode; 47 final bool strongMode;
27 48
49 final fieldNodes = <FieldNode<F>>[];
50
51 CoreTypes coreTypes;
52
53 ClassHierarchy classHierarchy;
54
28 /// The URI of the code for which type inference is currently being 55 /// The URI of the code for which type inference is currently being
29 /// performed--this is used for testing. 56 /// performed--this is used for testing.
30 Uri uri; 57 String uri;
31 58
32 TypeInferrer(this.coreTypes, this.classHierarchy, this.instrumentation, 59 /// Indicates whether we are currently performing top level inference.
33 this.strongMode); 60 bool isTopLevel = false;
61
62 TypeInferrer(this.instrumentation, this.strongMode);
63
64 /// Cleares the initializer of [field].
65 void clearFieldInitializer(F field);
66
67 /// Creates a [FieldNode] to track dependencies of the given [field].
68 FieldNode<F> createFieldNode(F field);
69
70 /// 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.
71 /// implicit.
72 DartType getFieldDeclaredType(F field);
73
74 /// Gets the list of top level type inference dependencies of the given
75 /// [field].
76 List<FieldNode<F>> getFieldDependencies(F field);
77
78 /// Gets the initializer for the given [field], or `null` if there is no
79 /// initializer.
80 E getFieldInitializer(F field);
81
82 /// Gets the [FieldNode] corresponding to the given [readTarget], if any.
83 FieldNode<F> getFieldNodeForReadTarget(Member readTarget);
84
85 /// Gets the character offset of the declaration of [field] within its
86 /// compilation unit.
87 int getFieldOffset(F field);
88
89 /// Gets the URI of the compilation unit the [field] is declared in.
90 String getFieldUri(F field);
34 91
35 /// Performs type inference on a method with the given method [body]. 92 /// Performs type inference on a method with the given method [body].
36 /// 93 ///
37 /// [uri] is the URI of the file the method is contained in--this is used for 94 /// [uri] is the URI of the file the method is contained in--this is used for
38 /// testing. 95 /// testing.
39 void inferBody(S body, Uri uri) { 96 void inferBody(S body, Uri uri) {
40 this.uri = uri; 97 this.uri = uri.toString();
41 inferStatement(body); 98 inferStatement(body);
42 } 99 }
43 100
44 /// Performs type inference on the given [expression]. 101 /// Performs type inference on the given [expression].
45 /// 102 ///
46 /// [typeContext] is the expected type of the expression, based on surrounding 103 /// [typeContext] is the expected type of the expression, based on surrounding
47 /// code. [typeNeeded] indicates whether it is necessary to compute the 104 /// code. [typeNeeded] indicates whether it is necessary to compute the
48 /// actual type of the expression. If [typeNeeded] is `true`, the actual type 105 /// actual type of the expression. If [typeNeeded] is `true`, the actual type
49 /// of the expression is returned; otherwise `null` is returned. 106 /// of the expression is returned; otherwise `null` is returned.
50 /// 107 ///
51 /// Derived classes should override this method with logic that dispatches on 108 /// Derived classes should override this method with logic that dispatches on
52 /// the expression type and calls the appropriate specialized "infer" method. 109 /// the expression type and calls the appropriate specialized "infer" method.
53 DartType inferExpression(E expression, DartType typeContext, bool typeNeeded); 110 DartType inferExpression(E expression, DartType typeContext, bool typeNeeded);
54 111
112 /// Performs type inference on the given [field].
113 void inferField(F field) {
114 var initializer = getFieldInitializer(field);
115 if (initializer != null) {
116 var type = getFieldDeclaredType(field);
117 uri = getFieldUri(field);
118 isTopLevel = true;
119 var inferredType = inferExpression(initializer, type, type == null);
120 if (type == null && strongMode) {
121 instrumentation?.record(
122 'topType',
123 Uri.parse(uri),
124 getFieldOffset(field),
125 new InstrumentationValueForType(inferredType));
126 setFieldInferredType(field, inferredType);
127 }
128 // TODO(paulberry): the following is a hack so that outlines don't contain
129 // initializers. But it means that we rebuild the initializers when doing
130 // a full compile. There should be a better way.
131 clearFieldInitializer(field);
132 }
133 }
134
135 /// Makes a note that the given [field] is part of a circularity, so its type
136 /// can't be inferred.
137 void inferFieldCircular(F field) {
138 // TODO(paulberry): report the appropriate error.
139 if (getFieldDeclaredType(field) == null) {
140 var uri = getFieldUri(field);
141 instrumentation?.record('topType', Uri.parse(uri), getFieldOffset(field),
142 const InstrumentationValueLiteral('circular'));
143 setFieldInferredType(field, const DynamicType());
144 }
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
145 }
146
55 /// Performs the core type inference algorithm for integer literals. 147 /// Performs the core type inference algorithm for integer literals.
56 /// 148 ///
57 /// [typeContext], [typeNeeded], and the return value behave as described in 149 /// [typeContext], [typeNeeded], and the return value behave as described in
58 /// [inferExpression]. 150 /// [inferExpression].
59 DartType inferIntLiteral(DartType typeContext, bool typeNeeded) { 151 DartType inferIntLiteral(DartType typeContext, bool typeNeeded) {
60 return typeNeeded ? coreTypes.intClass.rawType : null; 152 return typeNeeded ? coreTypes.intClass.rawType : null;
61 } 153 }
62 154
63 /// Performs type inference on the given [statement]. 155 /// Performs type inference on the given [statement].
64 /// 156 ///
65 /// Derived classes should override this method with logic that dispatches on 157 /// Derived classes should override this method with logic that dispatches on
66 /// the statement type and calls the appropriate specialized "infer" method. 158 /// the statement type and calls the appropriate specialized "infer" method.
67 void inferStatement(S statement); 159 void inferStatement(S statement);
68 160
161 /// Performs the core type inference algorithm for static variable getters.
162 ///
163 /// [typeContext], [typeNeeded], and the return value behave as described in
164 /// [inferExpression].
165 ///
166 /// [getterType] is the type of the field being referenced, or the return type
167 /// of the getter.
168 DartType inferStaticGet(
169 DartType typeContext, bool typeNeeded, DartType getterType) {
170 return typeNeeded ? getterType : null;
171 }
172
69 /// Performs the core type inference algorithm for variable declarations. 173 /// Performs the core type inference algorithm for variable declarations.
70 /// 174 ///
71 /// [declaredType] is the declared type of the variable, or `null` if the type 175 /// [declaredType] is the declared type of the variable, or `null` if the type
72 /// should be inferred. [initializer] is the initializer expression. 176 /// should be inferred. [initializer] is the initializer expression.
73 /// [offset] is the character offset of the variable declaration (for 177 /// [offset] is the character offset of the variable declaration (for
74 /// instrumentation). [setType] is a callback that will be used to set the 178 /// instrumentation). [setType] is a callback that will be used to set the
75 /// inferred type. 179 /// inferred type.
76 void inferVariableDeclaration(DartType declaredType, E initializer, 180 void inferVariableDeclaration(DartType declaredType, E initializer,
77 int offset, void setType(DartType type)) { 181 int offset, void setType(DartType type)) {
78 if (initializer == null) return; 182 if (initializer == null) return;
79 var inferredType = 183 var inferredType =
80 inferExpression(initializer, declaredType, declaredType == null); 184 inferExpression(initializer, declaredType, declaredType == null);
81 if (strongMode && declaredType == null) { 185 if (strongMode && declaredType == null) {
82 instrumentation?.record( 186 instrumentation?.record('type', Uri.parse(uri), offset,
83 'type', uri, offset, new InstrumentationValueForType(inferredType)); 187 new InstrumentationValueForType(inferredType));
84 setType(inferredType); 188 setType(inferredType);
85 } 189 }
86 } 190 }
191
192 /// 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.
193 /// yet.
194 bool isFieldInferred(F field);
195
196 /// Performs top level type inference for all fields that have been passed to
197 /// [recordField].
198 void performInitializerInference() {
199 for (var fieldNode in fieldNodes) {
200 if (fieldNode.isEvaluated) continue;
201 new _FieldWalker<F>().walk(fieldNode);
202 }
203 }
204
205 /// Records that the given [field] will need top level type inference.
206 void recordField(F field) {
207 fieldNodes.add(createFieldNode(field));
208 }
209
210 /// Stores [inferredType] as the inferred type of [field].
211 void setFieldInferredType(F field, DartType inferredType);
87 } 212 }
213
214 /// Subtype of [dependencyWalker.DependencyWalker] which is specialized to
215 /// perform top level type inference.
216 class _FieldWalker<F> extends dependencyWalker.DependencyWalker<FieldNode<F>> {
217 _FieldWalker();
218
219 @override
220 void evaluate(FieldNode<F> f) {
221 f._typeInferrer.inferField(f._field);
222 }
223
224 @override
225 void evaluateScc(List<FieldNode<F>> scc) {
226 for (var f in scc) {
227 f._typeInferrer.inferFieldCircular(f._field);
228 }
229 for (var f in scc) {
230 f._typeInferrer.inferField(f._field);
231 }
232 }
233 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698