| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 resolution; | 5 part of resolution; |
| 6 | 6 |
| 7 class InitializerResolver { | 7 class InitializerResolver { |
| 8 final ResolverVisitor visitor; | 8 final ResolverVisitor visitor; |
| 9 final Map<Element, Node> initialized; | 9 final ConstructorElementX constructor; |
| 10 final FunctionExpression functionNode; |
| 11 final Map<FieldElement, Node> initialized = <FieldElement, Node>{}; |
| 12 final Map<FieldElement, ConstantExpression> fieldInitializers = |
| 13 <FieldElement, ConstantExpression>{}; |
| 10 Link<Node> initializers; | 14 Link<Node> initializers; |
| 11 bool hasSuper; | 15 bool hasSuper = false; |
| 16 bool isValidAsConstant = true; |
| 12 | 17 |
| 13 InitializerResolver(this.visitor) | 18 bool get isConst => constructor.isConst; |
| 14 : initialized = new Map<Element, Node>(), hasSuper = false; | 19 |
| 20 InitializerResolver(this.visitor, this.constructor, this.functionNode); |
| 15 | 21 |
| 16 ResolutionRegistry get registry => visitor.registry; | 22 ResolutionRegistry get registry => visitor.registry; |
| 17 | 23 |
| 18 error(Node node, MessageKind kind, [arguments = const {}]) { | 24 error(Node node, MessageKind kind, [arguments = const {}]) { |
| 19 visitor.error(node, kind, arguments); | 25 visitor.error(node, kind, arguments); |
| 20 } | 26 } |
| 21 | 27 |
| 22 warning(Node node, MessageKind kind, [arguments = const {}]) { | 28 warning(Node node, MessageKind kind, [arguments = const {}]) { |
| 23 visitor.warning(node, kind, arguments); | 29 visitor.warning(node, kind, arguments); |
| 24 } | 30 } |
| 25 | 31 |
| 26 bool isFieldInitializer(SendSet node) { | 32 bool isFieldInitializer(SendSet node) { |
| 27 if (node.selector.asIdentifier() == null) return false; | 33 if (node.selector.asIdentifier() == null) return false; |
| 28 if (node.receiver == null) return true; | 34 if (node.receiver == null) return true; |
| 29 if (node.receiver.asIdentifier() == null) return false; | 35 if (node.receiver.asIdentifier() == null) return false; |
| 30 return node.receiver.asIdentifier().isThis(); | 36 return node.receiver.asIdentifier().isThis(); |
| 31 } | 37 } |
| 32 | 38 |
| 33 reportDuplicateInitializerError(Element field, Node init, Node existing) { | 39 reportDuplicateInitializerError(Element field, Node init, Node existing) { |
| 34 visitor.compiler.reportError( | 40 visitor.compiler.reportError( |
| 35 init, | 41 init, |
| 36 MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}); | 42 MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}); |
| 37 visitor.compiler.reportInfo( | 43 visitor.compiler.reportInfo( |
| 38 existing, | 44 existing, |
| 39 MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name}); | 45 MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name}); |
| 46 isValidAsConstant = false; |
| 40 } | 47 } |
| 41 | 48 |
| 42 void checkForDuplicateInitializers(FieldElementX field, Node init) { | 49 void checkForDuplicateInitializers(FieldElementX field, Node init) { |
| 43 // [field] can be null if it could not be resolved. | 50 // [field] can be null if it could not be resolved. |
| 44 if (field == null) return; | 51 if (field == null) return; |
| 45 if (initialized.containsKey(field)) { | 52 if (initialized.containsKey(field)) { |
| 46 reportDuplicateInitializerError(field, init, initialized[field]); | 53 reportDuplicateInitializerError(field, init, initialized[field]); |
| 47 } else if (field.isFinal) { | 54 } else if (field.isFinal) { |
| 48 field.parseNode(visitor.compiler); | 55 field.parseNode(visitor.compiler); |
| 49 Expression initializer = field.initializer; | 56 Expression initializer = field.initializer; |
| 50 if (initializer != null) { | 57 if (initializer != null) { |
| 51 reportDuplicateInitializerError(field, init, initializer); | 58 reportDuplicateInitializerError(field, init, initializer); |
| 52 } | 59 } |
| 53 } | 60 } |
| 54 initialized[field] = init; | 61 initialized[field] = init; |
| 55 } | 62 } |
| 56 | 63 |
| 57 void resolveFieldInitializer(FunctionElement constructor, SendSet init) { | 64 void resolveFieldInitializer(SendSet init) { |
| 58 // init is of the form [this.]field = value. | 65 // init is of the form [this.]field = value. |
| 59 final Node selector = init.selector; | 66 final Node selector = init.selector; |
| 60 final String name = selector.asIdentifier().source; | 67 final String name = selector.asIdentifier().source; |
| 61 // Lookup target field. | 68 // Lookup target field. |
| 62 Element target; | 69 Element target; |
| 70 FieldElement field; |
| 63 if (isFieldInitializer(init)) { | 71 if (isFieldInitializer(init)) { |
| 64 target = constructor.enclosingClass.lookupLocalMember(name); | 72 target = constructor.enclosingClass.lookupLocalMember(name); |
| 65 if (target == null) { | 73 if (target == null) { |
| 66 error(selector, MessageKind.CANNOT_RESOLVE, {'name': name}); | 74 error(selector, MessageKind.CANNOT_RESOLVE, {'name': name}); |
| 67 target = new ErroneousFieldElementX( | 75 target = new ErroneousFieldElementX( |
| 68 selector.asIdentifier(), constructor.enclosingClass); | 76 selector.asIdentifier(), constructor.enclosingClass); |
| 69 } else if (target.kind != ElementKind.FIELD) { | 77 } else if (target.kind != ElementKind.FIELD) { |
| 70 error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name}); | 78 error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name}); |
| 71 target = new ErroneousFieldElementX( | 79 target = new ErroneousFieldElementX( |
| 72 selector.asIdentifier(), constructor.enclosingClass); | 80 selector.asIdentifier(), constructor.enclosingClass); |
| 73 } else if (!target.isInstanceMember) { | 81 } else if (!target.isInstanceMember) { |
| 74 error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); | 82 error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); |
| 83 } else { |
| 84 field = target; |
| 75 } | 85 } |
| 76 } else { | 86 } else { |
| 77 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); | 87 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |
| 78 } | 88 } |
| 79 registry.useElement(init, target); | 89 registry.useElement(init, target); |
| 80 registry.registerStaticUse(target); | 90 registry.registerStaticUse(target); |
| 81 checkForDuplicateInitializers(target, init); | 91 checkForDuplicateInitializers(target, init); |
| 82 // Resolve initializing value. | 92 // Resolve initializing value. |
| 83 visitor.visitInStaticContext(init.arguments.head); | 93 ResolutionResult result = visitor.visitInStaticContext( |
| 94 init.arguments.head, |
| 95 inConstantInitializer: isConst); |
| 96 if (isConst) { |
| 97 if (result.isConstant && field != null) { |
| 98 // TODO(johnniwinther): Report error if `result.constant` is `null`. |
| 99 fieldInitializers[field] = result.constant; |
| 100 } else { |
| 101 isValidAsConstant = false; |
| 102 } |
| 103 } |
| 84 } | 104 } |
| 85 | 105 |
| 86 ClassElement getSuperOrThisLookupTarget(FunctionElement constructor, | 106 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, |
| 87 bool isSuperCall, | 107 {bool isSuperCall}) { |
| 88 Node diagnosticNode) { | |
| 89 ClassElement lookupTarget = constructor.enclosingClass; | |
| 90 if (isSuperCall) { | 108 if (isSuperCall) { |
| 91 // Calculate correct lookup target and constructor name. | 109 // Calculate correct lookup target and constructor name. |
| 92 if (identical(lookupTarget, visitor.compiler.objectClass)) { | 110 if (identical(constructor.enclosingClass, visitor.compiler.objectClass)) { |
| 93 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | 111 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |
| 112 isValidAsConstant = false; |
| 94 } else { | 113 } else { |
| 95 return lookupTarget.supertype.element; | 114 return constructor.enclosingClass.supertype; |
| 96 } | 115 } |
| 97 } | 116 } |
| 98 return lookupTarget; | 117 return constructor.enclosingClass.thisType; |
| 99 } | 118 } |
| 100 | 119 |
| 101 Element resolveSuperOrThisForSend(FunctionElement constructor, | 120 ResolutionResult resolveSuperOrThisForSend(Send call) { |
| 102 FunctionExpression functionNode, | |
| 103 Send call) { | |
| 104 // Resolve the selector and the arguments. | 121 // Resolve the selector and the arguments. |
| 105 visitor.inStaticContext(() { | 122 ArgumentsResult argumentsResult = visitor.inStaticContext(() { |
| 106 visitor.resolveSelector(call, null); | 123 visitor.resolveSelector(call, null); |
| 107 visitor.resolveArguments(call.argumentsNode); | 124 return visitor.resolveArguments(call.argumentsNode); |
| 108 }); | 125 }, inConstantInitializer: isConst); |
| 109 Selector selector = registry.getSelector(call); | 126 |
| 110 bool isSuperCall = Initializers.isSuperConstructorCall(call); | 127 bool isSuperCall = Initializers.isSuperConstructorCall(call); |
| 111 | 128 InterfaceType targetType = |
| 112 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, | 129 getSuperOrThisLookupTarget(call, isSuperCall: isSuperCall); |
| 113 isSuperCall, | 130 ClassElement lookupTarget = targetType.element; |
| 114 call); | |
| 115 Selector constructorSelector = | 131 Selector constructorSelector = |
| 116 visitor.getRedirectingThisOrSuperConstructorSelector(call); | 132 visitor.getRedirectingThisOrSuperConstructorSelector(call); |
| 117 FunctionElement calledConstructor = | 133 FunctionElement calledConstructor = |
| 118 lookupTarget.lookupConstructor(constructorSelector.name); | 134 lookupTarget.lookupConstructor(constructorSelector.name); |
| 119 | 135 |
| 120 final bool isImplicitSuperCall = false; | 136 final bool isImplicitSuperCall = false; |
| 121 final String className = lookupTarget.name; | 137 final String className = lookupTarget.name; |
| 122 verifyThatConstructorMatchesCall(constructor, | 138 verifyThatConstructorMatchesCall(calledConstructor, |
| 123 calledConstructor, | 139 argumentsResult.callStructure, |
| 124 selector.callStructure, | |
| 125 isImplicitSuperCall, | 140 isImplicitSuperCall, |
| 126 call, | 141 call, |
| 127 className, | 142 className, |
| 128 constructorSelector); | 143 constructorSelector); |
| 129 | 144 |
| 130 registry.useElement(call, calledConstructor); | 145 registry.useElement(call, calledConstructor); |
| 131 registry.registerStaticUse(calledConstructor); | 146 registry.registerStaticUse(calledConstructor); |
| 132 return calledConstructor; | 147 if (isConst) { |
| 148 if (isValidAsConstant && |
| 149 calledConstructor.isConst && |
| 150 argumentsResult.isValidAsConstant) { |
| 151 CallStructure callStructure = argumentsResult.callStructure; |
| 152 List<ConstantExpression> arguments = argumentsResult.constantArguments; |
| 153 return new ConstantResult( |
| 154 call, |
| 155 new ConstructedConstantExpression( |
| 156 targetType, |
| 157 calledConstructor, |
| 158 callStructure, |
| 159 arguments), |
| 160 element: calledConstructor); |
| 161 } else { |
| 162 isValidAsConstant = false; |
| 163 } |
| 164 } |
| 165 return new ResolutionResult.forElement(calledConstructor); |
| 133 } | 166 } |
| 134 | 167 |
| 135 void resolveImplicitSuperConstructorSend(FunctionElement constructor, | 168 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { |
| 136 FunctionExpression functionNode) { | |
| 137 // If the class has a super resolve the implicit super call. | 169 // If the class has a super resolve the implicit super call. |
| 138 ClassElement classElement = constructor.enclosingClass; | 170 ClassElement classElement = constructor.enclosingClass; |
| 139 ClassElement superClass = classElement.superclass; | 171 ClassElement superClass = classElement.superclass; |
| 140 if (classElement != visitor.compiler.objectClass) { | 172 if (classElement != visitor.compiler.objectClass) { |
| 141 assert(superClass != null); | 173 assert(superClass != null); |
| 142 assert(superClass.isResolved); | 174 assert(superClass.isResolved); |
| 143 | 175 |
| 144 final bool isSuperCall = true; | 176 InterfaceType targetType = |
| 145 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, | 177 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); |
| 146 isSuperCall, | 178 ClassElement lookupTarget = targetType.element; |
| 147 functionNode); | |
| 148 Selector constructorSelector = new Selector.callDefaultConstructor(); | 179 Selector constructorSelector = new Selector.callDefaultConstructor(); |
| 149 Element calledConstructor = lookupTarget.lookupConstructor( | 180 Element calledConstructor = lookupTarget.lookupConstructor( |
| 150 constructorSelector.name); | 181 constructorSelector.name); |
| 151 | 182 |
| 152 final String className = lookupTarget.name; | 183 final String className = lookupTarget.name; |
| 153 final bool isImplicitSuperCall = true; | 184 final bool isImplicitSuperCall = true; |
| 154 verifyThatConstructorMatchesCall(constructor, | 185 verifyThatConstructorMatchesCall(calledConstructor, |
| 155 calledConstructor, | |
| 156 CallStructure.NO_ARGS, | 186 CallStructure.NO_ARGS, |
| 157 isImplicitSuperCall, | 187 isImplicitSuperCall, |
| 158 functionNode, | 188 functionNode, |
| 159 className, | 189 className, |
| 160 constructorSelector); | 190 constructorSelector); |
| 161 registry.registerImplicitSuperCall(calledConstructor); | 191 registry.registerImplicitSuperCall(calledConstructor); |
| 162 registry.registerStaticUse(calledConstructor); | 192 registry.registerStaticUse(calledConstructor); |
| 193 |
| 194 if (isConst && isValidAsConstant) { |
| 195 return new ConstructedConstantExpression( |
| 196 targetType, |
| 197 calledConstructor, |
| 198 CallStructure.NO_ARGS, |
| 199 const <ConstantExpression>[]); |
| 200 } |
| 163 } | 201 } |
| 202 return null; |
| 164 } | 203 } |
| 165 | 204 |
| 166 void verifyThatConstructorMatchesCall( | 205 void verifyThatConstructorMatchesCall( |
| 167 FunctionElement caller, | |
| 168 ConstructorElementX lookedupConstructor, | 206 ConstructorElementX lookedupConstructor, |
| 169 CallStructure call, | 207 CallStructure call, |
| 170 bool isImplicitSuperCall, | 208 bool isImplicitSuperCall, |
| 171 Node diagnosticNode, | 209 Node diagnosticNode, |
| 172 String className, | 210 String className, |
| 173 Selector constructorSelector) { | 211 Selector constructorSelector) { |
| 174 if (lookedupConstructor == null || | 212 if (lookedupConstructor == null || |
| 175 !lookedupConstructor.isGenerativeConstructor) { | 213 !lookedupConstructor.isGenerativeConstructor) { |
| 176 String fullConstructorName = Elements.constructorNameForDiagnostics( | 214 String fullConstructorName = Elements.constructorNameForDiagnostics( |
| 177 className, | 215 className, |
| 178 constructorSelector.name); | 216 constructorSelector.name); |
| 179 MessageKind kind = isImplicitSuperCall | 217 MessageKind kind = isImplicitSuperCall |
| 180 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | 218 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |
| 181 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | 219 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |
| 182 visitor.compiler.reportError( | 220 visitor.compiler.reportError( |
| 183 diagnosticNode, kind, {'constructorName': fullConstructorName}); | 221 diagnosticNode, kind, {'constructorName': fullConstructorName}); |
| 222 isValidAsConstant = false; |
| 184 } else { | 223 } else { |
| 185 lookedupConstructor.computeSignature(visitor.compiler); | 224 lookedupConstructor.computeSignature(visitor.compiler); |
| 186 if (!call.signatureApplies(lookedupConstructor.functionSignature)) { | 225 if (!call.signatureApplies(lookedupConstructor.functionSignature)) { |
| 187 MessageKind kind = isImplicitSuperCall | 226 MessageKind kind = isImplicitSuperCall |
| 188 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | 227 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |
| 189 : MessageKind.NO_MATCHING_CONSTRUCTOR; | 228 : MessageKind.NO_MATCHING_CONSTRUCTOR; |
| 190 visitor.compiler.reportError(diagnosticNode, kind); | 229 visitor.compiler.reportError(diagnosticNode, kind); |
| 191 } else if (caller.isConst | 230 isValidAsConstant = false; |
| 231 } else if (constructor.isConst |
| 192 && !lookedupConstructor.isConst) { | 232 && !lookedupConstructor.isConst) { |
| 193 MessageKind kind = isImplicitSuperCall | 233 MessageKind kind = isImplicitSuperCall |
| 194 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT | 234 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT |
| 195 : MessageKind.CONST_CALLS_NON_CONST; | 235 : MessageKind.CONST_CALLS_NON_CONST; |
| 196 visitor.compiler.reportError(diagnosticNode, kind); | 236 visitor.compiler.reportError(diagnosticNode, kind); |
| 237 isValidAsConstant = false; |
| 197 } | 238 } |
| 198 } | 239 } |
| 199 } | 240 } |
| 200 | 241 |
| 201 /** | 242 /** |
| 202 * Resolve all initializers of this constructor. In the case of a redirecting | 243 * Resolve all initializers of this constructor. In the case of a redirecting |
| 203 * constructor, the resolved constructor's function element is returned. | 244 * constructor, the resolved constructor's function element is returned. |
| 204 */ | 245 */ |
| 205 ConstructorElement resolveInitializers(ConstructorElementX constructor, | 246 ConstructorElement resolveInitializers() { |
| 206 FunctionExpression functionNode) { | 247 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = |
| 248 <dynamic/*String|int*/, ConstantExpression>{}; |
| 249 ConstructedConstantExpression constructorInvocation; |
| 207 // Keep track of all "this.param" parameters specified for constructor so | 250 // Keep track of all "this.param" parameters specified for constructor so |
| 208 // that we can ensure that fields are initialized only once. | 251 // that we can ensure that fields are initialized only once. |
| 209 FunctionSignature functionParameters = constructor.functionSignature; | 252 FunctionSignature functionParameters = constructor.functionSignature; |
| 210 functionParameters.forEachParameter((ParameterElement element) { | 253 functionParameters.forEachParameter((ParameterElementX element) { |
| 254 if (isConst) { |
| 255 if (element.isOptional) { |
| 256 if (element.constantCache == null) { |
| 257 // TODO(johnniwinther): Remove this when all constant expressions |
| 258 // can be computed during resolution. |
| 259 isValidAsConstant = false; |
| 260 } else { |
| 261 ConstantExpression defaultValue = element.constant; |
| 262 if (defaultValue != null) { |
| 263 if (element.isNamed) { |
| 264 defaultValues[element.name] = defaultValue; |
| 265 } else { |
| 266 int index = |
| 267 element.functionDeclaration.parameters.indexOf(element); |
| 268 defaultValues[index] = defaultValue; |
| 269 } |
| 270 } else { |
| 271 isValidAsConstant = false; |
| 272 } |
| 273 } |
| 274 } |
| 275 } |
| 211 if (element.isInitializingFormal) { | 276 if (element.isInitializingFormal) { |
| 212 InitializingFormalElement initializingFormal = element; | 277 InitializingFormalElementX initializingFormal = element; |
| 213 checkForDuplicateInitializers(initializingFormal.fieldElement, | 278 FieldElement field = initializingFormal.fieldElement; |
| 214 element.initializer); | 279 checkForDuplicateInitializers(field, element.initializer); |
| 280 if (isConst) { |
| 281 if (element.isNamed) { |
| 282 fieldInitializers[field] = new NamedArgumentReference(element.name); |
| 283 } else { |
| 284 int index = element.functionDeclaration.parameters.indexOf(element); |
| 285 fieldInitializers[field] = new PositionalArgumentReference(index); |
| 286 } |
| 287 } else { |
| 288 isValidAsConstant = false; |
| 289 } |
| 215 } | 290 } |
| 216 }); | 291 }); |
| 217 | 292 |
| 218 if (functionNode.initializers == null) { | 293 if (functionNode.initializers == null) { |
| 219 initializers = const Link<Node>(); | 294 initializers = const Link<Node>(); |
| 220 } else { | 295 } else { |
| 221 initializers = functionNode.initializers.nodes; | 296 initializers = functionNode.initializers.nodes; |
| 222 } | 297 } |
| 223 bool resolvedSuper = false; | 298 bool resolvedSuper = false; |
| 224 for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) { | 299 for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) { |
| 225 if (link.head.asSendSet() != null) { | 300 if (link.head.asSendSet() != null) { |
| 226 final SendSet init = link.head.asSendSet(); | 301 final SendSet init = link.head.asSendSet(); |
| 227 resolveFieldInitializer(constructor, init); | 302 resolveFieldInitializer(init); |
| 228 } else if (link.head.asSend() != null) { | 303 } else if (link.head.asSend() != null) { |
| 229 final Send call = link.head.asSend(); | 304 final Send call = link.head.asSend(); |
| 230 if (call.argumentsNode == null) { | 305 if (call.argumentsNode == null) { |
| 231 error(link.head, MessageKind.INVALID_INITIALIZER); | 306 error(link.head, MessageKind.INVALID_INITIALIZER); |
| 232 continue; | 307 continue; |
| 233 } | 308 } |
| 234 if (Initializers.isSuperConstructorCall(call)) { | 309 if (Initializers.isSuperConstructorCall(call)) { |
| 235 if (resolvedSuper) { | 310 if (resolvedSuper) { |
| 236 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); | 311 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); |
| 237 } | 312 } |
| 238 resolveSuperOrThisForSend(constructor, functionNode, call); | 313 ResolutionResult result = resolveSuperOrThisForSend(call); |
| 314 if (isConst) { |
| 315 if (result.isConstant) { |
| 316 constructorInvocation = result.constant; |
| 317 } else { |
| 318 isValidAsConstant = false; |
| 319 } |
| 320 } |
| 239 resolvedSuper = true; | 321 resolvedSuper = true; |
| 240 } else if (Initializers.isConstructorRedirect(call)) { | 322 } else if (Initializers.isConstructorRedirect(call)) { |
| 241 // Check that there is no body (Language specification 7.5.1). If the | 323 // Check that there is no body (Language specification 7.5.1). If the |
| 242 // constructor is also const, we already reported an error in | 324 // constructor is also const, we already reported an error in |
| 243 // [resolveMethodElement]. | 325 // [resolveMethodElement]. |
| 244 if (functionNode.hasBody() && !constructor.isConst) { | 326 if (functionNode.hasBody() && !constructor.isConst) { |
| 245 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); | 327 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); |
| 246 } | 328 } |
| 247 // Check that there are no other initializers. | 329 // Check that there are no other initializers. |
| 248 if (!initializers.tail.isEmpty) { | 330 if (!initializers.tail.isEmpty) { |
| 249 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); | 331 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); |
| 250 } else { | 332 } else { |
| 251 constructor.isRedirectingGenerative = true; | 333 constructor.isRedirectingGenerative = true; |
| 252 } | 334 } |
| 253 // Check that there are no field initializing parameters. | 335 // Check that there are no field initializing parameters. |
| 254 FunctionSignature signature = constructor.functionSignature; | 336 FunctionSignature signature = constructor.functionSignature; |
| 255 signature.forEachParameter((ParameterElement parameter) { | 337 signature.forEachParameter((ParameterElement parameter) { |
| 256 if (parameter.isInitializingFormal) { | 338 if (parameter.isInitializingFormal) { |
| 257 Node node = parameter.node; | 339 Node node = parameter.node; |
| 258 error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED); | 340 error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED); |
| 341 isValidAsConstant = false; |
| 259 } | 342 } |
| 260 }); | 343 }); |
| 261 return resolveSuperOrThisForSend(constructor, functionNode, call); | 344 ResolutionResult result = resolveSuperOrThisForSend(call); |
| 345 if (isConst) { |
| 346 if (result.isConstant) { |
| 347 constructorInvocation = result.constant; |
| 348 } else { |
| 349 isValidAsConstant = false; |
| 350 } |
| 351 if (isConst && isValidAsConstant) { |
| 352 constructor.constantConstructor = |
| 353 new RedirectingGenerativeConstantConstructor( |
| 354 defaultValues, |
| 355 constructorInvocation); |
| 356 } |
| 357 } |
| 358 return result.element; |
| 262 } else { | 359 } else { |
| 263 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); | 360 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |
| 264 return null; | 361 return null; |
| 265 } | 362 } |
| 266 } else { | 363 } else { |
| 267 error(link.head, MessageKind.INVALID_INITIALIZER); | 364 error(link.head, MessageKind.INVALID_INITIALIZER); |
| 268 } | 365 } |
| 269 } | 366 } |
| 270 if (!resolvedSuper) { | 367 if (!resolvedSuper) { |
| 271 resolveImplicitSuperConstructorSend(constructor, functionNode); | 368 constructorInvocation = resolveImplicitSuperConstructorSend(); |
| 369 } |
| 370 if (isConst && isValidAsConstant) { |
| 371 constructor.constantConstructor = new GenerativeConstantConstructor( |
| 372 constructor.enclosingClass.thisType, |
| 373 defaultValues, |
| 374 fieldInitializers, |
| 375 constructorInvocation); |
| 272 } | 376 } |
| 273 return null; // If there was no redirection always return null. | 377 return null; // If there was no redirection always return null. |
| 274 } | 378 } |
| 275 } | 379 } |
| 276 | 380 |
| 277 class ConstructorResolver extends CommonResolverVisitor<Element> { | 381 class ConstructorResolver extends CommonResolverVisitor<Element> { |
| 278 final ResolverVisitor resolver; | 382 final ResolverVisitor resolver; |
| 279 bool inConstContext; | 383 bool inConstContext; |
| 280 DartType type; | 384 DartType type; |
| 281 | 385 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 return element; | 572 return element; |
| 469 } | 573 } |
| 470 | 574 |
| 471 /// Assumed to be called by [resolveRedirectingFactory]. | 575 /// Assumed to be called by [resolveRedirectingFactory]. |
| 472 Element visitRedirectingFactoryBody(RedirectingFactoryBody node) { | 576 Element visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
| 473 Node constructorReference = node.constructorReference; | 577 Node constructorReference = node.constructorReference; |
| 474 return finishConstructorReference(visit(constructorReference), | 578 return finishConstructorReference(visit(constructorReference), |
| 475 constructorReference, node); | 579 constructorReference, node); |
| 476 } | 580 } |
| 477 } | 581 } |
| OLD | NEW |