| 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 25 matching lines...) Expand all Loading... |
| 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 /** |
| 41 * An inferencing engine that computes a call graph of | 41 * An inferencing engine that computes a call graph of |
| 42 * [TypeInformation] nodes by visiting the AST of the application, and | 42 * [TypeInformation] nodes by visiting the AST of the application, and |
| 43 * then does the inferencing on the graph. | 43 * then does the inferencing on the graph. |
| 44 */ | 44 */ |
| 45 class InferrerEngine { | 45 class InferrerEngine { |
| 46 final Map<Element, TypeInformation> defaultTypeOfParameter = | 46 final Map<ParameterElement, TypeInformation> defaultTypeOfParameter = |
| 47 new Map<Element, TypeInformation>(); | 47 new Map<ParameterElement, TypeInformation>(); |
| 48 final WorkQueue workQueue = new WorkQueue(); | 48 final WorkQueue workQueue = new WorkQueue(); |
| 49 final FunctionEntity mainElement; | 49 final FunctionEntity mainElement; |
| 50 final Set<Element> analyzedElements = new Set<Element>(); | 50 final Set<MemberElement> analyzedElements = new Set<MemberElement>(); |
| 51 | 51 |
| 52 /// The maximum number of times we allow a node in the graph to | 52 /// 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 | 53 /// change types. If a node reaches that limit, we give up |
| 54 /// inferencing on it and give it the dynamic type. | 54 /// inferencing on it and give it the dynamic type. |
| 55 final int MAX_CHANGE_COUNT = 6; | 55 final int MAX_CHANGE_COUNT = 6; |
| 56 | 56 |
| 57 int overallRefineCount = 0; | 57 int overallRefineCount = 0; |
| 58 int addedInGraph = 0; | 58 int addedInGraph = 0; |
| 59 | 59 |
| 60 final Compiler compiler; | 60 final Compiler compiler; |
| 61 | 61 |
| 62 /// The [ClosedWorld] on which inference reasoning is based. | 62 /// The [ClosedWorld] on which inference reasoning is based. |
| 63 final ClosedWorld closedWorld; | 63 final ClosedWorld closedWorld; |
| 64 | 64 |
| 65 final ClosedWorldRefiner closedWorldRefiner; | 65 final ClosedWorldRefiner closedWorldRefiner; |
| 66 final TypeSystem types; | 66 final TypeSystem types; |
| 67 final Map<ast.Node, TypeInformation> concreteTypes = | 67 final Map<ast.Node, TypeInformation> concreteTypes = |
| 68 new Map<ast.Node, TypeInformation>(); | 68 new Map<ast.Node, TypeInformation>(); |
| 69 | 69 |
| 70 /// Parallel structure for concreteTypes. | 70 /// Parallel structure for concreteTypes. |
| 71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by | 71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by |
| 72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. | 72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. |
| 73 final Map<ir.Node, TypeInformation> concreteKernelTypes = | 73 final Map<ir.Node, TypeInformation> concreteKernelTypes = |
| 74 new Map<ir.Node, TypeInformation>(); | 74 new Map<ir.Node, TypeInformation>(); |
| 75 final Set<Element> generativeConstructorsExposingThis = new Set<Element>(); | 75 final Set<ConstructorElement> generativeConstructorsExposingThis = |
| 76 new Set<ConstructorElement>(); |
| 76 | 77 |
| 77 /// Data computed internally within elements, like the type-mask of a send a | 78 /// Data computed internally within elements, like the type-mask of a send a |
| 78 /// list allocation, or a for-in loop. | 79 /// list allocation, or a for-in loop. |
| 79 final Map<Element, GlobalTypeInferenceElementData> inTreeData = | 80 final Map<Element, GlobalTypeInferenceElementData> inTreeData = |
| 80 new Map<Element, GlobalTypeInferenceElementData>(); | 81 new Map<Element, GlobalTypeInferenceElementData>(); |
| 81 | 82 |
| 82 InferrerEngine(this.compiler, ClosedWorld closedWorld, | 83 InferrerEngine(this.compiler, ClosedWorld closedWorld, |
| 83 this.closedWorldRefiner, this.mainElement) | 84 this.closedWorldRefiner, this.mainElement) |
| 84 : this.types = new TypeSystem(closedWorld), | 85 : this.types = new TypeSystem(closedWorld), |
| 85 this.closedWorld = closedWorld; | 86 this.closedWorld = closedWorld; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 data.setMoveNextTypeMask(node, mask); | 218 data.setMoveNextTypeMask(node, mask); |
| 218 } | 219 } |
| 219 } | 220 } |
| 220 } | 221 } |
| 221 | 222 |
| 222 bool isNativeMember(Element element) { | 223 bool isNativeMember(Element element) { |
| 223 return element is MemberElement && | 224 return element is MemberElement && |
| 224 closedWorld.nativeData.isNativeMember(element); | 225 closedWorld.nativeData.isNativeMember(element); |
| 225 } | 226 } |
| 226 | 227 |
| 227 bool checkIfExposesThis(Element element) { | 228 bool checkIfExposesThis(ConstructorElement element) { |
| 228 element = element.implementation; | 229 element = element.implementation; |
| 229 return generativeConstructorsExposingThis.contains(element); | 230 return generativeConstructorsExposingThis.contains(element); |
| 230 } | 231 } |
| 231 | 232 |
| 232 void recordExposesThis(Element element, bool exposesThis) { | 233 void recordExposesThis(ConstructorElement element, bool exposesThis) { |
| 233 element = element.implementation; | 234 element = element.implementation; |
| 234 if (exposesThis) { | 235 if (exposesThis) { |
| 235 generativeConstructorsExposingThis.add(element); | 236 generativeConstructorsExposingThis.add(element); |
| 236 } | 237 } |
| 237 } | 238 } |
| 238 | 239 |
| 239 JavaScriptBackend get backend => compiler.backend; | 240 JavaScriptBackend get backend => compiler.backend; |
| 240 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; | 241 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; |
| 241 DiagnosticReporter get reporter => compiler.reporter; | 242 DiagnosticReporter get reporter => compiler.reporter; |
| 242 CommonMasks get commonMasks => closedWorld.commonMasks; | 243 CommonMasks get commonMasks => closedWorld.commonMasks; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 types.allocatedClosures.forEach((dynamic info) { | 353 types.allocatedClosures.forEach((dynamic info) { |
| 353 void trace( | 354 void trace( |
| 354 Iterable<FunctionElement> elements, ClosureTracerVisitor tracer) { | 355 Iterable<FunctionElement> elements, ClosureTracerVisitor tracer) { |
| 355 tracer.run(); | 356 tracer.run(); |
| 356 if (!tracer.continueAnalyzing) { | 357 if (!tracer.continueAnalyzing) { |
| 357 elements.forEach((FunctionElement e) { | 358 elements.forEach((FunctionElement e) { |
| 358 closedWorldRefiner.registerMightBePassedToApply(e); | 359 closedWorldRefiner.registerMightBePassedToApply(e); |
| 359 if (debug.VERBOSE) print("traced closure $e as ${true} (bail)"); | 360 if (debug.VERBOSE) print("traced closure $e as ${true} (bail)"); |
| 360 e.functionSignature.forEachParameter((parameter) { | 361 e.functionSignature.forEachParameter((parameter) { |
| 361 types | 362 types |
| 362 .getInferredTypeOf(parameter) | 363 .getInferredTypeOfParameter(parameter) |
| 363 .giveUp(this, clearAssignments: false); | 364 .giveUp(this, clearAssignments: false); |
| 364 }); | 365 }); |
| 365 }); | 366 }); |
| 366 bailedOutOn.addAll(elements); | 367 bailedOutOn.addAll(elements); |
| 367 return; | 368 return; |
| 368 } | 369 } |
| 369 elements | 370 elements |
| 370 .where((e) => !bailedOutOn.contains(e)) | 371 .where((e) => !bailedOutOn.contains(e)) |
| 371 .forEach((FunctionElement e) { | 372 .forEach((FunctionElement e) { |
| 372 e.functionSignature.forEachParameter((parameter) { | 373 e.functionSignature.forEachParameter((parameter) { |
| 373 var info = types.getInferredTypeOf(parameter); | 374 var info = types.getInferredTypeOfParameter(parameter); |
| 374 info.maybeResume(); | 375 info.maybeResume(); |
| 375 workQueue.add(info); | 376 workQueue.add(info); |
| 376 }); | 377 }); |
| 377 if (tracer.tracedType.mightBePassedToFunctionApply) { | 378 if (tracer.tracedType.mightBePassedToFunctionApply) { |
| 378 closedWorldRefiner.registerMightBePassedToApply(e); | 379 closedWorldRefiner.registerMightBePassedToApply(e); |
| 379 } | 380 } |
| 380 if (debug.VERBOSE) { | 381 if (debug.VERBOSE) { |
| 381 print("traced closure $e as " | 382 print("traced closure $e as " |
| 382 "${closedWorldRefiner | 383 "${closedWorldRefiner |
| 383 .getCurrentlyKnownMightBePassedToApply(e)}"); | 384 .getCurrentlyKnownMightBePassedToApply(e)}"); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 print('${types.getInferredSignatureOf(info.element)} for ' | 454 print('${types.getInferredSignatureOf(info.element)} for ' |
| 454 '${info.element}'); | 455 '${info.element}'); |
| 455 } else if (info is ClosureTypeInformation) { | 456 } else if (info is ClosureTypeInformation) { |
| 456 print('${types.getInferredSignatureOf(info.element)} for ' | 457 print('${types.getInferredSignatureOf(info.element)} for ' |
| 457 '${info.element}'); | 458 '${info.element}'); |
| 458 } else if (info is DynamicCallSiteTypeInformation) { | 459 } else if (info is DynamicCallSiteTypeInformation) { |
| 459 for (MemberElement target in info.targets) { | 460 for (MemberElement target in info.targets) { |
| 460 if (target is MethodElement) { | 461 if (target is MethodElement) { |
| 461 print('${types.getInferredSignatureOf(target)} for ${target}'); | 462 print('${types.getInferredSignatureOf(target)} for ${target}'); |
| 462 } else { | 463 } else { |
| 463 print('${types.getInferredTypeOf(target).type} for ${target}'); | 464 print( |
| 465 '${types.getInferredTypeOfMember(target).type} for ${target}')
; |
| 464 } | 466 } |
| 465 } | 467 } |
| 466 } else if (info is StaticCallSiteTypeInformation) { | 468 } else if (info is StaticCallSiteTypeInformation) { |
| 467 ClassElement cls = info.calledElement.enclosingClass; | 469 ClassElement cls = info.calledElement.enclosingClass; |
| 468 FunctionElement callMethod = cls.lookupMember(Identifiers.call); | 470 FunctionElement callMethod = cls.lookupMember(Identifiers.call); |
| 469 print('${types.getInferredSignatureOf(callMethod)} for ${cls}'); | 471 print('${types.getInferredSignatureOf(callMethod)} for ${cls}'); |
| 470 } else { | 472 } else { |
| 471 print('${info.type} for some unknown kind of closure'); | 473 print('${info.type} for some unknown kind of closure'); |
| 472 } | 474 } |
| 473 }); | 475 }); |
| 474 analyzedElements.forEach((Element elem) { | 476 analyzedElements.forEach((MemberElement elem) { |
| 475 TypeInformation type = types.getInferredTypeOf(elem); | 477 TypeInformation type = types.getInferredTypeOfMember(elem); |
| 476 print('${elem} :: ${type} from ${type.assignments} '); | 478 print('${elem} :: ${type} from ${type.assignments} '); |
| 477 }); | 479 }); |
| 478 } | 480 } |
| 479 dump?.afterAnalysis(); | 481 dump?.afterAnalysis(); |
| 480 | 482 |
| 481 reporter.log('Inferred $overallRefineCount types.'); | 483 reporter.log('Inferred $overallRefineCount types.'); |
| 482 | 484 |
| 483 processLoopInformation(); | 485 processLoopInformation(); |
| 484 } | 486 } |
| 485 | 487 |
| 486 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { | 488 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { |
| 487 AstElement element = resolvedAst.element.implementation; | 489 MemberElement element = resolvedAst.element.implementation; |
| 488 if (analyzedElements.contains(element)) return; | 490 if (analyzedElements.contains(element)) return; |
| 489 analyzedElements.add(element); | 491 analyzedElements.add(element); |
| 490 | 492 |
| 491 dynamic visitor = compiler.options.kernelGlobalInference | 493 dynamic visitor = compiler.options.kernelGlobalInference |
| 492 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) | 494 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) |
| 493 : new ElementGraphBuilder(element, resolvedAst, compiler, this); | 495 : new ElementGraphBuilder(element, resolvedAst, compiler, this); |
| 494 TypeInformation type; | 496 TypeInformation type; |
| 495 reporter.withCurrentElement(element, () { | 497 reporter.withCurrentElement(element, () { |
| 496 // ignore: UNDEFINED_METHOD | 498 // ignore: UNDEFINED_METHOD |
| 497 type = visitor.run(); | 499 type = visitor.run(); |
| 498 }); | 500 }); |
| 499 addedInGraph++; | 501 addedInGraph++; |
| 500 | 502 |
| 501 if (element.isField) { | 503 if (element.isField) { |
| 502 VariableElement fieldElement = element; | 504 FieldElement fieldElement = element; |
| 503 ast.Node node = resolvedAst.node; | 505 ast.Node node = resolvedAst.node; |
| 504 ast.Node initializer = resolvedAst.body; | 506 ast.Node initializer = resolvedAst.body; |
| 505 if (element.isFinal || element.isConst) { | 507 if (element.isFinal || element.isConst) { |
| 506 // If [element] is final and has an initializer, we record | 508 // If [element] is final and has an initializer, we record |
| 507 // the inferred type. | 509 // the inferred type. |
| 508 if (resolvedAst.body != null) { | 510 if (resolvedAst.body != null) { |
| 509 if (type is! ListTypeInformation && type is! MapTypeInformation) { | 511 if (type is! ListTypeInformation && type is! MapTypeInformation) { |
| 510 // For non-container types, the constant handler does | 512 // For non-container types, the constant handler does |
| 511 // constant folding that could give more precise results. | 513 // constant folding that could give more precise results. |
| 512 ConstantExpression constant = fieldElement.constant; | 514 ConstantExpression constant = fieldElement.constant; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 532 fieldElement.isInstanceMember || | 534 fieldElement.isInstanceMember || |
| 533 constant.isImplicit || | 535 constant.isImplicit || |
| 534 constant.isPotential, | 536 constant.isPotential, |
| 535 failedAt( | 537 failedAt( |
| 536 fieldElement, | 538 fieldElement, |
| 537 "Constant expression without value: " | 539 "Constant expression without value: " |
| 538 "${constant.toStructuredText()}.")); | 540 "${constant.toStructuredText()}.")); |
| 539 } | 541 } |
| 540 } | 542 } |
| 541 } | 543 } |
| 542 recordType(element, type); | 544 recordTypeOfField(element, type); |
| 543 } else if (!element.isInstanceMember) { | 545 } else if (!element.isInstanceMember) { |
| 544 recordType(element, types.nullType); | 546 recordTypeOfField(element, types.nullType); |
| 545 } | 547 } |
| 546 } else if (initializer == null) { | 548 } else if (initializer == null) { |
| 547 // Only update types of static fields if there is no | 549 // Only update types of static fields if there is no |
| 548 // assignment. Instance fields are dealt with in the constructor. | 550 // assignment. Instance fields are dealt with in the constructor. |
| 549 if (Elements.isStaticOrTopLevelField(element)) { | 551 if (Elements.isStaticOrTopLevelField(element)) { |
| 550 recordTypeOfNonFinalField(node, element, type); | 552 recordTypeOfNonFinalField(element, type); |
| 551 } | 553 } |
| 552 } else { | 554 } else { |
| 553 recordTypeOfNonFinalField(node, element, type); | 555 recordTypeOfNonFinalField(element, type); |
| 554 } | 556 } |
| 555 if (Elements.isStaticOrTopLevelField(element) && | 557 if (Elements.isStaticOrTopLevelField(element) && |
| 556 resolvedAst.body != null && | 558 resolvedAst.body != null && |
| 557 !element.isConst) { | 559 !element.isConst) { |
| 558 dynamic argument = resolvedAst.body; | 560 dynamic argument = resolvedAst.body; |
| 559 // TODO(13429): We could do better here by using the | 561 // TODO(13429): We could do better here by using the |
| 560 // constant handler to figure out if it's a lazy field or not. | 562 // constant handler to figure out if it's a lazy field or not. |
| 561 if (argument.asSend() != null || | 563 if (argument.asSend() != null || |
| 562 (argument.asNewExpression() != null && !argument.isConst)) { | 564 (argument.asNewExpression() != null && !argument.isConst)) { |
| 563 recordType(element, types.nullType); | 565 recordTypeOfField(element, types.nullType); |
| 564 } | 566 } |
| 565 } | 567 } |
| 566 } else { | 568 } else { |
| 567 recordReturnType(element, type); | 569 recordReturnType(element, type); |
| 568 } | 570 } |
| 569 } | 571 } |
| 570 | 572 |
| 571 void processLoopInformation() { | 573 void processLoopInformation() { |
| 572 types.allocatedCalls.forEach((dynamic info) { | 574 types.allocatedCalls.forEach((dynamic info) { |
| 573 if (!info.inLoop) return; | 575 if (!info.inLoop) return; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 * Update the assignments to parameters in the graph. [remove] tells | 630 * Update the assignments to parameters in the graph. [remove] tells |
| 629 * wheter assignments must be added or removed. If [init] is false, | 631 * wheter assignments must be added or removed. If [init] is false, |
| 630 * parameters are added to the work queue. | 632 * parameters are added to the work queue. |
| 631 */ | 633 */ |
| 632 void updateParameterAssignments(TypeInformation caller, Element callee, | 634 void updateParameterAssignments(TypeInformation caller, Element callee, |
| 633 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 635 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 634 {bool remove, bool addToQueue: true}) { | 636 {bool remove, bool addToQueue: true}) { |
| 635 if (callee.name == Identifiers.noSuchMethod_) return; | 637 if (callee.name == Identifiers.noSuchMethod_) return; |
| 636 if (callee.isField) { | 638 if (callee.isField) { |
| 637 if (selector.isSetter) { | 639 if (selector.isSetter) { |
| 638 ElementTypeInformation info = types.getInferredTypeOf(callee); | 640 ElementTypeInformation info = types.getInferredTypeOfMember(callee); |
| 639 if (remove) { | 641 if (remove) { |
| 640 info.removeAssignment(arguments.positional[0]); | 642 info.removeAssignment(arguments.positional[0]); |
| 641 } else { | 643 } else { |
| 642 info.addAssignment(arguments.positional[0]); | 644 info.addAssignment(arguments.positional[0]); |
| 643 } | 645 } |
| 644 if (addToQueue) workQueue.add(info); | 646 if (addToQueue) workQueue.add(info); |
| 645 } | 647 } |
| 646 } else if (callee.isGetter) { | 648 } else if (callee.isGetter) { |
| 647 return; | 649 return; |
| 648 } else if (selector != null && selector.isGetter) { | 650 } else if (selector != null && selector.isGetter) { |
| 649 // We are tearing a function off and thus create a closure. | 651 // We are tearing a function off and thus create a closure. |
| 650 assert(callee.isFunction); | 652 assert(callee.isFunction); |
| 651 MemberTypeInformation info = types.getInferredTypeOf(callee); | 653 MemberTypeInformation info = types.getInferredTypeOfMember(callee); |
| 652 if (remove) { | 654 if (remove) { |
| 653 info.closurizedCount--; | 655 info.closurizedCount--; |
| 654 } else { | 656 } else { |
| 655 info.closurizedCount++; | 657 info.closurizedCount++; |
| 656 if (Elements.isStaticOrTopLevel(callee)) { | 658 if (Elements.isStaticOrTopLevel(callee)) { |
| 657 types.allocatedClosures.add(info); | 659 types.allocatedClosures.add(info); |
| 658 } else { | 660 } else { |
| 659 // We add the call-site type information here so that we | 661 // We add the call-site type information here so that we |
| 660 // can benefit from further refinement of the selector. | 662 // can benefit from further refinement of the selector. |
| 661 types.allocatedClosures.add(caller); | 663 types.allocatedClosures.add(caller); |
| 662 } | 664 } |
| 663 FunctionElement function = callee.implementation; | 665 FunctionElement function = callee.implementation; |
| 664 FunctionSignature signature = function.functionSignature; | 666 FunctionSignature signature = function.functionSignature; |
| 665 signature.forEachParameter((Element parameter) { | 667 signature.forEachParameter((Element parameter) { |
| 666 ParameterTypeInformation info = types.getInferredTypeOf(parameter); | 668 ParameterTypeInformation info = |
| 669 types.getInferredTypeOfParameter(parameter); |
| 667 info.tagAsTearOffClosureParameter(this); | 670 info.tagAsTearOffClosureParameter(this); |
| 668 if (addToQueue) workQueue.add(info); | 671 if (addToQueue) workQueue.add(info); |
| 669 }); | 672 }); |
| 670 } | 673 } |
| 671 } else { | 674 } else { |
| 672 FunctionElement function = callee.implementation; | 675 FunctionElement function = callee.implementation; |
| 673 FunctionSignature signature = function.functionSignature; | 676 FunctionSignature signature = function.functionSignature; |
| 674 int parameterIndex = 0; | 677 int parameterIndex = 0; |
| 675 bool visitingRequiredParameter = true; | 678 bool visitingRequiredParameter = true; |
| 676 signature.forEachParameter((Element parameter) { | 679 signature.forEachParameter((Element parameter) { |
| 677 if (signature.hasOptionalParameters && | 680 if (signature.hasOptionalParameters && |
| 678 parameter == signature.optionalParameters.first) { | 681 parameter == signature.optionalParameters.first) { |
| 679 visitingRequiredParameter = false; | 682 visitingRequiredParameter = false; |
| 680 } | 683 } |
| 681 TypeInformation type = visitingRequiredParameter | 684 TypeInformation type = visitingRequiredParameter |
| 682 ? arguments.positional[parameterIndex] | 685 ? arguments.positional[parameterIndex] |
| 683 : signature.optionalParametersAreNamed | 686 : signature.optionalParametersAreNamed |
| 684 ? arguments.named[parameter.name] | 687 ? arguments.named[parameter.name] |
| 685 : parameterIndex < arguments.positional.length | 688 : parameterIndex < arguments.positional.length |
| 686 ? arguments.positional[parameterIndex] | 689 ? arguments.positional[parameterIndex] |
| 687 : null; | 690 : null; |
| 688 if (type == null) type = getDefaultTypeOfParameter(parameter); | 691 if (type == null) type = getDefaultTypeOfParameter(parameter); |
| 689 TypeInformation info = types.getInferredTypeOf(parameter); | 692 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
| 690 if (remove) { | 693 if (remove) { |
| 691 info.removeAssignment(type); | 694 info.removeAssignment(type); |
| 692 } else { | 695 } else { |
| 693 info.addAssignment(type); | 696 info.addAssignment(type); |
| 694 } | 697 } |
| 695 parameterIndex++; | 698 parameterIndex++; |
| 696 if (addToQueue) workQueue.add(info); | 699 if (addToQueue) workQueue.add(info); |
| 697 }); | 700 }); |
| 698 } | 701 } |
| 699 } | 702 } |
| 700 | 703 |
| 701 /** | 704 /** |
| 702 * Sets the type of a parameter's default value to [type]. If the global | 705 * Sets the type of a parameter's default value to [type]. If the global |
| 703 * mapping in [defaultTypeOfParameter] already contains a type, it must be | 706 * mapping in [defaultTypeOfParameter] already contains a type, it must be |
| 704 * a [PlaceholderTypeInformation], which will be replaced. All its uses are | 707 * a [PlaceholderTypeInformation], which will be replaced. All its uses are |
| 705 * updated. | 708 * updated. |
| 706 */ | 709 */ |
| 707 void setDefaultTypeOfParameter( | 710 void setDefaultTypeOfParameter( |
| 708 ParameterElement parameter, TypeInformation type) { | 711 ParameterElement parameter, TypeInformation type) { |
| 709 assert(parameter.functionDeclaration.isImplementation); | 712 assert(parameter.functionDeclaration.isImplementation); |
| 710 TypeInformation existing = defaultTypeOfParameter[parameter]; | 713 TypeInformation existing = defaultTypeOfParameter[parameter]; |
| 711 defaultTypeOfParameter[parameter] = type; | 714 defaultTypeOfParameter[parameter] = type; |
| 712 TypeInformation info = types.getInferredTypeOf(parameter); | 715 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
| 713 if (existing != null && existing is PlaceholderTypeInformation) { | 716 if (existing != null && existing is PlaceholderTypeInformation) { |
| 714 // Replace references to [existing] to use [type] instead. | 717 // Replace references to [existing] to use [type] instead. |
| 715 if (parameter.functionDeclaration.isInstanceMember) { | 718 if (parameter.functionDeclaration.isInstanceMember) { |
| 716 ParameterAssignments assignments = info.assignments; | 719 ParameterAssignments assignments = info.assignments; |
| 717 assignments.replace(existing, type); | 720 assignments.replace(existing, type); |
| 718 } else { | 721 } else { |
| 719 List<TypeInformation> assignments = info.assignments; | 722 List<TypeInformation> assignments = info.assignments; |
| 720 for (int i = 0; i < assignments.length; i++) { | 723 for (int i = 0; i < assignments.length; i++) { |
| 721 if (assignments[i] == existing) { | 724 if (assignments[i] == existing) { |
| 722 assignments[i] = type; | 725 assignments[i] = type; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 733 /** | 736 /** |
| 734 * Returns the [TypeInformation] node for the default value of a parameter. | 737 * Returns the [TypeInformation] node for the default value of a parameter. |
| 735 * If this is queried before it is set by [setDefaultTypeOfParameter], a | 738 * If this is queried before it is set by [setDefaultTypeOfParameter], a |
| 736 * [PlaceholderTypeInformation] is returned, which will later be replaced | 739 * [PlaceholderTypeInformation] is returned, which will later be replaced |
| 737 * by the actual node when [setDefaultTypeOfParameter] is called. | 740 * by the actual node when [setDefaultTypeOfParameter] is called. |
| 738 * | 741 * |
| 739 * Invariant: After graph construction, no [PlaceholderTypeInformation] nodes | 742 * Invariant: After graph construction, no [PlaceholderTypeInformation] nodes |
| 740 * should be present and a default type for each parameter should | 743 * should be present and a default type for each parameter should |
| 741 * exist. | 744 * exist. |
| 742 */ | 745 */ |
| 743 TypeInformation getDefaultTypeOfParameter(Element parameter) { | 746 TypeInformation getDefaultTypeOfParameter(ParameterElement parameter) { |
| 744 return defaultTypeOfParameter.putIfAbsent(parameter, () { | 747 return defaultTypeOfParameter.putIfAbsent(parameter, () { |
| 745 return new PlaceholderTypeInformation(types.currentMember); | 748 return new PlaceholderTypeInformation(types.currentMember); |
| 746 }); | 749 }); |
| 747 } | 750 } |
| 748 | 751 |
| 749 /** | 752 /** |
| 750 * This helper breaks abstractions but is currently required to work around | 753 * This helper breaks abstractions but is currently required to work around |
| 751 * the wrong modeling of default values of optional parameters of | 754 * the wrong modeling of default values of optional parameters of |
| 752 * synthetic constructors. | 755 * synthetic constructors. |
| 753 * | 756 * |
| 754 * TODO(johnniwinther): Remove once default values of synthetic parameters | 757 * TODO(johnniwinther): Remove once default values of synthetic parameters |
| 755 * are fixed. | 758 * are fixed. |
| 756 */ | 759 */ |
| 757 bool hasAlreadyComputedTypeOfParameterDefault(Element parameter) { | 760 bool hasAlreadyComputedTypeOfParameterDefault(ParameterElement parameter) { |
| 758 TypeInformation seen = defaultTypeOfParameter[parameter]; | 761 TypeInformation seen = defaultTypeOfParameter[parameter]; |
| 759 return (seen != null && seen is! PlaceholderTypeInformation); | 762 return (seen != null && seen is! PlaceholderTypeInformation); |
| 760 } | 763 } |
| 761 | 764 |
| 762 /** | 765 /** |
| 763 * Returns the type of [element]. | 766 * Returns the type of [element]. |
| 764 */ | 767 */ |
| 765 TypeInformation typeOfElement(Entity element) { | 768 TypeInformation typeOfParameter(ParameterElement element) { |
| 766 if (element is FunctionElement) return types.functionType; | 769 return types.getInferredTypeOfParameter(element); |
| 767 return types.getInferredTypeOf(element); | 770 } |
| 771 |
| 772 /** |
| 773 * Returns the type of [element]. |
| 774 */ |
| 775 TypeInformation typeOfMember(MemberElement element) { |
| 776 if (element is MethodElement) return types.functionType; |
| 777 return types.getInferredTypeOfMember(element); |
| 768 } | 778 } |
| 769 | 779 |
| 770 /** | 780 /** |
| 771 * Returns the return type of [element]. | 781 * Returns the return type of [element]. |
| 772 */ | 782 */ |
| 773 TypeInformation returnTypeOfElement(Entity element) { | 783 @deprecated |
| 774 if (element is! FunctionElement) return types.dynamicType; | 784 TypeInformation returnTypeOfLocalFunction(LocalFunctionElement element) { |
| 775 return types.getInferredTypeOf(element); | 785 return types.getInferredTypeOfLocalFunction(element); |
| 776 } | 786 } |
| 777 | 787 |
| 778 /** | 788 /** |
| 789 * Returns the return type of [element]. |
| 790 */ |
| 791 TypeInformation returnTypeOfMember(MemberElement element) { |
| 792 if (element is! MethodElement) return types.dynamicType; |
| 793 return types.getInferredTypeOfMember(element); |
| 794 } |
| 795 |
| 796 /** |
| 779 * Records that [node] sets final field [element] to be of type [type]. | 797 * Records that [node] sets final field [element] to be of type [type]. |
| 780 * | 798 * |
| 781 * [nodeHolder] is the element holder of [node]. | 799 * [nodeHolder] is the element holder of [node]. |
| 782 */ | 800 */ |
| 783 void recordTypeOfFinalField( | 801 void recordTypeOfFinalField(FieldElement element, TypeInformation type) { |
| 784 Spannable node, Entity analyzed, Entity element, TypeInformation type) { | 802 types.getInferredTypeOfMember(element).addAssignment(type); |
| 785 types.getInferredTypeOf(element).addAssignment(type); | |
| 786 } | 803 } |
| 787 | 804 |
| 788 /** | 805 /** |
| 789 * Records that [node] sets non-final field [element] to be of type | 806 * Records that [node] sets non-final field [element] to be of type |
| 790 * [type]. | 807 * [type]. |
| 791 */ | 808 */ |
| 792 void recordTypeOfNonFinalField( | 809 void recordTypeOfNonFinalField(FieldElement element, TypeInformation type) { |
| 793 Spannable node, Entity element, TypeInformation type) { | 810 types.getInferredTypeOfMember(element).addAssignment(type); |
| 794 types.getInferredTypeOf(element).addAssignment(type); | |
| 795 } | 811 } |
| 796 | 812 |
| 797 /** | 813 /** |
| 798 * Records that [element] is of type [type]. | 814 * Records that [element] is of type [type]. |
| 799 */ | 815 */ |
| 800 void recordType(Entity element, TypeInformation type) { | 816 // TODO(johnniwinther): Merge [recordTypeOfFinalField] and |
| 801 types.getInferredTypeOf(element).addAssignment(type); | 817 // [recordTypeOfNonFinalField] with this? |
| 818 void recordTypeOfField(FieldElement element, TypeInformation type) { |
| 819 types.getInferredTypeOfMember(element).addAssignment(type); |
| 802 } | 820 } |
| 803 | 821 |
| 804 /** | 822 /** |
| 805 * Records that the return type [element] is of type [type]. | 823 * Records that the return type [element] is of type [type]. |
| 806 */ | 824 */ |
| 807 void recordReturnType(Element element, TypeInformation type) { | 825 @deprecated |
| 808 TypeInformation info = types.getInferredTypeOf(element); | 826 void recordReturnTypeOfLocalFunction( |
| 827 LocalFunctionElement element, TypeInformation type) { |
| 828 TypeInformation info = types.getInferredTypeOfLocalFunction(element); |
| 809 if (element.name == '==') { | 829 if (element.name == '==') { |
| 810 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. | 830 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
| 811 info.addAssignment(types.boolType); | 831 info.addAssignment(types.boolType); |
| 832 } |
| 833 // TODO(ngeoffray): Clean up. We do these checks because |
| 834 // [SimpleTypesInferrer] deals with two different inferrers. |
| 835 if (type == null) return; |
| 836 if (info.assignments.isEmpty) info.addAssignment(type); |
| 837 } |
| 838 |
| 839 /** |
| 840 * Records that the return type [element] is of type [type]. |
| 841 */ |
| 842 void recordReturnType(MethodElement element, TypeInformation type) { |
| 843 TypeInformation info = types.getInferredTypeOfMember(element); |
| 844 if (element.name == '==') { |
| 845 // Even if x.== doesn't return a bool, 'x == null' evaluates to 'false'. |
| 846 info.addAssignment(types.boolType); |
| 812 } | 847 } |
| 813 // TODO(ngeoffray): Clean up. We do these checks because | 848 // TODO(ngeoffray): Clean up. We do these checks because |
| 814 // [SimpleTypesInferrer] deals with two different inferrers. | 849 // [SimpleTypesInferrer] deals with two different inferrers. |
| 815 if (type == null) return; | 850 if (type == null) return; |
| 816 if (info.assignments.isEmpty) info.addAssignment(type); | 851 if (info.assignments.isEmpty) info.addAssignment(type); |
| 817 } | 852 } |
| 818 | 853 |
| 819 /** | 854 /** |
| 820 * Notifies to the inferrer that [analyzedElement] can have return | 855 * Notifies to the inferrer that [analyzedElement] can have return |
| 821 * type [newType]. [currentType] is the type the [ElementGraphBuilder] | 856 * type [newType]. [currentType] is the type the [ElementGraphBuilder] |
| 822 * currently found. | 857 * currently found. |
| 823 * | 858 * |
| 824 * Returns the new type for [analyzedElement]. | 859 * Returns the new type for [analyzedElement]. |
| 825 */ | 860 */ |
| 826 TypeInformation addReturnTypeFor( | 861 @deprecated |
| 827 Element element, TypeInformation unused, TypeInformation newType) { | 862 TypeInformation addReturnTypeForLocalFunction(LocalFunctionElement element, |
| 828 TypeInformation type = types.getInferredTypeOf(element); | 863 TypeInformation unused, TypeInformation newType) { |
| 864 TypeInformation type = types.getInferredTypeOfLocalFunction(element); |
| 829 // TODO(ngeoffray): Clean up. We do this check because | 865 // TODO(ngeoffray): Clean up. We do this check because |
| 830 // [SimpleTypesInferrer] deals with two different inferrers. | 866 // [SimpleTypesInferrer] deals with two different inferrers. |
| 831 if (element.isGenerativeConstructor) return type; | 867 if (element.isGenerativeConstructor) return type; |
| 868 type.addAssignment(newType); |
| 869 return type; |
| 870 } |
| 871 |
| 872 /** |
| 873 * Notifies to the inferrer that [analyzedElement] can have return |
| 874 * type [newType]. [currentType] is the type the [ElementGraphBuilder] |
| 875 * currently found. |
| 876 * |
| 877 * Returns the new type for [analyzedElement]. |
| 878 */ |
| 879 TypeInformation addReturnTypeForMethod( |
| 880 MethodElement element, TypeInformation unused, TypeInformation newType) { |
| 881 TypeInformation type = types.getInferredTypeOfMember(element); |
| 882 // TODO(ngeoffray): Clean up. We do this check because |
| 883 // [SimpleTypesInferrer] deals with two different inferrers. |
| 884 if (element.isGenerativeConstructor) return type; |
| 832 type.addAssignment(newType); | 885 type.addAssignment(newType); |
| 833 return type; | 886 return type; |
| 834 } | 887 } |
| 835 | 888 |
| 836 /** | 889 /** |
| 837 * Registers that [caller] calls [callee] at location [node], with | 890 * Registers that [caller] calls [callee] at location [node], with |
| 838 * [selector], and [arguments]. Note that [selector] is null for | 891 * [selector], and [arguments]. Note that [selector] is null for |
| 839 * forwarding constructors. | 892 * forwarding constructors. |
| 840 * | 893 * |
| 841 * [sideEffects] will be updated to incorporate [callee]'s side | 894 * [sideEffects] will be updated to incorporate [callee]'s side |
| 842 * effects. | 895 * effects. |
| 843 * | 896 * |
| 844 * [inLoop] tells whether the call happens in a loop. | 897 * [inLoop] tells whether the call happens in a loop. |
| 845 */ | 898 */ |
| 846 TypeInformation registerCalledElement( | 899 @deprecated |
| 900 TypeInformation registerCalledLocalFunction( |
| 847 Spannable node, | 901 Spannable node, |
| 848 Selector selector, | 902 Selector selector, |
| 849 TypeMask mask, | 903 TypeMask mask, |
| 904 Element caller, |
| 905 LocalFunctionElement callee, |
| 906 ArgumentsTypes arguments, |
| 907 SideEffects sideEffects, |
| 908 bool inLoop) { |
| 909 return _registerCalledElement( |
| 910 node, selector, mask, caller, callee, arguments, sideEffects, inLoop); |
| 911 } |
| 912 |
| 913 /** |
| 914 * Registers that [caller] calls [callee] at location [node], with |
| 915 * [selector], and [arguments]. Note that [selector] is null for |
| 916 * forwarding constructors. |
| 917 * |
| 918 * [sideEffects] will be updated to incorporate [callee]'s side |
| 919 * effects. |
| 920 * |
| 921 * [inLoop] tells whether the call happens in a loop. |
| 922 */ |
| 923 TypeInformation registerCalledMember( |
| 924 Spannable node, |
| 925 Selector selector, |
| 926 TypeMask mask, |
| 927 Element caller, |
| 928 MemberElement callee, |
| 929 ArgumentsTypes arguments, |
| 930 SideEffects sideEffects, |
| 931 bool inLoop) { |
| 932 return _registerCalledElement( |
| 933 node, selector, mask, caller, callee, arguments, sideEffects, inLoop); |
| 934 } |
| 935 |
| 936 /** |
| 937 * Registers that [caller] calls [callee] at location [node], with |
| 938 * [selector], and [arguments]. Note that [selector] is null for |
| 939 * forwarding constructors. |
| 940 * |
| 941 * [sideEffects] will be updated to incorporate [callee]'s side |
| 942 * effects. |
| 943 * |
| 944 * [inLoop] tells whether the call happens in a loop. |
| 945 */ |
| 946 TypeInformation _registerCalledElement( |
| 947 Spannable node, |
| 948 Selector selector, |
| 949 TypeMask mask, |
| 850 Element caller, | 950 Element caller, |
| 851 Element callee, | 951 Element callee, |
| 852 ArgumentsTypes arguments, | 952 ArgumentsTypes arguments, |
| 853 SideEffects sideEffects, | 953 SideEffects sideEffects, |
| 854 bool inLoop) { | 954 bool inLoop) { |
| 855 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( | 955 CallSiteTypeInformation info = new StaticCallSiteTypeInformation( |
| 856 types.currentMember, | 956 types.currentMember, |
| 857 node, | 957 node, |
| 858 caller, | 958 caller, |
| 859 callee, | 959 callee, |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1036 types.allocatedClosures.forEach(cleanup); | 1136 types.allocatedClosures.forEach(cleanup); |
| 1037 types.allocatedClosures.clear(); | 1137 types.allocatedClosures.clear(); |
| 1038 | 1138 |
| 1039 analyzedElements.clear(); | 1139 analyzedElements.clear(); |
| 1040 generativeConstructorsExposingThis.clear(); | 1140 generativeConstructorsExposingThis.clear(); |
| 1041 | 1141 |
| 1042 types.allocatedMaps.values.forEach(cleanup); | 1142 types.allocatedMaps.values.forEach(cleanup); |
| 1043 types.allocatedLists.values.forEach(cleanup); | 1143 types.allocatedLists.values.forEach(cleanup); |
| 1044 } | 1144 } |
| 1045 | 1145 |
| 1046 Iterable<Element> getCallersOf(Element element) { | 1146 Iterable<Element> getCallersOf(MemberElement element) { |
| 1047 if (compiler.disableTypeInference) { | 1147 if (compiler.disableTypeInference) { |
| 1048 throw new UnsupportedError( | 1148 throw new UnsupportedError( |
| 1049 "Cannot query the type inferrer when type inference is disabled."); | 1149 "Cannot query the type inferrer when type inference is disabled."); |
| 1050 } | 1150 } |
| 1051 MemberTypeInformation info = types.getInferredTypeOf(element); | 1151 MemberTypeInformation info = types.getInferredTypeOfMember(element); |
| 1052 return info.callers; | 1152 return info.callers; |
| 1053 } | 1153 } |
| 1054 | 1154 |
| 1055 /** | 1155 /** |
| 1056 * Returns the type of [element] when being called with [selector]. | 1156 * Returns the type of [element] when being called with [selector]. |
| 1057 */ | 1157 */ |
| 1058 TypeInformation typeOfElementWithSelector( | 1158 TypeInformation typeOfLocalFunctionWithSelector( |
| 1159 LocalFunctionElement element, Selector selector) { |
| 1160 return _typeOfElementWithSelector(element, selector); |
| 1161 } |
| 1162 |
| 1163 /** |
| 1164 * Returns the type of [element] when being called with [selector]. |
| 1165 */ |
| 1166 TypeInformation typeOfMemberWithSelector( |
| 1167 MemberElement element, Selector selector) { |
| 1168 return _typeOfElementWithSelector(element, selector); |
| 1169 } |
| 1170 |
| 1171 /** |
| 1172 * Returns the type of [element] when being called with [selector]. |
| 1173 */ |
| 1174 TypeInformation _typeOfElementWithSelector( |
| 1059 Element element, Selector selector) { | 1175 Element element, Selector selector) { |
| 1060 if (element.name == Identifiers.noSuchMethod_ && | 1176 if (element.name == Identifiers.noSuchMethod_ && |
| 1061 selector.name != element.name) { | 1177 selector.name != element.name) { |
| 1062 // An invocation can resolve to a [noSuchMethod], in which case | 1178 // An invocation can resolve to a [noSuchMethod], in which case |
| 1063 // we get the return type of [noSuchMethod]. | 1179 // we get the return type of [noSuchMethod]. |
| 1064 return returnTypeOfElement(element); | 1180 if (element.isLocal) { |
| 1181 return returnTypeOfLocalFunction(element); |
| 1182 } else { |
| 1183 return returnTypeOfMember(element); |
| 1184 } |
| 1065 } else if (selector.isGetter) { | 1185 } else if (selector.isGetter) { |
| 1066 if (element.isFunction) { | 1186 if (element.isFunction) { |
| 1067 // [functionType] is null if the inferrer did not run. | 1187 // [functionType] is null if the inferrer did not run. |
| 1068 return types.functionType == null | 1188 return types.functionType == null |
| 1069 ? types.dynamicType | 1189 ? types.dynamicType |
| 1070 : types.functionType; | 1190 : types.functionType; |
| 1071 } else if (element.isField) { | 1191 } else if (element.isField) { |
| 1072 return typeOfElement(element); | 1192 return typeOfMember(element); |
| 1073 } else if (Elements.isUnresolved(element)) { | 1193 } else if (Elements.isUnresolved(element)) { |
| 1074 return types.dynamicType; | 1194 return types.dynamicType; |
| 1075 } else { | 1195 } else { |
| 1076 assert(element.isGetter); | 1196 assert(element.isGetter); |
| 1077 return returnTypeOfElement(element); | 1197 if (element.isLocal) { |
| 1198 return returnTypeOfLocalFunction(element); |
| 1199 } else { |
| 1200 return returnTypeOfMember(element); |
| 1201 } |
| 1078 } | 1202 } |
| 1079 } else if (element.isGetter || element.isField) { | 1203 } else if (element.isGetter || element.isField) { |
| 1080 assert(selector.isCall || selector.isSetter); | 1204 assert(selector.isCall || selector.isSetter); |
| 1081 return types.dynamicType; | 1205 return types.dynamicType; |
| 1082 } else { | 1206 } else { |
| 1083 return returnTypeOfElement(element); | 1207 if (element.isLocal) { |
| 1208 return returnTypeOfLocalFunction(element); |
| 1209 } else { |
| 1210 return returnTypeOfMember(element); |
| 1211 } |
| 1084 } | 1212 } |
| 1085 } | 1213 } |
| 1086 | 1214 |
| 1087 /** | 1215 /** |
| 1088 * Records that the captured variable [local] is read. | 1216 * Records that the captured variable [local] is read. |
| 1089 */ | 1217 */ |
| 1090 void recordCapturedLocalRead(Local local) {} | 1218 void recordCapturedLocalRead(Local local) {} |
| 1091 | 1219 |
| 1092 /** | 1220 /** |
| 1093 * Records that the variable [local] is being updated. | 1221 * Records that the variable [local] is being updated. |
| 1094 */ | 1222 */ |
| 1095 void recordLocalUpdate(Local local, TypeInformation type) {} | 1223 void recordLocalUpdate(Local local, TypeInformation type) {} |
| 1096 } | 1224 } |
| OLD | NEW |