| 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 /// General type checking tests | |
| 6 library dev_compiler.test.checker_test; | |
| 7 | |
| 8 import 'package:test/test.dart'; | |
| 9 | |
| 10 import '../testing.dart'; | |
| 11 | |
| 12 void main() { | |
| 13 testChecker('ternary operator', { | |
| 14 '/main.dart': ''' | |
| 15 abstract class Comparable<T> { | |
| 16 int compareTo(T other); | |
| 17 static int compare(Comparable a, Comparable b) => a.compareTo(b); | |
| 18 } | |
| 19 typedef int Comparator<T>(T a, T b); | |
| 20 | |
| 21 typedef bool _Predicate<T>(T value); | |
| 22 | |
| 23 class SplayTreeMap<K, V> { | |
| 24 Comparator<K> _comparator; | |
| 25 _Predicate _validKey; | |
| 26 | |
| 27 // Initializing _comparator needs a cast, since K may not always be | |
| 28 // Comparable. | |
| 29 // Initializing _validKey shouldn't need a cast. Currently | |
| 30 // it requires inference to work because of dartbug.com/23381 | |
| 31 SplayTreeMap([int compare(K key1, K key2), | |
| 32 bool isValidKey(potentialKey)]) { | |
| 33 : _comparator = /*warning:DownCastComposite*/(compare == null) ? Com
parable.compare : compare, | |
| 34 _validKey = /*info:InferredType should be pass*/(isValidKey != nul
l) ? isValidKey : ((v) => true); | |
| 35 _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey !
= null) ? isValidKey : ((v) => true); | |
| 36 _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v
: ((v) => true); | |
| 37 } | |
| 38 } | |
| 39 void main() { | |
| 40 Object obj = 42; | |
| 41 dynamic dyn = 42; | |
| 42 int i = 42; | |
| 43 | |
| 44 // Check the boolean conversion of the condition. | |
| 45 print((/*severe:StaticTypeError*/i) ? false : true); | |
| 46 print((/*info:DownCastImplicit*/obj) ? false : true); | |
| 47 print((/*info:DynamicCast*/dyn) ? false : true); | |
| 48 } | |
| 49 ''' | |
| 50 }); | |
| 51 | |
| 52 testChecker('if/for/do/while statements use boolean conversion', { | |
| 53 '/main.dart': ''' | |
| 54 main() { | |
| 55 dynamic d = 42; | |
| 56 Object obj = 42; | |
| 57 int i = 42; | |
| 58 bool b = false; | |
| 59 | |
| 60 if (b) {} | |
| 61 if (/*info:DynamicCast*/dyn) {} | |
| 62 if (/*info:DownCastImplicit*/obj) {} | |
| 63 if (/*severe:StaticTypeError*/i) {} | |
| 64 | |
| 65 while (b) {} | |
| 66 while (/*info:DynamicCast*/dyn) {} | |
| 67 while (/*info:DownCastImplicit*/obj) {} | |
| 68 while (/*severe:StaticTypeError*/i) {} | |
| 69 | |
| 70 do {} while (b); | |
| 71 do {} while (/*info:DynamicCast*/dyn); | |
| 72 do {} while (/*info:DownCastImplicit*/obj); | |
| 73 do {} while (/*severe:StaticTypeError*/i); | |
| 74 | |
| 75 for (;b;) {} | |
| 76 for (;/*info:DynamicCast*/dyn;) {} | |
| 77 for (;/*info:DownCastImplicit*/obj;) {} | |
| 78 for (;/*severe:StaticTypeError*/i;) {} | |
| 79 } | |
| 80 ''' | |
| 81 }); | |
| 82 | |
| 83 testChecker('dynamic invocation', { | |
| 84 '/main.dart': ''' | |
| 85 | |
| 86 class A { | |
| 87 dynamic call(dynamic x) => x; | |
| 88 } | |
| 89 class B extends A { | |
| 90 int call(int x) => x; | |
| 91 double col(double x) => x; | |
| 92 } | |
| 93 void main() { | |
| 94 { | |
| 95 B f = new B(); | |
| 96 int x; | |
| 97 double y; | |
| 98 // The analyzer has what I believe is a bug (dartbug.com/23252) which | |
| 99 // causes the return type of calls to f to be treated as dynamic. | |
| 100 x = /*info:DynamicCast should be pass*/f(3); | |
| 101 x = /*severe:StaticTypeError*/f.col(3.0); | |
| 102 y = /*info:DynamicCast should be severe:StaticTypeError*/f(3); | |
| 103 y = f.col(3.0); | |
| 104 f(/*severe:StaticTypeError*/3.0); | |
| 105 f.col(/*severe:StaticTypeError*/3); | |
| 106 } | |
| 107 { | |
| 108 Function f = new B(); | |
| 109 int x; | |
| 110 double y; | |
| 111 x = /*info:DynamicCast, info:DynamicInvoke*/f(3); | |
| 112 x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); | |
| 113 y = /*info:DynamicCast, info:DynamicInvoke*/f(3); | |
| 114 y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0); | |
| 115 (/*info:DynamicInvoke*/f(3.0)); | |
| 116 (/*info:DynamicInvoke*/f.col(3)); | |
| 117 } | |
| 118 { | |
| 119 A f = new B(); | |
| 120 int x; | |
| 121 double y; | |
| 122 x = /*info:DynamicCast, info:DynamicInvoke*/f(3); | |
| 123 y = /*info:DynamicCast, info:DynamicInvoke*/f(3); | |
| 124 (/*info:DynamicInvoke*/f(3.0)); | |
| 125 } | |
| 126 } | |
| 127 ''' | |
| 128 }); | |
| 129 | |
| 130 testChecker('conversion and dynamic invoke', { | |
| 131 '/helper.dart': ''' | |
| 132 dynamic toString = (int x) => x + 42; | |
| 133 dynamic hashCode = "hello"; | |
| 134 ''', | |
| 135 '/main.dart': ''' | |
| 136 import 'helper.dart' as helper; | |
| 137 | |
| 138 class A { | |
| 139 String x = "hello world"; | |
| 140 | |
| 141 void baz1(y) => x + /*info:DynamicCast*/y; | |
| 142 static baz2(y) => /*info:DynamicInvoke*/y + y; | |
| 143 } | |
| 144 | |
| 145 void foo(String str) { | |
| 146 print(str); | |
| 147 } | |
| 148 | |
| 149 class B { | |
| 150 String toString([int arg]) => arg.toString(); | |
| 151 } | |
| 152 | |
| 153 void bar(a) { | |
| 154 foo(/*info:DynamicCast,info:DynamicInvoke*/a.x); | |
| 155 } | |
| 156 | |
| 157 baz() => new B(); | |
| 158 | |
| 159 typedef DynFun(x); | |
| 160 typedef StrFun(String x); | |
| 161 | |
| 162 var bar1 = bar; | |
| 163 | |
| 164 void main() { | |
| 165 var a = new A(); | |
| 166 bar(a); | |
| 167 (/*info:DynamicInvoke*/bar1(a)); | |
| 168 var b = bar; | |
| 169 (/*info:DynamicInvoke*/b(a)); | |
| 170 var f1 = foo; | |
| 171 f1("hello"); | |
| 172 dynamic f2 = foo; | |
| 173 (/*info:DynamicInvoke*/f2("hello")); | |
| 174 DynFun f3 = foo; | |
| 175 (/*info:DynamicInvoke*/f3("hello")); | |
| 176 (/*info:DynamicInvoke*/f3(42)); | |
| 177 StrFun f4 = foo; | |
| 178 f4("hello"); | |
| 179 a.baz1("hello"); | |
| 180 var b1 = a.baz1; | |
| 181 (/*info:DynamicInvoke*/b1("hello")); | |
| 182 A.baz2("hello"); | |
| 183 var b2 = A.baz2; | |
| 184 (/*info:DynamicInvoke*/b2("hello")); | |
| 185 | |
| 186 dynamic a1 = new B(); | |
| 187 (/*info:DynamicInvoke*/a1.x); | |
| 188 a1.toString(); | |
| 189 (/*info:DynamicInvoke*/a1.toString(42)); | |
| 190 var toStringClosure = a1.toString; | |
| 191 (/*info:DynamicInvoke*/a1.toStringClosure()); | |
| 192 (/*info:DynamicInvoke*/a1.toStringClosure(42)); | |
| 193 (/*info:DynamicInvoke*/a1.toStringClosure("hello")); | |
| 194 a1.hashCode; | |
| 195 | |
| 196 dynamic toString = () => null; | |
| 197 (/*info:DynamicInvoke*/toString()); | |
| 198 | |
| 199 (/*info:DynamicInvoke*/helper.toString()); | |
| 200 var toStringClosure2 = helper.toString; | |
| 201 (/*info:DynamicInvoke*/toStringClosure2()); | |
| 202 int hashCode = /*info:DynamicCast*/helper.hashCode; | |
| 203 | |
| 204 baz().toString(); | |
| 205 baz().hashCode; | |
| 206 } | |
| 207 ''' | |
| 208 }); | |
| 209 | |
| 210 testChecker('Constructors', { | |
| 211 '/main.dart': ''' | |
| 212 const num z = 25; | |
| 213 Object obj = "world"; | |
| 214 | |
| 215 class A { | |
| 216 int x; | |
| 217 String y; | |
| 218 | |
| 219 A(this.x) : this.y = /*severe:StaticTypeError*/42; | |
| 220 | |
| 221 A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCas
t*/p; | |
| 222 | |
| 223 A.c2(this.x, this.y); | |
| 224 | |
| 225 A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y); | |
| 226 } | |
| 227 | |
| 228 class B extends A { | |
| 229 B() : super(/*severe:StaticTypeError*/"hello"); | |
| 230 | |
| 231 B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y, | |
| 232 /*severe:StaticTypeError*/x); | |
| 233 | |
| 234 B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y); | |
| 235 } | |
| 236 | |
| 237 void main() { | |
| 238 A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z)
; | |
| 239 var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImpl
icit*/obj); | |
| 240 } | |
| 241 ''' | |
| 242 }); | |
| 243 | |
| 244 testChecker('Unbound variable', { | |
| 245 '/main.dart': ''' | |
| 246 void main() { | |
| 247 dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable; | |
| 248 } | |
| 249 ''' | |
| 250 }); | |
| 251 | |
| 252 testChecker('Unbound type name', { | |
| 253 '/main.dart': ''' | |
| 254 void main() { | |
| 255 /*pass should be severe:StaticTypeError*/AToB y; | |
| 256 } | |
| 257 ''' | |
| 258 }); | |
| 259 | |
| 260 testChecker('Ground type subtyping: dynamic is top', { | |
| 261 '/main.dart': ''' | |
| 262 | |
| 263 class A {} | |
| 264 class B extends A {} | |
| 265 | |
| 266 void main() { | |
| 267 dynamic y; | |
| 268 Object o; | |
| 269 int i = 0; | |
| 270 double d = 0.0; | |
| 271 num n; | |
| 272 A a; | |
| 273 B b; | |
| 274 y = o; | |
| 275 y = i; | |
| 276 y = d; | |
| 277 y = n; | |
| 278 y = a; | |
| 279 y = b; | |
| 280 } | |
| 281 ''' | |
| 282 }); | |
| 283 | |
| 284 testChecker('Ground type subtyping: dynamic downcasts', { | |
| 285 '/main.dart': ''' | |
| 286 | |
| 287 class A {} | |
| 288 class B extends A {} | |
| 289 | |
| 290 void main() { | |
| 291 dynamic y; | |
| 292 Object o; | |
| 293 int i = 0; | |
| 294 double d = 0.0; | |
| 295 num n; | |
| 296 A a; | |
| 297 B b; | |
| 298 o = y; | |
| 299 i = /*info:DynamicCast*/y; | |
| 300 d = /*info:DynamicCast*/y; | |
| 301 n = /*info:DynamicCast*/y; | |
| 302 a = /*info:DynamicCast*/y; | |
| 303 b = /*info:DynamicCast*/y; | |
| 304 } | |
| 305 ''' | |
| 306 }); | |
| 307 | |
| 308 testChecker('Ground type subtyping: assigning a class', { | |
| 309 '/main.dart': ''' | |
| 310 | |
| 311 class A {} | |
| 312 class B extends A {} | |
| 313 | |
| 314 void main() { | |
| 315 dynamic y; | |
| 316 Object o; | |
| 317 int i = 0; | |
| 318 double d = 0.0; | |
| 319 num n; | |
| 320 A a; | |
| 321 B b; | |
| 322 y = a; | |
| 323 o = a; | |
| 324 i = /*severe:StaticTypeError*/a; | |
| 325 d = /*severe:StaticTypeError*/a; | |
| 326 n = /*severe:StaticTypeError*/a; | |
| 327 a = a; | |
| 328 b = /*info:DownCastImplicit*/a; | |
| 329 } | |
| 330 ''' | |
| 331 }); | |
| 332 | |
| 333 testChecker('Ground type subtyping: assigning a subclass', { | |
| 334 '/main.dart': ''' | |
| 335 | |
| 336 class A {} | |
| 337 class B extends A {} | |
| 338 class C extends A {} | |
| 339 | |
| 340 void main() { | |
| 341 dynamic y; | |
| 342 Object o; | |
| 343 int i = 0; | |
| 344 double d = 0.0; | |
| 345 num n; | |
| 346 A a; | |
| 347 B b; | |
| 348 C c; | |
| 349 y = b; | |
| 350 o = b; | |
| 351 i = /*severe:StaticTypeError*/b; | |
| 352 d = /*severe:StaticTypeError*/b; | |
| 353 n = /*severe:StaticTypeError*/b; | |
| 354 a = b; | |
| 355 b = b; | |
| 356 c = /*severe:StaticTypeError*/b; | |
| 357 } | |
| 358 ''' | |
| 359 }); | |
| 360 | |
| 361 testChecker('Ground type subtyping: interfaces', { | |
| 362 '/main.dart': ''' | |
| 363 | |
| 364 class A {} | |
| 365 class B extends A {} | |
| 366 class C extends A {} | |
| 367 class D extends B implements C {} | |
| 368 | |
| 369 void main() { | |
| 370 A top; | |
| 371 B left; | |
| 372 C right; | |
| 373 D bot; | |
| 374 { | |
| 375 top = top; | |
| 376 top = left; | |
| 377 top = right; | |
| 378 top = bot; | |
| 379 } | |
| 380 { | |
| 381 left = /*info:DownCastImplicit*/top; | |
| 382 left = left; | |
| 383 left = /*severe:StaticTypeError*/right; | |
| 384 left = bot; | |
| 385 } | |
| 386 { | |
| 387 right = /*info:DownCastImplicit*/top; | |
| 388 right = /*severe:StaticTypeError*/left; | |
| 389 right = right; | |
| 390 right = bot; | |
| 391 } | |
| 392 { | |
| 393 bot = /*info:DownCastImplicit*/top; | |
| 394 bot = /*info:DownCastImplicit*/left; | |
| 395 bot = /*info:DownCastImplicit*/right; | |
| 396 bot = bot; | |
| 397 } | |
| 398 } | |
| 399 ''' | |
| 400 }); | |
| 401 | |
| 402 testChecker('Function typing and subtyping: int and object', { | |
| 403 '/main.dart': ''' | |
| 404 | |
| 405 typedef Object Top(int x); // Top of the lattice | |
| 406 typedef int Left(int x); // Left branch | |
| 407 typedef int Left2(int x); // Left branch | |
| 408 typedef Object Right(Object x); // Right branch | |
| 409 typedef int Bot(Object x); // Bottom of the lattice | |
| 410 | |
| 411 Object top(int x) => x; | |
| 412 int left(int x) => x; | |
| 413 Object right(Object x) => x; | |
| 414 int _bot(Object x) => /*info:DownCastImplicit*/x; | |
| 415 int bot(Object x) => x as int; | |
| 416 | |
| 417 void main() { | |
| 418 { // Check typedef equality | |
| 419 Left f = left; | |
| 420 Left2 g = f; | |
| 421 } | |
| 422 { | |
| 423 Top f; | |
| 424 f = top; | |
| 425 f = left; | |
| 426 f = right; | |
| 427 f = bot; | |
| 428 } | |
| 429 { | |
| 430 Left f; | |
| 431 f = /*warning:DownCastComposite*/top; | |
| 432 f = left; | |
| 433 f = /*warning:DownCastComposite*/right; // Should we reject this? | |
| 434 f = bot; | |
| 435 } | |
| 436 { | |
| 437 Right f; | |
| 438 f = /*warning:DownCastComposite*/top; | |
| 439 f = /*warning:DownCastComposite*/left; // Should we reject this? | |
| 440 f = right; | |
| 441 f = bot; | |
| 442 } | |
| 443 { | |
| 444 Bot f; | |
| 445 f = /*warning:DownCastComposite*/top; | |
| 446 f = /*warning:DownCastComposite*/left; | |
| 447 f = /*warning:DownCastComposite*/right; | |
| 448 f = bot; | |
| 449 } | |
| 450 } | |
| 451 ''' | |
| 452 }); | |
| 453 | |
| 454 testChecker('Function typing and subtyping: classes', { | |
| 455 '/main.dart': ''' | |
| 456 | |
| 457 class A {} | |
| 458 class B extends A {} | |
| 459 | |
| 460 typedef A Top(B x); // Top of the lattice | |
| 461 typedef B Left(B x); // Left branch | |
| 462 typedef B Left2(B x); // Left branch | |
| 463 typedef A Right(A x); // Right branch | |
| 464 typedef B Bot(A x); // Bottom of the lattice | |
| 465 | |
| 466 B left(B x) => x; | |
| 467 B _bot(A x) => /*info:DownCastImplicit*/x; | |
| 468 B bot(A x) => x as B; | |
| 469 A top(B x) => x; | |
| 470 A right(A x) => x; | |
| 471 | |
| 472 void main() { | |
| 473 { // Check typedef equality | |
| 474 Left f = left; | |
| 475 Left2 g = f; | |
| 476 } | |
| 477 { | |
| 478 Top f; | |
| 479 f = top; | |
| 480 f = left; | |
| 481 f = right; | |
| 482 f = bot; | |
| 483 } | |
| 484 { | |
| 485 Left f; | |
| 486 f = /*warning:DownCastComposite*/top; | |
| 487 f = left; | |
| 488 f = /*warning:DownCastComposite*/right; // Should we reject this? | |
| 489 f = bot; | |
| 490 } | |
| 491 { | |
| 492 Right f; | |
| 493 f = /*warning:DownCastComposite*/top; | |
| 494 f = /*warning:DownCastComposite*/left; // Should we reject this? | |
| 495 f = right; | |
| 496 f = bot; | |
| 497 } | |
| 498 { | |
| 499 Bot f; | |
| 500 f = /*warning:DownCastComposite*/top; | |
| 501 f = /*warning:DownCastComposite*/left; | |
| 502 f = /*warning:DownCastComposite*/right; | |
| 503 f = bot; | |
| 504 } | |
| 505 } | |
| 506 ''' | |
| 507 }); | |
| 508 | |
| 509 testChecker('Function typing and subtyping: dynamic', { | |
| 510 '/main.dart': ''' | |
| 511 | |
| 512 class A {} | |
| 513 | |
| 514 typedef dynamic Top(dynamic x); // Top of the lattice | |
| 515 typedef dynamic Left(A x); // Left branch | |
| 516 typedef A Right(dynamic x); // Right branch | |
| 517 typedef A Bottom(A x); // Bottom of the lattice | |
| 518 | |
| 519 dynamic left(A x) => x; | |
| 520 A bot(A x) => x; | |
| 521 dynamic top(dynamic x) => x; | |
| 522 A right(dynamic x) => /*info:DynamicCast*/x; | |
| 523 | |
| 524 void main() { | |
| 525 { | |
| 526 Top f; | |
| 527 f = top; | |
| 528 f = left; | |
| 529 f = right; | |
| 530 f = bot; | |
| 531 } | |
| 532 { | |
| 533 Left f; | |
| 534 f = /*warning:DownCastComposite*/top; | |
| 535 f = left; | |
| 536 f = /*warning:DownCastComposite*/right; | |
| 537 f = bot; | |
| 538 } | |
| 539 { | |
| 540 Right f; | |
| 541 f = /*warning:DownCastComposite*/top; | |
| 542 f = /*warning:DownCastComposite*/left; | |
| 543 f = right; | |
| 544 f = bot; | |
| 545 } | |
| 546 { | |
| 547 Bottom f; | |
| 548 f = /*warning:DownCastComposite*/top; | |
| 549 f = /*warning:DownCastComposite*/left; | |
| 550 f = /*warning:DownCastComposite*/right; | |
| 551 f = bot; | |
| 552 } | |
| 553 } | |
| 554 ''' | |
| 555 }); | |
| 556 | |
| 557 testChecker('Function typing and subtyping: function literal variance', { | |
| 558 '/main.dart': ''' | |
| 559 | |
| 560 class A {} | |
| 561 class B extends A {} | |
| 562 | |
| 563 typedef T Function2<S, T>(S z); | |
| 564 | |
| 565 A top(B x) => x; | |
| 566 B left(B x) => x; | |
| 567 A right(A x) => x; | |
| 568 B bot(A x) => x as B; | |
| 569 | |
| 570 void main() { | |
| 571 { | |
| 572 Function2<B, A> f; | |
| 573 f = top; | |
| 574 f = left; | |
| 575 f = right; | |
| 576 f = bot; | |
| 577 } | |
| 578 { | |
| 579 Function2<B, B> f; | |
| 580 f = /*warning:DownCastComposite*/top; | |
| 581 f = left; | |
| 582 f = /*warning:DownCastComposite*/right; // Should we reject this? | |
| 583 f = bot; | |
| 584 } | |
| 585 { | |
| 586 Function2<A, A> f; | |
| 587 f = /*warning:DownCastComposite*/top; | |
| 588 f = /*warning:DownCastComposite*/left; // Should we reject this? | |
| 589 f = right; | |
| 590 f = bot; | |
| 591 } | |
| 592 { | |
| 593 Function2<A, B> f; | |
| 594 f = /*warning:DownCastComposite*/top; | |
| 595 f = /*warning:DownCastComposite*/left; | |
| 596 f = /*warning:DownCastComposite*/right; | |
| 597 f = bot; | |
| 598 } | |
| 599 } | |
| 600 ''' | |
| 601 }); | |
| 602 | |
| 603 testChecker('Function typing and subtyping: function variable variance', { | |
| 604 '/main.dart': ''' | |
| 605 | |
| 606 class A {} | |
| 607 class B extends A {} | |
| 608 | |
| 609 typedef T Function2<S, T>(S z); | |
| 610 | |
| 611 void main() { | |
| 612 { | |
| 613 Function2<B, A> top; | |
| 614 Function2<B, B> left; | |
| 615 Function2<A, A> right; | |
| 616 Function2<A, B> bot; | |
| 617 | |
| 618 top = right; | |
| 619 top = bot; | |
| 620 top = top; | |
| 621 top = left; | |
| 622 | |
| 623 left = /*warning:DownCastComposite*/top; | |
| 624 left = left; | |
| 625 left = /*warning:DownCastComposite*/right; // Should we reject this? | |
| 626 left = bot; | |
| 627 | |
| 628 right = /*warning:DownCastComposite*/top; | |
| 629 right = /*warning:DownCastComposite*/left; // Should we reject this? | |
| 630 right = right; | |
| 631 right = bot; | |
| 632 | |
| 633 bot = /*warning:DownCastComposite*/top; | |
| 634 bot = /*warning:DownCastComposite*/left; | |
| 635 bot = /*warning:DownCastComposite*/right; | |
| 636 bot = bot; | |
| 637 } | |
| 638 } | |
| 639 ''' | |
| 640 }); | |
| 641 | |
| 642 testChecker('Function typing and subtyping: higher order function literals', { | |
| 643 '/main.dart': ''' | |
| 644 | |
| 645 class A {} | |
| 646 class B extends A {} | |
| 647 | |
| 648 typedef T Function2<S, T>(S z); | |
| 649 | |
| 650 typedef A BToA(B x); // Top of the base lattice | |
| 651 typedef B AToB(A x); // Bot of the base lattice | |
| 652 | |
| 653 BToA top(AToB f) => f; | |
| 654 AToB left(AToB f) => f; | |
| 655 BToA right(BToA f) => f; | |
| 656 AToB _bot(BToA f) => /*warning:DownCastComposite*/f; | |
| 657 AToB bot(BToA f) => f as AToB; | |
| 658 | |
| 659 Function2<B, A> top(AToB f) => f; | |
| 660 Function2<A, B> left(AToB f) => f; | |
| 661 Function2<B, A> right(BToA f) => f; | |
| 662 Function2<A, B> _bot(BToA f) => /*warning:DownCastComposite*/f; | |
| 663 Function2<A, B> bot(BToA f) => f as Function2<A, B>; | |
| 664 | |
| 665 | |
| 666 BToA top(Function2<A, B> f) => f; | |
| 667 AToB left(Function2<A, B> f) => f; | |
| 668 BToA right(Function2<B, A> f) => f; | |
| 669 AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f; | |
| 670 AToB bot(Function2<B, A> f) => f as AToB; | |
| 671 | |
| 672 void main() { | |
| 673 { | |
| 674 Function2<AToB, BToA> f; // Top | |
| 675 f = top; | |
| 676 f = left; | |
| 677 f = right; | |
| 678 f = bot; | |
| 679 } | |
| 680 { | |
| 681 Function2<AToB, AToB> f; // Left | |
| 682 f = /*warning:DownCastComposite*/top; | |
| 683 f = left; | |
| 684 f = /*warning:DownCastComposite*/right; // Should we reject this? | |
| 685 f = bot; | |
| 686 } | |
| 687 { | |
| 688 Function2<BToA, BToA> f; // Right | |
| 689 f = /*warning:DownCastComposite*/top; | |
| 690 f = /*warning:DownCastComposite*/left; // Should we reject this? | |
| 691 f = right; | |
| 692 f = bot; | |
| 693 } | |
| 694 { | |
| 695 Function2<BToA, AToB> f; // Bot | |
| 696 f = bot; | |
| 697 f = /*warning:DownCastComposite*/left; | |
| 698 f = /*warning:DownCastComposite*/top; | |
| 699 f = /*warning:DownCastComposite*/left; | |
| 700 } | |
| 701 } | |
| 702 ''' | |
| 703 }); | |
| 704 | |
| 705 testChecker( | |
| 706 'Function typing and subtyping: higher order function variables', { | |
| 707 '/main.dart': ''' | |
| 708 | |
| 709 class A {} | |
| 710 class B extends A {} | |
| 711 | |
| 712 typedef T Function2<S, T>(S z); | |
| 713 | |
| 714 void main() { | |
| 715 { | |
| 716 Function2<Function2<A, B>, Function2<B, A>> top; | |
| 717 Function2<Function2<B, A>, Function2<B, A>> right; | |
| 718 Function2<Function2<A, B>, Function2<A, B>> left; | |
| 719 Function2<Function2<B, A>, Function2<A, B>> bot; | |
| 720 | |
| 721 top = right; | |
| 722 top = bot; | |
| 723 top = top; | |
| 724 top = left; | |
| 725 | |
| 726 left = /*warning:DownCastComposite*/top; | |
| 727 left = left; | |
| 728 left = | |
| 729 /*warning:DownCastComposite should be severe:StaticTypeError*/right; | |
| 730 left = bot; | |
| 731 | |
| 732 right = /*warning:DownCastComposite*/top; | |
| 733 right = | |
| 734 /*warning:DownCastComposite should be severe:StaticTypeError*/left; | |
| 735 right = right; | |
| 736 right = bot; | |
| 737 | |
| 738 bot = /*warning:DownCastComposite*/top; | |
| 739 bot = /*warning:DownCastComposite*/left; | |
| 740 bot = /*warning:DownCastComposite*/right; | |
| 741 bot = bot; | |
| 742 } | |
| 743 } | |
| 744 ''' | |
| 745 }); | |
| 746 | |
| 747 testChecker('Function typing and subtyping: named and optional parameters', { | |
| 748 '/main.dart': ''' | |
| 749 | |
| 750 class A {} | |
| 751 | |
| 752 typedef A FR(A x); | |
| 753 typedef A FO([A x]); | |
| 754 typedef A FN({A x}); | |
| 755 typedef A FRR(A x, A y); | |
| 756 typedef A FRO(A x, [A y]); | |
| 757 typedef A FRN(A x, {A n}); | |
| 758 typedef A FOO([A x, A y]); | |
| 759 typedef A FNN({A x, A y}); | |
| 760 typedef A FNNN({A z, A y, A x}); | |
| 761 | |
| 762 void main() { | |
| 763 FR r; | |
| 764 FO o; | |
| 765 FN n; | |
| 766 FRR rr; | |
| 767 FRO ro; | |
| 768 FRN rn; | |
| 769 FOO oo; | |
| 770 FNN nn; | |
| 771 FNNN nnn; | |
| 772 | |
| 773 r = r; | |
| 774 r = o; | |
| 775 r = /*severe:StaticTypeError*/n; | |
| 776 r = /*severe:StaticTypeError*/rr; | |
| 777 r = ro; | |
| 778 r = rn; | |
| 779 r = oo; | |
| 780 r = /*severe:StaticTypeError*/nn; | |
| 781 r = /*severe:StaticTypeError*/nnn; | |
| 782 | |
| 783 o = /*warning:DownCastComposite*/r; | |
| 784 o = o; | |
| 785 o = /*severe:StaticTypeError*/n; | |
| 786 o = /*severe:StaticTypeError*/rr; | |
| 787 o = /*severe:StaticTypeError*/ro; | |
| 788 o = /*severe:StaticTypeError*/rn; | |
| 789 o = oo; | |
| 790 o = /*severe:StaticTypeError*/nn | |
| 791 o = /*severe:StaticTypeError*/nnn; | |
| 792 | |
| 793 n = /*severe:StaticTypeError*/r; | |
| 794 n = /*severe:StaticTypeError*/o; | |
| 795 n = n; | |
| 796 n = /*severe:StaticTypeError*/rr; | |
| 797 n = /*severe:StaticTypeError*/ro; | |
| 798 n = /*severe:StaticTypeError*/rn; | |
| 799 n = /*severe:StaticTypeError*/oo; | |
| 800 n = nn; | |
| 801 n = nnn; | |
| 802 | |
| 803 rr = /*severe:StaticTypeError*/r; | |
| 804 rr = /*severe:StaticTypeError*/o; | |
| 805 rr = /*severe:StaticTypeError*/n; | |
| 806 rr = rr; | |
| 807 rr = ro; | |
| 808 rr = /*severe:StaticTypeError*/rn; | |
| 809 rr = oo; | |
| 810 rr = /*severe:StaticTypeError*/nn; | |
| 811 rr = /*severe:StaticTypeError*/nnn; | |
| 812 | |
| 813 ro = /*warning:DownCastComposite*/r; | |
| 814 ro = /*severe:StaticTypeError*/o; | |
| 815 ro = /*severe:StaticTypeError*/n; | |
| 816 ro = /*warning:DownCastComposite*/rr; | |
| 817 ro = ro; | |
| 818 ro = /*severe:StaticTypeError*/rn; | |
| 819 ro = oo; | |
| 820 ro = /*severe:StaticTypeError*/nn; | |
| 821 ro = /*severe:StaticTypeError*/nnn; | |
| 822 | |
| 823 rn = /*warning:DownCastComposite*/r; | |
| 824 rn = /*severe:StaticTypeError*/o; | |
| 825 rn = /*severe:StaticTypeError*/n; | |
| 826 rn = /*severe:StaticTypeError*/rr; | |
| 827 rn = /*severe:StaticTypeError*/ro; | |
| 828 rn = rn; | |
| 829 rn = /*severe:StaticTypeError*/oo; | |
| 830 rn = /*severe:StaticTypeError*/nn; | |
| 831 rn = /*severe:StaticTypeError*/nnn; | |
| 832 | |
| 833 oo = /*warning:DownCastComposite*/r; | |
| 834 oo = /*warning:DownCastComposite*/o; | |
| 835 oo = /*severe:StaticTypeError*/n; | |
| 836 oo = /*warning:DownCastComposite*/rr; | |
| 837 oo = /*warning:DownCastComposite*/ro; | |
| 838 oo = /*severe:StaticTypeError*/rn; | |
| 839 oo = oo; | |
| 840 oo = /*severe:StaticTypeError*/nn; | |
| 841 oo = /*severe:StaticTypeError*/nnn; | |
| 842 | |
| 843 nn = /*severe:StaticTypeError*/r; | |
| 844 nn = /*severe:StaticTypeError*/o; | |
| 845 nn = /*warning:DownCastComposite*/n; | |
| 846 nn = /*severe:StaticTypeError*/rr; | |
| 847 nn = /*severe:StaticTypeError*/ro; | |
| 848 nn = /*severe:StaticTypeError*/rn; | |
| 849 nn = /*severe:StaticTypeError*/oo; | |
| 850 nn = nn; | |
| 851 nn = nnn; | |
| 852 | |
| 853 nnn = /*severe:StaticTypeError*/r; | |
| 854 nnn = /*severe:StaticTypeError*/o; | |
| 855 nnn = /*warning:DownCastComposite*/n; | |
| 856 nnn = /*severe:StaticTypeError*/rr; | |
| 857 nnn = /*severe:StaticTypeError*/ro; | |
| 858 nnn = /*severe:StaticTypeError*/rn; | |
| 859 nnn = /*severe:StaticTypeError*/oo; | |
| 860 nnn = /*warning:DownCastComposite*/nn; | |
| 861 nnn = nnn; | |
| 862 } | |
| 863 ''' | |
| 864 }); | |
| 865 | |
| 866 testChecker('Function subtyping: objects with call methods', { | |
| 867 '/main.dart': ''' | |
| 868 | |
| 869 typedef int I2I(int x); | |
| 870 typedef num N2N(num x); | |
| 871 class A { | |
| 872 int call(int x) => x; | |
| 873 } | |
| 874 class B { | |
| 875 num call(num x) => x; | |
| 876 } | |
| 877 int i2i(int x) => x; | |
| 878 num n2n(num x) => x; | |
| 879 void main() { | |
| 880 { | |
| 881 I2I f; | |
| 882 f = new A(); | |
| 883 f = /*severe:StaticTypeError*/new B(); | |
| 884 f = i2i; | |
| 885 f = /*warning:DownCastComposite*/n2n; | |
| 886 f = /*warning:DownCastComposite*/i2i as Object; | |
| 887 f = /*warning:DownCastComposite*/n2n as Function; | |
| 888 } | |
| 889 { | |
| 890 N2N f; | |
| 891 f = /*severe:StaticTypeError*/new A(); | |
| 892 f = new B(); | |
| 893 f = /*warning:DownCastComposite*/i2i; | |
| 894 f = n2n; | |
| 895 f = /*warning:DownCastComposite*/i2i as Object; | |
| 896 f = /*warning:DownCastComposite*/n2n as Function; | |
| 897 } | |
| 898 { | |
| 899 A f; | |
| 900 f = new A(); | |
| 901 f = /*severe:StaticTypeError*/new B(); | |
| 902 f = /*severe:StaticTypeError*/i2i; | |
| 903 f = /*severe:StaticTypeError*/n2n; | |
| 904 f = /*info:DownCastImplicit*/i2i as Object; | |
| 905 f = /*info:DownCastImplicit*/n2n as Function; | |
| 906 } | |
| 907 { | |
| 908 B f; | |
| 909 f = /*severe:StaticTypeError*/new A(); | |
| 910 f = new B(); | |
| 911 f = /*severe:StaticTypeError*/i2i; | |
| 912 f = /*severe:StaticTypeError*/n2n; | |
| 913 f = /*info:DownCastImplicit*/i2i as Object; | |
| 914 f = /*info:DownCastImplicit*/n2n as Function; | |
| 915 } | |
| 916 { | |
| 917 Function f; | |
| 918 f = new A(); | |
| 919 f = new B(); | |
| 920 f = i2i; | |
| 921 f = n2n; | |
| 922 f = /*info:DownCastImplicit*/i2i as Object; | |
| 923 f = (n2n as Function); | |
| 924 } | |
| 925 } | |
| 926 ''' | |
| 927 }); | |
| 928 | |
| 929 testChecker('Function typing and subtyping: void', { | |
| 930 '/main.dart': ''' | |
| 931 | |
| 932 class A { | |
| 933 void bar() => null; | |
| 934 void foo() => bar; // allowed | |
| 935 } | |
| 936 ''' | |
| 937 }); | |
| 938 | |
| 939 testChecker('Relaxed casts', { | |
| 940 '/main.dart': ''' | |
| 941 | |
| 942 class A {} | |
| 943 | |
| 944 class L<T> {} | |
| 945 class M<T> extends L<T> {} | |
| 946 // L<dynamic|Object> | |
| 947 // / \ | |
| 948 // M<dynamic|Object> L<A> | |
| 949 // \ / | |
| 950 // M<A> | |
| 951 // In normal Dart, there are additional edges | |
| 952 // from M<A> to M<dynamic> | |
| 953 // from L<A> to M<dynamic> | |
| 954 // from L<A> to L<dynamic> | |
| 955 void main() { | |
| 956 L lOfDs; | |
| 957 L<Object> lOfOs; | |
| 958 L<A> lOfAs; | |
| 959 | |
| 960 M mOfDs; | |
| 961 M<Object> mOfOs; | |
| 962 M<A> mOfAs; | |
| 963 | |
| 964 { | |
| 965 lOfDs = mOfDs; | |
| 966 lOfDs = mOfOs; | |
| 967 lOfDs = mOfAs; | |
| 968 lOfDs = lOfDs; | |
| 969 lOfDs = lOfOs; | |
| 970 lOfDs = lOfAs; | |
| 971 } | |
| 972 { | |
| 973 lOfOs = mOfDs; | |
| 974 lOfOs = mOfOs; | |
| 975 lOfOs = mOfAs; | |
| 976 lOfOs = lOfDs; | |
| 977 lOfOs = lOfOs; | |
| 978 lOfOs = lOfAs; | |
| 979 } | |
| 980 { | |
| 981 lOfAs = /*warning:DownCastComposite*/mOfDs; | |
| 982 lOfAs = /*severe:StaticTypeError*/mOfOs; | |
| 983 lOfAs = mOfAs; | |
| 984 lOfAs = /*warning:DownCastComposite*/lOfDs; | |
| 985 lOfAs = /*warning:DownCastComposite*/lOfOs; | |
| 986 lOfAs = lOfAs; | |
| 987 } | |
| 988 { | |
| 989 mOfDs = mOfDs; | |
| 990 mOfDs = mOfOs; | |
| 991 mOfDs = mOfAs; | |
| 992 mOfDs = /*info:DownCastImplicit*/lOfDs; | |
| 993 mOfDs = /*info:DownCastImplicit*/lOfOs; | |
| 994 mOfDs = /*info:DownCastImplicit*/lOfAs; | |
| 995 } | |
| 996 { | |
| 997 mOfOs = mOfDs; | |
| 998 mOfOs = mOfOs; | |
| 999 mOfOs = mOfAs; | |
| 1000 mOfOs = /*info:DownCastImplicit*/lOfDs; | |
| 1001 mOfOs = /*info:DownCastImplicit*/lOfOs; | |
| 1002 mOfOs = /*severe:StaticTypeError*/lOfAs; | |
| 1003 } | |
| 1004 { | |
| 1005 mOfAs = /*warning:DownCastComposite*/mOfDs; | |
| 1006 mOfAs = /*warning:DownCastComposite*/mOfOs; | |
| 1007 mOfAs = mOfAs; | |
| 1008 mOfAs = /*warning:DownCastComposite*/lOfDs; | |
| 1009 mOfAs = /*warning:DownCastComposite*/lOfOs; | |
| 1010 mOfAs = /*warning:DownCastComposite*/lOfAs; | |
| 1011 } | |
| 1012 | |
| 1013 } | |
| 1014 ''' | |
| 1015 }); | |
| 1016 | |
| 1017 testChecker('Type checking literals', { | |
| 1018 '/main.dart': ''' | |
| 1019 test() { | |
| 1020 num n = 3; | |
| 1021 int i = 3; | |
| 1022 String s = "hello"; | |
| 1023 { | |
| 1024 List<int> l = <int>[i]; | |
| 1025 l = <int>[/*severe:StaticTypeError*/s]; | |
| 1026 l = <int>[/*info:DownCastImplicit*/n]; | |
| 1027 l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError
*/s]; | |
| 1028 } | |
| 1029 { | |
| 1030 List l = [i]; | |
| 1031 l = [s]; | |
| 1032 l = [n]; | |
| 1033 l = [i, n, s]; | |
| 1034 } | |
| 1035 { | |
| 1036 Map<String, int> m = <String, int>{s: i}; | |
| 1037 m = <String, int>{s: /*severe:StaticTypeError*/s}; | |
| 1038 m = <String, int>{s: /*info:DownCastImplicit*/n}; | |
| 1039 m = <String, int>{s: i, | |
| 1040 s: /*info:DownCastImplicit*/n, | |
| 1041 s: /*severe:StaticTypeError*/s}; | |
| 1042 } | |
| 1043 // TODO(leafp): We can't currently test for key errors since the | |
| 1044 // error marker binds to the entire entry. | |
| 1045 { | |
| 1046 Map m = {s: i}; | |
| 1047 m = {s: s}; | |
| 1048 m = {s: n}; | |
| 1049 m = {s: i, | |
| 1050 s: n, | |
| 1051 s: s}; | |
| 1052 m = {i: s, | |
| 1053 n: s, | |
| 1054 s: s}; | |
| 1055 } | |
| 1056 } | |
| 1057 ''' | |
| 1058 }); | |
| 1059 | |
| 1060 testChecker('casts in constant contexts', { | |
| 1061 '/main.dart': ''' | |
| 1062 class A { | |
| 1063 static const num n = 3.0; | |
| 1064 static const int i = /*info:AssignmentCast*/n; | |
| 1065 final int fi; | |
| 1066 const A(num a) : this.fi = /*info:DownCastImplicit*/a; | |
| 1067 } | |
| 1068 class B extends A { | |
| 1069 const B(Object a) : super(/*info:DownCastImplicit*/a); | |
| 1070 } | |
| 1071 void foo(Object o) { | |
| 1072 var a = const A(/*info:DownCastImplicit*/o); | |
| 1073 } | |
| 1074 ''' | |
| 1075 }); | |
| 1076 | |
| 1077 testChecker('casts in conditionals', { | |
| 1078 '/main.dart': ''' | |
| 1079 main() { | |
| 1080 bool b = true; | |
| 1081 num x = b ? 1 : 2.3; | |
| 1082 int y = /*info:AssignmentCast*/b ? 1 : 2.3; | |
| 1083 String z = !b ? "hello" : null; | |
| 1084 z = b ? null : "hello"; | |
| 1085 } | |
| 1086 ''' | |
| 1087 }); | |
| 1088 | |
| 1089 testChecker('redirecting constructor', { | |
| 1090 '/main.dart': ''' | |
| 1091 class A { | |
| 1092 A(A x) {} | |
| 1093 A.two() : this(/*severe:StaticTypeError*/3); | |
| 1094 } | |
| 1095 ''' | |
| 1096 }); | |
| 1097 | |
| 1098 testChecker('super constructor', { | |
| 1099 '/main.dart': ''' | |
| 1100 class A { A(A x) {} } | |
| 1101 class B extends A { | |
| 1102 B() : super(/*severe:StaticTypeError*/3); | |
| 1103 } | |
| 1104 ''' | |
| 1105 }); | |
| 1106 | |
| 1107 testChecker('field/field override', { | |
| 1108 '/main.dart': ''' | |
| 1109 class A {} | |
| 1110 class B extends A {} | |
| 1111 class C extends B {} | |
| 1112 | |
| 1113 class Base { | |
| 1114 B f1; | |
| 1115 B f2; | |
| 1116 B f3; | |
| 1117 B f4; | |
| 1118 } | |
| 1119 | |
| 1120 class Child extends Base { | |
| 1121 /*severe:InvalidMethodOverride*/A f1; // invalid for getter | |
| 1122 /*severe:InvalidMethodOverride*/C f2; // invalid for setter | |
| 1123 var f3; | |
| 1124 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic
f4; | |
| 1125 } | |
| 1126 ''' | |
| 1127 }); | |
| 1128 | |
| 1129 testChecker('getter/getter override', { | |
| 1130 '/main.dart': ''' | |
| 1131 class A {} | |
| 1132 class B extends A {} | |
| 1133 class C extends B {} | |
| 1134 | |
| 1135 abstract class Base { | |
| 1136 B get f1; | |
| 1137 B get f2; | |
| 1138 B get f3; | |
| 1139 B get f4; | |
| 1140 } | |
| 1141 | |
| 1142 class Child extends Base { | |
| 1143 /*severe:InvalidMethodOverride*/A get f1 => null; | |
| 1144 C get f2 => null; | |
| 1145 get f3 => null; | |
| 1146 /*severe:InvalidMethodOverride*/dynamic get f4 => null; | |
| 1147 } | |
| 1148 ''' | |
| 1149 }); | |
| 1150 | |
| 1151 testChecker('field/getter override', { | |
| 1152 '/main.dart': ''' | |
| 1153 class A {} | |
| 1154 class B extends A {} | |
| 1155 class C extends B {} | |
| 1156 | |
| 1157 abstract class Base { | |
| 1158 B f1; | |
| 1159 B f2; | |
| 1160 B f3; | |
| 1161 B f4; | |
| 1162 } | |
| 1163 | |
| 1164 class Child extends Base { | |
| 1165 /*severe:InvalidMethodOverride*/A get f1 => null; | |
| 1166 C get f2 => null; | |
| 1167 get f3 => null; | |
| 1168 /*severe:InvalidMethodOverride*/dynamic get f4 => null; | |
| 1169 } | |
| 1170 ''' | |
| 1171 }); | |
| 1172 | |
| 1173 testChecker('setter/setter override', { | |
| 1174 '/main.dart': ''' | |
| 1175 class A {} | |
| 1176 class B extends A {} | |
| 1177 class C extends B {} | |
| 1178 | |
| 1179 abstract class Base { | |
| 1180 void set f1(B value); | |
| 1181 void set f2(B value); | |
| 1182 void set f3(B value); | |
| 1183 void set f4(B value); | |
| 1184 void set f5(B value); | |
| 1185 } | |
| 1186 | |
| 1187 class Child extends Base { | |
| 1188 void set f1(A value) {} | |
| 1189 /*severe:InvalidMethodOverride*/void set f2(C value) {} | |
| 1190 void set f3(value) {} | |
| 1191 /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} | |
| 1192 set f5(B value) {} | |
| 1193 } | |
| 1194 ''' | |
| 1195 }); | |
| 1196 | |
| 1197 testChecker('field/setter override', { | |
| 1198 '/main.dart': ''' | |
| 1199 class A {} | |
| 1200 class B extends A {} | |
| 1201 class C extends B {} | |
| 1202 | |
| 1203 class Base { | |
| 1204 B f1; | |
| 1205 B f2; | |
| 1206 B f3; | |
| 1207 B f4; | |
| 1208 B f5; | |
| 1209 } | |
| 1210 | |
| 1211 class Child extends Base { | |
| 1212 B get f1 => null; | |
| 1213 B get f2 => null; | |
| 1214 B get f3 => null; | |
| 1215 B get f4 => null; | |
| 1216 B get f5 => null; | |
| 1217 | |
| 1218 void set f1(A value) {} | |
| 1219 /*severe:InvalidMethodOverride*/void set f2(C value) {} | |
| 1220 void set f3(value) {} | |
| 1221 /*severe:InvalidMethodOverride*/void set f4(dynamic value) {} | |
| 1222 set f5(B value) {} | |
| 1223 } | |
| 1224 ''' | |
| 1225 }); | |
| 1226 | |
| 1227 testChecker('method override', { | |
| 1228 '/main.dart': ''' | |
| 1229 class A {} | |
| 1230 class B extends A {} | |
| 1231 class C extends B {} | |
| 1232 | |
| 1233 class Base { | |
| 1234 B m1(B a); | |
| 1235 B m2(B a); | |
| 1236 B m3(B a); | |
| 1237 B m4(B a); | |
| 1238 B m5(B a); | |
| 1239 B m6(B a); | |
| 1240 } | |
| 1241 | |
| 1242 class Child extends Base { | |
| 1243 /*severe:InvalidMethodOverride*/A m1(A value) {} | |
| 1244 /*severe:InvalidMethodOverride*/C m2(C value) {} | |
| 1245 /*severe:InvalidMethodOverride*/A m3(C value) {} | |
| 1246 C m4(A value) {} | |
| 1247 m5(value) {} | |
| 1248 /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {} | |
| 1249 } | |
| 1250 ''' | |
| 1251 }); | |
| 1252 | |
| 1253 testChecker('unary operators', { | |
| 1254 '/main.dart': ''' | |
| 1255 class A { | |
| 1256 A operator ~() {} | |
| 1257 A operator +(int x) {} | |
| 1258 A operator -(int x) {} | |
| 1259 A operator -() {} | |
| 1260 } | |
| 1261 | |
| 1262 foo() => new A(); | |
| 1263 | |
| 1264 test() { | |
| 1265 A a = new A(); | |
| 1266 var c = foo(); | |
| 1267 | |
| 1268 ~a; | |
| 1269 (/*info:DynamicInvoke*/~d); | |
| 1270 | |
| 1271 !/*severe:StaticTypeError*/a; | |
| 1272 !/*info:DynamicCast*/d; | |
| 1273 | |
| 1274 -a; | |
| 1275 (/*info:DynamicInvoke*/-d); | |
| 1276 | |
| 1277 ++a; | |
| 1278 --a; | |
| 1279 (/*info:DynamicInvoke*/++d); | |
| 1280 (/*info:DynamicInvoke*/--d); | |
| 1281 | |
| 1282 a++; | |
| 1283 a--; | |
| 1284 (/*info:DynamicInvoke*/d++); | |
| 1285 (/*info:DynamicInvoke*/d--); | |
| 1286 }''' | |
| 1287 }); | |
| 1288 | |
| 1289 testChecker('binary and index operators', { | |
| 1290 '/main.dart': ''' | |
| 1291 class A { | |
| 1292 A operator *(B b) {} | |
| 1293 A operator /(B b) {} | |
| 1294 A operator ~/(B b) {} | |
| 1295 A operator %(B b) {} | |
| 1296 A operator +(B b) {} | |
| 1297 A operator -(B b) {} | |
| 1298 A operator <<(B b) {} | |
| 1299 A operator >>(B b) {} | |
| 1300 A operator &(B b) {} | |
| 1301 A operator ^(B b) {} | |
| 1302 A operator |(B b) {} | |
| 1303 A operator[](B b) {} | |
| 1304 } | |
| 1305 | |
| 1306 class B { | |
| 1307 A operator -(B b) {} | |
| 1308 } | |
| 1309 | |
| 1310 foo() => new A(); | |
| 1311 | |
| 1312 test() { | |
| 1313 A a = new A(); | |
| 1314 B b = new B(); | |
| 1315 var c = foo(); | |
| 1316 a = a * b; | |
| 1317 a = a * /*info:DynamicCast*/c; | |
| 1318 a = a / b; | |
| 1319 a = a ~/ b; | |
| 1320 a = a % b; | |
| 1321 a = a + b; | |
| 1322 a = a + /*severe:StaticTypeError*/a; | |
| 1323 a = a - b; | |
| 1324 b = /*severe:StaticTypeError*/b - b; | |
| 1325 a = a << b; | |
| 1326 a = a >> b; | |
| 1327 a = a & b; | |
| 1328 a = a ^ b; | |
| 1329 a = a | b; | |
| 1330 c = (/*info:DynamicInvoke*/c + b); | |
| 1331 | |
| 1332 String x = 'hello'; | |
| 1333 int y = 42; | |
| 1334 x = x + x; | |
| 1335 x = x + /*info:DynamicCast*/c; | |
| 1336 x = x + /*severe:StaticTypeError*/y; | |
| 1337 | |
| 1338 bool p = true; | |
| 1339 p = p && p; | |
| 1340 p = p && /*info:DynamicCast*/c; | |
| 1341 p = (/*info:DynamicCast*/c) && p; | |
| 1342 p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c; | |
| 1343 p = (/*severe:StaticTypeError*/y) && p; | |
| 1344 p = c == y; | |
| 1345 | |
| 1346 a = a[b]; | |
| 1347 a = a[/*info:DynamicCast*/c]; | |
| 1348 c = (/*info:DynamicInvoke*/c[b]); | |
| 1349 a[/*severe:StaticTypeError*/y]; | |
| 1350 } | |
| 1351 ''' | |
| 1352 }); | |
| 1353 | |
| 1354 testChecker('compound assignments', { | |
| 1355 '/main.dart': ''' | |
| 1356 class A { | |
| 1357 A operator *(B b) {} | |
| 1358 A operator /(B b) {} | |
| 1359 A operator ~/(B b) {} | |
| 1360 A operator %(B b) {} | |
| 1361 A operator +(B b) {} | |
| 1362 A operator -(B b) {} | |
| 1363 A operator <<(B b) {} | |
| 1364 A operator >>(B b) {} | |
| 1365 A operator &(B b) {} | |
| 1366 A operator ^(B b) {} | |
| 1367 A operator |(B b) {} | |
| 1368 D operator [](B index) {} | |
| 1369 void operator []=(B index, D value) {} | |
| 1370 } | |
| 1371 | |
| 1372 class B { | |
| 1373 A operator -(B b) {} | |
| 1374 } | |
| 1375 | |
| 1376 class D { | |
| 1377 D operator +(D d) {} | |
| 1378 } | |
| 1379 | |
| 1380 foo() => new A(); | |
| 1381 | |
| 1382 test() { | |
| 1383 int x = 0; | |
| 1384 x += 5; | |
| 1385 (/*severe:StaticTypeError*/x += 3.14); | |
| 1386 | |
| 1387 double y = 0.0; | |
| 1388 y += 5; | |
| 1389 y += 3.14; | |
| 1390 | |
| 1391 num z = 0; | |
| 1392 z += 5; | |
| 1393 z += 3.14; | |
| 1394 | |
| 1395 x = /*info:DownCastImplicit*/x + z; | |
| 1396 x += /*info:DownCastImplicit*/z; | |
| 1397 y = /*info:DownCastImplicit*/y + z; | |
| 1398 y += /*info:DownCastImplicit*/z; | |
| 1399 | |
| 1400 dynamic w = 42; | |
| 1401 x += /*info:DynamicCast*/w; | |
| 1402 y += /*info:DynamicCast*/w; | |
| 1403 z += /*info:DynamicCast*/w; | |
| 1404 | |
| 1405 A a = new A(); | |
| 1406 B b = new B(); | |
| 1407 var c = foo(); | |
| 1408 a = a * b; | |
| 1409 a *= b; | |
| 1410 a *= /*info:DynamicCast*/c; | |
| 1411 a /= b; | |
| 1412 a ~/= b; | |
| 1413 a %= b; | |
| 1414 a += b; | |
| 1415 a += /*severe:StaticTypeError*/a; | |
| 1416 a -= b; | |
| 1417 (/*severe:StaticTypeError*/b -= b); | |
| 1418 a <<= b; | |
| 1419 a >>= b; | |
| 1420 a &= b; | |
| 1421 a ^= b; | |
| 1422 a |= b; | |
| 1423 (/*info:DynamicInvoke*/c += b); | |
| 1424 | |
| 1425 var d = new D(); | |
| 1426 a[b] += d; | |
| 1427 a[/*info:DynamicCast*/c] += d; | |
| 1428 a[/*severe:StaticTypeError*/z] += d; | |
| 1429 a[b] += /*info:DynamicCast*/c; | |
| 1430 a[b] += /*severe:StaticTypeError*/z; | |
| 1431 (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d); | |
| 1432 } | |
| 1433 ''' | |
| 1434 }); | |
| 1435 | |
| 1436 testChecker('super call placement', { | |
| 1437 '/main.dart': ''' | |
| 1438 class Base { | |
| 1439 var x; | |
| 1440 Base() : x = print('Base.1') { print('Base.2'); } | |
| 1441 } | |
| 1442 | |
| 1443 class Derived extends Base { | |
| 1444 var y, z; | |
| 1445 Derived() | |
| 1446 : y = print('Derived.1'), | |
| 1447 /*severe:InvalidSuperInvocation*/super(), | |
| 1448 z = print('Derived.2') { | |
| 1449 print('Derived.3'); | |
| 1450 } | |
| 1451 } | |
| 1452 | |
| 1453 class Valid extends Base { | |
| 1454 var y, z; | |
| 1455 Valid() | |
| 1456 : y = print('Valid.1'), | |
| 1457 z = print('Valid.2'), | |
| 1458 super() { | |
| 1459 print('Valid.3'); | |
| 1460 } | |
| 1461 } | |
| 1462 | |
| 1463 class AlsoValid extends Base { | |
| 1464 AlsoValid() : super(); | |
| 1465 } | |
| 1466 | |
| 1467 main() => new Derived(); | |
| 1468 ''' | |
| 1469 }); | |
| 1470 | |
| 1471 testChecker('for loop variable', { | |
| 1472 '/main.dart': ''' | |
| 1473 foo() { | |
| 1474 for (int i = 0; i < 10; i++) { | |
| 1475 i = /*severe:StaticTypeError*/"hi"; | |
| 1476 } | |
| 1477 } | |
| 1478 bar() { | |
| 1479 for (var i = 0; i < 10; i++) { | |
| 1480 int j = i + 1; | |
| 1481 } | |
| 1482 } | |
| 1483 ''' | |
| 1484 }); | |
| 1485 | |
| 1486 group('invalid overrides', () { | |
| 1487 testChecker('child override', { | |
| 1488 '/main.dart': ''' | |
| 1489 class A {} | |
| 1490 class B {} | |
| 1491 | |
| 1492 class Base { | |
| 1493 A f; | |
| 1494 } | |
| 1495 | |
| 1496 class T1 extends Base { | |
| 1497 /*severe:InvalidMethodOverride*/B get f => null; | |
| 1498 } | |
| 1499 | |
| 1500 class T2 extends Base { | |
| 1501 /*severe:InvalidMethodOverride*/set f(B b) => null; | |
| 1502 } | |
| 1503 | |
| 1504 class T3 extends Base { | |
| 1505 /*severe:InvalidMethodOverride*/final B f; | |
| 1506 } | |
| 1507 class T4 extends Base { | |
| 1508 // two: one for the getter one for the setter. | |
| 1509 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f; | |
| 1510 } | |
| 1511 ''' | |
| 1512 }); | |
| 1513 | |
| 1514 testChecker('child override 2', { | |
| 1515 '/main.dart': ''' | |
| 1516 class A {} | |
| 1517 class B {} | |
| 1518 | |
| 1519 class Base { | |
| 1520 m(A a) {} | |
| 1521 } | |
| 1522 | |
| 1523 class Test extends Base { | |
| 1524 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1525 } | |
| 1526 ''' | |
| 1527 }); | |
| 1528 testChecker('grandchild override', { | |
| 1529 '/main.dart': ''' | |
| 1530 class A {} | |
| 1531 class B {} | |
| 1532 | |
| 1533 class Grandparent { | |
| 1534 m(A a) {} | |
| 1535 } | |
| 1536 class Parent extends Grandparent { | |
| 1537 } | |
| 1538 | |
| 1539 class Test extends Parent { | |
| 1540 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1541 } | |
| 1542 ''' | |
| 1543 }); | |
| 1544 | |
| 1545 testChecker('double override', { | |
| 1546 '/main.dart': ''' | |
| 1547 class A {} | |
| 1548 class B {} | |
| 1549 | |
| 1550 class Grandparent { | |
| 1551 m(A a) {} | |
| 1552 } | |
| 1553 class Parent extends Grandparent { | |
| 1554 m(A a) {} | |
| 1555 } | |
| 1556 | |
| 1557 class Test extends Parent { | |
| 1558 // Reported only once | |
| 1559 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1560 } | |
| 1561 ''' | |
| 1562 }); | |
| 1563 | |
| 1564 testChecker('double override 2', { | |
| 1565 '/main.dart': ''' | |
| 1566 class A {} | |
| 1567 class B {} | |
| 1568 | |
| 1569 class Grandparent { | |
| 1570 m(A a) {} | |
| 1571 } | |
| 1572 class Parent extends Grandparent { | |
| 1573 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1574 } | |
| 1575 | |
| 1576 class Test extends Parent { | |
| 1577 m(B a) {} | |
| 1578 } | |
| 1579 ''' | |
| 1580 }); | |
| 1581 | |
| 1582 testChecker('mixin override to base', { | |
| 1583 '/main.dart': ''' | |
| 1584 class A {} | |
| 1585 class B {} | |
| 1586 | |
| 1587 class Base { | |
| 1588 m(A a) {} | |
| 1589 } | |
| 1590 | |
| 1591 class M1 { | |
| 1592 m(B a) {} | |
| 1593 } | |
| 1594 | |
| 1595 class M2 {} | |
| 1596 | |
| 1597 class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {} | |
| 1598 class T2 extends Base with /*severe:InvalidMethodOverride*/M1, M2 {} | |
| 1599 class T3 extends Base with M2, /*severe:InvalidMethodOverride*/M1 {} | |
| 1600 ''' | |
| 1601 }); | |
| 1602 | |
| 1603 testChecker('mixin override to mixin', { | |
| 1604 '/main.dart': ''' | |
| 1605 class A {} | |
| 1606 class B {} | |
| 1607 | |
| 1608 class Base { | |
| 1609 } | |
| 1610 | |
| 1611 class M1 { | |
| 1612 m(B a) {} | |
| 1613 } | |
| 1614 | |
| 1615 class M2 { | |
| 1616 m(A a) {} | |
| 1617 } | |
| 1618 | |
| 1619 class T1 extends Base with M1, /*severe:InvalidMethodOverride*/M2 {} | |
| 1620 ''' | |
| 1621 }); | |
| 1622 | |
| 1623 // This is a regression test for a bug in an earlier implementation were | |
| 1624 // names were hiding errors if the first mixin override looked correct, | |
| 1625 // but subsequent ones did not. | |
| 1626 testChecker('no duplicate mixin override', { | |
| 1627 '/main.dart': ''' | |
| 1628 class A {} | |
| 1629 class B {} | |
| 1630 | |
| 1631 class Base { | |
| 1632 m(A a) {} | |
| 1633 } | |
| 1634 | |
| 1635 class M1 { | |
| 1636 m(A a) {} | |
| 1637 } | |
| 1638 | |
| 1639 class M2 { | |
| 1640 m(B a) {} | |
| 1641 } | |
| 1642 | |
| 1643 class M3 { | |
| 1644 m(B a) {} | |
| 1645 } | |
| 1646 | |
| 1647 class T1 extends Base | |
| 1648 with M1, /*severe:InvalidMethodOverride*/M2, M3 {} | |
| 1649 ''' | |
| 1650 }); | |
| 1651 | |
| 1652 testChecker('class override of interface', { | |
| 1653 '/main.dart': ''' | |
| 1654 class A {} | |
| 1655 class B {} | |
| 1656 | |
| 1657 abstract class I { | |
| 1658 m(A a); | |
| 1659 } | |
| 1660 | |
| 1661 class T1 implements I { | |
| 1662 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1663 } | |
| 1664 ''' | |
| 1665 }); | |
| 1666 | |
| 1667 testChecker('base class override to child interface', { | |
| 1668 '/main.dart': ''' | |
| 1669 class A {} | |
| 1670 class B {} | |
| 1671 | |
| 1672 abstract class I { | |
| 1673 m(A a); | |
| 1674 } | |
| 1675 | |
| 1676 class Base { | |
| 1677 m(B a) {} | |
| 1678 } | |
| 1679 | |
| 1680 | |
| 1681 class T1 /*severe:InvalidMethodOverride*/extends Base implements I { | |
| 1682 } | |
| 1683 ''' | |
| 1684 }); | |
| 1685 | |
| 1686 testChecker('mixin override of interface', { | |
| 1687 '/main.dart': ''' | |
| 1688 class A {} | |
| 1689 class B {} | |
| 1690 | |
| 1691 abstract class I { | |
| 1692 m(A a); | |
| 1693 } | |
| 1694 | |
| 1695 class M { | |
| 1696 m(B a) {} | |
| 1697 } | |
| 1698 | |
| 1699 class T1 extends Object with /*severe:InvalidMethodOverride*/M | |
| 1700 implements I {} | |
| 1701 ''' | |
| 1702 }); | |
| 1703 | |
| 1704 // This is a case were it is incorrect to say that the base class | |
| 1705 // incorrectly overrides the interface. | |
| 1706 testChecker( | |
| 1707 'no errors if subclass correctly overrides base and interface', { | |
| 1708 '/main.dart': ''' | |
| 1709 class A {} | |
| 1710 class B {} | |
| 1711 | |
| 1712 class Base { | |
| 1713 m(A a) {} | |
| 1714 } | |
| 1715 | |
| 1716 class I1 { | |
| 1717 m(B a) {} | |
| 1718 } | |
| 1719 | |
| 1720 class T1 /*severe:InvalidMethodOverride*/extends Base | |
| 1721 implements I1 {} | |
| 1722 | |
| 1723 class T2 extends Base implements I1 { | |
| 1724 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a
) {} | |
| 1725 } | |
| 1726 | |
| 1727 class T3 extends Object with /*severe:InvalidMethodOverride*/Base | |
| 1728 implements I1 {} | |
| 1729 | |
| 1730 class T4 extends Object with Base implements I1 { | |
| 1731 /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a
) {} | |
| 1732 } | |
| 1733 ''' | |
| 1734 }); | |
| 1735 }); | |
| 1736 | |
| 1737 group('class override of grand interface', () { | |
| 1738 testChecker('interface of interface of child', { | |
| 1739 '/main.dart': ''' | |
| 1740 class A {} | |
| 1741 class B {} | |
| 1742 | |
| 1743 abstract class I1 { | |
| 1744 m(A a); | |
| 1745 } | |
| 1746 abstract class I2 implements I1 {} | |
| 1747 | |
| 1748 class T1 implements I2 { | |
| 1749 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1750 } | |
| 1751 ''' | |
| 1752 }); | |
| 1753 testChecker('superclass of interface of child', { | |
| 1754 '/main.dart': ''' | |
| 1755 class A {} | |
| 1756 class B {} | |
| 1757 | |
| 1758 abstract class I1 { | |
| 1759 m(A a); | |
| 1760 } | |
| 1761 abstract class I2 extends I1 {} | |
| 1762 | |
| 1763 class T1 implements I2 { | |
| 1764 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1765 } | |
| 1766 ''' | |
| 1767 }); | |
| 1768 testChecker('mixin of interface of child', { | |
| 1769 '/main.dart': ''' | |
| 1770 class A {} | |
| 1771 class B {} | |
| 1772 | |
| 1773 abstract class M1 { | |
| 1774 m(A a); | |
| 1775 } | |
| 1776 abstract class I2 extends Object with M1 {} | |
| 1777 | |
| 1778 class T1 implements I2 { | |
| 1779 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1780 } | |
| 1781 ''' | |
| 1782 }); | |
| 1783 testChecker('interface of abstract superclass', { | |
| 1784 '/main.dart': ''' | |
| 1785 class A {} | |
| 1786 class B {} | |
| 1787 | |
| 1788 abstract class I1 { | |
| 1789 m(A a); | |
| 1790 } | |
| 1791 abstract class Base implements I1 {} | |
| 1792 | |
| 1793 class T1 extends Base { | |
| 1794 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1795 } | |
| 1796 ''' | |
| 1797 }); | |
| 1798 testChecker('interface of concrete superclass', { | |
| 1799 '/main.dart': ''' | |
| 1800 class A {} | |
| 1801 class B {} | |
| 1802 | |
| 1803 abstract class I1 { | |
| 1804 m(A a); | |
| 1805 } | |
| 1806 | |
| 1807 // See issue #25 | |
| 1808 /*pass should be warning:AnalyzerError*/class Base implements I1 { | |
| 1809 } | |
| 1810 | |
| 1811 class T1 extends Base { | |
| 1812 // not reported technically because if the class is concrete, | |
| 1813 // it should implement all its interfaces and hence it is | |
| 1814 // sufficient to check overrides against it. | |
| 1815 m(B a) {} | |
| 1816 } | |
| 1817 ''' | |
| 1818 }); | |
| 1819 }); | |
| 1820 | |
| 1821 group('mixin override of grand interface', () { | |
| 1822 testChecker('interface of interface of child', { | |
| 1823 '/main.dart': ''' | |
| 1824 class A {} | |
| 1825 class B {} | |
| 1826 | |
| 1827 abstract class I1 { | |
| 1828 m(A a); | |
| 1829 } | |
| 1830 abstract class I2 implements I1 {} | |
| 1831 | |
| 1832 class M { | |
| 1833 m(B a) {} | |
| 1834 } | |
| 1835 | |
| 1836 class T1 extends Object with /*severe:InvalidMethodOverride*/M | |
| 1837 implements I2 { | |
| 1838 } | |
| 1839 ''' | |
| 1840 }); | |
| 1841 testChecker('superclass of interface of child', { | |
| 1842 '/main.dart': ''' | |
| 1843 class A {} | |
| 1844 class B {} | |
| 1845 | |
| 1846 abstract class I1 { | |
| 1847 m(A a); | |
| 1848 } | |
| 1849 abstract class I2 extends I1 {} | |
| 1850 | |
| 1851 class M { | |
| 1852 m(B a) {} | |
| 1853 } | |
| 1854 | |
| 1855 class T1 extends Object with /*severe:InvalidMethodOverride*/M | |
| 1856 implements I2 { | |
| 1857 } | |
| 1858 ''' | |
| 1859 }); | |
| 1860 testChecker('mixin of interface of child', { | |
| 1861 '/main.dart': ''' | |
| 1862 class A {} | |
| 1863 class B {} | |
| 1864 | |
| 1865 abstract class M1 { | |
| 1866 m(A a); | |
| 1867 } | |
| 1868 abstract class I2 extends Object with M1 {} | |
| 1869 | |
| 1870 class M { | |
| 1871 m(B a) {} | |
| 1872 } | |
| 1873 | |
| 1874 class T1 extends Object with /*severe:InvalidMethodOverride*/M | |
| 1875 implements I2 { | |
| 1876 } | |
| 1877 ''' | |
| 1878 }); | |
| 1879 testChecker('interface of abstract superclass', { | |
| 1880 '/main.dart': ''' | |
| 1881 class A {} | |
| 1882 class B {} | |
| 1883 | |
| 1884 abstract class I1 { | |
| 1885 m(A a); | |
| 1886 } | |
| 1887 abstract class Base implements I1 {} | |
| 1888 | |
| 1889 class M { | |
| 1890 m(B a) {} | |
| 1891 } | |
| 1892 | |
| 1893 class T1 extends Base with /*severe:InvalidMethodOverride*/M { | |
| 1894 } | |
| 1895 ''' | |
| 1896 }); | |
| 1897 testChecker('interface of concrete superclass', { | |
| 1898 '/main.dart': ''' | |
| 1899 class A {} | |
| 1900 class B {} | |
| 1901 | |
| 1902 abstract class I1 { | |
| 1903 m(A a); | |
| 1904 } | |
| 1905 | |
| 1906 // See issue #25 | |
| 1907 /*pass should be warning:AnalyzerError*/class Base implements I1 { | |
| 1908 } | |
| 1909 | |
| 1910 class M { | |
| 1911 m(B a) {} | |
| 1912 } | |
| 1913 | |
| 1914 class T1 extends Base with M { | |
| 1915 } | |
| 1916 ''' | |
| 1917 }); | |
| 1918 }); | |
| 1919 | |
| 1920 group('superclass override of grand interface', () { | |
| 1921 testChecker('interface of interface of child', { | |
| 1922 '/main.dart': ''' | |
| 1923 class A {} | |
| 1924 class B {} | |
| 1925 | |
| 1926 abstract class I1 { | |
| 1927 m(A a); | |
| 1928 } | |
| 1929 abstract class I2 implements I1 {} | |
| 1930 | |
| 1931 class Base { | |
| 1932 m(B a) {} | |
| 1933 } | |
| 1934 | |
| 1935 class T1 /*severe:InvalidMethodOverride*/extends Base | |
| 1936 implements I2 { | |
| 1937 } | |
| 1938 ''' | |
| 1939 }); | |
| 1940 testChecker('superclass of interface of child', { | |
| 1941 '/main.dart': ''' | |
| 1942 class A {} | |
| 1943 class B {} | |
| 1944 | |
| 1945 abstract class I1 { | |
| 1946 m(A a); | |
| 1947 } | |
| 1948 abstract class I2 extends I1 {} | |
| 1949 | |
| 1950 class Base { | |
| 1951 m(B a) {} | |
| 1952 } | |
| 1953 | |
| 1954 class T1 /*severe:InvalidMethodOverride*/extends Base | |
| 1955 implements I2 { | |
| 1956 } | |
| 1957 ''' | |
| 1958 }); | |
| 1959 testChecker('mixin of interface of child', { | |
| 1960 '/main.dart': ''' | |
| 1961 class A {} | |
| 1962 class B {} | |
| 1963 | |
| 1964 abstract class M1 { | |
| 1965 m(A a); | |
| 1966 } | |
| 1967 abstract class I2 extends Object with M1 {} | |
| 1968 | |
| 1969 class Base { | |
| 1970 m(B a) {} | |
| 1971 } | |
| 1972 | |
| 1973 class T1 /*severe:InvalidMethodOverride*/extends Base | |
| 1974 implements I2 { | |
| 1975 } | |
| 1976 ''' | |
| 1977 }); | |
| 1978 testChecker('interface of abstract superclass', { | |
| 1979 '/main.dart': ''' | |
| 1980 class A {} | |
| 1981 class B {} | |
| 1982 | |
| 1983 abstract class I1 { | |
| 1984 m(A a); | |
| 1985 } | |
| 1986 | |
| 1987 abstract class Base implements I1 { | |
| 1988 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1989 } | |
| 1990 | |
| 1991 class T1 extends Base { | |
| 1992 // we consider the base class incomplete because it is | |
| 1993 // abstract, so we report the error here too. | |
| 1994 // TODO(sigmund): consider tracking overrides in a fine-grain | |
| 1995 // manner, then this and the double-overrides would not be | |
| 1996 // reported. | |
| 1997 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 1998 } | |
| 1999 ''' | |
| 2000 }); | |
| 2001 testChecker('interface of concrete superclass', { | |
| 2002 '/main.dart': ''' | |
| 2003 class A {} | |
| 2004 class B {} | |
| 2005 | |
| 2006 abstract class I1 { | |
| 2007 m(A a); | |
| 2008 } | |
| 2009 | |
| 2010 class Base implements I1 { | |
| 2011 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 2012 } | |
| 2013 | |
| 2014 class T1 extends Base { | |
| 2015 m(B a) {} | |
| 2016 } | |
| 2017 ''' | |
| 2018 }); | |
| 2019 }); | |
| 2020 | |
| 2021 group('no duplicate reports from overriding interfaces', () { | |
| 2022 testChecker('type overrides same method in multiple interfaces', { | |
| 2023 '/main.dart': ''' | |
| 2024 class A {} | |
| 2025 class B {} | |
| 2026 | |
| 2027 abstract class I1 { | |
| 2028 m(A a); | |
| 2029 } | |
| 2030 abstract class I2 implements I1 { | |
| 2031 m(A a); | |
| 2032 } | |
| 2033 | |
| 2034 class Base { | |
| 2035 } | |
| 2036 | |
| 2037 class T1 implements I2 { | |
| 2038 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 2039 } | |
| 2040 ''' | |
| 2041 }); | |
| 2042 | |
| 2043 testChecker('type and base type override same method in interface', { | |
| 2044 '/main.dart': ''' | |
| 2045 class A {} | |
| 2046 class B {} | |
| 2047 | |
| 2048 abstract class I1 { | |
| 2049 m(A a); | |
| 2050 } | |
| 2051 | |
| 2052 class Base { | |
| 2053 m(B a); | |
| 2054 } | |
| 2055 | |
| 2056 // Note: no error reported in `extends Base` to avoid duplicating | |
| 2057 // the error in T1. | |
| 2058 class T1 extends Base implements I1 { | |
| 2059 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 2060 } | |
| 2061 | |
| 2062 // If there is no error in the class, we do report the error at | |
| 2063 // the base class: | |
| 2064 class T2 /*severe:InvalidMethodOverride*/extends Base | |
| 2065 implements I1 { | |
| 2066 } | |
| 2067 ''' | |
| 2068 }); | |
| 2069 | |
| 2070 testChecker('type and mixin override same method in interface', { | |
| 2071 '/main.dart': ''' | |
| 2072 class A {} | |
| 2073 class B {} | |
| 2074 | |
| 2075 abstract class I1 { | |
| 2076 m(A a); | |
| 2077 } | |
| 2078 | |
| 2079 class M { | |
| 2080 m(B a); | |
| 2081 } | |
| 2082 | |
| 2083 class T1 extends Object with M implements I1 { | |
| 2084 /*severe:InvalidMethodOverride*/m(B a) {} | |
| 2085 } | |
| 2086 | |
| 2087 class T2 extends Object with /*severe:InvalidMethodOverride*/M | |
| 2088 implements I1 { | |
| 2089 } | |
| 2090 ''' | |
| 2091 }); | |
| 2092 | |
| 2093 testChecker('two grand types override same method in interface', { | |
| 2094 '/main.dart': ''' | |
| 2095 class A {} | |
| 2096 class B {} | |
| 2097 | |
| 2098 abstract class I1 { | |
| 2099 m(A a); | |
| 2100 } | |
| 2101 | |
| 2102 class Grandparent { | |
| 2103 m(B a) {} | |
| 2104 } | |
| 2105 | |
| 2106 class Parent1 extends Grandparent { | |
| 2107 m(B a) {} | |
| 2108 } | |
| 2109 class Parent2 extends Grandparent { | |
| 2110 } | |
| 2111 | |
| 2112 // Note: otherwise both errors would be reported on this line | |
| 2113 class T1 /*severe:InvalidMethodOverride*/extends Parent1 | |
| 2114 implements I1 { | |
| 2115 } | |
| 2116 class T2 /*severe:InvalidMethodOverride*/extends Parent2 | |
| 2117 implements I1 { | |
| 2118 } | |
| 2119 ''' | |
| 2120 }); | |
| 2121 | |
| 2122 testChecker('two mixins override same method in interface', { | |
| 2123 '/main.dart': ''' | |
| 2124 class A {} | |
| 2125 class B {} | |
| 2126 | |
| 2127 abstract class I1 { | |
| 2128 m(A a); | |
| 2129 } | |
| 2130 | |
| 2131 class M1 { | |
| 2132 m(B a) {} | |
| 2133 } | |
| 2134 | |
| 2135 class M2 { | |
| 2136 m(B a) {} | |
| 2137 } | |
| 2138 | |
| 2139 // Here we want to report both, because the error location is | |
| 2140 // different. | |
| 2141 // TODO(sigmund): should we merge these as well? | |
| 2142 class T1 extends Object | |
| 2143 with /*severe:InvalidMethodOverride*/M1 | |
| 2144 with /*severe:InvalidMethodOverride*/M2 | |
| 2145 implements I1 { | |
| 2146 } | |
| 2147 ''' | |
| 2148 }); | |
| 2149 | |
| 2150 testChecker('base type and mixin override same method in interface', { | |
| 2151 '/main.dart': ''' | |
| 2152 class A {} | |
| 2153 class B {} | |
| 2154 | |
| 2155 abstract class I1 { | |
| 2156 m(A a); | |
| 2157 } | |
| 2158 | |
| 2159 class Base { | |
| 2160 m(B a) {} | |
| 2161 } | |
| 2162 | |
| 2163 class M { | |
| 2164 m(B a) {} | |
| 2165 } | |
| 2166 | |
| 2167 // Here we want to report both, because the error location is | |
| 2168 // different. | |
| 2169 // TODO(sigmund): should we merge these as well? | |
| 2170 class T1 /*severe:InvalidMethodOverride*/extends Base | |
| 2171 with /*severe:InvalidMethodOverride*/M | |
| 2172 implements I1 { | |
| 2173 } | |
| 2174 ''' | |
| 2175 }); | |
| 2176 }); | |
| 2177 | |
| 2178 testChecker('invalid runtime checks', { | |
| 2179 '/main.dart': ''' | |
| 2180 typedef int I2I(int x); | |
| 2181 typedef int D2I(x); | |
| 2182 typedef int II2I(int x, int y); | |
| 2183 typedef int DI2I(x, int y); | |
| 2184 typedef int ID2I(int x, y); | |
| 2185 typedef int DD2I(x, y); | |
| 2186 | |
| 2187 typedef I2D(int x); | |
| 2188 typedef D2D(x); | |
| 2189 typedef II2D(int x, int y); | |
| 2190 typedef DI2D(x, int y); | |
| 2191 typedef ID2D(int x, y); | |
| 2192 typedef DD2D(x, y); | |
| 2193 | |
| 2194 int foo(int x) => x; | |
| 2195 int bar(int x, int y) => x + y; | |
| 2196 | |
| 2197 void main() { | |
| 2198 bool b; | |
| 2199 b = /*info:NonGroundTypeCheckInfo*/foo is I2I; | |
| 2200 b = /*info:NonGroundTypeCheckInfo*/foo is D2I; | |
| 2201 b = /*info:NonGroundTypeCheckInfo*/foo is I2D; | |
| 2202 b = foo is D2D; | |
| 2203 | |
| 2204 b = /*info:NonGroundTypeCheckInfo*/bar is II2I; | |
| 2205 b = /*info:NonGroundTypeCheckInfo*/bar is DI2I; | |
| 2206 b = /*info:NonGroundTypeCheckInfo*/bar is ID2I; | |
| 2207 b = /*info:NonGroundTypeCheckInfo*/bar is II2D; | |
| 2208 b = /*info:NonGroundTypeCheckInfo*/bar is DD2I; | |
| 2209 b = /*info:NonGroundTypeCheckInfo*/bar is DI2D; | |
| 2210 b = /*info:NonGroundTypeCheckInfo*/bar is ID2D; | |
| 2211 b = bar is DD2D; | |
| 2212 | |
| 2213 // For as, the validity of checks is deferred to runtime. | |
| 2214 Function f; | |
| 2215 f = foo as I2I; | |
| 2216 f = foo as D2I; | |
| 2217 f = foo as I2D; | |
| 2218 f = foo as D2D; | |
| 2219 | |
| 2220 f = bar as II2I; | |
| 2221 f = bar as DI2I; | |
| 2222 f = bar as ID2I; | |
| 2223 f = bar as II2D; | |
| 2224 f = bar as DD2I; | |
| 2225 f = bar as DI2D; | |
| 2226 f = bar as ID2D; | |
| 2227 f = bar as DD2D; | |
| 2228 } | |
| 2229 ''' | |
| 2230 }); | |
| 2231 | |
| 2232 testChecker('custom URL mappings', { | |
| 2233 '/main.dart': ''' | |
| 2234 import 'dart:foobar' show Baz; | |
| 2235 main() { | |
| 2236 print(Baz.quux); | |
| 2237 }''' | |
| 2238 }, customUrlMappings: { | |
| 2239 'dart:foobar': '$testDirectory/checker/dart_foobar.dart' | |
| 2240 }); | |
| 2241 | |
| 2242 group('function modifiers', () { | |
| 2243 testChecker('async', { | |
| 2244 '/main.dart': ''' | |
| 2245 import 'dart:async'; | |
| 2246 import 'dart:math' show Random; | |
| 2247 | |
| 2248 dynamic x; | |
| 2249 | |
| 2250 foo1() async => x; | |
| 2251 Future foo2() async => x; | |
| 2252 Future<int> foo3() async => (/*info:DynamicCast*/x); | |
| 2253 Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.v
alue(/*info:DynamicCast*/x)); | |
| 2254 | |
| 2255 bar1() async { return x; } | |
| 2256 Future bar2() async { return x; } | |
| 2257 Future<int> bar3() async { return (/*info:DynamicCast*/x); } | |
| 2258 Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<
int>.value(/*info:DynamicCast*/x)); } | |
| 2259 | |
| 2260 int y; | |
| 2261 Future<int> z; | |
| 2262 | |
| 2263 void baz() async { | |
| 2264 int a = /*info:DynamicCast*/await x; | |
| 2265 int b = await y; | |
| 2266 int c = await z; | |
| 2267 String d = /*severe:StaticTypeError*/await z; | |
| 2268 } | |
| 2269 | |
| 2270 Future<bool> get issue_264 async { | |
| 2271 await 42; | |
| 2272 if (new Random().nextBool()) { | |
| 2273 return true; | |
| 2274 } else { | |
| 2275 return /*severe:StaticTypeError*/new Future<bool>.value(false); | |
| 2276 } | |
| 2277 } | |
| 2278 ''' | |
| 2279 }); | |
| 2280 | |
| 2281 testChecker('async*', { | |
| 2282 '/main.dart': ''' | |
| 2283 import 'dart:async'; | |
| 2284 | |
| 2285 dynamic x; | |
| 2286 | |
| 2287 bar1() async* { yield x; } | |
| 2288 Stream bar2() async* { yield x; } | |
| 2289 Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); } | |
| 2290 Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<
int>()); } | |
| 2291 | |
| 2292 baz1() async* { yield* (/*info:DynamicCast*/x); } | |
| 2293 Stream baz2() async* { yield* (/*info:DynamicCast*/x); } | |
| 2294 Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); } | |
| 2295 Stream<int> baz4() async* { yield* new Stream<int>(); } | |
| 2296 Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new S
tream()); } | |
| 2297 ''' | |
| 2298 }); | |
| 2299 | |
| 2300 testChecker('sync*', { | |
| 2301 '/main.dart': ''' | |
| 2302 import 'dart:async'; | |
| 2303 | |
| 2304 dynamic x; | |
| 2305 | |
| 2306 bar1() sync* { yield x; } | |
| 2307 Iterable bar2() sync* { yield x; } | |
| 2308 Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); } | |
| 2309 Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterab
le<int>()); } | |
| 2310 | |
| 2311 baz1() sync* { yield* (/*info:DynamicCast*/x); } | |
| 2312 Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); } | |
| 2313 Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); } | |
| 2314 Iterable<int> baz4() sync* { yield* new Iterable<int>(); } | |
| 2315 Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new
Iterable()); } | |
| 2316 ''' | |
| 2317 }); | |
| 2318 }); | |
| 2319 } | |
| OLD | NEW |