| 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 dart2js.compile_time_constant_evaluator; | 5 library dart2js.compile_time_constant_evaluator; |
| 6 | 6 |
| 7 import 'common/tasks.dart' show | 7 import 'common/tasks.dart' show |
| 8 CompilerTask; | 8 CompilerTask; |
| 9 import 'compiler.dart' show | 9 import 'compiler.dart' show |
| 10 Compiler; | 10 Compiler; |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 * eagerly. If the variable needs to be initialized lazily returns `null`. | 214 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 215 * If the variable is `const` but cannot be compiled eagerly reports an | 215 * If the variable is `const` but cannot be compiled eagerly reports an |
| 216 * error. | 216 * error. |
| 217 */ | 217 */ |
| 218 ConstantExpression compileVariableWithDefinitions( | 218 ConstantExpression compileVariableWithDefinitions( |
| 219 VariableElement element, TreeElements definitions, | 219 VariableElement element, TreeElements definitions, |
| 220 {bool isConst: false, bool checkType: true}) { | 220 {bool isConst: false, bool checkType: true}) { |
| 221 Node node = element.node; | 221 Node node = element.node; |
| 222 if (pendingVariables.contains(element)) { | 222 if (pendingVariables.contains(element)) { |
| 223 if (isConst) { | 223 if (isConst) { |
| 224 compiler.reportError(node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | 224 compiler.reportErrorMessage( |
| 225 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 225 ConstantExpression expression = new ErroneousConstantExpression(); | 226 ConstantExpression expression = new ErroneousConstantExpression(); |
| 226 constantValueMap[expression] = constantSystem.createNull(); | 227 constantValueMap[expression] = constantSystem.createNull(); |
| 227 return expression; | 228 return expression; |
| 228 } | 229 } |
| 229 return null; | 230 return null; |
| 230 } | 231 } |
| 231 pendingVariables.add(element); | 232 pendingVariables.add(element); |
| 232 | 233 |
| 233 Expression initializer = element.initializer; | 234 Expression initializer = element.initializer; |
| 234 ConstantExpression expression; | 235 ConstantExpression expression; |
| 235 if (initializer == null) { | 236 if (initializer == null) { |
| 236 // No initial value. | 237 // No initial value. |
| 237 expression = new NullConstantExpression(); | 238 expression = new NullConstantExpression(); |
| 238 constantValueMap[expression] = constantSystem.createNull(); | 239 constantValueMap[expression] = constantSystem.createNull(); |
| 239 } else { | 240 } else { |
| 240 expression = compileNodeWithDefinitions(initializer, definitions, | 241 expression = compileNodeWithDefinitions(initializer, definitions, |
| 241 isConst: isConst); | 242 isConst: isConst); |
| 242 if (compiler.enableTypeAssertions && | 243 if (compiler.enableTypeAssertions && |
| 243 checkType && | 244 checkType && |
| 244 expression != null && | 245 expression != null && |
| 245 element.isField) { | 246 element.isField) { |
| 246 DartType elementType = element.type; | 247 DartType elementType = element.type; |
| 247 ConstantValue value = getConstantValue(expression); | 248 ConstantValue value = getConstantValue(expression); |
| 248 if (elementType.isMalformed && !value.isNull) { | 249 if (elementType.isMalformed && !value.isNull) { |
| 249 if (isConst) { | 250 if (isConst) { |
| 250 ErroneousElement element = elementType.element; | 251 ErroneousElement element = elementType.element; |
| 251 compiler.reportError( | 252 compiler.reportErrorMessage( |
| 252 node, element.messageKind, element.messageArguments); | 253 node, element.messageKind, element.messageArguments); |
| 253 } else { | 254 } else { |
| 254 // We need to throw an exception at runtime. | 255 // We need to throw an exception at runtime. |
| 255 expression = null; | 256 expression = null; |
| 256 } | 257 } |
| 257 } else { | 258 } else { |
| 258 DartType constantType = value.getType(compiler.coreTypes); | 259 DartType constantType = value.getType(compiler.coreTypes); |
| 259 if (!constantSystem.isSubtype( | 260 if (!constantSystem.isSubtype( |
| 260 compiler.types, constantType, elementType)) { | 261 compiler.types, constantType, elementType)) { |
| 261 if (isConst) { | 262 if (isConst) { |
| 262 compiler.reportError(node, MessageKind.NOT_ASSIGNABLE, { | 263 compiler.reportErrorMessage( |
| 263 'fromType': constantType, | 264 node, |
| 264 'toType': elementType | 265 MessageKind.NOT_ASSIGNABLE, |
| 265 }); | 266 {'fromType': constantType, |
| 267 'toType': elementType}); |
| 266 } else { | 268 } else { |
| 267 // If the field cannot be lazily initialized, we will throw | 269 // If the field cannot be lazily initialized, we will throw |
| 268 // the exception at runtime. | 270 // the exception at runtime. |
| 269 expression = null; | 271 expression = null; |
| 270 } | 272 } |
| 271 } | 273 } |
| 272 } | 274 } |
| 273 } | 275 } |
| 274 } | 276 } |
| 275 if (expression != null) { | 277 if (expression != null) { |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 if (key == null) { | 441 if (key == null) { |
| 440 return null; | 442 return null; |
| 441 } | 443 } |
| 442 AstConstant value = evaluateConstant(entry.value); | 444 AstConstant value = evaluateConstant(entry.value); |
| 443 if (value == null) { | 445 if (value == null) { |
| 444 return null; | 446 return null; |
| 445 } | 447 } |
| 446 if (!map.containsKey(key.value)) { | 448 if (!map.containsKey(key.value)) { |
| 447 keyValues.add(key.value); | 449 keyValues.add(key.value); |
| 448 } else { | 450 } else { |
| 449 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); | 451 compiler.reportWarningMessage( |
| 452 entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); |
| 450 } | 453 } |
| 451 keyExpressions.add(key.expression); | 454 keyExpressions.add(key.expression); |
| 452 valueExpressions.add(value.expression); | 455 valueExpressions.add(value.expression); |
| 453 map[key.value] = value.value; | 456 map[key.value] = value.value; |
| 454 } | 457 } |
| 455 InterfaceType type = elements.getType(node); | 458 InterfaceType type = elements.getType(node); |
| 456 return new AstConstant(context, node, | 459 return new AstConstant(context, node, |
| 457 new MapConstantExpression(type, keyExpressions, valueExpressions), | 460 new MapConstantExpression(type, keyExpressions, valueExpressions), |
| 458 constantSystem.createMap( | 461 constantSystem.createMap( |
| 459 compiler, type, keyValues, map.values.toList())); | 462 compiler, type, keyValues, map.values.toList())); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 result = new AstConstant(context, send, | 616 result = new AstConstant(context, send, |
| 614 new VariableConstantExpression(element), | 617 new VariableConstantExpression(element), |
| 615 handler.getConstantValue(variableExpression)); | 618 handler.getConstantValue(variableExpression)); |
| 616 } | 619 } |
| 617 } | 620 } |
| 618 if (result == null) { | 621 if (result == null) { |
| 619 return signalNotCompileTimeConstant(send); | 622 return signalNotCompileTimeConstant(send); |
| 620 } | 623 } |
| 621 if (isDeferredUse(send)) { | 624 if (isDeferredUse(send)) { |
| 622 if (isEvaluatingConstant) { | 625 if (isEvaluatingConstant) { |
| 623 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 626 compiler.reportErrorMessage( |
| 627 send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
| 624 } | 628 } |
| 625 PrefixElement prefix = | 629 PrefixElement prefix = |
| 626 compiler.deferredLoadTask.deferredPrefixElement(send, elements); | 630 compiler.deferredLoadTask.deferredPrefixElement(send, elements); |
| 627 result = new AstConstant(context, send, | 631 result = new AstConstant(context, send, |
| 628 new DeferredConstantExpression(result.expression, prefix), | 632 new DeferredConstantExpression(result.expression, prefix), |
| 629 new DeferredConstantValue(result.value, prefix)); | 633 new DeferredConstantValue(result.value, prefix)); |
| 630 compiler.deferredLoadTask.registerConstantDeferredUse( | 634 compiler.deferredLoadTask.registerConstantDeferredUse( |
| 631 result.value, prefix); | 635 result.value, prefix); |
| 632 } | 636 } |
| 633 return result; | 637 return result; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 return signalNotCompileTimeConstant(send); | 716 return signalNotCompileTimeConstant(send); |
| 713 } | 717 } |
| 714 | 718 |
| 715 AstConstant visitConditional(Conditional node) { | 719 AstConstant visitConditional(Conditional node) { |
| 716 AstConstant condition = evaluate(node.condition); | 720 AstConstant condition = evaluate(node.condition); |
| 717 if (condition == null) { | 721 if (condition == null) { |
| 718 return null; | 722 return null; |
| 719 } else if (!condition.value.isBool) { | 723 } else if (!condition.value.isBool) { |
| 720 DartType conditionType = condition.value.getType(compiler.coreTypes); | 724 DartType conditionType = condition.value.getType(compiler.coreTypes); |
| 721 if (isEvaluatingConstant) { | 725 if (isEvaluatingConstant) { |
| 722 compiler.reportError(node.condition, MessageKind.NOT_ASSIGNABLE, { | 726 compiler.reportErrorMessage( |
| 723 'fromType': conditionType, | 727 node.condition, |
| 724 'toType': compiler.boolClass.rawType | 728 MessageKind.NOT_ASSIGNABLE, |
| 725 }); | 729 {'fromType': conditionType, |
| 730 'toType': compiler.boolClass.rawType}); |
| 726 return new ErroneousAstConstant(context, node); | 731 return new ErroneousAstConstant(context, node); |
| 727 } | 732 } |
| 728 return null; | 733 return null; |
| 729 } | 734 } |
| 730 AstConstant thenExpression = evaluate(node.thenExpression); | 735 AstConstant thenExpression = evaluate(node.thenExpression); |
| 731 AstConstant elseExpression = evaluate(node.elseExpression); | 736 AstConstant elseExpression = evaluate(node.elseExpression); |
| 732 if (thenExpression == null || elseExpression == null) { | 737 if (thenExpression == null || elseExpression == null) { |
| 733 return null; | 738 return null; |
| 734 } | 739 } |
| 735 BoolConstantValue boolCondition = condition.value; | 740 BoolConstantValue boolCondition = condition.value; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 760 ConstantExpression constant = handler.compileConstant(element); | 765 ConstantExpression constant = handler.compileConstant(element); |
| 761 return new AstConstant.fromDefaultValue( | 766 return new AstConstant.fromDefaultValue( |
| 762 element, constant, handler.getConstantValue(constant)); | 767 element, constant, handler.getConstantValue(constant)); |
| 763 } | 768 } |
| 764 target.computeType(compiler); | 769 target.computeType(compiler); |
| 765 | 770 |
| 766 FunctionSignature signature = target.functionSignature; | 771 FunctionSignature signature = target.functionSignature; |
| 767 if (!callStructure.signatureApplies(signature)) { | 772 if (!callStructure.signatureApplies(signature)) { |
| 768 String name = Elements.constructorNameForDiagnostics( | 773 String name = Elements.constructorNameForDiagnostics( |
| 769 target.enclosingClass.name, target.name); | 774 target.enclosingClass.name, target.name); |
| 770 compiler.reportError(node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, { | 775 compiler.reportErrorMessage( |
| 771 'constructorName': name | 776 node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, |
| 772 }); | 777 {'constructorName': name}); |
| 773 | 778 |
| 774 return new List<AstConstant>.filled( | 779 return new List<AstConstant>.filled( |
| 775 target.functionSignature.parameterCount, | 780 target.functionSignature.parameterCount, |
| 776 new ErroneousAstConstant(context, node)); | 781 new ErroneousAstConstant(context, node)); |
| 777 } | 782 } |
| 778 return callStructure.makeArgumentsList( | 783 return callStructure.makeArgumentsList( |
| 779 arguments, target, compileArgument, compileDefaultValue); | 784 arguments, target, compileArgument, compileDefaultValue); |
| 780 } | 785 } |
| 781 | 786 |
| 782 AstConstant visitNewExpression(NewExpression node) { | 787 AstConstant visitNewExpression(NewExpression node) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 864 } | 869 } |
| 865 | 870 |
| 866 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type, | 871 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type, |
| 867 ConstructorElement constructor, CallStructure callStructure, | 872 ConstructorElement constructor, CallStructure callStructure, |
| 868 List<AstConstant> normalizedArguments, | 873 List<AstConstant> normalizedArguments, |
| 869 List<AstConstant> concreteArguments) { | 874 List<AstConstant> concreteArguments) { |
| 870 var firstArgument = normalizedArguments[0].value; | 875 var firstArgument = normalizedArguments[0].value; |
| 871 ConstantValue defaultValue = normalizedArguments[1].value; | 876 ConstantValue defaultValue = normalizedArguments[1].value; |
| 872 | 877 |
| 873 if (firstArgument.isNull) { | 878 if (firstArgument.isNull) { |
| 874 compiler.reportError( | 879 compiler.reportErrorMessage( |
| 875 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); | 880 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); |
| 876 return null; | 881 return null; |
| 877 } | 882 } |
| 878 | 883 |
| 879 if (!firstArgument.isString) { | 884 if (!firstArgument.isString) { |
| 880 DartType type = defaultValue.getType(compiler.coreTypes); | 885 DartType type = defaultValue.getType(compiler.coreTypes); |
| 881 compiler.reportError(normalizedArguments[0].node, | 886 compiler.reportErrorMessage( |
| 882 MessageKind.NOT_ASSIGNABLE, { | 887 normalizedArguments[0].node, |
| 883 'fromType': type, | 888 MessageKind.NOT_ASSIGNABLE, |
| 884 'toType': compiler.stringClass.rawType | 889 {'fromType': type, |
| 885 }); | 890 'toType': compiler.stringClass.rawType}); |
| 886 return null; | 891 return null; |
| 887 } | 892 } |
| 888 | 893 |
| 889 if (constructor == compiler.intEnvironment && | 894 if (constructor == compiler.intEnvironment && |
| 890 !(defaultValue.isNull || defaultValue.isInt)) { | 895 !(defaultValue.isNull || defaultValue.isInt)) { |
| 891 DartType type = defaultValue.getType(compiler.coreTypes); | 896 DartType type = defaultValue.getType(compiler.coreTypes); |
| 892 compiler.reportError(normalizedArguments[1].node, | 897 compiler.reportErrorMessage( |
| 893 MessageKind.NOT_ASSIGNABLE, { | 898 normalizedArguments[1].node, |
| 894 'fromType': type, | 899 MessageKind.NOT_ASSIGNABLE, |
| 895 'toType': compiler.intClass.rawType | 900 {'fromType': type, |
| 896 }); | 901 'toType': compiler.intClass.rawType}); |
| 897 return null; | 902 return null; |
| 898 } | 903 } |
| 899 | 904 |
| 900 if (constructor == compiler.boolEnvironment && | 905 if (constructor == compiler.boolEnvironment && |
| 901 !(defaultValue.isNull || defaultValue.isBool)) { | 906 !(defaultValue.isNull || defaultValue.isBool)) { |
| 902 DartType type = defaultValue.getType(compiler.coreTypes); | 907 DartType type = defaultValue.getType(compiler.coreTypes); |
| 903 compiler.reportError(normalizedArguments[1].node, | 908 compiler.reportErrorMessage( |
| 904 MessageKind.NOT_ASSIGNABLE, { | 909 normalizedArguments[1].node, |
| 905 'fromType': type, | 910 MessageKind.NOT_ASSIGNABLE, |
| 906 'toType': compiler.boolClass.rawType | 911 {'fromType': type, |
| 907 }); | 912 'toType': compiler.boolClass.rawType}); |
| 908 return null; | 913 return null; |
| 909 } | 914 } |
| 910 | 915 |
| 911 if (constructor == compiler.stringEnvironment && | 916 if (constructor == compiler.stringEnvironment && |
| 912 !(defaultValue.isNull || defaultValue.isString)) { | 917 !(defaultValue.isNull || defaultValue.isString)) { |
| 913 DartType type = defaultValue.getType(compiler.coreTypes); | 918 DartType type = defaultValue.getType(compiler.coreTypes); |
| 914 compiler.reportError(normalizedArguments[1].node, | 919 compiler.reportErrorMessage( |
| 915 MessageKind.NOT_ASSIGNABLE, { | 920 normalizedArguments[1].node, |
| 916 'fromType': type, | 921 MessageKind.NOT_ASSIGNABLE, |
| 917 'toType': compiler.stringClass.rawType | 922 {'fromType': type, |
| 918 }); | 923 'toType': compiler.stringClass.rawType}); |
| 919 return null; | 924 return null; |
| 920 } | 925 } |
| 921 | 926 |
| 922 String name = firstArgument.primitiveValue.slowToString(); | 927 String name = firstArgument.primitiveValue.slowToString(); |
| 923 String value = compiler.fromEnvironment(name); | 928 String value = compiler.fromEnvironment(name); |
| 924 | 929 |
| 925 AstConstant createEvaluatedConstant(ConstantValue value) { | 930 AstConstant createEvaluatedConstant(ConstantValue value) { |
| 926 ConstantExpression expression; | 931 ConstantExpression expression; |
| 927 ConstantExpression name = concreteArguments[0].expression; | 932 ConstantExpression name = concreteArguments[0].expression; |
| 928 ConstantExpression defaultValue; | 933 ConstantExpression defaultValue; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 995 return new AstConstant(context, node, new ConstructedConstantExpression( | 1000 return new AstConstant(context, node, new ConstructedConstantExpression( |
| 996 type, constructor, callStructure, | 1001 type, constructor, callStructure, |
| 997 concreteArguments.map((e) => e.expression).toList()), | 1002 concreteArguments.map((e) => e.expression).toList()), |
| 998 new ConstructedConstantValue(constructedType, fieldValues)); | 1003 new ConstructedConstantValue(constructedType, fieldValues)); |
| 999 } | 1004 } |
| 1000 | 1005 |
| 1001 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { | 1006 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1002 return node.expression.accept(this); | 1007 return node.expression.accept(this); |
| 1003 } | 1008 } |
| 1004 | 1009 |
| 1005 error(Node node, MessageKind message) { | |
| 1006 // TODO(floitsch): get the list of constants that are currently compiled | |
| 1007 // and present some kind of stack-trace. | |
| 1008 compiler.reportError(node, message); | |
| 1009 } | |
| 1010 | |
| 1011 AstConstant signalNotCompileTimeConstant(Node node, | 1010 AstConstant signalNotCompileTimeConstant(Node node, |
| 1012 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { | 1011 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { |
| 1013 if (isEvaluatingConstant) { | 1012 if (isEvaluatingConstant) { |
| 1014 error(node, message); | 1013 compiler.reportErrorMessage(node, message); |
| 1015 | 1014 |
| 1016 return new AstConstant(context, node, new ErroneousConstantExpression(), | 1015 return new AstConstant(context, node, new ErroneousConstantExpression(), |
| 1017 new NullConstantValue()); | 1016 new NullConstantValue()); |
| 1018 } | 1017 } |
| 1019 // Else we don't need to do anything. The final handler is only | 1018 // Else we don't need to do anything. The final handler is only |
| 1020 // optimistically trying to compile constants. So it is normal that we | 1019 // optimistically trying to compile constants. So it is normal that we |
| 1021 // sometimes see non-compile time constants. | 1020 // sometimes see non-compile time constants. |
| 1022 // Simply return [:null:] which is used to propagate a failing | 1021 // Simply return [:null:] which is used to propagate a failing |
| 1023 // compile-time compilation. | 1022 // compile-time compilation. |
| 1024 return null; | 1023 return null; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 return super.visitSend(send); | 1057 return super.visitSend(send); |
| 1059 } | 1058 } |
| 1060 | 1059 |
| 1061 void potentiallyCheckType(TypedElement element, AstConstant constant) { | 1060 void potentiallyCheckType(TypedElement element, AstConstant constant) { |
| 1062 if (compiler.enableTypeAssertions) { | 1061 if (compiler.enableTypeAssertions) { |
| 1063 DartType elementType = element.type.substByContext(constructedType); | 1062 DartType elementType = element.type.substByContext(constructedType); |
| 1064 DartType constantType = constant.value.getType(compiler.coreTypes); | 1063 DartType constantType = constant.value.getType(compiler.coreTypes); |
| 1065 if (!constantSystem.isSubtype( | 1064 if (!constantSystem.isSubtype( |
| 1066 compiler.types, constantType, elementType)) { | 1065 compiler.types, constantType, elementType)) { |
| 1067 compiler.withCurrentElement(constant.element, () { | 1066 compiler.withCurrentElement(constant.element, () { |
| 1068 compiler.reportError(constant.node, MessageKind.NOT_ASSIGNABLE, { | 1067 compiler.reportErrorMessage( |
| 1069 'fromType': constantType, | 1068 constant.node, |
| 1070 'toType': elementType | 1069 MessageKind.NOT_ASSIGNABLE, |
| 1071 }); | 1070 {'fromType': constantType, |
| 1071 'toType': elementType}); |
| 1072 }); | 1072 }); |
| 1073 } | 1073 } |
| 1074 } | 1074 } |
| 1075 } | 1075 } |
| 1076 | 1076 |
| 1077 void updateFieldValue(Node node, TypedElement element, AstConstant constant) { | 1077 void updateFieldValue(Node node, TypedElement element, AstConstant constant) { |
| 1078 potentiallyCheckType(element, constant); | 1078 potentiallyCheckType(element, constant); |
| 1079 fieldValues[element] = constant; | 1079 fieldValues[element] = constant; |
| 1080 } | 1080 } |
| 1081 | 1081 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 class _CompilerEnvironment implements Environment { | 1266 class _CompilerEnvironment implements Environment { |
| 1267 final Compiler compiler; | 1267 final Compiler compiler; |
| 1268 | 1268 |
| 1269 _CompilerEnvironment(this.compiler); | 1269 _CompilerEnvironment(this.compiler); |
| 1270 | 1270 |
| 1271 @override | 1271 @override |
| 1272 String readFromEnvironment(String name) { | 1272 String readFromEnvironment(String name) { |
| 1273 return compiler.fromEnvironment(name); | 1273 return compiler.fromEnvironment(name); |
| 1274 } | 1274 } |
| 1275 } | 1275 } |
| OLD | NEW |