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 |