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 |