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 |