OLD | NEW |
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 file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/names.dart'; | 8 import '../common/names.dart'; |
9 import '../compiler.dart'; | 9 import '../compiler.dart'; |
10 import '../constants/expressions.dart'; | |
11 import '../constants/values.dart'; | |
12 import '../common_elements.dart'; | 10 import '../common_elements.dart'; |
13 import '../elements/elements.dart'; | 11 import '../elements/elements.dart' |
| 12 show |
| 13 ClassElement, |
| 14 ConstructorElement, |
| 15 Elements, |
| 16 MemberElement, |
| 17 ParameterElement; |
14 import '../elements/entities.dart'; | 18 import '../elements/entities.dart'; |
15 import '../elements/names.dart'; | 19 import '../elements/names.dart'; |
16 import '../js_backend/annotations.dart'; | 20 import '../js_backend/annotations.dart'; |
17 import '../js_backend/js_backend.dart'; | 21 import '../js_backend/js_backend.dart'; |
18 import '../native/behavior.dart' as native; | 22 import '../native/behavior.dart' as native; |
19 import '../resolution/tree_elements.dart'; | |
20 import '../tree/nodes.dart' as ast; | |
21 import '../types/constants.dart'; | |
22 import '../types/types.dart'; | 23 import '../types/types.dart'; |
23 import '../universe/call_structure.dart'; | 24 import '../universe/call_structure.dart'; |
24 import '../universe/selector.dart'; | 25 import '../universe/selector.dart'; |
25 import '../universe/side_effects.dart'; | 26 import '../universe/side_effects.dart'; |
26 import '../util/util.dart'; | |
27 import '../world.dart'; | 27 import '../world.dart'; |
28 import 'closure_tracer.dart'; | |
29 import 'debug.dart' as debug; | 28 import 'debug.dart' as debug; |
30 import 'locals_handler.dart'; | 29 import 'locals_handler.dart'; |
31 import 'list_tracer.dart'; | 30 import 'list_tracer.dart'; |
32 import 'map_tracer.dart'; | 31 import 'map_tracer.dart'; |
33 import 'builder.dart'; | 32 import 'builder.dart'; |
34 import 'builder_kernel.dart'; | |
35 import 'type_graph_dump.dart'; | |
36 import 'type_graph_inferrer.dart'; | 33 import 'type_graph_inferrer.dart'; |
37 import 'type_graph_nodes.dart'; | 34 import 'type_graph_nodes.dart'; |
38 import 'type_system.dart'; | 35 import 'type_system.dart'; |
39 | 36 |
40 /// An inferencing engine that computes a call graph of [TypeInformation] nodes | 37 /// An inferencing engine that computes a call graph of [TypeInformation] nodes |
41 /// by visiting the AST of the application, and then does the inferencing on the | 38 /// by visiting the AST of the application, and then does the inferencing on the |
42 /// graph. | 39 /// graph. |
43 abstract class InferrerEngine { | 40 abstract class InferrerEngine<T> { |
44 /// A set of selector names that [List] implements, that we know return their | 41 /// A set of selector names that [List] implements, that we know return their |
45 /// element type. | 42 /// element type. |
46 final Set<Selector> returnsListElementTypeSet = | 43 final Set<Selector> returnsListElementTypeSet = |
47 new Set<Selector>.from(<Selector>[ | 44 new Set<Selector>.from(<Selector>[ |
48 new Selector.getter(const PublicName('first')), | 45 new Selector.getter(const PublicName('first')), |
49 new Selector.getter(const PublicName('last')), | 46 new Selector.getter(const PublicName('last')), |
50 new Selector.getter(const PublicName('single')), | 47 new Selector.getter(const PublicName('single')), |
51 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), | 48 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), |
52 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), | 49 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), |
53 new Selector.index(), | 50 new Selector.index(), |
54 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), | 51 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), |
55 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) | 52 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) |
56 ]); | 53 ]); |
57 | 54 |
58 Compiler get compiler; | 55 Compiler get compiler; |
59 ClosedWorld get closedWorld; | 56 ClosedWorld get closedWorld; |
60 ClosedWorldRefiner get closedWorldRefiner; | 57 ClosedWorldRefiner get closedWorldRefiner; |
61 JavaScriptBackend get backend => compiler.backend; | 58 JavaScriptBackend get backend => compiler.backend; |
62 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; | 59 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; |
63 DiagnosticReporter get reporter => compiler.reporter; | 60 DiagnosticReporter get reporter => compiler.reporter; |
64 CommonMasks get commonMasks => closedWorld.commonMasks; | 61 CommonMasks get commonMasks => closedWorld.commonMasks; |
65 CommonElements get commonElements => closedWorld.commonElements; | 62 CommonElements get commonElements => closedWorld.commonElements; |
66 | 63 |
67 TypeSystem<ast.Node> get types; | 64 TypeSystem<T> get types; |
68 Map<ast.Node, TypeInformation> get concreteTypes; | 65 Map<T, TypeInformation> get concreteTypes; |
69 | 66 |
70 /// Parallel structure for concreteTypes. | 67 /// Parallel structure for concreteTypes. |
71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by | 68 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by |
72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. | 69 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. |
73 Map<ir.Node, TypeInformation> get concreteKernelTypes; | 70 Map<ir.Node, TypeInformation> get concreteKernelTypes; |
74 | 71 |
75 FunctionEntity get mainElement; | 72 FunctionEntity get mainElement; |
76 | 73 |
77 void runOverAllElements(); | 74 void runOverAllElements(); |
78 | 75 |
79 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments); | 76 void analyze(MemberEntity member, T node, ArgumentsTypes arguments); |
80 void analyzeListAndEnqueue(ListTypeInformation info); | 77 void analyzeListAndEnqueue(ListTypeInformation info); |
81 void analyzeMapAndEnqueue(MapTypeInformation info); | 78 void analyzeMapAndEnqueue(MapTypeInformation info); |
82 | 79 |
83 /// Notifies to the inferrer that [analyzedElement] can have return type | 80 /// Notifies to the inferrer that [analyzedElement] can have return type |
84 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently | 81 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently |
85 /// found. | 82 /// found. |
86 /// | 83 /// |
87 /// Returns the new type for [analyzedElement]. | 84 /// Returns the new type for [analyzedElement]. |
88 TypeInformation addReturnTypeForMethod( | 85 TypeInformation addReturnTypeForMethod( |
89 FunctionEntity element, TypeInformation unused, TypeInformation newType); | 86 FunctionEntity element, TypeInformation unused, TypeInformation newType); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 void recordExposesThis(ConstructorEntity element, bool exposesThis); | 126 void recordExposesThis(ConstructorEntity element, bool exposesThis); |
130 | 127 |
131 /// Records that the return type [element] is of type [type]. | 128 /// Records that the return type [element] is of type [type]. |
132 void recordReturnType(FunctionEntity element, TypeInformation type); | 129 void recordReturnType(FunctionEntity element, TypeInformation type); |
133 | 130 |
134 /// Records that [element] is of type [type]. | 131 /// Records that [element] is of type [type]. |
135 void recordTypeOfField(FieldEntity element, TypeInformation type); | 132 void recordTypeOfField(FieldEntity element, TypeInformation type); |
136 | 133 |
137 /// Registers a call to await with an expression of type [argumentType] as | 134 /// Registers a call to await with an expression of type [argumentType] as |
138 /// argument. | 135 /// argument. |
139 TypeInformation registerAwait(ast.Node node, TypeInformation argument); | 136 TypeInformation registerAwait(T node, TypeInformation argument); |
140 | 137 |
141 /// Registers a call to yield with an expression of type [argumentType] as | 138 /// Registers a call to yield with an expression of type [argumentType] as |
142 /// argument. | 139 /// argument. |
143 TypeInformation registerYield(ast.Node node, TypeInformation argument); | 140 TypeInformation registerYield(T node, TypeInformation argument); |
144 | 141 |
145 /// Registers that [caller] calls [closure] with [arguments]. | 142 /// Registers that [caller] calls [closure] with [arguments]. |
146 /// | 143 /// |
147 /// [sideEffects] will be updated to incorporate the potential callees' side | 144 /// [sideEffects] will be updated to incorporate the potential callees' side |
148 /// effects. | 145 /// effects. |
149 /// | 146 /// |
150 /// [inLoop] tells whether the call happens in a loop. | 147 /// [inLoop] tells whether the call happens in a loop. |
151 TypeInformation registerCalledClosure( | 148 TypeInformation registerCalledClosure( |
152 ast.Node node, | 149 T node, |
153 Selector selector, | 150 Selector selector, |
154 TypeMask mask, | 151 TypeMask mask, |
155 TypeInformation closure, | 152 TypeInformation closure, |
156 MemberEntity caller, | 153 MemberEntity caller, |
157 ArgumentsTypes arguments, | 154 ArgumentsTypes arguments, |
158 SideEffects sideEffects, | 155 SideEffects sideEffects, |
159 bool inLoop); | 156 bool inLoop); |
160 | 157 |
161 /// Registers that [caller] calls [callee] at location [node], with | 158 /// Registers that [caller] calls [callee] at location [node], with |
162 /// [selector], and [arguments]. Note that [selector] is null for forwarding | 159 /// [selector], and [arguments]. Note that [selector] is null for forwarding |
(...skipping 14 matching lines...) Expand all Loading... |
177 | 174 |
178 /// Registers that [caller] calls [selector] with [receiverType] as receiver, | 175 /// Registers that [caller] calls [selector] with [receiverType] as receiver, |
179 /// and [arguments]. | 176 /// and [arguments]. |
180 /// | 177 /// |
181 /// [sideEffects] will be updated to incorporate the potential callees' side | 178 /// [sideEffects] will be updated to incorporate the potential callees' side |
182 /// effects. | 179 /// effects. |
183 /// | 180 /// |
184 /// [inLoop] tells whether the call happens in a loop. | 181 /// [inLoop] tells whether the call happens in a loop. |
185 TypeInformation registerCalledSelector( | 182 TypeInformation registerCalledSelector( |
186 CallType callType, | 183 CallType callType, |
187 ast.Node node, | 184 T node, |
188 Selector selector, | 185 Selector selector, |
189 TypeMask mask, | 186 TypeMask mask, |
190 TypeInformation receiverType, | 187 TypeInformation receiverType, |
191 MemberEntity caller, | 188 MemberEntity caller, |
192 ArgumentsTypes arguments, | 189 ArgumentsTypes arguments, |
193 SideEffects sideEffects, | 190 SideEffects sideEffects, |
194 bool inLoop, | 191 bool inLoop, |
195 bool isConditional); | 192 bool isConditional); |
196 | 193 |
197 /// Update the assignments to parameters in the graph. [remove] tells whether | 194 /// Update the assignments to parameters in the graph. [remove] tells whether |
198 /// assignments must be added or removed. If [init] is false, parameters are | 195 /// assignments must be added or removed. If [init] is false, parameters are |
199 /// added to the work queue. | 196 /// added to the work queue. |
200 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 197 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
201 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 198 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
202 {bool remove, bool addToQueue: true}); | 199 {bool remove, bool addToQueue: true}); |
203 | 200 |
204 void updateSelectorInMember(MemberEntity owner, CallType callType, | 201 void updateSelectorInMember(MemberEntity owner, CallType callType, T node, |
205 ast.Node node, Selector selector, TypeMask mask); | 202 Selector selector, TypeMask mask); |
206 | 203 |
207 /// Returns the return type of [element]. | 204 /// Returns the return type of [element]. |
208 TypeInformation returnTypeOfMember(MemberEntity element); | 205 TypeInformation returnTypeOfMember(MemberEntity element); |
209 | 206 |
210 /// Returns the type of [element] when being called with [selector]. | 207 /// Returns the type of [element] when being called with [selector]. |
211 TypeInformation typeOfMemberWithSelector( | 208 TypeInformation typeOfMemberWithSelector( |
212 MemberEntity element, Selector selector); | 209 MemberEntity element, Selector selector); |
213 | 210 |
214 /// Returns the type of [element]. | 211 /// Returns the type of [element]. |
215 TypeInformation typeOfMember(MemberEntity element); | 212 TypeInformation typeOfMember(MemberEntity element); |
216 | 213 |
217 /// Returns the type of [element]. | 214 /// Returns the type of [element]. |
218 TypeInformation typeOfParameter(Local element); | 215 TypeInformation typeOfParameter(Local element); |
219 | 216 |
220 /// Returns the type for [nativeBehavior]. See documentation on | 217 /// Returns the type for [nativeBehavior]. See documentation on |
221 /// [native.NativeBehavior]. | 218 /// [native.NativeBehavior]. |
222 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); | 219 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); |
223 | 220 |
224 bool returnsListElementType(Selector selector, TypeMask mask); | 221 bool returnsListElementType(Selector selector, TypeMask mask); |
225 | 222 |
226 bool returnsMapValueType(Selector selector, TypeMask mask); | 223 bool returnsMapValueType(Selector selector, TypeMask mask); |
227 | 224 |
228 void clear(); | 225 void clear(); |
229 } | 226 } |
230 | 227 |
231 class InferrerEngineImpl extends InferrerEngine { | 228 abstract class InferrerEngineImpl<T> extends InferrerEngine<T> { |
232 final Map<Local, TypeInformation> defaultTypeOfParameter = | 229 final Map<Local, TypeInformation> defaultTypeOfParameter = |
233 new Map<Local, TypeInformation>(); | 230 new Map<Local, TypeInformation>(); |
234 final WorkQueue workQueue = new WorkQueue(); | 231 final WorkQueue workQueue = new WorkQueue(); |
235 final FunctionEntity mainElement; | 232 final FunctionEntity mainElement; |
236 final Set<MemberEntity> analyzedElements = new Set<MemberEntity>(); | 233 final Set<MemberEntity> analyzedElements = new Set<MemberEntity>(); |
237 | 234 |
238 /// The maximum number of times we allow a node in the graph to | 235 /// The maximum number of times we allow a node in the graph to |
239 /// change types. If a node reaches that limit, we give up | 236 /// change types. If a node reaches that limit, we give up |
240 /// inferencing on it and give it the dynamic type. | 237 /// inferencing on it and give it the dynamic type. |
241 final int MAX_CHANGE_COUNT = 6; | 238 final int MAX_CHANGE_COUNT = 6; |
242 | 239 |
243 int overallRefineCount = 0; | 240 int overallRefineCount = 0; |
244 int addedInGraph = 0; | 241 int addedInGraph = 0; |
245 | 242 |
246 final Compiler compiler; | 243 final Compiler compiler; |
247 | 244 |
248 /// The [ClosedWorld] on which inference reasoning is based. | 245 /// The [ClosedWorld] on which inference reasoning is based. |
249 final ClosedWorld closedWorld; | 246 final ClosedWorld closedWorld; |
250 | 247 |
251 final ClosedWorldRefiner closedWorldRefiner; | 248 final ClosedWorldRefiner closedWorldRefiner; |
252 final TypeSystem<ast.Node> types; | 249 final TypeSystem<T> types; |
253 final Map<ast.Node, TypeInformation> concreteTypes = | 250 final Map<T, TypeInformation> concreteTypes = new Map<T, TypeInformation>(); |
254 new Map<ast.Node, TypeInformation>(); | |
255 | 251 |
256 final Map<ir.Node, TypeInformation> concreteKernelTypes = | 252 final Map<ir.Node, TypeInformation> concreteKernelTypes = |
257 new Map<ir.Node, TypeInformation>(); | 253 new Map<ir.Node, TypeInformation>(); |
258 final Set<ConstructorEntity> generativeConstructorsExposingThis = | 254 final Set<ConstructorEntity> generativeConstructorsExposingThis = |
259 new Set<ConstructorEntity>(); | 255 new Set<ConstructorEntity>(); |
260 | 256 |
261 /// Data computed internally within elements, like the type-mask of a send a | 257 /// Data computed internally within elements, like the type-mask of a send a |
262 /// list allocation, or a for-in loop. | 258 /// list allocation, or a for-in loop. |
263 final Map<MemberEntity, GlobalTypeInferenceElementData> _memberData = | 259 final Map<MemberEntity, GlobalTypeInferenceElementData> _memberData = |
264 new Map<MemberEntity, GlobalTypeInferenceElementData>(); | 260 new Map<MemberEntity, GlobalTypeInferenceElementData>(); |
265 | 261 |
266 InferrerEngineImpl(this.compiler, ClosedWorld closedWorld, | 262 InferrerEngineImpl( |
267 this.closedWorldRefiner, this.mainElement) | 263 this.compiler, |
268 : this.types = new TypeSystem<ast.Node>( | 264 ClosedWorld closedWorld, |
269 closedWorld, const TypeSystemStrategyImpl()), | 265 this.closedWorldRefiner, |
| 266 this.mainElement, |
| 267 TypeSystemStrategy<T> typeSystemStrategy) |
| 268 : this.types = new TypeSystem<T>(closedWorld, typeSystemStrategy), |
270 this.closedWorld = closedWorld; | 269 this.closedWorld = closedWorld; |
271 | 270 |
272 void forEachElementMatching( | 271 void forEachElementMatching( |
273 Selector selector, TypeMask mask, bool f(MemberEntity element)) { | 272 Selector selector, TypeMask mask, bool f(MemberEntity element)) { |
274 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); | 273 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); |
275 for (MemberEntity e in elements) { | 274 for (MemberEntity e in elements) { |
276 if (!f(e)) return; | 275 if (!f(e)) return; |
277 } | 276 } |
278 } | 277 } |
279 | 278 |
| 279 GlobalTypeInferenceElementData<T> createElementData(); |
| 280 |
280 // TODO(johnniwinther): Make this private again. | 281 // TODO(johnniwinther): Make this private again. |
281 GlobalTypeInferenceElementData dataOfMember(MemberEntity element) => | 282 GlobalTypeInferenceElementData<T> dataOfMember(MemberEntity element) => |
282 _memberData.putIfAbsent( | 283 _memberData.putIfAbsent(element, createElementData); |
283 element, () => new GlobalTypeInferenceElementData()); | |
284 | 284 |
285 GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element) => | 285 GlobalTypeInferenceElementData<T> lookupDataOfMember(MemberEntity element) => |
286 _memberData[element]; | 286 _memberData[element]; |
287 | 287 |
288 /** | 288 /** |
289 * Update [sideEffects] with the side effects of [callee] being | 289 * Update [sideEffects] with the side effects of [callee] being |
290 * called with [selector]. | 290 * called with [selector]. |
291 */ | 291 */ |
292 void updateSideEffects( | 292 void updateSideEffects( |
293 SideEffects sideEffects, Selector selector, MemberEntity callee) { | 293 SideEffects sideEffects, Selector selector, MemberEntity callee) { |
294 assert(!(callee is MemberElement && !callee.isDeclaration)); | 294 assert(!(callee is MemberElement && !callee.isDeclaration)); |
295 if (callee.isField) { | 295 if (callee.isField) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 mappedType = types.nonNullSubtype(type.element); | 351 mappedType = types.nonNullSubtype(type.element); |
352 } | 352 } |
353 returnType = types.computeLUB(returnType, mappedType); | 353 returnType = types.computeLUB(returnType, mappedType); |
354 if (returnType == types.dynamicType) { | 354 if (returnType == types.dynamicType) { |
355 break; | 355 break; |
356 } | 356 } |
357 } | 357 } |
358 return returnType; | 358 return returnType; |
359 } | 359 } |
360 | 360 |
361 void updateSelectorInMember(MemberEntity owner, CallType callType, | 361 void updateSelectorInMember(MemberEntity owner, CallType callType, T node, |
362 ast.Node node, Selector selector, TypeMask mask) { | 362 Selector selector, TypeMask mask) { |
363 GlobalTypeInferenceElementData data = dataOfMember(owner); | 363 GlobalTypeInferenceElementData data = dataOfMember(owner); |
364 assert(validCallType(callType, node)); | 364 assert(validCallType(callType, node)); |
365 switch (callType) { | 365 switch (callType) { |
366 case CallType.complex: | 366 case CallType.complex: |
367 if (selector.isSetter || selector.isIndexSet) { | 367 if (selector.isSetter || selector.isIndexSet) { |
368 data.setTypeMask(node, mask); | 368 data.setTypeMask(node, mask); |
369 } else if (selector.isGetter || selector.isIndex) { | 369 } else if (selector.isGetter || selector.isIndex) { |
370 data.setGetterTypeMaskInComplexSendSet(node, mask); | 370 data.setGetterTypeMaskInComplexSendSet(node, mask); |
371 } else { | 371 } else { |
372 assert(selector.isOperator); | 372 assert(selector.isOperator); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 workQueue.addAll(info.addMapAssignment(map)); | 449 workQueue.addAll(info.addMapAssignment(map)); |
450 } | 450 } |
451 | 451 |
452 info.markAsInferred(); | 452 info.markAsInferred(); |
453 workQueue.add(info.keyType); | 453 workQueue.add(info.keyType); |
454 workQueue.add(info.valueType); | 454 workQueue.add(info.valueType); |
455 workQueue.addAll(info.typeInfoMap.values); | 455 workQueue.addAll(info.typeInfoMap.values); |
456 workQueue.add(info); | 456 workQueue.add(info); |
457 } | 457 } |
458 | 458 |
459 void runOverAllElements() { | 459 void runOverAllElements(); |
460 if (compiler.disableTypeInference) return; | |
461 if (compiler.options.verbose) { | |
462 compiler.progress.reset(); | |
463 } | |
464 sortResolvedAsts().forEach((ResolvedAst resolvedAst) { | |
465 if (compiler.shouldPrintProgress) { | |
466 reporter.log('Added $addedInGraph elements in inferencing graph.'); | |
467 compiler.progress.reset(); | |
468 } | |
469 // This also forces the creation of the [ElementTypeInformation] to ensure | |
470 // it is in the graph. | |
471 MemberElement member = resolvedAst.element; | |
472 types.withMember(member, () => analyze(resolvedAst, null)); | |
473 }); | |
474 reporter.log('Added $addedInGraph elements in inferencing graph.'); | |
475 | 460 |
476 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null; | 461 void analyze(MemberEntity element, T body, ArgumentsTypes arguments); |
477 | |
478 dump?.beforeAnalysis(); | |
479 buildWorkQueue(); | |
480 refine(); | |
481 | |
482 // Try to infer element types of lists and compute their escape information. | |
483 types.allocatedLists.values.forEach((TypeInformation info) { | |
484 analyzeListAndEnqueue(info); | |
485 }); | |
486 | |
487 // Try to infer the key and value types for maps and compute the values' | |
488 // escape information. | |
489 types.allocatedMaps.values.forEach((TypeInformation info) { | |
490 analyzeMapAndEnqueue(info); | |
491 }); | |
492 | |
493 Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>(); | |
494 | |
495 // Trace closures to potentially infer argument types. | |
496 types.allocatedClosures.forEach((dynamic info) { | |
497 void trace( | |
498 Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) { | |
499 tracer.run(); | |
500 if (!tracer.continueAnalyzing) { | |
501 elements.forEach((FunctionEntity _element) { | |
502 MethodElement element = _element; | |
503 MethodElement implementation = element.implementation; | |
504 closedWorldRefiner.registerMightBePassedToApply(element); | |
505 if (debug.VERBOSE) { | |
506 print("traced closure $element as ${true} (bail)"); | |
507 } | |
508 implementation.functionSignature | |
509 .forEachParameter((FormalElement _parameter) { | |
510 ParameterElement parameter = _parameter; | |
511 types | |
512 .getInferredTypeOfParameter(parameter) | |
513 .giveUp(this, clearAssignments: false); | |
514 }); | |
515 }); | |
516 bailedOutOn.addAll(elements); | |
517 return; | |
518 } | |
519 elements | |
520 .where((e) => !bailedOutOn.contains(e)) | |
521 .forEach((FunctionEntity _element) { | |
522 MethodElement element = _element; | |
523 MethodElement implementation = element.implementation; | |
524 implementation.functionSignature | |
525 .forEachParameter((FormalElement _parameter) { | |
526 ParameterElement parameter = _parameter; | |
527 ParameterTypeInformation info = | |
528 types.getInferredTypeOfParameter(parameter); | |
529 info.maybeResume(); | |
530 workQueue.add(info); | |
531 }); | |
532 if (tracer.tracedType.mightBePassedToFunctionApply) { | |
533 closedWorldRefiner.registerMightBePassedToApply(element); | |
534 } | |
535 if (debug.VERBOSE) { | |
536 print("traced closure $element as " | |
537 "${closedWorldRefiner | |
538 .getCurrentlyKnownMightBePassedToApply(element)}"); | |
539 } | |
540 }); | |
541 } | |
542 | |
543 if (info is ClosureTypeInformation) { | |
544 Iterable<FunctionEntity> elements = [info.closure]; | |
545 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
546 } else if (info is CallSiteTypeInformation) { | |
547 if (info is StaticCallSiteTypeInformation && | |
548 info.selector != null && | |
549 info.selector.isCall) { | |
550 // This is a constructor call to a class with a call method. So we | |
551 // need to trace the call method here. | |
552 MethodElement calledElement = info.calledElement; | |
553 assert(calledElement.isGenerativeConstructor); | |
554 ClassElement cls = calledElement.enclosingClass; | |
555 MethodElement callMethod = cls.lookupMember(Identifiers.call); | |
556 if (callMethod == null) { | |
557 callMethod = cls.lookupMember(Identifiers.noSuchMethod_); | |
558 } | |
559 assert(callMethod != null, failedAt(cls)); | |
560 Iterable<FunctionEntity> elements = [callMethod]; | |
561 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
562 } else { | |
563 // We only are interested in functions here, as other targets | |
564 // of this closure call are not a root to trace but an intermediate | |
565 // for some other function. | |
566 Iterable<FunctionEntity> elements = new List<FunctionEntity>.from( | |
567 info.callees.where((e) => e.isFunction)); | |
568 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
569 } | |
570 } else if (info is MemberTypeInformation) { | |
571 trace(<FunctionEntity>[info.member], | |
572 new StaticTearOffClosureTracerVisitor(info.member, info, this)); | |
573 } else if (info is ParameterTypeInformation) { | |
574 failedAt( | |
575 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info'); | |
576 } | |
577 }); | |
578 | |
579 dump?.beforeTracing(); | |
580 | |
581 // Reset all nodes that use lists/maps that have been inferred, as well | |
582 // as nodes that use elements fetched from these lists/maps. The | |
583 // workset for a new run of the analysis will be these nodes. | |
584 Set<TypeInformation> seenTypes = new Set<TypeInformation>(); | |
585 while (!workQueue.isEmpty) { | |
586 TypeInformation info = workQueue.remove(); | |
587 if (seenTypes.contains(info)) continue; | |
588 // If the node cannot be reset, we do not need to update its users either. | |
589 if (!info.reset(this)) continue; | |
590 seenTypes.add(info); | |
591 workQueue.addAll(info.users); | |
592 } | |
593 | |
594 workQueue.addAll(seenTypes); | |
595 refine(); | |
596 | |
597 if (debug.PRINT_SUMMARY) { | |
598 types.allocatedLists.values.forEach((_info) { | |
599 ListTypeInformation info = _info; | |
600 print('${info.type} ' | |
601 'for ${info.originalType.allocationNode} ' | |
602 'at ${info.originalType.allocationElement} ' | |
603 'after ${info.refineCount}'); | |
604 }); | |
605 types.allocatedMaps.values.forEach((_info) { | |
606 MapTypeInformation info = _info; | |
607 print('${info.type} ' | |
608 'for ${info.originalType.allocationNode} ' | |
609 'at ${info.originalType.allocationElement} ' | |
610 'after ${info.refineCount}'); | |
611 }); | |
612 types.allocatedClosures.forEach((TypeInformation info) { | |
613 if (info is ElementTypeInformation) { | |
614 print('${info.getInferredSignature(types)} for ' | |
615 '${info.debugName}'); | |
616 } else if (info is ClosureTypeInformation) { | |
617 print('${info.getInferredSignature(types)} for ' | |
618 '${info.debugName}'); | |
619 } else if (info is DynamicCallSiteTypeInformation) { | |
620 for (MemberEntity target in info.targets) { | |
621 if (target is FunctionEntity) { | |
622 print( | |
623 '${types.getInferredSignatureOfMethod(target)} for ${target}')
; | |
624 } else { | |
625 print( | |
626 '${types.getInferredTypeOfMember(target).type} for ${target}')
; | |
627 } | |
628 } | |
629 } else if (info is StaticCallSiteTypeInformation) { | |
630 ClassElement cls = info.calledElement.enclosingClass; | |
631 MethodElement callMethod = cls.lookupMember(Identifiers.call); | |
632 print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}'); | |
633 } else { | |
634 print('${info.type} for some unknown kind of closure'); | |
635 } | |
636 }); | |
637 analyzedElements.forEach((MemberEntity elem) { | |
638 TypeInformation type = types.getInferredTypeOfMember(elem); | |
639 print('${elem} :: ${type} from ${type.assignments} '); | |
640 }); | |
641 } | |
642 dump?.afterAnalysis(); | |
643 | |
644 reporter.log('Inferred $overallRefineCount types.'); | |
645 | |
646 processLoopInformation(); | |
647 } | |
648 | |
649 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { | |
650 MemberElement element = resolvedAst.element; | |
651 if (analyzedElements.contains(element)) return; | |
652 analyzedElements.add(element); | |
653 | |
654 dynamic visitor = compiler.options.kernelGlobalInference | |
655 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) | |
656 : new ElementGraphBuilder(element, resolvedAst, compiler, this); | |
657 TypeInformation type; | |
658 reporter.withCurrentElement(element, () { | |
659 // ignore: UNDEFINED_METHOD | |
660 type = visitor.run(); | |
661 }); | |
662 addedInGraph++; | |
663 | |
664 if (element.isField) { | |
665 FieldElement field = element; | |
666 ast.Node initializer = resolvedAst.body; | |
667 if (field.isFinal || field.isConst) { | |
668 // If [element] is final and has an initializer, we record | |
669 // the inferred type. | |
670 if (resolvedAst.body != null) { | |
671 if (type is! ListTypeInformation && type is! MapTypeInformation) { | |
672 // For non-container types, the constant handler does | |
673 // constant folding that could give more precise results. | |
674 ConstantExpression constant = field.constant; | |
675 if (constant != null) { | |
676 ConstantValue value = | |
677 compiler.backend.constants.getConstantValue(constant); | |
678 if (value != null) { | |
679 if (value.isFunction) { | |
680 FunctionConstantValue functionConstant = value; | |
681 MethodElement function = functionConstant.element; | |
682 type = types.allocateClosure(function); | |
683 } else { | |
684 // Although we might find a better type, we have to keep | |
685 // the old type around to ensure that we get a complete view | |
686 // of the type graph and do not drop any flow edges. | |
687 TypeMask refinedType = computeTypeMask(closedWorld, value); | |
688 assert(TypeMask.assertIsNormalized(refinedType, closedWorld)); | |
689 type = new NarrowTypeInformation(type, refinedType); | |
690 types.allocatedTypes.add(type); | |
691 } | |
692 } else { | |
693 assert( | |
694 field.isInstanceMember || | |
695 constant.isImplicit || | |
696 constant.isPotential, | |
697 failedAt( | |
698 field, | |
699 "Constant expression without value: " | |
700 "${constant.toStructuredText()}.")); | |
701 } | |
702 } | |
703 } | |
704 recordTypeOfField(field, type); | |
705 } else if (!element.isInstanceMember) { | |
706 recordTypeOfField(field, types.nullType); | |
707 } | |
708 } else if (initializer == null) { | |
709 // Only update types of static fields if there is no | |
710 // assignment. Instance fields are dealt with in the constructor. | |
711 if (Elements.isStaticOrTopLevelField(element)) { | |
712 recordTypeOfField(field, type); | |
713 } | |
714 } else { | |
715 recordTypeOfField(field, type); | |
716 } | |
717 if (Elements.isStaticOrTopLevelField(field) && | |
718 resolvedAst.body != null && | |
719 !element.isConst) { | |
720 dynamic argument = resolvedAst.body; | |
721 // TODO(13429): We could do better here by using the | |
722 // constant handler to figure out if it's a lazy field or not. | |
723 if (argument.asSend() != null || | |
724 (argument.asNewExpression() != null && !argument.isConst)) { | |
725 recordTypeOfField(field, types.nullType); | |
726 } | |
727 } | |
728 } else { | |
729 MethodElement method = element; | |
730 recordReturnType(method, type); | |
731 } | |
732 } | |
733 | 462 |
734 void processLoopInformation() { | 463 void processLoopInformation() { |
735 types.allocatedCalls.forEach((dynamic info) { | 464 types.allocatedCalls.forEach((dynamic info) { |
736 if (!info.inLoop) return; | 465 if (!info.inLoop) return; |
737 if (info is StaticCallSiteTypeInformation) { | 466 if (info is StaticCallSiteTypeInformation) { |
738 MemberEntity member = info.calledElement; | 467 MemberEntity member = info.calledElement; |
739 closedWorldRefiner.addFunctionCalledInLoop(member); | 468 closedWorldRefiner.addFunctionCalledInLoop(member); |
740 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { | 469 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { |
741 // For instance methods, we only register a selector called in a | 470 // For instance methods, we only register a selector called in a |
742 // loop if it is a typed selector, to avoid marking too many | 471 // loop if it is a typed selector, to avoid marking too many |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
782 | 511 |
783 void buildWorkQueue() { | 512 void buildWorkQueue() { |
784 workQueue.addAll(types.orderedTypeInformations); | 513 workQueue.addAll(types.orderedTypeInformations); |
785 workQueue.addAll(types.allocatedTypes); | 514 workQueue.addAll(types.allocatedTypes); |
786 workQueue.addAll(types.allocatedClosures); | 515 workQueue.addAll(types.allocatedClosures); |
787 workQueue.addAll(types.allocatedCalls); | 516 workQueue.addAll(types.allocatedCalls); |
788 } | 517 } |
789 | 518 |
790 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 519 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
791 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 520 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
792 {bool remove, bool addToQueue: true}) { | 521 {bool remove, bool addToQueue: true}); |
793 if (callee.name == Identifiers.noSuchMethod_) return; | |
794 if (callee.isField) { | |
795 if (selector.isSetter) { | |
796 ElementTypeInformation info = types.getInferredTypeOfMember(callee); | |
797 if (remove) { | |
798 info.removeAssignment(arguments.positional[0]); | |
799 } else { | |
800 info.addAssignment(arguments.positional[0]); | |
801 } | |
802 if (addToQueue) workQueue.add(info); | |
803 } | |
804 } else if (callee.isGetter) { | |
805 return; | |
806 } else if (selector != null && selector.isGetter) { | |
807 // We are tearing a function off and thus create a closure. | |
808 assert(callee.isFunction); | |
809 MethodElement method = callee; | |
810 MemberTypeInformation info = types.getInferredTypeOfMember(method); | |
811 if (remove) { | |
812 info.closurizedCount--; | |
813 } else { | |
814 info.closurizedCount++; | |
815 if (Elements.isStaticOrTopLevel(method)) { | |
816 types.allocatedClosures.add(info); | |
817 } else { | |
818 // We add the call-site type information here so that we | |
819 // can benefit from further refinement of the selector. | |
820 types.allocatedClosures.add(caller); | |
821 } | |
822 FunctionElement function = method.implementation; | |
823 FunctionSignature signature = function.functionSignature; | |
824 signature.forEachParameter((FormalElement _parameter) { | |
825 ParameterElement parameter = _parameter; | |
826 ParameterTypeInformation info = | |
827 types.getInferredTypeOfParameter(parameter); | |
828 info.tagAsTearOffClosureParameter(this); | |
829 if (addToQueue) workQueue.add(info); | |
830 }); | |
831 } | |
832 } else { | |
833 MethodElement method = callee; | |
834 FunctionElement function = method.implementation; | |
835 FunctionSignature signature = function.functionSignature; | |
836 int parameterIndex = 0; | |
837 bool visitingRequiredParameter = true; | |
838 signature.forEachParameter((FormalElement _parameter) { | |
839 ParameterElement parameter = _parameter; | |
840 if (signature.hasOptionalParameters && | |
841 parameter == signature.optionalParameters.first) { | |
842 visitingRequiredParameter = false; | |
843 } | |
844 TypeInformation type = visitingRequiredParameter | |
845 ? arguments.positional[parameterIndex] | |
846 : signature.optionalParametersAreNamed | |
847 ? arguments.named[parameter.name] | |
848 : parameterIndex < arguments.positional.length | |
849 ? arguments.positional[parameterIndex] | |
850 : null; | |
851 if (type == null) type = getDefaultTypeOfParameter(parameter); | |
852 TypeInformation info = types.getInferredTypeOfParameter(parameter); | |
853 if (remove) { | |
854 info.removeAssignment(type); | |
855 } else { | |
856 info.addAssignment(type); | |
857 } | |
858 parameterIndex++; | |
859 if (addToQueue) workQueue.add(info); | |
860 }); | |
861 } | |
862 } | |
863 | 522 |
864 void setDefaultTypeOfParameter(Local parameter, TypeInformation type, | 523 void setDefaultTypeOfParameter(Local parameter, TypeInformation type, |
865 {bool isInstanceMember}) { | 524 {bool isInstanceMember}) { |
866 assert(!(parameter is ParameterElement && !parameter.isImplementation)); | 525 assert(!(parameter is ParameterElement && !parameter.isImplementation)); |
867 TypeInformation existing = defaultTypeOfParameter[parameter]; | 526 TypeInformation existing = defaultTypeOfParameter[parameter]; |
868 defaultTypeOfParameter[parameter] = type; | 527 defaultTypeOfParameter[parameter] = type; |
869 TypeInformation info = types.getInferredTypeOfParameter(parameter); | 528 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
870 if (existing != null && existing is PlaceholderTypeInformation) { | 529 if (existing != null && existing is PlaceholderTypeInformation) { |
871 // Replace references to [existing] to use [type] instead. | 530 // Replace references to [existing] to use [type] instead. |
872 if (isInstanceMember) { | 531 if (isInstanceMember) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
975 } | 634 } |
976 } | 635 } |
977 info.addToGraph(this); | 636 info.addToGraph(this); |
978 types.allocatedCalls.add(info); | 637 types.allocatedCalls.add(info); |
979 updateSideEffects(sideEffects, selector, callee); | 638 updateSideEffects(sideEffects, selector, callee); |
980 return info; | 639 return info; |
981 } | 640 } |
982 | 641 |
983 TypeInformation registerCalledSelector( | 642 TypeInformation registerCalledSelector( |
984 CallType callType, | 643 CallType callType, |
985 ast.Node node, | 644 T node, |
986 Selector selector, | 645 Selector selector, |
987 TypeMask mask, | 646 TypeMask mask, |
988 TypeInformation receiverType, | 647 TypeInformation receiverType, |
989 MemberEntity caller, | 648 MemberEntity caller, |
990 ArgumentsTypes arguments, | 649 ArgumentsTypes arguments, |
991 SideEffects sideEffects, | 650 SideEffects sideEffects, |
992 bool inLoop, | 651 bool inLoop, |
993 bool isConditional) { | 652 bool isConditional) { |
994 if (selector.isClosureCall) { | 653 if (selector.isClosureCall) { |
995 return registerCalledClosure(node, selector, mask, receiverType, caller, | 654 return registerCalledClosure(node, selector, mask, receiverType, caller, |
(...skipping 14 matching lines...) Expand all Loading... |
1010 receiverType, | 669 receiverType, |
1011 arguments, | 670 arguments, |
1012 inLoop, | 671 inLoop, |
1013 isConditional); | 672 isConditional); |
1014 | 673 |
1015 info.addToGraph(this); | 674 info.addToGraph(this); |
1016 types.allocatedCalls.add(info); | 675 types.allocatedCalls.add(info); |
1017 return info; | 676 return info; |
1018 } | 677 } |
1019 | 678 |
1020 TypeInformation registerAwait(ast.Node node, TypeInformation argument) { | 679 TypeInformation registerAwait(T node, TypeInformation argument) { |
1021 AwaitTypeInformation info = | 680 AwaitTypeInformation info = |
1022 new AwaitTypeInformation<ast.Node>(types.currentMember, node); | 681 new AwaitTypeInformation<T>(types.currentMember, node); |
1023 info.addAssignment(argument); | 682 info.addAssignment(argument); |
1024 types.allocatedTypes.add(info); | 683 types.allocatedTypes.add(info); |
1025 return info; | 684 return info; |
1026 } | 685 } |
1027 | 686 |
1028 TypeInformation registerYield(ast.Node node, TypeInformation argument) { | 687 TypeInformation registerYield(T node, TypeInformation argument) { |
1029 YieldTypeInformation info = | 688 YieldTypeInformation info = |
1030 new YieldTypeInformation<ast.Node>(types.currentMember, node); | 689 new YieldTypeInformation<T>(types.currentMember, node); |
1031 info.addAssignment(argument); | 690 info.addAssignment(argument); |
1032 types.allocatedTypes.add(info); | 691 types.allocatedTypes.add(info); |
1033 return info; | 692 return info; |
1034 } | 693 } |
1035 | 694 |
1036 TypeInformation registerCalledClosure( | 695 TypeInformation registerCalledClosure( |
1037 ast.Node node, | 696 T node, |
1038 Selector selector, | 697 Selector selector, |
1039 TypeMask mask, | 698 TypeMask mask, |
1040 TypeInformation closure, | 699 TypeInformation closure, |
1041 MemberEntity caller, | 700 MemberEntity caller, |
1042 ArgumentsTypes arguments, | 701 ArgumentsTypes arguments, |
1043 SideEffects sideEffects, | 702 SideEffects sideEffects, |
1044 bool inLoop) { | 703 bool inLoop) { |
1045 sideEffects.setDependsOnSomething(); | 704 sideEffects.setDependsOnSomething(); |
1046 sideEffects.setAllSideEffects(); | 705 sideEffects.setAllSideEffects(); |
1047 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( | 706 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( |
1048 types.currentMember, | 707 types.currentMember, |
1049 node, | 708 node, |
1050 caller, | 709 caller, |
1051 selector, | 710 selector, |
1052 mask, | 711 mask, |
1053 closure, | 712 closure, |
1054 arguments, | 713 arguments, |
1055 inLoop); | 714 inLoop); |
1056 info.addToGraph(this); | 715 info.addToGraph(this); |
1057 types.allocatedCalls.add(info); | 716 types.allocatedCalls.add(info); |
1058 return info; | 717 return info; |
1059 } | 718 } |
1060 | 719 |
1061 // Sorts the resolved elements by size. We do this for this inferrer | |
1062 // to get the same results for [ListTracer] compared to the | |
1063 // [SimpleTypesInferrer]. | |
1064 Iterable<ResolvedAst> sortResolvedAsts() { | |
1065 int max = 0; | |
1066 Map<int, Setlet<ResolvedAst>> methodSizes = <int, Setlet<ResolvedAst>>{}; | |
1067 compiler.enqueuer.resolution.processedEntities.forEach((_element) { | |
1068 MemberElement element = _element; | |
1069 ResolvedAst resolvedAst = element.resolvedAst; | |
1070 element = element.implementation; | |
1071 if (element.impliesType) return; | |
1072 assert( | |
1073 element.isField || | |
1074 element.isFunction || | |
1075 element.isConstructor || | |
1076 element.isGetter || | |
1077 element.isSetter, | |
1078 failedAt(element, 'Unexpected element kind: ${element.kind}')); | |
1079 if (element.isAbstract) return; | |
1080 // Put the other operators in buckets by length, later to be added in | |
1081 // length order. | |
1082 int length = 0; | |
1083 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | |
1084 TreeElementMapping mapping = resolvedAst.elements; | |
1085 length = mapping.getSelectorCount(); | |
1086 } | |
1087 max = length > max ? length : max; | |
1088 Setlet<ResolvedAst> set = | |
1089 methodSizes.putIfAbsent(length, () => new Setlet<ResolvedAst>()); | |
1090 set.add(resolvedAst); | |
1091 }); | |
1092 | |
1093 List<ResolvedAst> result = <ResolvedAst>[]; | |
1094 for (int i = 0; i <= max; i++) { | |
1095 Setlet<ResolvedAst> set = methodSizes[i]; | |
1096 if (set != null) result.addAll(set); | |
1097 } | |
1098 return result; | |
1099 } | |
1100 | |
1101 void clear() { | 720 void clear() { |
1102 void cleanup(TypeInformation info) => info.cleanup(); | 721 void cleanup(TypeInformation info) => info.cleanup(); |
1103 | 722 |
1104 types.allocatedCalls.forEach(cleanup); | 723 types.allocatedCalls.forEach(cleanup); |
1105 types.allocatedCalls.clear(); | 724 types.allocatedCalls.clear(); |
1106 | 725 |
1107 defaultTypeOfParameter.clear(); | 726 defaultTypeOfParameter.clear(); |
1108 | 727 |
1109 types.parameterTypeInformations.values.forEach(cleanup); | 728 types.parameterTypeInformations.values.forEach(cleanup); |
1110 types.memberTypeInformations.values.forEach(cleanup); | 729 types.memberTypeInformations.values.forEach(cleanup); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1155 return returnTypeOfMember(element); | 774 return returnTypeOfMember(element); |
1156 } | 775 } |
1157 } else if (element.isGetter || element.isField) { | 776 } else if (element.isGetter || element.isField) { |
1158 assert(selector.isCall || selector.isSetter); | 777 assert(selector.isCall || selector.isSetter); |
1159 return types.dynamicType; | 778 return types.dynamicType; |
1160 } else { | 779 } else { |
1161 return returnTypeOfMember(element); | 780 return returnTypeOfMember(element); |
1162 } | 781 } |
1163 } | 782 } |
1164 } | 783 } |
1165 | |
1166 class TypeSystemStrategyImpl implements TypeSystemStrategy<ast.Node> { | |
1167 const TypeSystemStrategyImpl(); | |
1168 | |
1169 @override | |
1170 MemberTypeInformation createMemberTypeInformation( | |
1171 covariant MemberElement member) { | |
1172 assert(member.isDeclaration, failedAt(member)); | |
1173 if (member.isField) { | |
1174 FieldElement field = member; | |
1175 return new FieldTypeInformation(field, field.type); | |
1176 } else if (member.isGetter) { | |
1177 GetterElement getter = member; | |
1178 return new GetterTypeInformation(getter, getter.type); | |
1179 } else if (member.isSetter) { | |
1180 SetterElement setter = member; | |
1181 return new SetterTypeInformation(setter); | |
1182 } else if (member.isFunction) { | |
1183 MethodElement method = member; | |
1184 return new MethodTypeInformation(method, method.type); | |
1185 } else { | |
1186 ConstructorElement constructor = member; | |
1187 if (constructor.isFactoryConstructor) { | |
1188 return new FactoryConstructorTypeInformation( | |
1189 constructor, constructor.type); | |
1190 } else { | |
1191 return new GenerativeConstructorTypeInformation(constructor); | |
1192 } | |
1193 } | |
1194 } | |
1195 | |
1196 @override | |
1197 ParameterTypeInformation createParameterTypeInformation( | |
1198 covariant ParameterElement parameter, TypeSystem<ast.Node> types) { | |
1199 assert(parameter.isImplementation, failedAt(parameter)); | |
1200 FunctionTypedElement function = parameter.functionDeclaration.declaration; | |
1201 if (function.isLocal) { | |
1202 LocalFunctionElement localFunction = function; | |
1203 MethodElement callMethod = localFunction.callMethod; | |
1204 return new ParameterTypeInformation.localFunction( | |
1205 types.getInferredTypeOfMember(callMethod), | |
1206 parameter, | |
1207 parameter.type, | |
1208 callMethod); | |
1209 } else if (function.isInstanceMember) { | |
1210 MethodElement method = function; | |
1211 return new ParameterTypeInformation.instanceMember( | |
1212 types.getInferredTypeOfMember(method), | |
1213 parameter, | |
1214 parameter.type, | |
1215 method, | |
1216 new ParameterAssignments()); | |
1217 } else { | |
1218 MethodElement method = function; | |
1219 return new ParameterTypeInformation.static( | |
1220 types.getInferredTypeOfMember(method), | |
1221 parameter, | |
1222 parameter.type, | |
1223 method, | |
1224 // TODO(johnniwinther): Is this still valid now that initializing | |
1225 // formals also introduce locals? | |
1226 isInitializingFormal: parameter.isInitializingFormal); | |
1227 } | |
1228 } | |
1229 | |
1230 @override | |
1231 void forEachParameter( | |
1232 covariant MethodElement function, void f(Local parameter)) { | |
1233 MethodElement impl = function.implementation; | |
1234 FunctionSignature signature = impl.functionSignature; | |
1235 signature.forEachParameter((FormalElement _parameter) { | |
1236 ParameterElement parameter = _parameter; | |
1237 f(parameter); | |
1238 }); | |
1239 } | |
1240 | |
1241 @override | |
1242 bool checkMapNode(ast.Node node) { | |
1243 return node is ast.LiteralMap; | |
1244 } | |
1245 | |
1246 @override | |
1247 bool checkListNode(ast.Node node) { | |
1248 return node is ast.LiteralList || node is ast.Send; | |
1249 } | |
1250 | |
1251 @override | |
1252 bool checkLoopPhiNode(ast.Node node) { | |
1253 return node is ast.Loop || node is ast.SwitchStatement; | |
1254 } | |
1255 | |
1256 @override | |
1257 bool checkPhiNode(ast.Node node) { | |
1258 return true; | |
1259 } | |
1260 | |
1261 @override | |
1262 bool checkClassEntity(covariant ClassElement cls) { | |
1263 return cls.isDeclaration; | |
1264 } | |
1265 } | |
OLD | NEW |