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 library dart2js.resolution.constructors; | 5 library dart2js.resolution.constructors; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/resolution.dart' show | 8 import '../common/resolution.dart' show Feature; |
9 Feature; | 9 import '../compiler.dart' show Compiler; |
10 import '../compiler.dart' show | 10 import '../constants/constructors.dart' |
11 Compiler; | 11 show |
12 import '../constants/constructors.dart' show | 12 GenerativeConstantConstructor, |
13 GenerativeConstantConstructor, | 13 RedirectingGenerativeConstantConstructor; |
14 RedirectingGenerativeConstantConstructor; | |
15 import '../constants/expressions.dart'; | 14 import '../constants/expressions.dart'; |
16 import '../dart_types.dart'; | 15 import '../dart_types.dart'; |
17 import '../elements/elements.dart'; | 16 import '../elements/elements.dart'; |
18 import '../elements/modelx.dart' show | 17 import '../elements/modelx.dart' |
19 ConstructorElementX, | 18 show |
20 ErroneousConstructorElementX, | 19 ConstructorElementX, |
21 ErroneousElementX, | 20 ErroneousConstructorElementX, |
22 ErroneousFieldElementX, | 21 ErroneousElementX, |
23 FieldElementX, | 22 ErroneousFieldElementX, |
24 InitializingFormalElementX, | 23 FieldElementX, |
25 ParameterElementX; | 24 InitializingFormalElementX, |
| 25 ParameterElementX; |
26 import '../tree/tree.dart'; | 26 import '../tree/tree.dart'; |
27 import '../util/util.dart' show | 27 import '../util/util.dart' show Link; |
28 Link; | 28 import '../universe/call_structure.dart' show CallStructure; |
29 import '../universe/call_structure.dart' show | 29 import '../universe/use.dart' show StaticUse; |
30 CallStructure; | |
31 import '../universe/use.dart' show | |
32 StaticUse; | |
33 | 30 |
34 import 'members.dart' show | 31 import 'members.dart' show lookupInScope, ResolverVisitor; |
35 lookupInScope, | 32 import 'registry.dart' show ResolutionRegistry; |
36 ResolverVisitor; | 33 import 'resolution_common.dart' show CommonResolverVisitor; |
37 import 'registry.dart' show | |
38 ResolutionRegistry; | |
39 import 'resolution_common.dart' show | |
40 CommonResolverVisitor; | |
41 import 'resolution_result.dart'; | 34 import 'resolution_result.dart'; |
42 | 35 |
43 class InitializerResolver { | 36 class InitializerResolver { |
44 final ResolverVisitor visitor; | 37 final ResolverVisitor visitor; |
45 final ConstructorElementX constructor; | 38 final ConstructorElementX constructor; |
46 final FunctionExpression functionNode; | 39 final FunctionExpression functionNode; |
47 final Map<FieldElement, Node> initialized = <FieldElement, Node>{}; | 40 final Map<FieldElement, Node> initialized = <FieldElement, Node>{}; |
48 final Map<FieldElement, ConstantExpression> fieldInitializers = | 41 final Map<FieldElement, ConstantExpression> fieldInitializers = |
49 <FieldElement, ConstantExpression>{}; | 42 <FieldElement, ConstantExpression>{}; |
50 Link<Node> initializers; | 43 Link<Node> initializers; |
51 bool hasSuper = false; | 44 bool hasSuper = false; |
52 bool isValidAsConstant = true; | 45 bool isValidAsConstant = true; |
53 | 46 |
54 bool get isConst => constructor.isConst; | 47 bool get isConst => constructor.isConst; |
55 | 48 |
56 InitializerResolver(this.visitor, this.constructor, this.functionNode); | 49 InitializerResolver(this.visitor, this.constructor, this.functionNode); |
57 | 50 |
58 ResolutionRegistry get registry => visitor.registry; | 51 ResolutionRegistry get registry => visitor.registry; |
59 | 52 |
60 DiagnosticReporter get reporter => visitor.reporter; | 53 DiagnosticReporter get reporter => visitor.reporter; |
61 | 54 |
62 bool isFieldInitializer(SendSet node) { | 55 bool isFieldInitializer(SendSet node) { |
63 if (node.selector.asIdentifier() == null) return false; | 56 if (node.selector.asIdentifier() == null) return false; |
64 if (node.receiver == null) return true; | 57 if (node.receiver == null) return true; |
65 if (node.receiver.asIdentifier() == null) return false; | 58 if (node.receiver.asIdentifier() == null) return false; |
66 return node.receiver.asIdentifier().isThis(); | 59 return node.receiver.asIdentifier().isThis(); |
67 } | 60 } |
68 | 61 |
69 reportDuplicateInitializerError(Element field, | 62 reportDuplicateInitializerError( |
70 Node init, | 63 Element field, Node init, Spannable existing) { |
71 Spannable existing) { | |
72 reporter.reportError( | 64 reporter.reportError( |
73 reporter.createMessage( | 65 reporter.createMessage( |
74 init, | 66 init, MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}), |
75 MessageKind.DUPLICATE_INITIALIZER, | |
76 {'fieldName': field.name}), | |
77 <DiagnosticMessage>[ | 67 <DiagnosticMessage>[ |
78 reporter.createMessage( | 68 reporter.createMessage(existing, MessageKind.ALREADY_INITIALIZED, |
79 existing, | 69 {'fieldName': field.name}), |
80 MessageKind.ALREADY_INITIALIZED, | |
81 {'fieldName': field.name}), | |
82 ]); | 70 ]); |
83 isValidAsConstant = false; | 71 isValidAsConstant = false; |
84 } | 72 } |
85 | 73 |
86 void checkForDuplicateInitializers(FieldElementX field, Node init) { | 74 void checkForDuplicateInitializers(FieldElementX field, Node init) { |
87 // [field] can be null if it could not be resolved. | 75 // [field] can be null if it could not be resolved. |
88 if (field == null) return; | 76 if (field == null) return; |
89 if (initialized.containsKey(field)) { | 77 if (initialized.containsKey(field)) { |
90 reportDuplicateInitializerError(field, init, initialized[field]); | 78 reportDuplicateInitializerError(field, init, initialized[field]); |
91 } else if (field.isFinal) { | 79 } else if (field.isFinal) { |
92 field.parseNode(visitor.resolution.parsing); | 80 field.parseNode(visitor.resolution.parsing); |
93 Expression initializer = field.initializer; | 81 Expression initializer = field.initializer; |
94 if (initializer != null) { | 82 if (initializer != null) { |
95 reportDuplicateInitializerError(field, init, | 83 reportDuplicateInitializerError( |
96 reporter.withCurrentElement(field, | 84 field, |
97 () => reporter.spanFromSpannable(initializer))); | 85 init, |
| 86 reporter.withCurrentElement( |
| 87 field, () => reporter.spanFromSpannable(initializer))); |
98 } | 88 } |
99 } | 89 } |
100 initialized[field] = init; | 90 initialized[field] = init; |
101 } | 91 } |
102 | 92 |
103 void resolveFieldInitializer(SendSet init) { | 93 void resolveFieldInitializer(SendSet init) { |
104 // init is of the form [this.]field = value. | 94 // init is of the form [this.]field = value. |
105 final Node selector = init.selector; | 95 final Node selector = init.selector; |
106 final String name = selector.asIdentifier().source; | 96 final String name = selector.asIdentifier().source; |
107 // Lookup target field. | 97 // Lookup target field. |
(...skipping 22 matching lines...) Expand all Loading... |
130 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); | 120 init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |
131 } | 121 } |
132 if (target != null) { | 122 if (target != null) { |
133 registry.useElement(init, target); | 123 registry.useElement(init, target); |
134 checkForDuplicateInitializers(target, init); | 124 checkForDuplicateInitializers(target, init); |
135 } | 125 } |
136 if (field != null) { | 126 if (field != null) { |
137 registry.registerStaticUse(new StaticUse.fieldInit(field)); | 127 registry.registerStaticUse(new StaticUse.fieldInit(field)); |
138 } | 128 } |
139 // Resolve initializing value. | 129 // Resolve initializing value. |
140 ResolutionResult result = visitor.visitInStaticContext( | 130 ResolutionResult result = visitor.visitInStaticContext(init.arguments.head, |
141 init.arguments.head, | |
142 inConstantInitializer: isConst); | 131 inConstantInitializer: isConst); |
143 if (isConst) { | 132 if (isConst) { |
144 if (result.isConstant && field != null) { | 133 if (result.isConstant && field != null) { |
145 // TODO(johnniwinther): Report error if `result.constant` is `null`. | 134 // TODO(johnniwinther): Report error if `result.constant` is `null`. |
146 fieldInitializers[field] = result.constant; | 135 fieldInitializers[field] = result.constant; |
147 } else { | 136 } else { |
148 isValidAsConstant = false; | 137 isValidAsConstant = false; |
149 } | 138 } |
150 } | 139 } |
151 } | 140 } |
152 | 141 |
153 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, | 142 InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode, |
154 {bool isSuperCall}) { | 143 {bool isSuperCall}) { |
155 if (isSuperCall) { | 144 if (isSuperCall) { |
156 // Calculate correct lookup target and constructor name. | 145 // Calculate correct lookup target and constructor name. |
157 if (constructor.enclosingClass.isObject) { | 146 if (constructor.enclosingClass.isObject) { |
158 reporter.reportErrorMessage( | 147 reporter.reportErrorMessage( |
159 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | 148 diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |
160 isValidAsConstant = false; | 149 isValidAsConstant = false; |
161 } else { | 150 } else { |
162 return constructor.enclosingClass.supertype; | 151 return constructor.enclosingClass.supertype; |
163 } | 152 } |
164 } | 153 } |
165 return constructor.enclosingClass.thisType; | 154 return constructor.enclosingClass.thisType; |
166 } | 155 } |
167 | 156 |
168 ResolutionResult resolveSuperOrThisForSend(Send node) { | 157 ResolutionResult resolveSuperOrThisForSend(Send node) { |
169 // Resolve the selector and the arguments. | 158 // Resolve the selector and the arguments. |
170 ArgumentsResult argumentsResult = visitor.inStaticContext(() { | 159 ArgumentsResult argumentsResult = visitor.inStaticContext(() { |
171 // TODO(johnniwinther): Remove this when [SendStructure] is used directly. | 160 // TODO(johnniwinther): Remove this when [SendStructure] is used directly. |
172 visitor.resolveSelector(node, null); | 161 visitor.resolveSelector(node, null); |
173 return visitor.resolveArguments(node.argumentsNode); | 162 return visitor.resolveArguments(node.argumentsNode); |
174 }, inConstantInitializer: isConst); | 163 }, inConstantInitializer: isConst); |
175 | 164 |
176 bool isSuperCall = Initializers.isSuperConstructorCall(node); | 165 bool isSuperCall = Initializers.isSuperConstructorCall(node); |
177 InterfaceType targetType = | 166 InterfaceType targetType = |
178 getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall); | 167 getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall); |
179 ClassElement lookupTarget = targetType.element; | 168 ClassElement lookupTarget = targetType.element; |
180 String constructorName = | 169 String constructorName = |
181 visitor.getRedirectingThisOrSuperConstructorName(node).text; | 170 visitor.getRedirectingThisOrSuperConstructorName(node).text; |
182 ConstructorElement foundConstructor = findConstructor( | 171 ConstructorElement foundConstructor = |
183 constructor.library, lookupTarget, constructorName); | 172 findConstructor(constructor.library, lookupTarget, constructorName); |
184 | 173 |
185 final bool isImplicitSuperCall = false; | 174 final bool isImplicitSuperCall = false; |
186 final String className = lookupTarget.name; | 175 final String className = lookupTarget.name; |
187 CallStructure callStructure = argumentsResult.callStructure; | 176 CallStructure callStructure = argumentsResult.callStructure; |
188 ConstructorElement calledConstructor = verifyThatConstructorMatchesCall( | 177 ConstructorElement calledConstructor = verifyThatConstructorMatchesCall( |
189 node, | 178 node, foundConstructor, callStructure, className, |
190 foundConstructor, | |
191 callStructure, | |
192 className, | |
193 constructorName: constructorName, | 179 constructorName: constructorName, |
194 isThisCall: !isSuperCall, | 180 isThisCall: !isSuperCall, |
195 isImplicitSuperCall: false); | 181 isImplicitSuperCall: false); |
196 // TODO(johnniwinther): Remove this when information is pulled from an | 182 // TODO(johnniwinther): Remove this when information is pulled from an |
197 // [InitializerStructure]. | 183 // [InitializerStructure]. |
198 registry.useElement(node, calledConstructor); | 184 registry.useElement(node, calledConstructor); |
199 if (!calledConstructor.isError) { | 185 if (!calledConstructor.isError) { |
200 registry.registerStaticUse( | 186 registry.registerStaticUse(new StaticUse.superConstructorInvoke( |
201 new StaticUse.superConstructorInvoke( | 187 calledConstructor, callStructure)); |
202 calledConstructor, callStructure)); | |
203 } | 188 } |
204 if (isConst) { | 189 if (isConst) { |
205 if (isValidAsConstant && | 190 if (isValidAsConstant && |
206 calledConstructor.isConst && | 191 calledConstructor.isConst && |
207 argumentsResult.isValidAsConstant) { | 192 argumentsResult.isValidAsConstant) { |
208 List<ConstantExpression> arguments = argumentsResult.constantArguments; | 193 List<ConstantExpression> arguments = argumentsResult.constantArguments; |
209 return new ConstantResult( | 194 return new ConstantResult( |
210 node, | 195 node, |
211 new ConstructedConstantExpression( | 196 new ConstructedConstantExpression( |
212 targetType, | 197 targetType, calledConstructor, callStructure, arguments), |
213 calledConstructor, | |
214 callStructure, | |
215 arguments), | |
216 element: calledConstructor); | 198 element: calledConstructor); |
217 } else { | 199 } else { |
218 isValidAsConstant = false; | 200 isValidAsConstant = false; |
219 } | 201 } |
220 } | 202 } |
221 return new ResolutionResult.forElement(calledConstructor); | 203 return new ResolutionResult.forElement(calledConstructor); |
222 } | 204 } |
223 | 205 |
224 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { | 206 ConstructedConstantExpression resolveImplicitSuperConstructorSend() { |
225 // If the class has a super resolve the implicit super call. | 207 // If the class has a super resolve the implicit super call. |
226 ClassElement classElement = constructor.enclosingClass; | 208 ClassElement classElement = constructor.enclosingClass; |
227 ClassElement superClass = classElement.superclass; | 209 ClassElement superClass = classElement.superclass; |
228 if (!classElement.isObject) { | 210 if (!classElement.isObject) { |
229 assert(superClass != null); | 211 assert(superClass != null); |
230 assert(superClass.isResolved); | 212 assert(superClass.isResolved); |
231 | 213 |
232 InterfaceType targetType = | 214 InterfaceType targetType = |
233 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); | 215 getSuperOrThisLookupTarget(functionNode, isSuperCall: true); |
234 ClassElement lookupTarget = targetType.element; | 216 ClassElement lookupTarget = targetType.element; |
235 ConstructorElement calledConstructor = | 217 ConstructorElement calledConstructor = |
236 findConstructor(constructor.library, lookupTarget, ''); | 218 findConstructor(constructor.library, lookupTarget, ''); |
237 | 219 |
238 final String className = lookupTarget.name; | 220 final String className = lookupTarget.name; |
239 CallStructure callStructure = CallStructure.NO_ARGS; | 221 CallStructure callStructure = CallStructure.NO_ARGS; |
240 ConstructorElement result = verifyThatConstructorMatchesCall( | 222 ConstructorElement result = verifyThatConstructorMatchesCall( |
241 functionNode, | 223 functionNode, calledConstructor, callStructure, className, |
242 calledConstructor, | |
243 callStructure, | |
244 className, | |
245 isImplicitSuperCall: true); | 224 isImplicitSuperCall: true); |
246 if (!result.isError) { | 225 if (!result.isError) { |
247 registry.registerStaticUse( | 226 registry.registerStaticUse( |
248 new StaticUse.constructorInvoke(calledConstructor, callStructure)); | 227 new StaticUse.constructorInvoke(calledConstructor, callStructure)); |
249 } | 228 } |
250 | 229 |
251 if (isConst && isValidAsConstant) { | 230 if (isConst && isValidAsConstant) { |
252 return new ConstructedConstantExpression( | 231 return new ConstructedConstantExpression(targetType, result, |
253 targetType, | 232 CallStructure.NO_ARGS, const <ConstantExpression>[]); |
254 result, | |
255 CallStructure.NO_ARGS, | |
256 const <ConstantExpression>[]); | |
257 } | 233 } |
258 } | 234 } |
259 return null; | 235 return null; |
260 } | 236 } |
261 | 237 |
262 ConstructorElement reportAndCreateErroneousConstructor( | 238 ConstructorElement reportAndCreateErroneousConstructor( |
263 Spannable diagnosticNode, | 239 Spannable diagnosticNode, String name, MessageKind kind, Map arguments) { |
264 String name, | |
265 MessageKind kind, | |
266 Map arguments) { | |
267 isValidAsConstant = false; | 240 isValidAsConstant = false; |
268 reporter.reportErrorMessage( | 241 reporter.reportErrorMessage(diagnosticNode, kind, arguments); |
269 diagnosticNode, kind, arguments); | |
270 return new ErroneousConstructorElementX( | 242 return new ErroneousConstructorElementX( |
271 kind, arguments, name, visitor.currentClass); | 243 kind, arguments, name, visitor.currentClass); |
272 } | 244 } |
273 | 245 |
274 /// Checks that [lookedupConstructor] is valid as a target for the super/this | 246 /// Checks that [lookedupConstructor] is valid as a target for the super/this |
275 /// constructor call using with the given [callStructure]. | 247 /// constructor call using with the given [callStructure]. |
276 /// | 248 /// |
277 /// If [lookedupConstructor] is valid it is returned, otherwise an error is | 249 /// If [lookedupConstructor] is valid it is returned, otherwise an error is |
278 /// reported and an [ErroneousConstructorElement] is returned. | 250 /// reported and an [ErroneousConstructorElement] is returned. |
279 ConstructorElement verifyThatConstructorMatchesCall( | 251 ConstructorElement verifyThatConstructorMatchesCall( |
280 Node node, | 252 Node node, |
281 ConstructorElementX lookedupConstructor, | 253 ConstructorElementX lookedupConstructor, |
282 CallStructure callStructure, | 254 CallStructure callStructure, |
283 String className, | 255 String className, |
284 {String constructorName: '', | 256 {String constructorName: '', |
285 bool isImplicitSuperCall: false, | 257 bool isImplicitSuperCall: false, |
286 bool isThisCall: false}) { | 258 bool isThisCall: false}) { |
287 Element result = lookedupConstructor; | 259 Element result = lookedupConstructor; |
288 if (lookedupConstructor == null) { | 260 if (lookedupConstructor == null) { |
289 String fullConstructorName = | 261 String fullConstructorName = |
290 Elements.constructorNameForDiagnostics(className, constructorName); | 262 Elements.constructorNameForDiagnostics(className, constructorName); |
291 MessageKind kind = isImplicitSuperCall | 263 MessageKind kind = isImplicitSuperCall |
292 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | 264 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |
293 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | 265 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |
294 result = reportAndCreateErroneousConstructor( | 266 result = reportAndCreateErroneousConstructor(node, constructorName, kind, |
295 node, constructorName, | 267 {'constructorName': fullConstructorName}); |
296 kind, {'constructorName': fullConstructorName}); | |
297 } else if (!lookedupConstructor.isGenerativeConstructor) { | 268 } else if (!lookedupConstructor.isGenerativeConstructor) { |
298 MessageKind kind = isThisCall | 269 MessageKind kind = isThisCall |
299 ? MessageKind.THIS_CALL_TO_FACTORY | 270 ? MessageKind.THIS_CALL_TO_FACTORY |
300 : MessageKind.SUPER_CALL_TO_FACTORY; | 271 : MessageKind.SUPER_CALL_TO_FACTORY; |
301 result = reportAndCreateErroneousConstructor( | 272 result = |
302 node, constructorName, kind, {}); | 273 reportAndCreateErroneousConstructor(node, constructorName, kind, {}); |
303 } else { | 274 } else { |
304 lookedupConstructor.computeType(visitor.resolution); | 275 lookedupConstructor.computeType(visitor.resolution); |
305 if (!callStructure.signatureApplies( | 276 if (!callStructure |
306 lookedupConstructor.functionSignature)) { | 277 .signatureApplies(lookedupConstructor.functionSignature)) { |
307 MessageKind kind = isImplicitSuperCall | 278 MessageKind kind = isImplicitSuperCall |
308 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | 279 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |
309 : MessageKind.NO_MATCHING_CONSTRUCTOR; | 280 : MessageKind.NO_MATCHING_CONSTRUCTOR; |
310 result = reportAndCreateErroneousConstructor( | 281 result = reportAndCreateErroneousConstructor( |
311 node, constructorName, kind, {}); | 282 node, constructorName, kind, {}); |
312 } else if (constructor.isConst && !lookedupConstructor.isConst) { | 283 } else if (constructor.isConst && !lookedupConstructor.isConst) { |
313 MessageKind kind = isImplicitSuperCall | 284 MessageKind kind = isImplicitSuperCall |
314 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT | 285 ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT |
315 : MessageKind.CONST_CALLS_NON_CONST; | 286 : MessageKind.CONST_CALLS_NON_CONST; |
316 result = reportAndCreateErroneousConstructor( | 287 result = reportAndCreateErroneousConstructor( |
317 node, constructorName, kind, {}); | 288 node, constructorName, kind, {}); |
318 } | 289 } |
319 } | 290 } |
320 return result; | 291 return result; |
321 } | 292 } |
322 | 293 |
323 /** | 294 /** |
324 * Resolve all initializers of this constructor. In the case of a redirecting | 295 * Resolve all initializers of this constructor. In the case of a redirecting |
325 * constructor, the resolved constructor's function element is returned. | 296 * constructor, the resolved constructor's function element is returned. |
326 */ | 297 */ |
327 ConstructorElement resolveInitializers() { | 298 ConstructorElement resolveInitializers() { |
328 Map<dynamic/*String|int*/, ConstantExpression> defaultValues = | 299 Map<dynamic /*String|int*/, ConstantExpression> defaultValues = |
329 <dynamic/*String|int*/, ConstantExpression>{}; | 300 <dynamic /*String|int*/, ConstantExpression>{}; |
330 ConstructedConstantExpression constructorInvocation; | 301 ConstructedConstantExpression constructorInvocation; |
331 // Keep track of all "this.param" parameters specified for constructor so | 302 // Keep track of all "this.param" parameters specified for constructor so |
332 // that we can ensure that fields are initialized only once. | 303 // that we can ensure that fields are initialized only once. |
333 FunctionSignature functionParameters = constructor.functionSignature; | 304 FunctionSignature functionParameters = constructor.functionSignature; |
334 functionParameters.forEachParameter((ParameterElementX element) { | 305 functionParameters.forEachParameter((ParameterElementX element) { |
335 if (isConst) { | 306 if (isConst) { |
336 if (element.isOptional) { | 307 if (element.isOptional) { |
337 if (element.constantCache == null) { | 308 if (element.constantCache == null) { |
338 // TODO(johnniwinther): Remove this when all constant expressions | 309 // TODO(johnniwinther): Remove this when all constant expressions |
339 // can be computed during resolution. | 310 // can be computed during resolution. |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 ResolutionResult result = resolveSuperOrThisForSend(call); | 401 ResolutionResult result = resolveSuperOrThisForSend(call); |
431 if (isConst) { | 402 if (isConst) { |
432 if (result.isConstant) { | 403 if (result.isConstant) { |
433 constructorInvocation = result.constant; | 404 constructorInvocation = result.constant; |
434 } else { | 405 } else { |
435 isValidAsConstant = false; | 406 isValidAsConstant = false; |
436 } | 407 } |
437 if (isConst && isValidAsConstant) { | 408 if (isConst && isValidAsConstant) { |
438 constructor.constantConstructor = | 409 constructor.constantConstructor = |
439 new RedirectingGenerativeConstantConstructor( | 410 new RedirectingGenerativeConstantConstructor( |
440 defaultValues, | 411 defaultValues, constructorInvocation); |
441 constructorInvocation); | |
442 } | 412 } |
443 } | 413 } |
444 return result.element; | 414 return result.element; |
445 } else { | 415 } else { |
446 reporter.reportErrorMessage( | 416 reporter.reportErrorMessage( |
447 call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); | 417 call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |
448 return null; | 418 return null; |
449 } | 419 } |
450 } else { | 420 } else { |
451 reporter.reportErrorMessage( | 421 reporter.reportErrorMessage(link.head, MessageKind.INVALID_INITIALIZER); |
452 link.head, MessageKind.INVALID_INITIALIZER); | |
453 } | 422 } |
454 } | 423 } |
455 if (!resolvedSuper) { | 424 if (!resolvedSuper) { |
456 constructorInvocation = resolveImplicitSuperConstructorSend(); | 425 constructorInvocation = resolveImplicitSuperConstructorSend(); |
457 } | 426 } |
458 if (isConst && isValidAsConstant) { | 427 if (isConst && isValidAsConstant) { |
459 constructor.constantConstructor = new GenerativeConstantConstructor( | 428 constructor.constantConstructor = new GenerativeConstantConstructor( |
460 constructor.enclosingClass.thisType, | 429 constructor.enclosingClass.thisType, |
461 defaultValues, | 430 defaultValues, |
462 fieldInitializers, | 431 fieldInitializers, |
463 constructorInvocation); | 432 constructorInvocation); |
464 } | 433 } |
465 return null; // If there was no redirection always return null. | 434 return null; // If there was no redirection always return null. |
466 } | 435 } |
467 } | 436 } |
468 | 437 |
469 class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> { | 438 class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> { |
470 final ResolverVisitor resolver; | 439 final ResolverVisitor resolver; |
471 final bool inConstContext; | 440 final bool inConstContext; |
472 | 441 |
473 ConstructorResolver(Compiler compiler, this.resolver, | 442 ConstructorResolver(Compiler compiler, this.resolver, |
474 {bool this.inConstContext: false}) | 443 {bool this.inConstContext: false}) |
475 : super(compiler); | 444 : super(compiler); |
476 | 445 |
477 ResolutionRegistry get registry => resolver.registry; | 446 ResolutionRegistry get registry => resolver.registry; |
478 | 447 |
479 visitNode(Node node) { | 448 visitNode(Node node) { |
480 throw 'not supported'; | 449 throw 'not supported'; |
481 } | 450 } |
482 | 451 |
483 ConstructorResult reportAndCreateErroneousConstructorElement( | 452 ConstructorResult reportAndCreateErroneousConstructorElement( |
484 Spannable diagnosticNode, | 453 Spannable diagnosticNode, |
485 ConstructorResultKind resultKind, | 454 ConstructorResultKind resultKind, |
486 DartType type, | 455 DartType type, |
487 Element enclosing, | 456 Element enclosing, |
488 String name, | 457 String name, |
489 MessageKind kind, | 458 MessageKind kind, |
490 Map arguments, | 459 Map arguments, |
491 {bool isError: false, | 460 {bool isError: false, |
492 bool missingConstructor: false, | 461 bool missingConstructor: false, |
493 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { | 462 List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) { |
494 if (missingConstructor) { | 463 if (missingConstructor) { |
495 registry.registerFeature(Feature.THROW_NO_SUCH_METHOD); | 464 registry.registerFeature(Feature.THROW_NO_SUCH_METHOD); |
496 } else { | 465 } else { |
497 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 466 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
498 } | 467 } |
499 DiagnosticMessage message = | 468 DiagnosticMessage message = |
500 reporter.createMessage(diagnosticNode, kind, arguments); | 469 reporter.createMessage(diagnosticNode, kind, arguments); |
501 if (isError || inConstContext) { | 470 if (isError || inConstContext) { |
502 reporter.reportError(message, infos); | 471 reporter.reportError(message, infos); |
503 } else { | 472 } else { |
504 reporter.reportWarning(message, infos); | 473 reporter.reportWarning(message, infos); |
505 } | 474 } |
506 ErroneousElement error = new ErroneousConstructorElementX( | 475 ErroneousElement error = |
507 kind, arguments, name, enclosing); | 476 new ErroneousConstructorElementX(kind, arguments, name, enclosing); |
508 if (type == null) { | 477 if (type == null) { |
509 type = new MalformedType(error, null); | 478 type = new MalformedType(error, null); |
510 } | 479 } |
511 return new ConstructorResult.forError(resultKind, error, type); | 480 return new ConstructorResult.forError(resultKind, error, type); |
512 } | 481 } |
513 | 482 |
514 ConstructorResult resolveConstructor( | 483 ConstructorResult resolveConstructor(PrefixElement prefix, InterfaceType type, |
515 PrefixElement prefix, | 484 Node diagnosticNode, String constructorName) { |
516 InterfaceType type, | |
517 Node diagnosticNode, | |
518 String constructorName) { | |
519 ClassElement cls = type.element; | 485 ClassElement cls = type.element; |
520 cls.ensureResolved(resolution); | 486 cls.ensureResolved(resolution); |
521 ConstructorElement constructor = findConstructor( | 487 ConstructorElement constructor = findConstructor( |
522 resolver.enclosingElement.library, cls, constructorName); | 488 resolver.enclosingElement.library, cls, constructorName); |
523 if (constructor == null) { | 489 if (constructor == null) { |
524 MessageKind kind = constructorName.isEmpty | 490 MessageKind kind = constructorName.isEmpty |
525 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR | 491 ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR |
526 : MessageKind.CANNOT_FIND_CONSTRUCTOR; | 492 : MessageKind.CANNOT_FIND_CONSTRUCTOR; |
527 return reportAndCreateErroneousConstructorElement( | 493 return reportAndCreateErroneousConstructorElement( |
528 diagnosticNode, | 494 diagnosticNode, |
529 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type, | 495 ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, |
530 cls, constructorName, kind, | 496 type, |
| 497 cls, |
| 498 constructorName, |
| 499 kind, |
531 {'className': cls.name, 'constructorName': constructorName}, | 500 {'className': cls.name, 'constructorName': constructorName}, |
532 missingConstructor: true); | 501 missingConstructor: true); |
533 } else if (inConstContext && !constructor.isConst) { | 502 } else if (inConstContext && !constructor.isConst) { |
534 reporter.reportErrorMessage( | 503 reporter.reportErrorMessage( |
535 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | 504 diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |
536 return new ConstructorResult( | 505 return new ConstructorResult( |
537 ConstructorResultKind.NON_CONSTANT, prefix, constructor, type); | 506 ConstructorResultKind.NON_CONSTANT, prefix, constructor, type); |
538 } else { | 507 } else { |
539 if (cls.isEnumClass && resolver.currentClass != cls) { | 508 if (cls.isEnumClass && resolver.currentClass != cls) { |
540 return reportAndCreateErroneousConstructorElement( | 509 return reportAndCreateErroneousConstructorElement( |
541 diagnosticNode, | 510 diagnosticNode, |
542 ConstructorResultKind.INVALID_TYPE, type, | 511 ConstructorResultKind.INVALID_TYPE, |
543 cls, constructorName, | 512 type, |
| 513 cls, |
| 514 constructorName, |
544 MessageKind.CANNOT_INSTANTIATE_ENUM, | 515 MessageKind.CANNOT_INSTANTIATE_ENUM, |
545 {'enumName': cls.name}, | 516 {'enumName': cls.name}, |
546 isError: true); | 517 isError: true); |
547 } | 518 } |
548 if (constructor.isGenerativeConstructor) { | 519 if (constructor.isGenerativeConstructor) { |
549 if (cls.isAbstract) { | 520 if (cls.isAbstract) { |
550 reporter.reportWarningMessage( | 521 reporter.reportWarningMessage( |
551 diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION); | 522 diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION); |
552 registry.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION); | 523 registry.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION); |
553 return new ConstructorResult( | 524 return new ConstructorResult( |
(...skipping 15 matching lines...) Expand all Loading... |
569 Node selector = node.send.selector; | 540 Node selector = node.send.selector; |
570 ConstructorResult result = visit(selector); | 541 ConstructorResult result = visit(selector); |
571 assert(invariant(selector, result != null, | 542 assert(invariant(selector, result != null, |
572 message: 'No result returned for $selector.')); | 543 message: 'No result returned for $selector.')); |
573 return finishConstructorReference(result, node.send.selector, node); | 544 return finishConstructorReference(result, node.send.selector, node); |
574 } | 545 } |
575 | 546 |
576 /// Finishes resolution of a constructor reference and records the | 547 /// Finishes resolution of a constructor reference and records the |
577 /// type of the constructed instance on [expression]. | 548 /// type of the constructed instance on [expression]. |
578 ConstructorResult finishConstructorReference( | 549 ConstructorResult finishConstructorReference( |
579 ConstructorResult result, | 550 ConstructorResult result, Node diagnosticNode, Node expression) { |
580 Node diagnosticNode, | |
581 Node expression) { | |
582 assert(invariant(diagnosticNode, result != null, | 551 assert(invariant(diagnosticNode, result != null, |
583 message: 'No result returned for $diagnosticNode.')); | 552 message: 'No result returned for $diagnosticNode.')); |
584 | 553 |
585 if (result.kind != null) { | 554 if (result.kind != null) { |
586 resolver.registry.setType(expression, result.type); | 555 resolver.registry.setType(expression, result.type); |
587 return result; | 556 return result; |
588 } | 557 } |
589 | 558 |
590 // Find the unnamed constructor if the reference resolved to a | 559 // Find the unnamed constructor if the reference resolved to a |
591 // class. | 560 // class. |
592 if (result.type != null) { | 561 if (result.type != null) { |
593 // The unnamed constructor may not exist, so [e] may become unresolved. | 562 // The unnamed constructor may not exist, so [e] may become unresolved. |
594 result = resolveConstructor( | 563 result = |
595 result.prefix, result.type, diagnosticNode, ''); | 564 resolveConstructor(result.prefix, result.type, diagnosticNode, ''); |
596 } else { | 565 } else { |
597 Element element = result.element; | 566 Element element = result.element; |
598 if (element.isMalformed) { | 567 if (element.isMalformed) { |
599 result = constructorResultForErroneous(diagnosticNode, element); | 568 result = constructorResultForErroneous(diagnosticNode, element); |
600 } else { | 569 } else { |
601 result = reportAndCreateErroneousConstructorElement( | 570 result = reportAndCreateErroneousConstructorElement( |
602 diagnosticNode, | 571 diagnosticNode, |
603 ConstructorResultKind.INVALID_TYPE, null, | 572 ConstructorResultKind.INVALID_TYPE, |
604 element, element.name, | 573 null, |
605 MessageKind.NOT_A_TYPE, {'node': diagnosticNode}); | 574 element, |
| 575 element.name, |
| 576 MessageKind.NOT_A_TYPE, |
| 577 {'node': diagnosticNode}); |
606 } | 578 } |
607 } | 579 } |
608 resolver.registry.setType(expression, result.type); | 580 resolver.registry.setType(expression, result.type); |
609 return result; | 581 return result; |
610 } | 582 } |
611 | 583 |
612 ConstructorResult visitTypeAnnotation(TypeAnnotation node) { | 584 ConstructorResult visitTypeAnnotation(TypeAnnotation node) { |
613 // This is not really resolving a type-annotation, but the name of the | 585 // This is not really resolving a type-annotation, but the name of the |
614 // constructor. Therefore we allow deferred types. | 586 // constructor. Therefore we allow deferred types. |
615 DartType type = resolver.resolveTypeAnnotation( | 587 DartType type = resolver.resolveTypeAnnotation(node, |
616 node, | 588 malformedIsError: inConstContext, deferredIsMalformed: false); |
617 malformedIsError: inConstContext, | |
618 deferredIsMalformed: false); | |
619 Send send = node.typeName.asSend(); | 589 Send send = node.typeName.asSend(); |
620 PrefixElement prefix; | 590 PrefixElement prefix; |
621 if (send != null) { | 591 if (send != null) { |
622 // The type name is of the form [: prefix . identifier :]. | 592 // The type name is of the form [: prefix . identifier :]. |
623 String name = send.receiver.asIdentifier().source; | 593 String name = send.receiver.asIdentifier().source; |
624 Element element = lookupInScope(reporter, send, resolver.scope, name); | 594 Element element = lookupInScope(reporter, send, resolver.scope, name); |
625 if (element != null && element.isPrefix) { | 595 if (element != null && element.isPrefix) { |
626 prefix = element; | 596 prefix = element; |
627 } | 597 } |
628 } | 598 } |
(...skipping 17 matching lines...) Expand all Loading... |
646 } | 616 } |
647 | 617 |
648 if (receiver.type != null) { | 618 if (receiver.type != null) { |
649 if (receiver.type.isInterfaceType) { | 619 if (receiver.type.isInterfaceType) { |
650 return resolveConstructor( | 620 return resolveConstructor( |
651 receiver.prefix, receiver.type, name, name.source); | 621 receiver.prefix, receiver.type, name, name.source); |
652 } else { | 622 } else { |
653 // TODO(johnniwinther): Update the message for the different types. | 623 // TODO(johnniwinther): Update the message for the different types. |
654 return reportAndCreateErroneousConstructorElement( | 624 return reportAndCreateErroneousConstructorElement( |
655 name, | 625 name, |
656 ConstructorResultKind.INVALID_TYPE, null, | 626 ConstructorResultKind.INVALID_TYPE, |
657 resolver.enclosingElement, name.source, | 627 null, |
658 MessageKind.NOT_A_TYPE, {'node': name}); | 628 resolver.enclosingElement, |
| 629 name.source, |
| 630 MessageKind.NOT_A_TYPE, |
| 631 {'node': name}); |
659 } | 632 } |
660 } else if (receiver.element.isPrefix) { | 633 } else if (receiver.element.isPrefix) { |
661 PrefixElement prefix = receiver.element; | 634 PrefixElement prefix = receiver.element; |
662 Element member = prefix.lookupLocalMember(name.source); | 635 Element member = prefix.lookupLocalMember(name.source); |
663 return constructorResultForElement( | 636 return constructorResultForElement(node, name.source, member, |
664 node, name.source, member, prefix: prefix); | 637 prefix: prefix); |
665 } else { | 638 } else { |
666 return reporter.internalError( | 639 return reporter.internalError( |
667 node.receiver, 'unexpected receiver $receiver'); | 640 node.receiver, 'unexpected receiver $receiver'); |
668 } | 641 } |
669 } | 642 } |
670 | 643 |
671 ConstructorResult visitIdentifier(Identifier node) { | 644 ConstructorResult visitIdentifier(Identifier node) { |
672 String name = node.source; | 645 String name = node.source; |
673 Element element = lookupInScope(reporter, node, resolver.scope, name); | 646 Element element = lookupInScope(reporter, node, resolver.scope, name); |
674 registry.useElement(node, element); | 647 registry.useElement(node, element); |
675 return constructorResultForElement(node, name, element); | 648 return constructorResultForElement(node, name, element); |
676 } | 649 } |
677 | 650 |
678 /// Assumed to be called by [resolveRedirectingFactory]. | 651 /// Assumed to be called by [resolveRedirectingFactory]. |
679 ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) { | 652 ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
680 Node constructorReference = node.constructorReference; | 653 Node constructorReference = node.constructorReference; |
681 return finishConstructorReference(visit(constructorReference), | 654 return finishConstructorReference( |
682 constructorReference, node); | 655 visit(constructorReference), constructorReference, node); |
683 } | 656 } |
684 | 657 |
685 ConstructorResult constructorResultForElement( | 658 ConstructorResult constructorResultForElement( |
686 Node node, String name, Element element, | 659 Node node, String name, Element element, |
687 {PrefixElement prefix}) { | 660 {PrefixElement prefix}) { |
688 element = Elements.unwrap(element, reporter, node); | 661 element = Elements.unwrap(element, reporter, node); |
689 if (element == null) { | 662 if (element == null) { |
690 return reportAndCreateErroneousConstructorElement( | 663 return reportAndCreateErroneousConstructorElement( |
691 node, | 664 node, |
692 ConstructorResultKind.INVALID_TYPE, null, | 665 ConstructorResultKind.INVALID_TYPE, |
693 resolver.enclosingElement, name, | 666 null, |
| 667 resolver.enclosingElement, |
| 668 name, |
694 MessageKind.CANNOT_RESOLVE, | 669 MessageKind.CANNOT_RESOLVE, |
695 {'name': name}); | 670 {'name': name}); |
696 } else if (element.isAmbiguous) { | 671 } else if (element.isAmbiguous) { |
697 AmbiguousElement ambiguous = element; | 672 AmbiguousElement ambiguous = element; |
698 return reportAndCreateErroneousConstructorElement( | 673 return reportAndCreateErroneousConstructorElement( |
699 node, | 674 node, |
700 ConstructorResultKind.INVALID_TYPE, null, | 675 ConstructorResultKind.INVALID_TYPE, |
701 resolver.enclosingElement, name, | 676 null, |
| 677 resolver.enclosingElement, |
| 678 name, |
702 ambiguous.messageKind, | 679 ambiguous.messageKind, |
703 ambiguous.messageArguments, | 680 ambiguous.messageArguments, |
704 infos: ambiguous.computeInfos(resolver.enclosingElement, reporter)); | 681 infos: ambiguous.computeInfos(resolver.enclosingElement, reporter)); |
705 } else if (element.isMalformed) { | 682 } else if (element.isMalformed) { |
706 return constructorResultForErroneous(node, element); | 683 return constructorResultForErroneous(node, element); |
707 } else if (element.isClass) { | 684 } else if (element.isClass) { |
708 ClassElement cls = element; | 685 ClassElement cls = element; |
709 cls.computeType(resolution); | 686 cls.computeType(resolution); |
710 return constructorResultForType(node, cls.rawType, prefix: prefix); | 687 return constructorResultForType(node, cls.rawType, prefix: prefix); |
711 } else if (element.isPrefix) { | 688 } else if (element.isPrefix) { |
712 return new ConstructorResult.forPrefix(element); | 689 return new ConstructorResult.forPrefix(element); |
713 } else if (element.isTypedef) { | 690 } else if (element.isTypedef) { |
714 TypedefElement typdef = element; | 691 TypedefElement typdef = element; |
715 typdef.ensureResolved(resolution); | 692 typdef.ensureResolved(resolution); |
716 return constructorResultForType(node, typdef.rawType); | 693 return constructorResultForType(node, typdef.rawType); |
717 } else if (element.isTypeVariable) { | 694 } else if (element.isTypeVariable) { |
718 TypeVariableElement typeVariableElement = element; | 695 TypeVariableElement typeVariableElement = element; |
719 return constructorResultForType(node, typeVariableElement.type); | 696 return constructorResultForType(node, typeVariableElement.type); |
720 } else { | 697 } else { |
721 return reportAndCreateErroneousConstructorElement( | 698 return reportAndCreateErroneousConstructorElement( |
722 node, | 699 node, |
723 ConstructorResultKind.INVALID_TYPE, null, | 700 ConstructorResultKind.INVALID_TYPE, |
724 resolver.enclosingElement, name, | 701 null, |
725 MessageKind.NOT_A_TYPE, {'node': name}); | 702 resolver.enclosingElement, |
| 703 name, |
| 704 MessageKind.NOT_A_TYPE, |
| 705 {'node': name}); |
726 } | 706 } |
727 } | 707 } |
728 | 708 |
729 ConstructorResult constructorResultForErroneous( | 709 ConstructorResult constructorResultForErroneous(Node node, Element error) { |
730 Node node, Element error) { | |
731 if (error is! ErroneousElementX) { | 710 if (error is! ErroneousElementX) { |
732 // Parser error. The error has already been reported. | 711 // Parser error. The error has already been reported. |
733 error = new ErroneousConstructorElementX( | 712 error = new ErroneousConstructorElementX( |
734 MessageKind.NOT_A_TYPE, {'node': node}, | 713 MessageKind.NOT_A_TYPE, {'node': node}, error.name, error); |
735 error.name, error); | |
736 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); | 714 registry.registerFeature(Feature.THROW_RUNTIME_ERROR); |
737 } | 715 } |
738 return new ConstructorResult.forError( | 716 return new ConstructorResult.forError(ConstructorResultKind.INVALID_TYPE, |
739 ConstructorResultKind.INVALID_TYPE, | 717 error, new MalformedType(error, null)); |
740 error, | |
741 new MalformedType(error, null)); | |
742 } | 718 } |
743 | 719 |
744 ConstructorResult constructorResultForType( | 720 ConstructorResult constructorResultForType(Node node, DartType type, |
745 Node node, | |
746 DartType type, | |
747 {PrefixElement prefix}) { | 721 {PrefixElement prefix}) { |
748 String name = type.name; | 722 String name = type.name; |
749 if (type.isMalformed) { | 723 if (type.isMalformed) { |
750 return new ConstructorResult.forError( | 724 return new ConstructorResult.forError( |
751 ConstructorResultKind.INVALID_TYPE, type.element, type); | 725 ConstructorResultKind.INVALID_TYPE, type.element, type); |
752 } else if (type.isInterfaceType) { | 726 } else if (type.isInterfaceType) { |
753 return new ConstructorResult.forType(prefix, type); | 727 return new ConstructorResult.forType(prefix, type); |
754 } else if (type.isTypedef) { | 728 } else if (type.isTypedef) { |
755 return reportAndCreateErroneousConstructorElement( | 729 return reportAndCreateErroneousConstructorElement( |
756 node, | 730 node, |
757 ConstructorResultKind.INVALID_TYPE, type, | 731 ConstructorResultKind.INVALID_TYPE, |
758 resolver.enclosingElement, name, | 732 type, |
759 MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name}); | 733 resolver.enclosingElement, |
| 734 name, |
| 735 MessageKind.CANNOT_INSTANTIATE_TYPEDEF, |
| 736 {'typedefName': name}); |
760 } else if (type.isTypeVariable) { | 737 } else if (type.isTypeVariable) { |
761 return reportAndCreateErroneousConstructorElement( | 738 return reportAndCreateErroneousConstructorElement( |
762 node, | 739 node, |
763 ConstructorResultKind.INVALID_TYPE, type, | 740 ConstructorResultKind.INVALID_TYPE, |
764 resolver.enclosingElement, name, | 741 type, |
| 742 resolver.enclosingElement, |
| 743 name, |
765 MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, | 744 MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, |
766 {'typeVariableName': name}); | 745 {'typeVariableName': name}); |
767 } | 746 } |
768 return reporter.internalError(node, "Unexpected constructor type $type"); | 747 return reporter.internalError(node, "Unexpected constructor type $type"); |
769 } | 748 } |
770 | |
771 } | 749 } |
772 | 750 |
773 /// The kind of constructor found by the [ConstructorResolver]. | 751 /// The kind of constructor found by the [ConstructorResolver]. |
774 enum ConstructorResultKind { | 752 enum ConstructorResultKind { |
775 /// A generative or redirecting generative constructor. | 753 /// A generative or redirecting generative constructor. |
776 GENERATIVE, | 754 GENERATIVE, |
| 755 |
777 /// A factory or redirecting factory constructor. | 756 /// A factory or redirecting factory constructor. |
778 FACTORY, | 757 FACTORY, |
| 758 |
779 /// A generative or redirecting generative constructor on an abstract class. | 759 /// A generative or redirecting generative constructor on an abstract class. |
780 ABSTRACT, | 760 ABSTRACT, |
| 761 |
781 /// No constructor was found because the type was invalid, for instance | 762 /// No constructor was found because the type was invalid, for instance |
782 /// unresolved, an enum class, a type variable, a typedef or a non-type. | 763 /// unresolved, an enum class, a type variable, a typedef or a non-type. |
783 INVALID_TYPE, | 764 INVALID_TYPE, |
| 765 |
784 /// No constructor of the sought name was found on the class. | 766 /// No constructor of the sought name was found on the class. |
785 UNRESOLVED_CONSTRUCTOR, | 767 UNRESOLVED_CONSTRUCTOR, |
| 768 |
786 /// A non-constant constructor was found for a const constructor invocation. | 769 /// A non-constant constructor was found for a const constructor invocation. |
787 NON_CONSTANT, | 770 NON_CONSTANT, |
788 } | 771 } |
789 | 772 |
790 /// The (partial) result of the resolution of a new expression used in | 773 /// The (partial) result of the resolution of a new expression used in |
791 /// [ConstructorResolver]. | 774 /// [ConstructorResolver]. |
792 class ConstructorResult { | 775 class ConstructorResult { |
793 /// The prefix used to access the constructor. For instance `prefix` in `new | 776 /// The prefix used to access the constructor. For instance `prefix` in `new |
794 /// prefix.Class.constructorName()`. | 777 /// prefix.Class.constructorName()`. |
795 final PrefixElement prefix; | 778 final PrefixElement prefix; |
796 | 779 |
797 /// The kind of the found constructor. | 780 /// The kind of the found constructor. |
798 final ConstructorResultKind kind; | 781 final ConstructorResultKind kind; |
799 | 782 |
800 /// The currently found element. Since [ConstructorResult] is used for partial | 783 /// The currently found element. Since [ConstructorResult] is used for partial |
801 /// results, this might be a [PrefixElement], a [ClassElement], a | 784 /// results, this might be a [PrefixElement], a [ClassElement], a |
802 /// [ConstructorElement] or in the negative cases an [ErroneousElement]. | 785 /// [ConstructorElement] or in the negative cases an [ErroneousElement]. |
803 final Element element; | 786 final Element element; |
804 | 787 |
805 /// The type of the new expression. For instance `Foo<String>` in | 788 /// The type of the new expression. For instance `Foo<String>` in |
806 /// `new prefix.Foo<String>.constructorName()`. | 789 /// `new prefix.Foo<String>.constructorName()`. |
807 final DartType type; | 790 final DartType type; |
808 | 791 |
809 /// Creates a fully resolved constructor access where [element] is resolved | 792 /// Creates a fully resolved constructor access where [element] is resolved |
810 /// to a constructor and [type] to an interface type. | 793 /// to a constructor and [type] to an interface type. |
811 ConstructorResult(this.kind, | 794 ConstructorResult(this.kind, this.prefix, ConstructorElement this.element, |
812 this.prefix, | 795 InterfaceType this.type); |
813 ConstructorElement this.element, | |
814 InterfaceType this.type); | |
815 | 796 |
816 /// Creates a fully resolved constructor access where [element] is an | 797 /// Creates a fully resolved constructor access where [element] is an |
817 /// [ErroneousElement]. | 798 /// [ErroneousElement]. |
818 // TODO(johnniwinther): Do we still need the prefix for cases like | 799 // TODO(johnniwinther): Do we still need the prefix for cases like |
819 // `new deferred.Class.unresolvedConstructor()` ? | 800 // `new deferred.Class.unresolvedConstructor()` ? |
820 ConstructorResult.forError( | 801 ConstructorResult.forError( |
821 this.kind, ErroneousElement this.element, this.type) | 802 this.kind, ErroneousElement this.element, this.type) |
822 : prefix = null; | 803 : prefix = null; |
823 | 804 |
824 /// Creates a constructor access that is partially resolved to a prefix. For | 805 /// Creates a constructor access that is partially resolved to a prefix. For |
(...skipping 30 matching lines...) Expand all Loading... |
855 sb.write('type=$type'); | 836 sb.write('type=$type'); |
856 } | 837 } |
857 sb.write(')'); | 838 sb.write(')'); |
858 return sb.toString(); | 839 return sb.toString(); |
859 } | 840 } |
860 } | 841 } |
861 | 842 |
862 /// Lookup the [constructorName] constructor in [cls] and normalize the result | 843 /// Lookup the [constructorName] constructor in [cls] and normalize the result |
863 /// with respect to privacy and patching. | 844 /// with respect to privacy and patching. |
864 ConstructorElement findConstructor( | 845 ConstructorElement findConstructor( |
865 LibraryElement currentLibrary, | 846 LibraryElement currentLibrary, ClassElement cls, String constructorName) { |
866 ClassElement cls, | |
867 String constructorName) { | |
868 if (Name.isPrivateName(constructorName) && | 847 if (Name.isPrivateName(constructorName) && |
869 currentLibrary.library != cls.library) { | 848 currentLibrary.library != cls.library) { |
870 // TODO(johnniwinther): Report a special error on unaccessible private | 849 // TODO(johnniwinther): Report a special error on unaccessible private |
871 // constructors. | 850 // constructors. |
872 return null; | 851 return null; |
873 } | 852 } |
874 // TODO(johnniwinther): Use [Name] for lookup. | 853 // TODO(johnniwinther): Use [Name] for lookup. |
875 ConstructorElement constructor = cls.lookupConstructor(constructorName); | 854 ConstructorElement constructor = cls.lookupConstructor(constructorName); |
876 if (constructor != null) { | 855 if (constructor != null) { |
877 constructor = constructor.declaration; | 856 constructor = constructor.declaration; |
878 } | 857 } |
879 return constructor; | 858 return constructor; |
880 } | 859 } |
OLD | NEW |