OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 import "dart:uri"; | 5 import "dart:uri"; |
6 import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dar t"; | 6 import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dar t"; |
7 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.da rt'; | 7 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.da rt'; |
8 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart'; | 8 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart'; |
9 import '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'; | 9 import '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'; |
10 import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'; | 10 import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
104 * occurence of [: variable; :] in the program is the concrete type | 104 * occurence of [: variable; :] in the program is the concrete type |
105 * made of [baseTypes]. | 105 * made of [baseTypes]. |
106 */ | 106 */ |
107 void checkNodeHasType(String variable, List<BaseType> baseTypes) { | 107 void checkNodeHasType(String variable, List<BaseType> baseTypes) { |
108 return Expect.equals( | 108 return Expect.equals( |
109 concreteFrom(baseTypes), | 109 concreteFrom(baseTypes), |
110 inferrer.inferredTypes[findNode(variable)]); | 110 inferrer.inferredTypes[findNode(variable)]); |
111 } | 111 } |
112 | 112 |
113 /** | 113 /** |
114 * Checks that the inferred type of the node corresponding to the last | |
115 * occurence of [: variable; :] in the program is the unknown concrete type. | |
116 */ | |
117 void checkNodeHasUnknownType(String variable) { | |
118 return Expect.isTrue(inferrer.inferredTypes[findNode(variable)].isUnkown()); | |
119 } | |
120 | |
121 /** | |
114 * Checks that [: className#fieldName :]'s inferred type is the concrete type | 122 * Checks that [: className#fieldName :]'s inferred type is the concrete type |
115 * made of [baseTypes]. | 123 * made of [baseTypes]. |
116 */ | 124 */ |
117 void checkFieldHasType(String className, String fieldName, | 125 void checkFieldHasType(String className, String fieldName, |
118 List<BaseType> baseTypes) { | 126 List<BaseType> baseTypes) { |
119 return Expect.equals( | 127 return Expect.equals( |
120 concreteFrom(baseTypes), | 128 concreteFrom(baseTypes), |
121 inferrer.inferredFieldTypes[findField(className, fieldName)]); | 129 inferrer.inferredFieldTypes[findField(className, fieldName)]); |
122 } | 130 } |
131 | |
132 /** | |
133 * Checks that [: className#fieldName :]'s inferred type is the unknown | |
134 * concrete type. | |
135 */ | |
136 void checkFieldHasUknownType(String className, String fieldName) { | |
137 return Expect.isTrue( | |
138 inferrer.inferredFieldTypes[findField(className, fieldName)] | |
139 .isUnkown()); | |
140 } | |
123 } | 141 } |
124 | 142 |
125 const String CORELIB = r''' | 143 const String CORELIB = r''' |
126 print(var obj) {} | 144 print(var obj) {} |
127 abstract class num { operator +(x); operator *(x); operator -(x); } | 145 abstract class num { |
146 operator +(x); | |
147 operator *(x); | |
148 operator -(x); | |
149 operator ==(x); | |
150 } | |
128 abstract class int extends num { } | 151 abstract class int extends num { } |
129 abstract class double extends num { } | 152 abstract class double extends num { } |
130 class bool {} | 153 class bool {} |
131 class String {} | 154 class String {} |
132 class Object {} | 155 class Object {} |
133 class Function {} | 156 class Function {} |
134 abstract class List {} | 157 abstract class List {} |
135 abstract class Map {} | 158 abstract class Map {} |
136 class Closure {} | 159 class Closure {} |
137 class Null {} | 160 class Null {} |
138 class Type {} | 161 class Type {} |
139 class Dynamic_ {} | 162 class Dynamic_ {} |
140 bool identical(Object a, Object b) {}'''; | 163 bool identical(Object a, Object b) {}'''; |
141 | 164 |
142 AnalysisResult analyze(String code) { | 165 AnalysisResult analyze(String code) { |
143 Uri uri = new Uri.fromComponents(scheme: 'source'); | 166 Uri uri = new Uri.fromComponents(scheme: 'source'); |
144 MockCompiler compiler = new MockCompiler(coreSource: CORELIB, | 167 MockCompiler compiler = new MockCompiler(coreSource: CORELIB, |
145 enableConcreteTypeInference: true); | 168 enableConcreteTypeInference: true); |
146 compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code); | 169 compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code); |
147 compiler.runCompiler(uri); | 170 compiler.runCompiler(uri); |
148 return new AnalysisResult(compiler); | 171 return new AnalysisResult(compiler); |
149 } | 172 } |
150 | 173 |
174 testDynamicBackDoor() { | |
175 final String source = r""" | |
176 main () { | |
177 var x = "__dynamic_for_test"; | |
178 x; | |
179 } | |
180 """; | |
181 AnalysisResult result = analyze(source); | |
182 result.checkNodeHasUnknownType('x'); | |
183 } | |
184 | |
151 testLiterals() { | 185 testLiterals() { |
152 final String source = r""" | 186 final String source = r""" |
153 main() { | 187 main() { |
154 var v1 = 42; | 188 var v1 = 42; |
155 var v2 = 42.0; | 189 var v2 = 42.0; |
156 var v3 = 'abc'; | 190 var v3 = 'abc'; |
157 var v4 = true; | 191 var v4 = true; |
158 var v5 = null; | 192 var v5 = null; |
159 v1; v2; v3; v4; v5; | 193 v1; v2; v3; v4; v5; |
160 } | 194 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 } | 294 } |
261 foo; bar; | 295 foo; bar; |
262 } | 296 } |
263 """; | 297 """; |
264 AnalysisResult result = analyze(source); | 298 AnalysisResult result = analyze(source); |
265 result.checkNodeHasType('foo', [result.base('A'), result.base('B')]); | 299 result.checkNodeHasType('foo', [result.base('A'), result.base('B')]); |
266 // Check that the condition is evaluated. | 300 // Check that the condition is evaluated. |
267 result.checkNodeHasType('bar', [result.int]); | 301 result.checkNodeHasType('bar', [result.int]); |
268 } | 302 } |
269 | 303 |
304 testToplevelVariable() { | |
305 final String source = r""" | |
306 final top = 'abc'; | |
307 main() { var foo = top; foo; } | |
308 """; | |
309 AnalysisResult result = analyze(source); | |
310 result.checkNodeHasType('foo', [result.string]); | |
311 } | |
312 | |
270 testNonRecusiveFunction() { | 313 testNonRecusiveFunction() { |
271 final String source = r""" | 314 final String source = r""" |
272 f(x, y) => true ? x : y; | 315 f(x, y) => true ? x : y; |
273 main() { var foo = f(42, "abc"); foo; } | 316 main() { var foo = f(42, "abc"); foo; } |
274 """; | 317 """; |
275 AnalysisResult result = analyze(source); | 318 AnalysisResult result = analyze(source); |
276 result.checkNodeHasType('foo', [result.int, result.string]); | 319 result.checkNodeHasType('foo', [result.int, result.string]); |
277 } | 320 } |
278 | 321 |
279 testRecusiveFunction() { | 322 testRecusiveFunction() { |
(...skipping 11 matching lines...) Expand all Loading... | |
291 testMutuallyRecusiveFunction() { | 334 testMutuallyRecusiveFunction() { |
292 final String source = r""" | 335 final String source = r""" |
293 f() => true ? 42 : g(); | 336 f() => true ? 42 : g(); |
294 g() => true ? "abc" : f(); | 337 g() => true ? "abc" : f(); |
295 main() { var foo = f(); foo; } | 338 main() { var foo = f(); foo; } |
296 """; | 339 """; |
297 AnalysisResult result = analyze(source); | 340 AnalysisResult result = analyze(source); |
298 result.checkNodeHasType('foo', [result.int, result.string]); | 341 result.checkNodeHasType('foo', [result.int, result.string]); |
299 } | 342 } |
300 | 343 |
344 testSimpleSend() { | |
345 final String source = r""" | |
346 class A { | |
347 f(x) => x; | |
348 } | |
349 class B { | |
350 f(x) => 'abc'; | |
351 } | |
352 class C { | |
353 f(x) => 3.14; | |
354 } | |
355 class D { | |
356 var f; // we check that this field is ignored in calls to dynamic.f() | |
357 D(this.f); | |
358 } | |
359 main() { | |
360 new B(); new D(42); // we instantiate B and D but not C | |
361 var foo = new A().f(42); | |
362 var bar = "__dynamic_for_test".f(42); | |
363 foo; bar; | |
364 } | |
365 """; | |
366 AnalysisResult result = analyze(source); | |
367 result.checkNodeHasType('foo', [result.int]); | |
368 result.checkNodeHasType('bar', [result.int, result.string]); | |
369 } | |
370 | |
371 testSendToClosureField() { | |
372 final String source = r""" | |
373 f(x) => x; | |
374 class A { | |
375 var g; | |
376 A(this.g); | |
377 } | |
378 main() { | |
379 var foo = new A(f).g(42); | |
380 foo; | |
381 } | |
382 """; | |
383 AnalysisResult result = analyze(source); | |
384 result.checkNodeHasType('foo', [result.int]); | |
385 } | |
386 | |
301 testSendToThis1() { | 387 testSendToThis1() { |
302 final String source = r""" | 388 final String source = r""" |
303 class A { | 389 class A { |
304 A(); | 390 A(); |
305 f() => g(); | 391 f() => g(); |
306 g() => 42; | 392 g() => 42; |
307 } | 393 } |
308 main() { | 394 main() { |
309 var foo = new A().f(); | 395 var foo = new A().f(); |
310 foo; | 396 foo; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 } | 435 } |
350 | 436 |
351 testGetters() { | 437 testGetters() { |
352 final String source = r""" | 438 final String source = r""" |
353 class A { | 439 class A { |
354 var x; | 440 var x; |
355 A(this.x); | 441 A(this.x); |
356 get y => x; | 442 get y => x; |
357 get z => y; | 443 get z => y; |
358 } | 444 } |
445 class B { | |
446 var x; | |
447 B(this.x); | |
448 } | |
359 main() { | 449 main() { |
360 var a = new A(42); | 450 var a = new A(42); |
451 var b = new B('abc'); | |
361 var foo = a.x; | 452 var foo = a.x; |
362 var bar = a.y; | 453 var bar = a.y; |
363 var baz = a.z; | 454 var baz = a.z; |
364 foo; bar; baz; | 455 var qux = "__dynamic_for_test".x; |
456 foo; bar; baz; qux; | |
365 } | 457 } |
366 """; | 458 """; |
367 AnalysisResult result = analyze(source); | 459 AnalysisResult result = analyze(source); |
368 result.checkNodeHasType('foo', [result.int]); | 460 result.checkNodeHasType('foo', [result.int]); |
369 result.checkNodeHasType('bar', [result.int]); | 461 result.checkNodeHasType('bar', [result.int]); |
370 result.checkNodeHasType('baz', [result.int]); | 462 result.checkNodeHasType('baz', [result.int]); |
463 result.checkNodeHasType('qux', [result.int, result.string]); | |
371 } | 464 } |
372 | 465 |
373 testSetters() { | 466 testSetters() { |
374 final String source = r""" | 467 final String source = r""" |
375 class A { | 468 class A { |
376 var x; | 469 var x; |
377 var w; | 470 var w; |
378 A(this.x, this.w); | 471 A(this.x, this.w); |
379 set y(a) { x = a; z = a; } | 472 set y(a) { x = a; z = a; } |
380 set z(a) { w = a; } | 473 set z(a) { w = a; } |
381 } | 474 } |
475 class B { | |
476 var x; | |
477 B(this.x); | |
478 } | |
382 main() { | 479 main() { |
383 var a = new A(42, 42); | 480 var a = new A(42, 42); |
481 var b = new B(42); | |
384 a.x = 'abc'; | 482 a.x = 'abc'; |
385 a.y = true; | 483 a.y = true; |
484 "__dynamic_for_test".x = null; | |
485 "__dynamic_for_test".y = 3.14; | |
386 } | 486 } |
387 """; | 487 """; |
388 AnalysisResult result = analyze(source); | 488 AnalysisResult result = analyze(source); |
389 result.checkFieldHasType('A', 'x', [result.int, result.string, result.bool]); | 489 result.checkFieldHasType('B', 'x', |
390 result.checkFieldHasType('A', 'w', [result.int, result.bool]); | 490 [result.int, // new B(42) |
491 result.nullType]); // dynamic.x = null | |
492 result.checkFieldHasType('A', 'x', | |
493 [result.int, // new A(42, ...) | |
494 result.string, // a.x = 'abc' | |
495 result.bool, // a.y = true | |
496 result.nullType, // dynamic.x = null | |
497 result.double]); // dynamic.y = 3.14 | |
498 result.checkFieldHasType('A', 'w', | |
499 [result.int, // new A(..., 42) | |
500 result.bool, // a.y = true | |
501 result.double]); // dynamic.y = double | |
391 } | 502 } |
392 | 503 |
393 testNamedParameters() { | 504 testNamedParameters() { |
394 final String source = r""" | 505 final String source = r""" |
395 class A { | 506 class A { |
396 var x, y, z, w; | 507 var x, y, z, w; |
397 A(this.x, {this.y, this.z, this.w}); | 508 A(this.x, {this.y, this.z, this.w}); |
398 } | 509 } |
399 main() { | 510 main() { |
400 new A(42); | 511 new A(42); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
520 var x = new A() < "foo"; | 631 var x = new A() < "foo"; |
521 var y = new A() << "foo"; | 632 var y = new A() << "foo"; |
522 x; y; | 633 x; y; |
523 } | 634 } |
524 """; | 635 """; |
525 AnalysisResult result = analyze(source); | 636 AnalysisResult result = analyze(source); |
526 result.checkNodeHasType('x', [result.int]); | 637 result.checkNodeHasType('x', [result.int]); |
527 result.checkNodeHasType('y', [result.string]); | 638 result.checkNodeHasType('y', [result.string]); |
528 } | 639 } |
529 | 640 |
641 testSetIndexOperator() { | |
642 final String source = r""" | |
643 class A { | |
644 var witness1; | |
645 var witness2; | |
646 operator []=(i, x) { witness1 = i; witness2 = x; } | |
647 } | |
648 main() { | |
649 var x = new A()[42] = "abc"; | |
650 x; | |
651 } | |
652 """; | |
653 AnalysisResult result = analyze(source); | |
654 result.checkNodeHasType('x', [result.string]); | |
655 // TODO(polux): the two following results should be {null, string}, see | |
656 // fieldInitialization(). | |
karlklose
2012/11/28 08:24:07
fieldInitialization() -> testFieldInitialization?
polux
2012/11/29 14:18:39
Done.
| |
657 result.checkFieldHasType('A', 'witness1', [result.int]); | |
658 result.checkFieldHasType('A', 'witness2', [result.string]); | |
659 } | |
660 | |
530 testCompoundOperators1() { | 661 testCompoundOperators1() { |
531 final String source = r""" | 662 final String source = r""" |
532 class A { | 663 class A { |
533 operator +(x) => "foo"; | 664 operator +(x) => "foo"; |
534 } | 665 } |
535 main() { | 666 main() { |
536 var x1 = 1; x1++; | 667 var x1 = 1; x1++; |
537 var x2 = 1; ++x2; | 668 var x2 = 1; ++x2; |
538 var x3 = new A(); x3++; | 669 var x3 = 1; x3 += 42; |
karlklose
2012/11/28 08:24:07
Perhaps these statements should all have their own
polux
2012/11/29 14:18:39
Done.
| |
539 var x4 = new A(); ++x4; | 670 var x4 = new A(); x4++; |
671 var x5 = new A(); ++x5; | |
672 var x6 = new A(); x6 += true; | |
540 | 673 |
541 x1; x2; x3; x4; | 674 x1; x2; x3; x4; x5; x6; |
542 } | 675 } |
543 """; | 676 """; |
544 AnalysisResult result = analyze(source); | 677 AnalysisResult result = analyze(source); |
545 result.checkNodeHasType('x1', [result.int]); | 678 result.checkNodeHasType('x1', [result.int]); |
546 result.checkNodeHasType('x2', [result.int]); | 679 result.checkNodeHasType('x2', [result.int]); |
547 result.checkNodeHasType('x3', [result.string]); | 680 result.checkNodeHasType('x3', [result.int]); |
548 result.checkNodeHasType('x4', [result.string]); | 681 result.checkNodeHasType('x4', [result.string]); |
682 result.checkNodeHasType('x5', [result.string]); | |
683 result.checkNodeHasType('x6', [result.string]); | |
549 } | 684 } |
550 | 685 |
551 | 686 |
552 testCompoundOperators2() { | 687 testCompoundOperators2() { |
553 final String source = r""" | 688 final String source = r""" |
554 class A { | 689 class A { |
555 var xx; | 690 var xx; |
691 var yy; | |
556 var witness1; | 692 var witness1; |
557 var witness2; | 693 var witness2; |
694 var witness3; | |
695 var witness4; | |
558 | 696 |
559 A(this.xx); | 697 A(this.xx, this.yy); |
560 get x { witness1 = "foo"; return xx; } | 698 get x { witness1 = "foo"; return xx; } |
561 set x(y) { witness2 = "foo"; xx = y; } | 699 set x(a) { witness2 = "foo"; xx = a; } |
700 get y { witness3 = "foo"; return yy; } | |
701 set y(a) { witness4 = "foo"; yy = a; } | |
562 } | 702 } |
563 main () { | 703 main () { |
564 var a = new A(1); | 704 var a = new A(1, 1); |
565 a.x++; | 705 a.x++; |
706 a.y++; | |
566 } | 707 } |
567 """; | 708 """; |
568 AnalysisResult result = analyze(source); | 709 AnalysisResult result = analyze(source); |
569 result.checkFieldHasType('A', 'xx', [result.int]); | 710 result.checkFieldHasType('A', 'xx', [result.int]); |
570 // TODO(polux): the two following results should be {null, string}, see | 711 result.checkFieldHasType('A', 'yy', [result.int]); |
712 // TODO(polux): the four following results should be {null, string}, see | |
571 // fieldInitialization(). | 713 // fieldInitialization(). |
572 result.checkFieldHasType('A', 'witness1', [result.string]); | 714 result.checkFieldHasType('A', 'witness1', [result.string]); |
573 result.checkFieldHasType('A', 'witness2', [result.string]); | 715 result.checkFieldHasType('A', 'witness2', [result.string]); |
716 result.checkFieldHasType('A', 'witness3', [result.string]); | |
717 result.checkFieldHasType('A', 'witness4', [result.string]); | |
718 } | |
719 | |
720 testDisequality() { | |
karlklose
2012/11/28 08:24:07
'Disequality' -> 'Inequality'.
polux
2012/11/29 14:18:39
In automated theorem proving, disequalities are in
| |
721 final String source = r""" | |
722 class A { | |
723 var witness; | |
724 operator ==(x) { witness = "foo"; return "abc"; } | |
725 } | |
726 class B { | |
727 operator ==(x) { throw "error"; } | |
728 } | |
729 main() { | |
730 var foo = 1 != 2; | |
731 var bar = new A() != 2; | |
732 var baz = new B() != 2; | |
733 foo; bar; baz; | |
734 } | |
735 """; | |
736 AnalysisResult result = analyze(source); | |
737 result.checkNodeHasType('foo', [result.bool]); | |
738 result.checkNodeHasType('bar', [result.bool]); | |
739 result.checkNodeHasType('baz', []); | |
740 // TODO(polux): the following result should be {null, string}, see | |
karlklose
2012/11/28 08:24:07
{null, string} -> [:[null, string]:]
polux
2012/11/29 14:18:39
Done. Is [: :] used in non dartdoc comments too?
| |
741 // fieldInitialization(). | |
742 result.checkFieldHasType('A', 'witness', [result.string]); | |
574 } | 743 } |
575 | 744 |
576 testFieldInitialization() { | 745 testFieldInitialization() { |
577 final String source = r""" | 746 final String source = r""" |
578 class A { | 747 class A { |
579 var x; | 748 var x; |
580 var y = 1; | 749 var y = 1; |
581 } | 750 } |
582 main () { | 751 main () { |
583 new A(); | 752 new A(); |
584 } | 753 } |
585 """; | 754 """; |
586 AnalysisResult result = analyze(source); | 755 AnalysisResult result = analyze(source); |
587 result.checkFieldHasType('A', 'x', [result.nullType]); | 756 result.checkFieldHasType('A', 'x', [result.nullType]); |
588 result.checkFieldHasType('A', 'y', [result.int]); | 757 result.checkFieldHasType('A', 'y', [result.int]); |
589 } | 758 } |
590 | 759 |
760 testDynamicIsAbsorbing() { | |
761 final String source = r""" | |
762 main () { | |
763 var x = 1; | |
764 if (true) { | |
765 x = "__dynamic_for_test"; | |
766 } else { | |
767 x = 42; | |
768 } | |
769 x; | |
770 } | |
771 """; | |
772 AnalysisResult result = analyze(source); | |
773 result.checkNodeHasUnknownType('x'); | |
774 } | |
775 | |
591 void main() { | 776 void main() { |
777 testDynamicBackDoor(); | |
592 testLiterals(); | 778 testLiterals(); |
593 testRedefinition(); | 779 testRedefinition(); |
594 testIfThenElse(); | 780 testIfThenElse(); |
595 testTernaryIf(); | 781 testTernaryIf(); |
596 testWhile(); | 782 testWhile(); |
597 testFor1(); | 783 testFor1(); |
598 testFor2(); | 784 testFor2(); |
785 // testToplevelVariable(); // toplevel variables are not yet supported | |
599 testNonRecusiveFunction(); | 786 testNonRecusiveFunction(); |
600 testRecusiveFunction(); | 787 testRecusiveFunction(); |
601 testMutuallyRecusiveFunction(); | 788 testMutuallyRecusiveFunction(); |
789 testSimpleSend(); | |
790 // testSendToClosureField(); // closures are not yet supported | |
602 testSendToThis1(); | 791 testSendToThis1(); |
603 testSendToThis2(); | 792 testSendToThis2(); |
604 testConstructor(); | 793 testConstructor(); |
605 testGetters(); | 794 testGetters(); |
606 testSetters(); | 795 testSetters(); |
607 testNamedParameters(); | 796 testNamedParameters(); |
608 testListLiterals(); | 797 testListLiterals(); |
609 testMapLiterals(); | 798 testMapLiterals(); |
610 testReturn(); | 799 testReturn(); |
611 // testNoReturn(); // right now we infer the empty type instead of null | 800 // testNoReturn(); // right now we infer the empty type instead of null |
612 testArithmeticOperators(); | 801 testArithmeticOperators(); |
613 testOperators(); | 802 testOperators(); |
614 testCompoundOperators1(); | 803 testCompoundOperators1(); |
615 testCompoundOperators2(); | 804 testCompoundOperators2(); |
805 testSetIndexOperator(); | |
806 testDisequality(); | |
616 // testFieldInitialization(); // TODO(polux) | 807 // testFieldInitialization(); // TODO(polux) |
808 testDynamicIsAbsorbing(); | |
617 } | 809 } |
OLD | NEW |