| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Tests for type inference. | 5 /// Tests for type inference. |
| 6 library dev_compiler.test.inferred_type_test; | 6 library dev_compiler.test.inferred_type_test; |
| 7 | 7 |
| 8 import 'package:unittest/unittest.dart'; | 8 import 'package:unittest/unittest.dart'; |
| 9 | 9 |
| 10 import 'package:dev_compiler/src/testing.dart'; | 10 import 'package:dev_compiler/src/testing.dart'; |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 y = /*severe:StaticTypeError*/"hi"; | 155 y = /*severe:StaticTypeError*/"hi"; |
| 156 A.x = "hi"; | 156 A.x = "hi"; |
| 157 A.y = /*severe:StaticTypeError*/"hi"; | 157 A.y = /*severe:StaticTypeError*/"hi"; |
| 158 new A().x2 = "hi"; | 158 new A().x2 = "hi"; |
| 159 new A().y2 = /*severe:StaticTypeError*/"hi"; | 159 new A().y2 = /*severe:StaticTypeError*/"hi"; |
| 160 } | 160 } |
| 161 ''' | 161 ''' |
| 162 }); | 162 }); |
| 163 }); | 163 }); |
| 164 | 164 |
| 165 test('do not infer from variables in same lib (order independence)', () { | 165 test('do not infer from variables if flag is off', () { |
| 166 testChecker({ | 166 testChecker({ |
| 167 '/main.dart': ''' | 167 '/main.dart': ''' |
| 168 var x = 2; | 168 var x = 2; |
| 169 var y = x; | 169 var y = x; |
| 170 | 170 |
| 171 test1() { | 171 test1() { |
| 172 x = /*severe:StaticTypeError*/"hi"; | 172 x = /*severe:StaticTypeError*/"hi"; |
| 173 y = "hi"; | 173 y = "hi"; |
| 174 } | 174 } |
| 175 ''' | 175 ''' |
| 176 }); | 176 }, inferTransitively: false); |
| 177 | 177 |
| 178 testChecker({ | 178 testChecker({ |
| 179 '/main.dart': ''' | 179 '/main.dart': ''' |
| 180 class A { | 180 class A { |
| 181 static var x = 2; | 181 static var x = 2; |
| 182 static var y = A.x; | 182 static var y = A.x; |
| 183 } | 183 } |
| 184 | 184 |
| 185 test1() { | 185 test1() { |
| 186 A.x = /*severe:StaticTypeError*/"hi"; | 186 A.x = /*severe:StaticTypeError*/"hi"; |
| 187 A.y = "hi"; | 187 A.y = "hi"; |
| 188 } | 188 } |
| 189 ''' | 189 ''' |
| 190 }); | 190 }, inferTransitively: false); |
| 191 }); | 191 }); |
| 192 | 192 |
| 193 test('not ok to infer from variables in non-cycle libs', () { | 193 test('do not infer from variables in non-cycle imports if flag is off', () { |
| 194 testChecker({ | 194 testChecker({ |
| 195 '/a.dart': ''' | 195 '/a.dart': ''' |
| 196 var x = 2; | 196 var x = 2; |
| 197 ''', | 197 ''', |
| 198 '/main.dart': ''' | 198 '/main.dart': ''' |
| 199 import 'a.dart'; | 199 import 'a.dart'; |
| 200 var y = x; | 200 var y = x; |
| 201 | 201 |
| 202 test1() { | 202 test1() { |
| 203 x = /*severe:StaticTypeError*/"hi"; | 203 x = /*severe:StaticTypeError*/"hi"; |
| 204 y = "hi"; | 204 y = "hi"; |
| 205 } | 205 } |
| 206 ''' | 206 ''' |
| 207 }); | 207 }, inferTransitively: false); |
| 208 | 208 |
| 209 testChecker({ | 209 testChecker({ |
| 210 '/a.dart': ''' | 210 '/a.dart': ''' |
| 211 class A { static var x = 2; } | 211 class A { static var x = 2; } |
| 212 ''', | 212 ''', |
| 213 '/main.dart': ''' | 213 '/main.dart': ''' |
| 214 import 'a.dart'; | 214 import 'a.dart'; |
| 215 class B { static var y = A.x; } | 215 class B { static var y = A.x; } |
| 216 | 216 |
| 217 test1() { | 217 test1() { |
| 218 A.x = /*severe:StaticTypeError*/"hi"; | 218 A.x = /*severe:StaticTypeError*/"hi"; |
| 219 B.y = "hi"; | 219 B.y = "hi"; |
| 220 } | 220 } |
| 221 ''' | 221 ''' |
| 222 }); | 222 }, inferTransitively: false); |
| 223 }); | 223 }); |
| 224 | 224 |
| 225 test('ok to infer from variables in non-cycle libs with flag', () { | 225 test('infer from variables in non-cycle imports with flag', () { |
| 226 testChecker({ | 226 testChecker({ |
| 227 '/a.dart': ''' | 227 '/a.dart': ''' |
| 228 var x = 2; | 228 var x = 2; |
| 229 ''', | 229 ''', |
| 230 '/main.dart': ''' | 230 '/main.dart': ''' |
| 231 import 'a.dart'; | 231 import 'a.dart'; |
| 232 var y = x; | 232 var y = x; |
| 233 | 233 |
| 234 test1() { | 234 test1() { |
| 235 x = /*severe:StaticTypeError*/"hi"; | 235 x = /*severe:StaticTypeError*/"hi"; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 247 class B { static var y = A.x; } | 247 class B { static var y = A.x; } |
| 248 | 248 |
| 249 test1() { | 249 test1() { |
| 250 A.x = /*severe:StaticTypeError*/"hi"; | 250 A.x = /*severe:StaticTypeError*/"hi"; |
| 251 B.y = /*severe:StaticTypeError*/"hi"; | 251 B.y = /*severe:StaticTypeError*/"hi"; |
| 252 } | 252 } |
| 253 ''' | 253 ''' |
| 254 }, inferTransitively: true); | 254 }, inferTransitively: true); |
| 255 }); | 255 }); |
| 256 | 256 |
| 257 test('do not infer from variables in cycle libs', () { | 257 test('do not infer from variables in cycle libs when flag is off', () { |
| 258 testChecker({ | 258 testChecker({ |
| 259 '/a.dart': ''' | 259 '/a.dart': ''' |
| 260 import 'main.dart'; | 260 import 'main.dart'; |
| 261 var x = 2; // ok to infer | 261 var x = 2; // ok to infer |
| 262 ''', | 262 ''', |
| 263 '/main.dart': ''' | 263 '/main.dart': ''' |
| 264 import 'a.dart'; | 264 import 'a.dart'; |
| 265 var y = x; // not ok to infer yet | 265 var y = x; // not ok to infer yet |
| 266 | 266 |
| 267 test1() { | 267 test1() { |
| 268 int t = 3; | 268 int t = 3; |
| 269 t = x; | 269 t = x; |
| 270 t = /*info:DownCast*/y; | 270 t = /*info:DownCast*/y; |
| 271 } | 271 } |
| 272 ''' | 272 ''' |
| 273 }, inferTransitively: false); |
| 274 |
| 275 testChecker({ |
| 276 '/a.dart': ''' |
| 277 import 'main.dart'; |
| 278 class A { static var x = 2; } |
| 279 ''', |
| 280 '/main.dart': ''' |
| 281 import 'a.dart'; |
| 282 class B { static var y = A.x; } |
| 283 |
| 284 test1() { |
| 285 int t = 3; |
| 286 t = A.x; |
| 287 t = /*info:DownCast*/B.y; |
| 288 } |
| 289 ''' |
| 290 }, inferTransitively: false); |
| 291 }); |
| 292 |
| 293 test('infer from variables in cycle libs when flag is on', () { |
| 294 testChecker({ |
| 295 '/a.dart': ''' |
| 296 import 'main.dart'; |
| 297 var x = 2; // ok to infer |
| 298 ''', |
| 299 '/main.dart': ''' |
| 300 import 'a.dart'; |
| 301 var y = x; // now ok :) |
| 302 |
| 303 test1() { |
| 304 int t = 3; |
| 305 t = x; |
| 306 t = y; |
| 307 } |
| 308 ''' |
| 273 }, inferTransitively: true); | 309 }, inferTransitively: true); |
| 274 | 310 |
| 275 testChecker({ | 311 testChecker({ |
| 276 '/a.dart': ''' | 312 '/a.dart': ''' |
| 277 import 'main.dart'; | 313 import 'main.dart'; |
| 278 class A { static var x = 2; } | 314 class A { static var x = 2; } |
| 279 ''', | 315 ''', |
| 280 '/main.dart': ''' | 316 '/main.dart': ''' |
| 281 import 'a.dart'; | 317 import 'a.dart'; |
| 282 class B { static var y = A.x; } | 318 class B { static var y = A.x; } |
| 283 | 319 |
| 284 test1() { | 320 test1() { |
| 285 int t = 3; | 321 int t = 3; |
| 286 t = A.x; | 322 t = A.x; |
| 287 t = /*info:DownCast*/A.y; | 323 t = B.y; |
| 288 } | 324 } |
| 289 ''' | 325 ''' |
| 290 }, inferTransitively: true); | 326 }, inferTransitively: true); |
| 291 }); | 327 }); |
| 292 | 328 |
| 293 test('do not infer from static and instance fields', () { | 329 test('do not infer from static and instance fields when flag is off', () { |
| 294 testChecker({ | 330 testChecker({ |
| 295 '/a.dart': ''' | 331 '/a.dart': ''' |
| 296 import 'b.dart'; | 332 import 'b.dart'; |
| 297 class A { | 333 class A { |
| 298 static final a1 = B.b1; | 334 static final a1 = B.b1; |
| 299 final a2 = new B().b2; | 335 final a2 = new B().b2; |
| 300 } | 336 } |
| 301 ''', | 337 ''', |
| 302 '/b.dart': ''' | 338 '/b.dart': ''' |
| 303 class B { | 339 class B { |
| 304 static final b1 = 1; | 340 static final b1 = 1; |
| 305 final b2 = 1; | 341 final b2 = 1; |
| 306 } | 342 } |
| 307 ''', | 343 ''', |
| 308 '/main.dart': ''' | 344 '/main.dart': ''' |
| 309 import "a.dart"; | 345 import "a.dart"; |
| 310 | 346 |
| 311 test1() { | 347 test1() { |
| 312 int x = 0; | 348 int x = 0; |
| 313 // inference in A disabled (flag is off) | 349 // inference in A disabled (flag is off) |
| 314 x = /*info:DownCast*/A.a1; | 350 x = /*info:DownCast*/A.a1; |
| 315 x = /*info:DownCast*/new A().a2; | 351 x = /*info:DownCast*/new A().a2; |
| 316 } | 352 } |
| 317 ''' | 353 ''' |
| 318 }); | 354 }, inferTransitively: false); |
| 319 }); | 355 }); |
| 320 | 356 |
| 321 test('can infer also from static and instance fields (flag on)', () { | 357 test('can infer also from static and instance fields (flag on)', () { |
| 322 testChecker({ | 358 testChecker({ |
| 323 '/a.dart': ''' | 359 '/a.dart': ''' |
| 324 import 'b.dart'; | 360 import 'b.dart'; |
| 325 class A { | 361 class A { |
| 326 static final a1 = B.b1; | 362 static final a1 = B.b1; |
| 327 final a2 = new B().b2; | 363 final a2 = new B().b2; |
| 328 } | 364 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 339 test1() { | 375 test1() { |
| 340 int x = 0; | 376 int x = 0; |
| 341 // inference in A now works. | 377 // inference in A now works. |
| 342 x = A.a1; | 378 x = A.a1; |
| 343 x = new A().a2; | 379 x = new A().a2; |
| 344 } | 380 } |
| 345 ''' | 381 ''' |
| 346 }, inferTransitively: true); | 382 }, inferTransitively: true); |
| 347 }); | 383 }); |
| 348 | 384 |
| 349 test('inference uses declared types', () { | |
| 350 testChecker({ | |
| 351 '/main.dart': ''' | |
| 352 int w = 0; | |
| 353 var x = 0; | |
| 354 | |
| 355 var y = w; // y can be inferred because w is typed int. | |
| 356 var z = x; // z cannot, because x would be inferred. | |
| 357 | |
| 358 test1() { | |
| 359 int a; | |
| 360 a = w; | |
| 361 a = x; | |
| 362 a = y; | |
| 363 a = /*info:DownCast*/z; | |
| 364 } | |
| 365 ''' | |
| 366 }, inferTransitively: true); | |
| 367 }); | |
| 368 | |
| 369 test('inference in cycles is deterministic', () { | 385 test('inference in cycles is deterministic', () { |
| 370 testChecker({ | 386 testChecker({ |
| 371 '/a.dart': ''' | 387 '/a.dart': ''' |
| 372 import 'b.dart'; | 388 import 'b.dart'; |
| 373 class A { | 389 class A { |
| 374 static final a1 = B.b1; | 390 static final a1 = B.b1; |
| 375 final a2 = new B().b2; | 391 final a2 = new B().b2; |
| 376 } | 392 } |
| 377 ''', | 393 ''', |
| 378 '/b.dart': ''' | 394 '/b.dart': ''' |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 test1() { | 442 test1() { |
| 427 int x = 0; | 443 int x = 0; |
| 428 // inference in A works, it's not in a cycle | 444 // inference in A works, it's not in a cycle |
| 429 x = A.a1; | 445 x = A.a1; |
| 430 x = new A().a2; | 446 x = new A().a2; |
| 431 | 447 |
| 432 // Within a cycle we allow inference when the RHS is well known, but | 448 // Within a cycle we allow inference when the RHS is well known, but |
| 433 // not when it depends on other fields within the cycle | 449 // not when it depends on other fields within the cycle |
| 434 x = C.c1; | 450 x = C.c1; |
| 435 x = D.d1; | 451 x = D.d1; |
| 436 x = /*info:DownCast*/D.d2; | 452 x = D.d2; |
| 437 x = new C().c2; | 453 x = new C().c2; |
| 438 x = new D().d3; | 454 x = new D().d3; |
| 439 x = /*info:DownCast*/new D().d4; | 455 x = /*info:DownCast*/new D().d4; |
| 440 | 456 |
| 441 | 457 |
| 442 // Similarly if the library contains parts. | 458 // Similarly if the library contains parts. |
| 443 x = E.e1; | 459 x = E.e1; |
| 444 x = /*info:DownCast*/E.e2; | 460 x = E.e2; |
| 445 x = E.e3; | 461 x = E.e3; |
| 446 x = new E().e4; | 462 x = new E().e4; |
| 447 x = /*info:DownCast*/new E().e5; | 463 x = /*info:DownCast*/new E().e5; |
| 448 x = new E().e6; | 464 x = new E().e6; |
| 449 x = F.f1; | 465 x = F.f1; |
| 450 x = new F().f2; | 466 x = new F().f2; |
| 451 } | 467 } |
| 452 ''' | 468 ''' |
| 453 }, inferTransitively: true); | 469 }, inferTransitively: true); |
| 454 }); | 470 }); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 int i = 0; | 538 int i = 0; |
| 523 A a; | 539 A a; |
| 524 B b; | 540 B b; |
| 525 a = t1; | 541 a = t1; |
| 526 i = /*info:DownCast*/t2; | 542 i = /*info:DownCast*/t2; |
| 527 b = t3; | 543 b = t3; |
| 528 i = /*info:DownCast*/t4; | 544 i = /*info:DownCast*/t4; |
| 529 i = new B().y; // B.y was inferred though | 545 i = new B().y; // B.y was inferred though |
| 530 } | 546 } |
| 531 ''' | 547 ''' |
| 532 }); | 548 }, inferTransitively: false); |
| 533 | 549 |
| 534 // but flags can enable this behavior. | 550 // but flags can enable this behavior. |
| 535 testChecker({ | 551 testChecker({ |
| 536 '/a.dart': ''' | 552 '/a.dart': ''' |
| 537 class A { | 553 class A { |
| 538 var x = 3; | 554 var x = 3; |
| 539 } | 555 } |
| 540 ''', | 556 ''', |
| 541 '/main.dart': ''' | 557 '/main.dart': ''' |
| 542 import 'a.dart'; | 558 import 'a.dart'; |
| (...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 s = /*severe:StaticTypeError*/new B().w; | 1061 s = /*severe:StaticTypeError*/new B().w; |
| 1046 | 1062 |
| 1047 i = /*info:DownCast*/new B().x; | 1063 i = /*info:DownCast*/new B().x; |
| 1048 i = new B().y; | 1064 i = new B().y; |
| 1049 i = /*severe:StaticTypeError*/new B().z; | 1065 i = /*severe:StaticTypeError*/new B().z; |
| 1050 i = new B().w; | 1066 i = new B().w; |
| 1051 } | 1067 } |
| 1052 ''' | 1068 ''' |
| 1053 }, inferFromOverrides: true); | 1069 }, inferFromOverrides: true); |
| 1054 }); | 1070 }); |
| 1071 |
| 1072 test('infer consts transitively', () { |
| 1073 testChecker({ |
| 1074 '/b.dart': ''' |
| 1075 const b1 = 2; |
| 1076 ''', |
| 1077 '/a.dart': ''' |
| 1078 import 'main.dart'; |
| 1079 import 'b.dart'; |
| 1080 const a1 = m2; |
| 1081 const a2 = b1; |
| 1082 ''', |
| 1083 '/main.dart': ''' |
| 1084 import 'a.dart'; |
| 1085 const m1 = a1; |
| 1086 const m2 = a2; |
| 1087 |
| 1088 foo() { |
| 1089 int i; |
| 1090 i = m1; |
| 1091 } |
| 1092 ''' |
| 1093 }, inferFromOverrides: true, inferTransitively: true); |
| 1094 }); |
| 1095 |
| 1096 test('infer statics transitively', () { |
| 1097 testChecker({ |
| 1098 '/b.dart': ''' |
| 1099 final b1 = 2; |
| 1100 ''', |
| 1101 '/a.dart': ''' |
| 1102 import 'main.dart'; |
| 1103 import 'b.dart'; |
| 1104 final a1 = m2; |
| 1105 class A { |
| 1106 static final a2 = b1; |
| 1107 } |
| 1108 ''', |
| 1109 '/main.dart': ''' |
| 1110 import 'a.dart'; |
| 1111 final m1 = a1; |
| 1112 final m2 = A.a2; |
| 1113 |
| 1114 foo() { |
| 1115 int i; |
| 1116 i = m1; |
| 1117 } |
| 1118 ''' |
| 1119 }, inferFromOverrides: true, inferTransitively: true); |
| 1120 |
| 1121 testChecker({ |
| 1122 '/main.dart': ''' |
| 1123 const x1 = 1; |
| 1124 final x2 = 1; |
| 1125 final y1 = x1; |
| 1126 final y2 = x2; |
| 1127 |
| 1128 foo() { |
| 1129 int i; |
| 1130 i = y1; |
| 1131 i = y2; |
| 1132 } |
| 1133 ''' |
| 1134 }, inferFromOverrides: true, inferTransitively: true); |
| 1135 |
| 1136 testChecker({ |
| 1137 '/a.dart': ''' |
| 1138 const a1 = 3; |
| 1139 const a2 = 4; |
| 1140 class A { |
| 1141 a3; |
| 1142 } |
| 1143 ''', |
| 1144 '/main.dart': ''' |
| 1145 import 'a.dart' show a1, A; |
| 1146 import 'a.dart' as p show a2, A; |
| 1147 const t1 = 1; |
| 1148 const t2 = t1; |
| 1149 const t3 = a1; |
| 1150 const t4 = p.a2; |
| 1151 const t5 = A.a3; |
| 1152 const t6 = p.A.a3; |
| 1153 |
| 1154 foo() { |
| 1155 int i; |
| 1156 i = t1; |
| 1157 i = t2; |
| 1158 i = t3; |
| 1159 i = t4; |
| 1160 } |
| 1161 ''' |
| 1162 }, inferFromOverrides: true, inferTransitively: true); |
| 1163 }); |
| 1164 |
| 1165 test('infer statics with method invocations', () { |
| 1166 testChecker({ |
| 1167 '/a.dart': ''' |
| 1168 m3(String a, String b, [a1,a2]) {} |
| 1169 ''', |
| 1170 '/main.dart': ''' |
| 1171 import 'a.dart'; |
| 1172 class T { |
| 1173 static final T foo = m1(m2(m3('', ''))); |
| 1174 static T m1(String m) { return null; } |
| 1175 static String m2(e) { return ''; } |
| 1176 } |
| 1177 |
| 1178 |
| 1179 ''' |
| 1180 }, inferFromOverrides: true, inferTransitively: true); |
| 1181 }); |
| 1055 } | 1182 } |
| OLD | NEW |