| 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 |