| 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 |
| 8 /// initializers. |
| 9 abstract class ConstantEnvironment { |
| 10 /// Returns the constant for the initializer of [element]. |
| 11 Constant getConstantForVariable(VariableElement element); |
| 12 } |
| 13 |
| 14 /// A class that can compile and provide constants for variables, nodes and |
| 15 /// metadata. |
| 16 abstract class ConstantCompiler extends ConstantEnvironment { |
| 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. |
| 19 /// |
| 20 /// Depending on implementation, the constant compiler might also compute |
| 21 /// the compile-time constant for the backend interpretation of constants. |
| 22 /// |
| 23 /// The returned constant is always of the frontend interpretation. |
| 24 Constant compileConstant(VariableElement element); |
| 25 |
| 26 /// Computes the compile-time constant for the variable initializer, |
| 27 /// if possible. |
| 28 void compileVariable(VariableElement element); |
| 29 |
| 30 /// Compiles the compile-time constant for [node], or reports an error if |
| 31 /// [node] is not a compile-time constant. |
| 32 /// |
| 33 /// Depending on implementation, the constant compiler might also compute |
| 34 /// the compile-time constant for the backend interpretation of constants. |
| 35 /// |
| 36 /// The returned constant is always of the frontend interpretation. |
| 37 Constant compileNode(Node node, TreeElements elements); |
| 38 |
| 39 /// Compiles the compile-time constant for the value [metadata], or reports an |
| 40 /// error if the value is not a compile-time constant. |
| 41 /// |
| 42 /// Depending on implementation, the constant compiler might also compute |
| 43 /// the compile-time constant for the backend interpretation of constants. |
| 44 /// |
| 45 /// The returned constant is always of the frontend interpretation. |
| 46 Constant compileMetadata(MetadataAnnotation metadata, |
| 47 Node node, TreeElements elements); |
| 48 } |
| 49 |
| 50 /// A [BackendConstantEnvironment] provides access to constants needed for |
| 51 /// backend implementation. |
| 52 abstract class BackendConstantEnvironment extends ConstantEnvironment { |
| 53 /// Returns the compile-time constant associated with [node]. |
| 54 /// |
| 55 /// Depending on implementation, the constant might be stored in [elements]. |
| 56 Constant getConstantForNode(Node node, TreeElements elements); |
| 57 |
| 58 /// Returns the compile-time constant value of [metadata]. |
| 59 Constant getConstantForMetadata(MetadataAnnotation metadata); |
| 60 } |
| 61 |
| 62 /// Interface for the task that compiles the constant environments for the |
| 63 /// frontend and backend interpretation of compile-time constants. |
| 64 abstract class ConstantCompilerTask extends CompilerTask |
| 65 implements ConstantCompiler { |
| 66 ConstantCompilerTask(Compiler compiler) : super(compiler); |
| 67 } |
| 68 |
| 7 /** | 69 /** |
| 8 * The [ConstantHandler] keeps track of compile-time constants, | 70 * The [ConstantCompilerBase] is provides base implementation for compilation of |
| 9 * initializations of global and static fields, and default values of | 71 * compile-time constants for both the Dart and JavaScript interpretation of |
| 10 * optional parameters. | 72 * constants. It keeps track of compile-time constants for initializations of |
| 73 * global and static fields, and default values of optional parameters. |
| 11 */ | 74 */ |
| 12 class ConstantHandler extends CompilerTask { | 75 abstract class ConstantCompilerBase implements ConstantCompiler { |
| 76 final Compiler compiler; |
| 13 final ConstantSystem constantSystem; | 77 final ConstantSystem constantSystem; |
| 14 final bool isMetadata; | |
| 15 | 78 |
| 16 /** | 79 /** |
| 17 * 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 |
| 18 * initializations of const fields. May contain eagerly compiled values for | 81 * initializations of const fields. May contain eagerly compiled values for |
| 19 * statics and instance fields. | 82 * statics and instance fields. |
| 20 * | 83 * |
| 21 * Invariant: The keys in this map are declarations. | 84 * Invariant: The keys in this map are declarations. |
| 22 */ | 85 */ |
| 23 final Map<VariableElement, Constant> initialVariableValues; | 86 final Map<VariableElement, Constant> initialVariableValues = |
| 24 | 87 new Map<VariableElement, Constant>(); |
| 25 /** Set of all registered compiled constants. */ | |
| 26 final Set<Constant> compiledConstants; | |
| 27 | 88 |
| 28 /** 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. */ |
| 29 final Set<VariableElement> pendingVariables; | 90 final Set<VariableElement> pendingVariables = new Set<VariableElement>(); |
| 30 | 91 |
| 31 /** Caches the statics where the initial value cannot be eagerly compiled. */ | 92 ConstantCompilerBase(this.compiler, this.constantSystem); |
| 32 final Set<VariableElement> lazyStatics; | |
| 33 | |
| 34 ConstantHandler(Compiler compiler, this.constantSystem, | |
| 35 { bool this.isMetadata: false }) | |
| 36 : initialVariableValues = new Map<VariableElement, dynamic>(), | |
| 37 compiledConstants = new Set<Constant>(), | |
| 38 pendingVariables = new Set<VariableElement>(), | |
| 39 lazyStatics = new Set<VariableElement>(), | |
| 40 super(compiler); | |
| 41 | |
| 42 String get name => 'ConstantHandler'; | |
| 43 | |
| 44 void addCompileTimeConstantForEmission(Constant constant) { | |
| 45 compiledConstants.add(constant); | |
| 46 } | |
| 47 | 93 |
| 48 Constant getConstantForVariable(VariableElement element) { | 94 Constant getConstantForVariable(VariableElement element) { |
| 49 return initialVariableValues[element.declaration]; | 95 return initialVariableValues[element.declaration]; |
| 50 } | 96 } |
| 51 | 97 |
| 52 /** | |
| 53 * Returns a compile-time constant, or reports an error if the element is not | |
| 54 * a compile-time constant. | |
| 55 */ | |
| 56 Constant compileConstant(VariableElement element) { | 98 Constant compileConstant(VariableElement element) { |
| 57 return compileVariable(element, isConst: true); | 99 return compileVariable(element, isConst: true); |
| 58 } | 100 } |
| 59 | 101 |
| 60 /** | |
| 61 * Returns the a compile-time constant if the variable could be compiled | |
| 62 * eagerly. Otherwise returns `null`. | |
| 63 */ | |
| 64 Constant compileVariable(VariableElement element, {bool isConst: false}) { | 102 Constant compileVariable(VariableElement element, {bool isConst: false}) { |
| 65 return measure(() { | 103 |
| 66 if (initialVariableValues.containsKey(element.declaration)) { | 104 if (initialVariableValues.containsKey(element.declaration)) { |
| 67 Constant result = initialVariableValues[element.declaration]; | 105 Constant result = initialVariableValues[element.declaration]; |
| 68 return result; | 106 return result; |
| 69 } | 107 } |
| 70 Element currentElement = element; | 108 Element currentElement = element; |
| 71 if (element.isParameter() | 109 if (element.isParameter() || |
| 72 || element.isFieldParameter() | 110 element.isFieldParameter() || |
| 73 || element.isVariable()) { | 111 element.isVariable()) { |
| 74 currentElement = element.enclosingElement; | 112 currentElement = element.enclosingElement; |
| 75 } | 113 } |
| 76 return compiler.withCurrentElement(currentElement, () { | 114 return compiler.withCurrentElement(currentElement, () { |
| 77 TreeElements definitions = | 115 TreeElements definitions = |
| 78 compiler.analyzeElement(currentElement.declaration); | 116 compiler.analyzeElement(currentElement.declaration); |
| 79 Constant constant = compileVariableWithDefinitions( | 117 Constant constant = compileVariableWithDefinitions( |
| 80 element, definitions, isConst: isConst); | 118 element, definitions, isConst: isConst); |
| 81 return constant; | 119 return constant; |
| 82 }); | |
| 83 }); | 120 }); |
| 84 } | 121 } |
| 85 | 122 |
| 86 /** | 123 /** |
| 87 * Returns the a compile-time constant if the variable could be compiled | 124 * Returns the a compile-time constant if the variable could be compiled |
| 88 * eagerly. If the variable needs to be initialized lazily returns `null`. | 125 * eagerly. If the variable needs to be initialized lazily returns `null`. |
| 89 * If the variable is `const` but cannot be compiled eagerly reports an | 126 * If the variable is `const` but cannot be compiled eagerly reports an |
| 90 * error. | 127 * error. |
| 91 */ | 128 */ |
| 92 Constant compileVariableWithDefinitions(VariableElement element, | 129 Constant compileVariableWithDefinitions(VariableElement element, |
| 93 TreeElements definitions, | 130 TreeElements definitions, |
| 94 {bool isConst: false}) { | 131 {bool isConst: false}) { |
| 95 return measure(() { | 132 Node node = element.parseNode(compiler); |
| 96 if (!isConst && lazyStatics.contains(element)) return null; | 133 if (pendingVariables.contains(element)) { |
| 134 if (isConst) { |
| 135 compiler.reportFatalError( |
| 136 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); |
| 137 } |
| 138 return null; |
| 139 } |
| 140 pendingVariables.add(element); |
| 97 | 141 |
| 98 Node node = element.parseNode(compiler); | 142 Expression initializer = element.initializer; |
| 99 if (pendingVariables.contains(element)) { | 143 Constant value; |
| 100 if (isConst) { | 144 if (initializer == null) { |
| 101 compiler.reportFatalError( | 145 // No initial value. |
| 102 node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS); | 146 value = new NullConstant(); |
| 147 } else { |
| 148 value = compileNodeWithDefinitions( |
| 149 initializer, definitions, isConst: isConst); |
| 150 if (compiler.enableTypeAssertions && |
| 151 value != null && |
| 152 element.isField()) { |
| 153 DartType elementType = element.type; |
| 154 if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) { |
| 155 if (isConst) { |
| 156 ErroneousElement element = elementType.element; |
| 157 compiler.reportFatalError( |
| 158 node, element.messageKind, element.messageArguments); |
| 159 } else { |
| 160 // We need to throw an exception at runtime. |
| 161 value = null; |
| 162 } |
| 103 } else { | 163 } else { |
| 104 lazyStatics.add(element); | 164 DartType constantType = value.computeType(compiler); |
| 105 return null; | 165 if (!constantSystem.isSubtype(compiler, |
| 106 } | 166 constantType, elementType)) { |
| 107 } | |
| 108 pendingVariables.add(element); | |
| 109 | |
| 110 Expression initializer = element.initializer; | |
| 111 Constant value; | |
| 112 if (initializer == null) { | |
| 113 // No initial value. | |
| 114 value = new NullConstant(); | |
| 115 } else { | |
| 116 value = compileNodeWithDefinitions( | |
| 117 initializer, definitions, isConst: isConst); | |
| 118 if (compiler.enableTypeAssertions && | |
| 119 value != null && | |
| 120 element.isField()) { | |
| 121 DartType elementType = element.type; | |
| 122 if (elementType.kind == TypeKind.MALFORMED_TYPE && !value.isNull) { | |
| 123 if (isConst) { | 167 if (isConst) { |
| 124 ErroneousElement element = elementType.element; | |
| 125 compiler.reportFatalError( | 168 compiler.reportFatalError( |
| 126 node, element.messageKind, element.messageArguments); | 169 node, MessageKind.NOT_ASSIGNABLE, |
| 170 {'fromType': constantType, 'toType': elementType}); |
| 127 } else { | 171 } else { |
| 128 // We need to throw an exception at runtime. | 172 // If the field cannot be lazily initialized, we will throw |
| 173 // the exception at runtime. |
| 129 value = null; | 174 value = null; |
| 130 } | 175 } |
| 131 } else { | |
| 132 DartType constantType = value.computeType(compiler); | |
| 133 if (!constantSystem.isSubtype(compiler, | |
| 134 constantType, elementType)) { | |
| 135 if (isConst) { | |
| 136 compiler.reportFatalError( | |
| 137 node, MessageKind.NOT_ASSIGNABLE, | |
| 138 {'fromType': constantType, 'toType': elementType}); | |
| 139 } else { | |
| 140 // If the field cannot be lazily initialized, we will throw | |
| 141 // the exception at runtime. | |
| 142 value = null; | |
| 143 } | |
| 144 } | |
| 145 } | 176 } |
| 146 } | 177 } |
| 147 } | 178 } |
| 148 if (value != null) { | 179 } |
| 149 initialVariableValues[element.declaration] = value; | 180 if (value != null) { |
| 150 } else { | 181 initialVariableValues[element.declaration] = value; |
| 151 assert(!isConst); | 182 } else { |
| 152 lazyStatics.add(element); | 183 assert(!isConst); |
| 153 } | 184 } |
| 154 pendingVariables.remove(element); | 185 pendingVariables.remove(element); |
| 155 return value; | 186 return value; |
| 156 }); | |
| 157 } | 187 } |
| 158 | 188 |
| 159 Constant compileNodeWithDefinitions(Node node, | 189 Constant compileNodeWithDefinitions(Node node, |
| 160 TreeElements definitions, | 190 TreeElements definitions, |
| 161 {bool isConst: false}) { | 191 {bool isConst: true}) { |
| 162 return measure(() { | 192 assert(node != null); |
| 163 assert(node != null); | 193 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( |
| 164 Constant constant = definitions.getConstant(node); | 194 this, definitions, compiler, isConst: isConst); |
| 165 if (constant != null) { | 195 return evaluator.evaluate(node); |
| 166 return constant; | |
| 167 } | |
| 168 CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator( | |
| 169 this, definitions, compiler, isConst: isConst); | |
| 170 constant = evaluator.evaluate(node); | |
| 171 if (constant != null) { | |
| 172 definitions.setConstant(node, constant); | |
| 173 } | |
| 174 return constant; | |
| 175 }); | |
| 176 } | 196 } |
| 177 | 197 |
| 178 /** | 198 Constant compileNode(Node node, TreeElements elements) { |
| 179 * Returns an [Iterable] of static non final fields that need to be | 199 return compileNodeWithDefinitions(node, elements); |
| 180 * initialized. The fields list must be evaluated in order since they might | |
| 181 * depend on each other. | |
| 182 */ | |
| 183 Iterable<VariableElement> getStaticNonFinalFieldsForEmission() { | |
| 184 return initialVariableValues.keys.where((element) { | |
| 185 return element.kind == ElementKind.FIELD | |
| 186 && !element.isInstanceMember() | |
| 187 && !element.modifiers.isFinal() | |
| 188 // The const fields are all either emitted elsewhere or inlined. | |
| 189 && !element.modifiers.isConst(); | |
| 190 }); | |
| 191 } | 200 } |
| 192 | 201 |
| 193 List<VariableElement> getLazilyInitializedFieldsForEmission() { | 202 Constant compileMetadata(MetadataAnnotation metadata, |
| 194 return new List<VariableElement>.from(lazyStatics); | 203 Node node, |
| 204 TreeElements elements) { |
| 205 return compileNodeWithDefinitions(node, elements); |
| 206 } |
| 207 } |
| 208 |
| 209 /// [ConstantCompiler] that uses the Dart semantics for the compile-time |
| 210 /// constant evaluation. |
| 211 class DartConstantCompiler extends ConstantCompilerBase { |
| 212 DartConstantCompiler(Compiler compiler) |
| 213 : super(compiler, const DartConstantSystem()); |
| 214 |
| 215 Constant getConstantForNode(Node node, TreeElements definitions) { |
| 216 return definitions.getConstant(node); |
| 195 } | 217 } |
| 196 | 218 |
| 197 /** | 219 Constant getConstantForMetadata(MetadataAnnotation metadata) { |
| 198 * Returns a list of constants topologically sorted so that dependencies | 220 return metadata.value; |
| 199 * appear before the dependent constant. [preSortCompare] is a comparator | |
| 200 * function that gives the constants a consistent order prior to the | |
| 201 * topological sort which gives the constants an ordering that is less | |
| 202 * sensitive to perturbations in the source code. | |
| 203 */ | |
| 204 List<Constant> getConstantsForEmission([preSortCompare]) { | |
| 205 // We must emit dependencies before their uses. | |
| 206 Set<Constant> seenConstants = new Set<Constant>(); | |
| 207 List<Constant> result = new List<Constant>(); | |
| 208 | |
| 209 void addConstant(Constant constant) { | |
| 210 if (!seenConstants.contains(constant)) { | |
| 211 constant.getDependencies().forEach(addConstant); | |
| 212 assert(!seenConstants.contains(constant)); | |
| 213 result.add(constant); | |
| 214 seenConstants.add(constant); | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 List<Constant> sorted = compiledConstants.toList(); | |
| 219 if (preSortCompare != null) { | |
| 220 sorted.sort(preSortCompare); | |
| 221 } | |
| 222 sorted.forEach(addConstant); | |
| 223 return result; | |
| 224 } | 221 } |
| 225 | 222 |
| 226 Constant getInitialValueFor(VariableElement element) { | 223 Constant compileNodeWithDefinitions(Node node, |
| 227 Constant initialValue = initialVariableValues[element.declaration]; | 224 TreeElements definitions, |
| 228 if (initialValue == null) { | 225 {bool isConst: true}) { |
| 229 compiler.internalError(element, "No initial value for given element."); | 226 Constant constant = definitions.getConstant(node); |
| 227 if (constant != null) { |
| 228 return constant; |
| 230 } | 229 } |
| 231 return initialValue; | 230 constant = |
| 231 super.compileNodeWithDefinitions(node, definitions, isConst: isConst); |
| 232 if (constant != null) { |
| 233 definitions.setConstant(node, constant); |
| 234 } |
| 235 return constant; |
| 232 } | 236 } |
| 233 } | 237 } |
| 234 | 238 |
| 235 class CompileTimeConstantEvaluator extends Visitor { | 239 class CompileTimeConstantEvaluator extends Visitor { |
| 236 bool isEvaluatingConstant; | 240 bool isEvaluatingConstant; |
| 237 final ConstantHandler handler; | 241 final ConstantCompilerBase handler; |
| 238 final TreeElements elements; | 242 final TreeElements elements; |
| 239 final Compiler compiler; | 243 final Compiler compiler; |
| 240 | 244 |
| 241 CompileTimeConstantEvaluator(this.handler, | 245 CompileTimeConstantEvaluator(this.handler, |
| 242 this.elements, | 246 this.elements, |
| 243 this.compiler, | 247 this.compiler, |
| 244 {bool isConst: false}) | 248 {bool isConst: false}) |
| 245 : this.isEvaluatingConstant = isConst; | 249 : this.isEvaluatingConstant = isConst; |
| 246 | 250 |
| 247 ConstantSystem get constantSystem => handler.constantSystem; | 251 ConstantSystem get constantSystem => handler.constantSystem; |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 if (prefixNode != null) { | 437 if (prefixNode != null) { |
| 434 Element maybePrefix = elements[prefixNode.asIdentifier()]; | 438 Element maybePrefix = elements[prefixNode.asIdentifier()]; |
| 435 if (maybePrefix != null && maybePrefix.isPrefix() && | 439 if (maybePrefix != null && maybePrefix.isPrefix() && |
| 436 (maybePrefix as PrefixElement).isDeferred) { | 440 (maybePrefix as PrefixElement).isDeferred) { |
| 437 return true; | 441 return true; |
| 438 } | 442 } |
| 439 } | 443 } |
| 440 return false; | 444 return false; |
| 441 } | 445 } |
| 442 | 446 |
| 447 Constant visitIdentifier(Identifier node) { |
| 448 Element element = elements[node]; |
| 449 if (Elements.isClass(element) || Elements.isTypedef(element)) { |
| 450 return makeTypeConstant(element); |
| 451 } |
| 452 return signalNotCompileTimeConstant(node); |
| 453 } |
| 454 |
| 443 // TODO(floitsch): provide better error-messages. | 455 // TODO(floitsch): provide better error-messages. |
| 444 Constant visitSend(Send send) { | 456 Constant visitSend(Send send) { |
| 445 Element element = elements[send]; | 457 Element element = elements[send]; |
| 446 if (send.isPropertyAccess) { | 458 if (send.isPropertyAccess) { |
| 447 if (isDeferredUse(send)) { | 459 if (isDeferredUse(send)) { |
| 448 return signalNotCompileTimeConstant(send, | 460 return signalNotCompileTimeConstant(send, |
| 449 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); | 461 message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT); |
| 450 } | 462 } |
| 451 if (Elements.isStaticOrTopLevelFunction(element)) { | 463 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 452 return new FunctionConstant(element); | 464 return new FunctionConstant(element); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 470 if (result != null) return result; | 482 if (result != null) return result; |
| 471 } | 483 } |
| 472 return signalNotCompileTimeConstant(send); | 484 return signalNotCompileTimeConstant(send); |
| 473 } else if (send.isCall) { | 485 } else if (send.isCall) { |
| 474 if (identical(element, compiler.identicalFunction) | 486 if (identical(element, compiler.identicalFunction) |
| 475 && send.argumentCount() == 2) { | 487 && send.argumentCount() == 2) { |
| 476 Constant left = evaluate(send.argumentsNode.nodes.head); | 488 Constant left = evaluate(send.argumentsNode.nodes.head); |
| 477 Constant right = evaluate(send.argumentsNode.nodes.tail.head); | 489 Constant right = evaluate(send.argumentsNode.nodes.tail.head); |
| 478 Constant result = constantSystem.identity.fold(left, right); | 490 Constant result = constantSystem.identity.fold(left, right); |
| 479 if (result != null) return result; | 491 if (result != null) return result; |
| 480 } else if (Elements.isClass(element) || Elements.isTypedef(element)) { | |
| 481 // The node itself is not a constant but we register the selector (the | |
| 482 // identifier that refers to the class/typedef) as a constant. | |
| 483 Constant typeConstant = makeTypeConstant(element); | |
| 484 elements.setConstant(send.selector, typeConstant); | |
| 485 } | 492 } |
| 486 return signalNotCompileTimeConstant(send); | 493 return signalNotCompileTimeConstant(send); |
| 487 } else if (send.isPrefix) { | 494 } else if (send.isPrefix) { |
| 488 assert(send.isOperator); | 495 assert(send.isOperator); |
| 489 Constant receiverConstant = evaluate(send.receiver); | 496 Constant receiverConstant = evaluate(send.receiver); |
| 490 if (receiverConstant == null) return null; | 497 if (receiverConstant == null) return null; |
| 491 Operator op = send.selector; | 498 Operator op = send.selector; |
| 492 Constant folded; | 499 Constant folded; |
| 493 switch (op.source) { | 500 switch (op.source) { |
| 494 case "!": | 501 case "!": |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 final FunctionElement constructor; | 810 final FunctionElement constructor; |
| 804 final Map<Element, Constant> definitions; | 811 final Map<Element, Constant> definitions; |
| 805 final Map<Element, Constant> fieldValues; | 812 final Map<Element, Constant> fieldValues; |
| 806 | 813 |
| 807 /** | 814 /** |
| 808 * Documentation wanted -- johnniwinther | 815 * Documentation wanted -- johnniwinther |
| 809 * | 816 * |
| 810 * Invariant: [constructor] must be an implementation element. | 817 * Invariant: [constructor] must be an implementation element. |
| 811 */ | 818 */ |
| 812 ConstructorEvaluator(FunctionElement constructor, | 819 ConstructorEvaluator(FunctionElement constructor, |
| 813 ConstantHandler handler, | 820 ConstantCompiler handler, |
| 814 Compiler compiler) | 821 Compiler compiler) |
| 815 : this.constructor = constructor, | 822 : this.constructor = constructor, |
| 816 this.definitions = new Map<Element, Constant>(), | 823 this.definitions = new Map<Element, Constant>(), |
| 817 this.fieldValues = new Map<Element, Constant>(), | 824 this.fieldValues = new Map<Element, Constant>(), |
| 818 super(handler, | 825 super(handler, |
| 819 compiler.resolver.resolveMethodElement(constructor.declaration), | 826 compiler.resolver.resolveMethodElement(constructor.declaration), |
| 820 compiler, | 827 compiler, |
| 821 isConst: true) { | 828 isConst: true) { |
| 822 assert(invariant(constructor, constructor.isImplementation)); | 829 assert(invariant(constructor, constructor.isImplementation)); |
| 823 } | 830 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 836 | 843 |
| 837 void potentiallyCheckType(Node node, | 844 void potentiallyCheckType(Node node, |
| 838 TypedElement element, | 845 TypedElement element, |
| 839 Constant constant) { | 846 Constant constant) { |
| 840 if (compiler.enableTypeAssertions) { | 847 if (compiler.enableTypeAssertions) { |
| 841 DartType elementType = element.type; | 848 DartType elementType = element.type; |
| 842 DartType constantType = constant.computeType(compiler); | 849 DartType constantType = constant.computeType(compiler); |
| 843 // TODO(ngeoffray): Handle type parameters. | 850 // TODO(ngeoffray): Handle type parameters. |
| 844 if (elementType.element.isTypeVariable()) return; | 851 if (elementType.element.isTypeVariable()) return; |
| 845 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { | 852 if (!constantSystem.isSubtype(compiler, constantType, elementType)) { |
| 853 // TODO(johnniwinther): Provide better [node] values that point to the |
| 854 // origin of the constant and not (just) the assignment. |
| 846 compiler.reportFatalError( | 855 compiler.reportFatalError( |
| 847 node, MessageKind.NOT_ASSIGNABLE, | 856 node, MessageKind.NOT_ASSIGNABLE, |
| 848 {'fromType': elementType, 'toType': constantType}); | 857 {'fromType': elementType, 'toType': constantType}); |
| 849 } | 858 } |
| 850 } | 859 } |
| 851 } | 860 } |
| 852 | 861 |
| 853 void updateFieldValue(Node node, TypedElement element, Constant constant) { | 862 void updateFieldValue(Node node, TypedElement element, Constant constant) { |
| 854 potentiallyCheckType(node, element, constant); | 863 potentiallyCheckType(node, element, constant); |
| 855 fieldValues[element] = constant; | 864 fieldValues[element] = constant; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 981 if (fieldValue == null) { | 990 if (fieldValue == null) { |
| 982 // Use the default value. | 991 // Use the default value. |
| 983 fieldValue = handler.compileConstant(field); | 992 fieldValue = handler.compileConstant(field); |
| 984 } | 993 } |
| 985 jsNewArguments.add(fieldValue); | 994 jsNewArguments.add(fieldValue); |
| 986 }, | 995 }, |
| 987 includeSuperAndInjectedMembers: true); | 996 includeSuperAndInjectedMembers: true); |
| 988 return jsNewArguments; | 997 return jsNewArguments; |
| 989 } | 998 } |
| 990 } | 999 } |
| OLD | NEW |