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 |