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 { operator +(x); operator *(x); operator -(x); } |
128 abstract class int extends num { } | 146 abstract class int extends num { } |
129 abstract class double extends num { } | 147 abstract class double extends num { } |
130 class bool {} | 148 class bool {} |
131 class String {} | 149 class String {} |
132 class Object {} | 150 class Object {} |
133 class Function {} | 151 class Function {} |
134 abstract class List {} | 152 abstract class List {} |
135 abstract class Map {} | 153 abstract class Map {} |
136 class Closure {} | 154 class Closure {} |
137 class Null {} | 155 class Null {} |
138 class Type {} | 156 class Type {} |
139 class Dynamic_ {} | 157 class Dynamic_ {} |
140 bool identical(Object a, Object b) {}'''; | 158 bool identical(Object a, Object b) {}'''; |
141 | 159 |
142 AnalysisResult analyze(String code) { | 160 AnalysisResult analyze(String code) { |
143 Uri uri = new Uri.fromComponents(scheme: 'source'); | 161 Uri uri = new Uri.fromComponents(scheme: 'source'); |
144 MockCompiler compiler = new MockCompiler(coreSource: CORELIB, | 162 MockCompiler compiler = new MockCompiler(coreSource: CORELIB, |
145 enableConcreteTypeInference: true); | 163 enableConcreteTypeInference: true); |
146 compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code); | 164 compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code); |
| 165 compiler.typesTask.concreteTypesInferrer.testMode = true; |
147 compiler.runCompiler(uri); | 166 compiler.runCompiler(uri); |
148 return new AnalysisResult(compiler); | 167 return new AnalysisResult(compiler); |
149 } | 168 } |
150 | 169 |
| 170 testDynamicBackDoor() { |
| 171 final String source = r""" |
| 172 main () { |
| 173 var x = "__dynamic_for_test"; |
| 174 x; |
| 175 } |
| 176 """; |
| 177 AnalysisResult result = analyze(source); |
| 178 result.checkNodeHasUnknownType('x'); |
| 179 } |
| 180 |
151 testLiterals() { | 181 testLiterals() { |
152 final String source = r""" | 182 final String source = r""" |
153 main() { | 183 main() { |
154 var v1 = 42; | 184 var v1 = 42; |
155 var v2 = 42.0; | 185 var v2 = 42.0; |
156 var v3 = 'abc'; | 186 var v3 = 'abc'; |
157 var v4 = true; | 187 var v4 = true; |
158 var v5 = null; | 188 var v5 = null; |
159 v1; v2; v3; v4; v5; | 189 v1; v2; v3; v4; v5; |
160 } | 190 } |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 } | 290 } |
261 foo; bar; | 291 foo; bar; |
262 } | 292 } |
263 """; | 293 """; |
264 AnalysisResult result = analyze(source); | 294 AnalysisResult result = analyze(source); |
265 result.checkNodeHasType('foo', [result.base('A'), result.base('B')]); | 295 result.checkNodeHasType('foo', [result.base('A'), result.base('B')]); |
266 // Check that the condition is evaluated. | 296 // Check that the condition is evaluated. |
267 result.checkNodeHasType('bar', [result.int]); | 297 result.checkNodeHasType('bar', [result.int]); |
268 } | 298 } |
269 | 299 |
| 300 testToplevelVariable() { |
| 301 final String source = r""" |
| 302 final top = 'abc'; |
| 303 main() { var foo = top; foo; } |
| 304 """; |
| 305 AnalysisResult result = analyze(source); |
| 306 result.checkNodeHasType('foo', [result.string]); |
| 307 } |
| 308 |
270 testNonRecusiveFunction() { | 309 testNonRecusiveFunction() { |
271 final String source = r""" | 310 final String source = r""" |
272 f(x, y) => true ? x : y; | 311 f(x, y) => true ? x : y; |
273 main() { var foo = f(42, "abc"); foo; } | 312 main() { var foo = f(42, "abc"); foo; } |
274 """; | 313 """; |
275 AnalysisResult result = analyze(source); | 314 AnalysisResult result = analyze(source); |
276 result.checkNodeHasType('foo', [result.int, result.string]); | 315 result.checkNodeHasType('foo', [result.int, result.string]); |
277 } | 316 } |
278 | 317 |
279 testRecusiveFunction() { | 318 testRecusiveFunction() { |
(...skipping 11 matching lines...) Expand all Loading... |
291 testMutuallyRecusiveFunction() { | 330 testMutuallyRecusiveFunction() { |
292 final String source = r""" | 331 final String source = r""" |
293 f() => true ? 42 : g(); | 332 f() => true ? 42 : g(); |
294 g() => true ? "abc" : f(); | 333 g() => true ? "abc" : f(); |
295 main() { var foo = f(); foo; } | 334 main() { var foo = f(); foo; } |
296 """; | 335 """; |
297 AnalysisResult result = analyze(source); | 336 AnalysisResult result = analyze(source); |
298 result.checkNodeHasType('foo', [result.int, result.string]); | 337 result.checkNodeHasType('foo', [result.int, result.string]); |
299 } | 338 } |
300 | 339 |
| 340 testSimpleSend() { |
| 341 final String source = r""" |
| 342 class A { |
| 343 f(x) => x; |
| 344 } |
| 345 class B { |
| 346 f(x) => 'abc'; |
| 347 } |
| 348 class C { |
| 349 f(x) => 3.14; |
| 350 } |
| 351 class D { |
| 352 var f; // we check that this field is ignored in calls to dynamic.f() |
| 353 D(this.f); |
| 354 } |
| 355 main() { |
| 356 new B(); new D(42); // we instantiate B and D but not C |
| 357 var foo = new A().f(42); |
| 358 var bar = "__dynamic_for_test".f(42); |
| 359 foo; bar; |
| 360 } |
| 361 """; |
| 362 AnalysisResult result = analyze(source); |
| 363 result.checkNodeHasType('foo', [result.int]); |
| 364 result.checkNodeHasType('bar', [result.int, result.string]); |
| 365 } |
| 366 |
| 367 testSendToClosureField() { |
| 368 final String source = r""" |
| 369 f(x) => x; |
| 370 class A { |
| 371 var g; |
| 372 A(this.g); |
| 373 } |
| 374 main() { |
| 375 var foo = new A(f).g(42); |
| 376 foo; |
| 377 } |
| 378 """; |
| 379 AnalysisResult result = analyze(source); |
| 380 result.checkNodeHasType('foo', [result.int]); |
| 381 } |
| 382 |
301 testSendToThis1() { | 383 testSendToThis1() { |
302 final String source = r""" | 384 final String source = r""" |
303 class A { | 385 class A { |
304 A(); | 386 A(); |
305 f() => g(); | 387 f() => g(); |
306 g() => 42; | 388 g() => 42; |
307 } | 389 } |
308 main() { | 390 main() { |
309 var foo = new A().f(); | 391 var foo = new A().f(); |
310 foo; | 392 foo; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 } | 431 } |
350 | 432 |
351 testGetters() { | 433 testGetters() { |
352 final String source = r""" | 434 final String source = r""" |
353 class A { | 435 class A { |
354 var x; | 436 var x; |
355 A(this.x); | 437 A(this.x); |
356 get y => x; | 438 get y => x; |
357 get z => y; | 439 get z => y; |
358 } | 440 } |
| 441 class B { |
| 442 var x; |
| 443 B(this.x); |
| 444 } |
359 main() { | 445 main() { |
360 var a = new A(42); | 446 var a = new A(42); |
| 447 var b = new B('abc'); |
361 var foo = a.x; | 448 var foo = a.x; |
362 var bar = a.y; | 449 var bar = a.y; |
363 var baz = a.z; | 450 var baz = a.z; |
364 var qux = null.x; | 451 var qux = null.x; |
365 foo; bar; baz; qux; | 452 var quux = "__dynamic_for_test".x; |
| 453 foo; bar; baz; qux; quux; |
366 } | 454 } |
367 """; | 455 """; |
368 AnalysisResult result = analyze(source); | 456 AnalysisResult result = analyze(source); |
369 result.checkNodeHasType('foo', [result.int]); | 457 result.checkNodeHasType('foo', [result.int]); |
370 result.checkNodeHasType('bar', [result.int]); | 458 result.checkNodeHasType('bar', [result.int]); |
371 result.checkNodeHasType('baz', [result.int]); | 459 result.checkNodeHasType('baz', [result.int]); |
372 result.checkNodeHasType('qux', []); | 460 result.checkNodeHasType('qux', []); |
| 461 result.checkNodeHasType('quux', [result.int, result.string]); |
373 } | 462 } |
374 | 463 |
375 testSetters() { | 464 testSetters() { |
376 final String source = r""" | 465 final String source = r""" |
377 class A { | 466 class A { |
378 var x; | 467 var x; |
379 var w; | 468 var w; |
380 A(this.x, this.w); | 469 A(this.x, this.w); |
381 set y(a) { x = a; z = a; } | 470 set y(a) { x = a; z = a; } |
382 set z(a) { w = a; } | 471 set z(a) { w = a; } |
383 } | 472 } |
| 473 class B { |
| 474 var x; |
| 475 B(this.x); |
| 476 } |
384 main() { | 477 main() { |
385 var a = new A(42, 42); | 478 var a = new A(42, 42); |
| 479 var b = new B(42); |
386 a.x = 'abc'; | 480 a.x = 'abc'; |
387 a.y = true; | 481 a.y = true; |
388 null.x = 42; // should be ignored | 482 null.x = 42; // should be ignored |
| 483 "__dynamic_for_test".x = null; |
| 484 "__dynamic_for_test".y = 3.14; |
389 } | 485 } |
390 """; | 486 """; |
391 AnalysisResult result = analyze(source); | 487 AnalysisResult result = analyze(source); |
392 result.checkFieldHasType('A', 'x', [result.int, result.string, result.bool]); | 488 result.checkFieldHasType('B', 'x', |
393 result.checkFieldHasType('A', 'w', [result.int, result.bool]); | 489 [result.int, // new B(42) |
| 490 result.nullType]); // dynamic.x = null |
| 491 result.checkFieldHasType('A', 'x', |
| 492 [result.int, // new A(42, ...) |
| 493 result.string, // a.x = 'abc' |
| 494 result.bool, // a.y = true |
| 495 result.nullType, // dynamic.x = null |
| 496 result.double]); // dynamic.y = 3.14 |
| 497 result.checkFieldHasType('A', 'w', |
| 498 [result.int, // new A(..., 42) |
| 499 result.bool, // a.y = true |
| 500 result.double]); // dynamic.y = double |
394 } | 501 } |
395 | 502 |
396 testNamedParameters() { | 503 testNamedParameters() { |
397 final String source = r""" | 504 final String source = r""" |
398 class A { | 505 class A { |
399 var x, y, z, w; | 506 var x, y, z, w; |
400 A(this.x, {this.y, this.z, this.w}); | 507 A(this.x, {this.y, this.z, this.w}); |
401 } | 508 } |
402 main() { | 509 main() { |
403 new A(42); | 510 new A(42); |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 x; y; z; w; | 710 x; y; z; w; |
604 } | 711 } |
605 """; | 712 """; |
606 AnalysisResult result = analyze(source); | 713 AnalysisResult result = analyze(source); |
607 result.checkNodeHasType('x', []); | 714 result.checkNodeHasType('x', []); |
608 result.checkNodeHasType('y', []); | 715 result.checkNodeHasType('y', []); |
609 result.checkNodeHasType('z', []); | 716 result.checkNodeHasType('z', []); |
610 result.checkNodeHasType('w', []); | 717 result.checkNodeHasType('w', []); |
611 } | 718 } |
612 | 719 |
| 720 testDynamicIsAbsorbing() { |
| 721 final String source = r""" |
| 722 main () { |
| 723 var x = 1; |
| 724 if (true) { |
| 725 x = "__dynamic_for_test"; |
| 726 } else { |
| 727 x = 42; |
| 728 } |
| 729 x; |
| 730 } |
| 731 """; |
| 732 AnalysisResult result = analyze(source); |
| 733 result.checkNodeHasUnknownType('x'); |
| 734 } |
| 735 |
613 void main() { | 736 void main() { |
| 737 testDynamicBackDoor(); |
614 testLiterals(); | 738 testLiterals(); |
615 testRedefinition(); | 739 testRedefinition(); |
616 testIfThenElse(); | 740 testIfThenElse(); |
617 testTernaryIf(); | 741 testTernaryIf(); |
618 testWhile(); | 742 testWhile(); |
619 testFor1(); | 743 testFor1(); |
620 testFor2(); | 744 testFor2(); |
| 745 // testToplevelVariable(); // toplevel variables are not yet supported |
621 testNonRecusiveFunction(); | 746 testNonRecusiveFunction(); |
622 testRecusiveFunction(); | 747 testRecusiveFunction(); |
623 testMutuallyRecusiveFunction(); | 748 testMutuallyRecusiveFunction(); |
| 749 testSimpleSend(); |
| 750 // testSendToClosureField(); // closures are not yet supported |
624 testSendToThis1(); | 751 testSendToThis1(); |
625 testSendToThis2(); | 752 testSendToThis2(); |
626 testConstructor(); | 753 testConstructor(); |
627 testGetters(); | 754 testGetters(); |
628 testSetters(); | 755 testSetters(); |
629 testNamedParameters(); | 756 testNamedParameters(); |
630 testListLiterals(); | 757 testListLiterals(); |
631 testMapLiterals(); | 758 testMapLiterals(); |
632 testReturn(); | 759 testReturn(); |
633 // testNoReturn(); // right now we infer the empty type instead of null | 760 // testNoReturn(); // right now we infer the empty type instead of null |
634 testArithmeticOperators(); | 761 testArithmeticOperators(); |
635 testOperators(); | 762 testOperators(); |
636 testCompoundOperators1(); | 763 testCompoundOperators1(); |
637 testCompoundOperators2(); | 764 testCompoundOperators2(); |
638 // testFieldInitialization(); // TODO(polux) | 765 // testFieldInitialization(); // TODO(polux) |
639 testSendWithWrongArity(); | 766 testSendWithWrongArity(); |
| 767 testDynamicIsAbsorbing(); |
640 } | 768 } |
OLD | NEW |