| 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'; | 10 import '../constants/expressions.dart'; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 import 'locals_handler.dart'; | 30 import 'locals_handler.dart'; |
| 31 import 'list_tracer.dart'; | 31 import 'list_tracer.dart'; |
| 32 import 'map_tracer.dart'; | 32 import 'map_tracer.dart'; |
| 33 import 'builder.dart'; | 33 import 'builder.dart'; |
| 34 import 'builder_kernel.dart'; | 34 import 'builder_kernel.dart'; |
| 35 import 'type_graph_dump.dart'; | 35 import 'type_graph_dump.dart'; |
| 36 import 'type_graph_inferrer.dart'; | 36 import 'type_graph_inferrer.dart'; |
| 37 import 'type_graph_nodes.dart'; | 37 import 'type_graph_nodes.dart'; |
| 38 import 'type_system.dart'; | 38 import 'type_system.dart'; |
| 39 | 39 |
| 40 /** | 40 /// An inferencing engine that computes a call graph of [TypeInformation] nodes |
| 41 * An inferencing engine that computes a call graph of | 41 /// by visiting the AST of the application, and then does the inferencing on the |
| 42 * [TypeInformation] nodes by visiting the AST of the application, and | 42 /// graph. |
| 43 * then does the inferencing on the graph. | 43 abstract class InferrerEngine { |
| 44 */ | 44 /// A set of selector names that [List] implements, that we know return their |
| 45 class InferrerEngine { | 45 /// element type. |
| 46 final Set<Selector> returnsListElementTypeSet = |
| 47 new Set<Selector>.from(<Selector>[ |
| 48 new Selector.getter(const PublicName('first')), |
| 49 new Selector.getter(const PublicName('last')), |
| 50 new Selector.getter(const PublicName('single')), |
| 51 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), |
| 52 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), |
| 53 new Selector.index(), |
| 54 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), |
| 55 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) |
| 56 ]); |
| 57 |
| 58 Compiler get compiler; |
| 59 ClosedWorld get closedWorld; |
| 60 ClosedWorldRefiner get closedWorldRefiner; |
| 61 JavaScriptBackend get backend => compiler.backend; |
| 62 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; |
| 63 DiagnosticReporter get reporter => compiler.reporter; |
| 64 CommonMasks get commonMasks => closedWorld.commonMasks; |
| 65 CommonElements get commonElements => closedWorld.commonElements; |
| 66 |
| 67 TypeSystem<ast.Node> get types; |
| 68 Map<ast.Node, TypeInformation> get concreteTypes; |
| 69 |
| 70 /// Parallel structure for concreteTypes. |
| 71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by |
| 72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. |
| 73 Map<ir.Node, TypeInformation> get concreteKernelTypes; |
| 74 |
| 75 FunctionEntity get mainElement; |
| 76 |
| 77 void runOverAllElements(); |
| 78 |
| 79 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments); |
| 80 void analyzeListAndEnqueue(ListTypeInformation info); |
| 81 void analyzeMapAndEnqueue(MapTypeInformation info); |
| 82 |
| 83 /// Notifies to the inferrer that [analyzedElement] can have return type |
| 84 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently |
| 85 /// found. |
| 86 /// |
| 87 /// Returns the new type for [analyzedElement]. |
| 88 TypeInformation addReturnTypeForMethod( |
| 89 MethodElement element, TypeInformation unused, TypeInformation newType); |
| 90 |
| 91 /// Applies [f] to all elements in the universe that match [selector] and |
| 92 /// [mask]. If [f] returns false, aborts the iteration. |
| 93 void forEachElementMatching( |
| 94 Selector selector, TypeMask mask, bool f(Element element)); |
| 95 |
| 96 /// Returns the [TypeInformation] node for the default value of a parameter. |
| 97 /// If this is queried before it is set by [setDefaultTypeOfParameter], a |
| 98 /// [PlaceholderTypeInformation] is returned, which will later be replaced |
| 99 /// by the actual node when [setDefaultTypeOfParameter] is called. |
| 100 /// |
| 101 /// Invariant: After graph construction, no [PlaceholderTypeInformation] nodes |
| 102 /// should be present and a default type for each parameter should exist. |
| 103 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter); |
| 104 |
| 105 /// This helper breaks abstractions but is currently required to work around |
| 106 /// the wrong modeling of default values of optional parameters of |
| 107 /// synthetic constructors. |
| 108 /// |
| 109 /// TODO(johnniwinther): Remove once default values of synthetic parameters |
| 110 /// are fixed. |
| 111 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter); |
| 112 |
| 113 /// Sets the type of a parameter's default value to [type]. If the global |
| 114 /// mapping in [defaultTypeOfParameter] already contains a type, it must be |
| 115 /// a [PlaceholderTypeInformation], which will be replaced. All its uses are |
| 116 /// updated. |
| 117 void setDefaultTypeOfParameter( |
| 118 ParameterElement parameter, TypeInformation type); |
| 119 |
| 120 Iterable<MemberEntity> getCallersOf(MemberElement element); |
| 121 |
| 122 // TODO(johnniwinther): Make this private again. |
| 123 GlobalTypeInferenceElementData dataOfMember(MemberElement element); |
| 124 |
| 125 GlobalTypeInferenceElementData lookupDataOfMember(MemberElement element); |
| 126 |
| 127 bool checkIfExposesThis(ConstructorElement element); |
| 128 |
| 129 void recordExposesThis(ConstructorElement element, bool exposesThis); |
| 130 |
| 131 /// Records that the return type [element] is of type [type]. |
| 132 void recordReturnType(MethodElement element, TypeInformation type); |
| 133 |
| 134 /// Records that [element] is of type [type]. |
| 135 // TODO(johnniwinther): Merge [recordTypeOfFinalField] and |
| 136 // [recordTypeOfNonFinalField] with this? |
| 137 void recordTypeOfField(FieldElement element, TypeInformation type); |
| 138 |
| 139 /// Records that [node] sets final field [element] to be of type [type]. |
| 140 void recordTypeOfFinalField(FieldElement element, TypeInformation type); |
| 141 |
| 142 /// Records that [node] sets non-final field [element] to be of type [type]. |
| 143 void recordTypeOfNonFinalField(FieldElement element, TypeInformation type); |
| 144 |
| 145 /// Records that the captured variable [local] is read. |
| 146 // TODO(johnniwinther): Remove this. |
| 147 void recordCapturedLocalRead(Local local) {} |
| 148 |
| 149 /// Records that the variable [local] is being updated. |
| 150 // TODO(johnniwinther): Remove this. |
| 151 void recordLocalUpdate(Local local, TypeInformation type) {} |
| 152 |
| 153 /// Registers a call to await with an expression of type [argumentType] as |
| 154 /// argument. |
| 155 TypeInformation registerAwait(ast.Node node, TypeInformation argument); |
| 156 |
| 157 /// Registers a call to yield with an expression of type [argumentType] as |
| 158 /// argument. |
| 159 TypeInformation registerYield(ast.Node node, TypeInformation argument); |
| 160 |
| 161 /// Registers that [caller] calls [closure] with [arguments]. |
| 162 /// |
| 163 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 164 /// effects. |
| 165 /// |
| 166 /// [inLoop] tells whether the call happens in a loop. |
| 167 TypeInformation registerCalledClosure( |
| 168 ast.Node node, |
| 169 Selector selector, |
| 170 TypeMask mask, |
| 171 TypeInformation closure, |
| 172 MemberElement caller, |
| 173 ArgumentsTypes arguments, |
| 174 SideEffects sideEffects, |
| 175 bool inLoop); |
| 176 |
| 177 /// Registers that [caller] calls [callee] at location [node], with |
| 178 /// [selector], and [arguments]. Note that [selector] is null for forwarding |
| 179 /// constructors. |
| 180 /// |
| 181 /// [sideEffects] will be updated to incorporate [callee]'s side effects. |
| 182 /// |
| 183 /// [inLoop] tells whether the call happens in a loop. |
| 184 TypeInformation registerCalledMember( |
| 185 Spannable node, |
| 186 Selector selector, |
| 187 TypeMask mask, |
| 188 MemberElement caller, |
| 189 MemberElement callee, |
| 190 ArgumentsTypes arguments, |
| 191 SideEffects sideEffects, |
| 192 bool inLoop); |
| 193 |
| 194 /// Registers that [caller] calls [selector] with [receiverType] as receiver, |
| 195 /// and [arguments]. |
| 196 /// |
| 197 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 198 /// effects. |
| 199 /// |
| 200 /// [inLoop] tells whether the call happens in a loop. |
| 201 TypeInformation registerCalledSelector( |
| 202 ast.Node node, |
| 203 Selector selector, |
| 204 TypeMask mask, |
| 205 TypeInformation receiverType, |
| 206 MemberElement caller, |
| 207 ArgumentsTypes arguments, |
| 208 SideEffects sideEffects, |
| 209 bool inLoop, |
| 210 bool isConditional); |
| 211 |
| 212 /// Update the assignments to parameters in the graph. [remove] tells whether |
| 213 /// assignments must be added or removed. If [init] is false, parameters are |
| 214 /// added to the work queue. |
| 215 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
| 216 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 217 {bool remove, bool addToQueue: true}); |
| 218 |
| 219 void updateSelectorInMember( |
| 220 MemberElement owner, Spannable node, Selector selector, TypeMask mask); |
| 221 |
| 222 /// Returns the return type of [element]. |
| 223 TypeInformation returnTypeOfMember(MemberElement element); |
| 224 |
| 225 /// Returns the type of [element] when being called with [selector]. |
| 226 TypeInformation typeOfMemberWithSelector( |
| 227 MemberElement element, Selector selector); |
| 228 |
| 229 /// Returns the type of [element]. |
| 230 TypeInformation typeOfMember(MemberElement element); |
| 231 |
| 232 /// Returns the type of [element]. |
| 233 TypeInformation typeOfParameter(ParameterElement element); |
| 234 |
| 235 /// Returns the type for [nativeBehavior]. See documentation on |
| 236 /// [native.NativeBehavior]. |
| 237 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); |
| 238 |
| 239 bool returnsListElementType(Selector selector, TypeMask mask); |
| 240 |
| 241 bool returnsMapValueType(Selector selector, TypeMask mask); |
| 242 |
| 243 void clear(); |
| 244 } |
| 245 |
| 246 class InferrerEngineImpl extends InferrerEngine { |
| 46 final Map<ParameterElement, TypeInformation> defaultTypeOfParameter = | 247 final Map<ParameterElement, TypeInformation> defaultTypeOfParameter = |
| 47 new Map<ParameterElement, TypeInformation>(); | 248 new Map<ParameterElement, TypeInformation>(); |
| 48 final WorkQueue workQueue = new WorkQueue(); | 249 final WorkQueue workQueue = new WorkQueue(); |
| 49 final FunctionEntity mainElement; | 250 final FunctionEntity mainElement; |
| 50 final Set<MemberElement> analyzedElements = new Set<MemberElement>(); | 251 final Set<MemberElement> analyzedElements = new Set<MemberElement>(); |
| 51 | 252 |
| 52 /// The maximum number of times we allow a node in the graph to | 253 /// The maximum number of times we allow a node in the graph to |
| 53 /// change types. If a node reaches that limit, we give up | 254 /// change types. If a node reaches that limit, we give up |
| 54 /// inferencing on it and give it the dynamic type. | 255 /// inferencing on it and give it the dynamic type. |
| 55 final int MAX_CHANGE_COUNT = 6; | 256 final int MAX_CHANGE_COUNT = 6; |
| 56 | 257 |
| 57 int overallRefineCount = 0; | 258 int overallRefineCount = 0; |
| 58 int addedInGraph = 0; | 259 int addedInGraph = 0; |
| 59 | 260 |
| 60 final Compiler compiler; | 261 final Compiler compiler; |
| 61 | 262 |
| 62 /// The [ClosedWorld] on which inference reasoning is based. | 263 /// The [ClosedWorld] on which inference reasoning is based. |
| 63 final ClosedWorld closedWorld; | 264 final ClosedWorld closedWorld; |
| 64 | 265 |
| 65 final ClosedWorldRefiner closedWorldRefiner; | 266 final ClosedWorldRefiner closedWorldRefiner; |
| 66 final TypeSystem<ast.Node> types; | 267 final TypeSystem<ast.Node> types; |
| 67 final Map<ast.Node, TypeInformation> concreteTypes = | 268 final Map<ast.Node, TypeInformation> concreteTypes = |
| 68 new Map<ast.Node, TypeInformation>(); | 269 new Map<ast.Node, TypeInformation>(); |
| 69 | 270 |
| 70 /// Parallel structure for concreteTypes. | |
| 71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by | |
| 72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. | |
| 73 final Map<ir.Node, TypeInformation> concreteKernelTypes = | 271 final Map<ir.Node, TypeInformation> concreteKernelTypes = |
| 74 new Map<ir.Node, TypeInformation>(); | 272 new Map<ir.Node, TypeInformation>(); |
| 75 final Set<ConstructorElement> generativeConstructorsExposingThis = | 273 final Set<ConstructorElement> generativeConstructorsExposingThis = |
| 76 new Set<ConstructorElement>(); | 274 new Set<ConstructorElement>(); |
| 77 | 275 |
| 78 /// Data computed internally within elements, like the type-mask of a send a | 276 /// Data computed internally within elements, like the type-mask of a send a |
| 79 /// list allocation, or a for-in loop. | 277 /// list allocation, or a for-in loop. |
| 80 final Map<MemberElement, GlobalTypeInferenceElementData> _memberData = | 278 final Map<MemberElement, GlobalTypeInferenceElementData> _memberData = |
| 81 new Map<MemberElement, GlobalTypeInferenceElementData>(); | 279 new Map<MemberElement, GlobalTypeInferenceElementData>(); |
| 82 | 280 |
| 83 InferrerEngine(this.compiler, ClosedWorld closedWorld, | 281 InferrerEngineImpl(this.compiler, ClosedWorld closedWorld, |
| 84 this.closedWorldRefiner, this.mainElement) | 282 this.closedWorldRefiner, this.mainElement) |
| 85 : this.types = new TypeSystem<ast.Node>( | 283 : this.types = new TypeSystem<ast.Node>( |
| 86 closedWorld, const TypeSystemStrategyImpl()), | 284 closedWorld, const TypeSystemStrategyImpl()), |
| 87 this.closedWorld = closedWorld; | 285 this.closedWorld = closedWorld; |
| 88 | 286 |
| 89 CommonElements get commonElements => closedWorld.commonElements; | |
| 90 | |
| 91 /** | |
| 92 * Applies [f] to all elements in the universe that match | |
| 93 * [selector] and [mask]. If [f] returns false, aborts the iteration. | |
| 94 */ | |
| 95 void forEachElementMatching( | 287 void forEachElementMatching( |
| 96 Selector selector, TypeMask mask, bool f(Element element)) { | 288 Selector selector, TypeMask mask, bool f(Element element)) { |
| 97 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); | 289 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); |
| 98 for (MemberElement e in elements) { | 290 for (MemberElement e in elements) { |
| 99 if (!f(e.implementation)) return; | 291 if (!f(e.implementation)) return; |
| 100 } | 292 } |
| 101 } | 293 } |
| 102 | 294 |
| 103 // TODO(johnniwinther): Make this private again. | 295 // TODO(johnniwinther): Make this private again. |
| 104 GlobalTypeInferenceElementData dataOfMember(MemberElement element) => | 296 GlobalTypeInferenceElementData dataOfMember(MemberElement element) => |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 } | 328 } |
| 137 } else if (callee.isGetter && !selector.isGetter) { | 329 } else if (callee.isGetter && !selector.isGetter) { |
| 138 sideEffects.setAllSideEffects(); | 330 sideEffects.setAllSideEffects(); |
| 139 sideEffects.setDependsOnSomething(); | 331 sideEffects.setDependsOnSomething(); |
| 140 } else { | 332 } else { |
| 141 MethodElement method = callee.declaration; | 333 MethodElement method = callee.declaration; |
| 142 sideEffects.add(closedWorldRefiner.getCurrentlyKnownSideEffects(method)); | 334 sideEffects.add(closedWorldRefiner.getCurrentlyKnownSideEffects(method)); |
| 143 } | 335 } |
| 144 } | 336 } |
| 145 | 337 |
| 146 /** | |
| 147 * Returns the type for [nativeBehavior]. See documentation on | |
| 148 * [native.NativeBehavior]. | |
| 149 */ | |
| 150 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior) { | 338 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior) { |
| 151 if (nativeBehavior == null) return types.dynamicType; | 339 if (nativeBehavior == null) return types.dynamicType; |
| 152 List typesReturned = nativeBehavior.typesReturned; | 340 List typesReturned = nativeBehavior.typesReturned; |
| 153 if (typesReturned.isEmpty) return types.dynamicType; | 341 if (typesReturned.isEmpty) return types.dynamicType; |
| 154 TypeInformation returnType; | 342 TypeInformation returnType; |
| 155 for (var type in typesReturned) { | 343 for (var type in typesReturned) { |
| 156 TypeInformation mappedType; | 344 TypeInformation mappedType; |
| 157 if (type == native.SpecialType.JsObject) { | 345 if (type == native.SpecialType.JsObject) { |
| 158 mappedType = types.nonNullExact(commonElements.objectClass); | 346 mappedType = types.nonNullExact(commonElements.objectClass); |
| 159 } else if (type == commonElements.stringType) { | 347 } else if (type == commonElements.stringType) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 return generativeConstructorsExposingThis.contains(element); | 406 return generativeConstructorsExposingThis.contains(element); |
| 219 } | 407 } |
| 220 | 408 |
| 221 void recordExposesThis(ConstructorElement element, bool exposesThis) { | 409 void recordExposesThis(ConstructorElement element, bool exposesThis) { |
| 222 element = element.implementation; | 410 element = element.implementation; |
| 223 if (exposesThis) { | 411 if (exposesThis) { |
| 224 generativeConstructorsExposingThis.add(element); | 412 generativeConstructorsExposingThis.add(element); |
| 225 } | 413 } |
| 226 } | 414 } |
| 227 | 415 |
| 228 JavaScriptBackend get backend => compiler.backend; | |
| 229 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; | |
| 230 DiagnosticReporter get reporter => compiler.reporter; | |
| 231 CommonMasks get commonMasks => closedWorld.commonMasks; | |
| 232 | |
| 233 /** | |
| 234 * A set of selector names that [List] implements, that we know return | |
| 235 * their element type. | |
| 236 */ | |
| 237 final Set<Selector> returnsListElementTypeSet = | |
| 238 new Set<Selector>.from(<Selector>[ | |
| 239 new Selector.getter(const PublicName('first')), | |
| 240 new Selector.getter(const PublicName('last')), | |
| 241 new Selector.getter(const PublicName('single')), | |
| 242 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), | |
| 243 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), | |
| 244 new Selector.index(), | |
| 245 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), | |
| 246 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) | |
| 247 ]); | |
| 248 | |
| 249 bool returnsListElementType(Selector selector, TypeMask mask) { | 416 bool returnsListElementType(Selector selector, TypeMask mask) { |
| 250 return mask != null && | 417 return mask != null && |
| 251 mask.isContainer && | 418 mask.isContainer && |
| 252 returnsListElementTypeSet.contains(selector); | 419 returnsListElementTypeSet.contains(selector); |
| 253 } | 420 } |
| 254 | 421 |
| 255 bool returnsMapValueType(Selector selector, TypeMask mask) { | 422 bool returnsMapValueType(Selector selector, TypeMask mask) { |
| 256 return mask != null && mask.isMap && selector.isIndex; | 423 return mask != null && mask.isMap && selector.isIndex; |
| 257 } | 424 } |
| 258 | 425 |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 } | 791 } |
| 625 } | 792 } |
| 626 | 793 |
| 627 void buildWorkQueue() { | 794 void buildWorkQueue() { |
| 628 workQueue.addAll(types.orderedTypeInformations); | 795 workQueue.addAll(types.orderedTypeInformations); |
| 629 workQueue.addAll(types.allocatedTypes); | 796 workQueue.addAll(types.allocatedTypes); |
| 630 workQueue.addAll(types.allocatedClosures); | 797 workQueue.addAll(types.allocatedClosures); |
| 631 workQueue.addAll(types.allocatedCalls); | 798 workQueue.addAll(types.allocatedCalls); |
| 632 } | 799 } |
| 633 | 800 |
| 634 /** | |
| 635 * Update the assignments to parameters in the graph. [remove] tells | |
| 636 * wheter assignments must be added or removed. If [init] is false, | |
| 637 * parameters are added to the work queue. | |
| 638 */ | |
| 639 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 801 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
| 640 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 802 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 641 {bool remove, bool addToQueue: true}) { | 803 {bool remove, bool addToQueue: true}) { |
| 642 if (callee.name == Identifiers.noSuchMethod_) return; | 804 if (callee.name == Identifiers.noSuchMethod_) return; |
| 643 if (callee.isField) { | 805 if (callee.isField) { |
| 644 if (selector.isSetter) { | 806 if (selector.isSetter) { |
| 645 ElementTypeInformation info = types.getInferredTypeOfMember(callee); | 807 ElementTypeInformation info = types.getInferredTypeOfMember(callee); |
| 646 if (remove) { | 808 if (remove) { |
| 647 info.removeAssignment(arguments.positional[0]); | 809 info.removeAssignment(arguments.positional[0]); |
| 648 } else { | 810 } else { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 703 info.removeAssignment(type); | 865 info.removeAssignment(type); |
| 704 } else { | 866 } else { |
| 705 info.addAssignment(type); | 867 info.addAssignment(type); |
| 706 } | 868 } |
| 707 parameterIndex++; | 869 parameterIndex++; |
| 708 if (addToQueue) workQueue.add(info); | 870 if (addToQueue) workQueue.add(info); |
| 709 }); | 871 }); |
| 710 } | 872 } |
| 711 } | 873 } |
| 712 | 874 |
| 713 /** | |
| 714 * Sets the type of a parameter's default value to [type]. If the global | |
| 715 * mapping in [defaultTypeOfParameter] already contains a type, it must be | |
| 716 * a [PlaceholderTypeInformation], which will be replaced. All its uses are | |
| 717 * updated. | |
| 718 */ | |
| 719 void setDefaultTypeOfParameter( | 875 void setDefaultTypeOfParameter( |
| 720 ParameterElement parameter, TypeInformation type) { | 876 ParameterElement parameter, TypeInformation type) { |
| 721 assert(parameter.functionDeclaration.isImplementation); | 877 assert(parameter.functionDeclaration.isImplementation); |
| 722 TypeInformation existing = defaultTypeOfParameter[parameter]; | 878 TypeInformation existing = defaultTypeOfParameter[parameter]; |
| 723 defaultTypeOfParameter[parameter] = type; | 879 defaultTypeOfParameter[parameter] = type; |
| 724 TypeInformation info = types.getInferredTypeOfParameter(parameter); | 880 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
| 725 if (existing != null && existing is PlaceholderTypeInformation) { | 881 if (existing != null && existing is PlaceholderTypeInformation) { |
| 726 // Replace references to [existing] to use [type] instead. | 882 // Replace references to [existing] to use [type] instead. |
| 727 if (parameter.functionDeclaration.isInstanceMember) { | 883 if (parameter.functionDeclaration.isInstanceMember) { |
| 728 ParameterAssignments assignments = info.assignments; | 884 ParameterAssignments assignments = info.assignments; |
| 729 assignments.replace(existing, type); | 885 assignments.replace(existing, type); |
| 730 } else { | 886 } else { |
| 731 List<TypeInformation> assignments = info.assignments; | 887 List<TypeInformation> assignments = info.assignments; |
| 732 for (int i = 0; i < assignments.length; i++) { | 888 for (int i = 0; i < assignments.length; i++) { |
| 733 if (assignments[i] == existing) { | 889 if (assignments[i] == existing) { |
| 734 assignments[i] = type; | 890 assignments[i] = type; |
| 735 } | 891 } |
| 736 } | 892 } |
| 737 } | 893 } |
| 738 // Also forward all users. | 894 // Also forward all users. |
| 739 type.addUsersOf(existing); | 895 type.addUsersOf(existing); |
| 740 } else { | 896 } else { |
| 741 assert(existing == null); | 897 assert(existing == null); |
| 742 } | 898 } |
| 743 } | 899 } |
| 744 | 900 |
| 745 /** | |
| 746 * Returns the [TypeInformation] node for the default value of a parameter. | |
| 747 * If this is queried before it is set by [setDefaultTypeOfParameter], a | |
| 748 * [PlaceholderTypeInformation] is returned, which will later be replaced | |
| 749 * by the actual node when [setDefaultTypeOfParameter] is called. | |
| 750 * | |
| 751 * Invariant: After graph construction, no [PlaceholderTypeInformation] nodes | |
| 752 * should be present and a default type for each parameter should | |
| 753 * exist. | |
| 754 */ | |
| 755 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter) { | 901 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter) { |
| 756 return defaultTypeOfParameter.putIfAbsent(parameter, () { | 902 return defaultTypeOfParameter.putIfAbsent(parameter, () { |
| 757 return new PlaceholderTypeInformation(types.currentMember); | 903 return new PlaceholderTypeInformation(types.currentMember); |
| 758 }); | 904 }); |
| 759 } | 905 } |
| 760 | 906 |
| 761 /** | |
| 762 * This helper breaks abstractions but is currently required to work around | |
| 763 * the wrong modeling of default values of optional parameters of | |
| 764 * synthetic constructors. | |
| 765 * | |
| 766 * TODO(johnniwinther): Remove once default values of synthetic parameters | |
| 767 * are fixed. | |
| 768 */ | |
| 769 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter) { | 907 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter) { |
| 770 TypeInformation seen = defaultTypeOfParameter[parameter]; | 908 TypeInformation seen = defaultTypeOfParameter[parameter]; |
| 771 return (seen != null && seen is! PlaceholderTypeInformation); | 909 return (seen != null && seen is! PlaceholderTypeInformation); |
| 772 } | 910 } |
| 773 | 911 |
| 774 /** | |
| 775 * Returns the type of [element]. | |
| 776 */ | |
| 777 TypeInformation typeOfParameter(ParameterElement element) { | 912 TypeInformation typeOfParameter(ParameterElement element) { |
| 778 return types.getInferredTypeOfParameter(element); | 913 return types.getInferredTypeOfParameter(element); |
| 779 } | 914 } |
| 780 | 915 |
| 781 /** | |
| 782 * Returns the type of [element]. | |
| 783 */ | |
| 784 TypeInformation typeOfMember(MemberElement element) { | 916 TypeInformation typeOfMember(MemberElement element) { |
| 785 if (element is MethodElement) return types.functionType; | 917 if (element is MethodElement) return types.functionType; |
| 786 return types.getInferredTypeOfMember(element); | 918 return types.getInferredTypeOfMember(element); |
| 787 } | 919 } |
| 788 | 920 |
| 789 /** | |
| 790 * Returns the return type of [element]. | |
| 791 */ | |
| 792 TypeInformation returnTypeOfMember(MemberElement element) { | 921 TypeInformation returnTypeOfMember(MemberElement element) { |
| 793 if (element is! MethodElement) return types.dynamicType; | 922 if (element is! MethodElement) return types.dynamicType; |
| 794 return types.getInferredTypeOfMember(element); | 923 return types.getInferredTypeOfMember(element); |
| 795 } | 924 } |
| 796 | 925 |
| 797 /** | |
| 798 * Records that [node] sets final field [element] to be of type [type]. | |
| 799 * | |
| 800 * [nodeHolder] is the element holder of [node]. | |
| 801 */ | |
| 802 void recordTypeOfFinalField(FieldElement element, TypeInformation type) { | 926 void recordTypeOfFinalField(FieldElement element, TypeInformation type) { |
| 803 types.getInferredTypeOfMember(element).addAssignment(type); | 927 types.getInferredTypeOfMember(element).addAssignment(type); |
| 804 } | 928 } |
| 805 | 929 |
| 806 /** | |
| 807 * Records that [node] sets non-final field [element] to be of type | |
| 808 * [type]. | |
| 809 */ | |
| 810 void recordTypeOfNonFinalField(FieldElement element, TypeInformation type) { | 930 void recordTypeOfNonFinalField(FieldElement element, TypeInformation type) { |
| 811 types.getInferredTypeOfMember(element).addAssignment(type); | 931 types.getInferredTypeOfMember(element).addAssignment(type); |
| 812 } | 932 } |
| 813 | 933 |
| 814 /** | |
| 815 * Records that [element] is of type [type]. | |
| 816 */ | |
| 817 // TODO(johnniwinther): Merge [recordTypeOfFinalField] and | |
| 818 // [recordTypeOfNonFinalField] with this? | |
| 819 void recordTypeOfField(FieldElement element, TypeInformation type) { | 934 void recordTypeOfField(FieldElement element, TypeInformation type) { |
| 820 types.getInferredTypeOfMember(element).addAssignment(type); | 935 types.getInferredTypeOfMember(element).addAssignment(type); |
| 821 } | 936 } |
| 822 | 937 |
| 823 /** | |
| 824 * Records that the return type [element] is of type [type]. | |
| 825 */ | |
| 826 void recordReturnType(MethodElement element, TypeInformation type) { | 938 void recordReturnType(MethodElement element, TypeInformation type) { |
| 827 TypeInformation info = types.getInferredTypeOfMember(element); | 939 TypeInformation info = types.getInferredTypeOfMember(element); |
| 828 if (element.name == '==') { | 940 if (element.name == '==') { |
| 829 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. | 941 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
| 830 info.addAssignment(types.boolType); | 942 info.addAssignment(types.boolType); |
| 831 } | 943 } |
| 832 // TODO(ngeoffray): Clean up. We do these checks because | 944 // TODO(ngeoffray): Clean up. We do these checks because |
| 833 // [SimpleTypesInferrer] deals with two different inferrers. | 945 // [SimpleTypesInferrer] deals with two different inferrers. |
| 834 if (type == null) return; | 946 if (type == null) return; |
| 835 if (info.assignments.isEmpty) info.addAssignment(type); | 947 if (info.assignments.isEmpty) info.addAssignment(type); |
| 836 } | 948 } |
| 837 | 949 |
| 838 /** | |
| 839 * Notifies to the inferrer that [analyzedElement] can have return | |
| 840 * type [newType]. [currentType] is the type the [ElementGraphBuilder] | |
| 841 * currently found. | |
| 842 * | |
| 843 * Returns the new type for [analyzedElement]. | |
| 844 */ | |
| 845 TypeInformation addReturnTypeForMethod( | 950 TypeInformation addReturnTypeForMethod( |
| 846 MethodElement element, TypeInformation unused, TypeInformation newType) { | 951 MethodElement element, TypeInformation unused, TypeInformation newType) { |
| 847 TypeInformation type = types.getInferredTypeOfMember(element); | 952 TypeInformation type = types.getInferredTypeOfMember(element); |
| 848 // TODO(ngeoffray): Clean up. We do this check because | 953 // TODO(ngeoffray): Clean up. We do this check because |
| 849 // [SimpleTypesInferrer] deals with two different inferrers. | 954 // [SimpleTypesInferrer] deals with two different inferrers. |
| 850 if (element.isGenerativeConstructor) return type; | 955 if (element.isGenerativeConstructor) return type; |
| 851 type.addAssignment(newType); | 956 type.addAssignment(newType); |
| 852 return type; | 957 return type; |
| 853 } | 958 } |
| 854 | 959 |
| 855 /** | |
| 856 * Registers that [caller] calls [callee] at location [node], with | |
| 857 * [selector], and [arguments]. Note that [selector] is null for | |
| 858 * forwarding constructors. | |
| 859 * | |
| 860 * [sideEffects] will be updated to incorporate [callee]'s side | |
| 861 * effects. | |
| 862 * | |
| 863 * [inLoop] tells whether the call happens in a loop. | |
| 864 */ | |
| 865 TypeInformation registerCalledMember( | 960 TypeInformation registerCalledMember( |
| 866 Spannable node, | 961 Spannable node, |
| 867 Selector selector, | 962 Selector selector, |
| 868 TypeMask mask, | 963 TypeMask mask, |
| 869 MemberElement caller, | 964 MemberElement caller, |
| 870 MemberElement callee, | 965 MemberElement callee, |
| 871 ArgumentsTypes arguments, | 966 ArgumentsTypes arguments, |
| 872 SideEffects sideEffects, | 967 SideEffects sideEffects, |
| 873 bool inLoop) { | 968 bool inLoop) { |
| 874 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( | 969 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( |
| (...skipping 15 matching lines...) Expand all Loading... |
| 890 if (cls.callType != null) { | 985 if (cls.callType != null) { |
| 891 types.allocatedClosures.add(info); | 986 types.allocatedClosures.add(info); |
| 892 } | 987 } |
| 893 } | 988 } |
| 894 info.addToGraph(this); | 989 info.addToGraph(this); |
| 895 types.allocatedCalls.add(info); | 990 types.allocatedCalls.add(info); |
| 896 updateSideEffects(sideEffects, selector, callee); | 991 updateSideEffects(sideEffects, selector, callee); |
| 897 return info; | 992 return info; |
| 898 } | 993 } |
| 899 | 994 |
| 900 /** | |
| 901 * Registers that [caller] calls [selector] with [receiverType] as | |
| 902 * receiver, and [arguments]. | |
| 903 * | |
| 904 * [sideEffects] will be updated to incorporate the potential | |
| 905 * callees' side effects. | |
| 906 * | |
| 907 * [inLoop] tells whether the call happens in a loop. | |
| 908 */ | |
| 909 TypeInformation registerCalledSelector( | 995 TypeInformation registerCalledSelector( |
| 910 ast.Node node, | 996 ast.Node node, |
| 911 Selector selector, | 997 Selector selector, |
| 912 TypeMask mask, | 998 TypeMask mask, |
| 913 TypeInformation receiverType, | 999 TypeInformation receiverType, |
| 914 MemberElement caller, | 1000 MemberElement caller, |
| 915 ArgumentsTypes arguments, | 1001 ArgumentsTypes arguments, |
| 916 SideEffects sideEffects, | 1002 SideEffects sideEffects, |
| 917 bool inLoop, | 1003 bool inLoop, |
| 918 bool isConditional) { | 1004 bool isConditional) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 935 receiverType, | 1021 receiverType, |
| 936 arguments, | 1022 arguments, |
| 937 inLoop, | 1023 inLoop, |
| 938 isConditional); | 1024 isConditional); |
| 939 | 1025 |
| 940 info.addToGraph(this); | 1026 info.addToGraph(this); |
| 941 types.allocatedCalls.add(info); | 1027 types.allocatedCalls.add(info); |
| 942 return info; | 1028 return info; |
| 943 } | 1029 } |
| 944 | 1030 |
| 945 /** | |
| 946 * Registers a call to await with an expression of type [argumentType] as | |
| 947 * argument. | |
| 948 */ | |
| 949 TypeInformation registerAwait(ast.Node node, TypeInformation argument) { | 1031 TypeInformation registerAwait(ast.Node node, TypeInformation argument) { |
| 950 AwaitTypeInformation info = | 1032 AwaitTypeInformation info = |
| 951 new AwaitTypeInformation<ast.Node>(types.currentMember, node); | 1033 new AwaitTypeInformation<ast.Node>(types.currentMember, node); |
| 952 info.addAssignment(argument); | 1034 info.addAssignment(argument); |
| 953 types.allocatedTypes.add(info); | 1035 types.allocatedTypes.add(info); |
| 954 return info; | 1036 return info; |
| 955 } | 1037 } |
| 956 | 1038 |
| 957 /** | |
| 958 * Registers a call to yield with an expression of type [argumentType] as | |
| 959 * argument. | |
| 960 */ | |
| 961 TypeInformation registerYield(ast.Node node, TypeInformation argument) { | 1039 TypeInformation registerYield(ast.Node node, TypeInformation argument) { |
| 962 YieldTypeInformation info = | 1040 YieldTypeInformation info = |
| 963 new YieldTypeInformation<ast.Node>(types.currentMember, node); | 1041 new YieldTypeInformation<ast.Node>(types.currentMember, node); |
| 964 info.addAssignment(argument); | 1042 info.addAssignment(argument); |
| 965 types.allocatedTypes.add(info); | 1043 types.allocatedTypes.add(info); |
| 966 return info; | 1044 return info; |
| 967 } | 1045 } |
| 968 | 1046 |
| 969 /** | |
| 970 * Registers that [caller] calls [closure] with [arguments]. | |
| 971 * | |
| 972 * [sideEffects] will be updated to incorporate the potential | |
| 973 * callees' side effects. | |
| 974 * | |
| 975 * [inLoop] tells whether the call happens in a loop. | |
| 976 */ | |
| 977 TypeInformation registerCalledClosure( | 1047 TypeInformation registerCalledClosure( |
| 978 ast.Node node, | 1048 ast.Node node, |
| 979 Selector selector, | 1049 Selector selector, |
| 980 TypeMask mask, | 1050 TypeMask mask, |
| 981 TypeInformation closure, | 1051 TypeInformation closure, |
| 982 MemberElement caller, | 1052 MemberElement caller, |
| 983 ArgumentsTypes arguments, | 1053 ArgumentsTypes arguments, |
| 984 SideEffects sideEffects, | 1054 SideEffects sideEffects, |
| 985 bool inLoop) { | 1055 bool inLoop) { |
| 986 sideEffects.setDependsOnSomething(); | 1056 sideEffects.setDependsOnSomething(); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 | 1137 |
| 1068 Iterable<MemberEntity> getCallersOf(MemberElement element) { | 1138 Iterable<MemberEntity> getCallersOf(MemberElement element) { |
| 1069 if (compiler.disableTypeInference) { | 1139 if (compiler.disableTypeInference) { |
| 1070 throw new UnsupportedError( | 1140 throw new UnsupportedError( |
| 1071 "Cannot query the type inferrer when type inference is disabled."); | 1141 "Cannot query the type inferrer when type inference is disabled."); |
| 1072 } | 1142 } |
| 1073 MemberTypeInformation info = types.getInferredTypeOfMember(element); | 1143 MemberTypeInformation info = types.getInferredTypeOfMember(element); |
| 1074 return info.callers; | 1144 return info.callers; |
| 1075 } | 1145 } |
| 1076 | 1146 |
| 1077 /** | |
| 1078 * Returns the type of [element] when being called with [selector]. | |
| 1079 */ | |
| 1080 TypeInformation typeOfMemberWithSelector( | 1147 TypeInformation typeOfMemberWithSelector( |
| 1081 MemberElement element, Selector selector) { | 1148 MemberElement element, Selector selector) { |
| 1082 return _typeOfElementWithSelector(element, selector); | |
| 1083 } | |
| 1084 | |
| 1085 /** | |
| 1086 * Returns the type of [element] when being called with [selector]. | |
| 1087 */ | |
| 1088 TypeInformation _typeOfElementWithSelector( | |
| 1089 MemberElement element, Selector selector) { | |
| 1090 if (element.name == Identifiers.noSuchMethod_ && | 1149 if (element.name == Identifiers.noSuchMethod_ && |
| 1091 selector.name != element.name) { | 1150 selector.name != element.name) { |
| 1092 // An invocation can resolve to a [noSuchMethod], in which case | 1151 // An invocation can resolve to a [noSuchMethod], in which case |
| 1093 // we get the return type of [noSuchMethod]. | 1152 // we get the return type of [noSuchMethod]. |
| 1094 return returnTypeOfMember(element); | 1153 return returnTypeOfMember(element); |
| 1095 } else if (selector.isGetter) { | 1154 } else if (selector.isGetter) { |
| 1096 if (element.isFunction) { | 1155 if (element.isFunction) { |
| 1097 // [functionType] is null if the inferrer did not run. | 1156 // [functionType] is null if the inferrer did not run. |
| 1098 return types.functionType == null | 1157 return types.functionType == null |
| 1099 ? types.dynamicType | 1158 ? types.dynamicType |
| 1100 : types.functionType; | 1159 : types.functionType; |
| 1101 } else if (element.isField) { | 1160 } else if (element.isField) { |
| 1102 return typeOfMember(element); | 1161 return typeOfMember(element); |
| 1103 } else if (Elements.isUnresolved(element)) { | 1162 } else if (Elements.isUnresolved(element)) { |
| 1104 return types.dynamicType; | 1163 return types.dynamicType; |
| 1105 } else { | 1164 } else { |
| 1106 assert(element.isGetter); | 1165 assert(element.isGetter); |
| 1107 return returnTypeOfMember(element); | 1166 return returnTypeOfMember(element); |
| 1108 } | 1167 } |
| 1109 } else if (element.isGetter || element.isField) { | 1168 } else if (element.isGetter || element.isField) { |
| 1110 assert(selector.isCall || selector.isSetter); | 1169 assert(selector.isCall || selector.isSetter); |
| 1111 return types.dynamicType; | 1170 return types.dynamicType; |
| 1112 } else { | 1171 } else { |
| 1113 return returnTypeOfMember(element); | 1172 return returnTypeOfMember(element); |
| 1114 } | 1173 } |
| 1115 } | 1174 } |
| 1116 | |
| 1117 /** | |
| 1118 * Records that the captured variable [local] is read. | |
| 1119 */ | |
| 1120 void recordCapturedLocalRead(Local local) {} | |
| 1121 | |
| 1122 /** | |
| 1123 * Records that the variable [local] is being updated. | |
| 1124 */ | |
| 1125 void recordLocalUpdate(Local local, TypeInformation type) {} | |
| 1126 } | 1175 } |
| 1127 | 1176 |
| 1128 class TypeSystemStrategyImpl implements TypeSystemStrategy<ast.Node> { | 1177 class TypeSystemStrategyImpl implements TypeSystemStrategy<ast.Node> { |
| 1129 const TypeSystemStrategyImpl(); | 1178 const TypeSystemStrategyImpl(); |
| 1130 | 1179 |
| 1131 @override | 1180 @override |
| 1132 MemberTypeInformation createMemberTypeInformation( | 1181 MemberTypeInformation createMemberTypeInformation( |
| 1133 covariant MemberElement member) { | 1182 covariant MemberElement member) { |
| 1134 assert(member.isDeclaration, failedAt(member)); | 1183 assert(member.isDeclaration, failedAt(member)); |
| 1135 if (member.isField) { | 1184 if (member.isField) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1218 @override | 1267 @override |
| 1219 bool checkPhiNode(ast.Node node) { | 1268 bool checkPhiNode(ast.Node node) { |
| 1220 return true; | 1269 return true; |
| 1221 } | 1270 } |
| 1222 | 1271 |
| 1223 @override | 1272 @override |
| 1224 bool checkClassEntity(covariant ClassElement cls) { | 1273 bool checkClassEntity(covariant ClassElement cls) { |
| 1225 return cls.isDeclaration; | 1274 return cls.isDeclaration; |
| 1226 } | 1275 } |
| 1227 } | 1276 } |
| OLD | NEW |