| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library inferrer_visitor; | 5 library inferrer_visitor; |
| 6 | 6 |
| 7 import 'dart:collection' show | 7 import 'dart:collection' show IterableMixin; |
| 8 IterableMixin; | |
| 9 | 8 |
| 10 import '../common.dart'; | 9 import '../common.dart'; |
| 11 import '../compiler.dart' show | 10 import '../compiler.dart' show Compiler; |
| 12 Compiler; | |
| 13 import '../constants/constant_system.dart'; | 11 import '../constants/constant_system.dart'; |
| 14 import '../constants/expressions.dart'; | 12 import '../constants/expressions.dart'; |
| 15 import '../dart_types.dart'; | 13 import '../dart_types.dart'; |
| 16 import '../elements/elements.dart'; | 14 import '../elements/elements.dart'; |
| 17 import '../resolution/operators.dart'; | 15 import '../resolution/operators.dart'; |
| 18 import '../resolution/semantic_visitor.dart'; | 16 import '../resolution/semantic_visitor.dart'; |
| 19 import '../resolution/tree_elements.dart' show | 17 import '../resolution/tree_elements.dart' show TreeElements; |
| 20 TreeElements; | |
| 21 import '../tree/tree.dart'; | 18 import '../tree/tree.dart'; |
| 22 import '../types/types.dart' show | 19 import '../types/types.dart' show TypeMask; |
| 23 TypeMask; | 20 import '../types/constants.dart' show computeTypeMask; |
| 24 import '../types/constants.dart' show | 21 import '../universe/call_structure.dart' show CallStructure; |
| 25 computeTypeMask; | 22 import '../universe/selector.dart' show Selector; |
| 26 import '../universe/call_structure.dart' show | |
| 27 CallStructure; | |
| 28 import '../universe/selector.dart' show | |
| 29 Selector; | |
| 30 import '../util/util.dart'; | 23 import '../util/util.dart'; |
| 31 import '../world.dart' show | 24 import '../world.dart' show ClassWorld; |
| 32 ClassWorld; | |
| 33 | 25 |
| 34 /** | 26 /** |
| 35 * The interface [InferrerVisitor] will use when working on types. | 27 * The interface [InferrerVisitor] will use when working on types. |
| 36 */ | 28 */ |
| 37 abstract class TypeSystem<T> { | 29 abstract class TypeSystem<T> { |
| 38 T get dynamicType; | 30 T get dynamicType; |
| 39 T get nullType; | 31 T get nullType; |
| 40 T get intType; | 32 T get intType; |
| 41 T get uint31Type; | 33 T get uint31Type; |
| 42 T get uint32Type; | 34 T get uint32Type; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 60 T stringLiteralType(DartString value); | 52 T stringLiteralType(DartString value); |
| 61 T boolLiteralType(LiteralBool value); | 53 T boolLiteralType(LiteralBool value); |
| 62 | 54 |
| 63 T nonNullSubtype(ClassElement type); | 55 T nonNullSubtype(ClassElement type); |
| 64 T nonNullSubclass(ClassElement type); | 56 T nonNullSubclass(ClassElement type); |
| 65 T nonNullExact(ClassElement type); | 57 T nonNullExact(ClassElement type); |
| 66 T nonNullEmpty(); | 58 T nonNullEmpty(); |
| 67 bool isNull(T type); | 59 bool isNull(T type); |
| 68 TypeMask newTypedSelector(T receiver, TypeMask mask); | 60 TypeMask newTypedSelector(T receiver, TypeMask mask); |
| 69 | 61 |
| 70 T allocateList(T type, | 62 T allocateList(T type, Node node, Element enclosing, |
| 71 Node node, | 63 [T elementType, int length]); |
| 72 Element enclosing, | |
| 73 [T elementType, int length]); | |
| 74 | 64 |
| 75 T allocateMap(T type, Node node, Element element, [List<T> keyType, | 65 T allocateMap(T type, Node node, Element element, |
| 76 List<T> valueType]); | 66 [List<T> keyType, List<T> valueType]); |
| 77 | 67 |
| 78 T allocateClosure(Node node, Element element); | 68 T allocateClosure(Node node, Element element); |
| 79 | 69 |
| 80 /** | 70 /** |
| 81 * Returns the least upper bound between [firstType] and | 71 * Returns the least upper bound between [firstType] and |
| 82 * [secondType]. | 72 * [secondType]. |
| 83 */ | 73 */ |
| 84 T computeLUB(T firstType, T secondType); | 74 T computeLUB(T firstType, T secondType); |
| 85 | 75 |
| 86 /** | 76 /** |
| (...skipping 12 matching lines...) Expand all Loading... |
| 99 * Returns a new type that unions [firstInput] and [secondInput]. | 89 * Returns a new type that unions [firstInput] and [secondInput]. |
| 100 */ | 90 */ |
| 101 T allocateDiamondPhi(T firstInput, T secondInput); | 91 T allocateDiamondPhi(T firstInput, T secondInput); |
| 102 | 92 |
| 103 /** | 93 /** |
| 104 * Returns a new type for holding the potential types of [element]. | 94 * Returns a new type for holding the potential types of [element]. |
| 105 * [inputType] is the first incoming type of the phi. | 95 * [inputType] is the first incoming type of the phi. |
| 106 */ | 96 */ |
| 107 T allocatePhi(Node node, Local variable, T inputType); | 97 T allocatePhi(Node node, Local variable, T inputType); |
| 108 | 98 |
| 109 | |
| 110 /** | 99 /** |
| 111 * Returns a new type for holding the potential types of [element]. | 100 * Returns a new type for holding the potential types of [element]. |
| 112 * [inputType] is the first incoming type of the phi. [allocateLoopPhi] | 101 * [inputType] is the first incoming type of the phi. [allocateLoopPhi] |
| 113 * only differs from [allocatePhi] in that it allows the underlying | 102 * only differs from [allocatePhi] in that it allows the underlying |
| 114 * implementation of [TypeSystem] to differentiate Phi nodes due to loops | 103 * implementation of [TypeSystem] to differentiate Phi nodes due to loops |
| 115 * from other merging uses. | 104 * from other merging uses. |
| 116 */ | 105 */ |
| 117 T allocateLoopPhi(Node node, Local variable, T inputType); | 106 T allocateLoopPhi(Node node, Local variable, T inputType); |
| 118 | 107 |
| 119 /** | 108 /** |
| (...skipping 16 matching lines...) Expand all Loading... |
| 136 bool selectorNeedsUpdate(T receiverType, TypeMask mask); | 125 bool selectorNeedsUpdate(T receiverType, TypeMask mask); |
| 137 | 126 |
| 138 /** | 127 /** |
| 139 * Returns a new receiver type for this [selector] applied to | 128 * Returns a new receiver type for this [selector] applied to |
| 140 * [receiverType]. | 129 * [receiverType]. |
| 141 * | 130 * |
| 142 * The option [isConditional] is true when [selector] was seen in a | 131 * The option [isConditional] is true when [selector] was seen in a |
| 143 * conditional send (e.g. `a?.selector`), in which case the returned type may | 132 * conditional send (e.g. `a?.selector`), in which case the returned type may |
| 144 * be null. | 133 * be null. |
| 145 */ | 134 */ |
| 146 T refineReceiver(Selector selector, | 135 T refineReceiver( |
| 147 TypeMask mask, | 136 Selector selector, TypeMask mask, T receiverType, bool isConditional); |
| 148 T receiverType, | |
| 149 bool isConditional); | |
| 150 | 137 |
| 151 /** | 138 /** |
| 152 * Returns the internal inferrer representation for [mask]. | 139 * Returns the internal inferrer representation for [mask]. |
| 153 */ | 140 */ |
| 154 T getConcreteTypeFor(TypeMask mask); | 141 T getConcreteTypeFor(TypeMask mask); |
| 155 } | 142 } |
| 156 | 143 |
| 157 /** | 144 /** |
| 158 * A variable scope holds types for variables. It has a link to a | 145 * A variable scope holds types for variables. It has a link to a |
| 159 * parent scope, but never changes the types in that parent. Instead, | 146 * parent scope, but never changes the types in that parent. Instead, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 variables = new Map<Local, T>(); | 191 variables = new Map<Local, T>(); |
| 205 } | 192 } |
| 206 variables[variable] = mask; | 193 variables[variable] = mask; |
| 207 } | 194 } |
| 208 | 195 |
| 209 void forEachOwnLocal(void f(Local variable, T type)) { | 196 void forEachOwnLocal(void f(Local variable, T type)) { |
| 210 if (variables == null) return; | 197 if (variables == null) return; |
| 211 variables.forEach(f); | 198 variables.forEach(f); |
| 212 } | 199 } |
| 213 | 200 |
| 214 void forEachLocalUntilNode(Node node, | 201 void forEachLocalUntilNode(Node node, void f(Local variable, T type), |
| 215 void f(Local variable, T type), | 202 [Setlet<Local> seenLocals]) { |
| 216 [Setlet<Local> seenLocals]) { | |
| 217 if (seenLocals == null) seenLocals = new Setlet<Local>(); | 203 if (seenLocals == null) seenLocals = new Setlet<Local>(); |
| 218 if (variables != null) { | 204 if (variables != null) { |
| 219 variables.forEach((variable, type) { | 205 variables.forEach((variable, type) { |
| 220 if (seenLocals.contains(variable)) return; | 206 if (seenLocals.contains(variable)) return; |
| 221 seenLocals.add(variable); | 207 seenLocals.add(variable); |
| 222 f(variable, type); | 208 f(variable, type); |
| 223 }); | 209 }); |
| 224 } | 210 } |
| 225 if (block == node) return; | 211 if (block == node) return; |
| 226 if (parent != null) parent.forEachLocalUntilNode(node, f, seenLocals); | 212 if (parent != null) parent.forEachLocalUntilNode(node, f, seenLocals); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 T readField(Element field) { | 252 T readField(Element field) { |
| 267 return fields == null ? null : fields[field]; | 253 return fields == null ? null : fields[field]; |
| 268 } | 254 } |
| 269 | 255 |
| 270 void forEach(void f(Element element, T type)) { | 256 void forEach(void f(Element element, T type)) { |
| 271 if (fields == null) return; | 257 if (fields == null) return; |
| 272 fields.forEach(f); | 258 fields.forEach(f); |
| 273 } | 259 } |
| 274 | 260 |
| 275 void mergeDiamondFlow(FieldInitializationScope<T> thenScope, | 261 void mergeDiamondFlow(FieldInitializationScope<T> thenScope, |
| 276 FieldInitializationScope<T> elseScope) { | 262 FieldInitializationScope<T> elseScope) { |
| 277 // Quick bailout check. If [isThisExposed] is true, we know the | 263 // Quick bailout check. If [isThisExposed] is true, we know the |
| 278 // code following won't do anything. | 264 // code following won't do anything. |
| 279 if (isThisExposed) return; | 265 if (isThisExposed) return; |
| 280 if (elseScope == null || elseScope.fields == null) { | 266 if (elseScope == null || elseScope.fields == null) { |
| 281 elseScope = this; | 267 elseScope = this; |
| 282 } | 268 } |
| 283 | 269 |
| 284 thenScope.forEach((Element field, T type) { | 270 thenScope.forEach((Element field, T type) { |
| 285 T otherType = elseScope.readField(field); | 271 T otherType = elseScope.readField(field); |
| 286 if (otherType == null) return; | 272 if (otherType == null) return; |
| 287 updateField(field, types.allocateDiamondPhi(type, otherType)); | 273 updateField(field, types.allocateDiamondPhi(type, otherType)); |
| 288 }); | 274 }); |
| 289 isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed; | 275 isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed; |
| 290 } | 276 } |
| 291 } | 277 } |
| 292 | 278 |
| 293 /** | 279 /** |
| 294 * Placeholder for inferred arguments types on sends. | 280 * Placeholder for inferred arguments types on sends. |
| 295 */ | 281 */ |
| 296 class ArgumentsTypes<T> extends IterableMixin<T> { | 282 class ArgumentsTypes<T> extends IterableMixin<T> { |
| 297 final List<T> positional; | 283 final List<T> positional; |
| 298 final Map<String, T> named; | 284 final Map<String, T> named; |
| 299 ArgumentsTypes(this.positional, named) | 285 ArgumentsTypes(this.positional, named) |
| 300 : this.named = (named == null || named.isEmpty) ? const {} : named { | 286 : this.named = (named == null || named.isEmpty) ? const {} : named { |
| 301 assert(this.positional.every((T type) => type != null)); | 287 assert(this.positional.every((T type) => type != null)); |
| 302 assert(this.named.values.every((T type) => type != null)); | 288 assert(this.named.values.every((T type) => type != null)); |
| 303 } | 289 } |
| 304 | 290 |
| 305 ArgumentsTypes.empty() : positional = const [], named = const {}; | 291 ArgumentsTypes.empty() |
| 292 : positional = const [], |
| 293 named = const {}; |
| 306 | 294 |
| 307 int get length => positional.length + named.length; | 295 int get length => positional.length + named.length; |
| 308 | 296 |
| 309 Iterator<T> get iterator => new ArgumentsTypesIterator(this); | 297 Iterator<T> get iterator => new ArgumentsTypesIterator(this); |
| 310 | 298 |
| 311 String toString() => "{ positional = $positional, named = $named }"; | 299 String toString() => "{ positional = $positional, named = $named }"; |
| 312 | 300 |
| 313 bool operator==(other) { | 301 bool operator ==(other) { |
| 314 if (positional.length != other.positional.length) return false; | 302 if (positional.length != other.positional.length) return false; |
| 315 if (named.length != other.named.length) return false; | 303 if (named.length != other.named.length) return false; |
| 316 for (int i = 0; i < positional.length; i++) { | 304 for (int i = 0; i < positional.length; i++) { |
| 317 if (positional[i] != other.positional[i]) return false; | 305 if (positional[i] != other.positional[i]) return false; |
| 318 } | 306 } |
| 319 named.forEach((name, type) { | 307 named.forEach((name, type) { |
| 320 if (other.named[name] != type) return false; | 308 if (other.named[name] != type) return false; |
| 321 }); | 309 }); |
| 322 return true; | 310 return true; |
| 323 } | 311 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 | 347 |
| 360 bool moveNext() { | 348 bool moveNext() { |
| 361 if (_iteratePositional && positional.moveNext()) { | 349 if (_iteratePositional && positional.moveNext()) { |
| 362 return true; | 350 return true; |
| 363 } | 351 } |
| 364 _iteratePositional = false; | 352 _iteratePositional = false; |
| 365 return named.moveNext(); | 353 return named.moveNext(); |
| 366 } | 354 } |
| 367 } | 355 } |
| 368 | 356 |
| 369 | |
| 370 abstract class MinimalInferrerEngine<T> { | 357 abstract class MinimalInferrerEngine<T> { |
| 371 /** | 358 /** |
| 372 * Returns the type of [element]. | 359 * Returns the type of [element]. |
| 373 */ | 360 */ |
| 374 T typeOfElement(Element element); | 361 T typeOfElement(Element element); |
| 375 | 362 |
| 376 /** | 363 /** |
| 377 * Records that [node] sets non-final field [element] to be of type | 364 * Records that [node] sets non-final field [element] to be of type |
| 378 * [type]. | 365 * [type]. |
| 379 */ | 366 */ |
| (...skipping 21 matching lines...) Expand all Loading... |
| 401 final Map<Local, Element> captured; | 388 final Map<Local, Element> captured; |
| 402 final Map<Local, Element> capturedAndBoxed; | 389 final Map<Local, Element> capturedAndBoxed; |
| 403 final FieldInitializationScope<T> fieldScope; | 390 final FieldInitializationScope<T> fieldScope; |
| 404 LocalsHandler<T> tryBlock; | 391 LocalsHandler<T> tryBlock; |
| 405 bool seenReturnOrThrow = false; | 392 bool seenReturnOrThrow = false; |
| 406 bool seenBreakOrContinue = false; | 393 bool seenBreakOrContinue = false; |
| 407 | 394 |
| 408 bool get aborts { | 395 bool get aborts { |
| 409 return seenReturnOrThrow || seenBreakOrContinue; | 396 return seenReturnOrThrow || seenBreakOrContinue; |
| 410 } | 397 } |
| 398 |
| 411 bool get inTryBlock => tryBlock != null; | 399 bool get inTryBlock => tryBlock != null; |
| 412 | 400 |
| 413 LocalsHandler(this.inferrer, | 401 LocalsHandler(this.inferrer, this.types, this.compiler, Node block, |
| 414 this.types, | 402 [this.fieldScope]) |
| 415 this.compiler, | |
| 416 Node block, | |
| 417 [this.fieldScope]) | |
| 418 : locals = new VariableScope<T>(block), | 403 : locals = new VariableScope<T>(block), |
| 419 captured = new Map<Local, Element>(), | 404 captured = new Map<Local, Element>(), |
| 420 capturedAndBoxed = new Map<Local, Element>(), | 405 capturedAndBoxed = new Map<Local, Element>(), |
| 421 tryBlock = null; | 406 tryBlock = null; |
| 422 | 407 |
| 423 LocalsHandler.from(LocalsHandler<T> other, | 408 LocalsHandler.from(LocalsHandler<T> other, Node block, |
| 424 Node block, | 409 {bool useOtherTryBlock: true}) |
| 425 {bool useOtherTryBlock: true}) | |
| 426 : locals = new VariableScope<T>(block, other.locals), | 410 : locals = new VariableScope<T>(block, other.locals), |
| 427 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), | 411 fieldScope = new FieldInitializationScope<T>.from(other.fieldScope), |
| 428 captured = other.captured, | 412 captured = other.captured, |
| 429 capturedAndBoxed = other.capturedAndBoxed, | 413 capturedAndBoxed = other.capturedAndBoxed, |
| 430 types = other.types, | 414 types = other.types, |
| 431 inferrer = other.inferrer, | 415 inferrer = other.inferrer, |
| 432 compiler = other.compiler { | 416 compiler = other.compiler { |
| 433 tryBlock = useOtherTryBlock ? other.tryBlock : this; | 417 tryBlock = useOtherTryBlock ? other.tryBlock : this; |
| 434 } | 418 } |
| 435 | 419 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 } | 456 } |
| 473 updateLocal() { | 457 updateLocal() { |
| 474 T currentType = locals[local]; | 458 T currentType = locals[local]; |
| 475 | 459 |
| 476 SendSet send = node != null ? node.asSendSet() : null; | 460 SendSet send = node != null ? node.asSendSet() : null; |
| 477 if (send != null && send.isIfNullAssignment && currentType != null) { | 461 if (send != null && send.isIfNullAssignment && currentType != null) { |
| 478 // If-null assignments may return either the new or the original value | 462 // If-null assignments may return either the new or the original value |
| 479 // narrowed to non-null. | 463 // narrowed to non-null. |
| 480 type = types.addPhiInput( | 464 type = types.addPhiInput( |
| 481 local, | 465 local, |
| 482 types.allocatePhi(locals.block, local, | 466 types.allocatePhi( |
| 483 types.narrowNotNull(currentType)), | 467 locals.block, local, types.narrowNotNull(currentType)), |
| 484 type); | 468 type); |
| 485 } | 469 } |
| 486 locals[local] = type; | 470 locals[local] = type; |
| 487 if (currentType != type) { | 471 if (currentType != type) { |
| 488 inferrer.recordLocalUpdate(local, type); | 472 inferrer.recordLocalUpdate(local, type); |
| 489 } | 473 } |
| 490 } | 474 } |
| 491 if (capturedAndBoxed.containsKey(local)) { | 475 if (capturedAndBoxed.containsKey(local)) { |
| 492 inferrer.recordTypeOfNonFinalField( | 476 inferrer.recordTypeOfNonFinalField(node, capturedAndBoxed[local], type); |
| 493 node, capturedAndBoxed[local], type); | |
| 494 } else if (inTryBlock) { | 477 } else if (inTryBlock) { |
| 495 // We don't know if an assignment in a try block | 478 // We don't know if an assignment in a try block |
| 496 // will be executed, so all assigments in that block are | 479 // will be executed, so all assigments in that block are |
| 497 // potential types after we have left it. We update the parent | 480 // potential types after we have left it. We update the parent |
| 498 // of the try block so that, at exit of the try block, we get | 481 // of the try block so that, at exit of the try block, we get |
| 499 // the right phi for it. | 482 // the right phi for it. |
| 500 T existing = tryBlock.locals.parent[local]; | 483 T existing = tryBlock.locals.parent[local]; |
| 501 if (existing != null) { | 484 if (existing != null) { |
| 502 T phiType = types.allocatePhi(tryBlock.locals.block, local, existing); | 485 T phiType = types.allocatePhi(tryBlock.locals.block, local, existing); |
| 503 T inputType = types.addPhiInput(local, phiType, type); | 486 T inputType = types.addPhiInput(local, phiType, type); |
| 504 tryBlock.locals.parent[local] = inputType; | 487 tryBlock.locals.parent[local] = inputType; |
| 505 } | 488 } |
| 506 // Update the current handler unconditionnally with the new | 489 // Update the current handler unconditionnally with the new |
| 507 // type. | 490 // type. |
| 508 updateLocal(); | 491 updateLocal(); |
| 509 } else { | 492 } else { |
| 510 updateLocal(); | 493 updateLocal(); |
| 511 } | 494 } |
| 512 } | 495 } |
| 513 | 496 |
| 514 void setCaptured(Local local, Element field) { | 497 void setCaptured(Local local, Element field) { |
| 515 captured[local] = field; | 498 captured[local] = field; |
| 516 } | 499 } |
| 517 | 500 |
| 518 void setCapturedAndBoxed(Local local, Element field) { | 501 void setCapturedAndBoxed(Local local, Element field) { |
| 519 capturedAndBoxed[local] = field; | 502 capturedAndBoxed[local] = field; |
| 520 } | 503 } |
| 521 | 504 |
| 522 void mergeDiamondFlow(LocalsHandler<T> thenBranch, | 505 void mergeDiamondFlow( |
| 523 LocalsHandler<T> elseBranch) { | 506 LocalsHandler<T> thenBranch, LocalsHandler<T> elseBranch) { |
| 524 if (fieldScope != null && elseBranch != null) { | 507 if (fieldScope != null && elseBranch != null) { |
| 525 fieldScope.mergeDiamondFlow(thenBranch.fieldScope, elseBranch.fieldScope); | 508 fieldScope.mergeDiamondFlow(thenBranch.fieldScope, elseBranch.fieldScope); |
| 526 } | 509 } |
| 527 seenReturnOrThrow = thenBranch.seenReturnOrThrow | 510 seenReturnOrThrow = thenBranch.seenReturnOrThrow && |
| 528 && elseBranch != null | 511 elseBranch != null && |
| 529 && elseBranch.seenReturnOrThrow; | 512 elseBranch.seenReturnOrThrow; |
| 530 seenBreakOrContinue = thenBranch.seenBreakOrContinue | 513 seenBreakOrContinue = thenBranch.seenBreakOrContinue && |
| 531 && elseBranch != null | 514 elseBranch != null && |
| 532 && elseBranch.seenBreakOrContinue; | 515 elseBranch.seenBreakOrContinue; |
| 533 if (aborts) return; | 516 if (aborts) return; |
| 534 | 517 |
| 535 void mergeOneBranch(LocalsHandler<T> other) { | 518 void mergeOneBranch(LocalsHandler<T> other) { |
| 536 other.locals.forEachOwnLocal((Local local, T type) { | 519 other.locals.forEachOwnLocal((Local local, T type) { |
| 537 T myType = locals[local]; | 520 T myType = locals[local]; |
| 538 if (myType == null) return; // Variable is only defined in [other]. | 521 if (myType == null) return; // Variable is only defined in [other]. |
| 539 if (type == myType) return; | 522 if (type == myType) return; |
| 540 locals[local] = types.allocateDiamondPhi(myType, type); | 523 locals[local] = types.allocateDiamondPhi(myType, type); |
| 541 }); | 524 }); |
| 542 } | 525 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 * [: L: { | 588 * [: L: { |
| 606 * if (...) break; | 589 * if (...) break; |
| 607 * ... | 590 * ... |
| 608 * } | 591 * } |
| 609 * :] | 592 * :] |
| 610 * | 593 * |
| 611 * where [:this:] is the [LocalsHandler] for the paths through the | 594 * where [:this:] is the [LocalsHandler] for the paths through the |
| 612 * labeled statement that do not break out. | 595 * labeled statement that do not break out. |
| 613 */ | 596 */ |
| 614 void mergeAfterBreaks(List<LocalsHandler<T>> handlers, | 597 void mergeAfterBreaks(List<LocalsHandler<T>> handlers, |
| 615 {bool keepOwnLocals: true}) { | 598 {bool keepOwnLocals: true}) { |
| 616 Node level = locals.block; | 599 Node level = locals.block; |
| 617 // Use a separate locals handler to perform the merge in, so that Phi | 600 // Use a separate locals handler to perform the merge in, so that Phi |
| 618 // creation does not invalidate previous type knowledge while we might | 601 // creation does not invalidate previous type knowledge while we might |
| 619 // still look it up. | 602 // still look it up. |
| 620 LocalsHandler merged = new LocalsHandler.from(this, level); | 603 LocalsHandler merged = new LocalsHandler.from(this, level); |
| 621 Set<Local> seenLocals = new Setlet<Local>(); | 604 Set<Local> seenLocals = new Setlet<Local>(); |
| 622 bool allBranchesAbort = true; | 605 bool allBranchesAbort = true; |
| 623 // Merge all other handlers. | 606 // Merge all other handlers. |
| 624 for (LocalsHandler handler in handlers) { | 607 for (LocalsHandler handler in handlers) { |
| 625 allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow; | 608 allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow; |
| 626 merged.mergeHandler(handler, seenLocals); | 609 merged.mergeHandler(handler, seenLocals); |
| 627 } | 610 } |
| 628 // If we want to keep own locals, we merge [seenLocals] from [this] into | 611 // If we want to keep own locals, we merge [seenLocals] from [this] into |
| 629 // [merged] to update the Phi nodes with original values. | 612 // [merged] to update the Phi nodes with original values. |
| 630 if (keepOwnLocals && !seenReturnOrThrow) { | 613 if (keepOwnLocals && !seenReturnOrThrow) { |
| 631 for (Local variable in seenLocals) { | 614 for (Local variable in seenLocals) { |
| 632 T originalType = locals[variable]; | 615 T originalType = locals[variable]; |
| 633 if (originalType != null) { | 616 if (originalType != null) { |
| 634 merged.locals[variable] = types.addPhiInput(variable, | 617 merged.locals[variable] = types.addPhiInput( |
| 635 merged.locals[variable], | 618 variable, merged.locals[variable], originalType); |
| 636 originalType); | |
| 637 } | 619 } |
| 638 } | 620 } |
| 639 } | 621 } |
| 640 // Clean up Phi nodes with single input and store back result into | 622 // Clean up Phi nodes with single input and store back result into |
| 641 // actual locals handler. | 623 // actual locals handler. |
| 642 merged.locals.forEachOwnLocal((Local variable, T type) { | 624 merged.locals.forEachOwnLocal((Local variable, T type) { |
| 643 locals[variable] = types.simplifyPhi(level, variable, type); | 625 locals[variable] = types.simplifyPhi(level, variable, type); |
| 644 }); | 626 }); |
| 645 seenReturnOrThrow = allBranchesAbort && | 627 seenReturnOrThrow = |
| 646 (!keepOwnLocals || seenReturnOrThrow); | 628 allBranchesAbort && (!keepOwnLocals || seenReturnOrThrow); |
| 647 } | 629 } |
| 648 | 630 |
| 649 /** | 631 /** |
| 650 * Merge [other] into this handler. Returns whether a local in this | 632 * Merge [other] into this handler. Returns whether a local in this |
| 651 * has changed. If [seen] is not null, we allocate new Phi nodes | 633 * has changed. If [seen] is not null, we allocate new Phi nodes |
| 652 * unless the local is already present in the set [seen]. This effectively | 634 * unless the local is already present in the set [seen]. This effectively |
| 653 * overwrites the current type knowledge in this handler. | 635 * overwrites the current type knowledge in this handler. |
| 654 */ | 636 */ |
| 655 bool mergeHandler(LocalsHandler<T> other, [Set<Local> seen]) { | 637 bool mergeHandler(LocalsHandler<T> other, [Set<Local> seen]) { |
| 656 if (other.seenReturnOrThrow) return false; | 638 if (other.seenReturnOrThrow) return false; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 }); | 686 }); |
| 705 } | 687 } |
| 706 | 688 |
| 707 void updateField(Element element, T type) { | 689 void updateField(Element element, T type) { |
| 708 fieldScope.updateField(element, type); | 690 fieldScope.updateField(element, type); |
| 709 } | 691 } |
| 710 } | 692 } |
| 711 | 693 |
| 712 abstract class InferrerVisitor<T, E extends MinimalInferrerEngine<T>> | 694 abstract class InferrerVisitor<T, E extends MinimalInferrerEngine<T>> |
| 713 extends Visitor<T> | 695 extends Visitor<T> |
| 714 with SemanticSendResolvedMixin<T, dynamic>, | 696 with |
| 715 CompoundBulkMixin<T, dynamic>, | 697 SemanticSendResolvedMixin<T, dynamic>, |
| 716 SetIfNullBulkMixin<T, dynamic>, | 698 CompoundBulkMixin<T, dynamic>, |
| 717 PrefixBulkMixin<T, dynamic>, | 699 SetIfNullBulkMixin<T, dynamic>, |
| 718 PostfixBulkMixin<T, dynamic>, | 700 PrefixBulkMixin<T, dynamic>, |
| 719 ErrorBulkMixin<T, dynamic>, | 701 PostfixBulkMixin<T, dynamic>, |
| 720 NewBulkMixin<T, dynamic>, | 702 ErrorBulkMixin<T, dynamic>, |
| 721 SetBulkMixin<T, dynamic> | 703 NewBulkMixin<T, dynamic>, |
| 704 SetBulkMixin<T, dynamic> |
| 722 implements SemanticSendVisitor<T, dynamic> { | 705 implements SemanticSendVisitor<T, dynamic> { |
| 723 final Compiler compiler; | 706 final Compiler compiler; |
| 724 final AstElement analyzedElement; | 707 final AstElement analyzedElement; |
| 725 final TypeSystem<T> types; | 708 final TypeSystem<T> types; |
| 726 final E inferrer; | 709 final E inferrer; |
| 727 final Map<JumpTarget, List<LocalsHandler<T>>> breaksFor = | 710 final Map<JumpTarget, List<LocalsHandler<T>>> breaksFor = |
| 728 new Map<JumpTarget, List<LocalsHandler<T>>>(); | 711 new Map<JumpTarget, List<LocalsHandler<T>>>(); |
| 729 final Map<JumpTarget, List<LocalsHandler>> continuesFor = | 712 final Map<JumpTarget, List<LocalsHandler>> continuesFor = |
| 730 new Map<JumpTarget, List<LocalsHandler<T>>>(); | 713 new Map<JumpTarget, List<LocalsHandler<T>>>(); |
| 731 LocalsHandler<T> locals; | 714 LocalsHandler<T> locals; |
| 732 final List<T> cascadeReceiverStack = new List<T>(); | 715 final List<T> cascadeReceiverStack = new List<T>(); |
| 733 final TreeElements elements; | 716 final TreeElements elements; |
| 734 | 717 |
| 735 bool accumulateIsChecks = false; | 718 bool accumulateIsChecks = false; |
| 736 bool conditionIsSimple = false; | 719 bool conditionIsSimple = false; |
| 737 List<Send> isChecks; | 720 List<Send> isChecks; |
| 738 int loopLevel = 0; | 721 int loopLevel = 0; |
| 739 | 722 |
| 740 bool get inLoop => loopLevel > 0; | 723 bool get inLoop => loopLevel > 0; |
| 741 bool get isThisExposed { | 724 bool get isThisExposed { |
| 742 return analyzedElement.isGenerativeConstructor | 725 return analyzedElement.isGenerativeConstructor |
| 743 ? locals.fieldScope.isThisExposed | 726 ? locals.fieldScope.isThisExposed |
| 744 : true; | 727 : true; |
| 745 } | 728 } |
| 729 |
| 746 void set isThisExposed(value) { | 730 void set isThisExposed(value) { |
| 747 if (analyzedElement.isGenerativeConstructor) { | 731 if (analyzedElement.isGenerativeConstructor) { |
| 748 locals.fieldScope.isThisExposed = value; | 732 locals.fieldScope.isThisExposed = value; |
| 749 } | 733 } |
| 750 } | 734 } |
| 751 | 735 |
| 752 InferrerVisitor(AstElement analyzedElement, | 736 InferrerVisitor( |
| 753 this.inferrer, | 737 AstElement analyzedElement, this.inferrer, this.types, this.compiler, |
| 754 this.types, | 738 [LocalsHandler<T> handler]) |
| 755 this.compiler, | 739 : this.analyzedElement = analyzedElement, |
| 756 [LocalsHandler<T> handler]) | 740 this.locals = handler, |
| 757 : this.analyzedElement = analyzedElement, | 741 this.elements = analyzedElement.resolvedAst.elements { |
| 758 this.locals = handler, | |
| 759 this.elements = analyzedElement.resolvedAst.elements { | |
| 760 if (handler != null) return; | 742 if (handler != null) return; |
| 761 Node node = analyzedElement.node; | 743 Node node = analyzedElement.node; |
| 762 FieldInitializationScope<T> fieldScope = | 744 FieldInitializationScope<T> fieldScope = |
| 763 analyzedElement.isGenerativeConstructor | 745 analyzedElement.isGenerativeConstructor |
| 764 ? new FieldInitializationScope<T>(types) | 746 ? new FieldInitializationScope<T>(types) |
| 765 : null; | 747 : null; |
| 766 locals = new LocalsHandler<T>(inferrer, types, compiler, node, fieldScope); | 748 locals = new LocalsHandler<T>(inferrer, types, compiler, node, fieldScope); |
| 767 } | 749 } |
| 768 | 750 |
| 769 DiagnosticReporter get reporter => compiler.reporter; | 751 DiagnosticReporter get reporter => compiler.reporter; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 } | 880 } |
| 899 | 881 |
| 900 T handleTypeLiteralGet() { | 882 T handleTypeLiteralGet() { |
| 901 return types.typeType; | 883 return types.typeType; |
| 902 } | 884 } |
| 903 | 885 |
| 904 T handleTypeLiteralInvoke(NodeList arguments) { | 886 T handleTypeLiteralInvoke(NodeList arguments) { |
| 905 return types.dynamicType; | 887 return types.dynamicType; |
| 906 } | 888 } |
| 907 | 889 |
| 908 | |
| 909 @override | 890 @override |
| 910 T bulkHandleNode(Node node, String message, _) { | 891 T bulkHandleNode(Node node, String message, _) { |
| 911 return internalError(node, message.replaceAll('#', '$node')); | 892 return internalError(node, message.replaceAll('#', '$node')); |
| 912 } | 893 } |
| 913 | 894 |
| 914 @override | 895 @override |
| 915 T visitConstantGet( | 896 T visitConstantGet(Send node, ConstantExpression constant, _) { |
| 916 Send node, | |
| 917 ConstantExpression constant, | |
| 918 _) { | |
| 919 return bulkHandleNode(node, "Constant read `#` unhandled.", _); | 897 return bulkHandleNode(node, "Constant read `#` unhandled.", _); |
| 920 } | 898 } |
| 921 | 899 |
| 922 @override | 900 @override |
| 923 T visitConstantInvoke( | 901 T visitConstantInvoke(Send node, ConstantExpression constant, |
| 924 Send node, | 902 NodeList arguments, CallStructure callStructure, _) { |
| 925 ConstantExpression constant, | |
| 926 NodeList arguments, | |
| 927 CallStructure callStructure, | |
| 928 _) { | |
| 929 return bulkHandleNode(node, "Constant invoke `#` unhandled.", _); | 903 return bulkHandleNode(node, "Constant invoke `#` unhandled.", _); |
| 930 } | 904 } |
| 931 | 905 |
| 932 T visitClassTypeLiteralGet( | 906 T visitClassTypeLiteralGet(Send node, ConstantExpression constant, _) { |
| 933 Send node, | |
| 934 ConstantExpression constant, | |
| 935 _) { | |
| 936 return handleTypeLiteralGet(); | 907 return handleTypeLiteralGet(); |
| 937 } | 908 } |
| 938 | 909 |
| 939 T visitClassTypeLiteralInvoke( | 910 T visitClassTypeLiteralInvoke(Send node, ConstantExpression constant, |
| 940 Send node, | 911 NodeList arguments, CallStructure callStructure, _) { |
| 941 ConstantExpression constant, | |
| 942 NodeList arguments, | |
| 943 CallStructure callStructure, | |
| 944 _) { | |
| 945 return handleTypeLiteralInvoke(arguments); | 912 return handleTypeLiteralInvoke(arguments); |
| 946 } | 913 } |
| 947 | 914 |
| 948 T visitTypedefTypeLiteralGet( | 915 T visitTypedefTypeLiteralGet(Send node, ConstantExpression constant, _) { |
| 949 Send node, | |
| 950 ConstantExpression constant, | |
| 951 _) { | |
| 952 return handleTypeLiteralGet(); | 916 return handleTypeLiteralGet(); |
| 953 } | 917 } |
| 954 | 918 |
| 955 T visitTypedefTypeLiteralInvoke( | 919 T visitTypedefTypeLiteralInvoke(Send node, ConstantExpression constant, |
| 956 Send node, | 920 NodeList arguments, CallStructure callStructure, _) { |
| 957 ConstantExpression constant, | |
| 958 NodeList arguments, | |
| 959 CallStructure callStructure, | |
| 960 _) { | |
| 961 return handleTypeLiteralInvoke(arguments); | 921 return handleTypeLiteralInvoke(arguments); |
| 962 } | 922 } |
| 963 | 923 |
| 964 T visitTypeVariableTypeLiteralGet( | 924 T visitTypeVariableTypeLiteralGet(Send node, TypeVariableElement element, _) { |
| 965 Send node, | |
| 966 TypeVariableElement element, | |
| 967 _) { | |
| 968 return handleTypeLiteralGet(); | 925 return handleTypeLiteralGet(); |
| 969 } | 926 } |
| 970 | 927 |
| 971 T visitTypeVariableTypeLiteralInvoke( | 928 T visitTypeVariableTypeLiteralInvoke(Send node, TypeVariableElement element, |
| 972 Send node, | 929 NodeList arguments, CallStructure callStructure, _) { |
| 973 TypeVariableElement element, | |
| 974 NodeList arguments, | |
| 975 CallStructure callStructure, | |
| 976 _) { | |
| 977 return handleTypeLiteralInvoke(arguments); | 930 return handleTypeLiteralInvoke(arguments); |
| 978 } | 931 } |
| 979 | 932 |
| 980 T visitDynamicTypeLiteralGet( | 933 T visitDynamicTypeLiteralGet(Send node, ConstantExpression constant, _) { |
| 981 Send node, | |
| 982 ConstantExpression constant, | |
| 983 _) { | |
| 984 return handleTypeLiteralGet(); | 934 return handleTypeLiteralGet(); |
| 985 } | 935 } |
| 986 | 936 |
| 987 T visitDynamicTypeLiteralInvoke( | 937 T visitDynamicTypeLiteralInvoke(Send node, ConstantExpression constant, |
| 988 Send node, | 938 NodeList arguments, CallStructure callStructure, _) { |
| 989 ConstantExpression constant, | |
| 990 NodeList arguments, | |
| 991 CallStructure callStructure, | |
| 992 _) { | |
| 993 return handleTypeLiteralInvoke(arguments); | 939 return handleTypeLiteralInvoke(arguments); |
| 994 } | 940 } |
| 995 | 941 |
| 996 bool isThisOrSuper(Node node) => node.isThis() || node.isSuper(); | 942 bool isThisOrSuper(Node node) => node.isThis() || node.isSuper(); |
| 997 | 943 |
| 998 Element get outermostElement { | 944 Element get outermostElement { |
| 999 return analyzedElement.outermostEnclosingMemberOrTopLevel.implementation; | 945 return analyzedElement.outermostEnclosingMemberOrTopLevel.implementation; |
| 1000 } | 946 } |
| 1001 | 947 |
| 1002 T _thisType; | 948 T _thisType; |
| 1003 T get thisType { | 949 T get thisType { |
| 1004 if (_thisType != null) return _thisType; | 950 if (_thisType != null) return _thisType; |
| 1005 ClassElement cls = outermostElement.enclosingClass; | 951 ClassElement cls = outermostElement.enclosingClass; |
| 1006 ClassWorld classWorld = compiler.world; | 952 ClassWorld classWorld = compiler.world; |
| 1007 if (classWorld.isUsedAsMixin(cls)) { | 953 if (classWorld.isUsedAsMixin(cls)) { |
| 1008 return _thisType = types.nonNullSubtype(cls); | 954 return _thisType = types.nonNullSubtype(cls); |
| 1009 } else { | 955 } else { |
| 1010 return _thisType = types.nonNullSubclass(cls); | 956 return _thisType = types.nonNullSubclass(cls); |
| 1011 } | 957 } |
| 1012 } | 958 } |
| 1013 | 959 |
| 1014 T _superType; | 960 T _superType; |
| 1015 T get superType { | 961 T get superType { |
| 1016 if (_superType != null) return _superType; | 962 if (_superType != null) return _superType; |
| 1017 return _superType = types.nonNullExact( | 963 return _superType = |
| 1018 outermostElement.enclosingClass.superclass); | 964 types.nonNullExact(outermostElement.enclosingClass.superclass); |
| 1019 } | 965 } |
| 1020 | 966 |
| 1021 @override | 967 @override |
| 1022 T visitThisGet(Identifier node, _) { | 968 T visitThisGet(Identifier node, _) { |
| 1023 return thisType; | 969 return thisType; |
| 1024 } | 970 } |
| 1025 | 971 |
| 1026 T visitIdentifier(Identifier node) { | 972 T visitIdentifier(Identifier node) { |
| 1027 if (node.isThis()) { | 973 if (node.isThis()) { |
| 1028 return thisType; | 974 return thisType; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1066 if (usePositive) continue; | 1012 if (usePositive) continue; |
| 1067 } else { | 1013 } else { |
| 1068 if (!usePositive) continue; | 1014 if (!usePositive) continue; |
| 1069 } | 1015 } |
| 1070 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 1016 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); |
| 1071 narrow(elements[node.receiver], type, node); | 1017 narrow(elements[node.receiver], type, node); |
| 1072 } else { | 1018 } else { |
| 1073 Element receiverElement = elements[node.receiver]; | 1019 Element receiverElement = elements[node.receiver]; |
| 1074 Element argumentElement = elements[node.arguments.first]; | 1020 Element argumentElement = elements[node.arguments.first]; |
| 1075 String operator = node.selector.asOperator().source; | 1021 String operator = node.selector.asOperator().source; |
| 1076 if ((operator == '==' && usePositive) | 1022 if ((operator == '==' && usePositive) || |
| 1077 || (operator == '!=' && !usePositive)) { | 1023 (operator == '!=' && !usePositive)) { |
| 1078 // Type the elements as null. | 1024 // Type the elements as null. |
| 1079 if (Elements.isLocal(receiverElement)) { | 1025 if (Elements.isLocal(receiverElement)) { |
| 1080 locals.update(receiverElement, types.nullType, node); | 1026 locals.update(receiverElement, types.nullType, node); |
| 1081 } | 1027 } |
| 1082 if (Elements.isLocal(argumentElement)) { | 1028 if (Elements.isLocal(argumentElement)) { |
| 1083 locals.update(argumentElement, types.nullType, node); | 1029 locals.update(argumentElement, types.nullType, node); |
| 1084 } | 1030 } |
| 1085 } else { | 1031 } else { |
| 1086 // Narrow the elements to a non-null type. | 1032 // Narrow the elements to a non-null type. |
| 1087 DartType objectType = compiler.coreTypes.objectType; | 1033 DartType objectType = compiler.coreTypes.objectType; |
| 1088 if (Elements.isLocal(receiverElement)) { | 1034 if (Elements.isLocal(receiverElement)) { |
| 1089 narrow(receiverElement, objectType, node); | 1035 narrow(receiverElement, objectType, node); |
| 1090 } | 1036 } |
| 1091 if (Elements.isLocal(argumentElement)) { | 1037 if (Elements.isLocal(argumentElement)) { |
| 1092 narrow(argumentElement, objectType, node); | 1038 narrow(argumentElement, objectType, node); |
| 1093 } | 1039 } |
| 1094 } | 1040 } |
| 1095 } | 1041 } |
| 1096 } | 1042 } |
| 1097 } | 1043 } |
| 1098 | 1044 |
| 1099 @override | 1045 @override |
| 1100 T visitIndex(Send node, Node receiver, Node index, _) { | 1046 T visitIndex(Send node, Node receiver, Node index, _) { |
| 1101 return handleDynamicInvoke(node); | 1047 return handleDynamicInvoke(node); |
| 1102 } | 1048 } |
| 1103 | 1049 |
| 1104 @override | 1050 @override |
| 1105 T visitDynamicPropertyInvoke( | 1051 T visitDynamicPropertyInvoke( |
| 1106 Send node, | 1052 Send node, Node receiver, NodeList arguments, Selector selector, _) { |
| 1107 Node receiver, | |
| 1108 NodeList arguments, | |
| 1109 Selector selector, | |
| 1110 _) { | |
| 1111 return handleDynamicInvoke(node); | 1053 return handleDynamicInvoke(node); |
| 1112 } | 1054 } |
| 1113 | 1055 |
| 1114 @override | 1056 @override |
| 1115 T visitIfNotNullDynamicPropertyInvoke( | 1057 T visitIfNotNullDynamicPropertyInvoke( |
| 1116 Send node, | 1058 Send node, Node receiver, NodeList arguments, Selector selector, _) { |
| 1117 Node receiver, | |
| 1118 NodeList arguments, | |
| 1119 Selector selector, | |
| 1120 _) { | |
| 1121 return handleDynamicInvoke(node); | 1059 return handleDynamicInvoke(node); |
| 1122 } | 1060 } |
| 1123 | 1061 |
| 1124 @override | 1062 @override |
| 1125 T visitThisPropertyInvoke( | 1063 T visitThisPropertyInvoke( |
| 1126 Send node, | 1064 Send node, NodeList arguments, Selector selector, _) { |
| 1127 NodeList arguments, | |
| 1128 Selector selector, | |
| 1129 _) { | |
| 1130 return handleDynamicInvoke(node); | 1065 return handleDynamicInvoke(node); |
| 1131 } | 1066 } |
| 1132 | 1067 |
| 1133 @override | 1068 @override |
| 1134 T visitIfNull(Send node, Node left, Node right, _) { | 1069 T visitIfNull(Send node, Node left, Node right, _) { |
| 1135 T firstType = visit(left); | 1070 T firstType = visit(left); |
| 1136 T secondType = visit(right); | 1071 T secondType = visit(right); |
| 1137 return types.allocateDiamondPhi(types.narrowNotNull(firstType), secondType); | 1072 return types.allocateDiamondPhi(types.narrowNotNull(firstType), secondType); |
| 1138 } | 1073 } |
| 1139 | 1074 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1152 updateIsChecks(isChecks, usePositive: true); | 1087 updateIsChecks(isChecks, usePositive: true); |
| 1153 LocalsHandler<T> narrowed; | 1088 LocalsHandler<T> narrowed; |
| 1154 if (oldAccumulateIsChecks) { | 1089 if (oldAccumulateIsChecks) { |
| 1155 narrowed = new LocalsHandler<T>.topLevelCopyOf(locals); | 1090 narrowed = new LocalsHandler<T>.topLevelCopyOf(locals); |
| 1156 } else { | 1091 } else { |
| 1157 accumulateIsChecks = false; | 1092 accumulateIsChecks = false; |
| 1158 isChecks = oldIsChecks; | 1093 isChecks = oldIsChecks; |
| 1159 } | 1094 } |
| 1160 visit(right); | 1095 visit(right); |
| 1161 if (oldAccumulateIsChecks) { | 1096 if (oldAccumulateIsChecks) { |
| 1162 | 1097 bool invalidatedInRightHandSide(Send test) { |
| 1163 bool invalidatedInRightHandSide (Send test) { | |
| 1164 Element receiver = elements[test.receiver]; | 1098 Element receiver = elements[test.receiver]; |
| 1165 if (receiver is LocalElement) { | 1099 if (receiver is LocalElement) { |
| 1166 return narrowed.locals[receiver] != locals.locals[receiver]; | 1100 return narrowed.locals[receiver] != locals.locals[receiver]; |
| 1167 } | 1101 } |
| 1168 return false; | 1102 return false; |
| 1169 } | 1103 } |
| 1170 | 1104 |
| 1171 isChecks.removeWhere(invalidatedInRightHandSide); | 1105 isChecks.removeWhere(invalidatedInRightHandSide); |
| 1172 } | 1106 } |
| 1173 saved.mergeDiamondFlow(locals, null); | 1107 saved.mergeDiamondFlow(locals, null); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1260 if (simpleCondition) updateIsChecks(tests, usePositive: false); | 1194 if (simpleCondition) updateIsChecks(tests, usePositive: false); |
| 1261 T secondType = visit(node.elseExpression); | 1195 T secondType = visit(node.elseExpression); |
| 1262 saved.mergeDiamondFlow(thenLocals, locals); | 1196 saved.mergeDiamondFlow(thenLocals, locals); |
| 1263 locals = saved; | 1197 locals = saved; |
| 1264 T type = types.allocateDiamondPhi(firstType, secondType); | 1198 T type = types.allocateDiamondPhi(firstType, secondType); |
| 1265 return type; | 1199 return type; |
| 1266 } | 1200 } |
| 1267 | 1201 |
| 1268 T visitVariableDefinitions(VariableDefinitions node) { | 1202 T visitVariableDefinitions(VariableDefinitions node) { |
| 1269 for (Link<Node> link = node.definitions.nodes; | 1203 for (Link<Node> link = node.definitions.nodes; |
| 1270 !link.isEmpty; | 1204 !link.isEmpty; |
| 1271 link = link.tail) { | 1205 link = link.tail) { |
| 1272 Node definition = link.head; | 1206 Node definition = link.head; |
| 1273 if (definition is Identifier) { | 1207 if (definition is Identifier) { |
| 1274 locals.update(elements[definition], types.nullType, node); | 1208 locals.update(elements[definition], types.nullType, node); |
| 1275 } else { | 1209 } else { |
| 1276 assert(definition.asSendSet() != null); | 1210 assert(definition.asSendSet() != null); |
| 1277 handleSendSet(definition); | 1211 handleSendSet(definition); |
| 1278 } | 1212 } |
| 1279 } | 1213 } |
| 1280 return null; | 1214 return null; |
| 1281 } | 1215 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1346 // Setup (and clear in case of multiple iterations of the loop) | 1280 // Setup (and clear in case of multiple iterations of the loop) |
| 1347 // the lists of breaks and continues seen in the loop. | 1281 // the lists of breaks and continues seen in the loop. |
| 1348 setupBreaksAndContinues(target); | 1282 setupBreaksAndContinues(target); |
| 1349 locals = new LocalsHandler<T>.from(saved, node); | 1283 locals = new LocalsHandler<T>.from(saved, node); |
| 1350 logic(); | 1284 logic(); |
| 1351 changed = saved.mergeAll(getLoopBackEdges(target)); | 1285 changed = saved.mergeAll(getLoopBackEdges(target)); |
| 1352 } while (changed); | 1286 } while (changed); |
| 1353 loopLevel--; | 1287 loopLevel--; |
| 1354 saved.endLoop(node); | 1288 saved.endLoop(node); |
| 1355 bool keepOwnLocals = node.asDoWhile() == null; | 1289 bool keepOwnLocals = node.asDoWhile() == null; |
| 1356 saved.mergeAfterBreaks( | 1290 saved.mergeAfterBreaks(getBreaks(target), keepOwnLocals: keepOwnLocals); |
| 1357 getBreaks(target), keepOwnLocals: keepOwnLocals); | |
| 1358 locals = saved; | 1291 locals = saved; |
| 1359 clearBreaksAndContinues(target); | 1292 clearBreaksAndContinues(target); |
| 1360 return null; | 1293 return null; |
| 1361 } | 1294 } |
| 1362 | 1295 |
| 1363 T visitWhile(While node) { | 1296 T visitWhile(While node) { |
| 1364 return handleLoop(node, () { | 1297 return handleLoop(node, () { |
| 1365 List<Send> tests = <Send>[]; | 1298 List<Send> tests = <Send>[]; |
| 1366 handleCondition(node.condition, tests); | 1299 handleCondition(node.condition, tests); |
| 1367 updateIsChecks(tests, usePositive: true); | 1300 updateIsChecks(tests, usePositive: true); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1384 List<Send> tests = <Send>[]; | 1317 List<Send> tests = <Send>[]; |
| 1385 handleCondition(node.condition, tests); | 1318 handleCondition(node.condition, tests); |
| 1386 updateIsChecks(tests, usePositive: true); | 1319 updateIsChecks(tests, usePositive: true); |
| 1387 visit(node.body); | 1320 visit(node.body); |
| 1388 visit(node.update); | 1321 visit(node.update); |
| 1389 }); | 1322 }); |
| 1390 } | 1323 } |
| 1391 | 1324 |
| 1392 T visitTryStatement(TryStatement node) { | 1325 T visitTryStatement(TryStatement node) { |
| 1393 LocalsHandler<T> saved = locals; | 1326 LocalsHandler<T> saved = locals; |
| 1394 locals = new LocalsHandler<T>.from( | 1327 locals = new LocalsHandler<T>.from(locals, node, useOtherTryBlock: false); |
| 1395 locals, node, useOtherTryBlock: false); | |
| 1396 visit(node.tryBlock); | 1328 visit(node.tryBlock); |
| 1397 saved.mergeDiamondFlow(locals, null); | 1329 saved.mergeDiamondFlow(locals, null); |
| 1398 locals = saved; | 1330 locals = saved; |
| 1399 for (Node catchBlock in node.catchBlocks) { | 1331 for (Node catchBlock in node.catchBlocks) { |
| 1400 saved = locals; | 1332 saved = locals; |
| 1401 locals = new LocalsHandler<T>.from(locals, catchBlock); | 1333 locals = new LocalsHandler<T>.from(locals, catchBlock); |
| 1402 visit(catchBlock); | 1334 visit(catchBlock); |
| 1403 saved.mergeDiamondFlow(locals, null); | 1335 saved.mergeDiamondFlow(locals, null); |
| 1404 locals = saved; | 1336 locals = saved; |
| 1405 } | 1337 } |
| 1406 visit(node.finallyBlock); | 1338 visit(node.finallyBlock); |
| 1407 return null; | 1339 return null; |
| 1408 } | 1340 } |
| 1409 | 1341 |
| 1410 T visitThrow(Throw node) { | 1342 T visitThrow(Throw node) { |
| 1411 node.visitChildren(this); | 1343 node.visitChildren(this); |
| 1412 locals.seenReturnOrThrow = true; | 1344 locals.seenReturnOrThrow = true; |
| 1413 return types.nonNullEmpty(); | 1345 return types.nonNullEmpty(); |
| 1414 } | 1346 } |
| 1415 | 1347 |
| 1416 T visitCatchBlock(CatchBlock node) { | 1348 T visitCatchBlock(CatchBlock node) { |
| 1417 Node exception = node.exception; | 1349 Node exception = node.exception; |
| 1418 if (exception != null) { | 1350 if (exception != null) { |
| 1419 DartType type = elements.getType(node.type); | 1351 DartType type = elements.getType(node.type); |
| 1420 T mask = type == null || | 1352 T mask = type == null || type.treatAsDynamic || type.isTypeVariable |
| 1421 type.treatAsDynamic || | |
| 1422 type.isTypeVariable | |
| 1423 ? types.dynamicType | 1353 ? types.dynamicType |
| 1424 : types.nonNullSubtype(type.element); | 1354 : types.nonNullSubtype(type.element); |
| 1425 locals.update(elements[exception], mask, node); | 1355 locals.update(elements[exception], mask, node); |
| 1426 } | 1356 } |
| 1427 Node trace = node.trace; | 1357 Node trace = node.trace; |
| 1428 if (trace != null) { | 1358 if (trace != null) { |
| 1429 locals.update(elements[trace], types.dynamicType, node); | 1359 locals.update(elements[trace], types.dynamicType, node); |
| 1430 } | 1360 } |
| 1431 visit(node.block); | 1361 visit(node.block); |
| 1432 return null; | 1362 return null; |
| 1433 } | 1363 } |
| 1434 | 1364 |
| 1435 T visitParenthesizedExpression(ParenthesizedExpression node) { | 1365 T visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1436 return visit(node.expression); | 1366 return visit(node.expression); |
| 1437 } | 1367 } |
| 1438 | 1368 |
| 1439 T visitBlock(Block node) { | 1369 T visitBlock(Block node) { |
| 1440 if (node.statements != null) { | 1370 if (node.statements != null) { |
| 1441 for (Node statement in node.statements) { | 1371 for (Node statement in node.statements) { |
| 1442 visit(statement); | 1372 visit(statement); |
| 1443 if (locals.aborts) break; | 1373 if (locals.aborts) break; |
| 1444 } | 1374 } |
| 1445 } | 1375 } |
| 1446 return null; | 1376 return null; |
| 1447 } | 1377 } |
| 1448 | 1378 |
| 1449 T visitLabeledStatement(LabeledStatement node) { | 1379 T visitLabeledStatement(LabeledStatement node) { |
| 1450 Statement body = node.statement; | 1380 Statement body = node.statement; |
| 1451 if (body is Loop | 1381 if (body is Loop || |
| 1452 || body is SwitchStatement | 1382 body is SwitchStatement || |
| 1453 || Elements.isUnusedLabel(node, elements)) { | 1383 Elements.isUnusedLabel(node, elements)) { |
| 1454 // Loops and switches handle their own labels. | 1384 // Loops and switches handle their own labels. |
| 1455 visit(body); | 1385 visit(body); |
| 1456 } else { | 1386 } else { |
| 1457 JumpTarget targetElement = elements.getTargetDefinition(body); | 1387 JumpTarget targetElement = elements.getTargetDefinition(body); |
| 1458 setupBreaksAndContinues(targetElement); | 1388 setupBreaksAndContinues(targetElement); |
| 1459 visit(body); | 1389 visit(body); |
| 1460 locals.mergeAfterBreaks(getBreaks(targetElement)); | 1390 locals.mergeAfterBreaks(getBreaks(targetElement)); |
| 1461 clearBreaksAndContinues(targetElement); | 1391 clearBreaksAndContinues(targetElement); |
| 1462 } | 1392 } |
| 1463 return null; | 1393 return null; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1553 return type; | 1483 return type; |
| 1554 } | 1484 } |
| 1555 | 1485 |
| 1556 T visitCascade(Cascade node) { | 1486 T visitCascade(Cascade node) { |
| 1557 // Ignore the result of the cascade send and return the type of the cascade | 1487 // Ignore the result of the cascade send and return the type of the cascade |
| 1558 // receiver. | 1488 // receiver. |
| 1559 visit(node.expression); | 1489 visit(node.expression); |
| 1560 return cascadeReceiverStack.removeLast(); | 1490 return cascadeReceiverStack.removeLast(); |
| 1561 } | 1491 } |
| 1562 } | 1492 } |
| OLD | NEW |