| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// Tests for type inference. | 5 /// Tests for type inference. |
| 6 library dev_compiler.test.inferred_type_test; | 6 library dev_compiler.test.inferred_type_test; |
| 7 | 7 |
| 8 import 'package:unittest/unittest.dart'; | 8 import 'package:unittest/unittest.dart'; |
| 9 | 9 |
| 10 import 'package:dev_compiler/src/testing.dart'; | 10 import 'package:dev_compiler/src/testing.dart'; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 } | 34 } |
| 35 ''' | 35 ''' |
| 36 }); | 36 }); |
| 37 }); | 37 }); |
| 38 | 38 |
| 39 // Error when declared type is `int` and assigned null. | 39 // Error when declared type is `int` and assigned null. |
| 40 testChecker({ | 40 testChecker({ |
| 41 '/main.dart': ''' | 41 '/main.dart': ''' |
| 42 test1() { | 42 test1() { |
| 43 int x = 3; | 43 int x = 3; |
| 44 x = /*warning:DownCastLiteral*/null; | 44 x = /*severe:StaticTypeError*/null; |
| 45 } | 45 } |
| 46 ''' | 46 ''' |
| 47 }, nonnullableTypes: <String>['int', 'double']); | 47 }, nonnullableTypes: <String>['int', 'double']); |
| 48 | 48 |
| 49 // Error when inferred type is `int` and assigned null. | 49 // Error when inferred type is `int` and assigned null. |
| 50 testChecker({ | 50 testChecker({ |
| 51 '/main.dart': ''' | 51 '/main.dart': ''' |
| 52 test1() { | 52 test1() { |
| 53 var x = 3; | 53 var x = 3; |
| 54 x = /*warning:DownCastLiteral*/null; | 54 x = /*severe:StaticTypeError*/null; |
| 55 } | 55 } |
| 56 ''' | 56 ''' |
| 57 }, nonnullableTypes: <String>['int', 'double']); | 57 }, nonnullableTypes: <String>['int', 'double']); |
| 58 | 58 |
| 59 // No error when declared type is `num` and assigned null. | 59 // No error when declared type is `num` and assigned null. |
| 60 testChecker({ | 60 testChecker({ |
| 61 '/main.dart': ''' | 61 '/main.dart': ''' |
| 62 test1() { | 62 test1() { |
| 63 num x = 3; | 63 num x = 3; |
| 64 x = null; | 64 x = null; |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 import 'main.dart'; | 260 import 'main.dart'; |
| 261 var x = 2; // ok to infer | 261 var x = 2; // ok to infer |
| 262 ''', | 262 ''', |
| 263 '/main.dart': ''' | 263 '/main.dart': ''' |
| 264 import 'a.dart'; | 264 import 'a.dart'; |
| 265 var y = x; // not ok to infer yet | 265 var y = x; // not ok to infer yet |
| 266 | 266 |
| 267 test1() { | 267 test1() { |
| 268 int t = 3; | 268 int t = 3; |
| 269 t = x; | 269 t = x; |
| 270 t = /*info:DownCast*/y; | 270 t = /*info:DynamicCast*/y; |
| 271 } | 271 } |
| 272 ''' | 272 ''' |
| 273 }, inferTransitively: false); | 273 }, inferTransitively: false); |
| 274 | 274 |
| 275 testChecker({ | 275 testChecker({ |
| 276 '/a.dart': ''' | 276 '/a.dart': ''' |
| 277 import 'main.dart'; | 277 import 'main.dart'; |
| 278 class A { static var x = 2; } | 278 class A { static var x = 2; } |
| 279 ''', | 279 ''', |
| 280 '/main.dart': ''' | 280 '/main.dart': ''' |
| 281 import 'a.dart'; | 281 import 'a.dart'; |
| 282 class B { static var y = A.x; } | 282 class B { static var y = A.x; } |
| 283 | 283 |
| 284 test1() { | 284 test1() { |
| 285 int t = 3; | 285 int t = 3; |
| 286 t = A.x; | 286 t = A.x; |
| 287 t = /*info:DownCast*/B.y; | 287 t = /*info:DynamicCast*/B.y; |
| 288 } | 288 } |
| 289 ''' | 289 ''' |
| 290 }, inferTransitively: false); | 290 }, inferTransitively: false); |
| 291 }); | 291 }); |
| 292 | 292 |
| 293 test('infer from variables in cycle libs when flag is on', () { | 293 test('infer from variables in cycle libs when flag is on', () { |
| 294 testChecker({ | 294 testChecker({ |
| 295 '/a.dart': ''' | 295 '/a.dart': ''' |
| 296 import 'main.dart'; | 296 import 'main.dart'; |
| 297 var x = 2; // ok to infer | 297 var x = 2; // ok to infer |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 static final b1 = 1; | 340 static final b1 = 1; |
| 341 final b2 = 1; | 341 final b2 = 1; |
| 342 } | 342 } |
| 343 ''', | 343 ''', |
| 344 '/main.dart': ''' | 344 '/main.dart': ''' |
| 345 import "a.dart"; | 345 import "a.dart"; |
| 346 | 346 |
| 347 test1() { | 347 test1() { |
| 348 int x = 0; | 348 int x = 0; |
| 349 // inference in A disabled (flag is off) | 349 // inference in A disabled (flag is off) |
| 350 x = /*info:DownCast*/A.a1; | 350 x = /*info:DynamicCast*/A.a1; |
| 351 x = /*info:DownCast*/new A().a2; | 351 x = /*info:DynamicCast*/new A().a2; |
| 352 } | 352 } |
| 353 ''' | 353 ''' |
| 354 }, inferTransitively: false); | 354 }, inferTransitively: false); |
| 355 }); | 355 }); |
| 356 | 356 |
| 357 test('can infer also from static and instance fields (flag on)', () { | 357 test('can infer also from static and instance fields (flag on)', () { |
| 358 testChecker({ | 358 testChecker({ |
| 359 '/a.dart': ''' | 359 '/a.dart': ''' |
| 360 import 'b.dart'; | 360 import 'b.dart'; |
| 361 class A { | 361 class A { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 x = A.a1; | 445 x = A.a1; |
| 446 x = new A().a2; | 446 x = new A().a2; |
| 447 | 447 |
| 448 // Within a cycle we allow inference when the RHS is well known, but | 448 // Within a cycle we allow inference when the RHS is well known, but |
| 449 // not when it depends on other fields within the cycle | 449 // not when it depends on other fields within the cycle |
| 450 x = C.c1; | 450 x = C.c1; |
| 451 x = D.d1; | 451 x = D.d1; |
| 452 x = D.d2; | 452 x = D.d2; |
| 453 x = new C().c2; | 453 x = new C().c2; |
| 454 x = new D().d3; | 454 x = new D().d3; |
| 455 x = /*info:DownCast*/new D().d4; | 455 x = /*info:DynamicCast*/new D().d4; |
| 456 | 456 |
| 457 | 457 |
| 458 // Similarly if the library contains parts. | 458 // Similarly if the library contains parts. |
| 459 x = E.e1; | 459 x = E.e1; |
| 460 x = E.e2; | 460 x = E.e2; |
| 461 x = E.e3; | 461 x = E.e3; |
| 462 x = new E().e4; | 462 x = new E().e4; |
| 463 x = /*info:DownCast*/new E().e5; | 463 x = /*info:DynamicCast*/new E().e5; |
| 464 x = new E().e6; | 464 x = new E().e6; |
| 465 x = F.f1; | 465 x = F.f1; |
| 466 x = new F().f2; | 466 x = new F().f2; |
| 467 } | 467 } |
| 468 ''' | 468 ''' |
| 469 }, inferTransitively: true); | 469 }, inferTransitively: true); |
| 470 }); | 470 }); |
| 471 | 471 |
| 472 test('infer from complex expressions if the outer-most value is precise', () { | 472 test('infer from complex expressions if the outer-most value is precise', () { |
| 473 testChecker({ | 473 testChecker({ |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 final t1 = new A(); | 532 final t1 = new A(); |
| 533 final t2 = new A().x; | 533 final t2 = new A().x; |
| 534 final t3 = new B(); | 534 final t3 = new B(); |
| 535 final t4 = new B().y; | 535 final t4 = new B().y; |
| 536 | 536 |
| 537 test1() { | 537 test1() { |
| 538 int i = 0; | 538 int i = 0; |
| 539 A a; | 539 A a; |
| 540 B b; | 540 B b; |
| 541 a = t1; | 541 a = t1; |
| 542 i = /*info:DownCast*/t2; | 542 i = /*info:DynamicCast*/t2; |
| 543 b = t3; | 543 b = t3; |
| 544 i = /*info:DownCast*/t4; | 544 i = /*info:DynamicCast*/t4; |
| 545 i = new B().y; // B.y was inferred though | 545 i = new B().y; // B.y was inferred though |
| 546 } | 546 } |
| 547 ''' | 547 ''' |
| 548 }, inferTransitively: false); | 548 }, inferTransitively: false); |
| 549 | 549 |
| 550 // but flags can enable this behavior. | 550 // but flags can enable this behavior. |
| 551 testChecker({ | 551 testChecker({ |
| 552 '/a.dart': ''' | 552 '/a.dart': ''' |
| 553 class A { | 553 class A { |
| 554 var x = 3; | 554 var x = 3; |
| 555 } | 555 } |
| 556 ''', | 556 ''', |
| 557 '/main.dart': ''' | 557 '/main.dart': ''' |
| 558 import 'a.dart'; | 558 import 'a.dart'; |
| 559 class B { | 559 class B { |
| 560 var y = 3; | 560 var y = 3; |
| 561 } | 561 } |
| 562 final t1 = new A(); | 562 final t1 = new A(); |
| 563 final t2 = new A().x; | 563 final t2 = new A().x; |
| 564 final t3 = new B(); | 564 final t3 = new B(); |
| 565 final t4 = new B().y; | 565 final t4 = new B().y; |
| 566 | 566 |
| 567 test1() { | 567 test1() { |
| 568 int i = 0; | 568 int i = 0; |
| 569 A a; | 569 A a; |
| 570 B b; | 570 B b; |
| 571 a = t1; | 571 a = t1; |
| 572 i = t2; | 572 i = t2; |
| 573 b = t3; | 573 b = t3; |
| 574 i = /*info:DownCast*/t4; | 574 i = /*info:DynamicCast*/t4; |
| 575 i = new B().y; // B.y was inferred though | 575 i = new B().y; // B.y was inferred though |
| 576 } | 576 } |
| 577 ''' | 577 ''' |
| 578 }, inferTransitively: true); | 578 }, inferTransitively: true); |
| 579 }); | 579 }); |
| 580 | 580 |
| 581 test('infer types on loop indices', () { | 581 test('infer types on loop indices', () { |
| 582 // foreach loop | 582 // foreach loop |
| 583 testChecker({ | 583 testChecker({ |
| 584 '/main.dart': ''' | 584 '/main.dart': ''' |
| 585 class Foo { | 585 class Foo { |
| 586 int bar = 42; | 586 int bar = 42; |
| 587 } | 587 } |
| 588 | 588 |
| 589 test() { | 589 test() { |
| 590 var l = List<Foo>(); | 590 var l = List<Foo>(); |
| 591 for (var x in list) { | 591 for (var x in list) { |
| 592 String y = /*info:DownCast should be severe:StaticTypeError*/x; | 592 String y = /*info:DynamicCast should be severe:StaticTypeError*/x; |
| 593 } | 593 } |
| 594 } | 594 } |
| 595 ''' | 595 ''' |
| 596 }); | 596 }); |
| 597 | 597 |
| 598 // for loop, with inference | 598 // for loop, with inference |
| 599 testChecker({ | 599 testChecker({ |
| 600 '/main.dart': ''' | 600 '/main.dart': ''' |
| 601 test() { | 601 test() { |
| 602 for (var i = 0; i < 10; i++) { | 602 for (var i = 0; i < 10; i++) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 625 | 625 |
| 626 // Same code with dynamic yields warnings | 626 // Same code with dynamic yields warnings |
| 627 testChecker({ | 627 testChecker({ |
| 628 '/main.dart': ''' | 628 '/main.dart': ''' |
| 629 class A { | 629 class A { |
| 630 int x = 2; | 630 int x = 2; |
| 631 } | 631 } |
| 632 | 632 |
| 633 test() { | 633 test() { |
| 634 dynamic a = new A(); | 634 dynamic a = new A(); |
| 635 A b = /*info:DownCast*/a; | 635 A b = /*info:DynamicCast*/a; |
| 636 print(/*warning:DynamicInvoke*/a.x); | 636 print(/*warning:DynamicInvoke*/a.x); |
| 637 print((/*warning:DynamicInvoke*/a.x) + 2); | 637 print((/*warning:DynamicInvoke*/a.x) + 2); |
| 638 } | 638 } |
| 639 ''' | 639 ''' |
| 640 }); | 640 }); |
| 641 }); | 641 }); |
| 642 | 642 |
| 643 test('propagate inference transitively ', () { | 643 test('propagate inference transitively ', () { |
| 644 testChecker({ | 644 testChecker({ |
| 645 '/main.dart': ''' | 645 '/main.dart': ''' |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 '/main.dart': ''' | 691 '/main.dart': ''' |
| 692 class A { | 692 class A { |
| 693 int x = 2; | 693 int x = 2; |
| 694 } | 694 } |
| 695 | 695 |
| 696 class B extends A { | 696 class B extends A { |
| 697 /*severe:InferableOverride*/get x => 3; | 697 /*severe:InferableOverride*/get x => 3; |
| 698 } | 698 } |
| 699 | 699 |
| 700 foo() { | 700 foo() { |
| 701 String y = /*info:DownCast*/new B().x; | 701 String y = /*info:DynamicCast*/new B().x; |
| 702 int z = /*info:DownCast*/new B().x; | 702 int z = /*info:DynamicCast*/new B().x; |
| 703 } | 703 } |
| 704 ''' | 704 ''' |
| 705 }, inferFromOverrides: false); | 705 }, inferFromOverrides: false); |
| 706 | 706 |
| 707 testChecker({ | 707 testChecker({ |
| 708 '/main.dart': ''' | 708 '/main.dart': ''' |
| 709 class A { | 709 class A { |
| 710 int x = 2; | 710 int x = 2; |
| 711 } | 711 } |
| 712 | 712 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 725 '/main.dart': ''' | 725 '/main.dart': ''' |
| 726 class A { | 726 class A { |
| 727 int x = 2; | 727 int x = 2; |
| 728 } | 728 } |
| 729 | 729 |
| 730 class B implements A { | 730 class B implements A { |
| 731 /*severe:InferableOverride*/get x => 3; | 731 /*severe:InferableOverride*/get x => 3; |
| 732 } | 732 } |
| 733 | 733 |
| 734 foo() { | 734 foo() { |
| 735 String y = /*info:DownCast*/new B().x; | 735 String y = /*info:DynamicCast*/new B().x; |
| 736 int z = /*info:DownCast*/new B().x; | 736 int z = /*info:DynamicCast*/new B().x; |
| 737 } | 737 } |
| 738 ''' | 738 ''' |
| 739 }, inferFromOverrides: false); | 739 }, inferFromOverrides: false); |
| 740 | 740 |
| 741 testChecker({ | 741 testChecker({ |
| 742 '/main.dart': ''' | 742 '/main.dart': ''' |
| 743 class A { | 743 class A { |
| 744 int x = 2; | 744 int x = 2; |
| 745 } | 745 } |
| 746 | 746 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 762 '/main.dart': ''' | 762 '/main.dart': ''' |
| 763 class A<T> { | 763 class A<T> { |
| 764 T x; | 764 T x; |
| 765 } | 765 } |
| 766 | 766 |
| 767 class B implements A<int> { | 767 class B implements A<int> { |
| 768 /*severe:InvalidMethodOverride*/dynamic get x => 3; | 768 /*severe:InvalidMethodOverride*/dynamic get x => 3; |
| 769 } | 769 } |
| 770 | 770 |
| 771 foo() { | 771 foo() { |
| 772 String y = /*info:DownCast*/new B().x; | 772 String y = /*info:DynamicCast*/new B().x; |
| 773 int z = /*info:DownCast*/new B().x; | 773 int z = /*info:DynamicCast*/new B().x; |
| 774 } | 774 } |
| 775 ''' | 775 ''' |
| 776 }, inferFromOverrides: infer); | 776 }, inferFromOverrides: infer); |
| 777 } | 777 } |
| 778 | 778 |
| 779 testChecker({ | 779 testChecker({ |
| 780 '/main.dart': ''' | 780 '/main.dart': ''' |
| 781 class A<T> { | 781 class A<T> { |
| 782 T x; | 782 T x; |
| 783 } | 783 } |
| 784 | 784 |
| 785 class B implements A<int> { | 785 class B implements A<int> { |
| 786 /*severe:InferableOverride*/get x => 3; | 786 /*severe:InferableOverride*/get x => 3; |
| 787 } | 787 } |
| 788 | 788 |
| 789 foo() { | 789 foo() { |
| 790 String y = /*info:DownCast*/new B().x; | 790 String y = /*info:DynamicCast*/new B().x; |
| 791 int z = /*info:DownCast*/new B().x; | 791 int z = /*info:DynamicCast*/new B().x; |
| 792 } | 792 } |
| 793 ''' | 793 ''' |
| 794 }, inferFromOverrides: false); | 794 }, inferFromOverrides: false); |
| 795 testChecker({ | 795 testChecker({ |
| 796 '/main.dart': ''' | 796 '/main.dart': ''' |
| 797 class A<T> { | 797 class A<T> { |
| 798 T x; | 798 T x; |
| 799 T w; | 799 T w; |
| 800 } | 800 } |
| 801 | 801 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 '/main.dart': ''' | 927 '/main.dart': ''' |
| 928 class A { | 928 class A { |
| 929 int x = 2; | 929 int x = 2; |
| 930 } | 930 } |
| 931 | 931 |
| 932 class B implements A { | 932 class B implements A { |
| 933 /*severe:InvalidMethodOverride*/dynamic get x => 3; | 933 /*severe:InvalidMethodOverride*/dynamic get x => 3; |
| 934 } | 934 } |
| 935 | 935 |
| 936 foo() { | 936 foo() { |
| 937 String y = /*info:DownCast*/new B().x; | 937 String y = /*info:DynamicCast*/new B().x; |
| 938 int z = /*info:DownCast*/new B().x; | 938 int z = /*info:DynamicCast*/new B().x; |
| 939 } | 939 } |
| 940 ''' | 940 ''' |
| 941 }, inferFromOverrides: infer); | 941 }, inferFromOverrides: infer); |
| 942 } | 942 } |
| 943 }); | 943 }); |
| 944 | 944 |
| 945 test('conflicts can happen', () { | 945 test('conflicts can happen', () { |
| 946 testChecker({ | 946 testChecker({ |
| 947 '/main.dart': ''' | 947 '/main.dart': ''' |
| 948 class I1 { | 948 class I1 { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1009 '/main.dart': ''' | 1009 '/main.dart': ''' |
| 1010 class A { | 1010 class A { |
| 1011 var x; | 1011 var x; |
| 1012 } | 1012 } |
| 1013 | 1013 |
| 1014 class B extends A { | 1014 class B extends A { |
| 1015 var x = 2; | 1015 var x = 2; |
| 1016 } | 1016 } |
| 1017 | 1017 |
| 1018 foo() { | 1018 foo() { |
| 1019 String y = /*info:DownCast*/new B().x; | 1019 String y = /*info:DynamicCast*/new B().x; |
| 1020 int z = /*info:DownCast*/new B().x; | 1020 int z = /*info:DynamicCast*/new B().x; |
| 1021 } | 1021 } |
| 1022 ''' | 1022 ''' |
| 1023 }, inferFromOverrides: true); | 1023 }, inferFromOverrides: true); |
| 1024 | 1024 |
| 1025 testChecker({ | 1025 testChecker({ |
| 1026 '/main.dart': ''' | 1026 '/main.dart': ''' |
| 1027 class A { | 1027 class A { |
| 1028 final x; | 1028 final x; |
| 1029 } | 1029 } |
| 1030 | 1030 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1048 } | 1048 } |
| 1049 | 1049 |
| 1050 class B extends A { | 1050 class B extends A { |
| 1051 var x = 2, y = 3, z, w = 2; | 1051 var x = 2, y = 3, z, w = 2; |
| 1052 } | 1052 } |
| 1053 | 1053 |
| 1054 foo() { | 1054 foo() { |
| 1055 String s; | 1055 String s; |
| 1056 int i; | 1056 int i; |
| 1057 | 1057 |
| 1058 s = /*info:DownCast*/new B().x; | 1058 s = /*info:DynamicCast*/new B().x; |
| 1059 s = /*severe:StaticTypeError*/new B().y; | 1059 s = /*severe:StaticTypeError*/new B().y; |
| 1060 s = new B().z; | 1060 s = new B().z; |
| 1061 s = /*severe:StaticTypeError*/new B().w; | 1061 s = /*severe:StaticTypeError*/new B().w; |
| 1062 | 1062 |
| 1063 i = /*info:DownCast*/new B().x; | 1063 i = /*info:DynamicCast*/new B().x; |
| 1064 i = new B().y; | 1064 i = new B().y; |
| 1065 i = /*severe:StaticTypeError*/new B().z; | 1065 i = /*severe:StaticTypeError*/new B().z; |
| 1066 i = new B().w; | 1066 i = new B().w; |
| 1067 } | 1067 } |
| 1068 ''' | 1068 ''' |
| 1069 }, inferFromOverrides: true); | 1069 }, inferFromOverrides: true); |
| 1070 }); | 1070 }); |
| 1071 | 1071 |
| 1072 test('infer consts transitively', () { | 1072 test('infer consts transitively', () { |
| 1073 testChecker({ | 1073 testChecker({ |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1173 static final T foo = m1(m2(m3('', ''))); | 1173 static final T foo = m1(m2(m3('', ''))); |
| 1174 static T m1(String m) { return null; } | 1174 static T m1(String m) { return null; } |
| 1175 static String m2(e) { return ''; } | 1175 static String m2(e) { return ''; } |
| 1176 } | 1176 } |
| 1177 | 1177 |
| 1178 | 1178 |
| 1179 ''' | 1179 ''' |
| 1180 }, inferFromOverrides: true, inferTransitively: true); | 1180 }, inferFromOverrides: true, inferTransitively: true); |
| 1181 }); | 1181 }); |
| 1182 } | 1182 } |
| OLD | NEW |