| 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 dart2js.ir_builder_task; | 5 library dart2js.ir_builder_task; |
| 6 | 6 |
| 7 import '../closure.dart' as closurelib; | 7 import '../closure.dart' as closurelib; |
| 8 import '../closure.dart' hide ClosureScope; | 8 import '../closure.dart' hide ClosureScope; |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 return irBuilder.buildConditional( | 544 return irBuilder.buildConditional( |
| 545 build(node.condition), | 545 build(node.condition), |
| 546 subbuild(node.thenExpression), | 546 subbuild(node.thenExpression), |
| 547 subbuild(node.elseExpression)); | 547 subbuild(node.elseExpression)); |
| 548 } | 548 } |
| 549 | 549 |
| 550 // For all simple literals: | 550 // For all simple literals: |
| 551 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] | 551 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] |
| 552 ir.Primitive visitLiteralBool(ast.LiteralBool node) { | 552 ir.Primitive visitLiteralBool(ast.LiteralBool node) { |
| 553 assert(irBuilder.isOpen); | 553 assert(irBuilder.isOpen); |
| 554 return translateConstant(node); | 554 return irBuilder.buildBooleanConstant(node.value); |
| 555 } | 555 } |
| 556 | 556 |
| 557 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) { | 557 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) { |
| 558 assert(irBuilder.isOpen); | 558 assert(irBuilder.isOpen); |
| 559 return translateConstant(node); | 559 return irBuilder.buildDoubleConstant(node.value); |
| 560 } | 560 } |
| 561 | 561 |
| 562 ir.Primitive visitLiteralInt(ast.LiteralInt node) { | 562 ir.Primitive visitLiteralInt(ast.LiteralInt node) { |
| 563 assert(irBuilder.isOpen); | 563 assert(irBuilder.isOpen); |
| 564 return translateConstant(node); | 564 return irBuilder.buildIntegerConstant(node.value); |
| 565 } | 565 } |
| 566 | 566 |
| 567 ir.Primitive visitLiteralNull(ast.LiteralNull node) { | 567 ir.Primitive visitLiteralNull(ast.LiteralNull node) { |
| 568 assert(irBuilder.isOpen); | 568 assert(irBuilder.isOpen); |
| 569 return translateConstant(node); | 569 return irBuilder.buildNullConstant(); |
| 570 } | 570 } |
| 571 | 571 |
| 572 ir.Primitive visitLiteralString(ast.LiteralString node) { | 572 ir.Primitive visitLiteralString(ast.LiteralString node) { |
| 573 assert(irBuilder.isOpen); | 573 assert(irBuilder.isOpen); |
| 574 return translateConstant(node); | 574 return irBuilder.buildDartStringConstant(node.dartString); |
| 575 } | 575 } |
| 576 | 576 |
| 577 ConstantExpression getConstantForNode(ast.Node node) { | 577 ConstantExpression getConstantForNode(ast.Node node) { |
| 578 ConstantExpression constant = | 578 ConstantExpression constant = |
| 579 compiler.backend.constantCompilerTask.compileNode(node, elements); | 579 compiler.backend.constants.getConstantForNode(node, elements); |
| 580 assert(invariant(node, constant != null, | 580 assert(invariant(node, constant != null, |
| 581 message: 'No constant computed for $node')); | 581 message: 'No constant computed for $node')); |
| 582 return constant; | 582 return constant; |
| 583 } | 583 } |
| 584 | 584 |
| 585 ConstantExpression getConstantForVariable(VariableElement element) { | 585 ConstantExpression getConstantForVariable(VariableElement element) { |
| 586 ConstantExpression constant = | 586 ConstantExpression constant = |
| 587 compiler.backend.constants.getConstantForVariable(element); | 587 compiler.backend.constants.getConstantForVariable(element); |
| 588 assert(invariant(element, constant != null, | 588 assert(invariant(element, constant != null, |
| 589 message: 'No constant computed for $element')); | 589 message: 'No constant computed for $element')); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 /// Returns `true` if [node] is a super call. | 683 /// Returns `true` if [node] is a super call. |
| 684 // TODO(johnniwinther): Remove the need for this. | 684 // TODO(johnniwinther): Remove the need for this. |
| 685 bool isSuperCall(ast.Send node) { | 685 bool isSuperCall(ast.Send node) { |
| 686 return node != null && node.receiver != null && node.receiver.isSuper(); | 686 return node != null && node.receiver != null && node.receiver.isSuper(); |
| 687 } | 687 } |
| 688 | 688 |
| 689 @override | 689 @override |
| 690 ir.Primitive handleConstantGet( | 690 ir.Primitive handleConstantGet( |
| 691 ast.Node node, | 691 ast.Node node, |
| 692 ConstantExpression constant, _) { | 692 ConstantExpression constant, _) { |
| 693 return irBuilder.buildConstantLiteral(constant); | 693 return irBuilder.buildConstant(constant); |
| 694 } | 694 } |
| 695 | 695 |
| 696 /// If [node] is null, returns this. | 696 /// If [node] is null, returns this. |
| 697 /// Otherwise visits [node] and returns the result. | 697 /// Otherwise visits [node] and returns the result. |
| 698 ir.Primitive translateReceiver(ast.Expression node) { | 698 ir.Primitive translateReceiver(ast.Expression node) { |
| 699 return node != null ? visit(node) : irBuilder.buildThis(); | 699 return node != null ? visit(node) : irBuilder.buildThis(); |
| 700 } | 700 } |
| 701 | 701 |
| 702 @override | 702 @override |
| 703 ir.Primitive handleDynamicGet( | 703 ir.Primitive handleDynamicGet( |
| 704 ast.Send node, | 704 ast.Send node, |
| 705 ast.Node receiver, | 705 ast.Node receiver, |
| 706 Selector selector, | 706 Selector selector, |
| 707 _) { | 707 _) { |
| 708 return irBuilder.buildDynamicGet( | 708 return irBuilder.buildDynamicGet( |
| 709 translateReceiver(receiver), | 709 translateReceiver(receiver), |
| 710 selector); | 710 selector); |
| 711 } | 711 } |
| 712 | 712 |
| 713 @override | 713 @override |
| 714 ir.Primitive visitDynamicTypeLiteralGet( | 714 ir.Primitive visitDynamicTypeLiteralGet( |
| 715 ast.Send node, | 715 ast.Send node, |
| 716 ConstantExpression constant, | 716 ConstantExpression constant, |
| 717 _) { | 717 _) { |
| 718 return irBuilder.buildConstantLiteral(constant); | 718 return irBuilder.buildConstant(constant); |
| 719 } | 719 } |
| 720 | 720 |
| 721 @override | 721 @override |
| 722 ir.Primitive visitLocalVariableGet( |
| 723 ast.Send node, |
| 724 LocalVariableElement element, |
| 725 _) { |
| 726 return element.isConst |
| 727 ? irBuilder.buildConstant(getConstantForVariable(element)) |
| 728 : irBuilder.buildLocalVariableGet(element); |
| 729 } |
| 730 |
| 731 @override |
| 722 ir.Primitive handleLocalGet( | 732 ir.Primitive handleLocalGet( |
| 723 ast.Send node, | 733 ast.Send node, |
| 724 LocalElement element, | 734 LocalElement element, |
| 725 _) { | 735 _) { |
| 726 if (element.isConst) { | |
| 727 return translateConstant(node); | |
| 728 } | |
| 729 return irBuilder.buildLocalVariableGet(element); | 736 return irBuilder.buildLocalVariableGet(element); |
| 730 } | 737 } |
| 731 | 738 |
| 732 @override | 739 @override |
| 733 ir.Primitive visitLocalFunctionGet( | 740 ir.Primitive visitLocalFunctionGet( |
| 734 ast.Send node, | 741 ast.Send node, |
| 735 LocalFunctionElement function, | 742 LocalFunctionElement function, |
| 736 _) { | 743 _) { |
| 737 return irBuilder.buildLocalFunctionGet(function); | 744 return irBuilder.buildLocalFunctionGet(function); |
| 738 } | 745 } |
| 739 | 746 |
| 740 @override | 747 @override |
| 741 ir.Primitive handleStaticFieldGet( | 748 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) { |
| 742 ast.Send node, | 749 return field.isConst |
| 743 FieldElement field, | 750 ? irBuilder.buildConstant(getConstantForVariable(field)) |
| 744 _) { | 751 : irBuilder.buildStaticFieldGet(field, |
| 745 if (field.isConst) { | 752 sourceInformation: sourceInformationBuilder.buildGet(node)); |
| 746 return translateConstant(node); | |
| 747 } | |
| 748 return irBuilder.buildStaticFieldGet(field, | |
| 749 sourceInformation: sourceInformationBuilder.buildGet(node)); | |
| 750 } | 753 } |
| 751 | 754 |
| 752 @override | 755 @override |
| 753 ir.Primitive handleStaticFunctionGet( | 756 ir.Primitive handleStaticFunctionGet( |
| 754 ast.Send node, | 757 ast.Send node, |
| 755 MethodElement function, | 758 MethodElement function, |
| 756 _) { | 759 _) { |
| 757 // TODO(karlklose): support foreign functions. | 760 // TODO(karlklose): support foreign functions. |
| 758 if (function.isForeign(compiler.backend)) { | 761 if (function.isForeign(compiler.backend)) { |
| 759 return giveup(node, 'handleStaticFunctionGet: foreign: $function'); | 762 return giveup(node, 'handleStaticFunctionGet: foreign: $function'); |
| 760 } | 763 } |
| 761 return translateConstant(node); | 764 return giveup(node, 'handleStaticFunctionGet: $function'); |
| 762 } | 765 } |
| 763 | 766 |
| 764 @override | 767 @override |
| 765 ir.Primitive handleStaticGetterGet( | 768 ir.Primitive handleStaticGetterGet( |
| 766 ast.Send node, | 769 ast.Send node, |
| 767 FunctionElement getter, | 770 FunctionElement getter, |
| 768 _) { | 771 _) { |
| 769 return irBuilder.buildStaticGetterGet(getter); | 772 return irBuilder.buildStaticGetterGet(getter); |
| 770 } | 773 } |
| 771 | 774 |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1017 translateDynamicArguments(arguments, callStructure)); | 1020 translateDynamicArguments(arguments, callStructure)); |
| 1018 } | 1021 } |
| 1019 | 1022 |
| 1020 @override | 1023 @override |
| 1021 ir.Primitive handleConstantInvoke( | 1024 ir.Primitive handleConstantInvoke( |
| 1022 ast.Send node, | 1025 ast.Send node, |
| 1023 ConstantExpression constant, | 1026 ConstantExpression constant, |
| 1024 ast.NodeList arguments, | 1027 ast.NodeList arguments, |
| 1025 CallStructure callStructure, | 1028 CallStructure callStructure, |
| 1026 _) { | 1029 _) { |
| 1027 return translateCallInvoke( | 1030 ir.Primitive target = irBuilder.buildConstant(constant); |
| 1028 irBuilder.buildConstantLiteral(constant), | 1031 return translateCallInvoke(target, arguments, callStructure); |
| 1029 arguments, | |
| 1030 callStructure); | |
| 1031 } | 1032 } |
| 1032 | 1033 |
| 1033 @override | 1034 @override |
| 1034 ir.Primitive handleDynamicInvoke( | 1035 ir.Primitive handleDynamicInvoke( |
| 1035 ast.Send node, | 1036 ast.Send node, |
| 1036 ast.Node receiver, | 1037 ast.Node receiver, |
| 1037 ast.NodeList arguments, | 1038 ast.NodeList arguments, |
| 1038 Selector selector, | 1039 Selector selector, |
| 1039 _) { | 1040 _) { |
| 1040 return irBuilder.buildDynamicInvocation( | 1041 return irBuilder.buildDynamicInvocation( |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1092 sourceInformation: sourceInformationBuilder.buildCall(node)); | 1093 sourceInformation: sourceInformationBuilder.buildCall(node)); |
| 1093 } | 1094 } |
| 1094 | 1095 |
| 1095 @override | 1096 @override |
| 1096 ir.Primitive handleStaticGetterInvoke( | 1097 ir.Primitive handleStaticGetterInvoke( |
| 1097 ast.Send node, | 1098 ast.Send node, |
| 1098 FunctionElement getter, | 1099 FunctionElement getter, |
| 1099 ast.NodeList arguments, | 1100 ast.NodeList arguments, |
| 1100 CallStructure callStructure, | 1101 CallStructure callStructure, |
| 1101 _) { | 1102 _) { |
| 1103 if (getter.isForeign(compiler.backend)) { |
| 1104 return giveup(node, 'handleStaticGetterInvoke: foreign: $getter'); |
| 1105 } |
| 1102 ir.Primitive target = irBuilder.buildStaticGetterGet(getter); | 1106 ir.Primitive target = irBuilder.buildStaticGetterGet(getter); |
| 1103 return irBuilder.buildCallInvocation(target, | 1107 return irBuilder.buildCallInvocation(target, |
| 1104 callStructure, | 1108 callStructure, |
| 1105 translateDynamicArguments(arguments, callStructure)); | 1109 translateDynamicArguments(arguments, callStructure)); |
| 1106 } | 1110 } |
| 1107 | 1111 |
| 1108 @override | 1112 @override |
| 1109 ir.Primitive visitSuperFieldInvoke( | 1113 ir.Primitive visitSuperFieldInvoke( |
| 1110 ast.Send node, | 1114 ast.Send node, |
| 1111 FieldElement field, | 1115 FieldElement field, |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1237 | 1241 |
| 1238 ir.Primitive translatePrefixPostfix( | 1242 ir.Primitive translatePrefixPostfix( |
| 1239 {ir.Primitive getValue(), | 1243 {ir.Primitive getValue(), |
| 1240 op.IncDecOperator operator, | 1244 op.IncDecOperator operator, |
| 1241 void setValue(ir.Primitive value), | 1245 void setValue(ir.Primitive value), |
| 1242 bool isPrefix}) { | 1246 bool isPrefix}) { |
| 1243 ir.Primitive value = getValue(); | 1247 ir.Primitive value = getValue(); |
| 1244 Selector operatorSelector = | 1248 Selector operatorSelector = |
| 1245 new Selector.binaryOperator(operator.selectorName); | 1249 new Selector.binaryOperator(operator.selectorName); |
| 1246 List<ir.Primitive> arguments = | 1250 List<ir.Primitive> arguments = |
| 1247 <ir.Primitive>[irBuilder.buildIntegerLiteral(1)]; | 1251 <ir.Primitive>[irBuilder.buildIntegerConstant(1)]; |
| 1248 arguments = normalizeDynamicArguments( | 1252 arguments = normalizeDynamicArguments( |
| 1249 operatorSelector.callStructure, arguments); | 1253 operatorSelector.callStructure, arguments); |
| 1250 ir.Primitive result = | 1254 ir.Primitive result = |
| 1251 irBuilder.buildDynamicInvocation(value, operatorSelector, arguments); | 1255 irBuilder.buildDynamicInvocation(value, operatorSelector, arguments); |
| 1252 setValue(result); | 1256 setValue(result); |
| 1253 return isPrefix ? result : value; | 1257 return isPrefix ? result : value; |
| 1254 } | 1258 } |
| 1255 | 1259 |
| 1256 ir.Primitive translateCompound( | 1260 ir.Primitive translateCompound( |
| 1257 {ir.Primitive getValue(), | 1261 {ir.Primitive getValue(), |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1764 while (it.moveNext()) { | 1768 while (it.moveNext()) { |
| 1765 ast.StringInterpolationPart part = it.current; | 1769 ast.StringInterpolationPart part = it.current; |
| 1766 arguments.add(visit(part.expression)); | 1770 arguments.add(visit(part.expression)); |
| 1767 arguments.add(visitLiteralString(part.string)); | 1771 arguments.add(visitLiteralString(part.string)); |
| 1768 } | 1772 } |
| 1769 return irBuilder.buildStringConcatenation(arguments); | 1773 return irBuilder.buildStringConcatenation(arguments); |
| 1770 } | 1774 } |
| 1771 | 1775 |
| 1772 ir.Primitive translateConstant(ast.Node node) { | 1776 ir.Primitive translateConstant(ast.Node node) { |
| 1773 assert(irBuilder.isOpen); | 1777 assert(irBuilder.isOpen); |
| 1774 return irBuilder.buildConstantLiteral(getConstantForNode(node)); | 1778 return irBuilder.buildConstant(getConstantForNode(node)); |
| 1775 } | 1779 } |
| 1776 | 1780 |
| 1777 ir.Primitive visitThrow(ast.Throw node) { | 1781 ir.Primitive visitThrow(ast.Throw node) { |
| 1778 assert(irBuilder.isOpen); | 1782 assert(irBuilder.isOpen); |
| 1779 // This function is not called for throw expressions occurring as | 1783 // This function is not called for throw expressions occurring as |
| 1780 // statements. | 1784 // statements. |
| 1781 return irBuilder.buildNonTailThrow(visit(node.expression)); | 1785 return irBuilder.buildNonTailThrow(visit(node.expression)); |
| 1782 } | 1786 } |
| 1783 | 1787 |
| 1784 ir.RootNode nullIfGiveup(ir.RootNode action()) { | 1788 ir.RootNode nullIfGiveup(ir.RootNode action()) { |
| (...skipping 628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2413 ClassElement enclosingClass = constructor.enclosingClass.implementation; | 2417 ClassElement enclosingClass = constructor.enclosingClass.implementation; |
| 2414 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) { | 2418 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) { |
| 2415 if (field.initializer != null) { | 2419 if (field.initializer != null) { |
| 2416 fieldValues[field] = inlineExpression(field, field.initializer); | 2420 fieldValues[field] = inlineExpression(field, field.initializer); |
| 2417 } else { | 2421 } else { |
| 2418 if (Elements.isNativeOrExtendsNative(c)) { | 2422 if (Elements.isNativeOrExtendsNative(c)) { |
| 2419 // Native field is initialized elsewhere. | 2423 // Native field is initialized elsewhere. |
| 2420 } else { | 2424 } else { |
| 2421 // Fields without an initializer default to null. | 2425 // Fields without an initializer default to null. |
| 2422 // This value will be overwritten below if an initializer is found. | 2426 // This value will be overwritten below if an initializer is found. |
| 2423 fieldValues[field] = irBuilder.buildNullLiteral(); | 2427 fieldValues[field] = irBuilder.buildNullConstant(); |
| 2424 } | 2428 } |
| 2425 } | 2429 } |
| 2426 }); | 2430 }); |
| 2427 // Evaluate initializing parameters, e.g. `Foo(this.x)`. | 2431 // Evaluate initializing parameters, e.g. `Foo(this.x)`. |
| 2428 constructor.functionSignature.orderedForEachParameter( | 2432 constructor.functionSignature.orderedForEachParameter( |
| 2429 (ParameterElement parameter) { | 2433 (ParameterElement parameter) { |
| 2430 if (parameter.isInitializingFormal) { | 2434 if (parameter.isInitializingFormal) { |
| 2431 InitializingFormalElement fieldParameter = parameter; | 2435 InitializingFormalElement fieldParameter = parameter; |
| 2432 fieldValues[fieldParameter.fieldElement] = | 2436 fieldValues[fieldParameter.fieldElement] = |
| 2433 irBuilder.buildLocalVariableGet(parameter); | 2437 irBuilder.buildLocalVariableGet(parameter); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2503 value = arguments[translatedIndex]; | 2507 value = arguments[translatedIndex]; |
| 2504 } | 2508 } |
| 2505 } else if (index < arguments.length) { | 2509 } else if (index < arguments.length) { |
| 2506 value = arguments[index]; | 2510 value = arguments[index]; |
| 2507 } | 2511 } |
| 2508 // Load default if argument was not provided. | 2512 // Load default if argument was not provided. |
| 2509 if (value == null) { | 2513 if (value == null) { |
| 2510 if (param.initializer != null) { | 2514 if (param.initializer != null) { |
| 2511 value = inlineExpression(target, param.initializer); | 2515 value = inlineExpression(target, param.initializer); |
| 2512 } else { | 2516 } else { |
| 2513 value = irBuilder.buildNullLiteral(); | 2517 value = irBuilder.buildNullConstant(); |
| 2514 } | 2518 } |
| 2515 } | 2519 } |
| 2516 irBuilder.declareLocalVariable(param, initialValue: value); | 2520 irBuilder.declareLocalVariable(param, initialValue: value); |
| 2517 index++; | 2521 index++; |
| 2518 }); | 2522 }); |
| 2519 } | 2523 } |
| 2520 | 2524 |
| 2521 /** | 2525 /** |
| 2522 * Returns the constructor body associated with the given constructor or | 2526 * Returns the constructor body associated with the given constructor or |
| 2523 * creates a new constructor body, if none can be found. | 2527 * creates a new constructor body, if none can be found. |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2651 elements); | 2655 elements); |
| 2652 DartCapturedVariables variables = _analyzeCapturedVariables(node); | 2656 DartCapturedVariables variables = _analyzeCapturedVariables(node); |
| 2653 tryStatements = variables.tryStatements; | 2657 tryStatements = variables.tryStatements; |
| 2654 IrBuilder builder = getBuilderFor(element); | 2658 IrBuilder builder = getBuilderFor(element); |
| 2655 return withBuilder(builder, () => _makeFunctionBody(element, node)); | 2659 return withBuilder(builder, () => _makeFunctionBody(element, node)); |
| 2656 } | 2660 } |
| 2657 | 2661 |
| 2658 /// Creates a primitive for the default value of [parameter]. | 2662 /// Creates a primitive for the default value of [parameter]. |
| 2659 ir.Primitive translateDefaultValue(ParameterElement parameter) { | 2663 ir.Primitive translateDefaultValue(ParameterElement parameter) { |
| 2660 if (parameter.initializer == null) { | 2664 if (parameter.initializer == null) { |
| 2661 return irBuilder.buildNullLiteral(); | 2665 return irBuilder.buildNullConstant(); |
| 2662 } else { | 2666 } else { |
| 2663 return inlineConstant(parameter.executableContext, parameter.initializer); | 2667 return inlineConstant(parameter.executableContext, parameter.initializer); |
| 2664 } | 2668 } |
| 2665 } | 2669 } |
| 2666 | 2670 |
| 2667 /// Inserts default arguments and normalizes order of named arguments. | 2671 /// Inserts default arguments and normalizes order of named arguments. |
| 2668 List<ir.Primitive> normalizeStaticArguments( | 2672 List<ir.Primitive> normalizeStaticArguments( |
| 2669 CallStructure callStructure, | 2673 CallStructure callStructure, |
| 2670 FunctionElement target, | 2674 FunctionElement target, |
| 2671 List<ir.Primitive> arguments) { | 2675 List<ir.Primitive> arguments) { |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2862 } | 2866 } |
| 2863 } | 2867 } |
| 2864 | 2868 |
| 2865 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2869 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
| 2866 class RemovalVisitor extends ir.RecursiveVisitor { | 2870 class RemovalVisitor extends ir.RecursiveVisitor { |
| 2867 processReference(ir.Reference reference) { | 2871 processReference(ir.Reference reference) { |
| 2868 reference.unlink(); | 2872 reference.unlink(); |
| 2869 } | 2873 } |
| 2870 } | 2874 } |
| 2871 | 2875 |
| OLD | NEW |