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

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

Issue 2830313002: Split up TypeInferrer class. (Closed)
Patch Set: 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
« no previous file with comments | « pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:front_end/src/dependency_walker.dart' as dependencyWalker; 6 import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
7 import 'package:kernel/ast.dart' show DartType, DynamicType, Member; 7 import 'package:kernel/ast.dart' show DartType, Member;
8 import 'package:kernel/class_hierarchy.dart';
9 import 'package:kernel/core_types.dart'; 8 import 'package:kernel/core_types.dart';
10 9
11 /// Data structure for tracking dependencies between fields that require type 10 /// Keeps track of the local state for the type inference that occurs during
12 /// inference. 11 /// compilation of a single method body or top level initializer.
13 /// 12 ///
14 /// TODO(paulberry): see if it's possible to make this class more lightweight 13 /// This class abstracts away the representation of the underlying AST using
15 /// by changing the API so that the walker is passed to computeDependencies(). 14 /// generic parameters. TODO(paulberry): would it make more sense to abstract
16 /// (This should allow us to drop the _typeInferrer field). 15 /// away the representation of types as well?
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
35 /// Abstract implementation of type inference which is independent of the
36 /// underlying AST representation (but still uses DartType from kernel).
37 ///
38 /// TODO(paulberry): would it make more sense to abstract away the
39 /// representation of types as well?
40 /// 16 ///
41 /// Derived classes should set S, E, V, and F to the class they use to represent 17 /// Derived classes should set S, E, V, and F to the class they use to represent
42 /// statements, expressions, variable declarations, and field declarations, 18 /// statements, expressions, variable declarations, and field declarations,
43 /// respectively. 19 /// respectively.
20 ///
21 /// This class describes the interface for use by clients of type inference
22 /// (e.g. BodyBuilder). Derived classes should derive from [TypeInferrerImpl].
44 abstract class TypeInferrer<S, E, V, F> { 23 abstract class TypeInferrer<S, E, V, F> {
45 final Instrumentation instrumentation; 24 /// The URI of the code for which type inference is currently being
25 /// performed--this is used for testing.
26 String get uri;
27
28 /// Gets the [FieldNode] corresponding to the given [readTarget], if any.
29 FieldNode<F> getFieldNodeForReadTarget(Member readTarget);
30
31 /// Performs type inference on the given [statement].
32 ///
33 /// Derived classes should override this method with logic that dispatches on
34 /// the statement type and calls the appropriate specialized "infer" method.
35 void inferStatement(S statement);
36 }
37
38 /// Derived class containing generic implementations of [TypeInferrerImpl].
39 ///
40 /// This class contains as much of the implementation of type inference as
41 /// possible without knowing the identity of the type parameters. It defers to
42 /// abstract methods for everything else.
43 abstract class TypeInferrerImpl<S, E, V, F> extends TypeInferrer<S, E, V, F> {
44 @override
45 final String uri;
46
47 /// Indicates whether the construct we are currently performing inference for
48 /// is outside of a method body, and hence top level type inference rules
49 /// should apply.
50 final bool isTopLevel = false;
51
52 final CoreTypes coreTypes;
46 53
47 final bool strongMode; 54 final bool strongMode;
48 55
49 final fieldNodes = <FieldNode<F>>[]; 56 final Instrumentation instrumentation;
50 57
51 CoreTypes coreTypes; 58 TypeInferrerImpl(TypeInferenceEngineImpl<F> engine, this.uri)
52 59 : coreTypes = engine.coreTypes,
53 ClassHierarchy classHierarchy; 60 strongMode = engine.strongMode,
54 61 instrumentation = engine.instrumentation;
55 /// The URI of the code for which type inference is currently being
56 /// performed--this is used for testing.
57 String uri;
58
59 /// Indicates whether we are currently performing top level inference.
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 `null` if the type is
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 62
78 /// Gets the initializer for the given [field], or `null` if there is no 63 /// Gets the initializer for the given [field], or `null` if there is no
79 /// initializer. 64 /// initializer.
80 E getFieldInitializer(F field); 65 E getFieldInitializer(F field);
81 66
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);
91
92 /// Performs type inference on a method with the given method [body].
93 ///
94 /// [uri] is the URI of the file the method is contained in--this is used for
95 /// testing.
96 void inferBody(S body, Uri uri) {
97 this.uri = uri.toString();
98 inferStatement(body);
99 }
100
101 /// Performs type inference on the given [expression]. 67 /// Performs type inference on the given [expression].
102 /// 68 ///
103 /// [typeContext] is the expected type of the expression, based on surrounding 69 /// [typeContext] is the expected type of the expression, based on surrounding
104 /// code. [typeNeeded] indicates whether it is necessary to compute the 70 /// code. [typeNeeded] indicates whether it is necessary to compute the
105 /// actual type of the expression. If [typeNeeded] is `true`, the actual type 71 /// actual type of the expression. If [typeNeeded] is `true`, the actual type
106 /// of the expression is returned; otherwise `null` is returned. 72 /// of the expression is returned; otherwise `null` is returned.
107 /// 73 ///
108 /// Derived classes should override this method with logic that dispatches on 74 /// Derived classes should override this method with logic that dispatches on
109 /// the expression type and calls the appropriate specialized "infer" method. 75 /// the expression type and calls the appropriate specialized "infer" method.
110 DartType inferExpression(E expression, DartType typeContext, bool typeNeeded); 76 DartType inferExpression(E expression, DartType typeContext, bool typeNeeded);
111 77
112 /// Performs type inference on the given [field]. 78 /// Performs type inference on the given [field]'s initializer expression.
113 void inferField(F field) { 79 ///
114 var initializer = getFieldInitializer(field); 80 /// Derived classes should provide an implementation that calls
115 if (initializer != null) { 81 /// [inferExpression] for the given [field]'s initializer expression.
116 var type = getFieldDeclaredType(field); 82 DartType inferFieldInitializer(F field, DartType type, bool typeNeeded);
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): if type != null, then check that the type of the
129 // initializer is assignable to it.
130 // TODO(paulberry): the following is a hack so that outlines don't contain
131 // initializers. But it means that we rebuild the initializers when doing
132 // a full compile. There should be a better way.
133 clearFieldInitializer(field);
134 }
135 }
136
137 /// Makes a note that the given [field] is part of a circularity, so its type
138 /// can't be inferred.
139 void inferFieldCircular(F field) {
140 // TODO(paulberry): report the appropriate error.
141 if (getFieldDeclaredType(field) == null) {
142 var uri = getFieldUri(field);
143 instrumentation?.record('topType', Uri.parse(uri), getFieldOffset(field),
144 const InstrumentationValueLiteral('circular'));
145 setFieldInferredType(field, const DynamicType());
146 }
147 }
148 83
149 /// Performs the core type inference algorithm for integer literals. 84 /// Performs the core type inference algorithm for integer literals.
150 /// 85 ///
151 /// [typeContext], [typeNeeded], and the return value behave as described in 86 /// [typeContext], [typeNeeded], and the return value behave as described in
152 /// [inferExpression]. 87 /// [inferExpression].
153 DartType inferIntLiteral(DartType typeContext, bool typeNeeded) { 88 DartType inferIntLiteral(DartType typeContext, bool typeNeeded) {
154 return typeNeeded ? coreTypes.intClass.rawType : null; 89 return typeNeeded ? coreTypes.intClass.rawType : null;
155 } 90 }
156 91
157 /// Performs type inference on the given [statement].
158 ///
159 /// Derived classes should override this method with logic that dispatches on
160 /// the statement type and calls the appropriate specialized "infer" method.
161 void inferStatement(S statement);
162
163 /// Performs the core type inference algorithm for static variable getters. 92 /// Performs the core type inference algorithm for static variable getters.
164 /// 93 ///
165 /// [typeContext], [typeNeeded], and the return value behave as described in 94 /// [typeContext], [typeNeeded], and the return value behave as described in
166 /// [inferExpression]. 95 /// [inferExpression].
167 /// 96 ///
168 /// [getterType] is the type of the field being referenced, or the return type 97 /// [getterType] is the type of the field being referenced, or the return type
169 /// of the getter. 98 /// of the getter.
170 DartType inferStaticGet( 99 DartType inferStaticGet(
171 DartType typeContext, bool typeNeeded, DartType getterType) { 100 DartType typeContext, bool typeNeeded, DartType getterType) {
172 return typeNeeded ? getterType : null; 101 return typeNeeded ? getterType : null;
(...skipping 10 matching lines...) Expand all
183 int offset, void setType(DartType type)) { 112 int offset, void setType(DartType type)) {
184 if (initializer == null) return; 113 if (initializer == null) return;
185 var inferredType = 114 var inferredType =
186 inferExpression(initializer, declaredType, declaredType == null); 115 inferExpression(initializer, declaredType, declaredType == null);
187 if (strongMode && declaredType == null) { 116 if (strongMode && declaredType == null) {
188 instrumentation?.record('type', Uri.parse(uri), offset, 117 instrumentation?.record('type', Uri.parse(uri), offset,
189 new InstrumentationValueForType(inferredType)); 118 new InstrumentationValueForType(inferredType));
190 setType(inferredType); 119 setType(inferredType);
191 } 120 }
192 } 121 }
193
194 /// Determines if top level type inference has been completed for [field].
195 bool isFieldInferred(F field);
196
197 /// Performs top level type inference for all fields that have been passed to
198 /// [recordField].
199 void performInitializerInference() {
200 for (var fieldNode in fieldNodes) {
201 if (fieldNode.isEvaluated) continue;
202 new _FieldWalker<F>().walk(fieldNode);
203 }
204 }
205
206 /// Records that the given [field] will need top level type inference.
207 void recordField(F field) {
208 fieldNodes.add(createFieldNode(field));
209 }
210
211 /// Stores [inferredType] as the inferred type of [field].
212 void setFieldInferredType(F field, DartType inferredType);
213 } 122 }
214
215 /// Subtype of [dependencyWalker.DependencyWalker] which is specialized to
216 /// perform top level type inference.
217 class _FieldWalker<F> extends dependencyWalker.DependencyWalker<FieldNode<F>> {
218 _FieldWalker();
219
220 @override
221 void evaluate(FieldNode<F> f) {
222 f._typeInferrer.inferField(f._field);
223 }
224
225 @override
226 void evaluateScc(List<FieldNode<F>> scc) {
227 for (var f in scc) {
228 f._typeInferrer.inferFieldCircular(f._field);
229 }
230 for (var f in scc) {
231 f._typeInferrer.inferField(f._field);
232 }
233 }
234 }
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698