| 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.dart'; | 7 import 'common.dart'; |
| 8 import 'common/resolution.dart' show | 8 import 'common/resolution.dart' show |
| 9 Resolution; | 9 Resolution; |
| 10 import 'common/tasks.dart' show | 10 import 'common/tasks.dart' show |
| 11 CompilerTask; | 11 CompilerTask; |
| 12 import 'compiler.dart' show | 12 import 'compiler.dart' show |
| 13 Compiler; | 13 Compiler; |
| 14 import 'constant_system_dart.dart'; | 14 import 'constant_system_dart.dart'; |
| 15 import 'constants/constant_system.dart'; | 15 import 'constants/constant_system.dart'; |
| 16 import 'constants/constructors.dart'; |
| 16 import 'constants/evaluation.dart'; | 17 import 'constants/evaluation.dart'; |
| 17 import 'constants/expressions.dart'; | 18 import 'constants/expressions.dart'; |
| 18 import 'constants/values.dart'; | 19 import 'constants/values.dart'; |
| 20 import 'core_types.dart'; |
| 19 import 'dart_types.dart'; | 21 import 'dart_types.dart'; |
| 20 import 'elements/elements.dart'; | 22 import 'elements/elements.dart'; |
| 21 import 'elements/modelx.dart' show | 23 import 'elements/modelx.dart' show |
| 22 FunctionElementX; | 24 FunctionElementX; |
| 25 import 'enqueue.dart' show |
| 26 WorldImpact; |
| 23 import 'resolution/tree_elements.dart' show | 27 import 'resolution/tree_elements.dart' show |
| 24 TreeElements; | 28 TreeElements; |
| 25 import 'resolution/operators.dart'; | 29 import 'resolution/operators.dart'; |
| 26 import 'tree/tree.dart'; | 30 import 'tree/tree.dart'; |
| 27 import 'util/util.dart' show | 31 import 'util/util.dart' show |
| 28 Link; | 32 Link; |
| 29 import 'universe/call_structure.dart' show | 33 import 'universe/call_structure.dart' show |
| 30 CallStructure; | 34 CallStructure; |
| 31 | 35 |
| 32 /// A [ConstantEnvironment] provides access for constants compiled for variable | 36 /// A [ConstantEnvironment] provides access for constants compiled for variable |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 /// Depending on implementation, the constant compiler might also compute | 88 /// Depending on implementation, the constant compiler might also compute |
| 85 /// the compile-time constant for the backend interpretation of constants. | 89 /// the compile-time constant for the backend interpretation of constants. |
| 86 /// | 90 /// |
| 87 /// The returned constant is always of the frontend interpretation. | 91 /// The returned constant is always of the frontend interpretation. |
| 88 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 92 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
| 89 Node node, | 93 Node node, |
| 90 TreeElements elements); | 94 TreeElements elements); |
| 91 | 95 |
| 92 /// Evaluates [constant] and caches the result. | 96 /// Evaluates [constant] and caches the result. |
| 93 // TODO(johnniwinther): Remove when all constants are evaluated. | 97 // TODO(johnniwinther): Remove when all constants are evaluated. |
| 94 void evaluate(ConstantExpression constant); | 98 void evaluate(Spannable spannable, ConstantExpression constant); |
| 95 } | 99 } |
| 96 | 100 |
| 97 /// A [BackendConstantEnvironment] provides access to constants needed for | 101 /// A [BackendConstantEnvironment] provides access to constants needed for |
| 98 /// backend implementation. | 102 /// backend implementation. |
| 99 abstract class BackendConstantEnvironment extends ConstantEnvironment { | 103 abstract class BackendConstantEnvironment extends ConstantEnvironment { |
| 100 /// Returns the compile-time constant value associated with [node]. | 104 /// Returns the compile-time constant value associated with [node]. |
| 101 /// | 105 /// |
| 102 /// Depending on implementation, the constant might be stored in [elements]. | 106 /// Depending on implementation, the constant might be stored in [elements]. |
| 103 ConstantValue getConstantValueForNode(Node node, TreeElements elements); | 107 ConstantValue getConstantValueForNode(Node node, TreeElements elements); |
| 104 | 108 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 @override | 172 @override |
| 169 ConstantExpression getConstantForVariable(VariableElement element) { | 173 ConstantExpression getConstantForVariable(VariableElement element) { |
| 170 return initialVariableValues[element.declaration]; | 174 return initialVariableValues[element.declaration]; |
| 171 } | 175 } |
| 172 | 176 |
| 173 ConstantExpression compileConstant(VariableElement element) { | 177 ConstantExpression compileConstant(VariableElement element) { |
| 174 return internalCompileVariable(element, true, true); | 178 return internalCompileVariable(element, true, true); |
| 175 } | 179 } |
| 176 | 180 |
| 177 @override | 181 @override |
| 178 void evaluate(ConstantExpression constant) { | 182 void evaluate(Spannable spannable, ConstantExpression constant) { |
| 179 constantValueMap.putIfAbsent(constant, () { | 183 constantValueMap.putIfAbsent(constant, () { |
| 180 return constant.evaluate( | 184 return constant.evaluate( |
| 181 new _CompilerEnvironment(compiler), | 185 new CompilerEnvironment(compiler, spannable), |
| 182 constantSystem); | 186 constantSystem); |
| 183 }); | 187 }); |
| 184 } | 188 } |
| 185 | 189 |
| 186 ConstantExpression compileVariable(VariableElement element) { | 190 ConstantExpression compileVariable(VariableElement element) { |
| 187 return internalCompileVariable(element, false, true); | 191 return internalCompileVariable(element, false, true); |
| 188 } | 192 } |
| 189 | 193 |
| 190 /// Compile [element] into a constant expression. If [isConst] is true, | 194 /// Compile [element] into a constant expression. If [isConst] is true, |
| 191 /// then [element] is a constant variable. If [checkType] is true, then | 195 /// then [element] is a constant variable. If [checkType] is true, then |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 return expression; | 287 return expression; |
| 284 } | 288 } |
| 285 | 289 |
| 286 void cacheConstantValue(ConstantExpression expression, ConstantValue value) { | 290 void cacheConstantValue(ConstantExpression expression, ConstantValue value) { |
| 287 constantValueMap[expression] = value; | 291 constantValueMap[expression] = value; |
| 288 } | 292 } |
| 289 | 293 |
| 290 ConstantExpression compileNodeWithDefinitions( | 294 ConstantExpression compileNodeWithDefinitions( |
| 291 Node node, TreeElements definitions, {bool isConst: true}) { | 295 Node node, TreeElements definitions, {bool isConst: true}) { |
| 292 assert(node != null); | 296 assert(node != null); |
| 297 ConstantExpression constantExpression = definitions.getConstant(node); |
| 298 if (constantExpression != null) { |
| 299 constantValueMap.putIfAbsent(constantExpression, () { |
| 300 return constantExpression.evaluate( |
| 301 new CompilerEnvironment(compiler, node), constantSystem); |
| 302 }); |
| 303 return constantExpression; |
| 304 } |
| 293 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 305 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 294 this, definitions, compiler, isConst: isConst); | 306 this, definitions, compiler, isConst: isConst); |
| 295 AstConstant constant = evaluator.evaluate(node); | 307 AstConstant constant = evaluator.evaluate(node); |
| 296 if (constant != null) { | 308 if (constant != null) { |
| 297 cacheConstantValue(constant.expression, constant.value); | 309 cacheConstantValue(constant.expression, constant.value); |
| 298 return constant.expression; | 310 return constant.expression; |
| 299 } | 311 } |
| 300 return null; | 312 return null; |
| 313 /* |
| 314 if (constantExpression == null) { |
| 315 compiler.internalError(node, "No constant computed for $node."); |
| 316 } |
| 317 constantValueMap.putIfAbsent( |
| 318 constantExpression, () { |
| 319 return constantExpression.evaluate( |
| 320 new CompilerEnvironment(compiler, node), constantSystem); |
| 321 }); |
| 322 return constantExpression;*/ |
| 301 } | 323 } |
| 302 | 324 |
| 303 ConstantValue getConstantValue(ConstantExpression expression) { | 325 ConstantValue getConstantValue(ConstantExpression expression) { |
| 304 return constantValueMap[expression]; | 326 return constantValueMap[expression]; |
| 305 } | 327 } |
| 306 | 328 |
| 307 ConstantExpression compileNode(Node node, TreeElements elements, | 329 ConstantExpression compileNode(Node node, TreeElements elements, |
| 308 {bool enforceConst: true}) { | 330 {bool enforceConst: true}) { |
| 309 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); | 331 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); |
| 310 } | 332 } |
| 311 | 333 |
| 312 ConstantExpression compileMetadata( | 334 ConstantExpression compileMetadata( |
| 313 MetadataAnnotation metadata, Node node, TreeElements elements) { | 335 MetadataAnnotation metadata, Node node, TreeElements elements) { |
| 314 return compileNodeWithDefinitions(node, elements); | 336 return compileNodeWithDefinitions(node, elements); |
| 315 } | 337 } |
| 316 | 338 |
| 317 void forgetElement(Element element) { | 339 void forgetElement(Element element) { |
| 318 initialVariableValues.remove(element); | 340 initialVariableValues.remove(element); |
| 319 if (element is ScopeContainerElement) { | 341 if (element is ScopeContainerElement) { |
| 320 element.forEachLocalMember(initialVariableValues.remove); | 342 element.forEachLocalMember(initialVariableValues.remove); |
| 321 } | 343 } |
| 322 if (element is FunctionElement && element.hasFunctionSignature) { | 344 if (element is FunctionElement && element.hasFunctionSignature) { |
| 323 element.functionSignature.forEachParameter(this.forgetElement); | 345 element.functionSignature.forEachParameter(this.forgetElement); |
| 324 } | 346 } |
| 325 } | 347 } |
| 326 } | 348 } |
| 327 | 349 |
| 350 class CompilerEnvironment implements Environment { |
| 351 final Compiler compiler; |
| 352 final Spannable spannable; |
| 353 final Set<VariableElement> evaluatingVariables = new Set<VariableElement>(); |
| 354 final Set<ConstructorElement> evaluatingConstructors = |
| 355 new Set<ConstructorElement>(); |
| 356 |
| 357 CompilerEnvironment(this.compiler, this.spannable); |
| 358 |
| 359 @override |
| 360 CoreTypes get coreTypes => compiler.coreTypes; |
| 361 |
| 362 @override |
| 363 String readFromEnvironment(String name) => compiler.fromEnvironment(name); |
| 364 |
| 365 @override |
| 366 void reportWarning(ConstantExpression expression, |
| 367 MessageKind kind, |
| 368 Map arguments) { |
| 369 compiler.reporter.reportWarningMessage(spannable, kind, arguments); |
| 370 } |
| 371 |
| 372 @override |
| 373 void reportError(ConstantExpression expression, |
| 374 MessageKind kind, |
| 375 Map arguments) { |
| 376 compiler.reporter.reportErrorMessage(spannable, kind, arguments); |
| 377 } |
| 378 |
| 379 @override |
| 380 ConstantValue evaluateConstructor( |
| 381 ConstructorElement constructor, |
| 382 ConstantValue evaluate()) { |
| 383 if (evaluatingConstructors.contains(constructor)) { |
| 384 return new NonConstantValue(); |
| 385 } |
| 386 ConstructorElement parentConstructor = constructor; |
| 387 while (parentConstructor != null) { |
| 388 _analyzeElementEagerly(compiler, parentConstructor); |
| 389 ConstantConstructor constantConstructor = |
| 390 parentConstructor.constantConstructor; |
| 391 assert(invariant(parentConstructor, constantConstructor != null, |
| 392 message: "No constant constructor on ${parentConstructor}.")); |
| 393 parentConstructor = constantConstructor.parentConstructor; |
| 394 } |
| 395 evaluatingConstructors.add(constructor); |
| 396 ConstantValue value = evaluate(); |
| 397 evaluatingConstructors.remove(constructor); |
| 398 return value; |
| 399 } |
| 400 |
| 401 @override |
| 402 ConstantValue evaluateVariable( |
| 403 VariableElement variable, |
| 404 ConstantValue evaluate()) { |
| 405 if (evaluatingVariables.contains(variable)) { |
| 406 return new NonConstantValue(); |
| 407 } |
| 408 if (!variable.isLocal) { |
| 409 _analyzeElementEagerly(compiler, variable); |
| 410 } |
| 411 evaluatingVariables.add(variable); |
| 412 ConstantValue value = evaluate(); |
| 413 evaluatingVariables.remove(variable); |
| 414 return value; |
| 415 } |
| 416 } |
| 417 |
| 328 /// [ConstantCompiler] that uses the Dart semantics for the compile-time | 418 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
| 329 /// constant evaluation. | 419 /// constant evaluation. |
| 330 class DartConstantCompiler extends ConstantCompilerBase { | 420 class DartConstantCompiler extends ConstantCompilerBase { |
| 331 DartConstantCompiler(Compiler compiler) | 421 DartConstantCompiler(Compiler compiler) |
| 332 : super(compiler, const DartConstantSystem()); | 422 : super(compiler, const DartConstantSystem()); |
| 333 | 423 |
| 334 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { | 424 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { |
| 335 return definitions.getConstant(node); | 425 return definitions.getConstant(node); |
| 336 } | 426 } |
| 337 | 427 |
| (...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 return makeConstructedConstant(compiler, handler, context, node, type, | 957 return makeConstructedConstant(compiler, handler, context, node, type, |
| 868 constructor, constructedType, implementation, callStructure, | 958 constructor, constructedType, implementation, callStructure, |
| 869 concreteArguments, normalizedArguments); | 959 concreteArguments, normalizedArguments); |
| 870 } | 960 } |
| 871 } | 961 } |
| 872 | 962 |
| 873 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type, | 963 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type, |
| 874 ConstructorElement constructor, CallStructure callStructure, | 964 ConstructorElement constructor, CallStructure callStructure, |
| 875 List<AstConstant> normalizedArguments, | 965 List<AstConstant> normalizedArguments, |
| 876 List<AstConstant> concreteArguments) { | 966 List<AstConstant> concreteArguments) { |
| 877 var firstArgument = normalizedArguments[0].value; | 967 |
| 968 ConstantValue firstArgument = normalizedArguments[0].value; |
| 878 ConstantValue defaultValue = normalizedArguments[1].value; | 969 ConstantValue defaultValue = normalizedArguments[1].value; |
| 879 | 970 |
| 880 if (firstArgument.isNull) { | 971 if (firstArgument.isNull) { |
| 881 reporter.reportErrorMessage( | 972 reporter.reportErrorMessage( |
| 882 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); | 973 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); |
| 883 return null; | 974 return null; |
| 884 } | 975 } |
| 885 | 976 |
| 886 if (!firstArgument.isString) { | 977 if (!firstArgument.isString) { |
| 887 DartType type = defaultValue.getType(compiler.coreTypes); | 978 DartType type = firstArgument.getType(compiler.coreTypes); |
| 888 reporter.reportErrorMessage( | 979 reporter.reportErrorMessage( |
| 889 normalizedArguments[0].node, | 980 normalizedArguments[0].node, |
| 890 MessageKind.NOT_ASSIGNABLE, | 981 MessageKind.NOT_ASSIGNABLE, |
| 891 {'fromType': type, | 982 {'fromType': type, |
| 892 'toType': compiler.stringClass.rawType}); | 983 'toType': compiler.stringClass.rawType}); |
| 893 return null; | 984 return null; |
| 894 } | 985 } |
| 895 | 986 |
| 896 if (constructor == compiler.intEnvironment && | 987 if (constructor == compiler.intEnvironment && |
| 897 !(defaultValue.isNull || defaultValue.isInt)) { | 988 !(defaultValue.isNull || defaultValue.isInt)) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 919 !(defaultValue.isNull || defaultValue.isString)) { | 1010 !(defaultValue.isNull || defaultValue.isString)) { |
| 920 DartType type = defaultValue.getType(compiler.coreTypes); | 1011 DartType type = defaultValue.getType(compiler.coreTypes); |
| 921 reporter.reportErrorMessage( | 1012 reporter.reportErrorMessage( |
| 922 normalizedArguments[1].node, | 1013 normalizedArguments[1].node, |
| 923 MessageKind.NOT_ASSIGNABLE, | 1014 MessageKind.NOT_ASSIGNABLE, |
| 924 {'fromType': type, | 1015 {'fromType': type, |
| 925 'toType': compiler.stringClass.rawType}); | 1016 'toType': compiler.stringClass.rawType}); |
| 926 return null; | 1017 return null; |
| 927 } | 1018 } |
| 928 | 1019 |
| 929 String name = firstArgument.primitiveValue.slowToString(); | 1020 PrimitiveConstantValue nameArgument = firstArgument; |
| 1021 String name = nameArgument.primitiveValue.slowToString(); |
| 930 String value = compiler.fromEnvironment(name); | 1022 String value = compiler.fromEnvironment(name); |
| 931 | 1023 |
| 932 AstConstant createEvaluatedConstant(ConstantValue value) { | 1024 AstConstant createEvaluatedConstant(ConstantValue value) { |
| 933 ConstantExpression expression; | 1025 ConstantExpression expression; |
| 934 ConstantExpression name = concreteArguments[0].expression; | 1026 ConstantExpression name = concreteArguments[0].expression; |
| 935 ConstantExpression defaultValue; | 1027 ConstantExpression defaultValue; |
| 936 if (concreteArguments.length > 1) { | 1028 if (concreteArguments.length > 1) { |
| 937 defaultValue = concreteArguments[1].expression; | 1029 defaultValue = concreteArguments[1].expression; |
| 938 } | 1030 } |
| 939 if (constructor == compiler.intEnvironment) { | 1031 if (constructor == compiler.intEnvironment) { |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1256 ErroneousAstConstant(Element element, Node node) : super(element, node, | 1348 ErroneousAstConstant(Element element, Node node) : super(element, node, |
| 1257 // TODO(johnniwinther): Return a [NonConstantValue] instead. | 1349 // TODO(johnniwinther): Return a [NonConstantValue] instead. |
| 1258 new ErroneousConstantExpression(), new NullConstantValue()); | 1350 new ErroneousConstantExpression(), new NullConstantValue()); |
| 1259 } | 1351 } |
| 1260 | 1352 |
| 1261 // TODO(johnniwinther): Clean this up. | 1353 // TODO(johnniwinther): Clean this up. |
| 1262 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { | 1354 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { |
| 1263 compiler.resolution.analyzeElement(element.declaration); | 1355 compiler.resolution.analyzeElement(element.declaration); |
| 1264 return element.resolvedAst.elements; | 1356 return element.resolvedAst.elements; |
| 1265 } | 1357 } |
| 1266 | |
| 1267 class _CompilerEnvironment implements Environment { | |
| 1268 final Compiler compiler; | |
| 1269 | |
| 1270 _CompilerEnvironment(this.compiler); | |
| 1271 | |
| 1272 @override | |
| 1273 String readFromEnvironment(String name) { | |
| 1274 return compiler.fromEnvironment(name); | |
| 1275 } | |
| 1276 } | |
| OLD | NEW |