Chromium Code Reviews| 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 part of dart2js; | 5 part of dart2js; |
| 6 | 6 |
| 7 /// A [ConstantEnvironment] provides access for constants compiled for variable | 7 /// A [ConstantEnvironment] provides access for constants compiled for variable |
| 8 /// initializers. | 8 /// initializers. |
| 9 abstract class ConstantEnvironment { | 9 abstract class ConstantEnvironment { |
| 10 /// Returns the constant for the initializer of [element]. | 10 /// Returns the constant for the initializer of [element]. |
| 11 Constant getConstantForVariable(VariableElement element); | 11 ConstExp getConstantForVariable(VariableElement element); |
| 12 } | 12 } |
| 13 | 13 |
| 14 /// A class that can compile and provide constants for variables, nodes and | 14 /// A class that can compile and provide constants for variables, nodes and |
| 15 /// metadata. | 15 /// metadata. |
| 16 abstract class ConstantCompiler extends ConstantEnvironment { | 16 abstract class ConstantCompiler extends ConstantEnvironment { |
| 17 /// Compiles the compile-time constant for the initializer of [element], or | 17 /// Compiles the compile-time constant for the initializer of [element], or |
| 18 /// reports an error if the initializer is not a compile-time constant. | 18 /// reports an error if the initializer is not a compile-time constant. |
| 19 /// | 19 /// |
| 20 /// Depending on implementation, the constant compiler might also compute | 20 /// Depending on implementation, the constant compiler might also compute |
| 21 /// the compile-time constant for the backend interpretation of constants. | 21 /// the compile-time constant for the backend interpretation of constants. |
| 22 /// | 22 /// |
| 23 /// The returned constant is always of the frontend interpretation. | 23 /// The returned constant is always of the frontend interpretation. |
| 24 Constant compileConstant(VariableElement element); | 24 ConstExp compileConstant(VariableElement element); |
| 25 | 25 |
| 26 /// Computes the compile-time constant for the variable initializer, | 26 /// Computes the compile-time constant for the variable initializer, |
| 27 /// if possible. | 27 /// if possible. |
| 28 void compileVariable(VariableElement element); | 28 void compileVariable(VariableElement element); |
| 29 | 29 |
| 30 /// Compiles the compile-time constant for [node], or reports an error if | 30 /// Compiles the compile-time constant for [node], or reports an error if |
| 31 /// [node] is not a compile-time constant. | 31 /// [node] is not a compile-time constant. |
| 32 /// | 32 /// |
| 33 /// Depending on implementation, the constant compiler might also compute | 33 /// Depending on implementation, the constant compiler might also compute |
| 34 /// the compile-time constant for the backend interpretation of constants. | 34 /// the compile-time constant for the backend interpretation of constants. |
| 35 /// | 35 /// |
| 36 /// The returned constant is always of the frontend interpretation. | 36 /// The returned constant is always of the frontend interpretation. |
| 37 Constant compileNode(Node node, TreeElements elements); | 37 ConstExp compileNode(Node node, TreeElements elements); |
| 38 | 38 |
| 39 /// Compiles the compile-time constant for the value [metadata], or reports an | 39 /// Compiles the compile-time constant for the value [metadata], or reports an |
| 40 /// error if the value is not a compile-time constant. | 40 /// error if the value is not a compile-time constant. |
| 41 /// | 41 /// |
| 42 /// Depending on implementation, the constant compiler might also compute | 42 /// Depending on implementation, the constant compiler might also compute |
| 43 /// the compile-time constant for the backend interpretation of constants. | 43 /// the compile-time constant for the backend interpretation of constants. |
| 44 /// | 44 /// |
| 45 /// The returned constant is always of the frontend interpretation. | 45 /// The returned constant is always of the frontend interpretation. |
| 46 Constant compileMetadata(MetadataAnnotation metadata, | 46 ConstExp compileMetadata(MetadataAnnotation metadata, |
| 47 Node node, TreeElements elements); | 47 Node node, TreeElements elements); |
| 48 } | 48 } |
| 49 | 49 |
| 50 /// A [BackendConstantEnvironment] provides access to constants needed for | 50 /// A [BackendConstantEnvironment] provides access to constants needed for |
| 51 /// backend implementation. | 51 /// backend implementation. |
| 52 abstract class BackendConstantEnvironment extends ConstantEnvironment { | 52 abstract class BackendConstantEnvironment extends ConstantEnvironment { |
| 53 /// Returns the compile-time constant associated with [node]. | 53 /// Returns the compile-time constant associated with [node]. |
| 54 /// | 54 /// |
| 55 /// Depending on implementation, the constant might be stored in [elements]. | 55 /// Depending on implementation, the constant might be stored in [elements]. |
| 56 Constant getConstantForNode(Node node, TreeElements elements); | 56 ConstExp getConstantForNode(Node node, TreeElements elements); |
| 57 | 57 |
| 58 /// Returns the compile-time constant value of [metadata]. | 58 /// Returns the compile-time constant value of [metadata]. |
| 59 Constant getConstantForMetadata(MetadataAnnotation metadata); | 59 ConstExp getConstantForMetadata(MetadataAnnotation metadata); |
| 60 } | 60 } |
| 61 | 61 |
| 62 /// Interface for the task that compiles the constant environments for the | 62 /// Interface for the task that compiles the constant environments for the |
| 63 /// frontend and backend interpretation of compile-time constants. | 63 /// frontend and backend interpretation of compile-time constants. |
| 64 abstract class ConstantCompilerTask extends CompilerTask | 64 abstract class ConstantCompilerTask extends CompilerTask |
| 65 implements ConstantCompiler { | 65 implements ConstantCompiler { |
| 66 ConstantCompilerTask(Compiler compiler) : super(compiler); | 66 ConstantCompilerTask(Compiler compiler) : super(compiler); |
| 67 } | 67 } |
| 68 | 68 |
| 69 /** | 69 /** |
| 70 * The [ConstantCompilerBase] is provides base implementation for compilation of | 70 * The [ConstantCompilerBase] is provides base implementation for compilation of |
| 71 * compile-time constants for both the Dart and JavaScript interpretation of | 71 * compile-time constants for both the Dart and JavaScript interpretation of |
| 72 * constants. It keeps track of compile-time constants for initializations of | 72 * constants. It keeps track of compile-time constants for initializations of |
| 73 * global and static fields, and default values of optional parameters. | 73 * global and static fields, and default values of optional parameters. |
| 74 */ | 74 */ |
| 75 abstract class ConstantCompilerBase implements ConstantCompiler { | 75 abstract class ConstantCompilerBase implements ConstantCompiler { |
| 76 final Compiler compiler; | 76 final Compiler compiler; |
| 77 final ConstantSystem constantSystem; | 77 final ConstantSystem constantSystem; |
| 78 | 78 |
| 79 /** | 79 /** |
| 80 * Contains the initial value of fields. Must contain all static and global | 80 * Contains the initial value of fields. Must contain all static and global |
| 81 * initializations of const fields. May contain eagerly compiled values for | 81 * initializations of const fields. May contain eagerly compiled values for |
| 82 * statics and instance fields. | 82 * statics and instance fields. |
| 83 * | 83 * |
| 84 * Invariant: The keys in this map are declarations. | 84 * Invariant: The keys in this map are declarations. |
| 85 */ | 85 */ |
| 86 final Map<VariableElement, Constant> initialVariableValues = | 86 final Map<VariableElement, ConstExp> initialVariableValues = |
| 87 new Map<VariableElement, Constant>(); | 87 new Map<VariableElement, ConstExp>(); |
| 88 | 88 |
| 89 /** The set of variable elements that are in the process of being computed. */ | 89 /** The set of variable elements that are in the process of being computed. */ |
| 90 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); | 90 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); |
| 91 | 91 |
| 92 ConstantCompilerBase(this.compiler, this.constantSystem); | 92 ConstantCompilerBase(this.compiler, this.constantSystem); |
| 93 | 93 |
| 94 Constant getConstantForVariable(VariableElement element) { | 94 ConstExp getConstantForVariable(VariableElement element) { |
| 95 return initialVariableValues[element.declaration]; | 95 return initialVariableValues[element.declaration]; |
| 96 } | 96 } |
| 97 | 97 |
| 98 Constant compileConstant(VariableElement element) { | 98 ConstExp compileConstant(VariableElement element) { |
| 99 return compileVariable(element, isConst: true); | 99 return compileVariable(element, isConst: true); |
| 100 } | 100 } |
| 101 | 101 |
| 102 Constant compileVariable(VariableElement element, {bool isConst: false}) { | 102 ConstExp compileVariable(VariableElement element, {bool isConst: false}) { |
| 103 | 103 |
| 104 if (initialVariableValues.containsKey(element.declaration)) { | 104 if (initialVariableValues.containsKey(element.declaration)) { |
| 105 Constant result = initialVariableValues[element.declaration]; | 105 ConstExp result = initialVariableValues[element.declaration]; |
| 106 return result; | 106 return result; |
| 107 } | 107 } |
| 108 AstElement currentElement = element.analyzableElement; | 108 AstElement currentElement = element.analyzableElement; |
| 109 return compiler.withCurrentElement(currentElement, () { | 109 return compiler.withCurrentElement(currentElement, () { |
| 110 compiler.analyzeElement(currentElement.declaration); | 110 compiler.analyzeElement(currentElement.declaration); |
| 111 Constant constant = compileVariableWithDefinitions( | 111 ConstExp constant = compileVariableWithDefinitions( |
| 112 element, currentElement.resolvedAst.elements, isConst: isConst); | 112 element, currentElement.resolvedAst.elements, isConst: isConst); |
| 113 return constant; | 113 return constant; |
| 114 }); | 114 }); |
| 115 } | 115 } |
| 116 | 116 |
| 117 /** | 117 /** |
| 118 * Returns the a compile-time constant if the variable could be compiled | 118 * Returns the a compile-time constant if the variable could be compiled |
| 119 * eagerly. If the variable needs to be initialized lazily returns `null`. | 119 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 120 * If the variable is `const` but cannot be compiled eagerly reports an | 120 * If the variable is `const` but cannot be compiled eagerly reports an |
| 121 * error. | 121 * error. |
| 122 */ | 122 */ |
| 123 Constant compileVariableWithDefinitions(VariableElement element, | 123 ConstExp compileVariableWithDefinitions(VariableElement element, |
| 124 TreeElements definitions, | 124 TreeElements definitions, |
| 125 {bool isConst: false}) { | 125 {bool isConst: false}) { |
| 126 Node node = element.node; | 126 Node node = element.node; |
| 127 if (pendingVariables.contains(element)) { | 127 if (pendingVariables.contains(element)) { |
| 128 if (isConst) { | 128 if (isConst) { |
| 129 compiler.reportFatalError( | 129 compiler.reportFatalError( |
| 130 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | 130 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 131 } | 131 } |
| 132 return null; | 132 return null; |
| 133 } | 133 } |
| 134 pendingVariables.add(element); | 134 pendingVariables.add(element); |
| 135 | 135 |
| 136 Expression initializer = element.initializer; | 136 Expression initializer = element.initializer; |
| 137 Constant value; | 137 ConstExp value; |
| 138 if (initializer == null) { | 138 if (initializer == null) { |
| 139 // No initial value. | 139 // No initial value. |
| 140 value = new NullConstant(); | 140 value = new PrimitiveConstExp(new NullConstant()); |
| 141 } else { | 141 } else { |
| 142 value = compileNodeWithDefinitions( | 142 value = compileNodeWithDefinitions( |
| 143 initializer, definitions, isConst: isConst); | 143 initializer, definitions, isConst: isConst); |
| 144 if (compiler.enableTypeAssertions && | 144 if (compiler.enableTypeAssertions && |
| 145 value != null && | 145 value != null && |
| 146 element.isField) { | 146 element.isField) { |
| 147 DartType elementType = element.type; | 147 DartType elementType = element.type; |
| 148 if (elementType.isMalformed && !value.isNull) { | 148 if (elementType.isMalformed && !value.value.isNull) { |
| 149 if (isConst) { | 149 if (isConst) { |
| 150 ErroneousElement element = elementType.element; | 150 ErroneousElement element = elementType.element; |
| 151 compiler.reportFatalError( | 151 compiler.reportFatalError( |
| 152 node, element.messageKind, element.messageArguments); | 152 node, element.messageKind, element.messageArguments); |
| 153 } else { | 153 } else { |
| 154 // We need to throw an exception at runtime. | 154 // We need to throw an exception at runtime. |
| 155 value = null; | 155 value = null; |
| 156 } | 156 } |
| 157 } else { | 157 } else { |
| 158 DartType constantType = value.computeType(compiler); | 158 DartType constantType = value.value.computeType(compiler); |
| 159 if (!constantSystem.isSubtype(compiler, | 159 if (!constantSystem.isSubtype(compiler, |
| 160 constantType, elementType)) { | 160 constantType, elementType)) { |
| 161 if (isConst) { | 161 if (isConst) { |
| 162 compiler.reportFatalError( | 162 compiler.reportFatalError( |
| 163 node, MessageKind.NOT_ASSIGNABLE, | 163 node, MessageKind.NOT_ASSIGNABLE, |
| 164 {'fromType': constantType, 'toType': elementType}); | 164 {'fromType': constantType, 'toType': elementType}); |
| 165 } else { | 165 } else { |
| 166 // If the field cannot be lazily initialized, we will throw | 166 // If the field cannot be lazily initialized, we will throw |
| 167 // the exception at runtime. | 167 // the exception at runtime. |
| 168 value = null; | 168 value = null; |
| 169 } | 169 } |
| 170 } | 170 } |
| 171 } | 171 } |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 if (value != null) { | 174 if (value != null) { |
| 175 initialVariableValues[element.declaration] = value; | 175 initialVariableValues[element.declaration] = value; |
| 176 } else { | 176 } else { |
| 177 assert(!isConst); | 177 assert(invariant(element, !isConst, |
| 178 message: "Variable $element does not compile to a constant.")); | |
| 178 } | 179 } |
| 179 pendingVariables.remove(element); | 180 pendingVariables.remove(element); |
| 180 return value; | 181 return value; |
| 181 } | 182 } |
| 182 | 183 |
| 183 Constant compileNodeWithDefinitions(Node node, | 184 ConstExp compileNodeWithDefinitions(Node node, |
| 184 TreeElements definitions, | 185 TreeElements definitions, |
| 185 {bool isConst: true}) { | 186 {bool isConst: true}) { |
| 186 assert(node != null); | 187 assert(node != null); |
| 187 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | 188 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 188 this, definitions, compiler, isConst: isConst); | 189 this, definitions, compiler, isConst: isConst); |
| 189 return evaluator.evaluate(node); | 190 EvaluatedConstant constant = evaluator.evaluate(node); |
| 191 return constant != null ? constant.expression : null; | |
| 190 } | 192 } |
| 191 | 193 |
| 192 Constant compileNode(Node node, TreeElements elements) { | 194 ConstExp compileNode(Node node, TreeElements elements) { |
| 193 return compileNodeWithDefinitions(node, elements); | 195 return compileNodeWithDefinitions(node, elements); |
| 194 } | 196 } |
| 195 | 197 |
| 196 Constant compileMetadata(MetadataAnnotation metadata, | 198 ConstExp compileMetadata(MetadataAnnotation metadata, |
| 197 Node node, | 199 Node node, |
| 198 TreeElements elements) { | 200 TreeElements elements) { |
| 199 return compileNodeWithDefinitions(node, elements); | 201 return compileNodeWithDefinitions(node, elements); |
| 200 } | 202 } |
| 201 } | 203 } |
| 202 | 204 |
| 203 /// [ConstantCompiler] that uses the Dart semantics for the compile-time | 205 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
| 204 /// constant evaluation. | 206 /// constant evaluation. |
| 205 class DartConstantCompiler extends ConstantCompilerBase { | 207 class DartConstantCompiler extends ConstantCompilerBase { |
| 206 DartConstantCompiler(Compiler compiler) | 208 DartConstantCompiler(Compiler compiler) |
| 207 : super(compiler, const DartConstantSystem()); | 209 : super(compiler, const DartConstantSystem()); |
| 208 | 210 |
| 209 Constant getConstantForNode(Node node, TreeElements definitions) { | 211 ConstExp getConstantForNode(Node node, TreeElements definitions) { |
| 210 return definitions.getConstant(node); | 212 return definitions.getConstant(node); |
| 211 } | 213 } |
| 212 | 214 |
| 213 Constant getConstantForMetadata(MetadataAnnotation metadata) { | 215 ConstExp getConstantForMetadata(MetadataAnnotation metadata) { |
| 214 return metadata.value; | 216 return metadata.constant; |
| 215 } | 217 } |
| 216 | 218 |
| 217 Constant compileNodeWithDefinitions(Node node, | 219 ConstExp compileNodeWithDefinitions(Node node, |
| 218 TreeElements definitions, | 220 TreeElements definitions, |
| 219 {bool isConst: true}) { | 221 {bool isConst: true}) { |
| 220 Constant constant = definitions.getConstant(node); | 222 ConstExp constant = definitions.getConstant(node); |
| 221 if (constant != null) { | 223 if (constant != null) { |
| 222 return constant; | 224 return constant; |
| 223 } | 225 } |
| 224 constant = | 226 constant = |
| 225 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); | 227 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| 226 if (constant != null) { | 228 if (constant != null) { |
| 227 definitions.setConstant(node, constant); | 229 definitions.setConstant(node, constant); |
| 228 } | 230 } |
| 229 return constant; | 231 return constant; |
| 230 } | 232 } |
| 231 } | 233 } |
| 232 | 234 |
| 233 // TODO(johnniwinther): Change to create [ConstExp] instead of [Constant]. | 235 // TODO(johnniwinther): Change to create [ConstExp] instead of [Constant]. |
|
sigurdm
2014/09/17 10:29:40
I think this TODO is solved now?
Johnni Winther
2014/09/17 12:20:39
Done.
| |
| 234 class CompileTimeConstantEvaluator extends Visitor { | 236 class CompileTimeConstantEvaluator extends Visitor<EvaluatedConstant> { |
|
sigurdm
2014/09/17 10:29:40
We might want to consider evaluating the constants
Johnni Winther
2014/09/17 12:20:39
Added a TODO.
| |
| 235 bool isEvaluatingConstant; | 237 bool isEvaluatingConstant; |
| 236 final ConstantCompilerBase handler; | 238 final ConstantCompilerBase handler; |
| 237 final TreeElements elements; | 239 final TreeElements elements; |
| 238 final Compiler compiler; | 240 final Compiler compiler; |
| 239 | 241 |
| 242 Element get context => elements.analyzedElement; | |
| 243 | |
| 240 CompileTimeConstantEvaluator(this.handler, | 244 CompileTimeConstantEvaluator(this.handler, |
| 241 this.elements, | 245 this.elements, |
| 242 this.compiler, | 246 this.compiler, |
| 243 {bool isConst: false}) | 247 {bool isConst: false}) |
| 244 : this.isEvaluatingConstant = isConst; | 248 : this.isEvaluatingConstant = isConst; |
| 245 | 249 |
| 246 ConstantSystem get constantSystem => handler.constantSystem; | 250 ConstantSystem get constantSystem => handler.constantSystem; |
| 247 | 251 |
| 248 Constant evaluate(Node node) { | 252 EvaluatedConstant evaluate(Node node) { |
| 249 return node.accept(this); | 253 return node.accept(this); |
| 250 } | 254 } |
| 251 | 255 |
| 252 Constant evaluateConstant(Node node) { | 256 EvaluatedConstant evaluateConstant(Node node) { |
| 253 bool oldIsEvaluatingConstant = isEvaluatingConstant; | 257 bool oldIsEvaluatingConstant = isEvaluatingConstant; |
| 254 isEvaluatingConstant = true; | 258 isEvaluatingConstant = true; |
| 255 Constant result = node.accept(this); | 259 EvaluatedConstant result = node.accept(this); |
| 256 isEvaluatingConstant = oldIsEvaluatingConstant; | 260 isEvaluatingConstant = oldIsEvaluatingConstant; |
| 257 assert(result != null); | 261 assert(result != null); |
| 258 return result; | 262 return result; |
| 259 } | 263 } |
| 260 | 264 |
| 261 Constant visitNode(Node node) { | 265 EvaluatedConstant visitNode(Node node) { |
| 262 return signalNotCompileTimeConstant(node); | 266 return signalNotCompileTimeConstant(node); |
| 263 } | 267 } |
| 264 | 268 |
| 265 Constant visitLiteralBool(LiteralBool node) { | 269 EvaluatedConstant visitLiteralBool(LiteralBool node) { |
| 266 return constantSystem.createBool(node.value); | 270 return new EvaluatedConstant( |
| 271 context, node, new PrimitiveConstExp( | |
| 272 constantSystem.createBool(node.value))); | |
| 267 } | 273 } |
| 268 | 274 |
| 269 Constant visitLiteralDouble(LiteralDouble node) { | 275 EvaluatedConstant visitLiteralDouble(LiteralDouble node) { |
| 270 return constantSystem.createDouble(node.value); | 276 return new EvaluatedConstant( |
| 277 context, node, new PrimitiveConstExp( | |
| 278 constantSystem.createDouble(node.value))); | |
| 271 } | 279 } |
| 272 | 280 |
| 273 Constant visitLiteralInt(LiteralInt node) { | 281 EvaluatedConstant visitLiteralInt(LiteralInt node) { |
| 274 return constantSystem.createInt(node.value); | 282 return new EvaluatedConstant( |
| 283 context, node, new PrimitiveConstExp( | |
| 284 constantSystem.createInt(node.value))); | |
| 275 } | 285 } |
| 276 | 286 |
| 277 Constant visitLiteralList(LiteralList node) { | 287 EvaluatedConstant visitLiteralList(LiteralList node) { |
| 278 if (!node.isConst) { | 288 if (!node.isConst) { |
| 279 return signalNotCompileTimeConstant(node); | 289 return signalNotCompileTimeConstant(node); |
| 280 } | 290 } |
| 281 List<Constant> arguments = <Constant>[]; | 291 List<ConstExp> argumentExpressions = <ConstExp>[]; |
| 292 List<Constant> argumentValues = <Constant>[]; | |
| 282 for (Link<Node> link = node.elements.nodes; | 293 for (Link<Node> link = node.elements.nodes; |
| 283 !link.isEmpty; | 294 !link.isEmpty; |
| 284 link = link.tail) { | 295 link = link.tail) { |
| 285 arguments.add(evaluateConstant(link.head)); | 296 EvaluatedConstant argument = evaluateConstant(link.head); |
| 297 if (argument == null) { | |
| 298 return null; | |
| 299 } | |
| 300 argumentExpressions.add(argument.expression); | |
| 301 argumentValues.add(argument.value); | |
| 286 } | 302 } |
| 287 DartType type = elements.getType(node); | 303 DartType type = elements.getType(node); |
| 288 return new ListConstant(type, arguments); | 304 return new EvaluatedConstant( |
| 305 context, node, new ListConstExp( | |
| 306 new ListConstant(type, argumentValues), | |
| 307 type, | |
| 308 argumentExpressions)); | |
| 289 } | 309 } |
| 290 | 310 |
| 291 Constant visitLiteralMap(LiteralMap node) { | 311 EvaluatedConstant visitLiteralMap(LiteralMap node) { |
| 292 if (!node.isConst) { | 312 if (!node.isConst) { |
| 293 return signalNotCompileTimeConstant(node); | 313 return signalNotCompileTimeConstant(node); |
| 294 } | 314 } |
| 295 List<Constant> keys = <Constant>[]; | 315 List<ConstExp> keyExpressions = <ConstExp>[]; |
| 296 Map<Constant, Constant> map = new Map<Constant, Constant>(); | 316 List<Constant> keyValues = <Constant>[]; |
| 317 Map<Constant, ConstExp> map = new Map<Constant, ConstExp>(); | |
| 297 for (Link<Node> link = node.entries.nodes; | 318 for (Link<Node> link = node.entries.nodes; |
| 298 !link.isEmpty; | 319 !link.isEmpty; |
| 299 link = link.tail) { | 320 link = link.tail) { |
| 300 LiteralMapEntry entry = link.head; | 321 LiteralMapEntry entry = link.head; |
| 301 Constant key = evaluateConstant(entry.key); | 322 EvaluatedConstant key = evaluateConstant(entry.key); |
| 302 if (!map.containsKey(key)) { | 323 if (key == null) { |
| 303 keys.add(key); | 324 return null; |
| 325 } | |
| 326 if (!map.containsKey(key.value)) { | |
| 327 keyExpressions.add(key.expression); | |
| 328 keyValues.add(key.value); | |
| 304 } else { | 329 } else { |
| 305 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); | 330 compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY); |
| 306 } | 331 } |
| 307 map[key] = evaluateConstant(entry.value); | 332 EvaluatedConstant value = evaluateConstant(entry.value); |
| 333 if (value == null) { | |
| 334 return null; | |
| 335 } | |
| 336 map[key.value] = value.expression; | |
| 308 } | 337 } |
| 309 List<Constant> values = map.values.toList(); | 338 List<ConstExp> valueExpressions = map.values.toList(); |
| 310 InterfaceType sourceType = elements.getType(node); | 339 InterfaceType type = elements.getType(node); |
| 311 return constantSystem.createMap(compiler, sourceType, keys, values); | 340 return new EvaluatedConstant( |
| 341 context, node, new MapConstExp( | |
| 342 constantSystem.createMap(compiler, type, keyValues, | |
| 343 valueExpressions.map((e) => e.value).toList()), | |
| 344 type, | |
| 345 keyExpressions, | |
| 346 valueExpressions)); | |
| 312 } | 347 } |
| 313 | 348 |
| 314 Constant visitLiteralNull(LiteralNull node) { | 349 EvaluatedConstant visitLiteralNull(LiteralNull node) { |
| 315 return constantSystem.createNull(); | 350 return new EvaluatedConstant( |
| 351 context, node, new PrimitiveConstExp( | |
| 352 constantSystem.createNull())); | |
| 316 } | 353 } |
| 317 | 354 |
| 318 Constant visitLiteralString(LiteralString node) { | 355 EvaluatedConstant visitLiteralString(LiteralString node) { |
| 319 return constantSystem.createString(node.dartString); | 356 return new EvaluatedConstant( |
| 357 context, node, new PrimitiveConstExp( | |
| 358 constantSystem.createString(node.dartString))); | |
| 320 } | 359 } |
| 321 | 360 |
| 322 Constant visitStringJuxtaposition(StringJuxtaposition node) { | 361 EvaluatedConstant visitStringJuxtaposition(StringJuxtaposition node) { |
| 323 StringConstant left = evaluate(node.first); | 362 EvaluatedConstant left = evaluate(node.first); |
| 324 StringConstant right = evaluate(node.second); | 363 EvaluatedConstant right = evaluate(node.second); |
| 325 if (left == null || right == null) return null; | 364 if (left == null || right == null) return null; |
| 326 return constantSystem.createString( | 365 StringConstant leftValue = left.value; |
| 327 new DartString.concat(left.value, right.value)); | 366 StringConstant rightValue = right.value; |
| 367 return new EvaluatedConstant( | |
| 368 context, node, new ConcatenateConstExp( | |
| 369 constantSystem.createString( | |
| 370 new DartString.concat(leftValue.value, rightValue.value)), | |
| 371 [left.expression, right.expression])); | |
| 328 } | 372 } |
| 329 | 373 |
| 330 Constant visitStringInterpolation(StringInterpolation node) { | 374 EvaluatedConstant visitStringInterpolation(StringInterpolation node) { |
| 331 StringConstant initialString = evaluate(node.string); | 375 List<ConstExp> subexpressions = <ConstExp>[]; |
| 332 if (initialString == null) return null; | 376 EvaluatedConstant initialString = evaluate(node.string); |
| 333 DartString accumulator = initialString.value; | 377 if (initialString == null) { |
| 378 return null; | |
| 379 } | |
| 380 subexpressions.add(initialString.expression); | |
| 381 StringConstant initialStringValue = initialString.value; | |
| 382 DartString accumulator = initialStringValue.value; | |
| 334 for (StringInterpolationPart part in node.parts) { | 383 for (StringInterpolationPart part in node.parts) { |
| 335 Constant expression = evaluate(part.expression); | 384 EvaluatedConstant subexpression = evaluate(part.expression); |
| 385 if (subexpression == null) { | |
| 386 return null; | |
| 387 } | |
| 388 subexpressions.add(subexpression.expression); | |
| 389 Constant expression = subexpression.value; | |
| 336 DartString expressionString; | 390 DartString expressionString; |
| 337 if (expression == null) { | 391 if (expression.isNum || expression.isBool) { |
| 338 return signalNotCompileTimeConstant(part.expression); | |
| 339 } else if (expression.isNum || expression.isBool) { | |
| 340 PrimitiveConstant primitive = expression; | 392 PrimitiveConstant primitive = expression; |
| 341 expressionString = new DartString.literal(primitive.value.toString()); | 393 expressionString = new DartString.literal(primitive.value.toString()); |
| 342 } else if (expression.isString) { | 394 } else if (expression.isString) { |
| 343 PrimitiveConstant primitive = expression; | 395 PrimitiveConstant primitive = expression; |
| 344 expressionString = primitive.value; | 396 expressionString = primitive.value; |
| 345 } else { | 397 } else { |
| 398 // TODO(johnniwinther): Specialize message to indicated that the problem | |
| 399 // is not constness but the types of the const expressions. | |
| 346 return signalNotCompileTimeConstant(part.expression); | 400 return signalNotCompileTimeConstant(part.expression); |
| 347 } | 401 } |
| 348 accumulator = new DartString.concat(accumulator, expressionString); | 402 accumulator = new DartString.concat(accumulator, expressionString); |
| 349 StringConstant partString = evaluate(part.string); | 403 EvaluatedConstant partString = evaluate(part.string); |
| 350 if (partString == null) return null; | 404 if (partString == null) return null; |
| 351 accumulator = new DartString.concat(accumulator, partString.value); | 405 subexpressions.add(partString.expression); |
| 406 StringConstant partStringValue = partString.value; | |
| 407 accumulator = new DartString.concat(accumulator, partStringValue.value); | |
| 352 }; | 408 }; |
| 353 return constantSystem.createString(accumulator); | 409 return new EvaluatedConstant( |
| 410 context, node, new ConcatenateConstExp( | |
| 411 constantSystem.createString(accumulator), | |
| 412 subexpressions)); | |
| 354 } | 413 } |
| 355 | 414 |
| 356 Constant visitLiteralSymbol(LiteralSymbol node) { | 415 EvaluatedConstant visitLiteralSymbol(LiteralSymbol node) { |
| 357 InterfaceType type = compiler.symbolClass.rawType; | 416 InterfaceType type = compiler.symbolClass.rawType; |
| 358 List<Constant> createArguments(_) { | 417 String text = node.slowNameString; |
| 359 return [constantSystem.createString( | 418 List<EvaluatedConstant> arguments = |
| 360 new DartString.literal(node.slowNameString))]; | 419 <EvaluatedConstant>[new EvaluatedConstant(context, node, |
| 361 } | 420 new PrimitiveConstExp(constantSystem.createString( |
| 362 return makeConstructedConstant( | 421 new DartString.literal(text))))]; |
| 363 compiler, handler, node, type, compiler.symbolConstructor, | 422 EvaluatedConstant constant = makeConstructedConstant( |
| 364 createArguments, isLiteralSymbol: true); | 423 compiler, handler, context, node, type, compiler.symbolConstructor, |
| 424 new Selector.callConstructor('', null, 1), | |
| 425 arguments, arguments); | |
| 426 return new EvaluatedConstant( | |
| 427 context, node, new SymbolConstExp(constant.value, text)); | |
| 365 } | 428 } |
| 366 | 429 |
| 367 Constant makeTypeConstant(DartType elementType) { | 430 EvaluatedConstant makeTypeConstant(Node node, DartType elementType) { |
| 368 DartType constantType = | 431 DartType constantType = |
| 369 compiler.backend.typeImplementation.computeType(compiler); | 432 compiler.backend.typeImplementation.computeType(compiler); |
| 370 return new TypeConstant(elementType, constantType); | 433 return new EvaluatedConstant( |
| 434 context, node, new TypeConstExp( | |
| 435 new TypeConstant(elementType, constantType), | |
| 436 elementType)); | |
| 371 } | 437 } |
| 372 | 438 |
| 373 /// Returns true if the prefix of the send resolves to a deferred import | 439 /// Returns true if the prefix of the send resolves to a deferred import |
| 374 /// prefix. | 440 /// prefix. |
| 375 bool isDeferredUse(Send send) { | 441 bool isDeferredUse(Send send) { |
| 376 if (send == null) return false; | 442 if (send == null) return false; |
| 377 return compiler.deferredLoadTask | 443 return compiler.deferredLoadTask |
| 378 .deferredPrefixElement(send, elements) != null; | 444 .deferredPrefixElement(send, elements) != null; |
| 379 } | 445 } |
| 380 | 446 |
| 381 Constant visitIdentifier(Identifier node) { | 447 EvaluatedConstant visitIdentifier(Identifier node) { |
| 382 Element element = elements[node]; | 448 Element element = elements[node]; |
| 383 if (Elements.isClass(element) || Elements.isTypedef(element)) { | 449 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 384 TypeDeclarationElement typeDeclarationElement = element; | 450 TypeDeclarationElement typeDeclarationElement = element; |
| 385 return makeTypeConstant(typeDeclarationElement.rawType); | 451 DartType type = typeDeclarationElement.rawType; |
| 452 return makeTypeConstant(node, type); | |
| 386 } | 453 } |
| 387 return signalNotCompileTimeConstant(node); | 454 return signalNotCompileTimeConstant(node); |
| 388 } | 455 } |
| 389 | 456 |
| 390 // TODO(floitsch): provide better error-messages. | 457 // TODO(floitsch): provide better error-messages. |
| 391 Constant visitSend(Send send) { | 458 EvaluatedConstant visitSend(Send send) { |
| 392 Element element = elements[send]; | 459 Element element = elements[send]; |
| 393 if (send.isPropertyAccess) { | 460 if (send.isPropertyAccess) { |
| 394 if (isDeferredUse(send)) { | 461 if (isDeferredUse(send)) { |
| 395 return signalNotCompileTimeConstant(send, | 462 return signalNotCompileTimeConstant(send, |
| 396 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 463 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
| 397 } | 464 } |
| 398 if (Elements.isStaticOrTopLevelFunction(element)) { | 465 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 399 return new FunctionConstant(element); | 466 return new EvaluatedConstant( |
| 467 context, send, new FunctionConstExp( | |
| 468 new FunctionConstant(element), | |
| 469 element)); | |
| 400 } else if (Elements.isStaticOrTopLevelField(element)) { | 470 } else if (Elements.isStaticOrTopLevelField(element)) { |
| 401 Constant result; | 471 ConstExp result; |
| 402 if (element.isConst) { | 472 if (element.isConst) { |
| 403 result = handler.compileConstant(element); | 473 result = handler.compileConstant(element); |
| 404 } else if (element.isFinal && !isEvaluatingConstant) { | 474 } else if (element.isFinal && !isEvaluatingConstant) { |
| 405 result = handler.compileVariable(element); | 475 result = handler.compileVariable(element); |
| 406 } | 476 } |
| 407 if (result != null) return result; | 477 if (result != null) { |
| 478 return new EvaluatedConstant( | |
| 479 context, send, new VariableConstExp(result.value, element)); | |
| 480 } | |
| 408 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | 481 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 409 assert(elements.isTypeLiteral(send)); | 482 assert(elements.isTypeLiteral(send)); |
| 410 return makeTypeConstant(elements.getTypeLiteralType(send)); | 483 return makeTypeConstant(send, elements.getTypeLiteralType(send)); |
| 411 } else if (send.receiver != null) { | 484 } else if (send.receiver != null) { |
| 412 // Fall through to error handling. | 485 // Fall through to error handling. |
| 413 } else if (!Elements.isUnresolved(element) | 486 } else if (!Elements.isUnresolved(element) |
| 414 && element.isVariable | 487 && element.isVariable |
| 415 && element.isConst) { | 488 && element.isConst) { |
| 416 Constant result = handler.compileConstant(element); | 489 ConstExp result = handler.compileConstant(element); |
| 417 if (result != null) return result; | 490 if (result != null) { |
| 491 return new EvaluatedConstant( | |
| 492 context, send, new VariableConstExp(result.value, element)); | |
| 493 } | |
| 418 } | 494 } |
| 419 return signalNotCompileTimeConstant(send); | 495 return signalNotCompileTimeConstant(send); |
| 420 } else if (send.isCall) { | 496 } else if (send.isCall) { |
| 421 if (identical(element, compiler.identicalFunction) | 497 if (identical(element, compiler.identicalFunction) |
| 422 && send.argumentCount() == 2) { | 498 && send.argumentCount() == 2) { |
| 423 Constant left = evaluate(send.argumentsNode.nodes.head); | 499 EvaluatedConstant left = evaluate(send.argumentsNode.nodes.head); |
| 424 Constant right = evaluate(send.argumentsNode.nodes.tail.head); | 500 EvaluatedConstant right = evaluate(send.argumentsNode.nodes.tail.head); |
| 425 Constant result = constantSystem.identity.fold(left, right); | 501 if (left == null || right == null) { |
| 426 if (result != null) return result; | 502 return null; |
| 503 } | |
| 504 Constant result = constantSystem.identity.fold(left.value, right.value); | |
| 505 if (result != null) { | |
| 506 return new EvaluatedConstant( | |
| 507 context, send, new BinaryConstExp(result, | |
| 508 left.expression, 'identical', right.expression)); | |
| 509 } | |
| 427 } | 510 } |
| 428 return signalNotCompileTimeConstant(send); | 511 return signalNotCompileTimeConstant(send); |
| 429 } else if (send.isPrefix) { | 512 } else if (send.isPrefix) { |
| 430 assert(send.isOperator); | 513 assert(send.isOperator); |
| 431 Constant receiverConstant = evaluate(send.receiver); | 514 EvaluatedConstant receiverConstant = evaluate(send.receiver); |
| 432 if (receiverConstant == null) return null; | 515 if (receiverConstant == null) { |
| 516 return null; | |
| 517 } | |
| 433 Operator op = send.selector; | 518 Operator op = send.selector; |
| 434 UnaryOperation operation = constantSystem.lookupUnary(op.source); | 519 UnaryOperation operation = constantSystem.lookupUnary(op.source); |
| 435 if (operation == null) { | 520 if (operation == null) { |
| 436 compiler.internalError(op, "Unexpected operator."); | 521 compiler.internalError(op, "Unexpected operator."); |
| 437 } | 522 } |
| 438 Constant folded = operation.fold(receiverConstant); | 523 Constant folded = operation.fold(receiverConstant.value); |
| 439 if (folded == null) return signalNotCompileTimeConstant(send); | 524 if (folded == null) { |
| 440 return folded; | 525 return signalNotCompileTimeConstant(send); |
| 526 } | |
| 527 return new EvaluatedConstant( | |
| 528 context, send, new UnaryConstExp(folded, | |
| 529 op.source, receiverConstant.expression)); | |
| 441 } else if (send.isOperator && !send.isPostfix) { | 530 } else if (send.isOperator && !send.isPostfix) { |
| 442 assert(send.argumentCount() == 1); | 531 assert(send.argumentCount() == 1); |
| 443 Constant left = evaluate(send.receiver); | 532 EvaluatedConstant left = evaluate(send.receiver); |
| 444 Constant right = evaluate(send.argumentsNode.nodes.head); | 533 EvaluatedConstant right = evaluate(send.argumentsNode.nodes.head); |
| 445 if (left == null || right == null) return null; | 534 if (left == null || right == null) { |
| 535 return null; | |
| 536 } | |
| 537 Constant leftValue = left.value; | |
| 538 Constant rightValue = right.value; | |
| 446 Operator op = send.selector.asOperator(); | 539 Operator op = send.selector.asOperator(); |
| 447 Constant folded = null; | 540 Constant folded = null; |
| 448 switch (op.source) { | 541 switch (op.source) { |
| 449 case "==": | 542 case "==": |
| 450 if (left.isPrimitive && right.isPrimitive) { | 543 if (leftValue.isPrimitive && rightValue.isPrimitive) { |
| 451 folded = constantSystem.equal.fold(left, right); | 544 folded = constantSystem.equal.fold(leftValue, rightValue); |
| 452 } | 545 } |
| 453 break; | 546 break; |
| 454 case "!=": | 547 case "!=": |
| 455 if (left.isPrimitive && right.isPrimitive) { | 548 if (leftValue.isPrimitive && rightValue.isPrimitive) { |
| 456 BoolConstant areEquals = constantSystem.equal.fold(left, right); | 549 BoolConstant areEquals = |
| 550 constantSystem.equal.fold(leftValue, rightValue); | |
| 457 if (areEquals == null) { | 551 if (areEquals == null) { |
| 458 folded = null; | 552 folded = null; |
| 459 } else { | 553 } else { |
| 460 folded = areEquals.negate(); | 554 folded = areEquals.negate(); |
| 461 } | 555 } |
| 462 } | 556 } |
| 463 break; | 557 break; |
| 464 default: | 558 default: |
| 465 BinaryOperation operation = constantSystem.lookupBinary(op.source); | 559 BinaryOperation operation = constantSystem.lookupBinary(op.source); |
| 466 if (operation != null) { | 560 if (operation != null) { |
| 467 folded = operation.fold(left, right); | 561 folded = operation.fold(leftValue, rightValue); |
| 468 } | 562 } |
| 469 } | 563 } |
| 470 if (folded == null) return signalNotCompileTimeConstant(send); | 564 if (folded == null) { |
| 471 return folded; | 565 return signalNotCompileTimeConstant(send); |
| 566 } | |
| 567 return new EvaluatedConstant( | |
| 568 context, send, new BinaryConstExp(folded, | |
| 569 left.expression, op.source, right.expression)); | |
| 472 } | 570 } |
| 473 return signalNotCompileTimeConstant(send); | 571 return signalNotCompileTimeConstant(send); |
| 474 } | 572 } |
| 475 | 573 |
| 476 Constant visitConditional(Conditional node) { | 574 EvaluatedConstant visitConditional(Conditional node) { |
| 477 Constant condition = evaluate(node.condition); | 575 EvaluatedConstant condition = evaluate(node.condition); |
| 478 if (condition == null) { | 576 if (condition == null) { |
| 479 return null; | 577 return null; |
| 480 } else if (!condition.isBool) { | 578 } else if (!condition.value.isBool) { |
| 481 DartType conditionType = condition.computeType(compiler); | 579 DartType conditionType = condition.value.computeType(compiler); |
| 482 if (isEvaluatingConstant) { | 580 if (isEvaluatingConstant) { |
| 483 compiler.reportFatalError( | 581 compiler.reportFatalError( |
| 484 node.condition, MessageKind.NOT_ASSIGNABLE, | 582 node.condition, MessageKind.NOT_ASSIGNABLE, |
| 485 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); | 583 {'fromType': conditionType, 'toType': compiler.boolClass.rawType}); |
| 486 } | 584 } |
| 487 return null; | 585 return null; |
| 488 } | 586 } |
| 489 Constant thenExpression = evaluate(node.thenExpression); | 587 EvaluatedConstant thenExpression = evaluate(node.thenExpression); |
| 490 Constant elseExpression = evaluate(node.elseExpression); | 588 EvaluatedConstant elseExpression = evaluate(node.elseExpression); |
| 491 BoolConstant boolCondition = condition; | 589 if (thenExpression == null || elseExpression == null) { |
| 492 return boolCondition.value ? thenExpression : elseExpression; | 590 return null; |
| 591 } | |
| 592 BoolConstant boolCondition = condition.value; | |
| 593 return new EvaluatedConstant( | |
| 594 context, node, new ConditionalConstExp( | |
| 595 boolCondition.value ? thenExpression.value : elseExpression.value, | |
| 596 condition.expression, | |
| 597 thenExpression.expression, | |
| 598 elseExpression.expression)); | |
| 493 } | 599 } |
| 494 | 600 |
| 495 Constant visitSendSet(SendSet node) { | 601 EvaluatedConstant visitSendSet(SendSet node) { |
| 496 return signalNotCompileTimeConstant(node); | 602 return signalNotCompileTimeConstant(node); |
| 497 } | 603 } |
| 498 | 604 |
| 499 /** | 605 /** |
| 500 * Returns the list of constants that are passed to the static function. | 606 * Returns the normalized list of constant arguments that are passed to the |
| 607 * constructor including both the concrete arguments and default values for | |
| 608 * omitted optional arguments. | |
| 501 * | 609 * |
| 502 * Invariant: [target] must be an implementation element. | 610 * Invariant: [target] must be an implementation element. |
| 503 */ | 611 */ |
| 504 List<Constant> evaluateArgumentsToConstructor(Node node, | 612 List<EvaluatedConstant> evaluateArgumentsToConstructor( |
| 505 Selector selector, | 613 Node node, |
| 506 Link<Node> arguments, | 614 Selector selector, |
| 507 FunctionElement target) { | 615 Link<Node> arguments, |
| 616 FunctionElement target, | |
| 617 {EvaluatedConstant compileArgument(Node node)}) { | |
| 508 assert(invariant(node, target.isImplementation)); | 618 assert(invariant(node, target.isImplementation)); |
| 509 List<Constant> compiledArguments = <Constant>[]; | 619 List<EvaluatedConstant> compiledArguments = <EvaluatedConstant>[]; |
| 510 | 620 |
| 511 Function compileArgument = evaluateConstant; | 621 EvaluatedConstant compileDefaultValue(VariableElement element) { |
| 512 Function compileConstant = handler.compileConstant; | 622 ConstExp constant = handler.compileConstant(element); |
| 623 return new EvaluatedConstant.fromDefaultValue(element, constant); | |
| 624 } | |
| 513 target.computeSignature(compiler); | 625 target.computeSignature(compiler); |
| 514 bool succeeded = selector.addArgumentsToList(arguments, | 626 bool succeeded = selector.addArgumentsToList(arguments, |
| 515 compiledArguments, | 627 compiledArguments, |
| 516 target, | 628 target, |
| 517 compileArgument, | 629 compileArgument, |
| 518 compileConstant, | 630 compileDefaultValue, |
| 519 compiler.world); | 631 compiler.world); |
| 520 if (!succeeded) { | 632 if (!succeeded) { |
| 521 String name = Elements.constructorNameForDiagnostics( | 633 String name = Elements.constructorNameForDiagnostics( |
| 522 target.enclosingClass.name, target.name); | 634 target.enclosingClass.name, target.name); |
| 523 compiler.reportFatalError( | 635 compiler.reportFatalError( |
| 524 node, | 636 node, |
| 525 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, | 637 MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS, |
| 526 {'constructorName': name}); | 638 {'constructorName': name}); |
| 527 } | 639 } |
| 528 return compiledArguments; | 640 return compiledArguments; |
| 529 } | 641 } |
| 530 | 642 |
| 531 Constant visitNewExpression(NewExpression node) { | 643 EvaluatedConstant visitNewExpression(NewExpression node) { |
| 532 if (!node.isConst) { | 644 if (!node.isConst) { |
| 533 return signalNotCompileTimeConstant(node); | 645 return signalNotCompileTimeConstant(node); |
| 534 } | 646 } |
| 535 | 647 |
| 536 Send send = node.send; | 648 Send send = node.send; |
| 537 FunctionElement constructor = elements[send]; | 649 FunctionElement constructor = elements[send]; |
| 538 if (Elements.isUnresolved(constructor)) { | 650 if (Elements.isUnresolved(constructor)) { |
| 539 return signalNotCompileTimeConstant(node); | 651 return signalNotCompileTimeConstant(node); |
| 540 } | 652 } |
| 541 | 653 |
| 542 // Deferred types can not be used in const instance creation expressions. | 654 // Deferred types can not be used in const instance creation expressions. |
| 543 // Check if the constructor comes from a deferred library. | 655 // Check if the constructor comes from a deferred library. |
| 544 if (isDeferredUse(node.send.selector.asSend())) { | 656 if (isDeferredUse(node.send.selector.asSend())) { |
| 545 return signalNotCompileTimeConstant(node, | 657 return signalNotCompileTimeConstant(node, |
| 546 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); | 658 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION); |
| 547 } | 659 } |
| 548 | 660 |
| 549 // TODO(ahe): This is nasty: we must eagerly analyze the | 661 // TODO(ahe): This is nasty: we must eagerly analyze the |
| 550 // constructor to ensure the redirectionTarget has been computed | 662 // constructor to ensure the redirectionTarget has been computed |
| 551 // correctly. Find a way to avoid this. | 663 // correctly. Find a way to avoid this. |
| 552 compiler.analyzeElement(constructor.declaration); | 664 compiler.analyzeElement(constructor.declaration); |
| 553 | 665 |
| 554 InterfaceType type = elements.getType(node); | 666 InterfaceType type = elements.getType(node); |
| 555 List<Constant> evaluateArguments(FunctionElement constructor) { | 667 Selector selector = elements.getSelector(send); |
| 556 Selector selector = elements.getSelector(send); | 668 |
| 557 return evaluateArgumentsToConstructor( | 669 Map<Node, EvaluatedConstant> concreteArgumentMap = |
| 558 node, selector, send.arguments, constructor); | 670 <Node, EvaluatedConstant>{}; |
| 671 for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) { | |
| 672 Node argument = link.head; | |
| 673 NamedArgument namedArgument = argument.asNamedArgument(); | |
| 674 if (namedArgument != null) { | |
| 675 argument = namedArgument.expression; | |
| 676 } | |
| 677 concreteArgumentMap[argument] = evaluateConstant(argument); | |
| 559 } | 678 } |
| 560 | 679 |
| 561 if (constructor == compiler.intEnvironment | 680 List<EvaluatedConstant> normalizedArguments = |
| 562 || constructor == compiler.boolEnvironment | 681 evaluateArgumentsToConstructor( |
| 563 || constructor == compiler.stringEnvironment) { | 682 node, selector, send.arguments, constructor.implementation, |
| 564 List<Constant> arguments = evaluateArguments(constructor.implementation); | 683 compileArgument: (node) => concreteArgumentMap[node]); |
| 565 var firstArgument = arguments[0]; | 684 List<EvaluatedConstant> concreteArguments = |
| 566 Constant defaultValue = arguments[1]; | 685 concreteArgumentMap.values.toList(); |
| 686 | |
| 687 if (constructor == compiler.intEnvironment || | |
| 688 constructor == compiler.boolEnvironment || | |
| 689 constructor == compiler.stringEnvironment) { | |
| 690 | |
| 691 EvaluatedConstant createEvaluatedConstant(Constant value) { | |
| 692 return new EvaluatedConstant( | |
| 693 context, node, new ConstructorConstExp( | |
| 694 value, | |
| 695 type, | |
| 696 constructor, | |
| 697 elements.getSelector(send), | |
| 698 concreteArguments.map((e) => e.expression).toList())); | |
| 699 } | |
| 700 | |
| 701 var firstArgument = normalizedArguments[0].value; | |
| 702 Constant defaultValue = normalizedArguments[1].value; | |
| 567 | 703 |
| 568 if (firstArgument is NullConstant) { | 704 if (firstArgument is NullConstant) { |
| 569 compiler.reportFatalError( | 705 compiler.reportFatalError( |
| 570 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); | 706 send.arguments.head, MessageKind.NULL_NOT_ALLOWED); |
| 707 return null; | |
| 571 } | 708 } |
| 572 | 709 |
| 573 if (firstArgument is! StringConstant) { | 710 if (firstArgument is! StringConstant) { |
| 574 DartType type = defaultValue.computeType(compiler); | 711 DartType type = defaultValue.computeType(compiler); |
| 575 compiler.reportFatalError( | 712 compiler.reportFatalError( |
| 576 send.arguments.head, MessageKind.NOT_ASSIGNABLE, | 713 send.arguments.head, MessageKind.NOT_ASSIGNABLE, |
| 577 {'fromType': type, 'toType': compiler.stringClass.rawType}); | 714 {'fromType': type, 'toType': compiler.stringClass.rawType}); |
| 715 return null; | |
| 578 } | 716 } |
| 579 | 717 |
| 580 if (constructor == compiler.intEnvironment | 718 if (constructor == compiler.intEnvironment |
| 581 && !(defaultValue is NullConstant || defaultValue is IntConstant)) { | 719 && !(defaultValue is NullConstant || defaultValue is IntConstant)) { |
| 582 DartType type = defaultValue.computeType(compiler); | 720 DartType type = defaultValue.computeType(compiler); |
| 583 compiler.reportFatalError( | 721 compiler.reportFatalError( |
| 584 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, | 722 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, |
| 585 {'fromType': type, 'toType': compiler.intClass.rawType}); | 723 {'fromType': type, 'toType': compiler.intClass.rawType}); |
| 724 return null; | |
| 586 } | 725 } |
| 587 | 726 |
| 588 if (constructor == compiler.boolEnvironment | 727 if (constructor == compiler.boolEnvironment |
| 589 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) { | 728 && !(defaultValue is NullConstant || defaultValue is BoolConstant)) { |
| 590 DartType type = defaultValue.computeType(compiler); | 729 DartType type = defaultValue.computeType(compiler); |
| 591 compiler.reportFatalError( | 730 compiler.reportFatalError( |
| 592 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, | 731 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, |
| 593 {'fromType': type, 'toType': compiler.boolClass.rawType}); | 732 {'fromType': type, 'toType': compiler.boolClass.rawType}); |
| 733 return null; | |
| 594 } | 734 } |
| 595 | 735 |
| 596 if (constructor == compiler.stringEnvironment | 736 if (constructor == compiler.stringEnvironment |
| 597 && !(defaultValue is NullConstant | 737 && !(defaultValue is NullConstant |
| 598 || defaultValue is StringConstant)) { | 738 || defaultValue is StringConstant)) { |
| 599 DartType type = defaultValue.computeType(compiler); | 739 DartType type = defaultValue.computeType(compiler); |
| 600 compiler.reportFatalError( | 740 compiler.reportFatalError( |
| 601 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, | 741 send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE, |
| 602 {'fromType': type, 'toType': compiler.stringClass.rawType}); | 742 {'fromType': type, 'toType': compiler.stringClass.rawType}); |
| 743 return null; | |
| 603 } | 744 } |
| 604 | 745 |
| 605 String value = | 746 String value = |
| 606 compiler.fromEnvironment(firstArgument.value.slowToString()); | 747 compiler.fromEnvironment(firstArgument.value.slowToString()); |
| 607 | 748 |
| 608 if (value == null) { | 749 if (value == null) { |
| 609 return defaultValue; | 750 return createEvaluatedConstant(defaultValue); |
| 610 } else if (constructor == compiler.intEnvironment) { | 751 } else if (constructor == compiler.intEnvironment) { |
| 611 int number = int.parse(value, onError: (_) => null); | 752 int number = int.parse(value, onError: (_) => null); |
| 612 return (number == null) | 753 return createEvaluatedConstant( |
| 613 ? defaultValue | 754 (number == null) |
| 614 : constantSystem.createInt(number); | 755 ? defaultValue |
| 756 : constantSystem.createInt(number)); | |
| 615 } else if (constructor == compiler.boolEnvironment) { | 757 } else if (constructor == compiler.boolEnvironment) { |
| 616 if (value == 'true') { | 758 if (value == 'true') { |
| 617 return constantSystem.createBool(true); | 759 return createEvaluatedConstant(constantSystem.createBool(true)); |
| 618 } else if (value == 'false') { | 760 } else if (value == 'false') { |
| 619 return constantSystem.createBool(false); | 761 return createEvaluatedConstant(constantSystem.createBool(false)); |
| 620 } else { | 762 } else { |
| 621 return defaultValue; | 763 return createEvaluatedConstant(defaultValue); |
| 622 } | 764 } |
| 623 } else { | 765 } else { |
| 624 assert(constructor == compiler.stringEnvironment); | 766 assert(constructor == compiler.stringEnvironment); |
| 625 return constantSystem.createString(new DartString.literal(value)); | 767 return createEvaluatedConstant( |
| 768 constantSystem.createString(new DartString.literal(value))); | |
| 626 } | 769 } |
| 627 } else { | 770 } else { |
| 628 return makeConstructedConstant( | 771 return makeConstructedConstant( |
| 629 compiler, handler, node, type, constructor, evaluateArguments); | 772 compiler, handler, context, |
| 773 node, type, constructor, selector, | |
| 774 concreteArguments, normalizedArguments); | |
| 630 } | 775 } |
| 631 } | 776 } |
| 632 | 777 |
| 633 static Constant makeConstructedConstant( | 778 static EvaluatedConstant makeConstructedConstant( |
| 634 Compiler compiler, | 779 Compiler compiler, |
| 635 ConstantCompilerBase handler, | 780 ConstantCompilerBase handler, |
| 636 Spannable node, | 781 Element context, |
| 782 Node node, | |
| 637 InterfaceType type, | 783 InterfaceType type, |
| 638 ConstructorElement constructor, | 784 ConstructorElement constructor, |
| 639 List<Constant> getArguments(ConstructorElement constructor), | 785 Selector selector, |
| 640 {bool isLiteralSymbol: false}) { | 786 List<EvaluatedConstant> concreteArguments, |
| 787 List<EvaluatedConstant> normalizedArguments) { | |
| 788 assert(invariant(node, selector.applies(constructor, compiler.world), | |
| 789 message: "Selector $selector does not apply to constructor " | |
| 790 "$constructor.")); | |
| 641 | 791 |
| 642 // The redirection chain of this element may not have been resolved through | 792 // The redirection chain of this element may not have been resolved through |
| 643 // a post-process action, so we have to make sure it is done here. | 793 // a post-process action, so we have to make sure it is done here. |
| 644 compiler.resolver.resolveRedirectionChain(constructor, node); | 794 compiler.resolver.resolveRedirectionChain(constructor, node); |
| 645 InterfaceType constructedType = | 795 InterfaceType constructedType = |
| 646 constructor.computeEffectiveTargetType(type); | 796 constructor.computeEffectiveTargetType(type); |
| 647 constructor = constructor.effectiveTarget; | 797 ConstructorElement target = constructor.effectiveTarget; |
| 648 ClassElement classElement = constructor.enclosingClass; | 798 ClassElement classElement = target.enclosingClass; |
| 649 // The constructor must be an implementation to ensure that field | 799 // The constructor must be an implementation to ensure that field |
| 650 // initializers are handled correctly. | 800 // initializers are handled correctly. |
| 651 constructor = constructor.implementation; | 801 target = target.implementation; |
| 652 assert(invariant(node, constructor.isImplementation)); | 802 assert(invariant(node, target.isImplementation)); |
| 653 | 803 |
| 654 List<Constant> arguments = getArguments(constructor); | |
| 655 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 804 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 656 constructedType, constructor, handler, compiler); | 805 constructedType, target, handler, compiler); |
| 657 evaluator.evaluateConstructorFieldValues(arguments); | 806 evaluator.evaluateConstructorFieldValues(normalizedArguments); |
| 658 List<Constant> jsNewArguments = evaluator.buildJsNewArguments(classElement); | 807 List<EvaluatedConstant> fieldConstants = |
| 808 evaluator.buildFieldConstants(classElement); | |
| 659 | 809 |
| 660 return new ConstructedConstant(constructedType, jsNewArguments, | 810 return new EvaluatedConstant( |
| 661 isLiteralSymbol: isLiteralSymbol); | 811 context, node, new ConstructorConstExp( |
| 812 new ConstructedConstant( | |
| 813 constructedType, | |
| 814 fieldConstants.map((e) => e.value).toList()), | |
| 815 type, | |
| 816 constructor, | |
| 817 selector, | |
| 818 concreteArguments.map((e) => e.expression).toList())); | |
| 662 } | 819 } |
| 663 | 820 |
| 664 Constant visitParenthesizedExpression(ParenthesizedExpression node) { | 821 EvaluatedConstant visitParenthesizedExpression(ParenthesizedExpression node) { |
| 665 return node.expression.accept(this); | 822 return node.expression.accept(this); |
| 666 } | 823 } |
| 667 | 824 |
| 668 error(Node node, MessageKind message) { | 825 error(Node node, MessageKind message) { |
| 669 // TODO(floitsch): get the list of constants that are currently compiled | 826 // TODO(floitsch): get the list of constants that are currently compiled |
| 670 // and present some kind of stack-trace. | 827 // and present some kind of stack-trace. |
| 671 compiler.reportFatalError(node, message); | 828 compiler.reportFatalError(node, message); |
| 672 } | 829 } |
| 673 | 830 |
| 674 Constant signalNotCompileTimeConstant(Node node, | 831 EvaluatedConstant signalNotCompileTimeConstant(Node node, |
| 675 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { | 832 {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) { |
| 676 if (isEvaluatingConstant) { | 833 if (isEvaluatingConstant) { |
| 677 error(node, message); | 834 error(node, message); |
| 678 } | 835 } |
| 679 // Else we don't need to do anything. The final handler is only | 836 // Else we don't need to do anything. The final handler is only |
| 680 // optimistically trying to compile constants. So it is normal that we | 837 // optimistically trying to compile constants. So it is normal that we |
| 681 // sometimes see non-compile time constants. | 838 // sometimes see non-compile time constants. |
| 682 // Simply return [:null:] which is used to propagate a failing | 839 // Simply return [:null:] which is used to propagate a failing |
| 683 // compile-time compilation. | 840 // compile-time compilation. |
| 684 return null; | 841 return null; |
| 685 } | 842 } |
| 686 } | 843 } |
| 687 | 844 |
| 688 class ConstructorEvaluator extends CompileTimeConstantEvaluator { | 845 class ConstructorEvaluator extends CompileTimeConstantEvaluator { |
| 689 final InterfaceType constructedType; | 846 final InterfaceType constructedType; |
| 690 final ConstructorElement constructor; | 847 final ConstructorElement constructor; |
| 691 final Map<Element, Constant> definitions; | 848 final Map<Element, EvaluatedConstant> definitions; |
| 692 final Map<Element, Constant> fieldValues; | 849 final Map<Element, EvaluatedConstant> fieldValues; |
| 693 | 850 |
| 694 /** | 851 /** |
| 695 * Documentation wanted -- johnniwinther | 852 * Documentation wanted -- johnniwinther |
| 696 * | 853 * |
| 697 * Invariant: [constructor] must be an implementation element. | 854 * Invariant: [constructor] must be an implementation element. |
| 698 */ | 855 */ |
| 699 ConstructorEvaluator(InterfaceType this.constructedType, | 856 ConstructorEvaluator(InterfaceType this.constructedType, |
| 700 FunctionElement constructor, | 857 FunctionElement constructor, |
| 701 ConstantCompiler handler, | 858 ConstantCompiler handler, |
| 702 Compiler compiler) | 859 Compiler compiler) |
| 703 : this.constructor = constructor, | 860 : this.constructor = constructor, |
| 704 this.definitions = new Map<Element, Constant>(), | 861 this.definitions = new Map<Element, EvaluatedConstant>(), |
| 705 this.fieldValues = new Map<Element, Constant>(), | 862 this.fieldValues = new Map<Element, EvaluatedConstant>(), |
| 706 super(handler, | 863 super(handler, |
| 707 compiler.resolver.resolveMethodElement(constructor.declaration), | 864 compiler.resolver.resolveMethodElement(constructor.declaration), |
| 708 compiler, | 865 compiler, |
| 709 isConst: true) { | 866 isConst: true) { |
| 710 assert(invariant(constructor, constructor.isImplementation)); | 867 assert(invariant(constructor, constructor.isImplementation)); |
| 711 } | 868 } |
| 712 | 869 |
| 713 Constant visitSend(Send send) { | 870 EvaluatedConstant visitSend(Send send) { |
| 714 Element element = elements[send]; | 871 Element element = elements[send]; |
| 715 if (Elements.isLocal(element)) { | 872 if (Elements.isLocal(element)) { |
| 716 Constant constant = definitions[element]; | 873 EvaluatedConstant constant = definitions[element]; |
| 717 if (constant == null) { | 874 if (constant == null) { |
| 718 compiler.internalError(send, "Local variable without value."); | 875 compiler.internalError(send, "Local variable without value."); |
| 719 } | 876 } |
| 720 return constant; | 877 return constant; |
| 721 } | 878 } |
| 722 return super.visitSend(send); | 879 return super.visitSend(send); |
| 723 } | 880 } |
| 724 | 881 |
| 725 void potentiallyCheckType(Node node, | 882 void potentiallyCheckType(Node node, |
| 726 TypedElement element, | 883 TypedElement element, |
| 727 Constant constant) { | 884 EvaluatedConstant constant) { |
| 728 if (compiler.enableTypeAssertions) { | 885 if (compiler.enableTypeAssertions) { |
| 729 DartType elementType = element.type.substByContext(constructedType); | 886 DartType elementType = element.type.substByContext(constructedType); |
| 730 DartType constantType = constant.computeType(compiler); | 887 DartType constantType = constant.value.computeType(compiler); |
| 731 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { | 888 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 732 compiler.reportFatalError( | 889 compiler.withCurrentElement(constant.element, () { |
| 733 node, MessageKind.NOT_ASSIGNABLE, | 890 compiler.reportFatalError( |
| 734 {'fromType': constantType, 'toType': elementType}); | 891 constant.node, MessageKind.NOT_ASSIGNABLE, |
| 892 {'fromType': constantType, 'toType': elementType}); | |
| 893 }); | |
| 735 } | 894 } |
| 736 } | 895 } |
| 737 } | 896 } |
| 738 | 897 |
| 739 void updateFieldValue(Node node, TypedElement element, Constant constant) { | 898 void updateFieldValue(Node node, |
| 899 TypedElement element, | |
| 900 EvaluatedConstant constant) { | |
| 740 potentiallyCheckType(node, element, constant); | 901 potentiallyCheckType(node, element, constant); |
| 741 fieldValues[element] = constant; | 902 fieldValues[element] = constant; |
| 742 } | 903 } |
| 743 | 904 |
| 744 /** | 905 /** |
| 745 * Given the arguments (a list of constants) assigns them to the parameters, | 906 * Given the arguments (a list of constants) assigns them to the parameters, |
| 746 * updating the definitions map. If the constructor has field-initializer | 907 * updating the definitions map. If the constructor has field-initializer |
| 747 * parameters (like [:this.x:]), also updates the [fieldValues] map. | 908 * parameters (like [:this.x:]), also updates the [fieldValues] map. |
| 748 */ | 909 */ |
| 749 void assignArgumentsToParameters(List<Constant> arguments) { | 910 void assignArgumentsToParameters(List<EvaluatedConstant> arguments) { |
| 750 // Assign arguments to parameters. | 911 // Assign arguments to parameters. |
| 751 FunctionSignature signature = constructor.functionSignature; | 912 FunctionSignature signature = constructor.functionSignature; |
| 752 int index = 0; | 913 int index = 0; |
| 753 signature.orderedForEachParameter((ParameterElement parameter) { | 914 signature.orderedForEachParameter((ParameterElement parameter) { |
| 754 Constant argument = arguments[index++]; | 915 EvaluatedConstant argument = arguments[index++]; |
| 755 Node node = parameter.node; | 916 Node node = parameter.node; |
| 756 potentiallyCheckType(node, parameter, argument); | |
| 757 definitions[parameter] = argument; | |
| 758 if (parameter.isInitializingFormal) { | 917 if (parameter.isInitializingFormal) { |
| 759 InitializingFormalElement initializingFormal = parameter; | 918 InitializingFormalElement initializingFormal = parameter; |
| 760 updateFieldValue(node, initializingFormal.fieldElement, argument); | 919 updateFieldValue(node, initializingFormal.fieldElement, argument); |
| 920 } else { | |
| 921 potentiallyCheckType(node, parameter, argument); | |
| 922 definitions[parameter] = argument; | |
| 761 } | 923 } |
| 762 }); | 924 }); |
| 763 } | 925 } |
| 764 | 926 |
| 765 void evaluateSuperOrRedirectSend(List<Constant> compiledArguments, | 927 void evaluateSuperOrRedirectSend(List<EvaluatedConstant> compiledArguments, |
| 766 FunctionElement targetConstructor) { | 928 FunctionElement targetConstructor) { |
| 767 ConstructorEvaluator evaluator = new ConstructorEvaluator( | 929 ConstructorEvaluator evaluator = new ConstructorEvaluator( |
| 768 constructedType.asInstanceOf(targetConstructor.enclosingClass), | 930 constructedType.asInstanceOf(targetConstructor.enclosingClass), |
| 769 targetConstructor, handler, compiler); | 931 targetConstructor, handler, compiler); |
| 770 evaluator.evaluateConstructorFieldValues(compiledArguments); | 932 evaluator.evaluateConstructorFieldValues(compiledArguments); |
| 771 // Copy over the fieldValues from the super/redirect-constructor. | 933 // Copy over the fieldValues from the super/redirect-constructor. |
| 772 // No need to go through [updateFieldValue] because the | 934 // No need to go through [updateFieldValue] because the |
| 773 // assignments have already been checked in checked mode. | 935 // assignments have already been checked in checked mode. |
| 774 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); | 936 evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value); |
| 775 } | 937 } |
| 776 | 938 |
| 777 /** | 939 /** |
| 778 * Runs through the initializers of the given [constructor] and updates | 940 * Runs through the initializers of the given [constructor] and updates |
| 779 * the [fieldValues] map. | 941 * the [fieldValues] map. |
| 780 */ | 942 */ |
| 781 void evaluateConstructorInitializers() { | 943 void evaluateConstructorInitializers() { |
| 782 if (constructor.isSynthesized) { | 944 if (constructor.isSynthesized) { |
| 783 List<Constant> compiledArguments = <Constant>[]; | 945 List<EvaluatedConstant> compiledArguments = <EvaluatedConstant>[]; |
| 784 | 946 |
| 785 Function compileArgument = (element) => definitions[element]; | 947 Function compileArgument = (element) => definitions[element]; |
| 786 Function compileConstant = handler.compileConstant; | 948 Function compileConstant = handler.compileConstant; |
| 787 FunctionElement target = constructor.definingConstructor.implementation; | 949 FunctionElement target = constructor.definingConstructor.implementation; |
| 788 Selector.addForwardingElementArgumentsToList(constructor, | 950 Selector.addForwardingElementArgumentsToList(constructor, |
| 789 compiledArguments, | 951 compiledArguments, |
| 790 target, | 952 target, |
| 791 compileArgument, | 953 compileArgument, |
| 792 compileConstant, | 954 compileConstant, |
| 793 compiler.world); | 955 compiler.world); |
| 794 evaluateSuperOrRedirectSend(compiledArguments, target); | 956 evaluateSuperOrRedirectSend(compiledArguments, target); |
| 795 return; | 957 return; |
| 796 } | 958 } |
| 797 FunctionExpression functionNode = constructor.node; | 959 FunctionExpression functionNode = constructor.node; |
| 798 NodeList initializerList = functionNode.initializers; | 960 NodeList initializerList = functionNode.initializers; |
| 799 | 961 |
| 800 bool foundSuperOrRedirect = false; | 962 bool foundSuperOrRedirect = false; |
| 801 | 963 |
| 802 if (initializerList != null) { | 964 if (initializerList != null) { |
| 803 for (Link<Node> link = initializerList.nodes; | 965 for (Link<Node> link = initializerList.nodes; |
| 804 !link.isEmpty; | 966 !link.isEmpty; |
| 805 link = link.tail) { | 967 link = link.tail) { |
| 806 assert(link.head is Send); | 968 assert(link.head is Send); |
| 807 if (link.head is !SendSet) { | 969 if (link.head is !SendSet) { |
| 808 // A super initializer or constructor redirection. | 970 // A super initializer or constructor redirection. |
| 809 Send call = link.head; | 971 Send call = link.head; |
| 810 FunctionElement target = elements[call]; | 972 FunctionElement target = elements[call]; |
| 811 List<Constant> compiledArguments = evaluateArgumentsToConstructor( | 973 List<EvaluatedConstant> compiledArguments = |
| 812 call, elements.getSelector(call), call.arguments, target); | 974 evaluateArgumentsToConstructor( |
| 975 call, elements.getSelector(call), call.arguments, target, | |
| 976 compileArgument: evaluateConstant); | |
| 813 evaluateSuperOrRedirectSend(compiledArguments, target); | 977 evaluateSuperOrRedirectSend(compiledArguments, target); |
| 814 foundSuperOrRedirect = true; | 978 foundSuperOrRedirect = true; |
| 815 } else { | 979 } else { |
| 816 // A field initializer. | 980 // A field initializer. |
| 817 SendSet init = link.head; | 981 SendSet init = link.head; |
| 818 Link<Node> initArguments = init.arguments; | 982 Link<Node> initArguments = init.arguments; |
| 819 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); | 983 assert(!initArguments.isEmpty && initArguments.tail.isEmpty); |
| 820 Constant fieldValue = evaluate(initArguments.head); | 984 EvaluatedConstant fieldValue = evaluate(initArguments.head); |
| 821 updateFieldValue(init, elements[init], fieldValue); | 985 updateFieldValue(init, elements[init], fieldValue); |
| 822 } | 986 } |
| 823 } | 987 } |
| 824 } | 988 } |
| 825 | 989 |
| 826 if (!foundSuperOrRedirect) { | 990 if (!foundSuperOrRedirect) { |
| 827 // No super initializer found. Try to find the default constructor if | 991 // No super initializer found. Try to find the default constructor if |
| 828 // the class is not Object. | 992 // the class is not Object. |
| 829 ClassElement enclosingClass = constructor.enclosingClass; | 993 ClassElement enclosingClass = constructor.enclosingClass; |
| 830 ClassElement superClass = enclosingClass.superclass; | 994 ClassElement superClass = enclosingClass.superclass; |
| 831 if (enclosingClass != compiler.objectClass) { | 995 if (enclosingClass != compiler.objectClass) { |
| 832 assert(superClass != null); | 996 assert(superClass != null); |
| 833 assert(superClass.resolutionState == STATE_DONE); | 997 assert(superClass.resolutionState == STATE_DONE); |
| 834 | 998 |
| 835 Selector selector = | 999 Selector selector = |
| 836 new Selector.callDefaultConstructor(enclosingClass.library); | 1000 new Selector.callDefaultConstructor(enclosingClass.library); |
| 837 | 1001 |
| 838 FunctionElement targetConstructor = | 1002 FunctionElement targetConstructor = |
| 839 superClass.lookupConstructor(selector); | 1003 superClass.lookupConstructor(selector); |
| 840 if (targetConstructor == null) { | 1004 if (targetConstructor == null) { |
| 841 compiler.internalError(functionNode, | 1005 compiler.internalError(functionNode, |
| 842 "No default constructor available."); | 1006 "No default constructor available."); |
| 843 } | 1007 } |
| 844 List<Constant> compiledArguments = evaluateArgumentsToConstructor( | 1008 List<EvaluatedConstant> compiledArguments = |
| 845 functionNode, selector, const Link<Node>(), targetConstructor); | 1009 evaluateArgumentsToConstructor( |
| 1010 functionNode, selector, const Link<Node>(), targetConstructor); | |
| 846 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); | 1011 evaluateSuperOrRedirectSend(compiledArguments, targetConstructor); |
| 847 } | 1012 } |
| 848 } | 1013 } |
| 849 } | 1014 } |
| 850 | 1015 |
| 851 /** | 1016 /** |
| 852 * Simulates the execution of the [constructor] with the given | 1017 * Simulates the execution of the [constructor] with the given |
| 853 * [arguments] to obtain the field values that need to be passed to the | 1018 * [arguments] to obtain the field values that need to be passed to the |
| 854 * native JavaScript constructor. | 1019 * native JavaScript constructor. |
| 855 */ | 1020 */ |
| 856 void evaluateConstructorFieldValues(List<Constant> arguments) { | 1021 void evaluateConstructorFieldValues(List<EvaluatedConstant> arguments) { |
| 857 compiler.withCurrentElement(constructor, () { | 1022 compiler.withCurrentElement(constructor, () { |
| 858 assignArgumentsToParameters(arguments); | 1023 assignArgumentsToParameters(arguments); |
| 859 evaluateConstructorInitializers(); | 1024 evaluateConstructorInitializers(); |
| 860 }); | 1025 }); |
| 861 } | 1026 } |
| 862 | 1027 |
| 863 List<Constant> buildJsNewArguments(ClassElement classElement) { | 1028 /// Builds a normalized list of the constant values for each field in the |
| 864 List<Constant> jsNewArguments = <Constant>[]; | 1029 /// inheritance chain of [classElement]. |
| 1030 List<EvaluatedConstant> buildFieldConstants(ClassElement classElement) { | |
| 1031 List<EvaluatedConstant> fieldConstants = <EvaluatedConstant>[]; | |
| 865 classElement.implementation.forEachInstanceField( | 1032 classElement.implementation.forEachInstanceField( |
| 866 (ClassElement enclosing, Element field) { | 1033 (ClassElement enclosing, FieldElement field) { |
| 867 Constant fieldValue = fieldValues[field]; | 1034 EvaluatedConstant fieldValue = fieldValues[field]; |
| 868 if (fieldValue == null) { | 1035 if (fieldValue == null) { |
| 869 // Use the default value. | 1036 // Use the default value. |
| 870 fieldValue = handler.compileConstant(field); | 1037 fieldValue = new EvaluatedConstant.fromDefaultValue( |
| 1038 field, handler.compileConstant(field)); | |
| 871 } | 1039 } |
| 872 jsNewArguments.add(fieldValue); | 1040 fieldConstants.add(fieldValue); |
| 873 }, | 1041 }, |
| 874 includeSuperAndInjectedMembers: true); | 1042 includeSuperAndInjectedMembers: true); |
| 875 return jsNewArguments; | 1043 return fieldConstants; |
| 876 } | 1044 } |
| 877 } | 1045 } |
| 1046 | |
| 1047 class EvaluatedConstant { | |
|
sigurdm
2014/09/17 10:29:40
Document this class esp. why we need it.
Maybe it
Johnni Winther
2014/09/17 12:20:39
Done.
| |
| 1048 final Element element; | |
| 1049 final Node node; | |
| 1050 final ConstExp expression; | |
| 1051 | |
| 1052 EvaluatedConstant(this.element, this.node, this.expression); | |
| 1053 | |
| 1054 factory EvaluatedConstant.fromDefaultValue( | |
| 1055 VariableElement element, | |
| 1056 ConstExp constant) { | |
| 1057 return new EvaluatedConstant( | |
| 1058 element, | |
| 1059 element.initializer != null ? element.initializer : element.node, | |
| 1060 constant); | |
| 1061 } | |
| 1062 | |
| 1063 Constant get value => expression.value; | |
| 1064 | |
| 1065 String toString() => expression.toString(); | |
| 1066 } | |
| OLD | NEW |