OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library compiler.src.inferrer.type_graph_nodes; | 5 library compiler.src.inferrer.type_graph_nodes; |
6 | 6 |
7 import 'dart:collection' show IterableBase; | 7 import 'dart:collection' show IterableBase; |
8 | 8 |
9 import '../common.dart'; | 9 import '../common.dart'; |
10 import '../common/names.dart' show Identifiers; | 10 import '../common/names.dart' show Identifiers; |
11 import '../compiler.dart' show Compiler; | 11 import '../compiler.dart' show Compiler; |
12 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
13 import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node; | 13 import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node; |
14 import '../dart_types.dart' show | 14 import '../dart_types.dart' |
15 DartType, | 15 show DartType, FunctionType, InterfaceType, TypeKind; |
16 FunctionType, | |
17 InterfaceType, | |
18 TypeKind; | |
19 import '../elements/elements.dart'; | 16 import '../elements/elements.dart'; |
20 import '../native/native.dart' as native; | 17 import '../native/native.dart' as native; |
21 import '../tree/tree.dart' as ast show | 18 import '../tree/tree.dart' as ast |
22 DartString, | 19 show DartString, Node, LiteralBool, Send, SendSet, TryStatement; |
23 Node, | 20 import '../types/types.dart' |
24 LiteralBool, | 21 show |
25 Send, | 22 ContainerTypeMask, |
26 SendSet, | 23 DictionaryTypeMask, |
27 TryStatement; | 24 MapTypeMask, |
28 import '../types/types.dart' show | 25 TypeMask, |
29 ContainerTypeMask, | 26 ValueTypeMask; |
30 DictionaryTypeMask, | |
31 MapTypeMask, | |
32 TypeMask, | |
33 ValueTypeMask; | |
34 import '../universe/selector.dart' show Selector; | 27 import '../universe/selector.dart' show Selector; |
35 import '../util/util.dart' show ImmutableEmptySet, Setlet; | 28 import '../util/util.dart' show ImmutableEmptySet, Setlet; |
36 import '../world.dart' show ClassWorld; | 29 import '../world.dart' show ClassWorld; |
37 | 30 |
38 import 'inferrer_visitor.dart' show ArgumentsTypes; | 31 import 'inferrer_visitor.dart' show ArgumentsTypes; |
39 import 'type_graph_inferrer.dart' show | 32 import 'type_graph_inferrer.dart' |
40 TypeGraphInferrerEngine, | 33 show TypeGraphInferrerEngine, TypeInformationSystem; |
41 TypeInformationSystem; | |
42 import 'debug.dart' as debug; | 34 import 'debug.dart' as debug; |
43 | 35 |
44 /** | 36 /** |
45 * Common class for all nodes in the graph. The current nodes are: | 37 * Common class for all nodes in the graph. The current nodes are: |
46 * | 38 * |
47 * - Concrete types | 39 * - Concrete types |
48 * - Elements | 40 * - Elements |
49 * - Call sites | 41 * - Call sites |
50 * - Narrowing instructions | 42 * - Narrowing instructions |
51 * - Phi instructions | 43 * - Phi instructions |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 /// Whether this [TypeInformation] has a stable [type] that will not | 90 /// Whether this [TypeInformation] has a stable [type] that will not |
99 /// change. | 91 /// change. |
100 bool isStable = false; | 92 bool isStable = false; |
101 | 93 |
102 // TypeInformations are unique. | 94 // TypeInformations are unique. |
103 static int staticHashCode = 0; | 95 static int staticHashCode = 0; |
104 final int hashCode = staticHashCode++; | 96 final int hashCode = staticHashCode++; |
105 | 97 |
106 bool get isConcrete => false; | 98 bool get isConcrete => false; |
107 | 99 |
108 TypeInformation(this.context) : _assignments = <TypeInformation>[], | 100 TypeInformation(this.context) |
109 users = new Setlet<TypeInformation>(); | 101 : _assignments = <TypeInformation>[], |
| 102 users = new Setlet<TypeInformation>(); |
110 | 103 |
111 TypeInformation.noAssignments(this.context) | 104 TypeInformation.noAssignments(this.context) |
112 : _assignments = const <TypeInformation>[], | 105 : _assignments = const <TypeInformation>[], |
113 users = new Setlet<TypeInformation>(); | 106 users = new Setlet<TypeInformation>(); |
114 | 107 |
115 TypeInformation.untracked() | 108 TypeInformation.untracked() |
116 : _assignments = const <TypeInformation>[], | 109 : _assignments = const <TypeInformation>[], |
117 users = const ImmutableEmptySet(), | 110 users = const ImmutableEmptySet(), |
118 context = null; | 111 context = null; |
119 | 112 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 /// the information. | 206 /// the information. |
214 Element get owner => (context != null) ? context.element : null; | 207 Element get owner => (context != null) ? context.element : null; |
215 | 208 |
216 /// Returns whether the type cannot change after it has been | 209 /// Returns whether the type cannot change after it has been |
217 /// inferred. | 210 /// inferred. |
218 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 211 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
219 return !mightResume && assignments.every((e) => e.isStable); | 212 return !mightResume && assignments.every((e) => e.isStable); |
220 } | 213 } |
221 | 214 |
222 void removeAndClearReferences(TypeGraphInferrerEngine inferrer) { | 215 void removeAndClearReferences(TypeGraphInferrerEngine inferrer) { |
223 assignments.forEach((info) { info.removeUser(this); }); | 216 assignments.forEach((info) { |
| 217 info.removeUser(this); |
| 218 }); |
224 } | 219 } |
225 | 220 |
226 void stabilize(TypeGraphInferrerEngine inferrer) { | 221 void stabilize(TypeGraphInferrerEngine inferrer) { |
227 removeAndClearReferences(inferrer); | 222 removeAndClearReferences(inferrer); |
228 // Do not remove users because the tracing analysis could be interested | 223 // Do not remove users because the tracing analysis could be interested |
229 // in tracing the users of this node. | 224 // in tracing the users of this node. |
230 _assignments = STOP_TRACKING_ASSIGNMENTS_MARKER; | 225 _assignments = STOP_TRACKING_ASSIGNMENTS_MARKER; |
231 abandonInferencing = true; | 226 abandonInferencing = true; |
232 isStable = true; | 227 isStable = true; |
233 } | 228 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 } | 267 } |
273 | 268 |
274 /** | 269 /** |
275 * Parameters of instance functions behave differently than other | 270 * Parameters of instance functions behave differently than other |
276 * elements because the inferrer may remove assignments. This happens | 271 * elements because the inferrer may remove assignments. This happens |
277 * when the receiver of a dynamic call site can be refined | 272 * when the receiver of a dynamic call site can be refined |
278 * to a type where we know more about which instance method is being | 273 * to a type where we know more about which instance method is being |
279 * called. | 274 * called. |
280 */ | 275 */ |
281 class ParameterAssignments extends IterableBase<TypeInformation> { | 276 class ParameterAssignments extends IterableBase<TypeInformation> { |
282 final Map<TypeInformation, int> assignments = | 277 final Map<TypeInformation, int> assignments = new Map<TypeInformation, int>(); |
283 new Map<TypeInformation, int>(); | |
284 | 278 |
285 void remove(TypeInformation info) { | 279 void remove(TypeInformation info) { |
286 int existing = assignments[info]; | 280 int existing = assignments[info]; |
287 if (existing == null) return; | 281 if (existing == null) return; |
288 if (existing == 1) { | 282 if (existing == 1) { |
289 assignments.remove(info); | 283 assignments.remove(info); |
290 } else { | 284 } else { |
291 assignments[info] = existing - 1; | 285 assignments[info] = existing - 1; |
292 } | 286 } |
293 } | 287 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 if (parameter.functionDeclaration.isInstanceMember) { | 352 if (parameter.functionDeclaration.isInstanceMember) { |
359 return new ParameterTypeInformation._instanceMember(element, types); | 353 return new ParameterTypeInformation._instanceMember(element, types); |
360 } | 354 } |
361 return new ParameterTypeInformation._internal(element, types); | 355 return new ParameterTypeInformation._internal(element, types); |
362 } | 356 } |
363 return new MemberTypeInformation._internal(element); | 357 return new MemberTypeInformation._internal(element); |
364 } | 358 } |
365 | 359 |
366 ElementTypeInformation._internal(MemberTypeInformation context, this.element) | 360 ElementTypeInformation._internal(MemberTypeInformation context, this.element) |
367 : super(context); | 361 : super(context); |
368 ElementTypeInformation._withAssignments(MemberTypeInformation context, | 362 ElementTypeInformation._withAssignments( |
369 this.element, assignments) | 363 MemberTypeInformation context, this.element, assignments) |
370 : super.withAssignments(context, assignments); | 364 : super.withAssignments(context, assignments); |
371 } | 365 } |
372 | 366 |
373 /** | 367 /** |
374 * A node representing members in the broadest sense: | 368 * A node representing members in the broadest sense: |
375 * | 369 * |
376 * - Functions | 370 * - Functions |
377 * - Constructors | 371 * - Constructors |
378 * - Fields (also synthetic ones due to closures) | 372 * - Fields (also synthetic ones due to closures) |
379 * - Local functions (closures) | 373 * - Local functions (closures) |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 | 454 |
461 // Closurized methods never become stable to ensure that the information in | 455 // Closurized methods never become stable to ensure that the information in |
462 // [users] is accurate. The inference stops tracking users for stable types. | 456 // [users] is accurate. The inference stops tracking users for stable types. |
463 // Note that we only override the getter, the setter will still modify the | 457 // Note that we only override the getter, the setter will still modify the |
464 // state of the [isStable] field inhertied from [TypeInformation]. | 458 // state of the [isStable] field inhertied from [TypeInformation]. |
465 bool get isStable => super.isStable && !isClosurized; | 459 bool get isStable => super.isStable && !isClosurized; |
466 | 460 |
467 TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) { | 461 TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) { |
468 if (element.isField && | 462 if (element.isField && |
469 (!inferrer.backend.canBeUsedForGlobalOptimizations(element) || | 463 (!inferrer.backend.canBeUsedForGlobalOptimizations(element) || |
470 inferrer.annotations.assumeDynamic(element))) { | 464 inferrer.annotations.assumeDynamic(element))) { |
471 // Do not infer types for fields that have a corresponding annotation or | 465 // Do not infer types for fields that have a corresponding annotation or |
472 // are assigned by synthesized calls | 466 // are assigned by synthesized calls |
473 | 467 |
474 giveUp(inferrer); | 468 giveUp(inferrer); |
475 return safeType(inferrer); | 469 return safeType(inferrer); |
476 } | 470 } |
477 if (inferrer.isNativeElement(element)) { | 471 if (inferrer.isNativeElement(element)) { |
478 // Use the type annotation as the type for native elements. We | 472 // Use the type annotation as the type for native elements. We |
479 // also give up on inferring to make sure this element never | 473 // also give up on inferring to make sure this element never |
480 // goes in the work queue. | 474 // goes in the work queue. |
481 giveUp(inferrer); | 475 giveUp(inferrer); |
482 if (element.isField) { | 476 if (element.isField) { |
483 return inferrer.typeOfNativeBehavior( | 477 return inferrer |
484 native.NativeBehavior.ofFieldLoad(element, inferrer.compiler)).type; | 478 .typeOfNativeBehavior( |
| 479 native.NativeBehavior.ofFieldLoad(element, inferrer.compiler)) |
| 480 .type; |
485 } else { | 481 } else { |
486 assert(element.isFunction || | 482 assert(element.isFunction || |
487 element.isGetter || | 483 element.isGetter || |
488 element.isSetter || | 484 element.isSetter || |
489 element.isConstructor); | 485 element.isConstructor); |
490 TypedElement typedElement = element; | 486 TypedElement typedElement = element; |
491 var elementType = typedElement.type; | 487 var elementType = typedElement.type; |
492 if (elementType.kind != TypeKind.FUNCTION) { | 488 if (elementType.kind != TypeKind.FUNCTION) { |
493 return safeType(inferrer); | 489 return safeType(inferrer); |
494 } else { | 490 } else { |
495 return inferrer.typeOfNativeBehavior( | 491 return inferrer |
496 native.NativeBehavior.ofMethod(element, inferrer.compiler)).type; | 492 .typeOfNativeBehavior( |
| 493 native.NativeBehavior.ofMethod(element, inferrer.compiler)) |
| 494 .type; |
497 } | 495 } |
498 } | 496 } |
499 } | 497 } |
500 | 498 |
501 Compiler compiler = inferrer.compiler; | 499 Compiler compiler = inferrer.compiler; |
502 if (element.declaration == compiler.intEnvironment) { | 500 if (element.declaration == compiler.intEnvironment) { |
503 giveUp(inferrer); | 501 giveUp(inferrer); |
504 return compiler.typesTask.intType.nullable(); | 502 return compiler.typesTask.intType.nullable(); |
505 } else if (element.declaration == compiler.boolEnvironment) { | 503 } else if (element.declaration == compiler.boolEnvironment) { |
506 giveUp(inferrer); | 504 giveUp(inferrer); |
507 return compiler.typesTask.boolType.nullable(); | 505 return compiler.typesTask.boolType.nullable(); |
508 } else if (element.declaration == compiler.stringEnvironment) { | 506 } else if (element.declaration == compiler.stringEnvironment) { |
509 giveUp(inferrer); | 507 giveUp(inferrer); |
510 return compiler.typesTask.stringType.nullable(); | 508 return compiler.typesTask.stringType.nullable(); |
511 } | 509 } |
512 return null; | 510 return null; |
513 } | 511 } |
514 | 512 |
515 TypeMask potentiallyNarrowType(TypeMask mask, | 513 TypeMask potentiallyNarrowType( |
516 TypeGraphInferrerEngine inferrer) { | 514 TypeMask mask, TypeGraphInferrerEngine inferrer) { |
517 Compiler compiler = inferrer.compiler; | 515 Compiler compiler = inferrer.compiler; |
518 if (!compiler.options.trustTypeAnnotations && | 516 if (!compiler.options.trustTypeAnnotations && |
519 !compiler.options.enableTypeAssertions && | 517 !compiler.options.enableTypeAssertions && |
520 !inferrer.annotations.trustTypeAnnotations(element)) { | 518 !inferrer.annotations.trustTypeAnnotations(element)) { |
521 return mask; | 519 return mask; |
522 } | 520 } |
523 if (element.isGenerativeConstructor || | 521 if (element.isGenerativeConstructor || element.isSetter) { |
524 element.isSetter) { | |
525 return mask; | 522 return mask; |
526 } | 523 } |
527 if (element.isField) { | 524 if (element.isField) { |
528 return _narrowType(compiler, mask, element.type); | 525 return _narrowType(compiler, mask, element.type); |
529 } | 526 } |
530 assert(element.isFunction || | 527 assert( |
531 element.isGetter || | 528 element.isFunction || element.isGetter || element.isFactoryConstructor); |
532 element.isFactoryConstructor); | |
533 | 529 |
534 FunctionType type = element.type; | 530 FunctionType type = element.type; |
535 return _narrowType(compiler, mask, type.returnType); | 531 return _narrowType(compiler, mask, type.returnType); |
536 } | 532 } |
537 | 533 |
538 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 534 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
539 TypeMask special = handleSpecialCases(inferrer); | 535 TypeMask special = handleSpecialCases(inferrer); |
540 if (special != null) return potentiallyNarrowType(special, inferrer); | 536 if (special != null) return potentiallyNarrowType(special, inferrer); |
541 return potentiallyNarrowType( | 537 return potentiallyNarrowType( |
542 inferrer.types.computeTypeMask(assignments), inferrer); | 538 inferrer.types.computeTypeMask(assignments), inferrer); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 * - Parameters | 575 * - Parameters |
580 * - Initializing formals | 576 * - Initializing formals |
581 * | 577 * |
582 * These should never be created directly but instead are constructed by | 578 * These should never be created directly but instead are constructed by |
583 * the [ElementTypeInformation] factory. | 579 * the [ElementTypeInformation] factory. |
584 */ | 580 */ |
585 class ParameterTypeInformation extends ElementTypeInformation { | 581 class ParameterTypeInformation extends ElementTypeInformation { |
586 ParameterElement get element => super.element; | 582 ParameterElement get element => super.element; |
587 FunctionElement get declaration => element.functionDeclaration; | 583 FunctionElement get declaration => element.functionDeclaration; |
588 | 584 |
589 ParameterTypeInformation._internal(ParameterElement element, | 585 ParameterTypeInformation._internal( |
590 TypeInformationSystem types) | 586 ParameterElement element, TypeInformationSystem types) |
591 : super._internal(types.getInferredTypeOf(element.functionDeclaration), | 587 : super._internal( |
592 element) { | 588 types.getInferredTypeOf(element.functionDeclaration), element) { |
593 assert(!element.functionDeclaration.isInstanceMember); | 589 assert(!element.functionDeclaration.isInstanceMember); |
594 } | 590 } |
595 | 591 |
596 ParameterTypeInformation._instanceMember(ParameterElement element, | 592 ParameterTypeInformation._instanceMember( |
597 TypeInformationSystem types) | 593 ParameterElement element, TypeInformationSystem types) |
598 : super._withAssignments( | 594 : super._withAssignments( |
599 types.getInferredTypeOf(element.functionDeclaration), | 595 types.getInferredTypeOf(element.functionDeclaration), |
600 element, | 596 element, |
601 new ParameterAssignments()) { | 597 new ParameterAssignments()) { |
602 assert(element.functionDeclaration.isInstanceMember); | 598 assert(element.functionDeclaration.isInstanceMember); |
603 } | 599 } |
604 | 600 |
605 bool isTearOffClosureParameter = false; | 601 bool isTearOffClosureParameter = false; |
606 | 602 |
607 void tagAsTearOffClosureParameter(TypeGraphInferrerEngine inferrer) { | 603 void tagAsTearOffClosureParameter(TypeGraphInferrerEngine inferrer) { |
608 assert(element.isParameter); | 604 assert(element.isParameter); |
609 isTearOffClosureParameter = true; | 605 isTearOffClosureParameter = true; |
610 // We have to add a flow-edge for the default value (if it exists), as we | 606 // We have to add a flow-edge for the default value (if it exists), as we |
611 // might not see all call-sites and thus miss the use of it. | 607 // might not see all call-sites and thus miss the use of it. |
(...skipping 18 matching lines...) Expand all Loading... |
630 if ((isTearOffClosureParameter || declaration.isLocal) && | 626 if ((isTearOffClosureParameter || declaration.isLocal) && |
631 disableInferenceForClosures) { | 627 disableInferenceForClosures) { |
632 // Do not infer types for parameters of closures. We do not | 628 // Do not infer types for parameters of closures. We do not |
633 // clear the assignments in case the closure is successfully | 629 // clear the assignments in case the closure is successfully |
634 // traced. | 630 // traced. |
635 giveUp(inferrer, clearAssignments: false); | 631 giveUp(inferrer, clearAssignments: false); |
636 return safeType(inferrer); | 632 return safeType(inferrer); |
637 } | 633 } |
638 if (declaration.isInstanceMember && | 634 if (declaration.isInstanceMember && |
639 (declaration.name == Identifiers.noSuchMethod_ || | 635 (declaration.name == Identifiers.noSuchMethod_ || |
640 (declaration.name == Identifiers.call && | 636 (declaration.name == Identifiers.call && |
641 disableInferenceForClosures))) { | 637 disableInferenceForClosures))) { |
642 // Do not infer types for parameters of [noSuchMethod] and | 638 // Do not infer types for parameters of [noSuchMethod] and |
643 // [call] instance methods. | 639 // [call] instance methods. |
644 giveUp(inferrer); | 640 giveUp(inferrer); |
645 return safeType(inferrer); | 641 return safeType(inferrer); |
646 } | 642 } |
647 if (inferrer.compiler.world.getMightBePassedToApply(declaration)) { | 643 if (inferrer.compiler.world.getMightBePassedToApply(declaration)) { |
648 giveUp(inferrer); | 644 giveUp(inferrer); |
649 return safeType(inferrer); | 645 return safeType(inferrer); |
650 } | 646 } |
651 if (declaration == inferrer.mainElement) { | 647 if (declaration == inferrer.mainElement) { |
652 // The implicit call to main is not seen by the inferrer, | 648 // The implicit call to main is not seen by the inferrer, |
653 // therefore we explicitly set the type of its parameters as | 649 // therefore we explicitly set the type of its parameters as |
654 // dynamic. | 650 // dynamic. |
655 // TODO(14566): synthesize a call instead to get the exact | 651 // TODO(14566): synthesize a call instead to get the exact |
656 // types. | 652 // types. |
657 giveUp(inferrer); | 653 giveUp(inferrer); |
658 return safeType(inferrer); | 654 return safeType(inferrer); |
659 } | 655 } |
660 | 656 |
661 return null; | 657 return null; |
662 } | 658 } |
663 | 659 |
664 TypeMask potentiallyNarrowType(TypeMask mask, | 660 TypeMask potentiallyNarrowType( |
665 TypeGraphInferrerEngine inferrer) { | 661 TypeMask mask, TypeGraphInferrerEngine inferrer) { |
666 Compiler compiler = inferrer.compiler; | 662 Compiler compiler = inferrer.compiler; |
667 if (!compiler.options.trustTypeAnnotations && | 663 if (!compiler.options.trustTypeAnnotations && |
668 !inferrer.annotations.trustTypeAnnotations(declaration)) { | 664 !inferrer.annotations.trustTypeAnnotations(declaration)) { |
669 return mask; | 665 return mask; |
670 } | 666 } |
671 // When type assertions are enabled (aka checked mode), we have to always | 667 // When type assertions are enabled (aka checked mode), we have to always |
672 // ignore type annotations to ensure that the checks are actually inserted | 668 // ignore type annotations to ensure that the checks are actually inserted |
673 // into the function body and retained until runtime. | 669 // into the function body and retained until runtime. |
674 assert(!compiler.options.enableTypeAssertions); | 670 assert(!compiler.options.enableTypeAssertions); |
675 return _narrowType(compiler, mask, element.type); | 671 return _narrowType(compiler, mask, element.type); |
676 } | 672 } |
677 | 673 |
678 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 674 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
679 TypeMask special = handleSpecialCases(inferrer); | 675 TypeMask special = handleSpecialCases(inferrer); |
680 if (special != null) return special; | 676 if (special != null) return special; |
681 return potentiallyNarrowType(inferrer.types.computeTypeMask(assignments), | 677 return potentiallyNarrowType( |
682 inferrer); | 678 inferrer.types.computeTypeMask(assignments), inferrer); |
683 } | 679 } |
684 | 680 |
685 TypeMask safeType(TypeGraphInferrerEngine inferrer) { | 681 TypeMask safeType(TypeGraphInferrerEngine inferrer) { |
686 return potentiallyNarrowType(super.safeType(inferrer), inferrer); | 682 return potentiallyNarrowType(super.safeType(inferrer), inferrer); |
687 } | 683 } |
688 | 684 |
689 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 685 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
690 // The number of assignments of parameters of instance methods is | 686 // The number of assignments of parameters of instance methods is |
691 // not stable. Therefore such a parameter cannot be stable. | 687 // not stable. Therefore such a parameter cannot be stable. |
692 if (element.functionDeclaration.isInstanceMember) { | 688 if (element.functionDeclaration.isInstanceMember) { |
(...skipping 21 matching lines...) Expand all Loading... |
714 */ | 710 */ |
715 abstract class CallSiteTypeInformation extends TypeInformation | 711 abstract class CallSiteTypeInformation extends TypeInformation |
716 with ApplyableTypeInformation { | 712 with ApplyableTypeInformation { |
717 final Spannable call; | 713 final Spannable call; |
718 final Element caller; | 714 final Element caller; |
719 final Selector selector; | 715 final Selector selector; |
720 final TypeMask mask; | 716 final TypeMask mask; |
721 final ArgumentsTypes arguments; | 717 final ArgumentsTypes arguments; |
722 final bool inLoop; | 718 final bool inLoop; |
723 | 719 |
724 CallSiteTypeInformation( | 720 CallSiteTypeInformation(MemberTypeInformation context, this.call, this.caller, |
725 MemberTypeInformation context, | 721 this.selector, this.mask, this.arguments, this.inLoop) |
726 this.call, | 722 : super.noAssignments(context); |
727 this.caller, | |
728 this.selector, | |
729 this.mask, | |
730 this.arguments, | |
731 this.inLoop) : super.noAssignments(context); | |
732 | 723 |
733 String toString() => 'Call site $call $type'; | 724 String toString() => 'Call site $call $type'; |
734 | 725 |
735 /// Add [this] to the graph being computed by [engine]. | 726 /// Add [this] to the graph being computed by [engine]. |
736 void addToGraph(TypeGraphInferrerEngine engine); | 727 void addToGraph(TypeGraphInferrerEngine engine); |
737 | 728 |
738 /// Return an iterable over the targets of this call. | 729 /// Return an iterable over the targets of this call. |
739 Iterable<Element> get callees; | 730 Iterable<Element> get callees; |
740 } | 731 } |
741 | 732 |
(...skipping 13 matching lines...) Expand all Loading... |
755 | 746 |
756 void addToGraph(TypeGraphInferrerEngine inferrer) { | 747 void addToGraph(TypeGraphInferrerEngine inferrer) { |
757 MemberTypeInformation callee = | 748 MemberTypeInformation callee = |
758 inferrer.types.getInferredTypeOf(calledElement); | 749 inferrer.types.getInferredTypeOf(calledElement); |
759 callee.addCall(caller, call); | 750 callee.addCall(caller, call); |
760 callee.addUser(this); | 751 callee.addUser(this); |
761 if (arguments != null) { | 752 if (arguments != null) { |
762 arguments.forEach((info) => info.addUser(this)); | 753 arguments.forEach((info) => info.addUser(this)); |
763 } | 754 } |
764 inferrer.updateParameterAssignments( | 755 inferrer.updateParameterAssignments( |
765 this, calledElement, arguments, selector, mask, remove: false, | 756 this, calledElement, arguments, selector, mask, |
766 addToQueue: false); | 757 remove: false, addToQueue: false); |
767 } | 758 } |
768 | 759 |
769 bool get isSynthesized { | 760 bool get isSynthesized { |
770 // Some calls do not have a corresponding selector, for example | 761 // Some calls do not have a corresponding selector, for example |
771 // fowarding factory constructors, or synthesized super | 762 // fowarding factory constructors, or synthesized super |
772 // constructor calls. We synthesize these calls but do | 763 // constructor calls. We synthesize these calls but do |
773 // not create a selector for them. | 764 // not create a selector for them. |
774 return selector == null; | 765 return selector == null; |
775 } | 766 } |
776 | 767 |
(...skipping 24 matching lines...) Expand all Loading... |
801 callee.removeUser(this); | 792 callee.removeUser(this); |
802 if (arguments != null) { | 793 if (arguments != null) { |
803 arguments.forEach((info) => info.removeUser(this)); | 794 arguments.forEach((info) => info.removeUser(this)); |
804 } | 795 } |
805 super.removeAndClearReferences(inferrer); | 796 super.removeAndClearReferences(inferrer); |
806 } | 797 } |
807 } | 798 } |
808 | 799 |
809 class DynamicCallSiteTypeInformation extends CallSiteTypeInformation { | 800 class DynamicCallSiteTypeInformation extends CallSiteTypeInformation { |
810 final TypeInformation receiver; | 801 final TypeInformation receiver; |
| 802 |
811 /// Cached targets of this call. | 803 /// Cached targets of this call. |
812 Iterable<Element> targets; | 804 Iterable<Element> targets; |
813 | 805 |
814 DynamicCallSiteTypeInformation( | 806 DynamicCallSiteTypeInformation( |
815 MemberTypeInformation context, | 807 MemberTypeInformation context, |
816 Spannable call, | 808 Spannable call, |
817 Element enclosing, | 809 Element enclosing, |
818 Selector selector, | 810 Selector selector, |
819 TypeMask mask, | 811 TypeMask mask, |
820 this.receiver, | 812 this.receiver, |
821 ArgumentsTypes arguments, | 813 ArgumentsTypes arguments, |
822 bool inLoop) | 814 bool inLoop) |
823 : super(context, call, enclosing, selector, mask, arguments, inLoop); | 815 : super(context, call, enclosing, selector, mask, arguments, inLoop); |
824 | 816 |
825 void addToGraph(TypeGraphInferrerEngine inferrer) { | 817 void addToGraph(TypeGraphInferrerEngine inferrer) { |
826 assert(receiver != null); | 818 assert(receiver != null); |
827 TypeMask typeMask = computeTypedSelector(inferrer); | 819 TypeMask typeMask = computeTypedSelector(inferrer); |
828 targets = inferrer.compiler.world.allFunctions.filter(selector, typeMask); | 820 targets = inferrer.compiler.world.allFunctions.filter(selector, typeMask); |
829 receiver.addUser(this); | 821 receiver.addUser(this); |
830 if (arguments != null) { | 822 if (arguments != null) { |
831 arguments.forEach((info) => info.addUser(this)); | 823 arguments.forEach((info) => info.addUser(this)); |
832 } | 824 } |
833 for (Element element in targets) { | 825 for (Element element in targets) { |
834 MemberTypeInformation callee = inferrer.types.getInferredTypeOf(element); | 826 MemberTypeInformation callee = inferrer.types.getInferredTypeOf(element); |
835 callee.addCall(caller, call); | 827 callee.addCall(caller, call); |
836 callee.addUser(this); | 828 callee.addUser(this); |
837 inferrer.updateParameterAssignments( | 829 inferrer.updateParameterAssignments( |
838 this, element, arguments, selector, typeMask, remove: false, | 830 this, element, arguments, selector, typeMask, |
839 addToQueue: false); | 831 remove: false, addToQueue: false); |
840 } | 832 } |
841 } | 833 } |
842 | 834 |
843 Iterable<Element> get callees => targets.map((e) => e.implementation); | 835 Iterable<Element> get callees => targets.map((e) => e.implementation); |
844 | 836 |
845 TypeMask computeTypedSelector(TypeGraphInferrerEngine inferrer) { | 837 TypeMask computeTypedSelector(TypeGraphInferrerEngine inferrer) { |
846 TypeMask receiverType = receiver.type; | 838 TypeMask receiverType = receiver.type; |
847 | 839 |
848 if (mask != receiverType) { | 840 if (mask != receiverType) { |
849 return receiverType == inferrer.compiler.typesTask.dynamicType | 841 return receiverType == inferrer.compiler.typesTask.dynamicType |
850 ? null : receiverType; | 842 ? null |
| 843 : receiverType; |
851 } else { | 844 } else { |
852 return mask; | 845 return mask; |
853 } | 846 } |
854 } | 847 } |
855 | 848 |
856 bool targetsIncludeComplexNoSuchMethod(TypeGraphInferrerEngine inferrer) { | 849 bool targetsIncludeComplexNoSuchMethod(TypeGraphInferrerEngine inferrer) { |
857 return targets.any((Element e) { | 850 return targets.any((Element e) { |
858 return e is FunctionElement && | 851 return e is FunctionElement && |
859 e.isInstanceMember && | 852 e.isInstanceMember && |
860 e.name == Identifiers.noSuchMethod_ && | 853 e.name == Identifiers.noSuchMethod_ && |
861 inferrer.backend.isComplexNoSuchMethod(e); | 854 inferrer.backend.isComplexNoSuchMethod(e); |
862 }); | 855 }); |
863 } | 856 } |
864 | 857 |
865 /** | 858 /** |
866 * We optimize certain operations on the [int] class because we know | 859 * We optimize certain operations on the [int] class because we know |
867 * more about their return type than the actual Dart code. For | 860 * more about their return type than the actual Dart code. For |
868 * example, we know int + int returns an int. The Dart code for | 861 * example, we know int + int returns an int. The Dart code for |
869 * [int.operator+] only says it returns a [num]. | 862 * [int.operator+] only says it returns a [num]. |
870 */ | 863 */ |
871 TypeInformation handleIntrisifiedSelector(Selector selector, | 864 TypeInformation handleIntrisifiedSelector( |
872 TypeMask mask, | 865 Selector selector, TypeMask mask, TypeGraphInferrerEngine inferrer) { |
873 TypeGraphInferrerEngine inferrer) { | |
874 ClassWorld classWorld = inferrer.classWorld; | 866 ClassWorld classWorld = inferrer.classWorld; |
875 if (!classWorld.backend.intImplementation.isResolved) return null; | 867 if (!classWorld.backend.intImplementation.isResolved) return null; |
876 if (mask == null) return null; | 868 if (mask == null) return null; |
877 if (!mask.containsOnlyInt(classWorld)) { | 869 if (!mask.containsOnlyInt(classWorld)) { |
878 return null; | 870 return null; |
879 } | 871 } |
880 if (!selector.isCall && !selector.isOperator) return null; | 872 if (!selector.isCall && !selector.isOperator) return null; |
881 if (!arguments.named.isEmpty) return null; | 873 if (!arguments.named.isEmpty) return null; |
882 if (arguments.positional.length > 1) return null; | 874 if (arguments.positional.length > 1) return null; |
883 | 875 |
884 ClassElement uint31Implementation = classWorld.backend.uint31Implementation; | 876 ClassElement uint31Implementation = classWorld.backend.uint31Implementation; |
885 bool isInt(info) => info.type.containsOnlyInt(classWorld); | 877 bool isInt(info) => info.type.containsOnlyInt(classWorld); |
886 bool isEmpty(info) => info.type.isEmpty; | 878 bool isEmpty(info) => info.type.isEmpty; |
887 bool isUInt31(info) { | 879 bool isUInt31(info) { |
888 return info.type.satisfies(uint31Implementation, classWorld); | 880 return info.type.satisfies(uint31Implementation, classWorld); |
889 } | 881 } |
890 bool isPositiveInt(info) { | 882 bool isPositiveInt(info) { |
891 return info.type.satisfies( | 883 return info.type |
892 classWorld.backend.positiveIntImplementation, classWorld); | 884 .satisfies(classWorld.backend.positiveIntImplementation, classWorld); |
893 } | 885 } |
894 | 886 |
895 String name = selector.name; | 887 String name = selector.name; |
896 // We are optimizing for the cases that are not expressed in the | 888 // We are optimizing for the cases that are not expressed in the |
897 // Dart code, for example: | 889 // Dart code, for example: |
898 // int + int -> int | 890 // int + int -> int |
899 // uint31 | uint31 -> uint31 | 891 // uint31 | uint31 -> uint31 |
900 if (name == '*' || name == '+' || name == '%' || name == 'remainder' || | 892 if (name == '*' || |
| 893 name == '+' || |
| 894 name == '%' || |
| 895 name == 'remainder' || |
901 name == '~/') { | 896 name == '~/') { |
902 if (isPositiveInt(receiver) && | 897 if (isPositiveInt(receiver) && |
903 arguments.hasOnePositionalArgumentThatMatches(isPositiveInt)) { | 898 arguments.hasOnePositionalArgumentThatMatches(isPositiveInt)) { |
904 // uint31 + uint31 -> uint32 | 899 // uint31 + uint31 -> uint32 |
905 if (name == '+' && isUInt31(receiver) && | 900 if (name == '+' && |
| 901 isUInt31(receiver) && |
906 arguments.hasOnePositionalArgumentThatMatches(isUInt31)) { | 902 arguments.hasOnePositionalArgumentThatMatches(isUInt31)) { |
907 return inferrer.types.uint32Type; | 903 return inferrer.types.uint32Type; |
908 } else { | 904 } else { |
909 return inferrer.types.positiveIntType; | 905 return inferrer.types.positiveIntType; |
910 } | 906 } |
911 } else if (arguments.hasOnePositionalArgumentThatMatches(isInt)) { | 907 } else if (arguments.hasOnePositionalArgumentThatMatches(isInt)) { |
912 return inferrer.types.intType; | 908 return inferrer.types.intType; |
913 } else if (arguments.hasOnePositionalArgumentThatMatches(isEmpty)) { | 909 } else if (arguments.hasOnePositionalArgumentThatMatches(isEmpty)) { |
914 return inferrer.types.nonNullEmptyType; | 910 return inferrer.types.nonNullEmptyType; |
915 } else { | 911 } else { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 } | 943 } |
948 | 944 |
949 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 945 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
950 Iterable<Element> oldTargets = targets; | 946 Iterable<Element> oldTargets = targets; |
951 TypeMask typeMask = computeTypedSelector(inferrer); | 947 TypeMask typeMask = computeTypedSelector(inferrer); |
952 inferrer.updateSelectorInTree(caller, call, selector, typeMask); | 948 inferrer.updateSelectorInTree(caller, call, selector, typeMask); |
953 | 949 |
954 Compiler compiler = inferrer.compiler; | 950 Compiler compiler = inferrer.compiler; |
955 TypeMask maskToUse = | 951 TypeMask maskToUse = |
956 compiler.world.extendMaskIfReachesAll(selector, typeMask); | 952 compiler.world.extendMaskIfReachesAll(selector, typeMask); |
957 bool canReachAll = compiler.enabledInvokeOn && | 953 bool canReachAll = compiler.enabledInvokeOn && (maskToUse != typeMask); |
958 (maskToUse != typeMask); | |
959 | 954 |
960 // If this call could potentially reach all methods that satisfy | 955 // If this call could potentially reach all methods that satisfy |
961 // the untyped selector (through noSuchMethod's `Invocation` | 956 // the untyped selector (through noSuchMethod's `Invocation` |
962 // and a call to `delegate`), we iterate over all these methods to | 957 // and a call to `delegate`), we iterate over all these methods to |
963 // update their parameter types. | 958 // update their parameter types. |
964 targets = compiler.world.allFunctions.filter(selector, maskToUse); | 959 targets = compiler.world.allFunctions.filter(selector, maskToUse); |
965 Iterable<Element> typedTargets = canReachAll | 960 Iterable<Element> typedTargets = canReachAll |
966 ? compiler.world.allFunctions.filter(selector, typeMask) | 961 ? compiler.world.allFunctions.filter(selector, typeMask) |
967 : targets; | 962 : targets; |
968 | 963 |
969 // Update the call graph if the targets could have changed. | 964 // Update the call graph if the targets could have changed. |
970 if (!identical(targets, oldTargets)) { | 965 if (!identical(targets, oldTargets)) { |
971 // Add calls to new targets to the graph. | 966 // Add calls to new targets to the graph. |
972 targets | 967 targets |
973 .where((target) => !oldTargets.contains(target)) | 968 .where((target) => !oldTargets.contains(target)) |
974 .forEach((element) { | 969 .forEach((element) { |
975 MemberTypeInformation callee = | 970 MemberTypeInformation callee = |
976 inferrer.types.getInferredTypeOf(element); | 971 inferrer.types.getInferredTypeOf(element); |
977 callee.addCall(caller, call); | 972 callee.addCall(caller, call); |
978 callee.addUser(this); | 973 callee.addUser(this); |
979 inferrer.updateParameterAssignments( | 974 inferrer.updateParameterAssignments( |
980 this, element, arguments, selector, typeMask, remove: false, | 975 this, element, arguments, selector, typeMask, |
981 addToQueue: true); | 976 remove: false, addToQueue: true); |
982 }); | 977 }); |
983 | 978 |
984 // Walk over the old targets, and remove calls that cannot happen anymore. | 979 // Walk over the old targets, and remove calls that cannot happen anymore. |
985 oldTargets | 980 oldTargets |
986 .where((target) => !targets.contains(target)) | 981 .where((target) => !targets.contains(target)) |
987 .forEach((element) { | 982 .forEach((element) { |
988 MemberTypeInformation callee = | 983 MemberTypeInformation callee = |
989 inferrer.types.getInferredTypeOf(element); | 984 inferrer.types.getInferredTypeOf(element); |
990 callee.removeCall(caller, call); | 985 callee.removeCall(caller, call); |
991 callee.removeUser(this); | 986 callee.removeUser(this); |
992 inferrer.updateParameterAssignments( | 987 inferrer.updateParameterAssignments( |
993 this, element, arguments, selector, typeMask, remove: true, | 988 this, element, arguments, selector, typeMask, |
994 addToQueue: true); | 989 remove: true, addToQueue: true); |
995 }); | 990 }); |
996 } | 991 } |
997 | 992 |
998 // Walk over the found targets, and compute the joined union type mask | 993 // Walk over the found targets, and compute the joined union type mask |
999 // for all these targets. | 994 // for all these targets. |
1000 TypeMask result = inferrer.types.joinTypeMasks(targets.map((element) { | 995 TypeMask result = inferrer.types.joinTypeMasks(targets.map((element) { |
1001 // If [canReachAll] is true, then we are iterating over all | 996 // If [canReachAll] is true, then we are iterating over all |
1002 // targets that satisfy the untyped selector. We skip the return | 997 // targets that satisfy the untyped selector. We skip the return |
1003 // type of the targets that can only be reached through | 998 // type of the targets that can only be reached through |
1004 // `Invocation.delegate`. Note that the `noSuchMethod` targets | 999 // `Invocation.delegate`. Note that the `noSuchMethod` targets |
1005 // are included in [typedTargets]. | 1000 // are included in [typedTargets]. |
1006 if (canReachAll && !typedTargets.contains(element)) { | 1001 if (canReachAll && !typedTargets.contains(element)) { |
1007 return const TypeMask.nonNullEmpty(); | 1002 return const TypeMask.nonNullEmpty(); |
1008 } | 1003 } |
1009 | 1004 |
1010 if (inferrer.returnsListElementType(selector, typeMask)) { | 1005 if (inferrer.returnsListElementType(selector, typeMask)) { |
1011 ContainerTypeMask containerTypeMask = receiver.type; | 1006 ContainerTypeMask containerTypeMask = receiver.type; |
1012 return containerTypeMask.elementType; | 1007 return containerTypeMask.elementType; |
1013 } else if (inferrer.returnsMapValueType(selector, typeMask)) { | 1008 } else if (inferrer.returnsMapValueType(selector, typeMask)) { |
1014 if (typeMask.isDictionary && | 1009 if (typeMask.isDictionary && |
1015 arguments.positional[0].type.isValue && | 1010 arguments.positional[0].type.isValue && |
1016 arguments.positional[0].type.value.isString) { | 1011 arguments.positional[0].type.value.isString) { |
1017 DictionaryTypeMask dictionaryTypeMask = typeMask; | 1012 DictionaryTypeMask dictionaryTypeMask = typeMask; |
1018 ValueTypeMask arg = arguments.positional[0].type; | 1013 ValueTypeMask arg = arguments.positional[0].type; |
1019 String key = arg.value.primitiveValue.slowToString(); | 1014 String key = arg.value.primitiveValue.slowToString(); |
1020 if (dictionaryTypeMask.typeMap.containsKey(key)) { | 1015 if (dictionaryTypeMask.typeMap.containsKey(key)) { |
1021 if (debug.VERBOSE) { | 1016 if (debug.VERBOSE) { |
1022 print("Dictionary lookup for $key yields " | 1017 print("Dictionary lookup for $key yields " |
1023 "${dictionaryTypeMask.typeMap[key]}."); | 1018 "${dictionaryTypeMask.typeMap[key]}."); |
1024 } | 1019 } |
1025 return dictionaryTypeMask.typeMap[key]; | 1020 return dictionaryTypeMask.typeMap[key]; |
1026 } else { | 1021 } else { |
1027 // The typeMap is precise, so if we do not find the key, the lookup | 1022 // The typeMap is precise, so if we do not find the key, the lookup |
1028 // will be [null] at runtime. | 1023 // will be [null] at runtime. |
1029 if (debug.VERBOSE) { | 1024 if (debug.VERBOSE) { |
1030 print("Dictionary lookup for $key yields [null]."); | 1025 print("Dictionary lookup for $key yields [null]."); |
1031 } | 1026 } |
1032 return inferrer.types.nullType.type; | 1027 return inferrer.types.nullType.type; |
1033 } | 1028 } |
1034 } | 1029 } |
1035 MapTypeMask mapTypeMask = typeMask; | 1030 MapTypeMask mapTypeMask = typeMask; |
1036 if (debug.VERBOSE) { | 1031 if (debug.VERBOSE) { |
1037 print( | 1032 print("Map lookup for $selector yields ${mapTypeMask.valueType}."); |
1038 "Map lookup for $selector yields ${mapTypeMask.valueType}."); | |
1039 } | 1033 } |
1040 return mapTypeMask.valueType; | 1034 return mapTypeMask.valueType; |
1041 } else { | 1035 } else { |
1042 TypeInformation info = | 1036 TypeInformation info = |
1043 handleIntrisifiedSelector(selector, typeMask, inferrer); | 1037 handleIntrisifiedSelector(selector, typeMask, inferrer); |
1044 if (info != null) return info.type; | 1038 if (info != null) return info.type; |
1045 return inferrer.typeOfElementWithSelector(element, selector).type; | 1039 return inferrer.typeOfElementWithSelector(element, selector).type; |
1046 } | 1040 } |
1047 })); | 1041 })); |
1048 | 1042 |
(...skipping 11 matching lines...) Expand all Loading... |
1060 if (!abandonInferencing) { | 1054 if (!abandonInferencing) { |
1061 inferrer.updateSelectorInTree(caller, call, selector, mask); | 1055 inferrer.updateSelectorInTree(caller, call, selector, mask); |
1062 Iterable<Element> oldTargets = targets; | 1056 Iterable<Element> oldTargets = targets; |
1063 targets = inferrer.compiler.world.allFunctions.filter(selector, mask); | 1057 targets = inferrer.compiler.world.allFunctions.filter(selector, mask); |
1064 for (Element element in targets) { | 1058 for (Element element in targets) { |
1065 if (!oldTargets.contains(element)) { | 1059 if (!oldTargets.contains(element)) { |
1066 MemberTypeInformation callee = | 1060 MemberTypeInformation callee = |
1067 inferrer.types.getInferredTypeOf(element); | 1061 inferrer.types.getInferredTypeOf(element); |
1068 callee.addCall(caller, call); | 1062 callee.addCall(caller, call); |
1069 inferrer.updateParameterAssignments( | 1063 inferrer.updateParameterAssignments( |
1070 this, element, arguments, selector, mask, remove: false, | 1064 this, element, arguments, selector, mask, |
1071 addToQueue: true); | 1065 remove: false, addToQueue: true); |
1072 } | 1066 } |
1073 } | 1067 } |
1074 } | 1068 } |
1075 super.giveUp(inferrer, clearAssignments: clearAssignments); | 1069 super.giveUp(inferrer, clearAssignments: clearAssignments); |
1076 } | 1070 } |
1077 | 1071 |
1078 void removeAndClearReferences(TypeGraphInferrerEngine inferrer) { | 1072 void removeAndClearReferences(TypeGraphInferrerEngine inferrer) { |
1079 for (Element element in targets) { | 1073 for (Element element in targets) { |
1080 ElementTypeInformation callee = inferrer.types.getInferredTypeOf(element); | 1074 ElementTypeInformation callee = inferrer.types.getInferredTypeOf(element); |
1081 callee.removeUser(this); | 1075 callee.removeUser(this); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 void addUser(TypeInformation user) { | 1158 void addUser(TypeInformation user) { |
1165 // Nothing to do, a concrete type does not get updated so never | 1159 // Nothing to do, a concrete type does not get updated so never |
1166 // needs to notify its users. | 1160 // needs to notify its users. |
1167 } | 1161 } |
1168 | 1162 |
1169 void addUsersOf(TypeInformation other) { | 1163 void addUsersOf(TypeInformation other) { |
1170 // Nothing to do, a concrete type does not get updated so never | 1164 // Nothing to do, a concrete type does not get updated so never |
1171 // needs to notify its users. | 1165 // needs to notify its users. |
1172 } | 1166 } |
1173 | 1167 |
1174 void removeUser(TypeInformation user) { | 1168 void removeUser(TypeInformation user) {} |
1175 } | |
1176 | 1169 |
1177 void addAssignment(TypeInformation assignment) { | 1170 void addAssignment(TypeInformation assignment) { |
1178 throw "Not supported"; | 1171 throw "Not supported"; |
1179 } | 1172 } |
1180 | 1173 |
1181 void removeAssignment(TypeInformation assignment) { | 1174 void removeAssignment(TypeInformation assignment) { |
1182 throw "Not supported"; | 1175 throw "Not supported"; |
1183 } | 1176 } |
1184 | 1177 |
1185 TypeMask computeType(TypeGraphInferrerEngine inferrer) => type; | 1178 TypeMask computeType(TypeGraphInferrerEngine inferrer) => type; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1254 addAssignment(narrowedType); | 1247 addAssignment(narrowedType); |
1255 } | 1248 } |
1256 | 1249 |
1257 addAssignment(TypeInformation info) { | 1250 addAssignment(TypeInformation info) { |
1258 super.addAssignment(info); | 1251 super.addAssignment(info); |
1259 assert(assignments.length == 1); | 1252 assert(assignments.length == 1); |
1260 } | 1253 } |
1261 | 1254 |
1262 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1255 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1263 TypeMask input = assignments.first.type; | 1256 TypeMask input = assignments.first.type; |
1264 TypeMask intersection = input.intersection(typeAnnotation, | 1257 TypeMask intersection = |
1265 inferrer.classWorld); | 1258 input.intersection(typeAnnotation, inferrer.classWorld); |
1266 if (debug.ANOMALY_WARN) { | 1259 if (debug.ANOMALY_WARN) { |
1267 if (!input.containsMask(intersection, inferrer.classWorld) || | 1260 if (!input.containsMask(intersection, inferrer.classWorld) || |
1268 !typeAnnotation.containsMask(intersection, inferrer.classWorld)) { | 1261 !typeAnnotation.containsMask(intersection, inferrer.classWorld)) { |
1269 print("ANOMALY WARNING: narrowed $input to $intersection via " | 1262 print("ANOMALY WARNING: narrowed $input to $intersection via " |
1270 "$typeAnnotation"); | 1263 "$typeAnnotation"); |
1271 } | 1264 } |
1272 } | 1265 } |
1273 return intersection; | 1266 return intersection; |
1274 } | 1267 } |
1275 | 1268 |
1276 String toString() { | 1269 String toString() { |
1277 return 'Narrow to $typeAnnotation $type'; | 1270 return 'Narrow to $typeAnnotation $type'; |
1278 } | 1271 } |
1279 | 1272 |
1280 accept(TypeInformationVisitor visitor) { | 1273 accept(TypeInformationVisitor visitor) { |
1281 return visitor.visitNarrowTypeInformation(this); | 1274 return visitor.visitNarrowTypeInformation(this); |
1282 } | 1275 } |
1283 } | 1276 } |
1284 | 1277 |
1285 /** | 1278 /** |
1286 * An [InferredTypeInformation] is a [TypeInformation] that | 1279 * An [InferredTypeInformation] is a [TypeInformation] that |
1287 * defaults to the dynamic type until it is marked as beeing | 1280 * defaults to the dynamic type until it is marked as beeing |
1288 * inferred, at which point it computes its type based on | 1281 * inferred, at which point it computes its type based on |
1289 * its assignments. | 1282 * its assignments. |
1290 */ | 1283 */ |
1291 abstract class InferredTypeInformation extends TypeInformation { | 1284 abstract class InferredTypeInformation extends TypeInformation { |
1292 /** Whether the element type in that container has been inferred. */ | 1285 /** Whether the element type in that container has been inferred. */ |
1293 bool inferred = false; | 1286 bool inferred = false; |
1294 | 1287 |
1295 InferredTypeInformation(MemberTypeInformation context, | 1288 InferredTypeInformation( |
1296 TypeInformation parentType) | 1289 MemberTypeInformation context, TypeInformation parentType) |
1297 : super(context) { | 1290 : super(context) { |
1298 if (parentType != null) addAssignment(parentType); | 1291 if (parentType != null) addAssignment(parentType); |
1299 } | 1292 } |
1300 | 1293 |
1301 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1294 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1302 if (!inferred) return safeType(inferrer); | 1295 if (!inferred) return safeType(inferrer); |
1303 return inferrer.types.computeTypeMask(assignments); | 1296 return inferrer.types.computeTypeMask(assignments); |
1304 } | 1297 } |
1305 | 1298 |
1306 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 1299 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
1307 return inferred && super.hasStableType(inferrer); | 1300 return inferred && super.hasStableType(inferrer); |
1308 } | 1301 } |
1309 } | 1302 } |
1310 | 1303 |
1311 /** | 1304 /** |
1312 * A [ListTypeInformation] is a [TypeInformation] created | 1305 * A [ListTypeInformation] is a [TypeInformation] created |
1313 * for each `List` instantiations. | 1306 * for each `List` instantiations. |
1314 */ | 1307 */ |
1315 class ListTypeInformation extends TypeInformation | 1308 class ListTypeInformation extends TypeInformation with TracedTypeInformation { |
1316 with TracedTypeInformation { | |
1317 final ElementInContainerTypeInformation elementType; | 1309 final ElementInContainerTypeInformation elementType; |
1318 | 1310 |
1319 /** The container type before it is inferred. */ | 1311 /** The container type before it is inferred. */ |
1320 final ContainerTypeMask originalType; | 1312 final ContainerTypeMask originalType; |
1321 | 1313 |
1322 /** The length at the allocation site. */ | 1314 /** The length at the allocation site. */ |
1323 final int originalLength; | 1315 final int originalLength; |
1324 | 1316 |
1325 /** The length after the container has been traced. */ | 1317 /** The length after the container has been traced. */ |
1326 int inferredLength; | 1318 int inferredLength; |
1327 | 1319 |
1328 /** | 1320 /** |
1329 * Whether this list goes through a growable check. | 1321 * Whether this list goes through a growable check. |
1330 * We conservatively assume it does. | 1322 * We conservatively assume it does. |
1331 */ | 1323 */ |
1332 bool checksGrowable = true; | 1324 bool checksGrowable = true; |
1333 | 1325 |
1334 ListTypeInformation(MemberTypeInformation context, | 1326 ListTypeInformation(MemberTypeInformation context, this.originalType, |
1335 this.originalType, | 1327 this.elementType, this.originalLength) |
1336 this.elementType, | |
1337 this.originalLength) | |
1338 : super(context) { | 1328 : super(context) { |
1339 type = originalType; | 1329 type = originalType; |
1340 inferredLength = originalType.length; | 1330 inferredLength = originalType.length; |
1341 elementType.addUser(this); | 1331 elementType.addUser(this); |
1342 } | 1332 } |
1343 | 1333 |
1344 String toString() => 'List type $type'; | 1334 String toString() => 'List type $type'; |
1345 | 1335 |
1346 accept(TypeInformationVisitor visitor) { | 1336 accept(TypeInformationVisitor visitor) { |
1347 return visitor.visitListTypeInformation(this); | 1337 return visitor.visitListTypeInformation(this); |
1348 } | 1338 } |
1349 | 1339 |
1350 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 1340 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
1351 return elementType.isStable && super.hasStableType(inferrer); | 1341 return elementType.isStable && super.hasStableType(inferrer); |
1352 } | 1342 } |
1353 | 1343 |
1354 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1344 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1355 var mask = type; | 1345 var mask = type; |
1356 if (!mask.isContainer || | 1346 if (!mask.isContainer || |
1357 mask.elementType != elementType.type || | 1347 mask.elementType != elementType.type || |
1358 mask.length != inferredLength) { | 1348 mask.length != inferredLength) { |
1359 return new ContainerTypeMask(originalType.forwardTo, | 1349 return new ContainerTypeMask( |
1360 originalType.allocationNode, | 1350 originalType.forwardTo, |
1361 originalType.allocationElement, | 1351 originalType.allocationNode, |
1362 elementType.type, | 1352 originalType.allocationElement, |
1363 inferredLength); | 1353 elementType.type, |
| 1354 inferredLength); |
1364 } | 1355 } |
1365 return mask; | 1356 return mask; |
1366 } | 1357 } |
1367 | 1358 |
1368 TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; | 1359 TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; |
1369 | 1360 |
1370 void cleanup() { | 1361 void cleanup() { |
1371 super.cleanup(); | 1362 super.cleanup(); |
1372 elementType.cleanup(); | 1363 elementType.cleanup(); |
1373 _flowsInto = null; | 1364 _flowsInto = null; |
1374 } | 1365 } |
1375 } | 1366 } |
1376 | 1367 |
1377 /** | 1368 /** |
1378 * An [ElementInContainerTypeInformation] holds the common type of the | 1369 * An [ElementInContainerTypeInformation] holds the common type of the |
1379 * elements in a [ListTypeInformation]. | 1370 * elements in a [ListTypeInformation]. |
1380 */ | 1371 */ |
1381 class ElementInContainerTypeInformation extends InferredTypeInformation { | 1372 class ElementInContainerTypeInformation extends InferredTypeInformation { |
1382 ElementInContainerTypeInformation(MemberTypeInformation context, | 1373 ElementInContainerTypeInformation(MemberTypeInformation context, elementType) |
1383 elementType) | |
1384 : super(context, elementType); | 1374 : super(context, elementType); |
1385 | 1375 |
1386 String toString() => 'Element in container $type'; | 1376 String toString() => 'Element in container $type'; |
1387 | 1377 |
1388 accept(TypeInformationVisitor visitor) { | 1378 accept(TypeInformationVisitor visitor) { |
1389 return visitor.visitElementInContainerTypeInformation(this); | 1379 return visitor.visitElementInContainerTypeInformation(this); |
1390 } | 1380 } |
1391 } | 1381 } |
1392 | 1382 |
1393 /** | 1383 /** |
1394 * A [MapTypeInformation] is a [TypeInformation] created | 1384 * A [MapTypeInformation] is a [TypeInformation] created |
1395 * for maps. | 1385 * for maps. |
1396 */ | 1386 */ |
1397 class MapTypeInformation extends TypeInformation | 1387 class MapTypeInformation extends TypeInformation with TracedTypeInformation { |
1398 with TracedTypeInformation { | |
1399 // When in Dictionary mode, this map tracks the type of the values that | 1388 // When in Dictionary mode, this map tracks the type of the values that |
1400 // have been assigned to a specific [String] key. | 1389 // have been assigned to a specific [String] key. |
1401 final Map<String, ValueInMapTypeInformation> typeInfoMap = {}; | 1390 final Map<String, ValueInMapTypeInformation> typeInfoMap = {}; |
1402 // These fields track the overall type of the keys/values in the map. | 1391 // These fields track the overall type of the keys/values in the map. |
1403 final KeyInMapTypeInformation keyType; | 1392 final KeyInMapTypeInformation keyType; |
1404 final ValueInMapTypeInformation valueType; | 1393 final ValueInMapTypeInformation valueType; |
1405 final MapTypeMask originalType; | 1394 final MapTypeMask originalType; |
1406 | 1395 |
1407 // Set to false if a statically unknown key flows into this map. | 1396 // Set to false if a statically unknown key flows into this map. |
1408 bool _allKeysAreStrings = true; | 1397 bool _allKeysAreStrings = true; |
1409 | 1398 |
1410 bool get inDictionaryMode => !bailedOut && _allKeysAreStrings; | 1399 bool get inDictionaryMode => !bailedOut && _allKeysAreStrings; |
1411 | 1400 |
1412 MapTypeInformation(MemberTypeInformation context, | 1401 MapTypeInformation(MemberTypeInformation context, this.originalType, |
1413 this.originalType, | 1402 this.keyType, this.valueType) |
1414 this.keyType, | |
1415 this.valueType) | |
1416 : super(context) { | 1403 : super(context) { |
1417 keyType.addUser(this); | 1404 keyType.addUser(this); |
1418 valueType.addUser(this); | 1405 valueType.addUser(this); |
1419 type = originalType; | 1406 type = originalType; |
1420 } | 1407 } |
1421 | 1408 |
1422 TypeInformation addEntryAssignment(TypeInformation key, | 1409 TypeInformation addEntryAssignment(TypeInformation key, TypeInformation value, |
1423 TypeInformation value, | 1410 [bool nonNull = false]) { |
1424 [bool nonNull = false]) { | |
1425 TypeInformation newInfo = null; | 1411 TypeInformation newInfo = null; |
1426 if (_allKeysAreStrings && key is StringLiteralTypeInformation) { | 1412 if (_allKeysAreStrings && key is StringLiteralTypeInformation) { |
1427 String keyString = key.asString(); | 1413 String keyString = key.asString(); |
1428 typeInfoMap.putIfAbsent(keyString, () { | 1414 typeInfoMap.putIfAbsent(keyString, () { |
1429 newInfo = new ValueInMapTypeInformation(context, null, nonNull); | 1415 newInfo = new ValueInMapTypeInformation(context, null, nonNull); |
1430 return newInfo; | 1416 return newInfo; |
1431 }); | 1417 }); |
1432 typeInfoMap[keyString].addAssignment(value); | 1418 typeInfoMap[keyString].addAssignment(value); |
1433 } else { | 1419 } else { |
1434 _allKeysAreStrings = false; | 1420 _allKeysAreStrings = false; |
1435 typeInfoMap.clear(); | 1421 typeInfoMap.clear(); |
1436 } | 1422 } |
1437 keyType.addAssignment(key); | 1423 keyType.addAssignment(key); |
1438 valueType.addAssignment(value); | 1424 valueType.addAssignment(value); |
1439 if (newInfo != null) newInfo.addUser(this); | 1425 if (newInfo != null) newInfo.addUser(this); |
1440 | 1426 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1475 accept(TypeInformationVisitor visitor) { | 1461 accept(TypeInformationVisitor visitor) { |
1476 return visitor.visitMapTypeInformation(this); | 1462 return visitor.visitMapTypeInformation(this); |
1477 } | 1463 } |
1478 | 1464 |
1479 TypeMask toTypeMask(TypeGraphInferrerEngine inferrer) { | 1465 TypeMask toTypeMask(TypeGraphInferrerEngine inferrer) { |
1480 if (inDictionaryMode) { | 1466 if (inDictionaryMode) { |
1481 Map<String, TypeMask> mappings = new Map<String, TypeMask>(); | 1467 Map<String, TypeMask> mappings = new Map<String, TypeMask>(); |
1482 for (var key in typeInfoMap.keys) { | 1468 for (var key in typeInfoMap.keys) { |
1483 mappings[key] = typeInfoMap[key].type; | 1469 mappings[key] = typeInfoMap[key].type; |
1484 } | 1470 } |
1485 return new DictionaryTypeMask(originalType.forwardTo, | 1471 return new DictionaryTypeMask( |
1486 originalType.allocationNode, | 1472 originalType.forwardTo, |
1487 originalType.allocationElement, | 1473 originalType.allocationNode, |
1488 keyType.type, | 1474 originalType.allocationElement, |
1489 valueType.type, | 1475 keyType.type, |
1490 mappings); | 1476 valueType.type, |
| 1477 mappings); |
1491 } else { | 1478 } else { |
1492 return new MapTypeMask(originalType.forwardTo, | 1479 return new MapTypeMask( |
1493 originalType.allocationNode, | 1480 originalType.forwardTo, |
1494 originalType.allocationElement, | 1481 originalType.allocationNode, |
1495 keyType.type, | 1482 originalType.allocationElement, |
1496 valueType.type); | 1483 keyType.type, |
| 1484 valueType.type); |
1497 } | 1485 } |
1498 } | 1486 } |
1499 | 1487 |
1500 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1488 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1501 if (type.isDictionary != inDictionaryMode) { | 1489 if (type.isDictionary != inDictionaryMode) { |
1502 return toTypeMask(inferrer); | 1490 return toTypeMask(inferrer); |
1503 } else if (type.isDictionary) { | 1491 } else if (type.isDictionary) { |
1504 assert(inDictionaryMode); | 1492 assert(inDictionaryMode); |
1505 DictionaryTypeMask mask = type; | 1493 DictionaryTypeMask mask = type; |
1506 for (var key in typeInfoMap.keys) { | 1494 for (var key in typeInfoMap.keys) { |
1507 TypeInformation value = typeInfoMap[key]; | 1495 TypeInformation value = typeInfoMap[key]; |
1508 if (!mask.typeMap.containsKey(key) && | 1496 if (!mask.typeMap.containsKey(key) && |
1509 !value.type.containsAll(inferrer.classWorld) && | 1497 !value.type.containsAll(inferrer.classWorld) && |
1510 !value.type.isNullable) { | 1498 !value.type.isNullable) { |
1511 return toTypeMask(inferrer); | 1499 return toTypeMask(inferrer); |
1512 } | 1500 } |
1513 if (mask.typeMap[key] != typeInfoMap[key].type) { | 1501 if (mask.typeMap[key] != typeInfoMap[key].type) { |
1514 return toTypeMask(inferrer); | 1502 return toTypeMask(inferrer); |
1515 } | 1503 } |
1516 } | 1504 } |
1517 } else if (type.isMap) { | 1505 } else if (type.isMap) { |
1518 MapTypeMask mask = type; | 1506 MapTypeMask mask = type; |
1519 if (mask.keyType != keyType.type || | 1507 if (mask.keyType != keyType.type || mask.valueType != valueType.type) { |
1520 mask.valueType != valueType.type) { | |
1521 return toTypeMask(inferrer); | 1508 return toTypeMask(inferrer); |
1522 } | 1509 } |
1523 } else { | 1510 } else { |
1524 return toTypeMask(inferrer); | 1511 return toTypeMask(inferrer); |
1525 } | 1512 } |
1526 | 1513 |
1527 return type; | 1514 return type; |
1528 } | 1515 } |
1529 | 1516 |
1530 TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; | 1517 TypeMask safeType(TypeGraphInferrerEngine inferrer) => originalType; |
1531 | 1518 |
1532 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 1519 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
1533 return keyType.isStable && | 1520 return keyType.isStable && |
1534 valueType.isStable && | 1521 valueType.isStable && |
1535 super.hasStableType(inferrer); | 1522 super.hasStableType(inferrer); |
1536 } | 1523 } |
1537 | 1524 |
1538 void cleanup() { | 1525 void cleanup() { |
1539 super.cleanup(); | 1526 super.cleanup(); |
1540 keyType.cleanup(); | 1527 keyType.cleanup(); |
1541 valueType.cleanup(); | 1528 valueType.cleanup(); |
1542 for (TypeInformation info in typeInfoMap.values) { | 1529 for (TypeInformation info in typeInfoMap.values) { |
1543 info.cleanup(); | 1530 info.cleanup(); |
1544 } | 1531 } |
1545 _flowsInto = null; | 1532 _flowsInto = null; |
1546 } | 1533 } |
1547 | 1534 |
1548 String toString() { | 1535 String toString() { |
1549 return 'Map $type (K:$keyType, V:$valueType) contents $typeInfoMap'; | 1536 return 'Map $type (K:$keyType, V:$valueType) contents $typeInfoMap'; |
1550 } | 1537 } |
1551 } | 1538 } |
1552 | 1539 |
1553 /** | 1540 /** |
1554 * A [KeyInMapTypeInformation] holds the common type | 1541 * A [KeyInMapTypeInformation] holds the common type |
1555 * for the keys in a [MapTypeInformation] | 1542 * for the keys in a [MapTypeInformation] |
1556 */ | 1543 */ |
1557 class KeyInMapTypeInformation extends InferredTypeInformation { | 1544 class KeyInMapTypeInformation extends InferredTypeInformation { |
1558 KeyInMapTypeInformation(MemberTypeInformation context, | 1545 KeyInMapTypeInformation( |
1559 TypeInformation keyType) | 1546 MemberTypeInformation context, TypeInformation keyType) |
1560 : super(context, keyType); | 1547 : super(context, keyType); |
1561 | 1548 |
1562 accept(TypeInformationVisitor visitor) { | 1549 accept(TypeInformationVisitor visitor) { |
1563 return visitor.visitKeyInMapTypeInformation(this); | 1550 return visitor.visitKeyInMapTypeInformation(this); |
1564 } | 1551 } |
1565 | 1552 |
1566 String toString() => 'Key in Map $type'; | 1553 String toString() => 'Key in Map $type'; |
1567 } | 1554 } |
1568 | 1555 |
1569 /** | 1556 /** |
1570 * A [ValueInMapTypeInformation] holds the common type | 1557 * A [ValueInMapTypeInformation] holds the common type |
1571 * for the values in a [MapTypeInformation] | 1558 * for the values in a [MapTypeInformation] |
1572 */ | 1559 */ |
1573 class ValueInMapTypeInformation extends InferredTypeInformation { | 1560 class ValueInMapTypeInformation extends InferredTypeInformation { |
1574 // [nonNull] is set to true if this value is known to be part of the map. | 1561 // [nonNull] is set to true if this value is known to be part of the map. |
1575 // Note that only values assigned to a specific key value in dictionary | 1562 // Note that only values assigned to a specific key value in dictionary |
1576 // mode can ever be marked as [nonNull]. | 1563 // mode can ever be marked as [nonNull]. |
1577 final bool nonNull; | 1564 final bool nonNull; |
1578 | 1565 |
1579 ValueInMapTypeInformation(MemberTypeInformation context, | 1566 ValueInMapTypeInformation( |
1580 TypeInformation valueType, [this.nonNull = false]) | 1567 MemberTypeInformation context, TypeInformation valueType, |
| 1568 [this.nonNull = false]) |
1581 : super(context, valueType); | 1569 : super(context, valueType); |
1582 | 1570 |
1583 accept(TypeInformationVisitor visitor) { | 1571 accept(TypeInformationVisitor visitor) { |
1584 return visitor.visitValueInMapTypeInformation(this); | 1572 return visitor.visitValueInMapTypeInformation(this); |
1585 } | 1573 } |
1586 | 1574 |
1587 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1575 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1588 return nonNull ? super.computeType(inferrer) | 1576 return nonNull |
1589 : super.computeType(inferrer).nullable(); | 1577 ? super.computeType(inferrer) |
| 1578 : super.computeType(inferrer).nullable(); |
1590 } | 1579 } |
1591 | 1580 |
1592 String toString() => 'Value in Map $type'; | 1581 String toString() => 'Value in Map $type'; |
1593 } | 1582 } |
1594 | 1583 |
1595 /** | 1584 /** |
1596 * A [PhiElementTypeInformation] is an union of | 1585 * A [PhiElementTypeInformation] is an union of |
1597 * [ElementTypeInformation], that is local to a method. | 1586 * [ElementTypeInformation], that is local to a method. |
1598 */ | 1587 */ |
1599 class PhiElementTypeInformation extends TypeInformation { | 1588 class PhiElementTypeInformation extends TypeInformation { |
1600 final ast.Node branchNode; | 1589 final ast.Node branchNode; |
1601 final bool isLoopPhi; | 1590 final bool isLoopPhi; |
1602 final Local variable; | 1591 final Local variable; |
1603 | 1592 |
1604 PhiElementTypeInformation(MemberTypeInformation context, this.branchNode, | 1593 PhiElementTypeInformation(MemberTypeInformation context, this.branchNode, |
1605 this.isLoopPhi, this.variable) | 1594 this.isLoopPhi, this.variable) |
1606 : super(context); | 1595 : super(context); |
1607 | 1596 |
1608 TypeMask computeType(TypeGraphInferrerEngine inferrer) { | 1597 TypeMask computeType(TypeGraphInferrerEngine inferrer) { |
1609 return inferrer.types.computeTypeMask(assignments); | 1598 return inferrer.types.computeTypeMask(assignments); |
1610 } | 1599 } |
1611 | 1600 |
1612 String toString() => 'Phi $variable $type'; | 1601 String toString() => 'Phi $variable $type'; |
1613 | 1602 |
1614 accept(TypeInformationVisitor visitor) { | 1603 accept(TypeInformationVisitor visitor) { |
1615 return visitor.visitPhiElementTypeInformation(this); | 1604 return visitor.visitPhiElementTypeInformation(this); |
1616 } | 1605 } |
1617 } | 1606 } |
1618 | 1607 |
1619 class ClosureTypeInformation extends TypeInformation | 1608 class ClosureTypeInformation extends TypeInformation |
1620 with ApplyableTypeInformation { | 1609 with ApplyableTypeInformation { |
1621 final ast.Node node; | 1610 final ast.Node node; |
1622 final Element element; | 1611 final Element element; |
1623 | 1612 |
1624 ClosureTypeInformation(MemberTypeInformation context, this.node, | 1613 ClosureTypeInformation(MemberTypeInformation context, this.node, this.element) |
1625 this.element) | |
1626 : super(context); | 1614 : super(context); |
1627 | 1615 |
1628 TypeMask computeType(TypeGraphInferrerEngine inferrer) => safeType(inferrer); | 1616 TypeMask computeType(TypeGraphInferrerEngine inferrer) => safeType(inferrer); |
1629 | 1617 |
1630 TypeMask safeType(TypeGraphInferrerEngine inferrer) { | 1618 TypeMask safeType(TypeGraphInferrerEngine inferrer) { |
1631 return inferrer.types.functionType.type; | 1619 return inferrer.types.functionType.type; |
1632 } | 1620 } |
1633 | 1621 |
1634 String toString() => 'Closure $element'; | 1622 String toString() => 'Closure $element'; |
1635 | 1623 |
1636 accept(TypeInformationVisitor visitor) { | 1624 accept(TypeInformationVisitor visitor) { |
1637 return visitor.visitClosureTypeInformation(this); | 1625 return visitor.visitClosureTypeInformation(this); |
1638 } | 1626 } |
1639 | 1627 |
1640 bool hasStableType(TypeGraphInferrerEngine inferrer) { | 1628 bool hasStableType(TypeGraphInferrerEngine inferrer) { |
1641 return false; | 1629 return false; |
1642 } | 1630 } |
1643 } | 1631 } |
1644 | 1632 |
1645 /** | 1633 /** |
1646 * Mixin for [TypeInformation] nodes that can bail out during tracing. | 1634 * Mixin for [TypeInformation] nodes that can bail out during tracing. |
1647 */ | 1635 */ |
1648 abstract class TracedTypeInformation implements TypeInformation { | 1636 abstract class TracedTypeInformation implements TypeInformation { |
1649 /// Set to false once analysis has succeeded. | 1637 /// Set to false once analysis has succeeded. |
1650 bool bailedOut = true; | 1638 bool bailedOut = true; |
| 1639 |
1651 /// Set to true once analysis is completed. | 1640 /// Set to true once analysis is completed. |
1652 bool analyzed = false; | 1641 bool analyzed = false; |
1653 | 1642 |
1654 Set<TypeInformation> _flowsInto; | 1643 Set<TypeInformation> _flowsInto; |
1655 | 1644 |
1656 /** | 1645 /** |
1657 * The set of [TypeInformation] nodes where values from the traced node could | 1646 * The set of [TypeInformation] nodes where values from the traced node could |
1658 * flow in. | 1647 * flow in. |
1659 */ | 1648 */ |
1660 Set<TypeInformation> get flowsInto { | 1649 Set<TypeInformation> get flowsInto { |
1661 return (_flowsInto == null) ? const ImmutableEmptySet<TypeInformation>() | 1650 return (_flowsInto == null) |
1662 : _flowsInto; | 1651 ? const ImmutableEmptySet<TypeInformation>() |
| 1652 : _flowsInto; |
1663 } | 1653 } |
1664 | 1654 |
1665 /** | 1655 /** |
1666 * Adds [nodes] to the sets of values this [TracedTypeInformation] flows into. | 1656 * Adds [nodes] to the sets of values this [TracedTypeInformation] flows into. |
1667 */ | 1657 */ |
1668 void addFlowsIntoTargets(Iterable<TypeInformation> nodes) { | 1658 void addFlowsIntoTargets(Iterable<TypeInformation> nodes) { |
1669 if (_flowsInto == null) { | 1659 if (_flowsInto == null) { |
1670 _flowsInto = nodes.toSet(); | 1660 _flowsInto = nodes.toSet(); |
1671 } else { | 1661 } else { |
1672 _flowsInto.addAll(nodes); | 1662 _flowsInto.addAll(nodes); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1724 } else if (annotation.isVoid) { | 1714 } else if (annotation.isVoid) { |
1725 otherType = compiler.typesTask.nullType; | 1715 otherType = compiler.typesTask.nullType; |
1726 } else { | 1716 } else { |
1727 assert(annotation.isInterfaceType); | 1717 assert(annotation.isInterfaceType); |
1728 otherType = new TypeMask.nonNullSubtype(annotation.element, compiler.world); | 1718 otherType = new TypeMask.nonNullSubtype(annotation.element, compiler.world); |
1729 } | 1719 } |
1730 if (isNullable) otherType = otherType.nullable(); | 1720 if (isNullable) otherType = otherType.nullable(); |
1731 if (type == null) return otherType; | 1721 if (type == null) return otherType; |
1732 return type.intersection(otherType, compiler.world); | 1722 return type.intersection(otherType, compiler.world); |
1733 } | 1723 } |
OLD | NEW |