| 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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments); | 79 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments); |
| 80 void analyzeListAndEnqueue(ListTypeInformation info); | 80 void analyzeListAndEnqueue(ListTypeInformation info); |
| 81 void analyzeMapAndEnqueue(MapTypeInformation info); | 81 void analyzeMapAndEnqueue(MapTypeInformation info); |
| 82 | 82 |
| 83 /// Notifies to the inferrer that [analyzedElement] can have return type | 83 /// Notifies to the inferrer that [analyzedElement] can have return type |
| 84 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently | 84 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently |
| 85 /// found. | 85 /// found. |
| 86 /// | 86 /// |
| 87 /// Returns the new type for [analyzedElement]. | 87 /// Returns the new type for [analyzedElement]. |
| 88 TypeInformation addReturnTypeForMethod( | 88 TypeInformation addReturnTypeForMethod( |
| 89 MethodElement element, TypeInformation unused, TypeInformation newType); | 89 FunctionEntity element, TypeInformation unused, TypeInformation newType); |
| 90 | 90 |
| 91 /// Applies [f] to all elements in the universe that match [selector] and | 91 /// Applies [f] to all elements in the universe that match [selector] and |
| 92 /// [mask]. If [f] returns false, aborts the iteration. | 92 /// [mask]. If [f] returns false, aborts the iteration. |
| 93 void forEachElementMatching( | 93 void forEachElementMatching( |
| 94 Selector selector, TypeMask mask, bool f(Element element)); | 94 Selector selector, TypeMask mask, bool f(MemberEntity element)); |
| 95 | 95 |
| 96 /// Returns the [TypeInformation] node for the default value of a parameter. | 96 /// Returns the [TypeInformation] node for the default value of a parameter. |
| 97 /// If this is queried before it is set by [setDefaultTypeOfParameter], a | 97 /// If this is queried before it is set by [setDefaultTypeOfParameter], a |
| 98 /// [PlaceholderTypeInformation] is returned, which will later be replaced | 98 /// [PlaceholderTypeInformation] is returned, which will later be replaced |
| 99 /// by the actual node when [setDefaultTypeOfParameter] is called. | 99 /// by the actual node when [setDefaultTypeOfParameter] is called. |
| 100 /// | 100 /// |
| 101 /// Invariant: After graph construction, no [PlaceholderTypeInformation] nodes | 101 /// Invariant: After graph construction, no [PlaceholderTypeInformation] nodes |
| 102 /// should be present and a default type for each parameter should exist. | 102 /// should be present and a default type for each parameter should exist. |
| 103 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter); | 103 TypeInformation getDefaultTypeOfParameter(Local parameter); |
| 104 | 104 |
| 105 /// This helper breaks abstractions but is currently required to work around | 105 /// This helper breaks abstractions but is currently required to work around |
| 106 /// the wrong modeling of default values of optional parameters of | 106 /// the wrong modeling of default values of optional parameters of |
| 107 /// synthetic constructors. | 107 /// synthetic constructors. |
| 108 /// | 108 /// |
| 109 /// TODO(johnniwinther): Remove once default values of synthetic parameters | 109 /// TODO(johnniwinther): Remove once default values of synthetic parameters |
| 110 /// are fixed. | 110 /// are fixed. |
| 111 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter); | 111 bool hasAlreadyComputedTypeOfParameterDefault(Local parameter); |
| 112 | 112 |
| 113 /// Sets the type of a parameter's default value to [type]. If the global | 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 | 114 /// mapping in [defaultTypeOfParameter] already contains a type, it must be |
| 115 /// a [PlaceholderTypeInformation], which will be replaced. All its uses are | 115 /// a [PlaceholderTypeInformation], which will be replaced. All its uses are |
| 116 /// updated. | 116 /// updated. |
| 117 void setDefaultTypeOfParameter( | 117 void setDefaultTypeOfParameter(Local parameter, TypeInformation type); |
| 118 ParameterElement parameter, TypeInformation type); | |
| 119 | 118 |
| 120 Iterable<MemberEntity> getCallersOf(MemberElement element); | 119 Iterable<MemberEntity> getCallersOf(MemberEntity element); |
| 121 | 120 |
| 122 // TODO(johnniwinther): Make this private again. | 121 // TODO(johnniwinther): Make this private again. |
| 123 GlobalTypeInferenceElementData dataOfMember(MemberElement element); | 122 GlobalTypeInferenceElementData dataOfMember(MemberEntity element); |
| 124 | 123 |
| 125 GlobalTypeInferenceElementData lookupDataOfMember(MemberElement element); | 124 GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element); |
| 126 | 125 |
| 127 bool checkIfExposesThis(ConstructorElement element); | 126 bool checkIfExposesThis(ConstructorEntity element); |
| 128 | 127 |
| 129 void recordExposesThis(ConstructorElement element, bool exposesThis); | 128 void recordExposesThis(ConstructorEntity element, bool exposesThis); |
| 130 | 129 |
| 131 /// Records that the return type [element] is of type [type]. | 130 /// Records that the return type [element] is of type [type]. |
| 132 void recordReturnType(MethodElement element, TypeInformation type); | 131 void recordReturnType(FunctionEntity element, TypeInformation type); |
| 133 | 132 |
| 134 /// Records that [element] is of type [type]. | 133 /// Records that [element] is of type [type]. |
| 135 void recordTypeOfField(FieldElement element, TypeInformation type); | 134 void recordTypeOfField(FieldEntity element, TypeInformation type); |
| 136 | 135 |
| 137 /// Registers a call to await with an expression of type [argumentType] as | 136 /// Registers a call to await with an expression of type [argumentType] as |
| 138 /// argument. | 137 /// argument. |
| 139 TypeInformation registerAwait(ast.Node node, TypeInformation argument); | 138 TypeInformation registerAwait(ast.Node node, TypeInformation argument); |
| 140 | 139 |
| 141 /// Registers a call to yield with an expression of type [argumentType] as | 140 /// Registers a call to yield with an expression of type [argumentType] as |
| 142 /// argument. | 141 /// argument. |
| 143 TypeInformation registerYield(ast.Node node, TypeInformation argument); | 142 TypeInformation registerYield(ast.Node node, TypeInformation argument); |
| 144 | 143 |
| 145 /// Registers that [caller] calls [closure] with [arguments]. | 144 /// Registers that [caller] calls [closure] with [arguments]. |
| 146 /// | 145 /// |
| 147 /// [sideEffects] will be updated to incorporate the potential callees' side | 146 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 148 /// effects. | 147 /// effects. |
| 149 /// | 148 /// |
| 150 /// [inLoop] tells whether the call happens in a loop. | 149 /// [inLoop] tells whether the call happens in a loop. |
| 151 TypeInformation registerCalledClosure( | 150 TypeInformation registerCalledClosure( |
| 152 ast.Node node, | 151 ast.Node node, |
| 153 Selector selector, | 152 Selector selector, |
| 154 TypeMask mask, | 153 TypeMask mask, |
| 155 TypeInformation closure, | 154 TypeInformation closure, |
| 156 MemberElement caller, | 155 MemberEntity caller, |
| 157 ArgumentsTypes arguments, | 156 ArgumentsTypes arguments, |
| 158 SideEffects sideEffects, | 157 SideEffects sideEffects, |
| 159 bool inLoop); | 158 bool inLoop); |
| 160 | 159 |
| 161 /// Registers that [caller] calls [callee] at location [node], with | 160 /// Registers that [caller] calls [callee] at location [node], with |
| 162 /// [selector], and [arguments]. Note that [selector] is null for forwarding | 161 /// [selector], and [arguments]. Note that [selector] is null for forwarding |
| 163 /// constructors. | 162 /// constructors. |
| 164 /// | 163 /// |
| 165 /// [sideEffects] will be updated to incorporate [callee]'s side effects. | 164 /// [sideEffects] will be updated to incorporate [callee]'s side effects. |
| 166 /// | 165 /// |
| 167 /// [inLoop] tells whether the call happens in a loop. | 166 /// [inLoop] tells whether the call happens in a loop. |
| 168 TypeInformation registerCalledMember( | 167 TypeInformation registerCalledMember( |
| 169 Spannable node, | 168 Spannable node, |
| 170 Selector selector, | 169 Selector selector, |
| 171 TypeMask mask, | 170 TypeMask mask, |
| 172 MemberElement caller, | 171 MemberEntity caller, |
| 173 MemberElement callee, | 172 MemberEntity callee, |
| 174 ArgumentsTypes arguments, | 173 ArgumentsTypes arguments, |
| 175 SideEffects sideEffects, | 174 SideEffects sideEffects, |
| 176 bool inLoop); | 175 bool inLoop); |
| 177 | 176 |
| 178 /// Registers that [caller] calls [selector] with [receiverType] as receiver, | 177 /// Registers that [caller] calls [selector] with [receiverType] as receiver, |
| 179 /// and [arguments]. | 178 /// and [arguments]. |
| 180 /// | 179 /// |
| 181 /// [sideEffects] will be updated to incorporate the potential callees' side | 180 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 182 /// effects. | 181 /// effects. |
| 183 /// | 182 /// |
| 184 /// [inLoop] tells whether the call happens in a loop. | 183 /// [inLoop] tells whether the call happens in a loop. |
| 185 TypeInformation registerCalledSelector( | 184 TypeInformation registerCalledSelector( |
| 186 ast.Node node, | 185 ast.Node node, |
| 187 Selector selector, | 186 Selector selector, |
| 188 TypeMask mask, | 187 TypeMask mask, |
| 189 TypeInformation receiverType, | 188 TypeInformation receiverType, |
| 190 MemberElement caller, | 189 MemberEntity caller, |
| 191 ArgumentsTypes arguments, | 190 ArgumentsTypes arguments, |
| 192 SideEffects sideEffects, | 191 SideEffects sideEffects, |
| 193 bool inLoop, | 192 bool inLoop, |
| 194 bool isConditional); | 193 bool isConditional); |
| 195 | 194 |
| 196 /// Update the assignments to parameters in the graph. [remove] tells whether | 195 /// Update the assignments to parameters in the graph. [remove] tells whether |
| 197 /// assignments must be added or removed. If [init] is false, parameters are | 196 /// assignments must be added or removed. If [init] is false, parameters are |
| 198 /// added to the work queue. | 197 /// added to the work queue. |
| 199 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 198 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
| 200 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 199 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 201 {bool remove, bool addToQueue: true}); | 200 {bool remove, bool addToQueue: true}); |
| 202 | 201 |
| 203 void updateSelectorInMember( | 202 void updateSelectorInMember( |
| 204 MemberElement owner, Spannable node, Selector selector, TypeMask mask); | 203 MemberEntity owner, ast.Node node, Selector selector, TypeMask mask); |
| 205 | 204 |
| 206 /// Returns the return type of [element]. | 205 /// Returns the return type of [element]. |
| 207 TypeInformation returnTypeOfMember(MemberElement element); | 206 TypeInformation returnTypeOfMember(MemberEntity element); |
| 208 | 207 |
| 209 /// Returns the type of [element] when being called with [selector]. | 208 /// Returns the type of [element] when being called with [selector]. |
| 210 TypeInformation typeOfMemberWithSelector( | 209 TypeInformation typeOfMemberWithSelector( |
| 211 MemberElement element, Selector selector); | 210 MemberEntity element, Selector selector); |
| 212 | 211 |
| 213 /// Returns the type of [element]. | 212 /// Returns the type of [element]. |
| 214 TypeInformation typeOfMember(MemberElement element); | 213 TypeInformation typeOfMember(MemberEntity element); |
| 215 | 214 |
| 216 /// Returns the type of [element]. | 215 /// Returns the type of [element]. |
| 217 TypeInformation typeOfParameter(ParameterElement element); | 216 TypeInformation typeOfParameter(Local element); |
| 218 | 217 |
| 219 /// Returns the type for [nativeBehavior]. See documentation on | 218 /// Returns the type for [nativeBehavior]. See documentation on |
| 220 /// [native.NativeBehavior]. | 219 /// [native.NativeBehavior]. |
| 221 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); | 220 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); |
| 222 | 221 |
| 223 bool returnsListElementType(Selector selector, TypeMask mask); | 222 bool returnsListElementType(Selector selector, TypeMask mask); |
| 224 | 223 |
| 225 bool returnsMapValueType(Selector selector, TypeMask mask); | 224 bool returnsMapValueType(Selector selector, TypeMask mask); |
| 226 | 225 |
| 227 void clear(); | 226 void clear(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 247 /// The [ClosedWorld] on which inference reasoning is based. | 246 /// The [ClosedWorld] on which inference reasoning is based. |
| 248 final ClosedWorld closedWorld; | 247 final ClosedWorld closedWorld; |
| 249 | 248 |
| 250 final ClosedWorldRefiner closedWorldRefiner; | 249 final ClosedWorldRefiner closedWorldRefiner; |
| 251 final TypeSystem<ast.Node> types; | 250 final TypeSystem<ast.Node> types; |
| 252 final Map<ast.Node, TypeInformation> concreteTypes = | 251 final Map<ast.Node, TypeInformation> concreteTypes = |
| 253 new Map<ast.Node, TypeInformation>(); | 252 new Map<ast.Node, TypeInformation>(); |
| 254 | 253 |
| 255 final Map<ir.Node, TypeInformation> concreteKernelTypes = | 254 final Map<ir.Node, TypeInformation> concreteKernelTypes = |
| 256 new Map<ir.Node, TypeInformation>(); | 255 new Map<ir.Node, TypeInformation>(); |
| 257 final Set<ConstructorElement> generativeConstructorsExposingThis = | 256 final Set<ConstructorEntity> generativeConstructorsExposingThis = |
| 258 new Set<ConstructorElement>(); | 257 new Set<ConstructorEntity>(); |
| 259 | 258 |
| 260 /// Data computed internally within elements, like the type-mask of a send a | 259 /// Data computed internally within elements, like the type-mask of a send a |
| 261 /// list allocation, or a for-in loop. | 260 /// list allocation, or a for-in loop. |
| 262 final Map<MemberElement, GlobalTypeInferenceElementData> _memberData = | 261 final Map<MemberElement, GlobalTypeInferenceElementData> _memberData = |
| 263 new Map<MemberElement, GlobalTypeInferenceElementData>(); | 262 new Map<MemberElement, GlobalTypeInferenceElementData>(); |
| 264 | 263 |
| 265 InferrerEngineImpl(this.compiler, ClosedWorld closedWorld, | 264 InferrerEngineImpl(this.compiler, ClosedWorld closedWorld, |
| 266 this.closedWorldRefiner, this.mainElement) | 265 this.closedWorldRefiner, this.mainElement) |
| 267 : this.types = new TypeSystem<ast.Node>( | 266 : this.types = new TypeSystem<ast.Node>( |
| 268 closedWorld, const TypeSystemStrategyImpl()), | 267 closedWorld, const TypeSystemStrategyImpl()), |
| 269 this.closedWorld = closedWorld; | 268 this.closedWorld = closedWorld; |
| 270 | 269 |
| 271 void forEachElementMatching( | 270 void forEachElementMatching( |
| 272 Selector selector, TypeMask mask, bool f(Element element)) { | 271 Selector selector, TypeMask mask, bool f(MemberEntity element)) { |
| 273 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); | 272 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); |
| 274 for (MemberElement e in elements) { | 273 for (MemberElement e in elements) { |
| 275 if (!f(e.implementation)) return; | 274 if (!f(e)) return; |
| 276 } | 275 } |
| 277 } | 276 } |
| 278 | 277 |
| 279 // TODO(johnniwinther): Make this private again. | 278 // TODO(johnniwinther): Make this private again. |
| 280 GlobalTypeInferenceElementData dataOfMember(MemberElement element) => | 279 GlobalTypeInferenceElementData dataOfMember(MemberEntity element) => |
| 281 _memberData.putIfAbsent( | 280 _memberData.putIfAbsent( |
| 282 element, () => new GlobalTypeInferenceElementData()); | 281 element, () => new GlobalTypeInferenceElementData()); |
| 283 | 282 |
| 284 GlobalTypeInferenceElementData lookupDataOfMember(MemberElement element) => | 283 GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element) => |
| 285 _memberData[element]; | 284 _memberData[element]; |
| 286 | 285 |
| 287 /** | 286 /** |
| 288 * Update [sideEffects] with the side effects of [callee] being | 287 * Update [sideEffects] with the side effects of [callee] being |
| 289 * called with [selector]. | 288 * called with [selector]. |
| 290 */ | 289 */ |
| 291 void updateSideEffects( | 290 void updateSideEffects( |
| 292 SideEffects sideEffects, Selector selector, MemberElement callee) { | 291 SideEffects sideEffects, Selector selector, MemberElement callee) { |
| 293 if (callee.isField) { | 292 if (callee.isField) { |
| 294 if (callee.isInstanceMember) { | 293 if (callee.isInstanceMember) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 } | 350 } |
| 352 returnType = types.computeLUB(returnType, mappedType); | 351 returnType = types.computeLUB(returnType, mappedType); |
| 353 if (returnType == types.dynamicType) { | 352 if (returnType == types.dynamicType) { |
| 354 break; | 353 break; |
| 355 } | 354 } |
| 356 } | 355 } |
| 357 return returnType; | 356 return returnType; |
| 358 } | 357 } |
| 359 | 358 |
| 360 void updateSelectorInMember( | 359 void updateSelectorInMember( |
| 361 MemberElement owner, Spannable node, Selector selector, TypeMask mask) { | 360 MemberEntity owner, ast.Node node, Selector selector, TypeMask mask) { |
| 362 GlobalTypeInferenceElementData data = dataOfMember(owner); | 361 GlobalTypeInferenceElementData data = dataOfMember(owner); |
| 363 ast.Node astNode = node; | 362 if (node.asSendSet() != null) { |
| 364 if (astNode.asSendSet() != null) { | |
| 365 if (selector.isSetter || selector.isIndexSet) { | 363 if (selector.isSetter || selector.isIndexSet) { |
| 366 data.setTypeMask(node, mask); | 364 data.setTypeMask(node, mask); |
| 367 } else if (selector.isGetter || selector.isIndex) { | 365 } else if (selector.isGetter || selector.isIndex) { |
| 368 data.setGetterTypeMaskInComplexSendSet(node, mask); | 366 data.setGetterTypeMaskInComplexSendSet(node, mask); |
| 369 } else { | 367 } else { |
| 370 assert(selector.isOperator); | 368 assert(selector.isOperator); |
| 371 data.setOperatorTypeMaskInComplexSendSet(node, mask); | 369 data.setOperatorTypeMaskInComplexSendSet(node, mask); |
| 372 } | 370 } |
| 373 } else if (astNode.asSend() != null) { | 371 } else if (node.asSend() != null) { |
| 374 data.setTypeMask(node, mask); | 372 data.setTypeMask(node, mask); |
| 375 } else { | 373 } else { |
| 376 assert(astNode.asForIn() != null); | 374 assert(node.asForIn() != null); |
| 377 if (selector == Selectors.iterator) { | 375 if (selector == Selectors.iterator) { |
| 378 data.setIteratorTypeMask(node, mask); | 376 data.setIteratorTypeMask(node, mask); |
| 379 } else if (selector == Selectors.current) { | 377 } else if (selector == Selectors.current) { |
| 380 data.setCurrentTypeMask(node, mask); | 378 data.setCurrentTypeMask(node, mask); |
| 381 } else { | 379 } else { |
| 382 assert(selector == Selectors.moveNext); | 380 assert(selector == Selectors.moveNext); |
| 383 data.setMoveNextTypeMask(node, mask); | 381 data.setMoveNextTypeMask(node, mask); |
| 384 } | 382 } |
| 385 } | 383 } |
| 386 } | 384 } |
| 387 | 385 |
| 388 bool checkIfExposesThis(ConstructorElement element) { | 386 bool checkIfExposesThis(ConstructorEntity element) { |
| 389 element = element.implementation; | 387 assert(!(element is ConstructorElement && !element.isDeclaration)); |
| 390 return generativeConstructorsExposingThis.contains(element); | 388 return generativeConstructorsExposingThis.contains(element); |
| 391 } | 389 } |
| 392 | 390 |
| 393 void recordExposesThis(ConstructorElement element, bool exposesThis) { | 391 void recordExposesThis(ConstructorEntity element, bool exposesThis) { |
| 394 element = element.implementation; | 392 assert(!(element is ConstructorElement && !element.isDeclaration)); |
| 395 if (exposesThis) { | 393 if (exposesThis) { |
| 396 generativeConstructorsExposingThis.add(element); | 394 generativeConstructorsExposingThis.add(element); |
| 397 } | 395 } |
| 398 } | 396 } |
| 399 | 397 |
| 400 bool returnsListElementType(Selector selector, TypeMask mask) { | 398 bool returnsListElementType(Selector selector, TypeMask mask) { |
| 401 return mask != null && | 399 return mask != null && |
| 402 mask.isContainer && | 400 mask.isContainer && |
| 403 returnsListElementTypeSet.contains(selector); | 401 returnsListElementTypeSet.contains(selector); |
| 404 } | 402 } |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) | 649 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) |
| 652 : new ElementGraphBuilder(element, resolvedAst, compiler, this); | 650 : new ElementGraphBuilder(element, resolvedAst, compiler, this); |
| 653 TypeInformation type; | 651 TypeInformation type; |
| 654 reporter.withCurrentElement(element, () { | 652 reporter.withCurrentElement(element, () { |
| 655 // ignore: UNDEFINED_METHOD | 653 // ignore: UNDEFINED_METHOD |
| 656 type = visitor.run(); | 654 type = visitor.run(); |
| 657 }); | 655 }); |
| 658 addedInGraph++; | 656 addedInGraph++; |
| 659 | 657 |
| 660 if (element.isField) { | 658 if (element.isField) { |
| 661 FieldElement fieldElement = element; | 659 FieldElement field = element; |
| 662 ast.Node initializer = resolvedAst.body; | 660 ast.Node initializer = resolvedAst.body; |
| 663 if (element.isFinal || element.isConst) { | 661 if (field.isFinal || field.isConst) { |
| 664 // If [element] is final and has an initializer, we record | 662 // If [element] is final and has an initializer, we record |
| 665 // the inferred type. | 663 // the inferred type. |
| 666 if (resolvedAst.body != null) { | 664 if (resolvedAst.body != null) { |
| 667 if (type is! ListTypeInformation && type is! MapTypeInformation) { | 665 if (type is! ListTypeInformation && type is! MapTypeInformation) { |
| 668 // For non-container types, the constant handler does | 666 // For non-container types, the constant handler does |
| 669 // constant folding that could give more precise results. | 667 // constant folding that could give more precise results. |
| 670 ConstantExpression constant = fieldElement.constant; | 668 ConstantExpression constant = field.constant; |
| 671 if (constant != null) { | 669 if (constant != null) { |
| 672 ConstantValue value = | 670 ConstantValue value = |
| 673 compiler.backend.constants.getConstantValue(constant); | 671 compiler.backend.constants.getConstantValue(constant); |
| 674 if (value != null) { | 672 if (value != null) { |
| 675 if (value.isFunction) { | 673 if (value.isFunction) { |
| 676 FunctionConstantValue functionConstant = value; | 674 FunctionConstantValue functionConstant = value; |
| 677 MethodElement function = functionConstant.element; | 675 MethodElement function = functionConstant.element; |
| 678 type = types.allocateClosure(function); | 676 type = types.allocateClosure(function); |
| 679 } else { | 677 } else { |
| 680 // Although we might find a better type, we have to keep | 678 // Although we might find a better type, we have to keep |
| 681 // the old type around to ensure that we get a complete view | 679 // the old type around to ensure that we get a complete view |
| 682 // of the type graph and do not drop any flow edges. | 680 // of the type graph and do not drop any flow edges. |
| 683 TypeMask refinedType = computeTypeMask(closedWorld, value); | 681 TypeMask refinedType = computeTypeMask(closedWorld, value); |
| 684 assert(TypeMask.assertIsNormalized(refinedType, closedWorld)); | 682 assert(TypeMask.assertIsNormalized(refinedType, closedWorld)); |
| 685 type = new NarrowTypeInformation(type, refinedType); | 683 type = new NarrowTypeInformation(type, refinedType); |
| 686 types.allocatedTypes.add(type); | 684 types.allocatedTypes.add(type); |
| 687 } | 685 } |
| 688 } else { | 686 } else { |
| 689 assert( | 687 assert( |
| 690 fieldElement.isInstanceMember || | 688 field.isInstanceMember || |
| 691 constant.isImplicit || | 689 constant.isImplicit || |
| 692 constant.isPotential, | 690 constant.isPotential, |
| 693 failedAt( | 691 failedAt( |
| 694 fieldElement, | 692 field, |
| 695 "Constant expression without value: " | 693 "Constant expression without value: " |
| 696 "${constant.toStructuredText()}.")); | 694 "${constant.toStructuredText()}.")); |
| 697 } | 695 } |
| 698 } | 696 } |
| 699 } | 697 } |
| 700 recordTypeOfField(element, type); | 698 recordTypeOfField(field, type); |
| 701 } else if (!element.isInstanceMember) { | 699 } else if (!element.isInstanceMember) { |
| 702 recordTypeOfField(element, types.nullType); | 700 recordTypeOfField(field, types.nullType); |
| 703 } | 701 } |
| 704 } else if (initializer == null) { | 702 } else if (initializer == null) { |
| 705 // Only update types of static fields if there is no | 703 // Only update types of static fields if there is no |
| 706 // assignment. Instance fields are dealt with in the constructor. | 704 // assignment. Instance fields are dealt with in the constructor. |
| 707 if (Elements.isStaticOrTopLevelField(element)) { | 705 if (Elements.isStaticOrTopLevelField(element)) { |
| 708 recordTypeOfField(element, type); | 706 recordTypeOfField(field, type); |
| 709 } | 707 } |
| 710 } else { | 708 } else { |
| 711 recordTypeOfField(element, type); | 709 recordTypeOfField(field, type); |
| 712 } | 710 } |
| 713 if (Elements.isStaticOrTopLevelField(element) && | 711 if (Elements.isStaticOrTopLevelField(field) && |
| 714 resolvedAst.body != null && | 712 resolvedAst.body != null && |
| 715 !element.isConst) { | 713 !element.isConst) { |
| 716 dynamic argument = resolvedAst.body; | 714 dynamic argument = resolvedAst.body; |
| 717 // TODO(13429): We could do better here by using the | 715 // TODO(13429): We could do better here by using the |
| 718 // constant handler to figure out if it's a lazy field or not. | 716 // constant handler to figure out if it's a lazy field or not. |
| 719 if (argument.asSend() != null || | 717 if (argument.asSend() != null || |
| 720 (argument.asNewExpression() != null && !argument.isConst)) { | 718 (argument.asNewExpression() != null && !argument.isConst)) { |
| 721 recordTypeOfField(element, types.nullType); | 719 recordTypeOfField(field, types.nullType); |
| 722 } | 720 } |
| 723 } | 721 } |
| 724 } else { | 722 } else { |
| 725 recordReturnType(element, type); | 723 MethodElement method = element; |
| 724 recordReturnType(method, type); |
| 726 } | 725 } |
| 727 } | 726 } |
| 728 | 727 |
| 729 void processLoopInformation() { | 728 void processLoopInformation() { |
| 730 types.allocatedCalls.forEach((dynamic info) { | 729 types.allocatedCalls.forEach((dynamic info) { |
| 731 if (!info.inLoop) return; | 730 if (!info.inLoop) return; |
| 732 if (info is StaticCallSiteTypeInformation) { | 731 if (info is StaticCallSiteTypeInformation) { |
| 733 MemberEntity member = info.calledElement; | 732 MemberEntity member = info.calledElement; |
| 734 closedWorldRefiner.addFunctionCalledInLoop(member); | 733 closedWorldRefiner.addFunctionCalledInLoop(member); |
| 735 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { | 734 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 850 } else { | 849 } else { |
| 851 info.addAssignment(type); | 850 info.addAssignment(type); |
| 852 } | 851 } |
| 853 parameterIndex++; | 852 parameterIndex++; |
| 854 if (addToQueue) workQueue.add(info); | 853 if (addToQueue) workQueue.add(info); |
| 855 }); | 854 }); |
| 856 } | 855 } |
| 857 } | 856 } |
| 858 | 857 |
| 859 void setDefaultTypeOfParameter( | 858 void setDefaultTypeOfParameter( |
| 860 ParameterElement parameter, TypeInformation type) { | 859 covariant ParameterElement parameter, TypeInformation type) { |
| 861 assert(parameter.functionDeclaration.isImplementation); | 860 assert(parameter.functionDeclaration.isImplementation); |
| 862 TypeInformation existing = defaultTypeOfParameter[parameter]; | 861 TypeInformation existing = defaultTypeOfParameter[parameter]; |
| 863 defaultTypeOfParameter[parameter] = type; | 862 defaultTypeOfParameter[parameter] = type; |
| 864 TypeInformation info = types.getInferredTypeOfParameter(parameter); | 863 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
| 865 if (existing != null && existing is PlaceholderTypeInformation) { | 864 if (existing != null && existing is PlaceholderTypeInformation) { |
| 866 // Replace references to [existing] to use [type] instead. | 865 // Replace references to [existing] to use [type] instead. |
| 867 if (parameter.functionDeclaration.isInstanceMember) { | 866 if (parameter.functionDeclaration.isInstanceMember) { |
| 868 ParameterAssignments assignments = info.assignments; | 867 ParameterAssignments assignments = info.assignments; |
| 869 assignments.replace(existing, type); | 868 assignments.replace(existing, type); |
| 870 } else { | 869 } else { |
| 871 List<TypeInformation> assignments = info.assignments; | 870 List<TypeInformation> assignments = info.assignments; |
| 872 for (int i = 0; i < assignments.length; i++) { | 871 for (int i = 0; i < assignments.length; i++) { |
| 873 if (assignments[i] == existing) { | 872 if (assignments[i] == existing) { |
| 874 assignments[i] = type; | 873 assignments[i] = type; |
| 875 } | 874 } |
| 876 } | 875 } |
| 877 } | 876 } |
| 878 // Also forward all users. | 877 // Also forward all users. |
| 879 type.addUsersOf(existing); | 878 type.addUsersOf(existing); |
| 880 } else { | 879 } else { |
| 881 assert(existing == null); | 880 assert(existing == null); |
| 882 } | 881 } |
| 883 } | 882 } |
| 884 | 883 |
| 885 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter) { | 884 TypeInformation getDefaultTypeOfParameter(Local parameter) { |
| 886 return defaultTypeOfParameter.putIfAbsent(parameter, () { | 885 return defaultTypeOfParameter.putIfAbsent(parameter, () { |
| 887 return new PlaceholderTypeInformation(types.currentMember); | 886 return new PlaceholderTypeInformation(types.currentMember); |
| 888 }); | 887 }); |
| 889 } | 888 } |
| 890 | 889 |
| 891 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter) { | 890 bool hasAlreadyComputedTypeOfParameterDefault(Local parameter) { |
| 892 TypeInformation seen = defaultTypeOfParameter[parameter]; | 891 TypeInformation seen = defaultTypeOfParameter[parameter]; |
| 893 return (seen != null && seen is! PlaceholderTypeInformation); | 892 return (seen != null && seen is! PlaceholderTypeInformation); |
| 894 } | 893 } |
| 895 | 894 |
| 896 TypeInformation typeOfParameter(ParameterElement element) { | 895 TypeInformation typeOfParameter(Local element) { |
| 897 return types.getInferredTypeOfParameter(element); | 896 return types.getInferredTypeOfParameter(element); |
| 898 } | 897 } |
| 899 | 898 |
| 900 TypeInformation typeOfMember(MemberElement element) { | 899 TypeInformation typeOfMember(MemberEntity element) { |
| 901 if (element is MethodElement) return types.functionType; | 900 if (element is FunctionEntity) return types.functionType; |
| 902 return types.getInferredTypeOfMember(element); | 901 return types.getInferredTypeOfMember(element); |
| 903 } | 902 } |
| 904 | 903 |
| 905 TypeInformation returnTypeOfMember(MemberElement element) { | 904 TypeInformation returnTypeOfMember(MemberEntity element) { |
| 906 if (element is! MethodElement) return types.dynamicType; | 905 if (element is! FunctionEntity) return types.dynamicType; |
| 907 return types.getInferredTypeOfMember(element); | 906 return types.getInferredTypeOfMember(element); |
| 908 } | 907 } |
| 909 | 908 |
| 910 void recordTypeOfField(FieldElement element, TypeInformation type) { | 909 void recordTypeOfField(FieldEntity element, TypeInformation type) { |
| 911 types.getInferredTypeOfMember(element).addAssignment(type); | 910 types.getInferredTypeOfMember(element).addAssignment(type); |
| 912 } | 911 } |
| 913 | 912 |
| 914 void recordReturnType(MethodElement element, TypeInformation type) { | 913 void recordReturnType(FunctionEntity element, TypeInformation type) { |
| 915 TypeInformation info = types.getInferredTypeOfMember(element); | 914 TypeInformation info = types.getInferredTypeOfMember(element); |
| 916 if (element.name == '==') { | 915 if (element.name == '==') { |
| 917 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. | 916 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
| 918 info.addAssignment(types.boolType); | 917 info.addAssignment(types.boolType); |
| 919 } | 918 } |
| 920 // TODO(ngeoffray): Clean up. We do these checks because | 919 // TODO(ngeoffray): Clean up. We do these checks because |
| 921 // [SimpleTypesInferrer] deals with two different inferrers. | 920 // [SimpleTypesInferrer] deals with two different inferrers. |
| 922 if (type == null) return; | 921 if (type == null) return; |
| 923 if (info.assignments.isEmpty) info.addAssignment(type); | 922 if (info.assignments.isEmpty) info.addAssignment(type); |
| 924 } | 923 } |
| 925 | 924 |
| 926 TypeInformation addReturnTypeForMethod( | 925 TypeInformation addReturnTypeForMethod(covariant MethodElement element, |
| 927 MethodElement element, TypeInformation unused, TypeInformation newType) { | 926 TypeInformation unused, TypeInformation newType) { |
| 928 TypeInformation type = types.getInferredTypeOfMember(element); | 927 TypeInformation type = types.getInferredTypeOfMember(element); |
| 929 // TODO(ngeoffray): Clean up. We do this check because | 928 // TODO(ngeoffray): Clean up. We do this check because |
| 930 // [SimpleTypesInferrer] deals with two different inferrers. | 929 // [SimpleTypesInferrer] deals with two different inferrers. |
| 931 if (element.isGenerativeConstructor) return type; | 930 if (element.isGenerativeConstructor) return type; |
| 932 type.addAssignment(newType); | 931 type.addAssignment(newType); |
| 933 return type; | 932 return type; |
| 934 } | 933 } |
| 935 | 934 |
| 936 TypeInformation registerCalledMember( | 935 TypeInformation registerCalledMember( |
| 937 Spannable node, | 936 Spannable node, |
| 938 Selector selector, | 937 Selector selector, |
| 939 TypeMask mask, | 938 TypeMask mask, |
| 940 MemberElement caller, | 939 MemberEntity caller, |
| 941 MemberElement callee, | 940 covariant MemberElement callee, |
| 942 ArgumentsTypes arguments, | 941 ArgumentsTypes arguments, |
| 943 SideEffects sideEffects, | 942 SideEffects sideEffects, |
| 944 bool inLoop) { | 943 bool inLoop) { |
| 945 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( | 944 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( |
| 946 types.currentMember, | 945 types.currentMember, |
| 947 node, | 946 node, |
| 948 caller, | 947 caller, |
| 949 callee, | 948 callee, |
| 950 selector, | 949 selector, |
| 951 mask, | 950 mask, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 966 types.allocatedCalls.add(info); | 965 types.allocatedCalls.add(info); |
| 967 updateSideEffects(sideEffects, selector, callee); | 966 updateSideEffects(sideEffects, selector, callee); |
| 968 return info; | 967 return info; |
| 969 } | 968 } |
| 970 | 969 |
| 971 TypeInformation registerCalledSelector( | 970 TypeInformation registerCalledSelector( |
| 972 ast.Node node, | 971 ast.Node node, |
| 973 Selector selector, | 972 Selector selector, |
| 974 TypeMask mask, | 973 TypeMask mask, |
| 975 TypeInformation receiverType, | 974 TypeInformation receiverType, |
| 976 MemberElement caller, | 975 MemberEntity caller, |
| 977 ArgumentsTypes arguments, | 976 ArgumentsTypes arguments, |
| 978 SideEffects sideEffects, | 977 SideEffects sideEffects, |
| 979 bool inLoop, | 978 bool inLoop, |
| 980 bool isConditional) { | 979 bool isConditional) { |
| 981 if (selector.isClosureCall) { | 980 if (selector.isClosureCall) { |
| 982 return registerCalledClosure(node, selector, mask, receiverType, caller, | 981 return registerCalledClosure(node, selector, mask, receiverType, caller, |
| 983 arguments, sideEffects, inLoop); | 982 arguments, sideEffects, inLoop); |
| 984 } | 983 } |
| 985 | 984 |
| 986 closedWorld.locateMembers(selector, mask).forEach((_callee) { | 985 closedWorld.locateMembers(selector, mask).forEach((_callee) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1018 info.addAssignment(argument); | 1017 info.addAssignment(argument); |
| 1019 types.allocatedTypes.add(info); | 1018 types.allocatedTypes.add(info); |
| 1020 return info; | 1019 return info; |
| 1021 } | 1020 } |
| 1022 | 1021 |
| 1023 TypeInformation registerCalledClosure( | 1022 TypeInformation registerCalledClosure( |
| 1024 ast.Node node, | 1023 ast.Node node, |
| 1025 Selector selector, | 1024 Selector selector, |
| 1026 TypeMask mask, | 1025 TypeMask mask, |
| 1027 TypeInformation closure, | 1026 TypeInformation closure, |
| 1028 MemberElement caller, | 1027 MemberEntity caller, |
| 1029 ArgumentsTypes arguments, | 1028 ArgumentsTypes arguments, |
| 1030 SideEffects sideEffects, | 1029 SideEffects sideEffects, |
| 1031 bool inLoop) { | 1030 bool inLoop) { |
| 1032 sideEffects.setDependsOnSomething(); | 1031 sideEffects.setDependsOnSomething(); |
| 1033 sideEffects.setAllSideEffects(); | 1032 sideEffects.setAllSideEffects(); |
| 1034 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( | 1033 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( |
| 1035 types.currentMember, | 1034 types.currentMember, |
| 1036 node, | 1035 node, |
| 1037 caller, | 1036 caller, |
| 1038 selector, | 1037 selector, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1104 types.allocatedClosures.forEach(cleanup); | 1103 types.allocatedClosures.forEach(cleanup); |
| 1105 types.allocatedClosures.clear(); | 1104 types.allocatedClosures.clear(); |
| 1106 | 1105 |
| 1107 analyzedElements.clear(); | 1106 analyzedElements.clear(); |
| 1108 generativeConstructorsExposingThis.clear(); | 1107 generativeConstructorsExposingThis.clear(); |
| 1109 | 1108 |
| 1110 types.allocatedMaps.values.forEach(cleanup); | 1109 types.allocatedMaps.values.forEach(cleanup); |
| 1111 types.allocatedLists.values.forEach(cleanup); | 1110 types.allocatedLists.values.forEach(cleanup); |
| 1112 } | 1111 } |
| 1113 | 1112 |
| 1114 Iterable<MemberEntity> getCallersOf(MemberElement element) { | 1113 Iterable<MemberEntity> getCallersOf(MemberEntity element) { |
| 1115 if (compiler.disableTypeInference) { | 1114 if (compiler.disableTypeInference) { |
| 1116 throw new UnsupportedError( | 1115 throw new UnsupportedError( |
| 1117 "Cannot query the type inferrer when type inference is disabled."); | 1116 "Cannot query the type inferrer when type inference is disabled."); |
| 1118 } | 1117 } |
| 1119 MemberTypeInformation info = types.getInferredTypeOfMember(element); | 1118 MemberTypeInformation info = types.getInferredTypeOfMember(element); |
| 1120 return info.callers; | 1119 return info.callers; |
| 1121 } | 1120 } |
| 1122 | 1121 |
| 1123 TypeInformation typeOfMemberWithSelector( | 1122 TypeInformation typeOfMemberWithSelector( |
| 1124 MemberElement element, Selector selector) { | 1123 covariant MemberElement element, Selector selector) { |
| 1125 if (element.name == Identifiers.noSuchMethod_ && | 1124 if (element.name == Identifiers.noSuchMethod_ && |
| 1126 selector.name != element.name) { | 1125 selector.name != element.name) { |
| 1127 // An invocation can resolve to a [noSuchMethod], in which case | 1126 // An invocation can resolve to a [noSuchMethod], in which case |
| 1128 // we get the return type of [noSuchMethod]. | 1127 // we get the return type of [noSuchMethod]. |
| 1129 return returnTypeOfMember(element); | 1128 return returnTypeOfMember(element); |
| 1130 } else if (selector.isGetter) { | 1129 } else if (selector.isGetter) { |
| 1131 if (element.isFunction) { | 1130 if (element.isFunction) { |
| 1132 // [functionType] is null if the inferrer did not run. | 1131 // [functionType] is null if the inferrer did not run. |
| 1133 return types.functionType == null | 1132 return types.functionType == null |
| 1134 ? types.dynamicType | 1133 ? types.dynamicType |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1243 @override | 1242 @override |
| 1244 bool checkPhiNode(ast.Node node) { | 1243 bool checkPhiNode(ast.Node node) { |
| 1245 return true; | 1244 return true; |
| 1246 } | 1245 } |
| 1247 | 1246 |
| 1248 @override | 1247 @override |
| 1249 bool checkClassEntity(covariant ClassElement cls) { | 1248 bool checkClassEntity(covariant ClassElement cls) { |
| 1250 return cls.isDeclaration; | 1249 return cls.isDeclaration; |
| 1251 } | 1250 } |
| 1252 } | 1251 } |
| OLD | NEW |