| 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/evaluation.dart'; | 9 import 'constants/evaluation.dart'; |
| 10 import 'constants/expressions.dart'; | 10 import 'constants/expressions.dart'; |
| 11 import 'constants/values.dart'; | 11 import 'constants/values.dart'; |
| 12 import 'dart_types.dart'; | 12 import 'dart_types.dart'; |
| 13 import 'dart2jslib.dart' show Compiler, CompilerTask, MessageKind, WorldImpact,
invariant; | 13 import 'dart2jslib.dart' |
| 14 show Compiler, CompilerTask, MessageKind, WorldImpact, invariant; |
| 14 import 'elements/elements.dart'; | 15 import 'elements/elements.dart'; |
| 15 import 'elements/modelx.dart' show FunctionElementX; | 16 import 'elements/modelx.dart' show FunctionElementX; |
| 16 import 'resolution/resolution.dart'; | 17 import 'resolution/resolution.dart'; |
| 17 import 'resolution/operators.dart'; | 18 import 'resolution/operators.dart'; |
| 18 import 'tree/tree.dart'; | 19 import 'tree/tree.dart'; |
| 19 import 'util/util.dart' show Link; | 20 import 'util/util.dart' show Link; |
| 20 import 'universe/universe.dart' show CallStructure; | 21 import 'universe/universe.dart' show CallStructure; |
| 21 | 22 |
| 22 /// A [ConstantEnvironment] provides access for constants compiled for variable | 23 /// A [ConstantEnvironment] provides access for constants compiled for variable |
| 23 /// initializers. | 24 /// initializers. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 /// | 60 /// |
| 60 /// If `!enforceConst`, then if [node] is a "runtime constant" (for example | 61 /// If `!enforceConst`, then if [node] is a "runtime constant" (for example |
| 61 /// a reference to a deferred constant) it will be returned - otherwise null | 62 /// a reference to a deferred constant) it will be returned - otherwise null |
| 62 /// is returned. | 63 /// is returned. |
| 63 /// | 64 /// |
| 64 /// Depending on implementation, the constant compiler might also compute | 65 /// Depending on implementation, the constant compiler might also compute |
| 65 /// the constant for the backend interpretation of constants. | 66 /// the constant for the backend interpretation of constants. |
| 66 /// | 67 /// |
| 67 /// The returned constant is always of the frontend interpretation. | 68 /// The returned constant is always of the frontend interpretation. |
| 68 ConstantExpression compileNode(Node node, TreeElements elements, | 69 ConstantExpression compileNode(Node node, TreeElements elements, |
| 69 {bool enforceConst: true}); | 70 {bool enforceConst: true}); |
| 70 | 71 |
| 71 /// Compiles the compile-time constant for the value [metadata], or reports an | 72 /// Compiles the compile-time constant for the value [metadata], or reports an |
| 72 /// error if the value is not a compile-time constant. | 73 /// error if the value is not a compile-time constant. |
| 73 /// | 74 /// |
| 74 /// Depending on implementation, the constant compiler might also compute | 75 /// Depending on implementation, the constant compiler might also compute |
| 75 /// the compile-time constant for the backend interpretation of constants. | 76 /// the compile-time constant for the backend interpretation of constants. |
| 76 /// | 77 /// |
| 77 /// The returned constant is always of the frontend interpretation. | 78 /// The returned constant is always of the frontend interpretation. |
| 78 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 79 ConstantExpression compileMetadata(MetadataAnnotation metadata, |
| 79 Node node, | 80 Node node, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 ConstantValue getConstantValueForVariable(VariableElement element) { | 153 ConstantValue getConstantValueForVariable(VariableElement element) { |
| 153 return getConstantValue(initialVariableValues[element.declaration]); | 154 return getConstantValue(initialVariableValues[element.declaration]); |
| 154 } | 155 } |
| 155 | 156 |
| 156 @override | 157 @override |
| 157 ConstantExpression getConstantForVariable(VariableElement element) { | 158 ConstantExpression getConstantForVariable(VariableElement element) { |
| 158 return initialVariableValues[element.declaration]; | 159 return initialVariableValues[element.declaration]; |
| 159 } | 160 } |
| 160 | 161 |
| 161 ConstantExpression compileConstant(VariableElement element) { | 162 ConstantExpression compileConstant(VariableElement element) { |
| 162 return compileVariable(element, isConst: true); | 163 return internalCompileVariable(element, true, true); |
| 163 } | 164 } |
| 164 | 165 |
| 165 @override | 166 @override |
| 166 void evaluate(ConstantExpression constant) { | 167 void evaluate(ConstantExpression constant) { |
| 167 constantValueMap.putIfAbsent(constant, () { | 168 constantValueMap.putIfAbsent(constant, () { |
| 168 return constant.evaluate( | 169 return constant.evaluate( |
| 169 new _CompilerEnvironment(compiler), | 170 new _CompilerEnvironment(compiler), |
| 170 constantSystem); | 171 constantSystem); |
| 171 }); | 172 }); |
| 172 } | 173 } |
| 173 | 174 |
| 174 ConstantExpression compileVariable(VariableElement element, | 175 ConstantExpression compileVariable(VariableElement element) { |
| 175 {bool isConst: false}) { | 176 return internalCompileVariable(element, false, true); |
| 177 } |
| 176 | 178 |
| 179 /// Compile [element] into a constant expression. If [isConst] is true, |
| 180 /// then [element] is a constant variable. If [checkType] is true, then |
| 181 /// report an error if [element] does not typecheck. |
| 182 ConstantExpression internalCompileVariable( |
| 183 VariableElement element, bool isConst, bool checkType) { |
| 177 if (initialVariableValues.containsKey(element.declaration)) { | 184 if (initialVariableValues.containsKey(element.declaration)) { |
| 178 ConstantExpression result = initialVariableValues[element.declaration]; | 185 ConstantExpression result = initialVariableValues[element.declaration]; |
| 179 return result; | 186 return result; |
| 180 } | 187 } |
| 181 AstElement currentElement = element.analyzableElement; | 188 AstElement currentElement = element.analyzableElement; |
| 182 return compiler.withCurrentElement(currentElement, () { | 189 return compiler.withCurrentElement(currentElement, () { |
| 183 // TODO(johnniwinther): Avoid this eager analysis. | 190 // TODO(johnniwinther): Avoid this eager analysis. |
| 184 _analyzeElementEagerly(compiler, currentElement); | 191 _analyzeElementEagerly(compiler, currentElement); |
| 185 | 192 |
| 186 ConstantExpression constant = compileVariableWithDefinitions( | 193 ConstantExpression constant = compileVariableWithDefinitions( |
| 187 element, currentElement.resolvedAst.elements, isConst: isConst); | 194 element, currentElement.resolvedAst.elements, |
| 195 isConst: isConst, checkType: checkType); |
| 188 return constant; | 196 return constant; |
| 189 }); | 197 }); |
| 190 } | 198 } |
| 191 | 199 |
| 192 /** | 200 /** |
| 193 * Returns the a compile-time constant if the variable could be compiled | 201 * Returns the a compile-time constant if the variable could be compiled |
| 194 * eagerly. If the variable needs to be initialized lazily returns `null`. | 202 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 195 * If the variable is `const` but cannot be compiled eagerly reports an | 203 * If the variable is `const` but cannot be compiled eagerly reports an |
| 196 * error. | 204 * error. |
| 197 */ | 205 */ |
| 198 ConstantExpression compileVariableWithDefinitions(VariableElement element, | 206 ConstantExpression compileVariableWithDefinitions( |
| 199 TreeElements definitions, | 207 VariableElement element, TreeElements definitions, |
| 200 {bool isConst: false}) { | 208 {bool isConst: false, bool checkType: true}) { |
| 201 Node node = element.node; | 209 Node node = element.node; |
| 202 if (pendingVariables.contains(element)) { | 210 if (pendingVariables.contains(element)) { |
| 203 if (isConst) { | 211 if (isConst) { |
| 204 compiler.reportError( | 212 compiler.reportError(node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 205 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | |
| 206 ConstantExpression expression = new ErroneousConstantExpression(); | 213 ConstantExpression expression = new ErroneousConstantExpression(); |
| 207 constantValueMap[expression] = constantSystem.createNull(); | 214 constantValueMap[expression] = constantSystem.createNull(); |
| 208 return expression; | 215 return expression; |
| 209 } | 216 } |
| 210 return null; | 217 return null; |
| 211 } | 218 } |
| 212 pendingVariables.add(element); | 219 pendingVariables.add(element); |
| 213 | 220 |
| 214 Expression initializer = element.initializer; | 221 Expression initializer = element.initializer; |
| 215 ConstantExpression expression; | 222 ConstantExpression expression; |
| 216 if (initializer == null) { | 223 if (initializer == null) { |
| 217 // No initial value. | 224 // No initial value. |
| 218 expression = new NullConstantExpression(); | 225 expression = new NullConstantExpression(); |
| 219 constantValueMap[expression] = constantSystem.createNull(); | 226 constantValueMap[expression] = constantSystem.createNull(); |
| 220 } else { | 227 } else { |
| 221 expression = compileNodeWithDefinitions( | 228 expression = compileNodeWithDefinitions(initializer, definitions, |
| 222 initializer, definitions, isConst: isConst); | 229 isConst: isConst); |
| 223 if (compiler.enableTypeAssertions && | 230 if (compiler.enableTypeAssertions && |
| 231 checkType && |
| 224 expression != null && | 232 expression != null && |
| 225 element.isField) { | 233 element.isField) { |
| 226 DartType elementType = element.type; | 234 DartType elementType = element.type; |
| 227 ConstantValue value = getConstantValue(expression); | 235 ConstantValue value = getConstantValue(expression); |
| 228 if (elementType.isMalformed && !value.isNull) { | 236 if (elementType.isMalformed && !value.isNull) { |
| 229 if (isConst) { | 237 if (isConst) { |
| 230 ErroneousElement element = elementType.element; | 238 ErroneousElement element = elementType.element; |
| 231 compiler.reportError( | 239 compiler.reportError( |
| 232 node, element.messageKind, element.messageArguments); | 240 node, element.messageKind, element.messageArguments); |
| 233 } else { | 241 } else { |
| 234 // We need to throw an exception at runtime. | 242 // We need to throw an exception at runtime. |
| 235 expression = null; | 243 expression = null; |
| 236 } | 244 } |
| 237 } else { | 245 } else { |
| 238 DartType constantType = value.getType(compiler.coreTypes); | 246 DartType constantType = value.getType(compiler.coreTypes); |
| 239 if (!constantSystem.isSubtype(compiler.types, | 247 if (!constantSystem.isSubtype( |
| 240 constantType, elementType)) { | 248 compiler.types, constantType, elementType)) { |
| 241 if (isConst) { | 249 if (isConst) { |
| 242 compiler.reportError( | 250 compiler.reportError(node, MessageKind.NOT_ASSIGNABLE, { |
| 243 node, MessageKind.NOT_ASSIGNABLE, | 251 'fromType': constantType, |
| 244 {'fromType': constantType, 'toType': elementType}); | 252 'toType': elementType |
| 253 }); |
| 245 } else { | 254 } else { |
| 246 // If the field cannot be lazily initialized, we will throw | 255 // If the field cannot be lazily initialized, we will throw |
| 247 // the exception at runtime. | 256 // the exception at runtime. |
| 248 expression = null; | 257 expression = null; |
| 249 } | 258 } |
| 250 } | 259 } |
| 251 } | 260 } |
| 252 } | 261 } |
| 253 } | 262 } |
| 254 if (expression != null) { | 263 if (expression != null) { |
| 255 initialVariableValues[element.declaration] = expression; | 264 initialVariableValues[element.declaration] = expression; |
| 256 } else { | 265 } else { |
| 257 assert(invariant(element, !isConst, | 266 assert(invariant(element, !isConst, |
| 258 message: "Variable $element does not compile to a constant.")); | 267 message: "Variable $element does not compile to a constant.")); |
| 259 } | 268 } |
| 260 pendingVariables.remove(element); | 269 pendingVariables.remove(element); |
| 261 return expression; | 270 return expression; |
| 262 } | 271 } |
| 263 | 272 |
| 264 void cacheConstantValue(ConstantExpression expression, ConstantValue value) { | 273 void cacheConstantValue(ConstantExpression expression, ConstantValue value) { |
| 265 constantValueMap[expression] = value; | 274 constantValueMap[expression] = value; |
| 266 } | 275 } |
| 267 | 276 |
| 268 ConstantExpression compileNodeWithDefinitions(Node node, | 277 ConstantExpression compileNodeWithDefinitions( |
| 269 TreeElements definitions, | 278 Node node, TreeElements definitions, {bool isConst: true}) { |
| 270 {bool isConst: true}) { | |
| 271 assert(node != null); | 279 assert(node != null); |
| 272 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 280 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 273 this, definitions, compiler, isConst: isConst); | 281 this, definitions, compiler, isConst: isConst); |
| 274 AstConstant constant = evaluator.evaluate(node); | 282 AstConstant constant = evaluator.evaluate(node); |
| 275 if (constant != null) { | 283 if (constant != null) { |
| 276 cacheConstantValue(constant.expression, constant.value); | 284 cacheConstantValue(constant.expression, constant.value); |
| 277 return constant.expression; | 285 return constant.expression; |
| 278 } | 286 } |
| 279 return null; | 287 return null; |
| 280 } | 288 } |
| 281 | 289 |
| 282 ConstantValue getConstantValue(ConstantExpression expression) { | 290 ConstantValue getConstantValue(ConstantExpression expression) { |
| 283 return constantValueMap[expression]; | 291 return constantValueMap[expression]; |
| 284 } | 292 } |
| 285 | 293 |
| 286 ConstantExpression compileNode(Node node, TreeElements elements, | 294 ConstantExpression compileNode(Node node, TreeElements elements, |
| 287 {bool enforceConst: true}) { | 295 {bool enforceConst: true}) { |
| 288 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); | 296 return compileNodeWithDefinitions(node, elements, isConst: enforceConst); |
| 289 } | 297 } |
| 290 | 298 |
| 291 ConstantExpression compileMetadata(MetadataAnnotation metadata, | 299 ConstantExpression compileMetadata( |
| 292 Node node, | 300 MetadataAnnotation metadata, Node node, TreeElements elements) { |
| 293 TreeElements elements) { | |
| 294 return compileNodeWithDefinitions(node, elements); | 301 return compileNodeWithDefinitions(node, elements); |
| 295 } | 302 } |
| 296 | 303 |
| 297 void forgetElement(Element element) { | 304 void forgetElement(Element element) { |
| 298 initialVariableValues.remove(element); | 305 initialVariableValues.remove(element); |
| 299 if (element is ScopeContainerElement) { | 306 if (element is ScopeContainerElement) { |
| 300 element.forEachLocalMember(initialVariableValues.remove); | 307 element.forEachLocalMember(initialVariableValues.remove); |
| 301 } | 308 } |
| 302 if (element is FunctionElement && element.hasFunctionSignature) { | 309 if (element is FunctionElement && element.hasFunctionSignature) { |
| 303 element.functionSignature.forEachParameter(this.forgetElement); | 310 element.functionSignature.forEachParameter(this.forgetElement); |
| 304 } | 311 } |
| 305 } | 312 } |
| 306 } | 313 } |
| 307 | 314 |
| 308 /// [ConstantCompiler] that uses the Dart semantics for the compile-time | 315 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
| 309 /// constant evaluation. | 316 /// constant evaluation. |
| 310 class DartConstantCompiler extends ConstantCompilerBase { | 317 class DartConstantCompiler extends ConstantCompilerBase { |
| 311 DartConstantCompiler(Compiler compiler) | 318 DartConstantCompiler(Compiler compiler) |
| 312 : super(compiler, const DartConstantSystem()); | 319 : super(compiler, const DartConstantSystem()); |
| 313 | 320 |
| 314 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { | 321 ConstantExpression getConstantForNode(Node node, TreeElements definitions) { |
| 315 return definitions.getConstant(node); | 322 return definitions.getConstant(node); |
| 316 } | 323 } |
| 317 | 324 |
| 318 ConstantExpression compileNodeWithDefinitions(Node node, | 325 ConstantExpression compileNodeWithDefinitions( |
| 319 TreeElements definitions, | 326 Node node, TreeElements definitions, {bool isConst: true}) { |
| 320 {bool isConst: true}) { | |
| 321 ConstantExpression constant = definitions.getConstant(node); | 327 ConstantExpression constant = definitions.getConstant(node); |
| 322 if (constant != null && getConstantValue(constant) != null) { | 328 if (constant != null && getConstantValue(constant) != null) { |
| 323 return constant; | 329 return constant; |
| 324 } | 330 } |
| 325 constant = | 331 constant = |
| 326 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); | 332 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| 327 if (constant != null) { | 333 if (constant != null) { |
| 328 definitions.setConstant(node, constant); | 334 definitions.setConstant(node, constant); |
| 329 } | 335 } |
| 330 return constant; | 336 return constant; |
| 331 } | 337 } |
| 332 } | 338 } |
| 333 | 339 |
| 334 // TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from | 340 // TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from |
| 335 // front-end AST in order to reuse the evaluation for the shared front-end. | 341 // front-end AST in order to reuse the evaluation for the shared front-end. |
| 336 class CompileTimeConstantEvaluator extends Visitor<AstConstant> { | 342 class CompileTimeConstantEvaluator extends Visitor<AstConstant> { |
| 337 bool isEvaluatingConstant; | 343 bool isEvaluatingConstant; |
| 338 final ConstantCompilerBase handler; | 344 final ConstantCompilerBase handler; |
| 339 final TreeElements elements; | 345 final TreeElements elements; |
| 340 final Compiler compiler; | 346 final Compiler compiler; |
| 341 | 347 |
| 342 Element get context => elements.analyzedElement; | 348 Element get context => elements.analyzedElement; |
| 343 | 349 |
| 344 CompileTimeConstantEvaluator(this.handler, | 350 CompileTimeConstantEvaluator(this.handler, this.elements, this.compiler, |
| 345 this.elements, | 351 {bool isConst: false}) |
| 346 this.compiler, | |
| 347 {bool isConst: false}) | |
| 348 : this.isEvaluatingConstant = isConst; | 352 : this.isEvaluatingConstant = isConst; |
| 349 | 353 |
| 350 ConstantSystem get constantSystem => handler.constantSystem; | 354 ConstantSystem get constantSystem => handler.constantSystem; |
| 351 | 355 |
| 352 AstConstant evaluate(Node node) { | 356 AstConstant evaluate(Node node) { |
| 353 // TODO(johnniwinther): should there be a visitErrorNode? | 357 // TODO(johnniwinther): should there be a visitErrorNode? |
| 354 if (node is ErrorNode) return new ErroneousAstConstant(context, node); | 358 if (node is ErrorNode) return new ErroneousAstConstant(context, node); |
| 355 return node.accept(this); | 359 return node.accept(this); |
| 356 } | 360 } |
| 357 | 361 |
| 358 AstConstant evaluateConstant(Node node) { | 362 AstConstant evaluateConstant(Node node) { |
| 359 bool oldIsEvaluatingConstant = isEvaluatingConstant; | 363 bool oldIsEvaluatingConstant = isEvaluatingConstant; |
| 360 isEvaluatingConstant = true; | 364 isEvaluatingConstant = true; |
| 361 AstConstant result = node.accept(this); | 365 AstConstant result = node.accept(this); |
| 362 isEvaluatingConstant = oldIsEvaluatingConstant; | 366 isEvaluatingConstant = oldIsEvaluatingConstant; |
| 363 assert(result != null); | 367 assert(result != null); |
| 364 return result; | 368 return result; |
| 365 } | 369 } |
| 366 | 370 |
| 367 AstConstant visitNode(Node node) { | 371 AstConstant visitNode(Node node) { |
| 368 return signalNotCompileTimeConstant(node); | 372 return signalNotCompileTimeConstant(node); |
| 369 } | 373 } |
| 370 | 374 |
| 371 AstConstant visitLiteralBool(LiteralBool node) { | 375 AstConstant visitLiteralBool(LiteralBool node) { |
| 372 return new AstConstant( | 376 return new AstConstant(context, node, |
| 373 context, | |
| 374 node, | |
| 375 new BoolConstantExpression(node.value), | 377 new BoolConstantExpression(node.value), |
| 376 constantSystem.createBool(node.value)); | 378 constantSystem.createBool(node.value)); |
| 377 } | 379 } |
| 378 | 380 |
| 379 AstConstant visitLiteralDouble(LiteralDouble node) { | 381 AstConstant visitLiteralDouble(LiteralDouble node) { |
| 380 return new AstConstant( | 382 return new AstConstant(context, node, |
| 381 context, | |
| 382 node, | |
| 383 new DoubleConstantExpression(node.value), | 383 new DoubleConstantExpression(node.value), |
| 384 constantSystem.createDouble(node.value)); | 384 constantSystem.createDouble(node.value)); |
| 385 } | 385 } |
| 386 | 386 |
| 387 AstConstant visitLiteralInt(LiteralInt node) { | 387 AstConstant visitLiteralInt(LiteralInt node) { |
| 388 return new AstConstant( | 388 return new AstConstant(context, node, new IntConstantExpression(node.value), |
| 389 context, | |
| 390 node, | |
| 391 new IntConstantExpression(node.value), | |
| 392 constantSystem.createInt(node.value)); | 389 constantSystem.createInt(node.value)); |
| 393 } | 390 } |
| 394 | 391 |
| 395 AstConstant visitLiteralList(LiteralList node) { | 392 AstConstant visitLiteralList(LiteralList node) { |
| 396 if (!node.isConst) { | 393 if (!node.isConst) { |
| 397 return signalNotCompileTimeConstant(node); | 394 return signalNotCompileTimeConstant(node); |
| 398 } | 395 } |
| 399 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; | 396 List<ConstantExpression> argumentExpressions = <ConstantExpression>[]; |
| 400 List<ConstantValue> argumentValues = <ConstantValue>[]; | 397 List<ConstantValue> argumentValues = <ConstantValue>[]; |
| 401 for (Link<Node> link = node.elements.nodes; | 398 for (Link<Node> link = node.elements.nodes; |
| 402 !link.isEmpty; | 399 !link.isEmpty; |
| 403 link = link.tail) { | 400 link = link.tail) { |
| 404 AstConstant argument = evaluateConstant(link.head); | 401 AstConstant argument = evaluateConstant(link.head); |
| 405 if (argument == null) { | 402 if (argument == null) { |
| 406 return null; | 403 return null; |
| 407 } | 404 } |
| 408 argumentExpressions.add(argument.expression); | 405 argumentExpressions.add(argument.expression); |
| 409 argumentValues.add(argument.value); | 406 argumentValues.add(argument.value); |
| 410 } | 407 } |
| 411 DartType type = elements.getType(node); | 408 DartType type = elements.getType(node); |
| 412 return new AstConstant( | 409 return new AstConstant(context, node, |
| 413 context, | |
| 414 node, | |
| 415 new ListConstantExpression(type, argumentExpressions), | 410 new ListConstantExpression(type, argumentExpressions), |
| 416 constantSystem.createList(type, argumentValues)); | 411 constantSystem.createList(type, argumentValues)); |
| 417 } | 412 } |
| 418 | 413 |
| 419 AstConstant visitLiteralMap(LiteralMap node) { | 414 AstConstant visitLiteralMap(LiteralMap node) { |
| 420 if (!node.isConst) { | 415 if (!node.isConst) { |
| 421 return signalNotCompileTimeConstant(node); | 416 return signalNotCompileTimeConstant(node); |
| 422 } | 417 } |
| 423 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; | 418 List<ConstantExpression> keyExpressions = <ConstantExpression>[]; |
| 424 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; | 419 List<ConstantExpression> valueExpressions = <ConstantExpression>[]; |
| 425 List<ConstantValue> keyValues = <ConstantValue>[]; | 420 List<ConstantValue> keyValues = <ConstantValue>[]; |
| 426 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; | 421 Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; |
| 427 for (Link<Node> link = node.entries.nodes; | 422 for (Link<Node> link = node.entries.nodes; |
| 428 !link.isEmpty; | 423 !link.isEmpty; |
| 429 link = link.tail) { | 424 link = link.tail) { |
| 430 LiteralMapEntry entry = link.head; | 425 LiteralMapEntry entry = link.head; |
| 431 AstConstant key = evaluateConstant(entry.key); | 426 AstConstant key = evaluateConstant(entry.key); |
| 432 if (key == null) { | 427 if (key == null) { |
| 433 return null; | 428 return null; |
| 434 } | 429 } |
| 435 AstConstant value = evaluateConstant(entry.value); | 430 AstConstant value = evaluateConstant(entry.value); |
| 436 if (value == null) { | 431 if (value == null) { |
| 437 return null; | 432 return null; |
| 438 } | 433 } |
| 439 if (!map.containsKey(key.value)) { | 434 if (!map.containsKey(key.value)) { |
| 440 keyValues.add(key.value); | 435 keyValues.add(key.value); |
| 441 } else { | 436 } else { |
| 442 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); | 437 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); |
| 443 } | 438 } |
| 444 keyExpressions.add(key.expression); | 439 keyExpressions.add(key.expression); |
| 445 valueExpressions.add(value.expression); | 440 valueExpressions.add(value.expression); |
| 446 map[key.value] = value.value; | 441 map[key.value] = value.value; |
| 447 } | 442 } |
| 448 InterfaceType type = elements.getType(node); | 443 InterfaceType type = elements.getType(node); |
| 449 return new AstConstant( | 444 return new AstConstant(context, node, |
| 450 context, | 445 new MapConstantExpression(type, keyExpressions, valueExpressions), |
| 451 node, | |
| 452 new MapConstantExpression( | |
| 453 type, | |
| 454 keyExpressions, | |
| 455 valueExpressions), | |
| 456 constantSystem.createMap( | 446 constantSystem.createMap( |
| 457 compiler, type, keyValues, map.values.toList())); | 447 compiler, type, keyValues, map.values.toList())); |
| 458 } | 448 } |
| 459 | 449 |
| 460 AstConstant visitLiteralNull(LiteralNull node) { | 450 AstConstant visitLiteralNull(LiteralNull node) { |
| 461 return new AstConstant( | 451 return new AstConstant(context, node, new NullConstantExpression(), |
| 462 context, | |
| 463 node, | |
| 464 new NullConstantExpression(), | |
| 465 constantSystem.createNull()); | 452 constantSystem.createNull()); |
| 466 } | 453 } |
| 467 | 454 |
| 468 AstConstant visitLiteralString(LiteralString node) { | 455 AstConstant visitLiteralString(LiteralString node) { |
| 469 return new AstConstant( | 456 return new AstConstant(context, node, |
| 470 context, | |
| 471 node, | |
| 472 new StringConstantExpression(node.dartString.slowToString()), | 457 new StringConstantExpression(node.dartString.slowToString()), |
| 473 constantSystem.createString(node.dartString)); | 458 constantSystem.createString(node.dartString)); |
| 474 } | 459 } |
| 475 | 460 |
| 476 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { | 461 AstConstant visitStringJuxtaposition(StringJuxtaposition node) { |
| 477 AstConstant left = evaluate(node.first); | 462 AstConstant left = evaluate(node.first); |
| 478 AstConstant right = evaluate(node.second); | 463 AstConstant right = evaluate(node.second); |
| 479 if (left == null || right == null) return null; | 464 if (left == null || right == null) return null; |
| 480 StringConstantValue leftValue = left.value; | 465 StringConstantValue leftValue = left.value; |
| 481 StringConstantValue rightValue = right.value; | 466 StringConstantValue rightValue = right.value; |
| 482 return new AstConstant( | 467 return new AstConstant(context, node, |
| 483 context, | |
| 484 node, | |
| 485 new ConcatenateConstantExpression([left.expression, right.expression]), | 468 new ConcatenateConstantExpression([left.expression, right.expression]), |
| 486 constantSystem.createString( | 469 constantSystem.createString(new DartString.concat( |
| 487 new DartString.concat( | 470 leftValue.primitiveValue, rightValue.primitiveValue))); |
| 488 leftValue.primitiveValue, rightValue.primitiveValue))); | |
| 489 } | 471 } |
| 490 | 472 |
| 491 AstConstant visitStringInterpolation(StringInterpolation node) { | 473 AstConstant visitStringInterpolation(StringInterpolation node) { |
| 492 List<ConstantExpression> subexpressions = <ConstantExpression>[]; | 474 List<ConstantExpression> subexpressions = <ConstantExpression>[]; |
| 493 AstConstant initialString = evaluate(node.string); | 475 AstConstant initialString = evaluate(node.string); |
| 494 if (initialString == null) { | 476 if (initialString == null) { |
| 495 return null; | 477 return null; |
| 496 } | 478 } |
| 497 subexpressions.add(initialString.expression); | 479 subexpressions.add(initialString.expression); |
| 498 StringConstantValue initialStringValue = initialString.value; | 480 StringConstantValue initialStringValue = initialString.value; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 517 // is not constness but the types of the const expressions. | 499 // is not constness but the types of the const expressions. |
| 518 return signalNotCompileTimeConstant(part.expression); | 500 return signalNotCompileTimeConstant(part.expression); |
| 519 } | 501 } |
| 520 accumulator = new DartString.concat(accumulator, expressionString); | 502 accumulator = new DartString.concat(accumulator, expressionString); |
| 521 AstConstant partString = evaluate(part.string); | 503 AstConstant partString = evaluate(part.string); |
| 522 if (partString == null) return null; | 504 if (partString == null) return null; |
| 523 subexpressions.add(partString.expression); | 505 subexpressions.add(partString.expression); |
| 524 StringConstantValue partStringValue = partString.value; | 506 StringConstantValue partStringValue = partString.value; |
| 525 accumulator = | 507 accumulator = |
| 526 new DartString.concat(accumulator, partStringValue.primitiveValue); | 508 new DartString.concat(accumulator, partStringValue.primitiveValue); |
| 527 }; | 509 } |
| 528 return new AstConstant( | 510 ; |
| 529 context, | 511 return new AstConstant(context, node, |
| 530 node, | |
| 531 new ConcatenateConstantExpression(subexpressions), | 512 new ConcatenateConstantExpression(subexpressions), |
| 532 constantSystem.createString(accumulator)); | 513 constantSystem.createString(accumulator)); |
| 533 } | 514 } |
| 534 | 515 |
| 535 AstConstant visitLiteralSymbol(LiteralSymbol node) { | 516 AstConstant visitLiteralSymbol(LiteralSymbol node) { |
| 536 InterfaceType type = compiler.symbolClass.rawType; | 517 InterfaceType type = compiler.symbolClass.rawType; |
| 537 String text = node.slowNameString; | 518 String text = node.slowNameString; |
| 538 List<AstConstant> arguments = | 519 List<AstConstant> arguments = <AstConstant>[ |
| 539 <AstConstant>[new AstConstant( | 520 new AstConstant(context, node, new StringConstantExpression(text), |
| 540 context, | 521 constantSystem.createString(new LiteralDartString(text))) |
| 541 node, | 522 ]; |
| 542 new StringConstantExpression(text), | |
| 543 constantSystem.createString(new LiteralDartString(text)))]; | |
| 544 ConstructorElement constructor = compiler.symbolConstructor; | 523 ConstructorElement constructor = compiler.symbolConstructor; |
| 545 AstConstant constant = createConstructorInvocation( | 524 AstConstant constant = createConstructorInvocation( |
| 546 node, type, constructor, CallStructure.ONE_ARG, | 525 node, type, constructor, CallStructure.ONE_ARG, |
| 547 normalizedArguments: arguments); | 526 normalizedArguments: arguments); |
| 548 return new AstConstant( | 527 return new AstConstant( |
| 549 context, node, new SymbolConstantExpression(text), constant.value); | 528 context, node, new SymbolConstantExpression(text), constant.value); |
| 550 } | 529 } |
| 551 | 530 |
| 552 ConstantValue makeTypeConstant(DartType elementType) { | 531 ConstantValue makeTypeConstant(DartType elementType) { |
| 553 return constantSystem.createType(compiler, elementType); | 532 return constantSystem.createType(compiler, elementType); |
| 554 } | 533 } |
| 555 | 534 |
| 556 /// Returns true if the prefix of the send resolves to a deferred import | 535 /// Returns true if the prefix of the send resolves to a deferred import |
| 557 /// prefix. | 536 /// prefix. |
| 558 bool isDeferredUse(Send send) { | 537 bool isDeferredUse(Send send) { |
| 559 if (send == null) return false; | 538 if (send == null) return false; |
| 560 return compiler.deferredLoadTask | 539 return compiler.deferredLoadTask.deferredPrefixElement(send, elements) != |
| 561 .deferredPrefixElement(send, elements) != null; | 540 null; |
| 562 } | 541 } |
| 563 | 542 |
| 564 AstConstant visitIdentifier(Identifier node) { | 543 AstConstant visitIdentifier(Identifier node) { |
| 565 Element element = elements[node]; | 544 Element element = elements[node]; |
| 566 if (Elements.isClass(element) || Elements.isTypedef(element)) { | 545 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 567 TypeDeclarationElement typeDeclarationElement = element; | 546 TypeDeclarationElement typeDeclarationElement = element; |
| 568 DartType type = typeDeclarationElement.rawType; | 547 DartType type = typeDeclarationElement.rawType; |
| 569 return new AstConstant(element, node, | 548 return new AstConstant(element, node, new TypeConstantExpression(type), |
| 570 new TypeConstantExpression(type), makeTypeConstant(type)); | 549 makeTypeConstant(type)); |
| 571 } | 550 } |
| 572 return signalNotCompileTimeConstant(node); | 551 return signalNotCompileTimeConstant(node); |
| 573 } | 552 } |
| 574 | 553 |
| 575 // TODO(floitsch): provide better error-messages. | 554 // TODO(floitsch): provide better error-messages. |
| 576 AstConstant visitSend(Send send) { | 555 AstConstant visitSend(Send send) { |
| 577 Element element = elements[send]; | 556 Element element = elements[send]; |
| 578 if (send.isPropertyAccess) { | 557 if (send.isPropertyAccess) { |
| 579 AstConstant result; | 558 AstConstant result; |
| 580 if (Elements.isStaticOrTopLevelFunction(element)) { | 559 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 581 FunctionElementX function = element; | 560 FunctionElementX function = element; |
| 582 function.computeType(compiler); | 561 function.computeType(compiler); |
| 583 result = new AstConstant( | 562 result = new AstConstant(context, send, |
| 584 context, | |
| 585 send, | |
| 586 new FunctionConstantExpression(function), | 563 new FunctionConstantExpression(function), |
| 587 new FunctionConstantValue(function)); | 564 new FunctionConstantValue(function)); |
| 588 } else if (Elements.isStaticOrTopLevelField(element)) { | 565 } else if (Elements.isStaticOrTopLevelField(element)) { |
| 589 ConstantExpression elementExpression; | 566 ConstantExpression elementExpression; |
| 590 if (element.isConst) { | 567 if (element.isConst) { |
| 591 elementExpression = handler.compileConstant(element); | 568 elementExpression = handler.compileConstant(element); |
| 592 } else if (element.isFinal && !isEvaluatingConstant) { | 569 } else if (element.isFinal && !isEvaluatingConstant) { |
| 593 elementExpression = handler.compileVariable(element); | 570 elementExpression = handler.compileVariable(element); |
| 594 } | 571 } |
| 595 if (elementExpression != null) { | 572 if (elementExpression != null) { |
| 596 result = new AstConstant( | 573 result = new AstConstant(context, send, |
| 597 context, | |
| 598 send, | |
| 599 new VariableConstantExpression(element), | 574 new VariableConstantExpression(element), |
| 600 handler.getConstantValue(elementExpression)); | 575 handler.getConstantValue(elementExpression)); |
| 601 } | 576 } |
| 602 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 577 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 603 assert(elements.isTypeLiteral(send)); | 578 assert(elements.isTypeLiteral(send)); |
| 604 DartType elementType = elements.getTypeLiteralType(send); | 579 DartType elementType = elements.getTypeLiteralType(send); |
| 605 result = new AstConstant( | 580 result = new AstConstant(context, send, |
| 606 context, | |
| 607 send, | |
| 608 new TypeConstantExpression(elementType), | 581 new TypeConstantExpression(elementType), |
| 609 makeTypeConstant(elementType)); | 582 makeTypeConstant(elementType)); |
| 610 } else if (send.receiver != null) { | 583 } else if (send.receiver != null) { |
| 611 if (send.selector.asIdentifier().source == "length") { | 584 if (send.selector.asIdentifier().source == "length") { |
| 612 AstConstant left = evaluate(send.receiver); | 585 AstConstant left = evaluate(send.receiver); |
| 613 if (left != null && left.value.isString) { | 586 if (left != null && left.value.isString) { |
| 614 StringConstantValue stringConstantValue = left.value; | 587 StringConstantValue stringConstantValue = left.value; |
| 615 DartString string = stringConstantValue.primitiveValue; | 588 DartString string = stringConstantValue.primitiveValue; |
| 616 IntConstantValue length = constantSystem.createInt(string.length); | 589 IntConstantValue length = constantSystem.createInt(string.length); |
| 617 result = new AstConstant( | 590 result = new AstConstant(context, send, |
| 618 context, | 591 new StringLengthConstantExpression(left.expression), length); |
| 619 send, | |
| 620 new StringLengthConstantExpression(left.expression), | |
| 621 length); | |
| 622 } | 592 } |
| 623 } | 593 } |
| 624 // Fall through to error handling. | 594 // Fall through to error handling. |
| 625 } else if (!Elements.isUnresolved(element) | 595 } else if (!Elements.isUnresolved(element) && |
| 626 && element.isVariable | 596 element.isVariable && |
| 627 && element.isConst) { | 597 element.isConst) { |
| 628 ConstantExpression variableExpression = | 598 ConstantExpression variableExpression = |
| 629 handler.compileConstant(element); | 599 handler.compileConstant(element); |
| 630 if (variableExpression != null) { | 600 if (variableExpression != null) { |
| 631 result = new AstConstant( | 601 result = new AstConstant(context, send, |
| 632 context, | |
| 633 send, | |
| 634 new VariableConstantExpression(element), | 602 new VariableConstantExpression(element), |
| 635 handler.getConstantValue(variableExpression)); | 603 handler.getConstantValue(variableExpression)); |
| 636 } | 604 } |
| 637 } | 605 } |
| 638 if (result == null) { | 606 if (result == null) { |
| 639 return signalNotCompileTimeConstant(send); | 607 return signalNotCompileTimeConstant(send); |
| 640 } | 608 } |
| 641 if (isDeferredUse(send)) { | 609 if (isDeferredUse(send)) { |
| 642 if (isEvaluatingConstant) { | 610 if (isEvaluatingConstant) { |
| 643 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 611 error(send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
| 644 } | 612 } |
| 645 PrefixElement prefix = compiler.deferredLoadTask | 613 PrefixElement prefix = |
| 646 .deferredPrefixElement(send, elements); | 614 compiler.deferredLoadTask.deferredPrefixElement(send, elements); |
| 647 result = new AstConstant( | 615 result = new AstConstant(context, send, |
| 648 context, | 616 new DeferredConstantExpression(result.expression, prefix), |
| 649 send, | |
| 650 new DeferredConstantExpression( | |
| 651 result.expression, | |
| 652 prefix), | |
| 653 new DeferredConstantValue(result.value, prefix)); | 617 new DeferredConstantValue(result.value, prefix)); |
| 654 compiler.deferredLoadTask | 618 compiler.deferredLoadTask.registerConstantDeferredUse( |
| 655 .registerConstantDeferredUse(result.value, prefix); | 619 result.value, prefix); |
| 656 } | 620 } |
| 657 return result; | 621 return result; |
| 658 } else if (send.isCall) { | 622 } else if (send.isCall) { |
| 659 if (element == compiler.identicalFunction | 623 if (element == compiler.identicalFunction && send.argumentCount() == 2) { |
| 660 && send.argumentCount() == 2) { | |
| 661 AstConstant left = evaluate(send.argumentsNode.nodes.head); | 624 AstConstant left = evaluate(send.argumentsNode.nodes.head); |
| 662 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); | 625 AstConstant right = evaluate(send.argumentsNode.nodes.tail.head); |
| 663 if (left == null || right == null) { | 626 if (left == null || right == null) { |
| 664 return null; | 627 return null; |
| 665 } | 628 } |
| 666 ConstantValue result = | 629 ConstantValue result = |
| 667 constantSystem.identity.fold(left.value, right.value); | 630 constantSystem.identity.fold(left.value, right.value); |
| 668 if (result != null) { | 631 if (result != null) { |
| 669 return new AstConstant( | 632 return new AstConstant(context, send, new IdenticalConstantExpression( |
| 670 context, | 633 left.expression, right.expression), result); |
| 671 send, | |
| 672 new IdenticalConstantExpression( | |
| 673 left.expression, right.expression), | |
| 674 result); | |
| 675 } | 634 } |
| 676 } | 635 } |
| 677 return signalNotCompileTimeConstant(send); | 636 return signalNotCompileTimeConstant(send); |
| 678 } else if (send.isPrefix) { | 637 } else if (send.isPrefix) { |
| 679 assert(send.isOperator); | 638 assert(send.isOperator); |
| 680 AstConstant receiverConstant = evaluate(send.receiver); | 639 AstConstant receiverConstant = evaluate(send.receiver); |
| 681 if (receiverConstant == null) { | 640 if (receiverConstant == null) { |
| 682 return null; | 641 return null; |
| 683 } | 642 } |
| 684 Operator node = send.selector; | 643 Operator node = send.selector; |
| 685 UnaryOperator operator = UnaryOperator.parse(node.source); | 644 UnaryOperator operator = UnaryOperator.parse(node.source); |
| 686 UnaryOperation operation = constantSystem.lookupUnary(operator); | 645 UnaryOperation operation = constantSystem.lookupUnary(operator); |
| 687 if (operation == null) { | 646 if (operation == null) { |
| 688 compiler.internalError(send.selector, "Unexpected operator."); | 647 compiler.internalError(send.selector, "Unexpected operator."); |
| 689 } | 648 } |
| 690 ConstantValue folded = operation.fold(receiverConstant.value); | 649 ConstantValue folded = operation.fold(receiverConstant.value); |
| 691 if (folded == null) { | 650 if (folded == null) { |
| 692 return signalNotCompileTimeConstant(send); | 651 return signalNotCompileTimeConstant(send); |
| 693 } | 652 } |
| 694 return new AstConstant( | 653 return new AstConstant(context, send, |
| 695 context, | 654 new UnaryConstantExpression(operator, receiverConstant.expression), |
| 696 send, | |
| 697 new UnaryConstantExpression( | |
| 698 operator, receiverConstant.expression), | |
| 699 folded); | 655 folded); |
| 700 } else if (send.isOperator && !send.isPostfix) { | 656 } else if (send.isOperator && !send.isPostfix) { |
| 701 assert(send.argumentCount() == 1); | 657 assert(send.argumentCount() == 1); |
| 702 AstConstant left = evaluate(send.receiver); | 658 AstConstant left = evaluate(send.receiver); |
| 703 AstConstant right = evaluate(send.argumentsNode.nodes.head); | 659 AstConstant right = evaluate(send.argumentsNode.nodes.head); |
| 704 if (left == null || right == null) { | 660 if (left == null || right == null) { |
| 705 return null; | 661 return null; |
| 706 } | 662 } |
| 707 ConstantValue leftValue = left.value; | 663 ConstantValue leftValue = left.value; |
| 708 ConstantValue rightValue = right.value; | 664 ConstantValue rightValue = right.value; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 731 default: | 687 default: |
| 732 BinaryOperation operation = constantSystem.lookupBinary(operator); | 688 BinaryOperation operation = constantSystem.lookupBinary(operator); |
| 733 if (operation != null) { | 689 if (operation != null) { |
| 734 folded = operation.fold(leftValue, rightValue); | 690 folded = operation.fold(leftValue, rightValue); |
| 735 } | 691 } |
| 736 } | 692 } |
| 737 } | 693 } |
| 738 if (folded == null) { | 694 if (folded == null) { |
| 739 return signalNotCompileTimeConstant(send); | 695 return signalNotCompileTimeConstant(send); |
| 740 } | 696 } |
| 741 return new AstConstant( | 697 return new AstConstant(context, send, new BinaryConstantExpression( |
| 742 context, | 698 left.expression, operator, right.expression), folded); |
| 743 send, | |
| 744 new BinaryConstantExpression( | |
| 745 left.expression, operator, right.expression), | |
| 746 folded); | |
| 747 } | 699 } |
| 748 return signalNotCompileTimeConstant(send); | 700 return signalNotCompileTimeConstant(send); |
| 749 } | 701 } |
| 750 | 702 |
| 751 AstConstant visitConditional(Conditional node) { | 703 AstConstant visitConditional(Conditional node) { |
| 752 AstConstant condition = evaluate(node.condition); | 704 AstConstant condition = evaluate(node.condition); |
| 753 if (condition == null) { | 705 if (condition == null) { |
| 754 return null; | 706 return null; |
| 755 } else if (!condition.value.isBool) { | 707 } else if (!condition.value.isBool) { |
| 756 DartType conditionType = condition.value.getType(compiler.coreTypes); | 708 DartType conditionType = condition.value.getType(compiler.coreTypes); |
| 757 if (isEvaluatingConstant) { | 709 if (isEvaluatingConstant) { |
| 758 compiler.reportError( | 710 compiler.reportError(node.condition, MessageKind.NOT_ASSIGNABLE, { |
| 759 node.condition, MessageKind.NOT_ASSIGNABLE, | 711 'fromType': conditionType, |
| 760 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); | 712 'toType': compiler.boolClass.rawType |
| 713 }); |
| 761 return new ErroneousAstConstant(context, node); | 714 return new ErroneousAstConstant(context, node); |
| 762 } | 715 } |
| 763 return null; | 716 return null; |
| 764 } | 717 } |
| 765 AstConstant thenExpression = evaluate(node.thenExpression); | 718 AstConstant thenExpression = evaluate(node.thenExpression); |
| 766 AstConstant elseExpression = evaluate(node.elseExpression); | 719 AstConstant elseExpression = evaluate(node.elseExpression); |
| 767 if (thenExpression == null || elseExpression == null) { | 720 if (thenExpression == null || elseExpression == null) { |
| 768 return null; | 721 return null; |
| 769 } | 722 } |
| 770 BoolConstantValue boolCondition = condition.value; | 723 BoolConstantValue boolCondition = condition.value; |
| 771 return new AstConstant( | 724 return new AstConstant(context, node, new ConditionalConstantExpression( |
| 772 context, | 725 condition.expression, thenExpression.expression, |
| 773 node, | 726 elseExpression.expression), boolCondition.primitiveValue |
| 774 new ConditionalConstantExpression( | 727 ? thenExpression.value |
| 775 condition.expression, | 728 : elseExpression.value); |
| 776 thenExpression.expression, | |
| 777 elseExpression.expression), | |
| 778 boolCondition.primitiveValue | |
| 779 ? thenExpression.value | |
| 780 : elseExpression.value); | |
| 781 } | 729 } |
| 782 | 730 |
| 783 AstConstant visitSendSet(SendSet node) { | 731 AstConstant visitSendSet(SendSet node) { |
| 784 return signalNotCompileTimeConstant(node); | 732 return signalNotCompileTimeConstant(node); |
| 785 } | 733 } |
| 786 | 734 |
| 787 /** | 735 /** |
| 788 * Returns the normalized list of constant arguments that are passed to the | 736 * Returns the normalized list of constant arguments that are passed to the |
| 789 * constructor including both the concrete arguments and default values for | 737 * constructor including both the concrete arguments and default values for |
| 790 * omitted optional arguments. | 738 * omitted optional arguments. |
| 791 * | 739 * |
| 792 * Invariant: [target] must be an implementation element. | 740 * Invariant: [target] must be an implementation element. |
| 793 */ | 741 */ |
| 794 List<AstConstant> evaluateArgumentsToConstructor( | 742 List<AstConstant> evaluateArgumentsToConstructor(Node node, |
| 795 Node node, | 743 CallStructure callStructure, Link<Node> arguments, |
| 796 CallStructure callStructure, | 744 ConstructorElement target, {AstConstant compileArgument(Node node)}) { |
| 797 Link<Node> arguments, | |
| 798 ConstructorElement target, | |
| 799 {AstConstant compileArgument(Node node)}) { | |
| 800 assert(invariant(node, target.isImplementation)); | 745 assert(invariant(node, target.isImplementation)); |
| 801 | 746 |
| 802 AstConstant compileDefaultValue(VariableElement element) { | 747 AstConstant compileDefaultValue(VariableElement element) { |
| 803 ConstantExpression constant = handler.compileConstant(element); | 748 ConstantExpression constant = handler.compileConstant(element); |
| 804 return new AstConstant.fromDefaultValue( | 749 return new AstConstant.fromDefaultValue( |
| 805 element, constant, handler.getConstantValue(constant)); | 750 element, constant, handler.getConstantValue(constant)); |
| 806 } | 751 } |
| 807 target.computeType(compiler); | 752 target.computeType(compiler); |
| 808 | 753 |
| 809 FunctionSignature signature = target.functionSignature; | 754 FunctionSignature signature = target.functionSignature; |
| 810 if (!callStructure.signatureApplies(signature)) { | 755 if (!callStructure.signatureApplies(signature)) { |
| 811 String name = Elements.constructorNameForDiagnostics( | 756 String name = Elements.constructorNameForDiagnostics( |
| 812 target.enclosingClass.name, target.name); | 757 target.enclosingClass.name, target.name); |
| 813 compiler.reportError( | 758 compiler.reportError(node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, { |
| 814 node, | 759 'constructorName': name |
| 815 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, | 760 }); |
| 816 {'constructorName': name}); | |
| 817 | 761 |
| 818 return new List<AstConstant>.filled( | 762 return new List<AstConstant>.filled( |
| 819 target.functionSignature.parameterCount, | 763 target.functionSignature.parameterCount, |
| 820 new ErroneousAstConstant(context, node)); | 764 new ErroneousAstConstant(context, node)); |
| 821 } | 765 } |
| 822 return callStructure.makeArgumentsList( | 766 return callStructure.makeArgumentsList( |
| 823 arguments, | 767 arguments, target, compileArgument, compileDefaultValue); |
| 824 target, | |
| 825 compileArgument, | |
| 826 compileDefaultValue); | |
| 827 } | 768 } |
| 828 | 769 |
| 829 AstConstant visitNewExpression(NewExpression node) { | 770 AstConstant visitNewExpression(NewExpression node) { |
| 830 if (!node.isConst) { | 771 if (!node.isConst) { |
| 831 return signalNotCompileTimeConstant(node); | 772 return signalNotCompileTimeConstant(node); |
| 832 } | 773 } |
| 833 | 774 |
| 834 Send send = node.send; | 775 Send send = node.send; |
| 835 ConstructorElement constructor = elements[send]; | 776 ConstructorElement constructor = elements[send]; |
| 836 if (Elements.isUnresolved(constructor)) { | 777 if (Elements.isUnresolved(constructor)) { |
| 837 return signalNotCompileTimeConstant(node); | 778 return signalNotCompileTimeConstant(node); |
| 838 } | 779 } |
| 839 | 780 |
| 840 // Deferred types can not be used in const instance creation expressions. | 781 // Deferred types can not be used in const instance creation expressions. |
| 841 // Check if the constructor comes from a deferred library. | 782 // Check if the constructor comes from a deferred library. |
| 842 if (isDeferredUse(node.send.selector.asSend())) { | 783 if (isDeferredUse(node.send.selector.asSend())) { |
| 843 return signalNotCompileTimeConstant(node, | 784 return signalNotCompileTimeConstant(node, |
| 844 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); | 785 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); |
| 845 } | 786 } |
| 846 | 787 |
| 847 InterfaceType type = elements.getType(node); | 788 InterfaceType type = elements.getType(node); |
| 848 CallStructure callStructure = elements.getSelector(send).callStructure; | 789 CallStructure callStructure = elements.getSelector(send).callStructure; |
| 849 | 790 |
| 850 return createConstructorInvocation( | 791 return createConstructorInvocation(node, type, constructor, callStructure, |
| 851 node, type, constructor, callStructure, | |
| 852 arguments: node.send.arguments); | 792 arguments: node.send.arguments); |
| 853 } | 793 } |
| 854 | 794 |
| 855 AstConstant createConstructorInvocation( | 795 AstConstant createConstructorInvocation(Node node, InterfaceType type, |
| 856 Node node, | 796 ConstructorElement constructor, CallStructure callStructure, |
| 857 InterfaceType type, | 797 {Link<Node> arguments, List<AstConstant> normalizedArguments}) { |
| 858 ConstructorElement constructor, | |
| 859 CallStructure callStructure, | |
| 860 {Link<Node> arguments, | |
| 861 List<AstConstant> normalizedArguments}) { | |
| 862 // TODO(ahe): This is nasty: we must eagerly analyze the | 798 // TODO(ahe): This is nasty: we must eagerly analyze the |
| 863 // constructor to ensure the redirectionTarget has been computed | 799 // constructor to ensure the redirectionTarget has been computed |
| 864 // correctly. Find a way to avoid this. | 800 // correctly. Find a way to avoid this. |
| 865 _analyzeElementEagerly(compiler, constructor); | 801 _analyzeElementEagerly(compiler, constructor); |
| 866 | 802 |
| 867 // The redirection chain of this element may not have been resolved through | 803 // The redirection chain of this element may not have been resolved through |
| 868 // a post-process action, so we have to make sure it is done here. | 804 // a post-process action, so we have to make sure it is done here. |
| 869 compiler.resolver.resolveRedirectionChain(constructor, node); | 805 compiler.resolver.resolveRedirectionChain(constructor, node); |
| 870 InterfaceType constructedType = | 806 InterfaceType constructedType = |
| 871 constructor.computeEffectiveTargetType(type); | 807 constructor.computeEffectiveTargetType(type); |
| 872 ConstructorElement target = constructor.effectiveTarget; | 808 ConstructorElement target = constructor.effectiveTarget; |
| 873 // The constructor must be an implementation to ensure that field | 809 // The constructor must be an implementation to ensure that field |
| 874 // initializers are handled correctly. | 810 // initializers are handled correctly. |
| 875 ConstructorElement implementation = target.implementation; | 811 ConstructorElement implementation = target.implementation; |
| 876 | 812 |
| 877 if (implementation.isErroneous) { | 813 if (implementation.isErroneous) { |
| 878 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant]. | 814 // TODO(johnniwinther): This should probably be an [ErroneousAstConstant]. |
| 879 return new AstConstant( | 815 return new AstConstant(context, node, new ConstructedConstantExpression( |
| 880 context, | 816 type, constructor, callStructure, const <ConstantExpression>[]), |
| 881 node, | |
| 882 new ConstructedConstantExpression( | |
| 883 type, | |
| 884 constructor, | |
| 885 callStructure, | |
| 886 const <ConstantExpression>[]), | |
| 887 new ConstructedConstantValue( | 817 new ConstructedConstantValue( |
| 888 constructedType, const <FieldElement, ConstantValue>{})); | 818 constructedType, const <FieldElement, ConstantValue>{})); |
| 889 } | 819 } |
| 890 | 820 |
| 891 List<AstConstant> concreteArguments; | 821 List<AstConstant> concreteArguments; |
| 892 if (arguments != null) { | 822 if (arguments != null) { |
| 893 Map<Node, AstConstant> concreteArgumentMap = | 823 Map<Node, AstConstant> concreteArgumentMap = <Node, AstConstant>{}; |
| 894 <Node, AstConstant>{}; | |
| 895 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { | 824 for (Link<Node> link = arguments; !link.isEmpty; link = link.tail) { |
| 896 Node argument = link.head; | 825 Node argument = link.head; |
| 897 NamedArgument namedArgument = argument.asNamedArgument(); | 826 NamedArgument namedArgument = argument.asNamedArgument(); |
| 898 if (namedArgument != null) { | 827 if (namedArgument != null) { |
| 899 argument = namedArgument.expression; | 828 argument = namedArgument.expression; |
| 900 } | 829 } |
| 901 concreteArgumentMap[argument] = evaluateConstant(argument); | 830 concreteArgumentMap[argument] = evaluateConstant(argument); |
| 902 } | 831 } |
| 903 | 832 |
| 904 normalizedArguments = evaluateArgumentsToConstructor( | 833 normalizedArguments = evaluateArgumentsToConstructor( |
| 905 node, callStructure, arguments, implementation, | 834 node, callStructure, arguments, implementation, |
| 906 compileArgument: (node) => concreteArgumentMap[node]); | 835 compileArgument: (node) => concreteArgumentMap[node]); |
| 907 concreteArguments = concreteArgumentMap.values.toList(); | 836 concreteArguments = concreteArgumentMap.values.toList(); |
| 908 } else { | 837 } else { |
| 909 assert(normalizedArguments != null); | 838 assert(normalizedArguments != null); |
| 910 concreteArguments = normalizedArguments; | 839 concreteArguments = normalizedArguments; |
| 911 } | 840 } |
| 912 | 841 |
| 913 if (target == compiler.intEnvironment || | 842 if (target == compiler.intEnvironment || |
| 914 target == compiler.boolEnvironment || | 843 target == compiler.boolEnvironment || |
| 915 target == compiler.stringEnvironment) { | 844 target == compiler.stringEnvironment) { |
| 916 return createFromEnvironmentConstant( | 845 return createFromEnvironmentConstant(node, constructedType, target, |
| 917 node, constructedType, target, | |
| 918 callStructure, normalizedArguments, concreteArguments); | 846 callStructure, normalizedArguments, concreteArguments); |
| 919 } else { | 847 } else { |
| 920 return makeConstructedConstant( | 848 return makeConstructedConstant(compiler, handler, context, node, type, |
| 921 compiler, handler, context, node, | 849 constructor, constructedType, implementation, callStructure, |
| 922 type, constructor, | 850 concreteArguments, normalizedArguments); |
| 923 constructedType, implementation, | |
| 924 callStructure, concreteArguments, normalizedArguments); | |
| 925 } | 851 } |
| 926 } | 852 } |
| 927 | 853 |
| 928 AstConstant createFromEnvironmentConstant( | 854 AstConstant createFromEnvironmentConstant(Node node, InterfaceType type, |
| 929 Node node, | 855 ConstructorElement constructor, CallStructure callStructure, |
| 930 InterfaceType type, | |
| 931 ConstructorElement constructor, | |
| 932 CallStructure callStructure, | |
| 933 List<AstConstant> normalizedArguments, | 856 List<AstConstant> normalizedArguments, |
| 934 List<AstConstant> concreteArguments) { | 857 List<AstConstant> concreteArguments) { |
| 935 | |
| 936 var firstArgument = normalizedArguments[0].value; | 858 var firstArgument = normalizedArguments[0].value; |
| 937 ConstantValue defaultValue = normalizedArguments[1].value; | 859 ConstantValue defaultValue = normalizedArguments[1].value; |
| 938 | 860 |
| 939 if (firstArgument.isNull) { | 861 if (firstArgument.isNull) { |
| 940 compiler.reportError( | 862 compiler.reportError( |
| 941 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); | 863 normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED); |
| 942 return null; | 864 return null; |
| 943 } | 865 } |
| 944 | 866 |
| 945 if (!firstArgument.isString) { | 867 if (!firstArgument.isString) { |
| 946 DartType type = defaultValue.getType(compiler.coreTypes); | 868 DartType type = defaultValue.getType(compiler.coreTypes); |
| 947 compiler.reportError( | 869 compiler.reportError(normalizedArguments[0].node, |
| 948 normalizedArguments[0].node, MessageKind.NOT_ASSIGNABLE, | 870 MessageKind.NOT_ASSIGNABLE, { |
| 949 {'fromType': type, 'toType': compiler.stringClass.rawType}); | 871 'fromType': type, |
| 872 'toType': compiler.stringClass.rawType |
| 873 }); |
| 950 return null; | 874 return null; |
| 951 } | 875 } |
| 952 | 876 |
| 953 if (constructor == compiler.intEnvironment && | 877 if (constructor == compiler.intEnvironment && |
| 954 !(defaultValue.isNull || defaultValue.isInt)) { | 878 !(defaultValue.isNull || defaultValue.isInt)) { |
| 955 DartType type = defaultValue.getType(compiler.coreTypes); | 879 DartType type = defaultValue.getType(compiler.coreTypes); |
| 956 compiler.reportError( | 880 compiler.reportError(normalizedArguments[1].node, |
| 957 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, | 881 MessageKind.NOT_ASSIGNABLE, { |
| 958 {'fromType': type, 'toType': compiler.intClass.rawType}); | 882 'fromType': type, |
| 883 'toType': compiler.intClass.rawType |
| 884 }); |
| 959 return null; | 885 return null; |
| 960 } | 886 } |
| 961 | 887 |
| 962 if (constructor == compiler.boolEnvironment && | 888 if (constructor == compiler.boolEnvironment && |
| 963 !(defaultValue.isNull || defaultValue.isBool)) { | 889 !(defaultValue.isNull || defaultValue.isBool)) { |
| 964 DartType type = defaultValue.getType(compiler.coreTypes); | 890 DartType type = defaultValue.getType(compiler.coreTypes); |
| 965 compiler.reportError( | 891 compiler.reportError(normalizedArguments[1].node, |
| 966 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, | 892 MessageKind.NOT_ASSIGNABLE, { |
| 967 {'fromType': type, 'toType': compiler.boolClass.rawType}); | 893 'fromType': type, |
| 894 'toType': compiler.boolClass.rawType |
| 895 }); |
| 968 return null; | 896 return null; |
| 969 } | 897 } |
| 970 | 898 |
| 971 if (constructor == compiler.stringEnvironment && | 899 if (constructor == compiler.stringEnvironment && |
| 972 !(defaultValue.isNull || defaultValue.isString)) { | 900 !(defaultValue.isNull || defaultValue.isString)) { |
| 973 DartType type = defaultValue.getType(compiler.coreTypes); | 901 DartType type = defaultValue.getType(compiler.coreTypes); |
| 974 compiler.reportError( | 902 compiler.reportError(normalizedArguments[1].node, |
| 975 normalizedArguments[1].node, MessageKind.NOT_ASSIGNABLE, | 903 MessageKind.NOT_ASSIGNABLE, { |
| 976 {'fromType': type, 'toType': compiler.stringClass.rawType}); | 904 'fromType': type, |
| 905 'toType': compiler.stringClass.rawType |
| 906 }); |
| 977 return null; | 907 return null; |
| 978 } | 908 } |
| 979 | 909 |
| 980 String name = | 910 String name = firstArgument.primitiveValue.slowToString(); |
| 981 firstArgument.primitiveValue.slowToString(); | 911 String value = compiler.fromEnvironment(name); |
| 982 String value = | |
| 983 compiler.fromEnvironment(name); | |
| 984 | 912 |
| 985 AstConstant createEvaluatedConstant(ConstantValue value) { | 913 AstConstant createEvaluatedConstant(ConstantValue value) { |
| 986 | |
| 987 ConstantExpression expression; | 914 ConstantExpression expression; |
| 988 ConstantExpression name = concreteArguments[0].expression; | 915 ConstantExpression name = concreteArguments[0].expression; |
| 989 ConstantExpression defaultValue; | 916 ConstantExpression defaultValue; |
| 990 if (concreteArguments.length > 1) { | 917 if (concreteArguments.length > 1) { |
| 991 defaultValue = concreteArguments[1].expression; | 918 defaultValue = concreteArguments[1].expression; |
| 992 } | 919 } |
| 993 if (constructor == compiler.intEnvironment) { | 920 if (constructor == compiler.intEnvironment) { |
| 994 expression = new IntFromEnvironmentConstantExpression( | 921 expression = |
| 995 name, defaultValue); | 922 new IntFromEnvironmentConstantExpression(name, defaultValue); |
| 996 } else if (constructor == compiler.boolEnvironment) { | 923 } else if (constructor == compiler.boolEnvironment) { |
| 997 expression = new BoolFromEnvironmentConstantExpression( | 924 expression = |
| 998 name, defaultValue); | 925 new BoolFromEnvironmentConstantExpression(name, defaultValue); |
| 999 } else if (constructor == compiler.stringEnvironment) { | 926 } else if (constructor == compiler.stringEnvironment) { |
| 1000 expression = new StringFromEnvironmentConstantExpression( | 927 expression = |
| 1001 name, defaultValue); | 928 new StringFromEnvironmentConstantExpression(name, defaultValue); |
| 1002 } | 929 } |
| 1003 return new AstConstant(context, node, expression, value); | 930 return new AstConstant(context, node, expression, value); |
| 1004 } | 931 } |
| 1005 | 932 |
| 1006 if (value == null) { | 933 if (value == null) { |
| 1007 return createEvaluatedConstant(defaultValue); | 934 return createEvaluatedConstant(defaultValue); |
| 1008 } else if (constructor == compiler.intEnvironment) { | 935 } else if (constructor == compiler.intEnvironment) { |
| 1009 int number = int.parse(value, onError: (_) => null); | 936 int number = int.parse(value, onError: (_) => null); |
| 1010 return createEvaluatedConstant( | 937 return createEvaluatedConstant( |
| 1011 (number == null) | 938 (number == null) ? defaultValue : constantSystem.createInt(number)); |
| 1012 ? defaultValue | |
| 1013 : constantSystem.createInt(number)); | |
| 1014 } else if (constructor == compiler.boolEnvironment) { | 939 } else if (constructor == compiler.boolEnvironment) { |
| 1015 if (value == 'true') { | 940 if (value == 'true') { |
| 1016 return createEvaluatedConstant(constantSystem.createBool(true)); | 941 return createEvaluatedConstant(constantSystem.createBool(true)); |
| 1017 } else if (value == 'false') { | 942 } else if (value == 'false') { |
| 1018 return createEvaluatedConstant(constantSystem.createBool(false)); | 943 return createEvaluatedConstant(constantSystem.createBool(false)); |
| 1019 } else { | 944 } else { |
| 1020 return createEvaluatedConstant(defaultValue); | 945 return createEvaluatedConstant(defaultValue); |
| 1021 } | 946 } |
| 1022 } else { | 947 } else { |
| 1023 assert(constructor == compiler.stringEnvironment); | 948 assert(constructor == compiler.stringEnvironment); |
| 1024 return createEvaluatedConstant( | 949 return createEvaluatedConstant( |
| 1025 constantSystem.createString(new DartString.literal(value))); | 950 constantSystem.createString(new DartString.literal(value))); |
| 1026 } | 951 } |
| 1027 } | 952 } |
| 1028 | 953 |
| 1029 static AstConstant makeConstructedConstant( | 954 static AstConstant makeConstructedConstant(Compiler compiler, |
| 1030 Compiler compiler, | 955 ConstantCompilerBase handler, Element context, Node node, |
| 1031 ConstantCompilerBase handler, | 956 InterfaceType type, ConstructorElement constructor, |
| 1032 Element context, | 957 InterfaceType constructedType, ConstructorElement target, |
| 1033 Node node, | 958 CallStructure callStructure, List<AstConstant> concreteArguments, |
| 1034 InterfaceType type, | |
| 1035 ConstructorElement constructor, | |
| 1036 InterfaceType constructedType, | |
| 1037 ConstructorElement target, | |
| 1038 CallStructure callStructure, | |
| 1039 List<AstConstant> concreteArguments, | |
| 1040 List<AstConstant> normalizedArguments) { | 959 List<AstConstant> normalizedArguments) { |
| 1041 if (target.isRedirectingFactory) { | 960 if (target.isRedirectingFactory) { |
| 1042 // This happens is case of cyclic redirection. | 961 // This happens is case of cyclic redirection. |
| 1043 assert(invariant(node, compiler.compilationFailed, | 962 assert(invariant(node, compiler.compilationFailed, |
| 1044 message: "makeConstructedConstant can only be called with the " | 963 message: "makeConstructedConstant can only be called with the " |
| 1045 "effective target: $constructor")); | 964 "effective target: $constructor")); |
| 1046 return new ErroneousAstConstant(context, node); | 965 return new ErroneousAstConstant(context, node); |
| 1047 } | 966 } |
| 1048 assert(invariant( | 967 assert(invariant(node, |
| 1049 node, | |
| 1050 callStructure.signatureApplies(constructor.functionSignature) || | 968 callStructure.signatureApplies(constructor.functionSignature) || |
| 1051 compiler.compilationFailed, | 969 compiler.compilationFailed, |
| 1052 message: "Call structure $callStructure does not apply to constructor " | 970 message: "Call structure $callStructure does not apply to constructor " |
| 1053 "$constructor.")); | 971 "$constructor.")); |
| 1054 | 972 |
| 1055 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 973 ConstructorEvaluator evaluator = |
| 1056 constructedType, target, handler, compiler); | 974 new ConstructorEvaluator(constructedType, target, handler, compiler); |
| 1057 evaluator.evaluateConstructorFieldValues(normalizedArguments); | 975 evaluator.evaluateConstructorFieldValues(normalizedArguments); |
| 1058 Map<FieldElement, AstConstant> fieldConstants = | 976 Map<FieldElement, AstConstant> fieldConstants = |
| 1059 evaluator.buildFieldConstants(target.enclosingClass); | 977 evaluator.buildFieldConstants(target.enclosingClass); |
| 1060 Map<FieldElement, ConstantValue> fieldValues = | 978 Map<FieldElement, ConstantValue> fieldValues = |
| 1061 <FieldElement, ConstantValue>{}; | 979 <FieldElement, ConstantValue>{}; |
| 1062 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { | 980 fieldConstants.forEach((FieldElement field, AstConstant astConstant) { |
| 1063 fieldValues[field] = astConstant.value; | 981 fieldValues[field] = astConstant.value; |
| 1064 }); | 982 }); |
| 1065 return new AstConstant( | 983 return new AstConstant(context, node, new ConstructedConstantExpression( |
| 1066 context, | 984 type, constructor, callStructure, |
| 1067 node, | |
| 1068 new ConstructedConstantExpression( | |
| 1069 type, | |
| 1070 constructor, | |
| 1071 callStructure, | |
| 1072 concreteArguments.map((e) => e.expression).toList()), | 985 concreteArguments.map((e) => e.expression).toList()), |
| 1073 new ConstructedConstantValue(constructedType, fieldValues)); | 986 new ConstructedConstantValue(constructedType, fieldValues)); |
| 1074 } | 987 } |
| 1075 | 988 |
| 1076 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { | 989 AstConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1077 return node.expression.accept(this); | 990 return node.expression.accept(this); |
| 1078 } | 991 } |
| 1079 | 992 |
| 1080 error(Node node, MessageKind message) { | 993 error(Node node, MessageKind message) { |
| 1081 // TODO(floitsch): get the list of constants that are currently compiled | 994 // TODO(floitsch): get the list of constants that are currently compiled |
| 1082 // and present some kind of stack-trace. | 995 // and present some kind of stack-trace. |
| 1083 compiler.reportError(node, message); | 996 compiler.reportError(node, message); |
| 1084 } | 997 } |
| 1085 | 998 |
| 1086 AstConstant signalNotCompileTimeConstant(Node node, | 999 AstConstant signalNotCompileTimeConstant(Node node, |
| 1087 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { | 1000 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { |
| 1088 if (isEvaluatingConstant) { | 1001 if (isEvaluatingConstant) { |
| 1089 error(node, message); | 1002 error(node, message); |
| 1090 | 1003 |
| 1091 return new AstConstant( | 1004 return new AstConstant(context, node, new ErroneousConstantExpression(), |
| 1092 context, | |
| 1093 node, | |
| 1094 new ErroneousConstantExpression(), | |
| 1095 new NullConstantValue()); | 1005 new NullConstantValue()); |
| 1096 } | 1006 } |
| 1097 // Else we don't need to do anything. The final handler is only | 1007 // Else we don't need to do anything. The final handler is only |
| 1098 // optimistically trying to compile constants. So it is normal that we | 1008 // optimistically trying to compile constants. So it is normal that we |
| 1099 // sometimes see non-compile time constants. | 1009 // sometimes see non-compile time constants. |
| 1100 // Simply return [:null:] which is used to propagate a failing | 1010 // Simply return [:null:] which is used to propagate a failing |
| 1101 // compile-time compilation. | 1011 // compile-time compilation. |
| 1102 return null; | 1012 return null; |
| 1103 } | 1013 } |
| 1104 } | 1014 } |
| 1105 | 1015 |
| 1106 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 1016 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 1107 final InterfaceType constructedType; | 1017 final InterfaceType constructedType; |
| 1108 final ConstructorElement constructor; | 1018 final ConstructorElement constructor; |
| 1109 final Map<Element, AstConstant> definitions; | 1019 final Map<Element, AstConstant> definitions; |
| 1110 final Map<Element, AstConstant> fieldValues; | 1020 final Map<Element, AstConstant> fieldValues; |
| 1111 | 1021 |
| 1112 /** | 1022 /** |
| 1113 * Documentation wanted -- johnniwinther | 1023 * Documentation wanted -- johnniwinther |
| 1114 * | 1024 * |
| 1115 * Invariant: [constructor] must be an implementation element. | 1025 * Invariant: [constructor] must be an implementation element. |
| 1116 */ | 1026 */ |
| 1117 ConstructorEvaluator(InterfaceType this.constructedType, | 1027 ConstructorEvaluator(InterfaceType this.constructedType, |
| 1118 FunctionElement constructor, | 1028 FunctionElement constructor, ConstantCompiler handler, Compiler compiler) |
| 1119 ConstantCompiler handler, | |
| 1120 Compiler compiler) | |
| 1121 : this.constructor = constructor, | 1029 : this.constructor = constructor, |
| 1122 this.definitions = new Map<Element, AstConstant>(), | 1030 this.definitions = new Map<Element, AstConstant>(), |
| 1123 this.fieldValues = new Map<Element, AstConstant>(), | 1031 this.fieldValues = new Map<Element, AstConstant>(), |
| 1124 super(handler, | 1032 super(handler, _analyzeElementEagerly(compiler, constructor), compiler, |
| 1125 _analyzeElementEagerly(compiler, constructor), | 1033 isConst: true) { |
| 1126 compiler, | |
| 1127 isConst: true) { | |
| 1128 assert(invariant(constructor, constructor.isImplementation)); | 1034 assert(invariant(constructor, constructor.isImplementation)); |
| 1129 } | 1035 } |
| 1130 | 1036 |
| 1131 AstConstant visitSend(Send send) { | 1037 AstConstant visitSend(Send send) { |
| 1132 Element element = elements[send]; | 1038 Element element = elements[send]; |
| 1133 if (Elements.isLocal(element)) { | 1039 if (Elements.isLocal(element)) { |
| 1134 AstConstant constant = definitions[element]; | 1040 AstConstant constant = definitions[element]; |
| 1135 if (constant == null) { | 1041 if (constant == null) { |
| 1136 compiler.internalError(send, "Local variable without value."); | 1042 compiler.internalError(send, "Local variable without value."); |
| 1137 } | 1043 } |
| 1138 return constant; | 1044 return constant; |
| 1139 } | 1045 } |
| 1140 return super.visitSend(send); | 1046 return super.visitSend(send); |
| 1141 } | 1047 } |
| 1142 | 1048 |
| 1143 void potentiallyCheckType(Node node, | 1049 void potentiallyCheckType(TypedElement element, AstConstant constant) { |
| 1144 TypedElement element, | |
| 1145 AstConstant constant) { | |
| 1146 if (compiler.enableTypeAssertions) { | 1050 if (compiler.enableTypeAssertions) { |
| 1147 DartType elementType = element.type.substByContext(constructedType); | 1051 DartType elementType = element.type.substByContext(constructedType); |
| 1148 DartType constantType = constant.value.getType(compiler.coreTypes); | 1052 DartType constantType = constant.value.getType(compiler.coreTypes); |
| 1149 if (!constantSystem.isSubtype(compiler.types, | 1053 if (!constantSystem.isSubtype( |
| 1150 constantType, elementType)) { | 1054 compiler.types, constantType, elementType)) { |
| 1151 compiler.withCurrentElement(constant.element, () { | 1055 compiler.withCurrentElement(constant.element, () { |
| 1152 compiler.reportError( | 1056 compiler.reportError(constant.node, MessageKind.NOT_ASSIGNABLE, { |
| 1153 constant.node, MessageKind.NOT_ASSIGNABLE, | 1057 'fromType': constantType, |
| 1154 {'fromType': constantType, 'toType': elementType}); | 1058 'toType': elementType |
| 1059 }); |
| 1155 }); | 1060 }); |
| 1156 } | 1061 } |
| 1157 } | 1062 } |
| 1158 } | 1063 } |
| 1159 | 1064 |
| 1160 void updateFieldValue(Node node, | 1065 void updateFieldValue(Node node, TypedElement element, AstConstant constant) { |
| 1161 TypedElement element, | 1066 potentiallyCheckType(element, constant); |
| 1162 AstConstant constant) { | |
| 1163 potentiallyCheckType(node, element, constant); | |
| 1164 fieldValues[element] = constant; | 1067 fieldValues[element] = constant; |
| 1165 } | 1068 } |
| 1166 | 1069 |
| 1167 /** | 1070 /** |
| 1168 * Given the arguments (a list of constants) assigns them to the parameters, | 1071 * Given the arguments (a list of constants) assigns them to the parameters, |
| 1169 * updating the definitions map. If the constructor has field-initializer | 1072 * updating the definitions map. If the constructor has field-initializer |
| 1170 * parameters (like [:this.x:]), also updates the [fieldValues] map. | 1073 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
| 1171 */ | 1074 */ |
| 1172 void assignArgumentsToParameters(List<AstConstant> arguments) { | 1075 void assignArgumentsToParameters(List<AstConstant> arguments) { |
| 1173 if (constructor.isErroneous) return; | 1076 if (constructor.isErroneous) return; |
| 1174 // Assign arguments to parameters. | 1077 // Assign arguments to parameters. |
| 1175 FunctionSignature signature = constructor.functionSignature; | 1078 FunctionSignature signature = constructor.functionSignature; |
| 1176 int index = 0; | 1079 int index = 0; |
| 1177 signature.orderedForEachParameter((ParameterElement parameter) { | 1080 signature.orderedForEachParameter((ParameterElement parameter) { |
| 1178 AstConstant argument = arguments[index++]; | 1081 AstConstant argument = arguments[index++]; |
| 1179 Node node = parameter.node; | 1082 Node node = parameter.node; |
| 1180 if (parameter.isInitializingFormal) { | 1083 if (parameter.isInitializingFormal) { |
| 1181 InitializingFormalElement initializingFormal = parameter; | 1084 InitializingFormalElement initializingFormal = parameter; |
| 1182 updateFieldValue(node, initializingFormal.fieldElement, argument); | 1085 updateFieldValue(node, initializingFormal.fieldElement, argument); |
| 1183 } else { | 1086 } else { |
| 1184 potentiallyCheckType(node, parameter, argument); | 1087 potentiallyCheckType(parameter, argument); |
| 1185 definitions[parameter] = argument; | 1088 definitions[parameter] = argument; |
| 1186 } | 1089 } |
| 1187 }); | 1090 }); |
| 1188 } | 1091 } |
| 1189 | 1092 |
| 1190 void evaluateSuperOrRedirectSend(List<AstConstant> compiledArguments, | 1093 void evaluateSuperOrRedirectSend( |
| 1191 FunctionElement targetConstructor) { | 1094 List<AstConstant> compiledArguments, FunctionElement targetConstructor) { |
| 1192 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 1095 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 1193 constructedType.asInstanceOf(targetConstructor.enclosingClass), | 1096 constructedType.asInstanceOf(targetConstructor.enclosingClass), |
| 1194 targetConstructor, handler, compiler); | 1097 targetConstructor, handler, compiler); |
| 1195 evaluator.evaluateConstructorFieldValues(compiledArguments); | 1098 evaluator.evaluateConstructorFieldValues(compiledArguments); |
| 1196 // Copy over the fieldValues from the super/redirect-constructor. | 1099 // Copy over the fieldValues from the super/redirect-constructor. |
| 1197 // No need to go through [updateFieldValue] because the | 1100 // No need to go through [updateFieldValue] because the |
| 1198 // assignments have already been checked in checked mode. | 1101 // assignments have already been checked in checked mode. |
| 1199 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 1102 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 1200 } | 1103 } |
| 1201 | 1104 |
| 1202 /** | 1105 /** |
| 1203 * Runs through the initializers of the given [constructor] and updates | 1106 * Runs through the initializers of the given [constructor] and updates |
| 1204 * the [fieldValues] map. | 1107 * the [fieldValues] map. |
| 1205 */ | 1108 */ |
| 1206 void evaluateConstructorInitializers() { | 1109 void evaluateConstructorInitializers() { |
| 1207 if (constructor.isSynthesized) { | 1110 if (constructor.isSynthesized) { |
| 1208 List<AstConstant> compiledArguments = <AstConstant>[]; | 1111 List<AstConstant> compiledArguments = <AstConstant>[]; |
| 1209 | 1112 |
| 1210 Function compileArgument = (element) => definitions[element]; | 1113 Function compileArgument = (element) => definitions[element]; |
| 1211 Function compileConstant = handler.compileConstant; | 1114 Function compileConstant = handler.compileConstant; |
| 1212 FunctionElement target = constructor.definingConstructor.implementation; | 1115 FunctionElement target = constructor.definingConstructor.implementation; |
| 1213 CallStructure.addForwardingElementArgumentsToList( | 1116 CallStructure.addForwardingElementArgumentsToList(constructor, |
| 1214 constructor, | 1117 compiledArguments, target, compileArgument, compileConstant); |
| 1215 compiledArguments, | |
| 1216 target, | |
| 1217 compileArgument, | |
| 1218 compileConstant); | |
| 1219 evaluateSuperOrRedirectSend(compiledArguments, target); | 1118 evaluateSuperOrRedirectSend(compiledArguments, target); |
| 1220 return; | 1119 return; |
| 1221 } | 1120 } |
| 1222 FunctionExpression functionNode = constructor.node; | 1121 FunctionExpression functionNode = constructor.node; |
| 1223 NodeList initializerList = functionNode.initializers; | 1122 NodeList initializerList = functionNode.initializers; |
| 1224 | 1123 |
| 1225 bool foundSuperOrRedirect = false; | 1124 bool foundSuperOrRedirect = false; |
| 1226 | 1125 |
| 1227 if (initializerList != null) { | 1126 if (initializerList != null) { |
| 1228 for (Link<Node> link = initializerList.nodes; | 1127 for (Link<Node> link = initializerList.nodes; |
| 1229 !link.isEmpty; | 1128 !link.isEmpty; |
| 1230 link = link.tail) { | 1129 link = link.tail) { |
| 1231 assert(link.head is Send); | 1130 assert(link.head is Send); |
| 1232 if (link.head is !SendSet) { | 1131 if (link.head is! SendSet) { |
| 1233 // A super initializer or constructor redirection. | 1132 // A super initializer or constructor redirection. |
| 1234 Send call = link.head; | 1133 Send call = link.head; |
| 1235 FunctionElement target = elements[call]; | 1134 FunctionElement target = elements[call]; |
| 1236 List<AstConstant> compiledArguments = | 1135 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( |
| 1237 evaluateArgumentsToConstructor( | 1136 call, elements.getSelector(call).callStructure, call.arguments, |
| 1238 call, elements.getSelector(call).callStructure, | 1137 target, compileArgument: evaluateConstant); |
| 1239 call.arguments, target, | |
| 1240 compileArgument: evaluateConstant); | |
| 1241 evaluateSuperOrRedirectSend(compiledArguments, target); | 1138 evaluateSuperOrRedirectSend(compiledArguments, target); |
| 1242 foundSuperOrRedirect = true; | 1139 foundSuperOrRedirect = true; |
| 1243 } else { | 1140 } else { |
| 1244 // A field initializer. | 1141 // A field initializer. |
| 1245 SendSet init = link.head; | 1142 SendSet init = link.head; |
| 1246 Link<Node> initArguments = init.arguments; | 1143 Link<Node> initArguments = init.arguments; |
| 1247 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); | 1144 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); |
| 1248 AstConstant fieldValue = evaluate(initArguments.head); | 1145 AstConstant fieldValue = evaluate(initArguments.head); |
| 1249 updateFieldValue(init, elements[init], fieldValue); | 1146 updateFieldValue(init, elements[init], fieldValue); |
| 1250 } | 1147 } |
| 1251 } | 1148 } |
| 1252 } | 1149 } |
| 1253 | 1150 |
| 1254 if (!foundSuperOrRedirect) { | 1151 if (!foundSuperOrRedirect) { |
| 1255 // No super initializer found. Try to find the default constructor if | 1152 // No super initializer found. Try to find the default constructor if |
| 1256 // the class is not Object. | 1153 // the class is not Object. |
| 1257 ClassElement enclosingClass = constructor.enclosingClass; | 1154 ClassElement enclosingClass = constructor.enclosingClass; |
| 1258 ClassElement superClass = enclosingClass.superclass; | 1155 ClassElement superClass = enclosingClass.superclass; |
| 1259 if (enclosingClass != compiler.objectClass) { | 1156 if (enclosingClass != compiler.objectClass) { |
| 1260 assert(superClass != null); | 1157 assert(superClass != null); |
| 1261 assert(superClass.isResolved); | 1158 assert(superClass.isResolved); |
| 1262 | 1159 |
| 1263 FunctionElement targetConstructor = | 1160 FunctionElement targetConstructor = |
| 1264 superClass.lookupDefaultConstructor(); | 1161 superClass.lookupDefaultConstructor(); |
| 1265 // If we do not find a default constructor, an error was reported | 1162 // If we do not find a default constructor, an error was reported |
| 1266 // already and compilation will fail anyway. So just ignore that case. | 1163 // already and compilation will fail anyway. So just ignore that case. |
| 1267 if (targetConstructor != null) { | 1164 if (targetConstructor != null) { |
| 1268 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( | 1165 List<AstConstant> compiledArguments = evaluateArgumentsToConstructor( |
| 1269 functionNode, CallStructure.NO_ARGS, | 1166 functionNode, CallStructure.NO_ARGS, const Link<Node>(), |
| 1270 const Link<Node>(), targetConstructor); | 1167 targetConstructor); |
| 1271 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); | 1168 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); |
| 1272 } | 1169 } |
| 1273 } | 1170 } |
| 1274 } | 1171 } |
| 1275 } | 1172 } |
| 1276 | 1173 |
| 1277 /** | 1174 /** |
| 1278 * Simulates the execution of the [constructor] with the given | 1175 * Simulates the execution of the [constructor] with the given |
| 1279 * [arguments] to obtain the field values that need to be passed to the | 1176 * [arguments] to obtain the field values that need to be passed to the |
| 1280 * native JavaScript constructor. | 1177 * native JavaScript constructor. |
| 1281 */ | 1178 */ |
| 1282 void evaluateConstructorFieldValues(List<AstConstant> arguments) { | 1179 void evaluateConstructorFieldValues(List<AstConstant> arguments) { |
| 1283 if (constructor.isErroneous) return; | 1180 if (constructor.isErroneous) return; |
| 1284 compiler.withCurrentElement(constructor, () { | 1181 compiler.withCurrentElement(constructor, () { |
| 1285 assignArgumentsToParameters(arguments); | 1182 assignArgumentsToParameters(arguments); |
| 1286 evaluateConstructorInitializers(); | 1183 evaluateConstructorInitializers(); |
| 1287 }); | 1184 }); |
| 1288 } | 1185 } |
| 1289 | 1186 |
| 1290 /// Builds a normalized list of the constant values for each field in the | 1187 /// Builds a normalized list of the constant values for each field in the |
| 1291 /// inheritance chain of [classElement]. | 1188 /// inheritance chain of [classElement]. |
| 1292 Map<FieldElement, AstConstant> buildFieldConstants( | 1189 Map<FieldElement, AstConstant> buildFieldConstants( |
| 1293 ClassElement classElement) { | 1190 ClassElement classElement) { |
| 1294 Map<FieldElement, AstConstant> fieldConstants = | 1191 Map<FieldElement, AstConstant> fieldConstants = <FieldElement, AstConstant>{ |
| 1295 <FieldElement, AstConstant>{}; | 1192 }; |
| 1296 classElement.implementation.forEachInstanceField( | 1193 classElement.implementation |
| 1297 (ClassElement enclosing, FieldElement field) { | 1194 .forEachInstanceField((ClassElement enclosing, FieldElement field) { |
| 1298 AstConstant fieldValue = fieldValues[field]; | 1195 AstConstant fieldValue = fieldValues[field]; |
| 1299 if (fieldValue == null) { | 1196 if (fieldValue == null) { |
| 1300 // Use the default value. | 1197 // Use the default value. |
| 1301 ConstantExpression fieldExpression = handler.compileConstant(field); | 1198 ConstantExpression fieldExpression = |
| 1302 fieldValue = new AstConstant.fromDefaultValue( | 1199 handler.internalCompileVariable(field, true, false); |
| 1303 field, | 1200 fieldValue = new AstConstant.fromDefaultValue( |
| 1304 fieldExpression, | 1201 field, fieldExpression, handler.getConstantValue(fieldExpression)); |
| 1305 handler.getConstantValue(fieldExpression)); | 1202 // TODO(het): If the field value doesn't typecheck due to the type |
| 1306 } | 1203 // variable in the constructor invocation, then report the error on the |
| 1307 fieldConstants[field] = fieldValue; | 1204 // invocation rather than the field. |
| 1308 }, | 1205 potentiallyCheckType(field, fieldValue); |
| 1309 includeSuperAndInjectedMembers: true); | 1206 } |
| 1207 fieldConstants[field] = fieldValue; |
| 1208 }, includeSuperAndInjectedMembers: true); |
| 1310 return fieldConstants; | 1209 return fieldConstants; |
| 1311 } | 1210 } |
| 1312 } | 1211 } |
| 1313 | 1212 |
| 1314 /// A constant created from the front-end AST. | 1213 /// A constant created from the front-end AST. |
| 1315 /// | 1214 /// |
| 1316 /// [element] and [node] point to the source location of the constant. | 1215 /// [element] and [node] point to the source location of the constant. |
| 1317 /// [expression] holds the symbolic constant expression and [value] its constant | 1216 /// [expression] holds the symbolic constant expression and [value] its constant |
| 1318 /// value. | 1217 /// value. |
| 1319 /// | 1218 /// |
| 1320 /// This class differs from [ConstantExpression] in that it is coupled to the | 1219 /// This class differs from [ConstantExpression] in that it is coupled to the |
| 1321 /// front-end AST whereas [ConstantExpression] is only coupled to the element | 1220 /// front-end AST whereas [ConstantExpression] is only coupled to the element |
| 1322 /// model. | 1221 /// model. |
| 1323 class AstConstant { | 1222 class AstConstant { |
| 1324 final Element element; | 1223 final Element element; |
| 1325 final Node node; | 1224 final Node node; |
| 1326 final ConstantExpression expression; | 1225 final ConstantExpression expression; |
| 1327 final ConstantValue value; | 1226 final ConstantValue value; |
| 1328 | 1227 |
| 1329 AstConstant(this.element, this.node, this.expression, this.value); | 1228 AstConstant(this.element, this.node, this.expression, this.value); |
| 1330 | 1229 |
| 1331 factory AstConstant.fromDefaultValue( | 1230 factory AstConstant.fromDefaultValue(VariableElement element, |
| 1332 VariableElement element, | 1231 ConstantExpression constant, ConstantValue value) { |
| 1333 ConstantExpression constant, | 1232 return new AstConstant(element, element.initializer != null |
| 1334 ConstantValue value) { | 1233 ? element.initializer |
| 1335 return new AstConstant( | 1234 : element.node, constant, value); |
| 1336 element, | |
| 1337 element.initializer != null ? element.initializer : element.node, | |
| 1338 constant, | |
| 1339 value); | |
| 1340 } | 1235 } |
| 1341 | 1236 |
| 1342 String toString() => expression.toString(); | 1237 String toString() => expression.toString(); |
| 1343 } | 1238 } |
| 1344 | 1239 |
| 1345 /// A synthetic constant used to recover from errors. | 1240 /// A synthetic constant used to recover from errors. |
| 1346 class ErroneousAstConstant extends AstConstant { | 1241 class ErroneousAstConstant extends AstConstant { |
| 1347 ErroneousAstConstant(Element element, Node node) | 1242 ErroneousAstConstant(Element element, Node node) : super(element, node, |
| 1348 : super(element, node, | |
| 1349 // TODO(johnniwinther): Return a [NonConstantValue] instead. | 1243 // TODO(johnniwinther): Return a [NonConstantValue] instead. |
| 1350 new ErroneousConstantExpression(), new NullConstantValue()); | 1244 new ErroneousConstantExpression(), new NullConstantValue()); |
| 1351 } | 1245 } |
| 1352 | 1246 |
| 1353 // TODO(johnniwinther): Avoid the need for this hack. | 1247 // TODO(johnniwinther): Avoid the need for this hack. |
| 1354 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { | 1248 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) { |
| 1355 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); | 1249 WorldImpact worldImpact = compiler.analyzeElement(element.declaration); |
| 1356 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); | 1250 compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact); |
| 1357 return element.resolvedAst.elements; | 1251 return element.resolvedAst.elements; |
| 1358 } | 1252 } |
| 1359 | 1253 |
| 1360 class _CompilerEnvironment implements Environment { | 1254 class _CompilerEnvironment implements Environment { |
| 1361 final Compiler compiler; | 1255 final Compiler compiler; |
| 1362 | 1256 |
| 1363 _CompilerEnvironment(this.compiler); | 1257 _CompilerEnvironment(this.compiler); |
| 1364 | 1258 |
| 1365 @override | 1259 @override |
| 1366 String readFromEnvironment(String name) { | 1260 String readFromEnvironment(String name) { |
| 1367 return compiler.fromEnvironment(name); | 1261 return compiler.fromEnvironment(name); |
| 1368 } | 1262 } |
| 1369 } | 1263 } |
| OLD | NEW |