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 inferrer_visitor; | 5 library inferrer_visitor; |
6 | 6 |
7 import 'dart:collection' show IterableMixin; | 7 import 'dart:collection' show IterableMixin; |
8 | 8 |
9 import '../common.dart'; | 9 import '../common.dart'; |
| 10 import '../options.dart' show CompilerOptions; |
10 import '../compiler.dart' show Compiler; | 11 import '../compiler.dart' show Compiler; |
11 import '../constants/constant_system.dart'; | 12 import '../constants/constant_system.dart'; |
12 import '../constants/expressions.dart'; | 13 import '../constants/expressions.dart'; |
13 import '../dart_types.dart'; | 14 import '../dart_types.dart'; |
14 import '../elements/elements.dart'; | 15 import '../elements/elements.dart'; |
15 import '../resolution/operators.dart'; | 16 import '../resolution/operators.dart'; |
16 import '../resolution/semantic_visitor.dart'; | 17 import '../resolution/semantic_visitor.dart'; |
17 import '../resolution/tree_elements.dart' show TreeElements; | 18 import '../resolution/tree_elements.dart' show TreeElements; |
18 import '../tree/tree.dart'; | 19 import '../tree/tree.dart'; |
19 import '../types/constants.dart' show computeTypeMask; | 20 import '../types/constants.dart' show computeTypeMask; |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 | 365 |
365 /** | 366 /** |
366 * Records that the captured variable [local] is read. | 367 * Records that the captured variable [local] is read. |
367 */ | 368 */ |
368 void recordCapturedLocalRead(Local local); | 369 void recordCapturedLocalRead(Local local); |
369 | 370 |
370 /** | 371 /** |
371 * Records that the variable [local] is being updated. | 372 * Records that the variable [local] is being updated. |
372 */ | 373 */ |
373 void recordLocalUpdate(Local local, T type); | 374 void recordLocalUpdate(Local local, T type); |
| 375 |
| 376 /// The [ClosedWorld] on which inference reasoning is based. |
| 377 ClosedWorld get closedWorld; |
374 } | 378 } |
375 | 379 |
376 /** | 380 /** |
377 * Placeholder for inferred types of local variables. | 381 * Placeholder for inferred types of local variables. |
378 */ | 382 */ |
379 class LocalsHandler<T> { | 383 class LocalsHandler<T> { |
380 final Compiler compiler; | 384 final CompilerOptions options; |
381 final TypeSystem<T> types; | 385 final TypeSystem<T> types; |
382 final MinimalInferrerEngine<T> inferrer; | 386 final MinimalInferrerEngine<T> inferrer; |
383 final VariableScope<T> locals; | 387 final VariableScope<T> locals; |
384 final Map<Local, Element> captured; | 388 final Map<Local, Element> captured; |
385 final Map<Local, Element> capturedAndBoxed; | 389 final Map<Local, Element> capturedAndBoxed; |
386 final FieldInitializationScope<T> fieldScope; | 390 final FieldInitializationScope<T> fieldScope; |
387 LocalsHandler<T> tryBlock; | 391 LocalsHandler<T> tryBlock; |
388 bool seenReturnOrThrow = false; | 392 bool seenReturnOrThrow = false; |
389 bool seenBreakOrContinue = false; | 393 bool seenBreakOrContinue = false; |
390 | 394 |
391 bool get aborts { | 395 bool get aborts { |
392 return seenReturnOrThrow || seenBreakOrContinue; | 396 return seenReturnOrThrow || seenBreakOrContinue; |
393 } | 397 } |
394 | 398 |
395 bool get inTryBlock => tryBlock != null; | 399 bool get inTryBlock => tryBlock != null; |
396 | 400 |
397 LocalsHandler(this.inferrer, this.types, this.compiler, Node block, | 401 LocalsHandler(this.inferrer, this.types, this.options, Node block, |
398 [this.fieldScope]) | 402 [this.fieldScope]) |
399 : locals = new VariableScope<T>(block), | 403 : locals = new VariableScope<T>(block), |
400 captured = new Map<Local, Element>(), | 404 captured = new Map<Local, Element>(), |
401 capturedAndBoxed = new Map<Local, Element>(), | 405 capturedAndBoxed = new Map<Local, Element>(), |
402 tryBlock = null; | 406 tryBlock = null; |
403 | 407 |
404 LocalsHandler.from(LocalsHandler<T> other, Node block, | 408 LocalsHandler.from(LocalsHandler<T> other, Node block, |
405 {bool useOtherTryBlock: true}) | 409 {bool useOtherTryBlock: true}) |
406 : locals = new VariableScope<T>(block, other.locals), | 410 : locals = new VariableScope<T>(block, other.locals), |
407 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), | 411 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), |
408 captured = other.captured, | 412 captured = other.captured, |
409 capturedAndBoxed = other.capturedAndBoxed, | 413 capturedAndBoxed = other.capturedAndBoxed, |
410 types = other.types, | 414 types = other.types, |
411 inferrer = other.inferrer, | 415 inferrer = other.inferrer, |
412 compiler = other.compiler { | 416 options = other.options { |
413 tryBlock = useOtherTryBlock ? other.tryBlock : this; | 417 tryBlock = useOtherTryBlock ? other.tryBlock : this; |
414 } | 418 } |
415 | 419 |
416 LocalsHandler.deepCopyOf(LocalsHandler<T> other) | 420 LocalsHandler.deepCopyOf(LocalsHandler<T> other) |
417 : locals = new VariableScope<T>.deepCopyOf(other.locals), | 421 : locals = new VariableScope<T>.deepCopyOf(other.locals), |
418 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), | 422 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), |
419 captured = other.captured, | 423 captured = other.captured, |
420 capturedAndBoxed = other.capturedAndBoxed, | 424 capturedAndBoxed = other.capturedAndBoxed, |
421 tryBlock = other.tryBlock, | 425 tryBlock = other.tryBlock, |
422 types = other.types, | 426 types = other.types, |
423 inferrer = other.inferrer, | 427 inferrer = other.inferrer, |
424 compiler = other.compiler; | 428 options = other.options; |
425 | 429 |
426 LocalsHandler.topLevelCopyOf(LocalsHandler<T> other) | 430 LocalsHandler.topLevelCopyOf(LocalsHandler<T> other) |
427 : locals = new VariableScope<T>.topLevelCopyOf(other.locals), | 431 : locals = new VariableScope<T>.topLevelCopyOf(other.locals), |
428 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), | 432 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), |
429 captured = other.captured, | 433 captured = other.captured, |
430 capturedAndBoxed = other.capturedAndBoxed, | 434 capturedAndBoxed = other.capturedAndBoxed, |
431 tryBlock = other.tryBlock, | 435 tryBlock = other.tryBlock, |
432 types = other.types, | 436 types = other.types, |
433 inferrer = other.inferrer, | 437 inferrer = other.inferrer, |
434 compiler = other.compiler; | 438 options = other.options; |
435 | 439 |
436 T use(Local local) { | 440 T use(Local local) { |
437 if (capturedAndBoxed.containsKey(local)) { | 441 if (capturedAndBoxed.containsKey(local)) { |
438 return inferrer.typeOfElement(capturedAndBoxed[local]); | 442 return inferrer.typeOfElement(capturedAndBoxed[local]); |
439 } else { | 443 } else { |
440 if (captured.containsKey(local)) { | 444 if (captured.containsKey(local)) { |
441 inferrer.recordCapturedLocalRead(local); | 445 inferrer.recordCapturedLocalRead(local); |
442 } | 446 } |
443 return locals[local]; | 447 return locals[local]; |
444 } | 448 } |
445 } | 449 } |
446 | 450 |
447 void update(LocalElement local, T type, Node node) { | 451 void update(LocalElement local, T type, Node node) { |
448 assert(type != null); | 452 assert(type != null); |
449 if (compiler.options.trustTypeAnnotations || | 453 if (options.trustTypeAnnotations || options.enableTypeAssertions) { |
450 compiler.options.enableTypeAssertions) { | |
451 type = types.narrowType(type, local.type); | 454 type = types.narrowType(type, local.type); |
452 } | 455 } |
453 updateLocal() { | 456 updateLocal() { |
454 T currentType = locals[local]; | 457 T currentType = locals[local]; |
455 | 458 |
456 SendSet send = node != null ? node.asSendSet() : null; | 459 SendSet send = node != null ? node.asSendSet() : null; |
457 if (send != null && send.isIfNullAssignment && currentType != null) { | 460 if (send != null && send.isIfNullAssignment && currentType != null) { |
458 // If-null assignments may return either the new or the original value | 461 // If-null assignments may return either the new or the original value |
459 // narrowed to non-null. | 462 // narrowed to non-null. |
460 type = types.addPhiInput( | 463 type = types.addPhiInput( |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 this.locals = handler { | 742 this.locals = handler { |
740 if (handler != null) return; | 743 if (handler != null) return; |
741 Node node; | 744 Node node; |
742 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | 745 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
743 node = resolvedAst.node; | 746 node = resolvedAst.node; |
744 } | 747 } |
745 FieldInitializationScope<T> fieldScope = | 748 FieldInitializationScope<T> fieldScope = |
746 analyzedElement.isGenerativeConstructor | 749 analyzedElement.isGenerativeConstructor |
747 ? new FieldInitializationScope<T>(types) | 750 ? new FieldInitializationScope<T>(types) |
748 : null; | 751 : null; |
749 locals = new LocalsHandler<T>(inferrer, types, compiler, node, fieldScope); | 752 locals = new LocalsHandler<T>( |
| 753 inferrer, types, compiler.options, node, fieldScope); |
750 } | 754 } |
751 | 755 |
752 DiagnosticReporter get reporter => compiler.reporter; | 756 DiagnosticReporter get reporter => compiler.reporter; |
753 | 757 |
754 ClosedWorld get closedWorld => compiler.closedWorld; | 758 ClosedWorld get closedWorld => inferrer.closedWorld; |
755 | 759 |
756 @override | 760 @override |
757 SemanticSendVisitor get sendVisitor => this; | 761 SemanticSendVisitor get sendVisitor => this; |
758 | 762 |
759 @override | 763 @override |
760 T apply(Node node, _) => visit(node); | 764 T apply(Node node, _) => visit(node); |
761 | 765 |
762 T handleSendSet(SendSet node); | 766 T handleSendSet(SendSet node); |
763 | 767 |
764 T handleDynamicInvoke(Send node); | 768 T handleDynamicInvoke(Send node); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
880 } | 884 } |
881 | 885 |
882 T visitLiteralNull(LiteralNull node) { | 886 T visitLiteralNull(LiteralNull node) { |
883 return types.nullType; | 887 return types.nullType; |
884 } | 888 } |
885 | 889 |
886 T visitLiteralSymbol(LiteralSymbol node) { | 890 T visitLiteralSymbol(LiteralSymbol node) { |
887 // TODO(kasperl): We should be able to tell that the type of a literal | 891 // TODO(kasperl): We should be able to tell that the type of a literal |
888 // symbol is always a non-null exact symbol implementation -- not just | 892 // symbol is always a non-null exact symbol implementation -- not just |
889 // any non-null subtype of the symbol interface. | 893 // any non-null subtype of the symbol interface. |
890 return types.nonNullSubtype(compiler.coreClasses.symbolClass); | 894 return types.nonNullSubtype(closedWorld.coreClasses.symbolClass); |
891 } | 895 } |
892 | 896 |
893 @override | 897 @override |
894 void previsitDeferredAccess(Send node, PrefixElement prefix, _) { | 898 void previsitDeferredAccess(Send node, PrefixElement prefix, _) { |
895 // Deferred access does not affect inference. | 899 // Deferred access does not affect inference. |
896 } | 900 } |
897 | 901 |
898 T handleTypeLiteralGet() { | 902 T handleTypeLiteralGet() { |
899 return types.typeType; | 903 return types.typeType; |
900 } | 904 } |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1031 (operator == '!=' && !usePositive)) { | 1035 (operator == '!=' && !usePositive)) { |
1032 // Type the elements as null. | 1036 // Type the elements as null. |
1033 if (Elements.isLocal(receiverElement)) { | 1037 if (Elements.isLocal(receiverElement)) { |
1034 locals.update(receiverElement, types.nullType, node); | 1038 locals.update(receiverElement, types.nullType, node); |
1035 } | 1039 } |
1036 if (Elements.isLocal(argumentElement)) { | 1040 if (Elements.isLocal(argumentElement)) { |
1037 locals.update(argumentElement, types.nullType, node); | 1041 locals.update(argumentElement, types.nullType, node); |
1038 } | 1042 } |
1039 } else { | 1043 } else { |
1040 // Narrow the elements to a non-null type. | 1044 // Narrow the elements to a non-null type. |
1041 DartType objectType = compiler.coreTypes.objectType; | 1045 DartType objectType = closedWorld.coreTypes.objectType; |
1042 if (Elements.isLocal(receiverElement)) { | 1046 if (Elements.isLocal(receiverElement)) { |
1043 narrow(receiverElement, objectType, node); | 1047 narrow(receiverElement, objectType, node); |
1044 } | 1048 } |
1045 if (Elements.isLocal(argumentElement)) { | 1049 if (Elements.isLocal(argumentElement)) { |
1046 narrow(argumentElement, objectType, node); | 1050 narrow(argumentElement, objectType, node); |
1047 } | 1051 } |
1048 } | 1052 } |
1049 } | 1053 } |
1050 } | 1054 } |
1051 } | 1055 } |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 return type; | 1495 return type; |
1492 } | 1496 } |
1493 | 1497 |
1494 T visitCascade(Cascade node) { | 1498 T visitCascade(Cascade node) { |
1495 // Ignore the result of the cascade send and return the type of the cascade | 1499 // Ignore the result of the cascade send and return the type of the cascade |
1496 // receiver. | 1500 // receiver. |
1497 visit(node.expression); | 1501 visit(node.expression); |
1498 return cascadeReceiverStack.removeLast(); | 1502 return cascadeReceiverStack.removeLast(); |
1499 } | 1503 } |
1500 } | 1504 } |
OLD | NEW |