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 |