| 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 | |
| 399 visit(Node node) => node.accept(this); | 393 visit(Node node) => node.accept(this); |
| 400 | 394 |
| 401 visitNode(Node node) => node.visitChildren(this); | 395 visitNode(Node node) => node.visitChildren(this); |
| 402 | 396 |
| 403 visitVariableDefinitions(VariableDefinitions node) { | 397 visitVariableDefinitions(VariableDefinitions node) { |
| 404 if (node.type != null) { | |
| 405 visit(node.type); | |
| 406 } | |
| 407 for (Link<Node> link = node.definitions.nodes; | 398 for (Link<Node> link = node.definitions.nodes; |
| 408 !link.isEmpty; | 399 !link.isEmpty; |
| 409 link = link.tail) { | 400 link = link.tail) { |
| 410 Node definition = link.head; | 401 Node definition = link.head; |
| 411 Element element = elements[definition]; | 402 Element element = elements[definition]; |
| 412 assert(element != null); | 403 assert(element != null); |
| 413 declareLocal(element); | 404 declareLocal(element); |
| 414 // We still need to visit the right-hand sides of the init-assignments. | 405 // We still need to visit the right-hand sides of the init-assignments. |
| 415 // For SendSets don't visit the left again. Otherwise it would be marked | 406 // For SendSets don't visit the left again. Otherwise it would be marked |
| 416 // as mutated. | 407 // as mutated. |
| 417 if (definition is Send) { | 408 if (definition is Send) { |
| 418 Send assignment = definition; | 409 Send assignment = definition; |
| 419 Node arguments = assignment.argumentsNode; | 410 Node arguments = assignment.argumentsNode; |
| 420 if (arguments != null) { | 411 if (arguments != null) { |
| 421 visit(arguments); | 412 visit(arguments); |
| 422 } | 413 } |
| 423 } else { | 414 } else { |
| 424 visit(definition); | 415 visit(definition); |
| 425 } | 416 } |
| 426 } | 417 } |
| 427 } | 418 } |
| 428 | 419 |
| 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 | |
| 454 visitIdentifier(Identifier node) { | 420 visitIdentifier(Identifier node) { |
| 455 if (node.isThis()) { | 421 if (node.isThis()) { |
| 456 registerNeedsThis(); | 422 useLocal(closureData.thisElement); |
| 457 } else { | 423 } else { |
| 458 Element element = elements[node]; | 424 Element element = elements[node]; |
| 459 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { | 425 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { |
| 460 registerNeedsThis(); | 426 useLocal(closureData.thisElement); |
| 461 } | 427 } |
| 462 } | 428 } |
| 463 node.visitChildren(this); | 429 node.visitChildren(this); |
| 464 } | 430 } |
| 465 | 431 |
| 466 visitSend(Send node) { | 432 visitSend(Send node) { |
| 467 Element element = elements[node]; | 433 Element element = elements[node]; |
| 468 if (Elements.isLocal(element)) { | 434 if (Elements.isLocal(element)) { |
| 469 useLocal(element); | 435 useLocal(element); |
| 470 } else if (node.receiver == null && | 436 } else if (node.receiver == null && |
| 471 Elements.isInstanceSend(node, elements)) { | 437 Elements.isInstanceSend(node, elements)) { |
| 472 registerNeedsThis(); | 438 useLocal(closureData.thisElement); |
| 473 } else if (node.isSuperCall) { | 439 } else if (node.isSuperCall) { |
| 474 registerNeedsThis(); | 440 useLocal(closureData.thisElement); |
| 475 } else if (node.isParameterCheck) { | 441 } else if (node.isParameterCheck) { |
| 476 Element parameter = elements[node.receiver]; | 442 Element parameter = elements[node.receiver]; |
| 477 FunctionElement enclosing = parameter.enclosingElement; | 443 FunctionElement enclosing = parameter.enclosingElement; |
| 478 FunctionExpression function = enclosing.parseNode(compiler); | 444 FunctionExpression function = enclosing.parseNode(compiler); |
| 479 ClosureClassMap cached = closureMappingCache[function]; | 445 ClosureClassMap cached = closureMappingCache[function]; |
| 480 if (!cached.parametersWithSentinel.containsKey(parameter)) { | 446 if (!cached.parametersWithSentinel.containsKey(parameter)) { |
| 481 SourceString parameterName = parameter.name; | 447 SourceString parameterName = parameter.name; |
| 482 String name = '${parameterName.slowToString()}_check'; | 448 String name = '${parameterName.slowToString()}_check'; |
| 483 Element newElement = new CheckVariableElement(new SourceString(name), | 449 Element newElement = new CheckVariableElement(new SourceString(name), |
| 484 parameter, | 450 parameter, |
| 485 enclosing); | 451 enclosing); |
| 486 useLocal(newElement); | 452 useLocal(newElement); |
| 487 cached.parametersWithSentinel[parameter] = newElement; | 453 cached.parametersWithSentinel[parameter] = newElement; |
| 488 } | 454 } |
| 489 } | 455 } |
| 490 node.visitChildren(this); | 456 node.visitChildren(this); |
| 491 } | 457 } |
| 492 | 458 |
| 493 visitSendSet(SendSet node) { | 459 visitSendSet(SendSet node) { |
| 494 Element element = elements[node]; | 460 Element element = elements[node]; |
| 495 if (Elements.isLocal(element)) { | 461 if (Elements.isLocal(element)) { |
| 496 mutatedVariables.add(element); | 462 mutatedVariables.add(element); |
| 497 } | 463 } |
| 498 if (Elements.isLocal(element) && | |
| 499 element.computeType(compiler).containsTypeVariables) { | |
| 500 registerNeedsThis(); | |
| 501 } | |
| 502 super.visitSendSet(node); | 464 super.visitSendSet(node); |
| 503 } | 465 } |
| 504 | 466 |
| 505 visitNewExpression(NewExpression node) { | 467 visitNewExpression(NewExpression node) { |
| 506 DartType type = elements.getType(node); | 468 DartType type = elements.getType(node); |
| 507 | 469 |
| 508 bool hasTypeVariable(DartType type) { | 470 bool hasTypeVariable(DartType type) { |
| 509 if (type is TypeVariableType) { | 471 if (type is TypeVariableType) { |
| 510 return true; | 472 return true; |
| 511 } else if (type is InterfaceType) { | 473 } else if (type is InterfaceType) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 528 analyzeTypeVariables(argument); | 490 analyzeTypeVariables(argument); |
| 529 } | 491 } |
| 530 } | 492 } |
| 531 } | 493 } |
| 532 | 494 |
| 533 if (outermostElement.isMember() && | 495 if (outermostElement.isMember() && |
| 534 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { | 496 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { |
| 535 if (outermostElement.isConstructor() || outermostElement.isField()) { | 497 if (outermostElement.isConstructor() || outermostElement.isField()) { |
| 536 analyzeTypeVariables(type); | 498 analyzeTypeVariables(type); |
| 537 } else if (outermostElement.isInstanceMember()) { | 499 } else if (outermostElement.isInstanceMember()) { |
| 538 if (hasTypeVariable(type)) { | 500 if (hasTypeVariable(type)) useLocal(closureData.thisElement); |
| 539 registerNeedsThis(); | |
| 540 } | |
| 541 } | 501 } |
| 542 } | 502 } |
| 543 | 503 |
| 544 node.visitChildren(this); | 504 node.visitChildren(this); |
| 545 } | 505 } |
| 546 | 506 |
| 547 // If variables that are declared in the [node] scope are captured and need | 507 // If variables that are declared in the [node] scope are captured and need |
| 548 // to be boxed create a box-element and update the [capturingScopes] in the | 508 // to be boxed create a box-element and update the [capturingScopes] in the |
| 549 // current [closureData]. | 509 // current [closureData]. |
| 550 // The boxed variables are updated in the [capturedVariableMapping]. | 510 // The boxed variables are updated in the [capturedVariableMapping]. |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 if (currentElement.isFactoryConstructor() && | 662 if (currentElement.isFactoryConstructor() && |
| 703 compiler.backend.needsRti(currentElement.enclosingElement)) { | 663 compiler.backend.needsRti(currentElement.enclosingElement)) { |
| 704 // Declare the type parameters in the scope. Generative | 664 // Declare the type parameters in the scope. Generative |
| 705 // constructors just use 'this'. | 665 // constructors just use 'this'. |
| 706 ClassElement cls = currentElement.enclosingElement; | 666 ClassElement cls = currentElement.enclosingElement; |
| 707 cls.typeVariables.forEach((TypeVariableType typeVariable) { | 667 cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| 708 declareLocal(typeVariable.element); | 668 declareLocal(typeVariable.element); |
| 709 }); | 669 }); |
| 710 } | 670 } |
| 711 | 671 |
| 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 | |
| 718 visitChildren(); | 672 visitChildren(); |
| 719 }); | 673 }); |
| 720 | 674 |
| 721 | 675 |
| 722 ClosureClassMap savedClosureData = closureData; | 676 ClosureClassMap savedClosureData = closureData; |
| 723 bool savedInsideClosure = insideClosure; | 677 bool savedInsideClosure = insideClosure; |
| 724 | 678 |
| 725 // Restore old values. | 679 // Restore old values. |
| 726 insideClosure = oldInsideClosure; | 680 insideClosure = oldInsideClosure; |
| 727 closureData = oldClosureData; | 681 closureData = oldClosureData; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 } | 719 } |
| 766 | 720 |
| 767 visitTryStatement(TryStatement node) { | 721 visitTryStatement(TryStatement node) { |
| 768 // TODO(ngeoffray): implement finer grain state. | 722 // TODO(ngeoffray): implement finer grain state. |
| 769 bool oldInTryStatement = inTryStatement; | 723 bool oldInTryStatement = inTryStatement; |
| 770 inTryStatement = true; | 724 inTryStatement = true; |
| 771 node.visitChildren(this); | 725 node.visitChildren(this); |
| 772 inTryStatement = oldInTryStatement; | 726 inTryStatement = oldInTryStatement; |
| 773 } | 727 } |
| 774 } | 728 } |
| OLD | NEW |