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/compact_vm_config.dart'; | 8 import 'package:unittest/compact_vm_config.dart'; |
9 import 'package:unittest/unittest.dart'; | 9 import 'package:unittest/unittest.dart'; |
10 | 10 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 static var x = 2; | 154 static var x = 2; |
155 static var y = A.x; | 155 static var y = A.x; |
156 } | 156 } |
157 | 157 |
158 test1() { | 158 test1() { |
159 A.x = /*severe:StaticTypeError*/"hi"; | 159 A.x = /*severe:StaticTypeError*/"hi"; |
160 A.y = "hi"; | 160 A.y = "hi"; |
161 } | 161 } |
162 ''' | 162 ''' |
163 }); | 163 }); |
164 | |
165 // Allowed with special flag. Note, while the flag is generally not stable, | |
166 // we can use it in this test because it is stable within a library (order | |
167 // matches program order). | |
168 testChecker({ | |
169 '/main.dart': ''' | |
170 var x = 2; | |
171 var y = x; | |
172 | |
173 test1() { | |
174 x = /*severe:StaticTypeError*/"hi"; | |
175 y = /*severe:StaticTypeError*/"hi"; | |
176 } | |
177 ''' | |
178 }, inferInNonStableOrder: true); | |
179 | |
180 testChecker({ | |
181 '/main.dart': ''' | |
182 class A { | |
183 static var x = 2; | |
184 static var y = A.x; | |
185 } | |
186 | |
187 test1() { | |
188 A.x = /*severe:StaticTypeError*/"hi"; | |
189 A.y = /*severe:StaticTypeError*/"hi"; | |
190 } | |
191 ''' | |
192 }, inferInNonStableOrder: true); | |
193 }); | 164 }); |
194 | 165 |
195 test('not ok to infer from variables in non-cycle libs', () { | 166 test('not ok to infer from variables in non-cycle libs', () { |
196 testChecker({ | 167 testChecker({ |
197 '/a.dart': ''' | 168 '/a.dart': ''' |
198 var x = 2; | 169 var x = 2; |
199 ''', | 170 ''', |
200 '/main.dart': ''' | 171 '/main.dart': ''' |
201 import 'a.dart'; | 172 import 'a.dart'; |
202 var y = x; | 173 var y = x; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 B.y = /*severe:StaticTypeError*/"hi"; | 224 B.y = /*severe:StaticTypeError*/"hi"; |
254 } | 225 } |
255 ''' | 226 ''' |
256 }, inferStaticsFromIdentifiers: true); | 227 }, inferStaticsFromIdentifiers: true); |
257 }); | 228 }); |
258 | 229 |
259 test('do not infer from variables in cycle libs', () { | 230 test('do not infer from variables in cycle libs', () { |
260 testChecker({ | 231 testChecker({ |
261 '/a.dart': ''' | 232 '/a.dart': ''' |
262 import 'main.dart'; | 233 import 'main.dart'; |
263 var x = 2; | 234 var x = 2; // ok to infer |
264 ''', | 235 ''', |
265 '/main.dart': ''' | 236 '/main.dart': ''' |
266 import 'a.dart'; | 237 import 'a.dart'; |
267 var y = x; | 238 var y = x; // not ok to infer yet |
268 | 239 |
269 test1() { | 240 test1() { |
270 int t = 3; | 241 int t = 3; |
271 t = /*info:DownCast*/x; | 242 t = x; |
272 t = /*info:DownCast*/y; | 243 t = /*info:DownCast*/y; |
273 } | 244 } |
274 ''' | 245 ''' |
275 }, inferStaticsFromIdentifiers: true); | 246 }, inferStaticsFromIdentifiers: true); |
276 | 247 |
277 testChecker({ | 248 testChecker({ |
278 '/a.dart': ''' | 249 '/a.dart': ''' |
279 import 'main.dart'; | 250 import 'main.dart'; |
280 class A { static var x = 2; } | 251 class A { static var x = 2; } |
281 ''', | 252 ''', |
282 '/main.dart': ''' | 253 '/main.dart': ''' |
283 import 'a.dart'; | 254 import 'a.dart'; |
284 class B { static var y = A.x; } | 255 class B { static var y = A.x; } |
285 | 256 |
286 test1() { | 257 test1() { |
287 int t = 3; | 258 int t = 3; |
288 t = /*info:DownCast*/A.x; | 259 t = A.x; |
289 t = /*info:DownCast*/A.y; | 260 t = /*info:DownCast*/A.y; |
290 } | 261 } |
291 ''' | 262 ''' |
292 }, inferStaticsFromIdentifiers: true); | 263 }, inferStaticsFromIdentifiers: true); |
293 }); | 264 }); |
294 | 265 |
295 test('do not infer from static and instance fields', () { | 266 test('do not infer from static and instance fields', () { |
296 testChecker({ | 267 testChecker({ |
297 '/a.dart': ''' | 268 '/a.dart': ''' |
298 import 'b.dart'; | 269 import 'b.dart'; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 test1() { | 312 test1() { |
342 int x = 0; | 313 int x = 0; |
343 // inference in A now works. | 314 // inference in A now works. |
344 x = A.a1; | 315 x = A.a1; |
345 x = new A().a2; | 316 x = new A().a2; |
346 } | 317 } |
347 ''' | 318 ''' |
348 }, inferStaticsFromIdentifiers: true); | 319 }, inferStaticsFromIdentifiers: true); |
349 }); | 320 }); |
350 | 321 |
351 test('don\'t infer on cycles', () { | 322 test('inference uses declared types', () { |
| 323 testChecker({ |
| 324 '/main.dart': ''' |
| 325 int w = 0; |
| 326 var x = 0; |
| 327 |
| 328 var y = w; // y can be inferred because w is typed int. |
| 329 var z = x; // z cannot, because x would be inferred. |
| 330 |
| 331 test1() { |
| 332 int a; |
| 333 a = w; |
| 334 a = x; |
| 335 a = y; |
| 336 a = /*info:DownCast*/z; |
| 337 } |
| 338 ''' |
| 339 }, inferStaticsFromIdentifiers: true); |
| 340 }); |
| 341 |
| 342 test('inference in cycles is deterministic', () { |
352 testChecker({ | 343 testChecker({ |
353 '/a.dart': ''' | 344 '/a.dart': ''' |
354 import 'b.dart'; | 345 import 'b.dart'; |
355 class A { | 346 class A { |
356 static final a1 = B.b1; | 347 static final a1 = B.b1; |
357 final a2 = new B().b2; | 348 final a2 = new B().b2; |
358 } | 349 } |
359 ''', | 350 ''', |
360 '/b.dart': ''' | 351 '/b.dart': ''' |
361 class B { | 352 class B { |
362 static final b1 = 1; | 353 static final b1 = 1; |
363 final b2 = 1; | 354 final b2 = 1; |
364 } | 355 } |
365 ''', | 356 ''', |
366 '/c.dart': ''' | 357 '/c.dart': ''' |
367 import "main.dart"; // creates a cycle | 358 import "main.dart"; // creates a cycle |
368 | 359 |
369 class C { | 360 class C { |
370 static final c1 = 1; | 361 static final c1 = 1; |
371 final c2 = 1; | 362 final c2 = 1; |
372 } | 363 } |
373 ''', | 364 ''', |
374 '/e.dart': ''' | 365 '/e.dart': ''' |
375 part "e2.dart"; | 366 import 'a.dart'; |
| 367 part 'e2.dart'; |
376 | 368 |
377 class E { | 369 class E { |
378 static final e1 = 1; | 370 static final e1 = 1; |
379 final e2 = 1; | 371 static final e2 = F.f1; |
| 372 static final e3 = A.a1; |
| 373 final e4 = 1; |
| 374 final e5 = new F().f2; |
| 375 final e6 = new A().a2; |
380 } | 376 } |
381 ''', | 377 ''', |
382 '/f.dart': ''' | 378 '/f.dart': ''' |
383 part "f2.dart"; | 379 part 'f2.dart'; |
384 ''', | 380 ''', |
385 '/e2.dart': ''' | 381 '/e2.dart': ''' |
386 class F { | 382 class F { |
387 static final f1 = 1; | 383 static final f1 = 1; |
388 final f2 = 1; | 384 final f2 = 1; |
389 } | 385 } |
390 ''', | 386 ''', |
391 '/main.dart': ''' | 387 '/main.dart': ''' |
392 import "a.dart"; | 388 import "a.dart"; |
393 import "c.dart"; | 389 import "c.dart"; |
394 import "e.dart"; | 390 import "e.dart"; |
395 | 391 |
396 class D { | 392 class D { |
397 static final d1 = A.a1 + 1; | 393 static final d1 = A.a1 + 1; |
398 static final d2 = C.c1 + 1; | 394 static final d2 = C.c1 + 1; |
399 final d3 = new A().a2; | 395 final d3 = new A().a2; |
400 final d4 = new C().c2; | 396 final d4 = new C().c2; |
401 } | 397 } |
402 | 398 |
403 test1() { | 399 test1() { |
404 int x = 0; | 400 int x = 0; |
405 // inference in A works, it's not in a cycle | 401 // inference in A works, it's not in a cycle |
406 x = A.a1; | 402 x = A.a1; |
407 x = new A().a2; | 403 x = new A().a2; |
408 | 404 |
409 // inference here or in c.dart is disabled because of the cycle | 405 // Within a cycle we allow inference when the RHS is well known, but |
410 x = /*info:DownCast*/C.c1; | 406 // not when it depends on other fields within the cycle |
411 x = /*info:DownCast*/D.d1; | 407 x = C.c1; |
| 408 x = D.d1; |
412 x = /*info:DownCast*/D.d2; | 409 x = /*info:DownCast*/D.d2; |
413 x = /*info:DownCast*/new C().c2; | 410 x = new C().c2; |
414 x = /*info:DownCast*/new D().d3; | 411 x = new D().d3; |
415 x = /*info:DownCast*/new D().d4; | 412 x = /*info:DownCast*/new D().d4; |
416 | 413 |
417 | 414 |
418 // inference in e.dart and f.dart is disabled because they contains | 415 // Similarly if the library contains parts. |
419 // parts | 416 x = E.e1; |
420 x = /*info:DownCast*/E.e1; | 417 x = /*info:DownCast*/E.e2; |
421 x = /*info:DownCast*/new E().e2; | 418 x = E.e3; |
422 x = /*info:DownCast*/F.f1; | 419 x = new E().e4; |
423 x = /*info:DownCast*/new F().f2; | 420 x = /*info:DownCast*/new E().e5; |
| 421 x = new E().e6; |
| 422 x = F.f1; |
| 423 x = new F().f2; |
424 } | 424 } |
425 ''' | 425 ''' |
426 }, inferStaticsFromIdentifiers: true); | 426 }, inferStaticsFromIdentifiers: true); |
427 }); | 427 }); |
428 | 428 |
429 test('infer from complex expressions if the outer-most value is precise', () { | 429 test('infer from complex expressions if the outer-most value is precise', () { |
430 testChecker({ | 430 testChecker({ |
431 '/main.dart': ''' | 431 '/main.dart': ''' |
432 class A { int x; B operator+(other) {} } | 432 class A { int x; B operator+(other) {} } |
433 class B extends A { B(ignore); } | 433 class B extends A { B(ignore); } |
434 var a = new A(); | 434 var a = new A(); |
435 // Note: it doesn't matter that some of these refer to 'x'. | 435 // Note: it doesn't matter that some of these refer to 'x'. |
436 var b = new B(x); // allocations | 436 var b = new B(x); // allocations |
437 var c1 = [x]; // list literals | 437 var c1 = [x]; // list literals |
438 var c2 = const []; | 438 var c2 = const []; |
439 var d = {'a': 'b'}; // map literals | 439 var d = {'a': 'b'}; // map literals |
440 var e = new A()..x = 3; // cascades | 440 var e = new A()..x = 3; // cascades |
441 var f = 2 + 3; // binary expressions are OK if the left operand | 441 var f = 2 + 3; // binary expressions are OK if the left operand |
442 // is from a library in a different strongest | 442 // is from a library in a different strongest |
443 // conected component. | 443 // conected component. |
444 var g = -3; | 444 var g = -3; |
445 var h = new A() + 3; | 445 var h = new A() + 3; |
446 var i = - new A(); | 446 var i = - new A(); |
| 447 var j = null as B; |
447 | 448 |
448 test1() { | 449 test1() { |
449 a = /*severe:StaticTypeError*/"hi"; | 450 a = /*severe:StaticTypeError*/"hi"; |
450 a = new B(3); | 451 a = new B(3); |
451 b = /*severe:StaticTypeError*/"hi"; | 452 b = /*severe:StaticTypeError*/"hi"; |
452 b = new B(3); | 453 b = new B(3); |
453 c1 = []; | 454 c1 = []; |
454 c1 = /*severe:StaticTypeError*/{}; | 455 c1 = /*severe:StaticTypeError*/{}; |
455 c2 = []; | 456 c2 = []; |
456 c2 = /*severe:StaticTypeError*/{}; | 457 c2 = /*severe:StaticTypeError*/{}; |
457 d = {}; | 458 d = {}; |
458 d = /*severe:StaticTypeError*/3; | 459 d = /*severe:StaticTypeError*/3; |
459 e = new A(); | 460 e = new A(); |
460 e = /*severe:StaticTypeError*/{}; | 461 e = /*severe:StaticTypeError*/{}; |
461 f = 3; | 462 f = 3; |
462 f = /*severe:StaticTypeError*/false; | 463 f = /*severe:StaticTypeError*/false; |
463 g = 1; | 464 g = 1; |
464 g = /*severe:StaticTypeError*/false; | 465 g = /*severe:StaticTypeError*/false; |
465 h = /*severe:StaticTypeError*/false; | 466 h = /*severe:StaticTypeError*/false; |
466 h = new B(); | 467 h = new B(); |
467 i = false; | 468 i = false; |
| 469 j = new B(); |
| 470 j = /*severe:StaticTypeError*/false; |
| 471 j = /*severe:StaticTypeError*/[]; |
468 } | 472 } |
469 ''' | 473 ''' |
470 }); | 474 }); |
471 }); | 475 }); |
472 | 476 |
473 test('do not infer if complex expressions read possibly inferred field', () { | 477 test('do not infer if complex expressions read possibly inferred field', () { |
474 testChecker({ | 478 testChecker({ |
475 '/a.dart': ''' | 479 '/a.dart': ''' |
476 class A { | 480 class A { |
477 var x = 3; | 481 var x = 3; |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 } | 809 } |
806 | 810 |
807 foo () { | 811 foo () { |
808 int y = /*severe:StaticTypeError*/new B().m(null, null); | 812 int y = /*severe:StaticTypeError*/new B().m(null, null); |
809 String z = new B().m(null, null); | 813 String z = new B().m(null, null); |
810 } | 814 } |
811 ''' | 815 ''' |
812 }, inferFromOverrides: true); | 816 }, inferFromOverrides: true); |
813 }); | 817 }); |
814 | 818 |
815 // TODO(sigmund): enable this test, it's currently flaky (see issue #48). | 819 test('infer type regardless of declaration order or cycles', () { |
816 skip_test('infer types on generic instantiations in library cycle', () { | 820 testChecker({ |
| 821 '/b.dart': ''' |
| 822 import 'main.dart'; |
| 823 |
| 824 class B extends A { } |
| 825 ''', |
| 826 '/main.dart': ''' |
| 827 import 'b.dart'; |
| 828 class C extends B { |
| 829 get x; |
| 830 } |
| 831 class A { |
| 832 int get x; |
| 833 } |
| 834 foo () { |
| 835 int y = new C().x; |
| 836 String y = /*severe:StaticTypeError*/new C().x; |
| 837 } |
| 838 ''' |
| 839 }, inferFromOverrides: true); |
| 840 }); |
| 841 |
| 842 // Note: this is a regression test for a non-deterministic behavior we used to |
| 843 // have with inference in library cycles. If you see this test flake out, |
| 844 // change `test` to `skip_test` and reopen bug #48. |
| 845 test('infer types on generic instantiations in library cycle', () { |
817 testChecker({ | 846 testChecker({ |
818 '/a.dart': ''' | 847 '/a.dart': ''' |
819 import 'main.dart'; | 848 import 'main.dart'; |
820 abstract class I<E> { | 849 abstract class I<E> { |
821 A<E> m(a, String f(v, T e)); | 850 A<E> m(a, String f(v, T e)); |
822 } | 851 } |
823 ''', | 852 ''', |
824 '/main.dart': ''' | 853 '/main.dart': ''' |
825 import 'a.dart'; | 854 import 'a.dart'; |
826 | 855 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 I3 get a => null; | 954 I3 get a => null; |
926 } | 955 } |
927 | 956 |
928 class C2 extends A implements B { | 957 class C2 extends A implements B { |
929 /*severe:InvalidMethodOverride*/get a => null; | 958 /*severe:InvalidMethodOverride*/get a => null; |
930 } | 959 } |
931 ''' | 960 ''' |
932 }, inferFromOverrides: true); | 961 }, inferFromOverrides: true); |
933 }); | 962 }); |
934 } | 963 } |
OLD | NEW |