| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// Tests for type inference. | |
| 6 library dev_compiler.test.inferred_type_test; | |
| 7 | |
| 8 import 'package:test/test.dart'; | |
| 9 | |
| 10 import '../testing.dart'; | |
| 11 | |
| 12 void main() { | |
| 13 // Error also expected when declared type is `int`. | |
| 14 testChecker('infer type on var', { | |
| 15 '/main.dart': ''' | |
| 16 test1() { | |
| 17 int x = 3; | |
| 18 x = /*severe:StaticTypeError*/"hi"; | |
| 19 } | |
| 20 ''' | |
| 21 }); | |
| 22 | |
| 23 // If inferred type is `int`, error is also reported | |
| 24 testChecker('infer type on var 2', { | |
| 25 '/main.dart': ''' | |
| 26 test2() { | |
| 27 var x = 3; | |
| 28 x = /*severe:StaticTypeError*/"hi"; | |
| 29 } | |
| 30 ''' | |
| 31 }); | |
| 32 | |
| 33 testChecker('No error when declared type is `num` and assigned null.', { | |
| 34 '/main.dart': ''' | |
| 35 test1() { | |
| 36 num x = 3; | |
| 37 x = null; | |
| 38 } | |
| 39 ''' | |
| 40 }); | |
| 41 | |
| 42 testChecker('do not infer type on dynamic', { | |
| 43 '/main.dart': ''' | |
| 44 test() { | |
| 45 dynamic x = 3; | |
| 46 x = "hi"; | |
| 47 } | |
| 48 ''' | |
| 49 }); | |
| 50 | |
| 51 testChecker('do not infer type when initializer is null', { | |
| 52 '/main.dart': ''' | |
| 53 test() { | |
| 54 var x = null; | |
| 55 x = "hi"; | |
| 56 x = 3; | |
| 57 } | |
| 58 ''' | |
| 59 }); | |
| 60 | |
| 61 testChecker('infer type on var from field', { | |
| 62 '/main.dart': ''' | |
| 63 class A { | |
| 64 int x = 0; | |
| 65 | |
| 66 test1() { | |
| 67 var a = x; | |
| 68 a = /*severe:StaticTypeError*/"hi"; | |
| 69 a = 3; | |
| 70 var b = y; | |
| 71 b = /*severe:StaticTypeError*/"hi"; | |
| 72 b = 4; | |
| 73 var c = z; | |
| 74 c = /*severe:StaticTypeError*/"hi"; | |
| 75 c = 4; | |
| 76 } | |
| 77 | |
| 78 int y; // field def after use | |
| 79 final z = 42; // should infer `int` | |
| 80 } | |
| 81 ''' | |
| 82 }); | |
| 83 | |
| 84 testChecker('infer type on var from top-level', { | |
| 85 '/main.dart': ''' | |
| 86 int x = 0; | |
| 87 | |
| 88 test1() { | |
| 89 var a = x; | |
| 90 a = /*severe:StaticTypeError*/"hi"; | |
| 91 a = 3; | |
| 92 var b = y; | |
| 93 b = /*severe:StaticTypeError*/"hi"; | |
| 94 b = 4; | |
| 95 var c = z; | |
| 96 c = /*severe:StaticTypeError*/"hi"; | |
| 97 c = 4; | |
| 98 } | |
| 99 | |
| 100 int y = 0; // field def after use | |
| 101 final z = 42; // should infer `int` | |
| 102 ''' | |
| 103 }); | |
| 104 | |
| 105 testChecker('do not infer field type when initializer is null', { | |
| 106 '/main.dart': ''' | |
| 107 var x = null; | |
| 108 var y = 3; | |
| 109 class A { | |
| 110 static var x = null; | |
| 111 static var y = 3; | |
| 112 | |
| 113 var x2 = null; | |
| 114 var y2 = 3; | |
| 115 } | |
| 116 | |
| 117 test() { | |
| 118 x = "hi"; | |
| 119 y = /*severe:StaticTypeError*/"hi"; | |
| 120 A.x = "hi"; | |
| 121 A.y = /*severe:StaticTypeError*/"hi"; | |
| 122 new A().x2 = "hi"; | |
| 123 new A().y2 = /*severe:StaticTypeError*/"hi"; | |
| 124 } | |
| 125 ''' | |
| 126 }); | |
| 127 | |
| 128 testChecker('infer from variables in non-cycle imports with flag', { | |
| 129 '/a.dart': ''' | |
| 130 var x = 2; | |
| 131 ''', | |
| 132 '/main.dart': ''' | |
| 133 import 'a.dart'; | |
| 134 var y = x; | |
| 135 | |
| 136 test1() { | |
| 137 x = /*severe:StaticTypeError*/"hi"; | |
| 138 y = /*severe:StaticTypeError*/"hi"; | |
| 139 } | |
| 140 ''' | |
| 141 }); | |
| 142 | |
| 143 testChecker('infer from variables in non-cycle imports with flag 2', { | |
| 144 '/a.dart': ''' | |
| 145 class A { static var x = 2; } | |
| 146 ''', | |
| 147 '/main.dart': ''' | |
| 148 import 'a.dart'; | |
| 149 class B { static var y = A.x; } | |
| 150 | |
| 151 test1() { | |
| 152 A.x = /*severe:StaticTypeError*/"hi"; | |
| 153 B.y = /*severe:StaticTypeError*/"hi"; | |
| 154 } | |
| 155 ''' | |
| 156 }); | |
| 157 | |
| 158 testChecker('infer from variables in cycle libs when flag is on', { | |
| 159 '/a.dart': ''' | |
| 160 import 'main.dart'; | |
| 161 var x = 2; // ok to infer | |
| 162 ''', | |
| 163 '/main.dart': ''' | |
| 164 import 'a.dart'; | |
| 165 var y = x; // now ok :) | |
| 166 | |
| 167 test1() { | |
| 168 int t = 3; | |
| 169 t = x; | |
| 170 t = y; | |
| 171 } | |
| 172 ''' | |
| 173 }); | |
| 174 | |
| 175 testChecker('infer from variables in cycle libs when flag is on 2', { | |
| 176 '/a.dart': ''' | |
| 177 import 'main.dart'; | |
| 178 class A { static var x = 2; } | |
| 179 ''', | |
| 180 '/main.dart': ''' | |
| 181 import 'a.dart'; | |
| 182 class B { static var y = A.x; } | |
| 183 | |
| 184 test1() { | |
| 185 int t = 3; | |
| 186 t = A.x; | |
| 187 t = B.y; | |
| 188 } | |
| 189 ''' | |
| 190 }); | |
| 191 | |
| 192 testChecker('can infer also from static and instance fields (flag on)', { | |
| 193 '/a.dart': ''' | |
| 194 import 'b.dart'; | |
| 195 class A { | |
| 196 static final a1 = B.b1; | |
| 197 final a2 = new B().b2; | |
| 198 } | |
| 199 ''', | |
| 200 '/b.dart': ''' | |
| 201 class B { | |
| 202 static final b1 = 1; | |
| 203 final b2 = 1; | |
| 204 } | |
| 205 ''', | |
| 206 '/main.dart': ''' | |
| 207 import "a.dart"; | |
| 208 | |
| 209 test1() { | |
| 210 int x = 0; | |
| 211 // inference in A now works. | |
| 212 x = A.a1; | |
| 213 x = new A().a2; | |
| 214 } | |
| 215 ''' | |
| 216 }); | |
| 217 | |
| 218 testChecker('inference in cycles is deterministic', { | |
| 219 '/a.dart': ''' | |
| 220 import 'b.dart'; | |
| 221 class A { | |
| 222 static final a1 = B.b1; | |
| 223 final a2 = new B().b2; | |
| 224 } | |
| 225 ''', | |
| 226 '/b.dart': ''' | |
| 227 class B { | |
| 228 static final b1 = 1; | |
| 229 final b2 = 1; | |
| 230 } | |
| 231 ''', | |
| 232 '/c.dart': ''' | |
| 233 import "main.dart"; // creates a cycle | |
| 234 | |
| 235 class C { | |
| 236 static final c1 = 1; | |
| 237 final c2 = 1; | |
| 238 } | |
| 239 ''', | |
| 240 '/e.dart': ''' | |
| 241 import 'a.dart'; | |
| 242 part 'e2.dart'; | |
| 243 | |
| 244 class E { | |
| 245 static final e1 = 1; | |
| 246 static final e2 = F.f1; | |
| 247 static final e3 = A.a1; | |
| 248 final e4 = 1; | |
| 249 final e5 = new F().f2; | |
| 250 final e6 = new A().a2; | |
| 251 } | |
| 252 ''', | |
| 253 '/f.dart': ''' | |
| 254 part 'f2.dart'; | |
| 255 ''', | |
| 256 '/e2.dart': ''' | |
| 257 class F { | |
| 258 static final f1 = 1; | |
| 259 final f2 = 1; | |
| 260 } | |
| 261 ''', | |
| 262 '/main.dart': ''' | |
| 263 import "a.dart"; | |
| 264 import "c.dart"; | |
| 265 import "e.dart"; | |
| 266 | |
| 267 class D { | |
| 268 static final d1 = A.a1 + 1; | |
| 269 static final d2 = C.c1 + 1; | |
| 270 final d3 = new A().a2; | |
| 271 final d4 = new C().c2; | |
| 272 } | |
| 273 | |
| 274 test1() { | |
| 275 int x = 0; | |
| 276 // inference in A works, it's not in a cycle | |
| 277 x = A.a1; | |
| 278 x = new A().a2; | |
| 279 | |
| 280 // Within a cycle we allow inference when the RHS is well known, but | |
| 281 // not when it depends on other fields within the cycle | |
| 282 x = C.c1; | |
| 283 x = D.d1; | |
| 284 x = D.d2; | |
| 285 x = new C().c2; | |
| 286 x = new D().d3; | |
| 287 x = /*info:DynamicCast*/new D().d4; | |
| 288 | |
| 289 | |
| 290 // Similarly if the library contains parts. | |
| 291 x = E.e1; | |
| 292 x = E.e2; | |
| 293 x = E.e3; | |
| 294 x = new E().e4; | |
| 295 x = /*info:DynamicCast*/new E().e5; | |
| 296 x = new E().e6; | |
| 297 x = F.f1; | |
| 298 x = new F().f2; | |
| 299 } | |
| 300 ''' | |
| 301 }); | |
| 302 | |
| 303 testChecker( | |
| 304 'infer from complex expressions if the outer-most value is precise', { | |
| 305 '/main.dart': ''' | |
| 306 class A { int x; B operator+(other) {} } | |
| 307 class B extends A { B(ignore); } | |
| 308 var a = new A(); | |
| 309 // Note: it doesn't matter that some of these refer to 'x'. | |
| 310 var b = new B(x); // allocations | |
| 311 var c1 = [x]; // list literals | |
| 312 var c2 = const []; | |
| 313 var d = {'a': 'b'}; // map literals | |
| 314 var e = new A()..x = 3; // cascades | |
| 315 var f = 2 + 3; // binary expressions are OK if the left operand | |
| 316 // is from a library in a different strongest | |
| 317 // conected component. | |
| 318 var g = -3; | |
| 319 var h = new A() + 3; | |
| 320 var i = - new A(); | |
| 321 var j = null as B; | |
| 322 | |
| 323 test1() { | |
| 324 a = /*severe:StaticTypeError*/"hi"; | |
| 325 a = new B(3); | |
| 326 b = /*severe:StaticTypeError*/"hi"; | |
| 327 b = new B(3); | |
| 328 c1 = []; | |
| 329 c1 = /*severe:StaticTypeError*/{}; | |
| 330 c2 = []; | |
| 331 c2 = /*severe:StaticTypeError*/{}; | |
| 332 d = {}; | |
| 333 d = /*severe:StaticTypeError*/3; | |
| 334 e = new A(); | |
| 335 e = /*severe:StaticTypeError*/{}; | |
| 336 f = 3; | |
| 337 f = /*severe:StaticTypeError*/false; | |
| 338 g = 1; | |
| 339 g = /*severe:StaticTypeError*/false; | |
| 340 h = /*severe:StaticTypeError*/false; | |
| 341 h = new B(); | |
| 342 i = false; | |
| 343 j = new B(); | |
| 344 j = /*severe:StaticTypeError*/false; | |
| 345 j = /*severe:StaticTypeError*/[]; | |
| 346 } | |
| 347 ''' | |
| 348 }); | |
| 349 | |
| 350 // but flags can enable this behavior. | |
| 351 testChecker('infer if complex expressions read possibly inferred field', { | |
| 352 '/a.dart': ''' | |
| 353 class A { | |
| 354 var x = 3; | |
| 355 } | |
| 356 ''', | |
| 357 '/main.dart': ''' | |
| 358 import 'a.dart'; | |
| 359 class B { | |
| 360 var y = 3; | |
| 361 } | |
| 362 final t1 = new A(); | |
| 363 final t2 = new A().x; | |
| 364 final t3 = new B(); | |
| 365 final t4 = new B().y; | |
| 366 | |
| 367 test1() { | |
| 368 int i = 0; | |
| 369 A a; | |
| 370 B b; | |
| 371 a = t1; | |
| 372 i = t2; | |
| 373 b = t3; | |
| 374 i = /*info:DynamicCast*/t4; | |
| 375 i = new B().y; // B.y was inferred though | |
| 376 } | |
| 377 ''' | |
| 378 }); | |
| 379 | |
| 380 group('infer types on loop indices', () { | |
| 381 testChecker('foreach loop', { | |
| 382 '/main.dart': ''' | |
| 383 class Foo { | |
| 384 int bar = 42; | |
| 385 } | |
| 386 | |
| 387 test() { | |
| 388 var list = <Foo>[]; | |
| 389 for (var x in list) { | |
| 390 String y = /*severe:StaticTypeError*/x; | |
| 391 } | |
| 392 | |
| 393 for (dynamic x in list) { | |
| 394 String y = /*info:DynamicCast*/x; | |
| 395 } | |
| 396 | |
| 397 for (String x in /*severe:StaticTypeError*/list) { | |
| 398 String y = x; | |
| 399 } | |
| 400 | |
| 401 var z; | |
| 402 for(z in list) { | |
| 403 String y = /*info:DynamicCast*/z; | |
| 404 } | |
| 405 | |
| 406 Iterable iter = list; | |
| 407 for (Foo x in /*warning:DownCastComposite*/iter) { | |
| 408 var y = x; | |
| 409 } | |
| 410 | |
| 411 dynamic iter2 = list; | |
| 412 for (Foo x in /*warning:DownCastComposite*/iter2) { | |
| 413 var y = x; | |
| 414 } | |
| 415 | |
| 416 var map = <String, Foo>{}; | |
| 417 // Error: map must be an Iterable. | |
| 418 for (var x in /*severe:StaticTypeError*/map) { | |
| 419 String y = /*info:DynamicCast*/x; | |
| 420 } | |
| 421 | |
| 422 // We're not properly inferring that map.keys is an Iterable<String> | |
| 423 // and that x is a String. | |
| 424 for (var x in map.keys) { | |
| 425 String y = x; | |
| 426 } | |
| 427 } | |
| 428 ''' | |
| 429 }); | |
| 430 | |
| 431 testChecker('for loop, with inference', { | |
| 432 '/main.dart': ''' | |
| 433 test() { | |
| 434 for (var i = 0; i < 10; i++) { | |
| 435 int j = i + 1; | |
| 436 } | |
| 437 } | |
| 438 ''' | |
| 439 }); | |
| 440 }); | |
| 441 | |
| 442 testChecker('propagate inference to field in class', { | |
| 443 '/main.dart': ''' | |
| 444 class A { | |
| 445 int x = 2; | |
| 446 } | |
| 447 | |
| 448 test() { | |
| 449 var a = new A(); | |
| 450 A b = a; // doesn't require down cast | |
| 451 print(a.x); // doesn't require dynamic invoke | |
| 452 print(a.x + 2); // ok to use in bigger expression | |
| 453 } | |
| 454 ''' | |
| 455 }); | |
| 456 | |
| 457 testChecker('propagate inference to field in class dynamic warnings', { | |
| 458 '/main.dart': ''' | |
| 459 class A { | |
| 460 int x = 2; | |
| 461 } | |
| 462 | |
| 463 test() { | |
| 464 dynamic a = new A(); | |
| 465 A b = /*info:DynamicCast*/a; | |
| 466 print(/*info:DynamicInvoke*/a.x); | |
| 467 print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2); | |
| 468 } | |
| 469 ''' | |
| 470 }); | |
| 471 | |
| 472 testChecker('propagate inference transitively', { | |
| 473 '/main.dart': ''' | |
| 474 class A { | |
| 475 int x = 2; | |
| 476 } | |
| 477 | |
| 478 test5() { | |
| 479 var a1 = new A(); | |
| 480 a1.x = /*severe:StaticTypeError*/"hi"; | |
| 481 | |
| 482 A a2 = new A(); | |
| 483 a2.x = /*severe:StaticTypeError*/"hi"; | |
| 484 } | |
| 485 ''' | |
| 486 }); | |
| 487 | |
| 488 testChecker('propagate inference transitively 2', { | |
| 489 '/main.dart': ''' | |
| 490 class A { | |
| 491 int x = 42; | |
| 492 } | |
| 493 | |
| 494 class B { | |
| 495 A a = new A(); | |
| 496 } | |
| 497 | |
| 498 class C { | |
| 499 B b = new B(); | |
| 500 } | |
| 501 | |
| 502 class D { | |
| 503 C c = new C(); | |
| 504 } | |
| 505 | |
| 506 void main() { | |
| 507 var d1 = new D(); | |
| 508 print(d1.c.b.a.x); | |
| 509 | |
| 510 D d2 = new D(); | |
| 511 print(d2.c.b.a.x); | |
| 512 } | |
| 513 ''' | |
| 514 }); | |
| 515 | |
| 516 group('infer type on overridden fields', () { | |
| 517 testChecker('2', { | |
| 518 '/main.dart': ''' | |
| 519 class A { | |
| 520 int x = 2; | |
| 521 } | |
| 522 | |
| 523 class B extends A { | |
| 524 get x => 3; | |
| 525 } | |
| 526 | |
| 527 foo() { | |
| 528 String y = /*severe:StaticTypeError*/new B().x; | |
| 529 int z = new B().x; | |
| 530 } | |
| 531 ''' | |
| 532 }); | |
| 533 | |
| 534 testChecker('4', { | |
| 535 '/main.dart': ''' | |
| 536 class A { | |
| 537 int x = 2; | |
| 538 } | |
| 539 | |
| 540 class B implements A { | |
| 541 get x => 3; | |
| 542 } | |
| 543 | |
| 544 foo() { | |
| 545 String y = /*severe:StaticTypeError*/new B().x; | |
| 546 int z = new B().x; | |
| 547 } | |
| 548 ''' | |
| 549 }); | |
| 550 }); | |
| 551 | |
| 552 group('infer types on generic instantiations', () { | |
| 553 testChecker('infer', { | |
| 554 '/main.dart': ''' | |
| 555 class A<T> { | |
| 556 T x; | |
| 557 } | |
| 558 | |
| 559 class B implements A<int> { | |
| 560 /*severe:InvalidMethodOverride*/dynamic get x => 3; | |
| 561 } | |
| 562 | |
| 563 foo() { | |
| 564 String y = /*info:DynamicCast*/new B().x; | |
| 565 int z = /*info:DynamicCast*/new B().x; | |
| 566 } | |
| 567 ''' | |
| 568 }); | |
| 569 | |
| 570 testChecker('3', { | |
| 571 '/main.dart': ''' | |
| 572 class A<T> { | |
| 573 T x; | |
| 574 T w; | |
| 575 } | |
| 576 | |
| 577 class B implements A<int> { | |
| 578 get x => 3; | |
| 579 get w => /*severe:StaticTypeError*/"hello"; | |
| 580 } | |
| 581 | |
| 582 foo() { | |
| 583 String y = /*severe:StaticTypeError*/new B().x; | |
| 584 int z = new B().x; | |
| 585 } | |
| 586 ''' | |
| 587 }); | |
| 588 | |
| 589 testChecker('4', { | |
| 590 '/main.dart': ''' | |
| 591 class A<T> { | |
| 592 T x; | |
| 593 } | |
| 594 | |
| 595 class B<E> extends A<E> { | |
| 596 E y; | |
| 597 get x => y; | |
| 598 } | |
| 599 | |
| 600 foo() { | |
| 601 int y = /*severe:StaticTypeError*/new B<String>().x; | |
| 602 String z = new B<String>().x; | |
| 603 } | |
| 604 ''' | |
| 605 }); | |
| 606 | |
| 607 testChecker('5', { | |
| 608 '/main.dart': ''' | |
| 609 abstract class I<E> { | |
| 610 String m(a, String f(v, T e)); | |
| 611 } | |
| 612 | |
| 613 abstract class A<E> implements I<E> { | |
| 614 const A(); | |
| 615 String m(a, String f(v, T e)); | |
| 616 } | |
| 617 | |
| 618 abstract class M { | |
| 619 int y; | |
| 620 } | |
| 621 | |
| 622 class B<E> extends A<E> implements M { | |
| 623 const B(); | |
| 624 int get y => 0; | |
| 625 | |
| 626 m(a, f(v, T e)) {} | |
| 627 } | |
| 628 | |
| 629 foo () { | |
| 630 int y = /*severe:StaticTypeError*/new B().m(null, null); | |
| 631 String z = new B().m(null, null); | |
| 632 } | |
| 633 ''' | |
| 634 }); | |
| 635 }); | |
| 636 | |
| 637 testChecker('infer type regardless of declaration order or cycles', { | |
| 638 '/b.dart': ''' | |
| 639 import 'main.dart'; | |
| 640 | |
| 641 class B extends A { } | |
| 642 ''', | |
| 643 '/main.dart': ''' | |
| 644 import 'b.dart'; | |
| 645 class C extends B { | |
| 646 get x; | |
| 647 } | |
| 648 class A { | |
| 649 int get x; | |
| 650 } | |
| 651 foo () { | |
| 652 int y = new C().x; | |
| 653 String y = /*severe:StaticTypeError*/new C().x; | |
| 654 } | |
| 655 ''' | |
| 656 }); | |
| 657 | |
| 658 // Note: this is a regression test for a non-deterministic behavior we used to | |
| 659 // have with inference in library cycles. If you see this test flake out, | |
| 660 // change `test` to `skip_test` and reopen bug #48. | |
| 661 testChecker('infer types on generic instantiations in library cycle', { | |
| 662 '/a.dart': ''' | |
| 663 import 'main.dart'; | |
| 664 abstract class I<E> { | |
| 665 A<E> m(a, String f(v, int e)); | |
| 666 } | |
| 667 ''', | |
| 668 '/main.dart': ''' | |
| 669 import 'a.dart'; | |
| 670 | |
| 671 abstract class A<E> implements I<E> { | |
| 672 const A(); | |
| 673 | |
| 674 E value; | |
| 675 } | |
| 676 | |
| 677 abstract class M { | |
| 678 int y; | |
| 679 } | |
| 680 | |
| 681 class B<E> extends A<E> implements M { | |
| 682 const B(); | |
| 683 int get y => 0; | |
| 684 | |
| 685 m(a, f(v, int e)) {} | |
| 686 } | |
| 687 | |
| 688 foo () { | |
| 689 int y = /*severe:StaticTypeError*/new B<String>().m(null, null).value; | |
| 690 String z = new B<String>().m(null, null).value; | |
| 691 } | |
| 692 ''' | |
| 693 }); | |
| 694 | |
| 695 group('do not infer overridden fields that explicitly say dynamic', () { | |
| 696 testChecker('infer', { | |
| 697 '/main.dart': ''' | |
| 698 class A { | |
| 699 int x = 2; | |
| 700 } | |
| 701 | |
| 702 class B implements A { | |
| 703 /*severe:InvalidMethodOverride*/dynamic get x => 3; | |
| 704 } | |
| 705 | |
| 706 foo() { | |
| 707 String y = /*info:DynamicCast*/new B().x; | |
| 708 int z = /*info:DynamicCast*/new B().x; | |
| 709 } | |
| 710 ''' | |
| 711 }); | |
| 712 }); | |
| 713 | |
| 714 testChecker('conflicts can happen', { | |
| 715 '/main.dart': ''' | |
| 716 class I1 { | |
| 717 int x; | |
| 718 } | |
| 719 class I2 extends I1 { | |
| 720 int y; | |
| 721 } | |
| 722 | |
| 723 class A { | |
| 724 final I1 a; | |
| 725 } | |
| 726 | |
| 727 class B { | |
| 728 final I2 a; | |
| 729 } | |
| 730 | |
| 731 class C1 extends A implements B { | |
| 732 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a =>
null; | |
| 733 } | |
| 734 | |
| 735 // Still ambiguous | |
| 736 class C2 extends B implements A { | |
| 737 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a =>
null; | |
| 738 } | |
| 739 ''' | |
| 740 }); | |
| 741 | |
| 742 testChecker('conflicts can happen 2', { | |
| 743 '/main.dart': ''' | |
| 744 class I1 { | |
| 745 int x; | |
| 746 } | |
| 747 class I2 { | |
| 748 int y; | |
| 749 } | |
| 750 | |
| 751 class I3 implements I1, I2 { | |
| 752 int x; | |
| 753 int y; | |
| 754 } | |
| 755 | |
| 756 class A { | |
| 757 final I1 a; | |
| 758 } | |
| 759 | |
| 760 class B { | |
| 761 final I2 a; | |
| 762 } | |
| 763 | |
| 764 class C1 extends A implements B { | |
| 765 I3 get a => null; | |
| 766 } | |
| 767 | |
| 768 class C2 extends A implements B { | |
| 769 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/get a =>
null; | |
| 770 } | |
| 771 ''' | |
| 772 }); | |
| 773 | |
| 774 testChecker( | |
| 775 'infer from RHS only if it wont conflict with overridden fields', { | |
| 776 '/main.dart': ''' | |
| 777 class A { | |
| 778 var x; | |
| 779 } | |
| 780 | |
| 781 class B extends A { | |
| 782 var x = 2; | |
| 783 } | |
| 784 | |
| 785 foo() { | |
| 786 String y = /*info:DynamicCast*/new B().x; | |
| 787 int z = /*info:DynamicCast*/new B().x; | |
| 788 } | |
| 789 ''' | |
| 790 }); | |
| 791 | |
| 792 testChecker( | |
| 793 'infer from RHS only if it wont conflict with overridden fields 2', { | |
| 794 '/main.dart': ''' | |
| 795 class A { | |
| 796 final x; | |
| 797 } | |
| 798 | |
| 799 class B extends A { | |
| 800 final x = 2; | |
| 801 } | |
| 802 | |
| 803 foo() { | |
| 804 String y = /*severe:StaticTypeError*/new B().x; | |
| 805 int z = new B().x; | |
| 806 } | |
| 807 ''' | |
| 808 }); | |
| 809 | |
| 810 testChecker('infer correctly on multiple variables declared together', { | |
| 811 '/main.dart': ''' | |
| 812 class A { | |
| 813 var x, y = 2, z = "hi"; | |
| 814 } | |
| 815 | |
| 816 class B extends A { | |
| 817 var x = 2, y = 3, z, w = 2; | |
| 818 } | |
| 819 | |
| 820 foo() { | |
| 821 String s; | |
| 822 int i; | |
| 823 | |
| 824 s = /*info:DynamicCast*/new B().x; | |
| 825 s = /*severe:StaticTypeError*/new B().y; | |
| 826 s = new B().z; | |
| 827 s = /*severe:StaticTypeError*/new B().w; | |
| 828 | |
| 829 i = /*info:DynamicCast*/new B().x; | |
| 830 i = new B().y; | |
| 831 i = /*severe:StaticTypeError*/new B().z; | |
| 832 i = new B().w; | |
| 833 } | |
| 834 ''' | |
| 835 }); | |
| 836 | |
| 837 testChecker('infer consts transitively', { | |
| 838 '/b.dart': ''' | |
| 839 const b1 = 2; | |
| 840 ''', | |
| 841 '/a.dart': ''' | |
| 842 import 'main.dart'; | |
| 843 import 'b.dart'; | |
| 844 const a1 = m2; | |
| 845 const a2 = b1; | |
| 846 ''', | |
| 847 '/main.dart': ''' | |
| 848 import 'a.dart'; | |
| 849 const m1 = a1; | |
| 850 const m2 = a2; | |
| 851 | |
| 852 foo() { | |
| 853 int i; | |
| 854 i = m1; | |
| 855 } | |
| 856 ''' | |
| 857 }); | |
| 858 | |
| 859 testChecker('infer statics transitively', { | |
| 860 '/b.dart': ''' | |
| 861 final b1 = 2; | |
| 862 ''', | |
| 863 '/a.dart': ''' | |
| 864 import 'main.dart'; | |
| 865 import 'b.dart'; | |
| 866 final a1 = m2; | |
| 867 class A { | |
| 868 static final a2 = b1; | |
| 869 } | |
| 870 ''', | |
| 871 '/main.dart': ''' | |
| 872 import 'a.dart'; | |
| 873 final m1 = a1; | |
| 874 final m2 = A.a2; | |
| 875 | |
| 876 foo() { | |
| 877 int i; | |
| 878 i = m1; | |
| 879 } | |
| 880 ''' | |
| 881 }); | |
| 882 | |
| 883 testChecker('infer statics transitively 2', { | |
| 884 '/main.dart': ''' | |
| 885 const x1 = 1; | |
| 886 final x2 = 1; | |
| 887 final y1 = x1; | |
| 888 final y2 = x2; | |
| 889 | |
| 890 foo() { | |
| 891 int i; | |
| 892 i = y1; | |
| 893 i = y2; | |
| 894 } | |
| 895 ''' | |
| 896 }); | |
| 897 | |
| 898 testChecker('infer statics transitively 3', { | |
| 899 '/a.dart': ''' | |
| 900 const a1 = 3; | |
| 901 const a2 = 4; | |
| 902 class A { | |
| 903 a3; | |
| 904 } | |
| 905 ''', | |
| 906 '/main.dart': ''' | |
| 907 import 'a.dart' show a1, A; | |
| 908 import 'a.dart' as p show a2, A; | |
| 909 const t1 = 1; | |
| 910 const t2 = t1; | |
| 911 const t3 = a1; | |
| 912 const t4 = p.a2; | |
| 913 const t5 = A.a3; | |
| 914 const t6 = p.A.a3; | |
| 915 | |
| 916 foo() { | |
| 917 int i; | |
| 918 i = t1; | |
| 919 i = t2; | |
| 920 i = t3; | |
| 921 i = t4; | |
| 922 } | |
| 923 ''' | |
| 924 }); | |
| 925 | |
| 926 testChecker('infer statics with method invocations', { | |
| 927 '/a.dart': ''' | |
| 928 m3(String a, String b, [a1,a2]) {} | |
| 929 ''', | |
| 930 '/main.dart': ''' | |
| 931 import 'a.dart'; | |
| 932 class T { | |
| 933 static final T foo = m1(m2(m3('', ''))); | |
| 934 static T m1(String m) { return null; } | |
| 935 static String m2(e) { return ''; } | |
| 936 } | |
| 937 | |
| 938 | |
| 939 ''' | |
| 940 }); | |
| 941 | |
| 942 testChecker('downwards inference: miscellaneous', { | |
| 943 '/main.dart': ''' | |
| 944 typedef (T x); | |
| 945 class A<T> { | |
| 946 Function2<T> x; | |
| 947 A(this.x); | |
| 948 } | |
| 949 void main() { | |
| 950 { // Variables, nested literals | |
| 951 var x = "hello"; | |
| 952 var y = 3; | |
| 953 void f(List<Map<int, String>> l) {}; | |
| 954 f(/*info:InferredTypeLiteral*/[{y: x}]); | |
| 955 } | |
| 956 { | |
| 957 int f(int x) {}; | |
| 958 A<int> a = /*info:InferredTypeAllocation*/new A(f); | |
| 959 } | |
| 960 } | |
| 961 ''' | |
| 962 }); | |
| 963 | |
| 964 group('downwards inference on instance creations', () { | |
| 965 String info = 'info:InferredTypeAllocation'; | |
| 966 String code = ''' | |
| 967 class A<S, T> { | |
| 968 S x; | |
| 969 T y; | |
| 970 A(this.x, this.y); | |
| 971 A.named(this.x, this.y); | |
| 972 } | |
| 973 | |
| 974 class B<S, T> extends A<T, S> { | |
| 975 B(S y, T x) : super(x, y); | |
| 976 B.named(S y, T x) : super.named(x, y); | |
| 977 } | |
| 978 | |
| 979 class C<S> extends B<S, S> { | |
| 980 C(S a) : super(a, a); | |
| 981 C.named(S a) : super.named(a, a); | |
| 982 } | |
| 983 | |
| 984 class D<S, T> extends B<T, int> { | |
| 985 D(T a) : super(a, 3); | |
| 986 D.named(T a) : super.named(a, 3); | |
| 987 } | |
| 988 | |
| 989 class E<S, T> extends A<C<S>, T> { | |
| 990 E(T a) : super(null, a); | |
| 991 } | |
| 992 | |
| 993 class F<S, T> extends A<S, T> { | |
| 994 F(S x, T y, {List<S> a, List<T> b}) : super(x, y); | |
| 995 F.named(S x, T y, [S a, T b]) : super(a, b); | |
| 996 } | |
| 997 | |
| 998 void main() { | |
| 999 { | |
| 1000 A<int, String> a0 = /*$info*/new A(3, "hello"); | |
| 1001 A<int, String> a1 = /*$info*/new A.named(3, "hello"); | |
| 1002 A<int, String> a2 = new A<int, String>(3, "hello"); | |
| 1003 A<int, String> a3 = new A<int, String>.named(3, "hello"); | |
| 1004 A<int, String> a4 = /*severe:StaticTypeError*/new A<int, dynamic>(3, "
hello"); | |
| 1005 A<int, String> a5 = /*severe:StaticTypeError*/new A<dynamic, dynamic>.
named(3, "hello"); | |
| 1006 } | |
| 1007 { | |
| 1008 A<int, String> a0 = /*severe:StaticTypeError*/new A("hello", 3); | |
| 1009 A<int, String> a1 = /*severe:StaticTypeError*/new A.named("hello", 3); | |
| 1010 } | |
| 1011 { | |
| 1012 A<int, String> a0 = /*$info*/new B("hello", 3); | |
| 1013 A<int, String> a1 = /*$info*/new B.named("hello", 3); | |
| 1014 A<int, String> a2 = new B<String, int>("hello", 3); | |
| 1015 A<int, String> a3 = new B<String, int>.named("hello", 3); | |
| 1016 A<int, String> a4 = /*severe:StaticTypeError*/new B<String, dynamic>("
hello", 3); | |
| 1017 A<int, String> a5 = /*severe:StaticTypeError*/new B<dynamic, dynamic>.
named("hello", 3); | |
| 1018 } | |
| 1019 { | |
| 1020 A<int, String> a0 = /*severe:StaticTypeError*/new B(3, "hello"); | |
| 1021 A<int, String> a1 = /*severe:StaticTypeError*/new B.named(3, "hello"); | |
| 1022 } | |
| 1023 { | |
| 1024 A<int, int> a0 = /*$info*/new C(3); | |
| 1025 A<int, int> a1 = /*$info*/new C.named(3); | |
| 1026 A<int, int> a2 = new C<int>(3); | |
| 1027 A<int, int> a3 = new C<int>.named(3); | |
| 1028 A<int, int> a4 = /*severe:StaticTypeError*/new C<dynamic>(3); | |
| 1029 A<int, int> a5 = /*severe:StaticTypeError*/new C<dynamic>.named(3); | |
| 1030 } | |
| 1031 { | |
| 1032 A<int, int> a0 = /*severe:StaticTypeError*/new C("hello"); | |
| 1033 A<int, int> a1 = /*severe:StaticTypeError*/new C.named("hello"); | |
| 1034 } | |
| 1035 { | |
| 1036 A<int, String> a0 = /*$info*/new D("hello"); | |
| 1037 A<int, String> a1 = /*$info*/new D.named("hello"); | |
| 1038 A<int, String> a2 = new D<int, String>("hello"); | |
| 1039 A<int, String> a3 = new D<String, String>.named("hello"); | |
| 1040 A<int, String> a4 = /*severe:StaticTypeError*/new D<num, dynamic>("hel
lo"); | |
| 1041 A<int, String> a5 = /*severe:StaticTypeError*/new D<dynamic, dynamic>.
named("hello"); | |
| 1042 } | |
| 1043 { | |
| 1044 A<int, String> a0 = /*severe:StaticTypeError*/new D(3); | |
| 1045 A<int, String> a1 = /*severe:StaticTypeError*/new D.named(3); | |
| 1046 } | |
| 1047 { // Currently we only allow variable constraints. Test that we reject. | |
| 1048 A<C<int>, String> a0 = /*severe:StaticTypeError*/new E("hello"); | |
| 1049 } | |
| 1050 { // Check named and optional arguments | |
| 1051 A<int, String> a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]); | |
| 1052 A<int, String> a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["h
ello"], b:[3]); | |
| 1053 A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello"); | |
| 1054 A<int, String> a3 = /*$info*/new F.named(3, "hello"); | |
| 1055 A<int, String> a4 = /*severe:StaticTypeError*/new F.named(3, "hello",
"hello", 3); | |
| 1056 A<int, String> a5 = /*severe:StaticTypeError*/new F.named(3, "hello",
"hello"); | |
| 1057 } | |
| 1058 } | |
| 1059 '''; | |
| 1060 testChecker('infer downwards', {'/main.dart': code}); | |
| 1061 }); | |
| 1062 | |
| 1063 group('downwards inference on list literals', () { | |
| 1064 String info = "info:InferredTypeLiteral"; | |
| 1065 String code = ''' | |
| 1066 void foo([List<String> list1 = /*$info*/const [], | |
| 1067 List<String> list2 = /*severe:StaticTypeError*/const [42]]) { | |
| 1068 } | |
| 1069 | |
| 1070 void main() { | |
| 1071 { | |
| 1072 List<int> l0 = /*$info*/[]; | |
| 1073 List<int> l1 = /*$info*/[3]; | |
| 1074 List<int> l2 = /*severe:StaticTypeError*/["hello"]; | |
| 1075 List<int> l3 = /*severe:StaticTypeError*/["hello", 3]; | |
| 1076 } | |
| 1077 { | |
| 1078 List<dynamic> l0 = []; | |
| 1079 List<dynamic> l1 = [3]; | |
| 1080 List<dynamic> l2 = ["hello"]; | |
| 1081 List<dynamic> l3 = ["hello", 3]; | |
| 1082 } | |
| 1083 { | |
| 1084 List<int> l0 = /*severe:StaticTypeError*/<num>[]; | |
| 1085 List<int> l1 = /*severe:StaticTypeError*/<num>[3]; | |
| 1086 List<int> l2 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeErro
r*/"hello"]; | |
| 1087 List<int> l3 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeErro
r*/"hello", 3]; | |
| 1088 } | |
| 1089 { | |
| 1090 Iterable<int> i0 = /*$info*/[]; | |
| 1091 Iterable<int> i1 = /*$info*/[3]; | |
| 1092 Iterable<int> i2 = /*severe:StaticTypeError*/["hello"]; | |
| 1093 Iterable<int> i3 = /*severe:StaticTypeError*/["hello", 3]; | |
| 1094 } | |
| 1095 { | |
| 1096 const List<int> c0 = /*$info*/const []; | |
| 1097 const List<int> c1 = /*$info*/const [3]; | |
| 1098 const List<int> c2 = /*severe:StaticTypeError*/const ["hello"]; | |
| 1099 const List<int> c3 = /*severe:StaticTypeError*/const ["hello", 3]; | |
| 1100 } | |
| 1101 } | |
| 1102 '''; | |
| 1103 testChecker('infer downwards', {'/main.dart': code}); | |
| 1104 }); | |
| 1105 | |
| 1106 group('downwards inference on function arguments', () { | |
| 1107 String info = "info:InferredTypeLiteral"; | |
| 1108 String code = ''' | |
| 1109 void f0(List<int> a) {}; | |
| 1110 void f1({List<int> a}) {}; | |
| 1111 void f2(Iterable<int> a) {}; | |
| 1112 void f3(Iterable<Iterable<int>> a) {}; | |
| 1113 void f4({Iterable<Iterable<int>> a}) {}; | |
| 1114 void main() { | |
| 1115 f0(/*$info*/[]); | |
| 1116 f0(/*$info*/[3]); | |
| 1117 f0(/*severe:StaticTypeError*/["hello"]); | |
| 1118 f0(/*severe:StaticTypeError*/["hello", 3]); | |
| 1119 | |
| 1120 f1(a: /*$info*/[]); | |
| 1121 f1(a: /*$info*/[3]); | |
| 1122 f1(a: /*severe:StaticTypeError*/["hello"]); | |
| 1123 f1(a: /*severe:StaticTypeError*/["hello", 3]); | |
| 1124 | |
| 1125 f2(/*$info*/[]); | |
| 1126 f2(/*$info*/[3]); | |
| 1127 f2(/*severe:StaticTypeError*/["hello"]); | |
| 1128 f2(/*severe:StaticTypeError*/["hello", 3]); | |
| 1129 | |
| 1130 f3(/*$info*/[]); | |
| 1131 f3(/*$info*/[[3]]); | |
| 1132 f3(/*severe:StaticTypeError*/[["hello"]]); | |
| 1133 f3(/*severe:StaticTypeError*/[["hello"], [3]]); | |
| 1134 | |
| 1135 f4(a: /*$info*/[]); | |
| 1136 f4(a: /*$info*/[[3]]); | |
| 1137 f4(a: /*severe:StaticTypeError*/[["hello"]]); | |
| 1138 f4(a: /*severe:StaticTypeError*/[["hello"], [3]]); | |
| 1139 } | |
| 1140 '''; | |
| 1141 testChecker('infer downwards', {'/main.dart': code}); | |
| 1142 }); | |
| 1143 | |
| 1144 group('downwards inference on map literals', () { | |
| 1145 String info = "info:InferredTypeLiteral"; | |
| 1146 String code = ''' | |
| 1147 void foo([Map<int, String> m1 = /*$info*/const {1: "hello"}, | |
| 1148 Map<int, String> m1 = /*severe:StaticTypeError*/const {"hello":
"world"}]) { | |
| 1149 } | |
| 1150 void main() { | |
| 1151 { | |
| 1152 Map<int, String> l0 = /*$info*/{}; | |
| 1153 Map<int, String> l1 = /*$info*/{3: "hello"}; | |
| 1154 Map<int, String> l2 = /*severe:StaticTypeError*/{"hello": "hello"}; | |
| 1155 Map<int, String> l3 = /*severe:StaticTypeError*/{3: 3}; | |
| 1156 Map<int, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3
}; | |
| 1157 } | |
| 1158 { | |
| 1159 Map<dynamic, dynamic> l0 = {}; | |
| 1160 Map<dynamic, dynamic> l1 = {3: "hello"}; | |
| 1161 Map<dynamic, dynamic> l2 = {"hello": "hello"}; | |
| 1162 Map<dynamic, dynamic> l3 = {3: 3}; | |
| 1163 Map<dynamic, dynamic> l4 = {3:"hello", "hello": 3}; | |
| 1164 } | |
| 1165 { | |
| 1166 Map<dynamic, String> l0 = /*$info*/{}; | |
| 1167 Map<dynamic, String> l1 = /*$info*/{3: "hello"}; | |
| 1168 Map<dynamic, String> l2 = /*$info*/{"hello": "hello"}; | |
| 1169 Map<dynamic, String> l3 = /*severe:StaticTypeError*/{3: 3}; | |
| 1170 Map<dynamic, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello
": 3}; | |
| 1171 } | |
| 1172 { | |
| 1173 Map<int, dynamic> l0 = /*$info*/{}; | |
| 1174 Map<int, dynamic> l1 = /*$info*/{3: "hello"}; | |
| 1175 Map<int, dynamic> l2 = /*severe:StaticTypeError*/{"hello": "hello"}; | |
| 1176 Map<int, dynamic> l3 = /*$info*/{3: 3}; | |
| 1177 Map<int, dynamic> l3 = /*severe:StaticTypeError*/{3:"hello", "hello":
3}; | |
| 1178 } | |
| 1179 { | |
| 1180 Map<int, String> l0 = /*severe:StaticTypeError*/<num, dynamic>{}; | |
| 1181 Map<int, String> l1 = /*severe:StaticTypeError*/<num, dynamic>{3: "hel
lo"}; | |
| 1182 Map<int, String> l3 = /*severe:StaticTypeError*/<num, dynamic>{3: 3}; | |
| 1183 } | |
| 1184 { | |
| 1185 const Map<int, String> l0 = /*$info*/const {}; | |
| 1186 const Map<int, String> l1 = /*$info*/const {3: "hello"}; | |
| 1187 const Map<int, String> l2 = /*severe:StaticTypeError*/const {"hello":
"hello"}; | |
| 1188 const Map<int, String> l3 = /*severe:StaticTypeError*/const {3: 3}; | |
| 1189 const Map<int, String> l4 = /*severe:StaticTypeError*/const {3:"hello"
, "hello": 3}; | |
| 1190 } | |
| 1191 } | |
| 1192 '''; | |
| 1193 testChecker('infer downwards', {'/main.dart': code}); | |
| 1194 }); | |
| 1195 | |
| 1196 testChecker('downwards inference on function expressions', { | |
| 1197 '/main.dart': ''' | |
| 1198 typedef T Function2<S, T>(S x); | |
| 1199 | |
| 1200 void main () { | |
| 1201 { | |
| 1202 Function2<int, String> l0 = (int x) => null; | |
| 1203 Function2<int, String> l1 = (int x) => "hello"; | |
| 1204 Function2<int, String> l2 = /*severe:StaticTypeError*/(String x) => "h
ello"; | |
| 1205 Function2<int, String> l3 = /*severe:StaticTypeError*/(int x) => 3; | |
| 1206 Function2<int, String> l4 = /*warning:UninferredClosure should be seve
re:StaticTypeError*/(int x) {return 3}; | |
| 1207 } | |
| 1208 { | |
| 1209 Function2<int, String> l0 = /*info:InferredTypeClosure*/(x) => null; | |
| 1210 Function2<int, String> l1 = /*info:InferredTypeClosure*/(x) => "hello"
; | |
| 1211 Function2<int, String> l2 = /*severe:StaticTypeError*/(x) => 3; | |
| 1212 Function2<int, String> l3 = /*warning:UninferredClosure should be seve
re:StaticTypeError*/(x) {return 3}; | |
| 1213 } | |
| 1214 { | |
| 1215 Function2<int, List<String>> l0 = (int x) => null; | |
| 1216 Function2<int, List<String>> l1 = /*info:InferredTypeClosure*/(int x)
=> ["hello"]; | |
| 1217 Function2<int, List<String>> l2 = /*severe:StaticTypeError*/(String x)
=> ["hello"]; | |
| 1218 Function2<int, List<String>> l3 = /*warning:UninferredClosure should b
e severe:StaticTypeError*/(int x) => [3]; | |
| 1219 Function2<int, List<String>> l4 = /*warning:UninferredClosure should b
e severe:StaticTypeError*/(int x) {return [3]}; | |
| 1220 } | |
| 1221 { | |
| 1222 Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x; | |
| 1223 Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:Dyn
amicInvoke should be pass*/x+1; | |
| 1224 Function2<int, String> l2 = /*info:InferredTypeClosure should be sever
e:StaticTypeError*/(x) => x; | |
| 1225 Function2<int, String> l3 = /*info:InferredTypeClosure should be sever
e:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3); | |
| 1226 Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*in
fo:DynamicInvoke should be pass*/x.substring(3); | |
| 1227 } | |
| 1228 } | |
| 1229 ''' | |
| 1230 }); | |
| 1231 | |
| 1232 testChecker('inferred initializing formal checks default value', { | |
| 1233 '/main.dart': ''' | |
| 1234 class Foo { | |
| 1235 var x = 1; | |
| 1236 Foo([this.x = /*severe:StaticTypeError*/"1"]); | |
| 1237 }''' | |
| 1238 }); | |
| 1239 | |
| 1240 group('quasi-generics', () { | |
| 1241 testChecker('dart:math min/max', { | |
| 1242 '/main.dart': ''' | |
| 1243 import 'dart:math'; | |
| 1244 | |
| 1245 void printInt(int x) => print(x); | |
| 1246 void printDouble(double x) => print(x); | |
| 1247 | |
| 1248 num myMax(num x, num y) => max(x, y); | |
| 1249 | |
| 1250 main() { | |
| 1251 // Okay if static types match. | |
| 1252 printInt(max(1, 2)); | |
| 1253 printInt(min(1, 2)); | |
| 1254 printDouble(max(1.0, 2.0)); | |
| 1255 printDouble(min(1.0, 2.0)); | |
| 1256 | |
| 1257 // No help for user-defined functions from num->num->num. | |
| 1258 printInt(/*info:DownCastImplicit*/myMax(1, 2)); | |
| 1259 printInt(myMax(1, 2) as int); | |
| 1260 | |
| 1261 // Mixing int and double means return type is num. | |
| 1262 printInt(/*info:DownCastImplicit*/max(1, 2.0)); | |
| 1263 printInt(/*info:DownCastImplicit*/min(1, 2.0)); | |
| 1264 printDouble(/*info:DownCastImplicit*/max(1, 2.0)); | |
| 1265 printDouble(/*info:DownCastImplicit*/min(1, 2.0)); | |
| 1266 | |
| 1267 // Types other than int and double are not accepted. | |
| 1268 printInt( | |
| 1269 /*info:DownCastImplicit*/min( | |
| 1270 /*severe:StaticTypeError*/"hi", | |
| 1271 /*severe:StaticTypeError*/"there")); | |
| 1272 } | |
| 1273 ''' | |
| 1274 }); | |
| 1275 | |
| 1276 testChecker('Iterable and Future', { | |
| 1277 '/main.dart': ''' | |
| 1278 import 'dart:async'; | |
| 1279 | |
| 1280 Future<int> make(int x) => (/*info:InferredTypeAllocation*/new Future(()
=> x)); | |
| 1281 | |
| 1282 main() { | |
| 1283 Iterable<Future<int>> list = <int>[1, 2, 3].map(make); | |
| 1284 Future<List<int>> results = Future.wait(list); | |
| 1285 Future<String> results2 = results.then((List<int> list) | |
| 1286 => list.fold('', (String x, int y) => x + y.toString())); | |
| 1287 } | |
| 1288 ''' | |
| 1289 }); | |
| 1290 }); | |
| 1291 } | |
| OLD | NEW |