| 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 'constant_system_dart.dart'; | 7 import 'constant_system_dart.dart'; |
| 8 import 'constants/constant_system.dart'; | 8 import 'constants/constant_system.dart'; |
| 9 import 'constants/expressions.dart'; | 9 import 'constants/expressions.dart'; |
| 10 import 'constants/values.dart'; | 10 import 'constants/values.dart'; |
| 11 import 'dart_types.dart'; | 11 import 'dart_types.dart'; |
| 12 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact,
invariant; | 12 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact,
invariant; |
| 13 import 'elements/elements.dart'; | 13 import 'elements/elements.dart'; |
| 14 import 'elements/modelx.dart' show FunctionElementX; | 14 import 'elements/modelx.dart' show FunctionElementX; |
| 15 import 'helpers/helpers.dart'; | 15 import 'helpers/helpers.dart'; |
| 16 import 'resolution/resolution.dart'; | 16 import 'resolution/resolution.dart'; |
| 17 import 'resolution/operators.dart'; | 17 import 'resolution/operators.dart'; |
| 18 import 'tree/tree.dart'; | 18 import 'tree/tree.dart'; |
| 19 import 'util/util.dart' show Link; | 19 import 'util/util.dart' show Link; |
| 20 import 'universe/universe.dart' show CallStructure; | 20 import 'universe/universe.dart' show CallStructure; |
| 21 | 21 |
| 22 /// A [ConstantEnvironment] provides access for constants compiled for variable | 22 /// A [ConstantEnvironment] provides access for constants compiled for variable |
| 23 /// initializers. | 23 /// initializers. |
| 24 abstract class ConstantEnvironment { | 24 abstract class ConstantEnvironment { |
| 25 /// The [ConstantSystem] used by this environment. |
| 26 ConstantSystem get constantSystem; |
| 27 |
| 28 /// Returns the constant value computed for [expression]. |
| 29 // TODO(johnniwinther): Support directly evaluation of [expression]. |
| 30 ConstantValue getConstantValue(ConstantExpression expression); |
| 31 |
| 32 /// Returns the constant value for the initializer of [element]. |
| 33 ConstantValue getConstantValueForVariable(VariableElement element); |
| 34 |
| 25 /// Returns the constant for the initializer of [element]. | 35 /// Returns the constant for the initializer of [element]. |
| 26 ConstantExpression getConstantForVariable(VariableElement element); | 36 ConstantExpression getConstantForVariable(VariableElement element); |
| 27 } | 37 } |
| 28 | 38 |
| 29 /// A class that can compile and provide constants for variables, nodes and | 39 /// A class that can compile and provide constants for variables, nodes and |
| 30 /// metadata. | 40 /// metadata. |
| 31 abstract class ConstantCompiler extends ConstantEnvironment { | 41 abstract class ConstantCompiler extends ConstantEnvironment { |
| 32 /// Compiles the compile-time constant for the initializer of [element], or | 42 /// Compiles the compile-time constant for the initializer of [element], or |
| 33 /// reports an error if the initializer is not a compile-time constant. | 43 /// reports an error if the initializer is not a compile-time constant. |
| 34 /// | 44 /// |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 /// | 76 /// |
| 67 /// The returned constant is always of the frontend interpretation. | 77 /// The returned constant is always of the frontend interpretation. |
| 68 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 78 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
| 69 Node node, | 79 Node node, |
| 70 TreeElements elements); | 80 TreeElements elements); |
| 71 } | 81 } |
| 72 | 82 |
| 73 /// A [BackendConstantEnvironment] provides access to constants needed for | 83 /// A [BackendConstantEnvironment] provides access to constants needed for |
| 74 /// backend implementation. | 84 /// backend implementation. |
| 75 abstract class BackendConstantEnvironment extends ConstantEnvironment { | 85 abstract class BackendConstantEnvironment extends ConstantEnvironment { |
| 86 /// Returns the compile-time constant value associated with [node]. |
| 87 /// |
| 88 /// Depending on implementation, the constant might be stored in [elements]. |
| 89 ConstantValue getConstantValueForNode(Node node, TreeElements elements); |
| 90 |
| 76 /// Returns the compile-time constant associated with [node]. | 91 /// Returns the compile-time constant associated with [node]. |
| 77 /// | 92 /// |
| 78 /// Depending on implementation, the constant might be stored in [elements]. | 93 /// Depending on implementation, the constant might be stored in [elements]. |
| 79 ConstantExpression getConstantForNode(Node node, TreeElements elements); | 94 ConstantExpression getConstantForNode(Node node, TreeElements elements); |
| 80 | 95 |
| 81 /// Returns the compile-time constant value of [metadata]. | 96 /// Returns the compile-time constant value of [metadata]. |
| 82 ConstantExpression getConstantForMetadata(MetadataAnnotation metadata); | 97 ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata); |
| 83 } | 98 } |
| 84 | 99 |
| 85 /// Interface for the task that compiles the constant environments for the | 100 /// Interface for the task that compiles the constant environments for the |
| 86 /// frontend and backend interpretation of compile-time constants. | 101 /// frontend and backend interpretation of compile-time constants. |
| 87 abstract class ConstantCompilerTask extends CompilerTask | 102 abstract class ConstantCompilerTask extends CompilerTask |
| 88 implements ConstantCompiler { | 103 implements ConstantCompiler { |
| 89 ConstantCompilerTask(Compiler compiler) : super(compiler); | 104 ConstantCompilerTask(Compiler compiler) : super(compiler); |
| 105 |
| 106 /// Copy all cached constant values from [task]. |
| 107 /// |
| 108 /// This is a hack to support reuse cached compilers in memory_compiler. |
| 109 // TODO(johnniwinther): Remove this when values are computed from the |
| 110 // expressions. |
| 111 void copyConstantValues(ConstantCompilerTask task); |
| 90 } | 112 } |
| 91 | 113 |
| 92 /** | 114 /** |
| 93 * The [ConstantCompilerBase] is provides base implementation for compilation of | 115 * The [ConstantCompilerBase] is provides base implementation for compilation of |
| 94 * compile-time constants for both the Dart and JavaScript interpretation of | 116 * compile-time constants for both the Dart and JavaScript interpretation of |
| 95 * constants. It keeps track of compile-time constants for initializations of | 117 * constants. It keeps track of compile-time constants for initializations of |
| 96 * global and static fields, and default values of optional parameters. | 118 * global and static fields, and default values of optional parameters. |
| 97 */ | 119 */ |
| 98 abstract class ConstantCompilerBase implements ConstantCompiler { | 120 abstract class ConstantCompilerBase implements ConstantCompiler { |
| 99 final Compiler compiler; | 121 final Compiler compiler; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 110 * May contain default parameter values of optional arguments. | 132 * May contain default parameter values of optional arguments. |
| 111 * | 133 * |
| 112 * Invariant: The keys in this map are declarations. | 134 * Invariant: The keys in this map are declarations. |
| 113 */ | 135 */ |
| 114 final Map<VariableElement, ConstantExpression> initialVariableValues = | 136 final Map<VariableElement, ConstantExpression> initialVariableValues = |
| 115 new Map<VariableElement, ConstantExpression>(); | 137 new Map<VariableElement, ConstantExpression>(); |
| 116 | 138 |
| 117 /** The set of variable elements that are in the process of being computed. */ | 139 /** The set of variable elements that are in the process of being computed. */ |
| 118 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); | 140 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); |
| 119 | 141 |
| 142 final Map<ConstantExpression, ConstantValue> constantValueMap = |
| 143 <ConstantExpression, ConstantValue>{}; |
| 144 |
| 120 ConstantCompilerBase(this.compiler, this.constantSystem); | 145 ConstantCompilerBase(this.compiler, this.constantSystem); |
| 121 | 146 |
| 147 @override |
| 148 ConstantValue getConstantValueForVariable(VariableElement element) { |
| 149 return getConstantValue(initialVariableValues[element.declaration]); |
| 150 } |
| 151 |
| 152 @override |
| 122 ConstantExpression getConstantForVariable(VariableElement element) { | 153 ConstantExpression getConstantForVariable(VariableElement element) { |
| 123 return initialVariableValues[element.declaration]; | 154 return initialVariableValues[element.declaration]; |
| 124 } | 155 } |
| 125 | 156 |
| 126 ConstantExpression compileConstant(VariableElement element) { | 157 ConstantExpression compileConstant(VariableElement element) { |
| 127 return compileVariable(element, isConst: true); | 158 return compileVariable(element, isConst: true); |
| 128 } | 159 } |
| 129 | 160 |
| 130 ConstantExpression compileVariable(VariableElement element, | 161 ConstantExpression compileVariable(VariableElement element, |
| 131 {bool isConst: false}) { | 162 {bool isConst: false}) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 152 * error. | 183 * error. |
| 153 */ | 184 */ |
| 154 ConstantExpression compileVariableWithDefinitions(VariableElement element, | 185 ConstantExpression compileVariableWithDefinitions(VariableElement element, |
| 155 TreeElements definitions, | 186 TreeElements definitions, |
| 156 {bool isConst: false}) { | 187 {bool isConst: false}) { |
| 157 Node node = element.node; | 188 Node node = element.node; |
| 158 if (pendingVariables.contains(element)) { | 189 if (pendingVariables.contains(element)) { |
| 159 if (isConst) { | 190 if (isConst) { |
| 160 compiler.reportError( | 191 compiler.reportError( |
| 161 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | 192 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 162 return new ErroneousConstantExpression(); | 193 ConstantExpression expression = new ErroneousConstantExpression(); |
| 194 constantValueMap[expression] = constantSystem.createNull(); |
| 195 return expression; |
| 163 } | 196 } |
| 164 return null; | 197 return null; |
| 165 } | 198 } |
| 166 pendingVariables.add(element); | 199 pendingVariables.add(element); |
| 167 | 200 |
| 168 Expression initializer = element.initializer; | 201 Expression initializer = element.initializer; |
| 169 ConstantExpression value; | 202 ConstantExpression expression; |
| 170 if (initializer == null) { | 203 if (initializer == null) { |
| 171 // No initial value. | 204 // No initial value. |
| 172 value = new NullConstantExpression(new NullConstantValue()); | 205 expression = new NullConstantExpression(); |
| 206 constantValueMap[expression] = constantSystem.createNull(); |
| 173 } else { | 207 } else { |
| 174 value = compileNodeWithDefinitions( | 208 expression = compileNodeWithDefinitions( |
| 175 initializer, definitions, isConst: isConst); | 209 initializer, definitions, isConst: isConst); |
| 176 if (compiler.enableTypeAssertions && | 210 if (compiler.enableTypeAssertions && |
| 177 value != null && | 211 expression != null && |
| 178 element.isField) { | 212 element.isField) { |
| 179 DartType elementType = element.type; | 213 DartType elementType = element.type; |
| 180 if (elementType.isMalformed && !value.value.isNull) { | 214 ConstantValue value = getConstantValue(expression); |
| 215 if (elementType.isMalformed && !value.isNull) { |
| 181 if (isConst) { | 216 if (isConst) { |
| 182 ErroneousElement element = elementType.element; | 217 ErroneousElement element = elementType.element; |
| 183 compiler.reportError( | 218 compiler.reportError( |
| 184 node, element.messageKind, element.messageArguments); | 219 node, element.messageKind, element.messageArguments); |
| 185 } else { | 220 } else { |
| 186 // We need to throw an exception at runtime. | 221 // We need to throw an exception at runtime. |
| 187 value = null; | 222 expression = null; |
| 188 } | 223 } |
| 189 } else { | 224 } else { |
| 190 DartType constantType = value.value.getType(compiler.coreTypes); | 225 DartType constantType = value.getType(compiler.coreTypes); |
| 191 if (!constantSystem.isSubtype(compiler.types, | 226 if (!constantSystem.isSubtype(compiler.types, |
| 192 constantType, elementType)) { | 227 constantType, elementType)) { |
| 193 if (isConst) { | 228 if (isConst) { |
| 194 compiler.reportError( | 229 compiler.reportError( |
| 195 node, MessageKind.NOT_ASSIGNABLE, | 230 node, MessageKind.NOT_ASSIGNABLE, |
| 196 {'fromType': constantType, 'toType': elementType}); | 231 {'fromType': constantType, 'toType': elementType}); |
| 197 } else { | 232 } else { |
| 198 // If the field cannot be lazily initialized, we will throw | 233 // If the field cannot be lazily initialized, we will throw |
| 199 // the exception at runtime. | 234 // the exception at runtime. |
| 200 value = null; | 235 expression = null; |
| 201 } | 236 } |
| 202 } | 237 } |
| 203 } | 238 } |
| 204 } | 239 } |
| 205 } | 240 } |
| 206 if (value != null) { | 241 if (expression != null) { |
| 207 initialVariableValues[element.declaration] = value; | 242 initialVariableValues[element.declaration] = expression; |
| 208 } else { | 243 } else { |
| 209 assert(invariant(element, !isConst, | 244 assert(invariant(element, !isConst, |
| 210 message: "Variable $element does not compile to a constant.")); | 245 message: "Variable $element does not compile to a constant.")); |
| 211 } | 246 } |
| 212 pendingVariables.remove(element); | 247 pendingVariables.remove(element); |
| 213 return value; | 248 return expression; |
| 214 } | 249 } |
| 215 | 250 |
| 216 ConstantExpression compileNodeWithDefinitions(Node node, | 251 ConstantExpression compileNodeWithDefinitions(Node node, |
| 217 TreeElements definitions, | 252 TreeElements definitions, |
| 218 {bool isConst: true}) { | 253 {bool isConst: true}) { |
| 219 assert(node != null); | 254 assert(node != null); |
| 220 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 255 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 221 this, definitions, compiler, isConst: isConst); | 256 this, definitions, compiler, isConst: isConst); |
| 222 AstConstant constant = evaluator.evaluate(node); | 257 AstConstant constant = evaluator.evaluate(node); |
| 223 return constant != null ? constant.expression : null; | 258 if (constant != null) { |
| 259 constantValueMap[constant.expression] = constant.value; |
| 260 return constant.expression; |
| 261 } |
| 262 return null; |
| 263 } |
| 264 |
| 265 ConstantValue getConstantValue(ConstantExpression expression) { |
| 266 return constantValueMap[expression]; |
| 224 } | 267 } |
| 225 | 268 |
| 226 ConstantExpression compileNode(Node node, TreeElements elements, | 269 ConstantExpression compileNode(Node node, TreeElements elements, |
| 227 {bool enforceConst: true}) { | 270 {bool enforceConst: true}) { |
| 228 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); | 271 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); |
| 229 } | 272 } |
| 230 | 273 |
| 231 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 274 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
| 232 Node node, | 275 Node node, |
| 233 TreeElements elements) { | 276 TreeElements elements) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 248 /// [ConstantCompiler] that uses the Dart semantics for the compile-time | 291 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
| 249 /// constant evaluation. | 292 /// constant evaluation. |
| 250 class DartConstantCompiler extends ConstantCompilerBase { | 293 class DartConstantCompiler extends ConstantCompilerBase { |
| 251 DartConstantCompiler(Compiler compiler) | 294 DartConstantCompiler(Compiler compiler) |
| 252 : super(compiler, const DartConstantSystem()); | 295 : super(compiler, const DartConstantSystem()); |
| 253 | 296 |
| 254 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { | 297 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { |
| 255 return definitions.getConstant(node); | 298 return definitions.getConstant(node); |
| 256 } | 299 } |
| 257 | 300 |
| 258 ConstantExpression getConstantForMetadata(MetadataAnnotation metadata) { | |
| 259 return metadata.constant; | |
| 260 } | |
| 261 | |
| 262 ConstantExpression compileNodeWithDefinitions(Node node, | 301 ConstantExpression compileNodeWithDefinitions(Node node, |
| 263 TreeElements definitions, | 302 TreeElements definitions, |
| 264 {bool isConst: true}) { | 303 {bool isConst: true}) { |
| 265 ConstantExpression constant = definitions.getConstant(node); | 304 ConstantExpression constant = definitions.getConstant(node); |
| 266 if (constant != null) { | 305 if (constant != null) { |
| 267 return constant; | 306 return constant; |
| 268 } | 307 } |
| 269 constant = | 308 constant = |
| 270 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); | 309 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| 271 if (constant != null) { | 310 if (constant != null) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 assert(result != null); | 344 assert(result != null); |
| 306 return result; | 345 return result; |
| 307 } | 346 } |
| 308 | 347 |
| 309 AstConstant visitNode(Node node) { | 348 AstConstant visitNode(Node node) { |
| 310 return signalNotCompileTimeConstant(node); | 349 return signalNotCompileTimeConstant(node); |
| 311 } | 350 } |
| 312 | 351 |
| 313 AstConstant visitLiteralBool(LiteralBool node) { | 352 AstConstant visitLiteralBool(LiteralBool node) { |
| 314 return new AstConstant( | 353 return new AstConstant( |
| 315 context, node, new BoolConstantExpression( | 354 context, |
| 316 node.value, | 355 node, |
| 317 constantSystem.createBool(node.value))); | 356 new BoolConstantExpression(node.value), |
| 357 constantSystem.createBool(node.value)); |
| 318 } | 358 } |
| 319 | 359 |
| 320 AstConstant visitLiteralDouble(LiteralDouble node) { | 360 AstConstant visitLiteralDouble(LiteralDouble node) { |
| 321 return new AstConstant( | 361 return new AstConstant( |
| 322 context, node, new DoubleConstantExpression( | 362 context, |
| 323 node.value, | 363 node, |
| 324 constantSystem.createDouble(node.value))); | 364 new DoubleConstantExpression(node.value), |
| 365 constantSystem.createDouble(node.value)); |
| 325 } | 366 } |
| 326 | 367 |
| 327 AstConstant visitLiteralInt(LiteralInt node) { | 368 AstConstant visitLiteralInt(LiteralInt node) { |
| 328 return new AstConstant( | 369 return new AstConstant( |
| 329 context, node, new IntConstantExpression( | 370 context, |
| 330 node.value, | 371 node, |
| 331 constantSystem.createInt(node.value))); | 372 new IntConstantExpression(node.value), |
| 373 constantSystem.createInt(node.value)); |
| 332 } | 374 } |
| 333 | 375 |
| 334 AstConstant visitLiteralList(LiteralList node) { | 376 AstConstant visitLiteralList(LiteralList node) { |
| 335 if (!node.isConst) { | 377 if (!node.isConst) { |
| 336 return signalNotCompileTimeConstant(node); | 378 return signalNotCompileTimeConstant(node); |
| 337 } | 379 } |
| 338 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; | 380 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; |
| 339 List<ConstantValue> argumentValues = <ConstantValue>[]; | 381 List<ConstantValue> argumentValues = <ConstantValue>[]; |
| 340 for (Link<Node> link = node.elements.nodes; | 382 for (Link<Node> link = node.elements.nodes; |
| 341 !link.isEmpty; | 383 !link.isEmpty; |
| 342 link = link.tail) { | 384 link = link.tail) { |
| 343 AstConstant argument = evaluateConstant(link.head); | 385 AstConstant argument = evaluateConstant(link.head); |
| 344 if (argument == null) { | 386 if (argument == null) { |
| 345 return null; | 387 return null; |
| 346 } | 388 } |
| 347 argumentExpressions.add(argument.expression); | 389 argumentExpressions.add(argument.expression); |
| 348 argumentValues.add(argument.value); | 390 argumentValues.add(argument.value); |
| 349 } | 391 } |
| 350 DartType type = elements.getType(node); | 392 DartType type = elements.getType(node); |
| 351 return new AstConstant( | 393 return new AstConstant( |
| 352 context, node, new ListConstantExpression( | 394 context, |
| 353 constantSystem.createList(type, argumentValues), | 395 node, |
| 354 type, | 396 new ListConstantExpression(type, argumentExpressions), |
| 355 argumentExpressions)); | 397 constantSystem.createList(type, argumentValues)); |
| 356 } | 398 } |
| 357 | 399 |
| 358 AstConstant visitLiteralMap(LiteralMap node) { | 400 AstConstant visitLiteralMap(LiteralMap node) { |
| 359 if (!node.isConst) { | 401 if (!node.isConst) { |
| 360 return signalNotCompileTimeConstant(node); | 402 return signalNotCompileTimeConstant(node); |
| 361 } | 403 } |
| 362 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; | 404 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; |
| 405 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; |
| 363 List<ConstantValue> keyValues = <ConstantValue>[]; | 406 List<ConstantValue> keyValues = <ConstantValue>[]; |
| 364 Map<ConstantValue, ConstantExpression> map = | 407 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; |
| 365 new Map<ConstantValue, ConstantExpression>(); | |
| 366 for (Link<Node> link = node.entries.nodes; | 408 for (Link<Node> link = node.entries.nodes; |
| 367 !link.isEmpty; | 409 !link.isEmpty; |
| 368 link = link.tail) { | 410 link = link.tail) { |
| 369 LiteralMapEntry entry = link.head; | 411 LiteralMapEntry entry = link.head; |
| 370 AstConstant key = evaluateConstant(entry.key); | 412 AstConstant key = evaluateConstant(entry.key); |
| 371 if (key == null) { | 413 if (key == null) { |
| 372 return null; | 414 return null; |
| 373 } | 415 } |
| 374 if (!map.containsKey(key.value)) { | |
| 375 keyExpressions.add(key.expression); | |
| 376 keyValues.add(key.value); | |
| 377 } else { | |
| 378 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); | |
| 379 } | |
| 380 AstConstant value = evaluateConstant(entry.value); | 416 AstConstant value = evaluateConstant(entry.value); |
| 381 if (value == null) { | 417 if (value == null) { |
| 382 return null; | 418 return null; |
| 383 } | 419 } |
| 384 map[key.value] = value.expression; | 420 if (!map.containsKey(key.value)) { |
| 421 keyValues.add(key.value); |
| 422 } else { |
| 423 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); |
| 424 } |
| 425 keyExpressions.add(key.expression); |
| 426 valueExpressions.add(value.expression); |
| 427 map[key.value] = value.value; |
| 385 } | 428 } |
| 386 List<ConstantExpression> valueExpressions = map.values.toList(); | |
| 387 InterfaceType type = elements.getType(node); | 429 InterfaceType type = elements.getType(node); |
| 388 return new AstConstant( | 430 return new AstConstant( |
| 389 context, node, new MapConstantExpression( | 431 context, |
| 390 constantSystem.createMap(compiler, type, keyValues, | 432 node, |
| 391 valueExpressions.map((e) => e.value).toList()), | 433 new MapConstantExpression( |
| 392 type, | 434 type, |
| 393 keyExpressions, | 435 keyExpressions, |
| 394 valueExpressions)); | 436 valueExpressions), |
| 437 constantSystem.createMap( |
| 438 compiler, type, keyValues, map.values.toList())); |
| 395 } | 439 } |
| 396 | 440 |
| 397 AstConstant visitLiteralNull(LiteralNull node) { | 441 AstConstant visitLiteralNull(LiteralNull node) { |
| 398 return new AstConstant( | 442 return new AstConstant( |
| 399 context, node, new NullConstantExpression( | 443 context, |
| 400 constantSystem.createNull())); | 444 node, |
| 445 new NullConstantExpression(), |
| 446 constantSystem.createNull()); |
| 401 } | 447 } |
| 402 | 448 |
| 403 AstConstant visitLiteralString(LiteralString node) { | 449 AstConstant visitLiteralString(LiteralString node) { |
| 404 return new AstConstant( | 450 return new AstConstant( |
| 405 context, node, new StringConstantExpression( | 451 context, |
| 406 node.dartString.slowToString(), | 452 node, |
| 407 constantSystem.createString(node.dartString))); | 453 new StringConstantExpression(node.dartString.slowToString()), |
| 454 constantSystem.createString(node.dartString)); |
| 408 } | 455 } |
| 409 | 456 |
| 410 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { | 457 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { |
| 411 AstConstant left = evaluate(node.first); | 458 AstConstant left = evaluate(node.first); |
| 412 AstConstant right = evaluate(node.second); | 459 AstConstant right = evaluate(node.second); |
| 413 if (left == null || right == null) return null; | 460 if (left == null || right == null) return null; |
| 414 StringConstantValue leftValue = left.value; | 461 StringConstantValue leftValue = left.value; |
| 415 StringConstantValue rightValue = right.value; | 462 StringConstantValue rightValue = right.value; |
| 416 return new AstConstant( | 463 return new AstConstant( |
| 417 context, node, new ConcatenateConstantExpression( | 464 context, |
| 418 constantSystem.createString( | 465 node, |
| 419 new DartString.concat( | 466 new ConcatenateConstantExpression([left.expression, right.expression]), |
| 420 leftValue.primitiveValue, rightValue.primitiveValue)), | 467 constantSystem.createString( |
| 421 [left.expression, right.expression])); | 468 new DartString.concat( |
| 469 leftValue.primitiveValue, rightValue.primitiveValue))); |
| 422 } | 470 } |
| 423 | 471 |
| 424 AstConstant visitStringInterpolation(StringInterpolation node) { | 472 AstConstant visitStringInterpolation(StringInterpolation node) { |
| 425 List<ConstantExpression> subexpressions = <ConstantExpression>[]; | 473 List<ConstantExpression> subexpressions = <ConstantExpression>[]; |
| 426 AstConstant initialString = evaluate(node.string); | 474 AstConstant initialString = evaluate(node.string); |
| 427 if (initialString == null) { | 475 if (initialString == null) { |
| 428 return null; | 476 return null; |
| 429 } | 477 } |
| 430 subexpressions.add(initialString.expression); | 478 subexpressions.add(initialString.expression); |
| 431 StringConstantValue initialStringValue = initialString.value; | 479 StringConstantValue initialStringValue = initialString.value; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 452 } | 500 } |
| 453 accumulator = new DartString.concat(accumulator, expressionString); | 501 accumulator = new DartString.concat(accumulator, expressionString); |
| 454 AstConstant partString = evaluate(part.string); | 502 AstConstant partString = evaluate(part.string); |
| 455 if (partString == null) return null; | 503 if (partString == null) return null; |
| 456 subexpressions.add(partString.expression); | 504 subexpressions.add(partString.expression); |
| 457 StringConstantValue partStringValue = partString.value; | 505 StringConstantValue partStringValue = partString.value; |
| 458 accumulator = | 506 accumulator = |
| 459 new DartString.concat(accumulator, partStringValue.primitiveValue); | 507 new DartString.concat(accumulator, partStringValue.primitiveValue); |
| 460 }; | 508 }; |
| 461 return new AstConstant( | 509 return new AstConstant( |
| 462 context, node, new ConcatenateConstantExpression( | 510 context, |
| 463 constantSystem.createString(accumulator), | 511 node, |
| 464 subexpressions)); | 512 new ConcatenateConstantExpression(subexpressions), |
| 513 constantSystem.createString(accumulator)); |
| 465 } | 514 } |
| 466 | 515 |
| 467 AstConstant visitLiteralSymbol(LiteralSymbol node) { | 516 AstConstant visitLiteralSymbol(LiteralSymbol node) { |
| 468 InterfaceType type = compiler.symbolClass.rawType; | 517 InterfaceType type = compiler.symbolClass.rawType; |
| 469 String text = node.slowNameString; | 518 String text = node.slowNameString; |
| 470 List<AstConstant> arguments = | 519 List<AstConstant> arguments = |
| 471 <AstConstant>[new AstConstant(context, node, | 520 <AstConstant>[new AstConstant( |
| 472 new StringConstantExpression( | 521 context, |
| 473 text, | 522 node, |
| 474 constantSystem.createString(new LiteralDartString(text))))]; | 523 new StringConstantExpression(text), |
| 524 constantSystem.createString(new LiteralDartString(text)))]; |
| 475 ConstructorElement constructor = compiler.symbolConstructor; | 525 ConstructorElement constructor = compiler.symbolConstructor; |
| 476 AstConstant constant = createConstructorInvocation( | 526 AstConstant constant = createConstructorInvocation( |
| 477 node, type, constructor, CallStructure.ONE_ARG, | 527 node, type, constructor, CallStructure.ONE_ARG, |
| 478 normalizedArguments: arguments); | 528 normalizedArguments: arguments); |
| 479 return new AstConstant( | 529 return new AstConstant( |
| 480 context, node, new SymbolConstantExpression(constant.value, text)); | 530 context, node, new SymbolConstantExpression(text), constant.value); |
| 481 } | 531 } |
| 482 | 532 |
| 483 ConstantExpression makeTypeConstant(DartType elementType) { | 533 ConstantValue makeTypeConstant(DartType elementType) { |
| 484 return new TypeConstantExpression( | 534 return constantSystem.createType(compiler, elementType); |
| 485 constantSystem.createType(compiler, elementType), elementType); | |
| 486 } | 535 } |
| 487 | 536 |
| 488 /// Returns true if the prefix of the send resolves to a deferred import | 537 /// Returns true if the prefix of the send resolves to a deferred import |
| 489 /// prefix. | 538 /// prefix. |
| 490 bool isDeferredUse(Send send) { | 539 bool isDeferredUse(Send send) { |
| 491 if (send == null) return false; | 540 if (send == null) return false; |
| 492 return compiler.deferredLoadTask | 541 return compiler.deferredLoadTask |
| 493 .deferredPrefixElement(send, elements) != null; | 542 .deferredPrefixElement(send, elements) != null; |
| 494 } | 543 } |
| 495 | 544 |
| 496 AstConstant visitIdentifier(Identifier node) { | 545 AstConstant visitIdentifier(Identifier node) { |
| 497 Element element = elements[node]; | 546 Element element = elements[node]; |
| 498 if (Elements.isClass(element) || Elements.isTypedef(element)) { | 547 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 499 TypeDeclarationElement typeDeclarationElement = element; | 548 TypeDeclarationElement typeDeclarationElement = element; |
| 500 DartType type = typeDeclarationElement.rawType; | 549 DartType type = typeDeclarationElement.rawType; |
| 501 return new AstConstant(element, node, makeTypeConstant(type)); | 550 return new AstConstant(element, node, |
| 551 new TypeConstantExpression(type), makeTypeConstant(type)); |
| 502 } | 552 } |
| 503 return signalNotCompileTimeConstant(node); | 553 return signalNotCompileTimeConstant(node); |
| 504 } | 554 } |
| 505 | 555 |
| 506 // TODO(floitsch): provide better error-messages. | 556 // TODO(floitsch): provide better error-messages. |
| 507 AstConstant visitSend(Send send) { | 557 AstConstant visitSend(Send send) { |
| 508 Element element = elements[send]; | 558 Element element = elements[send]; |
| 509 if (send.isPropertyAccess) { | 559 if (send.isPropertyAccess) { |
| 510 ConstantExpression result; | 560 AstConstant result; |
| 511 | |
| 512 if (Elements.isStaticOrTopLevelFunction(element)) { | 561 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 513 FunctionElementX function = element; | 562 FunctionElementX function = element; |
| 514 function.computeType(compiler); | 563 function.computeType(compiler); |
| 515 result = new FunctionConstantExpression( | 564 result = new AstConstant( |
| 516 new FunctionConstantValue(function), function); | 565 context, |
| 566 send, |
| 567 new FunctionConstantExpression(function), |
| 568 new FunctionConstantValue(function)); |
| 517 } else if (Elements.isStaticOrTopLevelField(element)) { | 569 } else if (Elements.isStaticOrTopLevelField(element)) { |
| 518 ConstantExpression elementExpression; | 570 ConstantExpression elementExpression; |
| 519 if (element.isConst) { | 571 if (element.isConst) { |
| 520 elementExpression = handler.compileConstant(element); | 572 elementExpression = handler.compileConstant(element); |
| 521 } else if (element.isFinal && !isEvaluatingConstant) { | 573 } else if (element.isFinal && !isEvaluatingConstant) { |
| 522 elementExpression = handler.compileVariable(element); | 574 elementExpression = handler.compileVariable(element); |
| 523 } | 575 } |
| 524 if (elementExpression != null) { | 576 if (elementExpression != null) { |
| 525 result = | 577 result = new AstConstant( |
| 526 new VariableConstantExpression(elementExpression.value, element); | 578 context, |
| 579 send, |
| 580 new VariableConstantExpression(element), |
| 581 handler.getConstantValue(elementExpression)); |
| 527 } | 582 } |
| 528 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 583 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 529 assert(elements.isTypeLiteral(send)); | 584 assert(elements.isTypeLiteral(send)); |
| 530 result = makeTypeConstant(elements.getTypeLiteralType(send)); | 585 DartType elementType = elements.getTypeLiteralType(send); |
| 586 result = new AstConstant( |
| 587 context, |
| 588 send, |
| 589 new TypeConstantExpression(elementType), |
| 590 makeTypeConstant(elementType)); |
| 531 } else if (send.receiver != null) { | 591 } else if (send.receiver != null) { |
| 532 if (send.selector.asIdentifier().source == "length") { | 592 if (send.selector.asIdentifier().source == "length") { |
| 533 AstConstant left = evaluate(send.receiver); | 593 AstConstant left = evaluate(send.receiver); |
| 534 if (left != null && left.value.isString) { | 594 if (left != null && left.value.isString) { |
| 535 StringConstantValue stringConstantValue = left.value; | 595 StringConstantValue stringConstantValue = left.value; |
| 536 DartString string = stringConstantValue.primitiveValue; | 596 DartString string = stringConstantValue.primitiveValue; |
| 537 IntConstantValue length = constantSystem.createInt(string.length); | 597 IntConstantValue length = constantSystem.createInt(string.length); |
| 538 result = | 598 result = new AstConstant( |
| 539 new StringLengthConstantExpression(length, left.expression); | 599 context, |
| 600 send, |
| 601 new StringLengthConstantExpression(left.expression), |
| 602 length); |
| 540 } | 603 } |
| 541 } | 604 } |
| 542 // Fall through to error handling. | 605 // Fall through to error handling. |
| 543 } else if (!Elements.isUnresolved(element) | 606 } else if (!Elements.isUnresolved(element) |
| 544 && element.isVariable | 607 && element.isVariable |
| 545 && element.isConst) { | 608 && element.isConst) { |
| 546 ConstantExpression variableExpression = | 609 ConstantExpression variableExpression = |
| 547 handler.compileConstant(element); | 610 handler.compileConstant(element); |
| 548 if (variableExpression != null) { | 611 if (variableExpression != null) { |
| 549 result = new VariableConstantExpression(variableExpression.value, | 612 result = new AstConstant( |
| 550 element); | 613 context, |
| 614 send, |
| 615 new VariableConstantExpression(element), |
| 616 handler.getConstantValue(variableExpression)); |
| 551 } | 617 } |
| 552 } | 618 } |
| 553 if (result == null) { | 619 if (result == null) { |
| 554 return signalNotCompileTimeConstant(send); | 620 return signalNotCompileTimeConstant(send); |
| 555 } | 621 } |
| 556 if (isDeferredUse(send)) { | 622 if (isDeferredUse(send)) { |
| 557 if (isEvaluatingConstant) { | 623 if (isEvaluatingConstant) { |
| 558 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 624 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
| 559 } | 625 } |
| 560 PrefixElement prefix = compiler.deferredLoadTask | 626 PrefixElement prefix = compiler.deferredLoadTask |
| 561 .deferredPrefixElement(send, elements); | 627 .deferredPrefixElement(send, elements); |
| 562 result = new DeferredConstantExpression( | 628 result = new AstConstant( |
| 563 new DeferredConstantValue(result.value, prefix), | 629 context, |
| 564 result, | 630 send, |
| 565 prefix); | 631 new DeferredConstantExpression( |
| 632 result.expression, |
| 633 prefix), |
| 634 new DeferredConstantValue(result.value, prefix)); |
| 566 compiler.deferredLoadTask | 635 compiler.deferredLoadTask |
| 567 .registerConstantDeferredUse(result.value, prefix); | 636 .registerConstantDeferredUse(result.value, prefix); |
| 568 } | 637 } |
| 569 return new AstConstant(context, send, result); | 638 return result; |
| 570 } else if (send.isCall) { | 639 } else if (send.isCall) { |
| 571 if (element == compiler.identicalFunction | 640 if (element == compiler.identicalFunction |
| 572 && send.argumentCount() == 2) { | 641 && send.argumentCount() == 2) { |
| 573 AstConstant left = evaluate(send.argumentsNode.nodes.head); | 642 AstConstant left = evaluate(send.argumentsNode.nodes.head); |
| 574 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); | 643 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); |
| 575 if (left == null || right == null) { | 644 if (left == null || right == null) { |
| 576 return null; | 645 return null; |
| 577 } | 646 } |
| 578 ConstantValue result = | 647 ConstantValue result = |
| 579 constantSystem.identity.fold(left.value, right.value); | 648 constantSystem.identity.fold(left.value, right.value); |
| 580 if (result != null) { | 649 if (result != null) { |
| 581 return new AstConstant( | 650 return new AstConstant( |
| 582 context, send, new IdenticalConstantExpression(result, | 651 context, |
| 583 left.expression, right.expression)); | 652 send, |
| 653 new IdenticalConstantExpression( |
| 654 left.expression, right.expression), |
| 655 result); |
| 584 } | 656 } |
| 585 } | 657 } |
| 586 return signalNotCompileTimeConstant(send); | 658 return signalNotCompileTimeConstant(send); |
| 587 } else if (send.isPrefix) { | 659 } else if (send.isPrefix) { |
| 588 assert(send.isOperator); | 660 assert(send.isOperator); |
| 589 AstConstant receiverConstant = evaluate(send.receiver); | 661 AstConstant receiverConstant = evaluate(send.receiver); |
| 590 if (receiverConstant == null) { | 662 if (receiverConstant == null) { |
| 591 return null; | 663 return null; |
| 592 } | 664 } |
| 593 Operator node = send.selector; | 665 Operator node = send.selector; |
| 594 UnaryOperator operator = UnaryOperator.parse(node.source); | 666 UnaryOperator operator = UnaryOperator.parse(node.source); |
| 595 UnaryOperation operation = constantSystem.lookupUnary(operator); | 667 UnaryOperation operation = constantSystem.lookupUnary(operator); |
| 596 if (operation == null) { | 668 if (operation == null) { |
| 597 compiler.internalError(send.selector, "Unexpected operator."); | 669 compiler.internalError(send.selector, "Unexpected operator."); |
| 598 } | 670 } |
| 599 ConstantValue folded = operation.fold(receiverConstant.value); | 671 ConstantValue folded = operation.fold(receiverConstant.value); |
| 600 if (folded == null) { | 672 if (folded == null) { |
| 601 return signalNotCompileTimeConstant(send); | 673 return signalNotCompileTimeConstant(send); |
| 602 } | 674 } |
| 603 return new AstConstant( | 675 return new AstConstant( |
| 604 context, send, new UnaryConstantExpression(folded, | 676 context, |
| 605 operator, receiverConstant.expression)); | 677 send, |
| 678 new UnaryConstantExpression( |
| 679 operator, receiverConstant.expression), |
| 680 folded); |
| 606 } else if (send.isOperator && !send.isPostfix) { | 681 } else if (send.isOperator && !send.isPostfix) { |
| 607 assert(send.argumentCount() == 1); | 682 assert(send.argumentCount() == 1); |
| 608 AstConstant left = evaluate(send.receiver); | 683 AstConstant left = evaluate(send.receiver); |
| 609 AstConstant right = evaluate(send.argumentsNode.nodes.head); | 684 AstConstant right = evaluate(send.argumentsNode.nodes.head); |
| 610 if (left == null || right == null) { | 685 if (left == null || right == null) { |
| 611 return null; | 686 return null; |
| 612 } | 687 } |
| 613 ConstantValue leftValue = left.value; | 688 ConstantValue leftValue = left.value; |
| 614 ConstantValue rightValue = right.value; | 689 ConstantValue rightValue = right.value; |
| 615 Operator node = send.selector.asOperator(); | 690 Operator node = send.selector.asOperator(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 638 BinaryOperation operation = constantSystem.lookupBinary(operator); | 713 BinaryOperation operation = constantSystem.lookupBinary(operator); |
| 639 if (operation != null) { | 714 if (operation != null) { |
| 640 folded = operation.fold(leftValue, rightValue); | 715 folded = operation.fold(leftValue, rightValue); |
| 641 } | 716 } |
| 642 } | 717 } |
| 643 } | 718 } |
| 644 if (folded == null) { | 719 if (folded == null) { |
| 645 return signalNotCompileTimeConstant(send); | 720 return signalNotCompileTimeConstant(send); |
| 646 } | 721 } |
| 647 return new AstConstant( | 722 return new AstConstant( |
| 648 context, send, new BinaryConstantExpression(folded, | 723 context, |
| 649 left.expression, operator, right.expression)); | 724 send, |
| 725 new BinaryConstantExpression( |
| 726 left.expression, operator, right.expression), |
| 727 folded); |
| 650 } | 728 } |
| 651 return signalNotCompileTimeConstant(send); | 729 return signalNotCompileTimeConstant(send); |
| 652 } | 730 } |
| 653 | 731 |
| 654 AstConstant visitConditional(Conditional node) { | 732 AstConstant visitConditional(Conditional node) { |
| 655 AstConstant condition = evaluate(node.condition); | 733 AstConstant condition = evaluate(node.condition); |
| 656 if (condition == null) { | 734 if (condition == null) { |
| 657 return null; | 735 return null; |
| 658 } else if (!condition.value.isBool) { | 736 } else if (!condition.value.isBool) { |
| 659 DartType conditionType = condition.value.getType(compiler.coreTypes); | 737 DartType conditionType = condition.value.getType(compiler.coreTypes); |
| 660 if (isEvaluatingConstant) { | 738 if (isEvaluatingConstant) { |
| 661 compiler.reportError( | 739 compiler.reportError( |
| 662 node.condition, MessageKind.NOT_ASSIGNABLE, | 740 node.condition, MessageKind.NOT_ASSIGNABLE, |
| 663 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); | 741 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); |
| 664 return new ErroneousAstConstant(context, node); | 742 return new ErroneousAstConstant(context, node); |
| 665 } | 743 } |
| 666 return null; | 744 return null; |
| 667 } | 745 } |
| 668 AstConstant thenExpression = evaluate(node.thenExpression); | 746 AstConstant thenExpression = evaluate(node.thenExpression); |
| 669 AstConstant elseExpression = evaluate(node.elseExpression); | 747 AstConstant elseExpression = evaluate(node.elseExpression); |
| 670 if (thenExpression == null || elseExpression == null) { | 748 if (thenExpression == null || elseExpression == null) { |
| 671 return null; | 749 return null; |
| 672 } | 750 } |
| 673 BoolConstantValue boolCondition = condition.value; | 751 BoolConstantValue boolCondition = condition.value; |
| 674 return new AstConstant( | 752 return new AstConstant( |
| 675 context, node, new ConditionalConstantExpression( | 753 context, |
| 676 boolCondition.primitiveValue | 754 node, |
| 677 ? thenExpression.value | 755 new ConditionalConstantExpression( |
| 678 : elseExpression.value, | |
| 679 condition.expression, | 756 condition.expression, |
| 680 thenExpression.expression, | 757 thenExpression.expression, |
| 681 elseExpression.expression)); | 758 elseExpression.expression), |
| 759 boolCondition.primitiveValue |
| 760 ? thenExpression.value |
| 761 : elseExpression.value); |
| 682 } | 762 } |
| 683 | 763 |
| 684 AstConstant visitSendSet(SendSet node) { | 764 AstConstant visitSendSet(SendSet node) { |
| 685 return signalNotCompileTimeConstant(node); | 765 return signalNotCompileTimeConstant(node); |
| 686 } | 766 } |
| 687 | 767 |
| 688 /** | 768 /** |
| 689 * Returns the normalized list of constant arguments that are passed to the | 769 * Returns the normalized list of constant arguments that are passed to the |
| 690 * constructor including both the concrete arguments and default values for | 770 * constructor including both the concrete arguments and default values for |
| 691 * omitted optional arguments. | 771 * omitted optional arguments. |
| 692 * | 772 * |
| 693 * Invariant: [target] must be an implementation element. | 773 * Invariant: [target] must be an implementation element. |
| 694 */ | 774 */ |
| 695 List<AstConstant> evaluateArgumentsToConstructor( | 775 List<AstConstant> evaluateArgumentsToConstructor( |
| 696 Node node, | 776 Node node, |
| 697 CallStructure callStructure, | 777 CallStructure callStructure, |
| 698 Link<Node> arguments, | 778 Link<Node> arguments, |
| 699 FunctionElement target, | 779 FunctionElement target, |
| 700 {AstConstant compileArgument(Node node)}) { | 780 {AstConstant compileArgument(Node node)}) { |
| 701 assert(invariant(node, target.isImplementation)); | 781 assert(invariant(node, target.isImplementation)); |
| 702 | 782 |
| 703 AstConstant compileDefaultValue(VariableElement element) { | 783 AstConstant compileDefaultValue(VariableElement element) { |
| 704 ConstantExpression constant = handler.compileConstant(element); | 784 ConstantExpression constant = handler.compileConstant(element); |
| 705 return new AstConstant.fromDefaultValue(element, constant); | 785 return new AstConstant.fromDefaultValue( |
| 786 element, constant, handler.getConstantValue(constant)); |
| 706 } | 787 } |
| 707 target.computeSignature(compiler); | 788 target.computeSignature(compiler); |
| 708 | 789 |
| 709 if (!callStructure.signatureApplies(target)) { | 790 if (!callStructure.signatureApplies(target)) { |
| 710 String name = Elements.constructorNameForDiagnostics( | 791 String name = Elements.constructorNameForDiagnostics( |
| 711 target.enclosingClass.name, target.name); | 792 target.enclosingClass.name, target.name); |
| 712 compiler.reportError( | 793 compiler.reportError( |
| 713 node, | 794 node, |
| 714 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, | 795 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, |
| 715 {'constructorName': name}); | 796 {'constructorName': name}); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 // a post-process action, so we have to make sure it is done here. | 848 // a post-process action, so we have to make sure it is done here. |
| 768 compiler.resolver.resolveRedirectionChain(constructor, node); | 849 compiler.resolver.resolveRedirectionChain(constructor, node); |
| 769 InterfaceType constructedType = | 850 InterfaceType constructedType = |
| 770 constructor.computeEffectiveTargetType(type); | 851 constructor.computeEffectiveTargetType(type); |
| 771 ConstructorElement target = constructor.effectiveTarget; | 852 ConstructorElement target = constructor.effectiveTarget; |
| 772 // The constructor must be an implementation to ensure that field | 853 // The constructor must be an implementation to ensure that field |
| 773 // initializers are handled correctly. | 854 // initializers are handled correctly. |
| 774 ConstructorElement implementation = target.implementation; | 855 ConstructorElement implementation = target.implementation; |
| 775 | 856 |
| 776 if (implementation.isErroneous) { | 857 if (implementation.isErroneous) { |
| 858 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant]. |
| 777 return new AstConstant( | 859 return new AstConstant( |
| 778 context, node, new ConstructedConstantExpression( | 860 context, |
| 779 new ConstructedConstantValue( | 861 node, |
| 780 constructedType, const <FieldElement, ConstantValue>{}), | 862 new ConstructedConstantExpression( |
| 781 type, | 863 type, |
| 782 constructor, | 864 constructor, |
| 783 callStructure, | 865 callStructure, |
| 784 const <ConstantExpression>[])); | 866 const <ConstantExpression>[]), |
| 867 new ConstructedConstantValue( |
| 868 constructedType, const <FieldElement, ConstantValue>{})); |
| 785 } | 869 } |
| 786 | 870 |
| 787 List<AstConstant> concreteArguments; | 871 List<AstConstant> concreteArguments; |
| 788 if (arguments != null) { | 872 if (arguments != null) { |
| 789 Map<Node, AstConstant> concreteArgumentMap = | 873 Map<Node, AstConstant> concreteArgumentMap = |
| 790 <Node, AstConstant>{}; | 874 <Node, AstConstant>{}; |
| 791 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { | 875 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { |
| 792 Node argument = link.head; | 876 Node argument = link.head; |
| 793 NamedArgument namedArgument = argument.asNamedArgument(); | 877 NamedArgument namedArgument = argument.asNamedArgument(); |
| 794 if (namedArgument != null) { | 878 if (namedArgument != null) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 AstConstant createEvaluatedConstant(ConstantValue value) { | 965 AstConstant createEvaluatedConstant(ConstantValue value) { |
| 882 | 966 |
| 883 ConstantExpression expression; | 967 ConstantExpression expression; |
| 884 ConstantExpression name = concreteArguments[0].expression; | 968 ConstantExpression name = concreteArguments[0].expression; |
| 885 ConstantExpression defaultValue; | 969 ConstantExpression defaultValue; |
| 886 if (concreteArguments.length > 1) { | 970 if (concreteArguments.length > 1) { |
| 887 defaultValue = concreteArguments[1].expression; | 971 defaultValue = concreteArguments[1].expression; |
| 888 } | 972 } |
| 889 if (constructor == compiler.intEnvironment) { | 973 if (constructor == compiler.intEnvironment) { |
| 890 expression = new IntFromEnvironmentConstantExpression( | 974 expression = new IntFromEnvironmentConstantExpression( |
| 891 value, name, defaultValue); | 975 name, defaultValue); |
| 892 } else if (constructor == compiler.boolEnvironment) { | 976 } else if (constructor == compiler.boolEnvironment) { |
| 893 expression = new BoolFromEnvironmentConstantExpression( | 977 expression = new BoolFromEnvironmentConstantExpression( |
| 894 value, name, defaultValue); | 978 name, defaultValue); |
| 895 } else if (constructor == compiler.stringEnvironment) { | 979 } else if (constructor == compiler.stringEnvironment) { |
| 896 expression = new StringFromEnvironmentConstantExpression( | 980 expression = new StringFromEnvironmentConstantExpression( |
| 897 value, name, defaultValue); | 981 name, defaultValue); |
| 898 } | 982 } |
| 899 return new AstConstant(context, node, expression); | 983 return new AstConstant(context, node, expression, value); |
| 900 } | 984 } |
| 901 | 985 |
| 902 if (value == null) { | 986 if (value == null) { |
| 903 return createEvaluatedConstant(defaultValue); | 987 return createEvaluatedConstant(defaultValue); |
| 904 } else if (constructor == compiler.intEnvironment) { | 988 } else if (constructor == compiler.intEnvironment) { |
| 905 int number = int.parse(value, onError: (_) => null); | 989 int number = int.parse(value, onError: (_) => null); |
| 906 return createEvaluatedConstant( | 990 return createEvaluatedConstant( |
| 907 (number == null) | 991 (number == null) |
| 908 ? defaultValue | 992 ? defaultValue |
| 909 : constantSystem.createInt(number)); | 993 : constantSystem.createInt(number)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 932 InterfaceType constructedType, | 1016 InterfaceType constructedType, |
| 933 ConstructorElement target, | 1017 ConstructorElement target, |
| 934 CallStructure callStructure, | 1018 CallStructure callStructure, |
| 935 List<AstConstant> concreteArguments, | 1019 List<AstConstant> concreteArguments, |
| 936 List<AstConstant> normalizedArguments) { | 1020 List<AstConstant> normalizedArguments) { |
| 937 if (target.isRedirectingFactory) { | 1021 if (target.isRedirectingFactory) { |
| 938 // This happens is case of cyclic redirection. | 1022 // This happens is case of cyclic redirection. |
| 939 assert(invariant(node, compiler.compilationFailed, | 1023 assert(invariant(node, compiler.compilationFailed, |
| 940 message: "makeConstructedConstant can only be called with the " | 1024 message: "makeConstructedConstant can only be called with the " |
| 941 "effective target: $constructor")); | 1025 "effective target: $constructor")); |
| 942 return new AstConstant( | 1026 return new ErroneousAstConstant(context, node); |
| 943 context, node, new ErroneousConstantExpression()); | |
| 944 } | 1027 } |
| 945 assert(invariant(node, callStructure.signatureApplies(constructor) || | 1028 assert(invariant(node, callStructure.signatureApplies(constructor) || |
| 946 compiler.compilationFailed, | 1029 compiler.compilationFailed, |
| 947 message: "Call structure $callStructure does not apply to constructor " | 1030 message: "Call structure $callStructure does not apply to constructor " |
| 948 "$constructor.")); | 1031 "$constructor.")); |
| 949 | 1032 |
| 950 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 1033 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 951 constructedType, target, handler, compiler); | 1034 constructedType, target, handler, compiler); |
| 952 evaluator.evaluateConstructorFieldValues(normalizedArguments); | 1035 evaluator.evaluateConstructorFieldValues(normalizedArguments); |
| 953 Map<FieldElement, AstConstant> fieldConstants = | 1036 Map<FieldElement, AstConstant> fieldConstants = |
| 954 evaluator.buildFieldConstants(target.enclosingClass); | 1037 evaluator.buildFieldConstants(target.enclosingClass); |
| 955 Map<FieldElement, ConstantValue> fieldValues = | 1038 Map<FieldElement, ConstantValue> fieldValues = |
| 956 <FieldElement, ConstantValue>{}; | 1039 <FieldElement, ConstantValue>{}; |
| 957 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { | 1040 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { |
| 958 fieldValues[field] = astConstant.value; | 1041 fieldValues[field] = astConstant.value; |
| 959 }); | 1042 }); |
| 960 return new AstConstant( | 1043 return new AstConstant( |
| 961 context, node, new ConstructedConstantExpression( | 1044 context, |
| 962 new ConstructedConstantValue(constructedType, fieldValues), | 1045 node, |
| 1046 new ConstructedConstantExpression( |
| 963 type, | 1047 type, |
| 964 constructor, | 1048 constructor, |
| 965 callStructure, | 1049 callStructure, |
| 966 concreteArguments.map((e) => e.expression).toList())); | 1050 concreteArguments.map((e) => e.expression).toList()), |
| 1051 new ConstructedConstantValue(constructedType, fieldValues)); |
| 967 } | 1052 } |
| 968 | 1053 |
| 969 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { | 1054 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 970 return node.expression.accept(this); | 1055 return node.expression.accept(this); |
| 971 } | 1056 } |
| 972 | 1057 |
| 973 error(Node node, MessageKind message) { | 1058 error(Node node, MessageKind message) { |
| 974 // TODO(floitsch): get the list of constants that are currently compiled | 1059 // TODO(floitsch): get the list of constants that are currently compiled |
| 975 // and present some kind of stack-trace. | 1060 // and present some kind of stack-trace. |
| 976 compiler.reportError(node, message); | 1061 compiler.reportError(node, message); |
| 977 } | 1062 } |
| 978 | 1063 |
| 979 AstConstant signalNotCompileTimeConstant(Node node, | 1064 AstConstant signalNotCompileTimeConstant(Node node, |
| 980 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { | 1065 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { |
| 981 if (isEvaluatingConstant) { | 1066 if (isEvaluatingConstant) { |
| 982 error(node, message); | 1067 error(node, message); |
| 983 | 1068 |
| 984 return new AstConstant( | 1069 return new AstConstant( |
| 985 null, node, new ErroneousConstantExpression()); | 1070 context, |
| 1071 node, |
| 1072 new ErroneousConstantExpression(), |
| 1073 new NullConstantValue()); |
| 986 } | 1074 } |
| 987 // Else we don't need to do anything. The final handler is only | 1075 // Else we don't need to do anything. The final handler is only |
| 988 // optimistically trying to compile constants. So it is normal that we | 1076 // optimistically trying to compile constants. So it is normal that we |
| 989 // sometimes see non-compile time constants. | 1077 // sometimes see non-compile time constants. |
| 990 // Simply return [:null:] which is used to propagate a failing | 1078 // Simply return [:null:] which is used to propagate a failing |
| 991 // compile-time compilation. | 1079 // compile-time compilation. |
| 992 return null; | 1080 return null; |
| 993 } | 1081 } |
| 994 } | 1082 } |
| 995 | 1083 |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1181 /// inheritance chain of [classElement]. | 1269 /// inheritance chain of [classElement]. |
| 1182 Map<FieldElement, AstConstant> buildFieldConstants( | 1270 Map<FieldElement, AstConstant> buildFieldConstants( |
| 1183 ClassElement classElement) { | 1271 ClassElement classElement) { |
| 1184 Map<FieldElement, AstConstant> fieldConstants = | 1272 Map<FieldElement, AstConstant> fieldConstants = |
| 1185 <FieldElement, AstConstant>{}; | 1273 <FieldElement, AstConstant>{}; |
| 1186 classElement.implementation.forEachInstanceField( | 1274 classElement.implementation.forEachInstanceField( |
| 1187 (ClassElement enclosing, FieldElement field) { | 1275 (ClassElement enclosing, FieldElement field) { |
| 1188 AstConstant fieldValue = fieldValues[field]; | 1276 AstConstant fieldValue = fieldValues[field]; |
| 1189 if (fieldValue == null) { | 1277 if (fieldValue == null) { |
| 1190 // Use the default value. | 1278 // Use the default value. |
| 1279 ConstantExpression fieldExpression = handler.compileConstant(field); |
| 1191 fieldValue = new AstConstant.fromDefaultValue( | 1280 fieldValue = new AstConstant.fromDefaultValue( |
| 1192 field, handler.compileConstant(field)); | 1281 field, |
| 1282 fieldExpression, |
| 1283 handler.getConstantValue(fieldExpression)); |
| 1193 } | 1284 } |
| 1194 fieldConstants[field] = fieldValue; | 1285 fieldConstants[field] = fieldValue; |
| 1195 }, | 1286 }, |
| 1196 includeSuperAndInjectedMembers: true); | 1287 includeSuperAndInjectedMembers: true); |
| 1197 return fieldConstants; | 1288 return fieldConstants; |
| 1198 } | 1289 } |
| 1199 } | 1290 } |
| 1200 | 1291 |
| 1201 /// A constant created from the front-end AST. | 1292 /// A constant created from the front-end AST. |
| 1202 /// | 1293 /// |
| 1203 /// [element] and [node] point to the source location of the constant. | 1294 /// [element] and [node] point to the source location of the constant. |
| 1204 /// [expression] holds the symbolic constant expression and [value] its constant | 1295 /// [expression] holds the symbolic constant expression and [value] its constant |
| 1205 /// value. | 1296 /// value. |
| 1206 /// | 1297 /// |
| 1207 /// This class differs from [ConstantExpression] in that it is coupled to the | 1298 /// This class differs from [ConstantExpression] in that it is coupled to the |
| 1208 /// front-end AST whereas [ConstantExpression] is only coupled to the element | 1299 /// front-end AST whereas [ConstantExpression] is only coupled to the element |
| 1209 /// model. | 1300 /// model. |
| 1210 class AstConstant { | 1301 class AstConstant { |
| 1211 final Element element; | 1302 final Element element; |
| 1212 final Node node; | 1303 final Node node; |
| 1213 final ConstantExpression expression; | 1304 final ConstantExpression expression; |
| 1305 final ConstantValue value; |
| 1214 | 1306 |
| 1215 AstConstant(this.element, this.node, this.expression); | 1307 AstConstant(this.element, this.node, this.expression, this.value); |
| 1216 | 1308 |
| 1217 factory AstConstant.fromDefaultValue( | 1309 factory AstConstant.fromDefaultValue( |
| 1218 VariableElement element, | 1310 VariableElement element, |
| 1219 ConstantExpression constant) { | 1311 ConstantExpression constant, |
| 1312 ConstantValue value) { |
| 1220 return new AstConstant( | 1313 return new AstConstant( |
| 1221 element, | 1314 element, |
| 1222 element.initializer != null ? element.initializer : element.node, | 1315 element.initializer != null ? element.initializer : element.node, |
| 1223 constant); | 1316 constant, |
| 1317 value); |
| 1224 } | 1318 } |
| 1225 | 1319 |
| 1226 ConstantValue get value => expression.value; | |
| 1227 | |
| 1228 String toString() => expression.toString(); | 1320 String toString() => expression.toString(); |
| 1229 } | 1321 } |
| 1230 | 1322 |
| 1231 /// A synthetic constant used to recover from errors. | 1323 /// A synthetic constant used to recover from errors. |
| 1232 class ErroneousAstConstant extends AstConstant { | 1324 class ErroneousAstConstant extends AstConstant { |
| 1233 ErroneousAstConstant(Element element, Node node) | 1325 ErroneousAstConstant(Element element, Node node) |
| 1234 : super(element, node, new ErroneousConstantExpression()); | 1326 : super(element, node, |
| 1327 // TODO(johnniwinther): Return a [NonConstantValue] instead. |
| 1328 new ErroneousConstantExpression(), new NullConstantValue()); |
| 1235 } | 1329 } |
| 1236 | 1330 |
| 1237 // TODO(johnniwinther): Avoid the need for this hack. | 1331 // TODO(johnniwinther): Avoid the need for this hack. |
| 1238 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { | 1332 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { |
| 1239 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); | 1333 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); |
| 1240 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); | 1334 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); |
| 1241 return element.resolvedAst.elements; | 1335 return element.resolvedAst.elements; |
| 1242 } | 1336 } |
| OLD | NEW |