| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 closureToClassMapper; | 5 library closureToClassMapper; |
| 6 | 6 |
| 7 import "elements/elements.dart"; | 7 import "elements/elements.dart"; |
| 8 import "dart2jslib.dart"; | 8 import "dart2jslib.dart"; |
| 9 import "dart_types.dart"; | 9 import "dart_types.dart"; |
| 10 import "scanner/scannerlib.dart" show Token; | 10 import "scanner/scannerlib.dart" show Token; |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 // TODO(ngeoffray): only do this if the variable is mutated. | 383 // TODO(ngeoffray): only do this if the variable is mutated. |
| 384 closureData.usedVariablesInTry.add(element); | 384 closureData.usedVariablesInTry.add(element); |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 } | 387 } |
| 388 | 388 |
| 389 void declareLocal(Element element) { | 389 void declareLocal(Element element) { |
| 390 scopeVariables.add(element); | 390 scopeVariables.add(element); |
| 391 } | 391 } |
| 392 | 392 |
| 393 void registerNeedsThis() { |
| 394 if (closureData.thisElement != null) { |
| 395 useLocal(closureData.thisElement); |
| 396 } |
| 397 } |
| 398 |
| 393 visit(Node node) => node.accept(this); | 399 visit(Node node) => node.accept(this); |
| 394 | 400 |
| 395 visitNode(Node node) => node.visitChildren(this); | 401 visitNode(Node node) => node.visitChildren(this); |
| 396 | 402 |
| 397 visitVariableDefinitions(VariableDefinitions node) { | 403 visitVariableDefinitions(VariableDefinitions node) { |
| 404 if (node.type != null) { |
| 405 visit(node.type); |
| 406 } |
| 398 for (Link<Node> link = node.definitions.nodes; | 407 for (Link<Node> link = node.definitions.nodes; |
| 399 !link.isEmpty; | 408 !link.isEmpty; |
| 400 link = link.tail) { | 409 link = link.tail) { |
| 401 Node definition = link.head; | 410 Node definition = link.head; |
| 402 Element element = elements[definition]; | 411 Element element = elements[definition]; |
| 403 assert(element != null); | 412 assert(element != null); |
| 404 declareLocal(element); | 413 declareLocal(element); |
| 405 // We still need to visit the right-hand sides of the init-assignments. | 414 // We still need to visit the right-hand sides of the init-assignments. |
| 406 // For SendSets don't visit the left again. Otherwise it would be marked | 415 // For SendSets don't visit the left again. Otherwise it would be marked |
| 407 // as mutated. | 416 // as mutated. |
| 408 if (definition is Send) { | 417 if (definition is Send) { |
| 409 Send assignment = definition; | 418 Send assignment = definition; |
| 410 Node arguments = assignment.argumentsNode; | 419 Node arguments = assignment.argumentsNode; |
| 411 if (arguments != null) { | 420 if (arguments != null) { |
| 412 visit(arguments); | 421 visit(arguments); |
| 413 } | 422 } |
| 414 } else { | 423 } else { |
| 415 visit(definition); | 424 visit(definition); |
| 416 } | 425 } |
| 417 } | 426 } |
| 418 } | 427 } |
| 419 | 428 |
| 429 visitTypeAnnotation(TypeAnnotation node) { |
| 430 Element member = currentElement.getEnclosingMember(); |
| 431 DartType type = elements.getType(node); |
| 432 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
| 433 // from a parameter which has been analyzed before the method has been |
| 434 // resolved and the result has been thrown away. |
| 435 if (compiler.enableTypeAssertions && type != null && |
| 436 type.containsTypeVariables) { |
| 437 if (insideClosure && member.isFactoryConstructor()) { |
| 438 // This is a closure in a factory constructor. Since there is no |
| 439 // [:this:], we have to mark the type arguments as free variables to |
| 440 // capture them in the closure. |
| 441 type.forEachTypeVariable((variable) => useLocal(variable.element)); |
| 442 } |
| 443 // TODO(karlklose): try to get rid of the isField check; there is a bug |
| 444 // with type variable use in field initializer (in both modes). |
| 445 if (member.isInstanceMember() && !member.isField()) { |
| 446 // In checked mode, using a type variable in a type annotation may lead |
| 447 // to a runtime type check that needs to access the type argument and |
| 448 // therefore the closure needs a this-element. |
| 449 registerNeedsThis(); |
| 450 } |
| 451 } |
| 452 } |
| 453 |
| 420 visitIdentifier(Identifier node) { | 454 visitIdentifier(Identifier node) { |
| 421 if (node.isThis()) { | 455 if (node.isThis()) { |
| 422 useLocal(closureData.thisElement); | 456 registerNeedsThis(); |
| 423 } else { | 457 } else { |
| 424 Element element = elements[node]; | 458 Element element = elements[node]; |
| 425 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { | 459 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { |
| 426 useLocal(closureData.thisElement); | 460 registerNeedsThis(); |
| 427 } | 461 } |
| 428 } | 462 } |
| 429 node.visitChildren(this); | 463 node.visitChildren(this); |
| 430 } | 464 } |
| 431 | 465 |
| 432 visitSend(Send node) { | 466 visitSend(Send node) { |
| 433 Element element = elements[node]; | 467 Element element = elements[node]; |
| 434 if (Elements.isLocal(element)) { | 468 if (Elements.isLocal(element)) { |
| 435 useLocal(element); | 469 useLocal(element); |
| 436 } else if (node.receiver == null && | 470 } else if (node.receiver == null && |
| 437 Elements.isInstanceSend(node, elements)) { | 471 Elements.isInstanceSend(node, elements)) { |
| 438 useLocal(closureData.thisElement); | 472 registerNeedsThis(); |
| 439 } else if (node.isSuperCall) { | 473 } else if (node.isSuperCall) { |
| 440 useLocal(closureData.thisElement); | 474 registerNeedsThis(); |
| 441 } else if (node.isParameterCheck) { | 475 } else if (node.isParameterCheck) { |
| 442 Element parameter = elements[node.receiver]; | 476 Element parameter = elements[node.receiver]; |
| 443 FunctionElement enclosing = parameter.enclosingElement; | 477 FunctionElement enclosing = parameter.enclosingElement; |
| 444 FunctionExpression function = enclosing.parseNode(compiler); | 478 FunctionExpression function = enclosing.parseNode(compiler); |
| 445 ClosureClassMap cached = closureMappingCache[function]; | 479 ClosureClassMap cached = closureMappingCache[function]; |
| 446 if (!cached.parametersWithSentinel.containsKey(parameter)) { | 480 if (!cached.parametersWithSentinel.containsKey(parameter)) { |
| 447 SourceString parameterName = parameter.name; | 481 SourceString parameterName = parameter.name; |
| 448 String name = '${parameterName.slowToString()}_check'; | 482 String name = '${parameterName.slowToString()}_check'; |
| 449 Element newElement = new CheckVariableElement(new SourceString(name), | 483 Element newElement = new CheckVariableElement(new SourceString(name), |
| 450 parameter, | 484 parameter, |
| 451 enclosing); | 485 enclosing); |
| 452 useLocal(newElement); | 486 useLocal(newElement); |
| 453 cached.parametersWithSentinel[parameter] = newElement; | 487 cached.parametersWithSentinel[parameter] = newElement; |
| 454 } | 488 } |
| 455 } | 489 } |
| 456 node.visitChildren(this); | 490 node.visitChildren(this); |
| 457 } | 491 } |
| 458 | 492 |
| 459 visitSendSet(SendSet node) { | 493 visitSendSet(SendSet node) { |
| 460 Element element = elements[node]; | 494 Element element = elements[node]; |
| 461 if (Elements.isLocal(element)) { | 495 if (Elements.isLocal(element)) { |
| 462 mutatedVariables.add(element); | 496 mutatedVariables.add(element); |
| 463 } | 497 } |
| 498 if (Elements.isLocal(element) && |
| 499 element.computeType(compiler).containsTypeVariables) { |
| 500 registerNeedsThis(); |
| 501 } |
| 464 super.visitSendSet(node); | 502 super.visitSendSet(node); |
| 465 } | 503 } |
| 466 | 504 |
| 467 visitNewExpression(NewExpression node) { | 505 visitNewExpression(NewExpression node) { |
| 468 DartType type = elements.getType(node); | 506 DartType type = elements.getType(node); |
| 469 | 507 |
| 470 bool hasTypeVariable(DartType type) { | 508 bool hasTypeVariable(DartType type) { |
| 471 if (type is TypeVariableType) { | 509 if (type is TypeVariableType) { |
| 472 return true; | 510 return true; |
| 473 } else if (type is InterfaceType) { | 511 } else if (type is InterfaceType) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 490 analyzeTypeVariables(argument); | 528 analyzeTypeVariables(argument); |
| 491 } | 529 } |
| 492 } | 530 } |
| 493 } | 531 } |
| 494 | 532 |
| 495 if (outermostElement.isMember() && | 533 if (outermostElement.isMember() && |
| 496 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { | 534 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { |
| 497 if (outermostElement.isConstructor() || outermostElement.isField()) { | 535 if (outermostElement.isConstructor() || outermostElement.isField()) { |
| 498 analyzeTypeVariables(type); | 536 analyzeTypeVariables(type); |
| 499 } else if (outermostElement.isInstanceMember()) { | 537 } else if (outermostElement.isInstanceMember()) { |
| 500 if (hasTypeVariable(type)) useLocal(closureData.thisElement); | 538 if (hasTypeVariable(type)) { |
| 539 registerNeedsThis(); |
| 540 } |
| 501 } | 541 } |
| 502 } | 542 } |
| 503 | 543 |
| 504 node.visitChildren(this); | 544 node.visitChildren(this); |
| 505 } | 545 } |
| 506 | 546 |
| 507 // If variables that are declared in the [node] scope are captured and need | 547 // If variables that are declared in the [node] scope are captured and need |
| 508 // to be boxed create a box-element and update the [capturingScopes] in the | 548 // to be boxed create a box-element and update the [capturingScopes] in the |
| 509 // current [closureData]. | 549 // current [closureData]. |
| 510 // The boxed variables are updated in the [capturedVariableMapping]. | 550 // The boxed variables are updated in the [capturedVariableMapping]. |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 if (currentElement.isFactoryConstructor() && | 702 if (currentElement.isFactoryConstructor() && |
| 663 compiler.backend.needsRti(currentElement.enclosingElement)) { | 703 compiler.backend.needsRti(currentElement.enclosingElement)) { |
| 664 // Declare the type parameters in the scope. Generative | 704 // Declare the type parameters in the scope. Generative |
| 665 // constructors just use 'this'. | 705 // constructors just use 'this'. |
| 666 ClassElement cls = currentElement.enclosingElement; | 706 ClassElement cls = currentElement.enclosingElement; |
| 667 cls.typeVariables.forEach((TypeVariableType typeVariable) { | 707 cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| 668 declareLocal(typeVariable.element); | 708 declareLocal(typeVariable.element); |
| 669 }); | 709 }); |
| 670 } | 710 } |
| 671 | 711 |
| 712 // Compute the function type and check for type variables in return or |
| 713 // parameter types. |
| 714 if (element.computeType(compiler).containsTypeVariables) { |
| 715 registerNeedsThis(); |
| 716 } |
| 717 |
| 672 visitChildren(); | 718 visitChildren(); |
| 673 }); | 719 }); |
| 674 | 720 |
| 675 | 721 |
| 676 ClosureClassMap savedClosureData = closureData; | 722 ClosureClassMap savedClosureData = closureData; |
| 677 bool savedInsideClosure = insideClosure; | 723 bool savedInsideClosure = insideClosure; |
| 678 | 724 |
| 679 // Restore old values. | 725 // Restore old values. |
| 680 insideClosure = oldInsideClosure; | 726 insideClosure = oldInsideClosure; |
| 681 closureData = oldClosureData; | 727 closureData = oldClosureData; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 } | 765 } |
| 720 | 766 |
| 721 visitTryStatement(TryStatement node) { | 767 visitTryStatement(TryStatement node) { |
| 722 // TODO(ngeoffray): implement finer grain state. | 768 // TODO(ngeoffray): implement finer grain state. |
| 723 bool oldInTryStatement = inTryStatement; | 769 bool oldInTryStatement = inTryStatement; |
| 724 inTryStatement = true; | 770 inTryStatement = true; |
| 725 node.visitChildren(this); | 771 node.visitChildren(this); |
| 726 inTryStatement = oldInTryStatement; | 772 inTryStatement = oldInTryStatement; |
| 727 } | 773 } |
| 728 } | 774 } |
| OLD | NEW |