OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library resolution; | 5 library dart2js.resolution; |
6 | 6 |
7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
8 | 8 |
9 import '../common/backend_api.dart' show | |
10 Backend; | |
11 import '../common/registry.dart' show | |
12 Registry; | |
13 import '../common/tasks.dart' show | 9 import '../common/tasks.dart' show |
14 CompilerTask, | 10 CompilerTask, |
15 DeferredAction; | 11 DeferredAction; |
16 import '../compiler.dart' show | 12 import '../compiler.dart' show |
17 Compiler, | 13 Compiler; |
18 isPrivateName; | 14 import '../compile_time_constants.dart' show |
19 import '../compile_time_constants.dart'; | 15 ConstantCompiler; |
20 import '../constants/constructors.dart'; | 16 import '../constants/values.dart' show |
21 import '../constants/expressions.dart'; | 17 ConstantValue; |
22 import '../constants/values.dart'; | |
23 import '../core_types.dart'; | |
24 import '../dart_backend/dart_backend.dart' show DartBackend; | |
25 import '../dart_types.dart'; | 18 import '../dart_types.dart'; |
26 import '../diagnostics/invariant.dart' show | 19 import '../diagnostics/invariant.dart' show |
27 invariant; | 20 invariant; |
28 import '../diagnostics/messages.dart' show MessageKind; | 21 import '../diagnostics/messages.dart' show |
22 MessageKind; | |
29 import '../diagnostics/spannable.dart' show | 23 import '../diagnostics/spannable.dart' show |
30 Spannable; | 24 Spannable; |
31 import '../enqueue.dart' show | |
32 ResolutionEnqueuer, | |
33 WorldImpact; | |
34 import '../tree/tree.dart'; | |
35 import '../scanner/scannerlib.dart'; | |
36 import '../elements/elements.dart'; | 25 import '../elements/elements.dart'; |
37 import '../elements/modelx.dart' show | 26 import '../elements/modelx.dart' show |
38 BaseClassElementX, | 27 BaseClassElementX, |
39 BaseFunctionElementX, | 28 BaseFunctionElementX, |
40 ConstructorElementX, | 29 ConstructorElementX, |
41 ErroneousConstructorElementX, | |
42 ErroneousElementX, | |
43 ErroneousFieldElementX, | |
44 ErroneousInitializingFormalElementX, | |
45 FieldElementX, | 30 FieldElementX, |
46 FormalElementX, | |
47 FunctionElementX, | 31 FunctionElementX, |
48 FunctionSignatureX, | |
49 GetterElementX, | 32 GetterElementX, |
50 InitializingFormalElementX, | |
51 JumpTargetX, | |
52 LabelDefinitionX, | |
53 LocalFunctionElementX, | |
54 LocalParameterElementX, | |
55 LocalVariableElementX, | |
56 MetadataAnnotationX, | 33 MetadataAnnotationX, |
57 MethodElementX, | |
58 MixinApplicationElementX, | 34 MixinApplicationElementX, |
59 ParameterElementX, | |
60 ParameterMetadataAnnotation, | 35 ParameterMetadataAnnotation, |
61 SetterElementX, | 36 SetterElementX, |
62 SynthesizedConstructorElementX, | 37 TypedefElementX; |
63 TypeVariableElementX, | 38 import '../enqueue.dart' show |
64 TypedefElementX, | 39 WorldImpact; |
65 VariableElementX, | 40 import '../scanner/scannerlib.dart' show |
66 VariableList; | 41 isBinaryOperator, |
67 import '../ordered_typeset.dart' show OrderedTypeSet, OrderedTypeSetBuilder; | 42 isMinusOperator, |
68 import '../types/types.dart' show TypeMask; | 43 isTernaryOperator, |
69 import '../util/util.dart'; | 44 isUnaryOperator, |
70 import '../universe/universe.dart' show | 45 isUserDefinableOperator; |
71 CallStructure, | 46 import '../tree/tree.dart'; |
72 Selector, | 47 import '../util/util.dart' show |
73 SelectorKind, | 48 Link, |
74 UniverseSelector; | 49 LinkBuilder, |
75 import '../world.dart' show World; | 50 Setlet; |
76 | 51 |
77 import 'access_semantics.dart'; | 52 import 'class_hierarchy.dart'; |
78 import 'class_members.dart' show MembersCreator; | 53 import 'class_members.dart' show MembersCreator; |
79 import 'enum_creator.dart'; | 54 import 'constructors.dart'; |
80 import 'operators.dart'; | 55 import 'members.dart'; |
81 import 'secret_tree_element.dart' show getTreeElement, setTreeElement; | 56 import 'registry.dart'; |
82 import 'send_structure.dart'; | 57 import 'signatures.dart'; |
83 | 58 import 'tree_elements.dart'; |
84 part 'class_hierarchy.dart'; | 59 import 'typedefs.dart'; |
85 part 'constructors.dart'; | 60 |
Johnni Winther
2015/08/17 08:01:34
The rest of the file is moved here from resolver_c
| |
86 part 'label_scope.dart'; | 61 class ResolverTask extends CompilerTask { |
87 part 'members.dart'; | 62 final ConstantCompiler constantCompiler; |
88 part 'registry.dart'; | 63 |
89 part 'resolution_common.dart'; | 64 ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler); |
90 part 'resolution_result.dart'; | 65 |
91 part 'scope.dart'; | 66 String get name => 'Resolver'; |
92 part 'signatures.dart'; | 67 |
93 part 'tree_elements.dart'; | 68 WorldImpact resolve(Element element) { |
94 part 'typedefs.dart'; | 69 return measure(() { |
95 part 'type_resolver.dart'; | 70 if (Elements.isErroneous(element)) { |
96 part 'variables.dart'; | 71 // TODO(johnniwinther): Add a predicate for this. |
72 assert(invariant(element, element is! ErroneousElement, | |
73 message: "Element $element expected to have parse errors.")); | |
74 _ensureTreeElements(element); | |
75 return const WorldImpact(); | |
76 } | |
77 | |
78 WorldImpact processMetadata([WorldImpact result]) { | |
79 for (MetadataAnnotation metadata in element.metadata) { | |
80 metadata.ensureResolved(compiler); | |
81 } | |
82 return result; | |
83 } | |
84 | |
85 ElementKind kind = element.kind; | |
86 if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) || | |
87 identical(kind, ElementKind.FUNCTION) || | |
88 identical(kind, ElementKind.GETTER) || | |
89 identical(kind, ElementKind.SETTER)) { | |
90 return processMetadata(resolveMethodElement(element)); | |
91 } | |
92 | |
93 if (identical(kind, ElementKind.FIELD)) { | |
94 return processMetadata(resolveField(element)); | |
95 } | |
96 if (element.isClass) { | |
97 ClassElement cls = element; | |
98 cls.ensureResolved(compiler); | |
99 return processMetadata(const WorldImpact()); | |
100 } else if (element.isTypedef) { | |
101 TypedefElement typdef = element; | |
102 return processMetadata(resolveTypedef(typdef)); | |
103 } | |
104 | |
105 compiler.unimplemented(element, "resolve($element)"); | |
106 }); | |
107 } | |
108 | |
109 void resolveRedirectingConstructor(InitializerResolver resolver, | |
110 Node node, | |
111 FunctionElement constructor, | |
112 FunctionElement redirection) { | |
113 assert(invariant(node, constructor.isImplementation, | |
114 message: 'Redirecting constructors must be resolved on implementation ' | |
115 'elements.')); | |
116 Setlet<FunctionElement> seen = new Setlet<FunctionElement>(); | |
117 seen.add(constructor); | |
118 while (redirection != null) { | |
119 // Ensure that we follow redirections through implementation elements. | |
120 redirection = redirection.implementation; | |
121 if (seen.contains(redirection)) { | |
122 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); | |
123 return; | |
124 } | |
125 seen.add(redirection); | |
126 redirection = resolver.visitor.resolveConstructorRedirection(redirection); | |
127 } | |
128 } | |
129 | |
130 static void processAsyncMarker(Compiler compiler, | |
131 BaseFunctionElementX element, | |
132 ResolutionRegistry registry) { | |
133 FunctionExpression functionExpression = element.node; | |
134 AsyncModifier asyncModifier = functionExpression.asyncModifier; | |
135 if (asyncModifier != null) { | |
136 | |
137 if (asyncModifier.isAsynchronous) { | |
138 element.asyncMarker = asyncModifier.isYielding | |
139 ? AsyncMarker.ASYNC_STAR : AsyncMarker.ASYNC; | |
140 } else { | |
141 element.asyncMarker = AsyncMarker.SYNC_STAR; | |
142 } | |
143 if (element.isAbstract) { | |
144 compiler.reportError(asyncModifier, | |
145 MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD, | |
146 {'modifier': element.asyncMarker}); | |
147 } else if (element.isConstructor) { | |
148 compiler.reportError(asyncModifier, | |
149 MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR, | |
150 {'modifier': element.asyncMarker}); | |
151 } else { | |
152 if (element.isSetter) { | |
153 compiler.reportError(asyncModifier, | |
154 MessageKind.ASYNC_MODIFIER_ON_SETTER, | |
155 {'modifier': element.asyncMarker}); | |
156 | |
157 } | |
158 if (functionExpression.body.asReturn() != null && | |
159 element.asyncMarker.isYielding) { | |
160 compiler.reportError(asyncModifier, | |
161 MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY, | |
162 {'modifier': element.asyncMarker}); | |
163 } | |
164 } | |
165 registry.registerAsyncMarker(element); | |
166 switch (element.asyncMarker) { | |
167 case AsyncMarker.ASYNC: | |
168 compiler.futureClass.ensureResolved(compiler); | |
169 break; | |
170 case AsyncMarker.ASYNC_STAR: | |
171 compiler.streamClass.ensureResolved(compiler); | |
172 break; | |
173 case AsyncMarker.SYNC_STAR: | |
174 compiler.iterableClass.ensureResolved(compiler); | |
175 break; | |
176 } | |
177 } | |
178 } | |
179 | |
180 bool _isNativeClassOrExtendsNativeClass(ClassElement classElement) { | |
181 assert(classElement != null); | |
182 while (classElement != null) { | |
183 if (classElement.isNative) return true; | |
184 classElement = classElement.superclass; | |
185 } | |
186 return false; | |
187 } | |
188 | |
189 WorldImpact resolveMethodElementImplementation( | |
190 FunctionElement element, FunctionExpression tree) { | |
191 return compiler.withCurrentElement(element, () { | |
192 if (element.isExternal && tree.hasBody()) { | |
193 error(element, | |
194 MessageKind.EXTERNAL_WITH_BODY, | |
195 {'functionName': element.name}); | |
196 } | |
197 if (element.isConstructor) { | |
198 if (tree.returnType != null) { | |
199 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); | |
200 } | |
201 if (element.isConst && | |
202 tree.hasBody() && | |
203 !tree.isRedirectingFactory) { | |
204 error(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY); | |
205 } | |
206 } | |
207 | |
208 ResolverVisitor visitor = visitorFor(element); | |
209 ResolutionRegistry registry = visitor.registry; | |
210 registry.defineFunction(tree, element); | |
211 visitor.setupFunction(tree, element); | |
212 processAsyncMarker(compiler, element, registry); | |
213 | |
214 if (element.isGenerativeConstructor) { | |
215 // Even if there is no initializer list we still have to do the | |
216 // resolution in case there is an implicit super constructor call. | |
217 InitializerResolver resolver = | |
218 new InitializerResolver(visitor, element, tree); | |
219 FunctionElement redirection = resolver.resolveInitializers(); | |
220 if (redirection != null) { | |
221 resolveRedirectingConstructor(resolver, tree, element, redirection); | |
222 } | |
223 } else if (tree.initializers != null) { | |
224 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); | |
225 } | |
226 | |
227 if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) { | |
228 // We need to analyze the redirecting factory bodies to ensure that | |
229 // we can analyze compile-time constants. | |
230 visitor.visit(tree.body); | |
231 } | |
232 | |
233 // Get the resolution tree and check that the resolved | |
234 // function doesn't use 'super' if it is mixed into another | |
235 // class. This is the part of the 'super' mixin check that | |
236 // happens when a function is resolved after the mixin | |
237 // application has been performed. | |
238 TreeElements resolutionTree = registry.mapping; | |
239 ClassElement enclosingClass = element.enclosingClass; | |
240 if (enclosingClass != null) { | |
241 // TODO(johnniwinther): Find another way to obtain mixin uses. | |
242 Iterable<MixinApplicationElement> mixinUses = | |
243 compiler.world.allMixinUsesOf(enclosingClass); | |
244 ClassElement mixin = enclosingClass; | |
245 for (MixinApplicationElement mixinApplication in mixinUses) { | |
246 checkMixinSuperUses(resolutionTree, mixinApplication, mixin); | |
247 } | |
248 } | |
249 | |
250 // TODO(9631): support noSuchMethod on native classes. | |
251 if (Elements.isInstanceMethod(element) && | |
252 element.name == Compiler.NO_SUCH_METHOD && | |
253 _isNativeClassOrExtendsNativeClass(enclosingClass)) { | |
254 error(tree, MessageKind.NO_SUCH_METHOD_IN_NATIVE); | |
255 } | |
256 | |
257 return registry.worldImpact; | |
258 }); | |
259 | |
260 } | |
261 | |
262 WorldImpact resolveMethodElement(FunctionElementX element) { | |
263 assert(invariant(element, element.isDeclaration)); | |
264 return compiler.withCurrentElement(element, () { | |
265 if (compiler.enqueuer.resolution.hasBeenResolved(element)) { | |
266 // TODO(karlklose): Remove the check for [isConstructor]. [elememts] | |
267 // should never be non-null, not even for constructors. | |
268 assert(invariant(element, element.isConstructor, | |
269 message: 'Non-constructor element $element ' | |
270 'has already been analyzed.')); | |
271 return const WorldImpact(); | |
272 } | |
273 if (element.isSynthesized) { | |
274 if (element.isGenerativeConstructor) { | |
275 ResolutionRegistry registry = | |
276 new ResolutionRegistry(compiler, _ensureTreeElements(element)); | |
277 ConstructorElement constructor = element.asFunctionElement(); | |
278 ConstructorElement target = constructor.definingConstructor; | |
279 // Ensure the signature of the synthesized element is | |
280 // resolved. This is the only place where the resolver is | |
281 // seeing this element. | |
282 element.computeSignature(compiler); | |
283 if (!target.isErroneous) { | |
284 registry.registerStaticUse(target); | |
285 registry.registerImplicitSuperCall(target); | |
286 } | |
287 return registry.worldImpact; | |
288 } else { | |
289 assert(element.isDeferredLoaderGetter || element.isErroneous); | |
290 _ensureTreeElements(element); | |
291 return const WorldImpact(); | |
292 } | |
293 } else { | |
294 element.parseNode(compiler); | |
295 element.computeType(compiler); | |
296 FunctionElementX implementation = element; | |
297 if (element.isExternal) { | |
298 implementation = compiler.backend.resolveExternalFunction(element); | |
299 } | |
300 return resolveMethodElementImplementation( | |
301 implementation, implementation.node); | |
302 } | |
303 }); | |
304 } | |
305 | |
306 /// Creates a [ResolverVisitor] for resolving an AST in context of [element]. | |
307 /// If [useEnclosingScope] is `true` then the initial scope of the visitor | |
308 /// does not include inner scope of [element]. | |
309 /// | |
310 /// This method should only be used by this library (or tests of | |
311 /// this library). | |
312 ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) { | |
313 return new ResolverVisitor(compiler, element, | |
314 new ResolutionRegistry(compiler, _ensureTreeElements(element)), | |
315 useEnclosingScope: useEnclosingScope); | |
316 } | |
317 | |
318 WorldImpact resolveField(FieldElementX element) { | |
319 VariableDefinitions tree = element.parseNode(compiler); | |
320 if(element.modifiers.isStatic && element.isTopLevel) { | |
321 error(element.modifiers.getStatic(), | |
322 MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC); | |
323 } | |
324 ResolverVisitor visitor = visitorFor(element); | |
325 ResolutionRegistry registry = visitor.registry; | |
326 // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates | |
327 // to the backend ast. | |
328 registry.defineElement(tree.definitions.nodes.head, element); | |
329 // TODO(johnniwinther): Share the resolved type between all variables | |
330 // declared in the same declaration. | |
331 if (tree.type != null) { | |
332 element.variables.type = visitor.resolveTypeAnnotation(tree.type); | |
333 } else { | |
334 element.variables.type = const DynamicType(); | |
335 } | |
336 | |
337 Expression initializer = element.initializer; | |
338 Modifiers modifiers = element.modifiers; | |
339 if (initializer != null) { | |
340 // TODO(johnniwinther): Avoid analyzing initializers if | |
341 // [Compiler.analyzeSignaturesOnly] is set. | |
342 visitor.visit(initializer); | |
343 } else if (modifiers.isConst) { | |
344 compiler.reportError(element, MessageKind.CONST_WITHOUT_INITIALIZER); | |
345 } else if (modifiers.isFinal && !element.isInstanceMember) { | |
346 compiler.reportError(element, MessageKind.FINAL_WITHOUT_INITIALIZER); | |
347 } else { | |
348 registry.registerInstantiatedClass(compiler.nullClass); | |
349 } | |
350 | |
351 if (Elements.isStaticOrTopLevelField(element)) { | |
352 visitor.addDeferredAction(element, () { | |
353 if (element.modifiers.isConst) { | |
354 element.constant = constantCompiler.compileConstant(element); | |
355 } else { | |
356 constantCompiler.compileVariable(element); | |
357 } | |
358 }); | |
359 if (initializer != null) { | |
360 if (!element.modifiers.isConst) { | |
361 // TODO(johnniwinther): Determine the const-ness eagerly to avoid | |
362 // unnecessary registrations. | |
363 registry.registerLazyField(); | |
364 } | |
365 } | |
366 } | |
367 | |
368 // Perform various checks as side effect of "computing" the type. | |
369 element.computeType(compiler); | |
370 | |
371 return registry.worldImpact; | |
372 } | |
373 | |
374 DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) { | |
375 DartType type = resolveReturnType(element, annotation); | |
376 if (type.isVoid) { | |
377 error(annotation, MessageKind.VOID_NOT_ALLOWED); | |
378 } | |
379 return type; | |
380 } | |
381 | |
382 DartType resolveReturnType(Element element, TypeAnnotation annotation) { | |
383 if (annotation == null) return const DynamicType(); | |
384 DartType result = visitorFor(element).resolveTypeAnnotation(annotation); | |
385 if (result == null) { | |
386 // TODO(karklose): warning. | |
387 return const DynamicType(); | |
388 } | |
389 return result; | |
390 } | |
391 | |
392 void resolveRedirectionChain(ConstructorElementX constructor, | |
393 Spannable node) { | |
394 ConstructorElementX target = constructor; | |
395 InterfaceType targetType; | |
396 List<Element> seen = new List<Element>(); | |
397 // Follow the chain of redirections and check for cycles. | |
398 while (target.isRedirectingFactory) { | |
399 if (target.internalEffectiveTarget != null) { | |
400 // We found a constructor that already has been processed. | |
401 targetType = target.effectiveTargetType; | |
402 assert(invariant(target, targetType != null, | |
403 message: 'Redirection target type has not been computed for ' | |
404 '$target')); | |
405 target = target.internalEffectiveTarget; | |
406 break; | |
407 } | |
408 | |
409 Element nextTarget = target.immediateRedirectionTarget; | |
410 if (seen.contains(nextTarget)) { | |
411 error(node, MessageKind.CYCLIC_REDIRECTING_FACTORY); | |
412 targetType = target.enclosingClass.thisType; | |
413 break; | |
414 } | |
415 seen.add(target); | |
416 target = nextTarget; | |
417 } | |
418 | |
419 if (targetType == null) { | |
420 assert(!target.isRedirectingFactory); | |
421 targetType = target.enclosingClass.thisType; | |
422 } | |
423 | |
424 // [target] is now the actual target of the redirections. Run through | |
425 // the constructors again and set their [redirectionTarget], so that we | |
426 // do not have to run the loop for these constructors again. Furthermore, | |
427 // compute [redirectionTargetType] for each factory by computing the | |
428 // substitution of the target type with respect to the factory type. | |
429 while (!seen.isEmpty) { | |
430 ConstructorElementX factory = seen.removeLast(); | |
431 | |
432 // [factory] must already be analyzed but the [TreeElements] might not | |
433 // have been stored in the enqueuer cache yet. | |
434 // TODO(johnniwinther): Store [TreeElements] in the cache before | |
435 // resolution of the element. | |
436 TreeElements treeElements = factory.treeElements; | |
437 assert(invariant(node, treeElements != null, | |
438 message: 'No TreeElements cached for $factory.')); | |
439 FunctionExpression functionNode = factory.parseNode(compiler); | |
440 RedirectingFactoryBody redirectionNode = functionNode.body; | |
441 DartType factoryType = treeElements.getType(redirectionNode); | |
442 if (!factoryType.isDynamic) { | |
443 targetType = targetType.substByContext(factoryType); | |
444 } | |
445 factory.effectiveTarget = target; | |
446 factory.effectiveTargetType = targetType; | |
447 } | |
448 } | |
449 | |
450 /** | |
451 * Load and resolve the supertypes of [cls]. | |
452 * | |
453 * Warning: do not call this method directly. It should only be | |
454 * called by [resolveClass] and [ClassSupertypeResolver]. | |
455 */ | |
456 void loadSupertypes(BaseClassElementX cls, Spannable from) { | |
457 compiler.withCurrentElement(cls, () => measure(() { | |
458 if (cls.supertypeLoadState == STATE_DONE) return; | |
459 if (cls.supertypeLoadState == STATE_STARTED) { | |
460 compiler.reportError(from, MessageKind.CYCLIC_CLASS_HIERARCHY, | |
461 {'className': cls.name}); | |
462 cls.supertypeLoadState = STATE_DONE; | |
463 cls.hasIncompleteHierarchy = true; | |
464 cls.allSupertypesAndSelf = | |
465 compiler.objectClass.allSupertypesAndSelf.extendClass( | |
466 cls.computeType(compiler)); | |
467 cls.supertype = cls.allSupertypes.head; | |
468 assert(invariant(from, cls.supertype != null, | |
469 message: 'Missing supertype on cyclic class $cls.')); | |
470 cls.interfaces = const Link<DartType>(); | |
471 return; | |
472 } | |
473 cls.supertypeLoadState = STATE_STARTED; | |
474 compiler.withCurrentElement(cls, () { | |
475 // TODO(ahe): Cache the node in cls. | |
476 cls.parseNode(compiler).accept( | |
477 new ClassSupertypeResolver(compiler, cls)); | |
478 if (cls.supertypeLoadState != STATE_DONE) { | |
479 cls.supertypeLoadState = STATE_DONE; | |
480 } | |
481 }); | |
482 })); | |
483 } | |
484 | |
485 // TODO(johnniwinther): Remove this queue when resolution has been split into | |
486 // syntax and semantic resolution. | |
487 TypeDeclarationElement currentlyResolvedTypeDeclaration; | |
488 Queue<ClassElement> pendingClassesToBeResolved = new Queue<ClassElement>(); | |
489 Queue<ClassElement> pendingClassesToBePostProcessed = | |
490 new Queue<ClassElement>(); | |
491 | |
492 /// Resolve [element] using [resolveTypeDeclaration]. | |
493 /// | |
494 /// This methods ensure that class declarations encountered through type | |
495 /// annotations during the resolution of [element] are resolved after | |
496 /// [element] has been resolved. | |
497 // TODO(johnniwinther): Encapsulate this functionality in a | |
498 // 'TypeDeclarationResolver'. | |
499 _resolveTypeDeclaration(TypeDeclarationElement element, | |
500 resolveTypeDeclaration()) { | |
501 return compiler.withCurrentElement(element, () { | |
502 return measure(() { | |
503 TypeDeclarationElement previousResolvedTypeDeclaration = | |
504 currentlyResolvedTypeDeclaration; | |
505 currentlyResolvedTypeDeclaration = element; | |
506 var result = resolveTypeDeclaration(); | |
507 if (previousResolvedTypeDeclaration == null) { | |
508 do { | |
509 while (!pendingClassesToBeResolved.isEmpty) { | |
510 pendingClassesToBeResolved.removeFirst().ensureResolved(compiler); | |
511 } | |
512 while (!pendingClassesToBePostProcessed.isEmpty) { | |
513 _postProcessClassElement( | |
514 pendingClassesToBePostProcessed.removeFirst()); | |
515 } | |
516 } while (!pendingClassesToBeResolved.isEmpty); | |
517 assert(pendingClassesToBeResolved.isEmpty); | |
518 assert(pendingClassesToBePostProcessed.isEmpty); | |
519 } | |
520 currentlyResolvedTypeDeclaration = previousResolvedTypeDeclaration; | |
521 return result; | |
522 }); | |
523 }); | |
524 } | |
525 | |
526 /** | |
527 * Resolve the class [element]. | |
528 * | |
529 * Before calling this method, [element] was constructed by the | |
530 * scanner and most fields are null or empty. This method fills in | |
531 * these fields and also ensure that the supertypes of [element] are | |
532 * resolved. | |
533 * | |
534 * Warning: Do not call this method directly. Instead use | |
535 * [:element.ensureResolved(compiler):]. | |
536 */ | |
537 TreeElements resolveClass(BaseClassElementX element) { | |
538 return _resolveTypeDeclaration(element, () { | |
539 // TODO(johnniwinther): Store the mapping in the resolution enqueuer. | |
540 ResolutionRegistry registry = | |
541 new ResolutionRegistry(compiler, _ensureTreeElements(element)); | |
542 resolveClassInternal(element, registry); | |
543 return element.treeElements; | |
544 }); | |
545 } | |
546 | |
547 void ensureClassWillBeResolvedInternal(ClassElement element) { | |
548 if (currentlyResolvedTypeDeclaration == null) { | |
549 element.ensureResolved(compiler); | |
550 } else { | |
551 pendingClassesToBeResolved.add(element); | |
552 } | |
553 } | |
554 | |
555 void resolveClassInternal(BaseClassElementX element, | |
556 ResolutionRegistry registry) { | |
557 if (!element.isPatch) { | |
558 compiler.withCurrentElement(element, () => measure(() { | |
559 assert(element.resolutionState == STATE_NOT_STARTED); | |
560 element.resolutionState = STATE_STARTED; | |
561 Node tree = element.parseNode(compiler); | |
562 loadSupertypes(element, tree); | |
563 | |
564 ClassResolverVisitor visitor = | |
565 new ClassResolverVisitor(compiler, element, registry); | |
566 visitor.visit(tree); | |
567 element.resolutionState = STATE_DONE; | |
568 compiler.onClassResolved(element); | |
569 pendingClassesToBePostProcessed.add(element); | |
570 })); | |
571 if (element.isPatched) { | |
572 // Ensure handling patch after origin. | |
573 element.patch.ensureResolved(compiler); | |
574 } | |
575 } else { // Handle patch classes: | |
576 element.resolutionState = STATE_STARTED; | |
577 // Ensure handling origin before patch. | |
578 element.origin.ensureResolved(compiler); | |
579 // Ensure that the type is computed. | |
580 element.computeType(compiler); | |
581 // Copy class hierarchy from origin. | |
582 element.supertype = element.origin.supertype; | |
583 element.interfaces = element.origin.interfaces; | |
584 element.allSupertypesAndSelf = element.origin.allSupertypesAndSelf; | |
585 // Stepwise assignment to ensure invariant. | |
586 element.supertypeLoadState = STATE_STARTED; | |
587 element.supertypeLoadState = STATE_DONE; | |
588 element.resolutionState = STATE_DONE; | |
589 // TODO(johnniwinther): Check matching type variables and | |
590 // empty extends/implements clauses. | |
591 } | |
592 } | |
593 | |
594 void _postProcessClassElement(BaseClassElementX element) { | |
595 for (MetadataAnnotation metadata in element.metadata) { | |
596 metadata.ensureResolved(compiler); | |
597 ConstantValue value = | |
598 compiler.constants.getConstantValue(metadata.constant); | |
599 if (!element.isProxy && value == compiler.proxyConstant) { | |
600 element.isProxy = true; | |
601 } | |
602 } | |
603 | |
604 // Force resolution of metadata on non-instance members since they may be | |
605 // inspected by the backend while emitting. Metadata on instance members is | |
606 // handled as a result of processing instantiated class members in the | |
607 // enqueuer. | |
608 // TODO(ahe): Avoid this eager resolution. | |
609 element.forEachMember((_, Element member) { | |
610 if (!member.isInstanceMember) { | |
611 compiler.withCurrentElement(member, () { | |
612 for (MetadataAnnotation metadata in member.metadata) { | |
613 metadata.ensureResolved(compiler); | |
614 } | |
615 }); | |
616 } | |
617 }); | |
618 | |
619 computeClassMember(element, Compiler.CALL_OPERATOR_NAME); | |
620 } | |
621 | |
622 void computeClassMembers(ClassElement element) { | |
623 MembersCreator.computeAllClassMembers(compiler, element); | |
624 } | |
625 | |
626 void computeClassMember(ClassElement element, String name) { | |
627 MembersCreator.computeClassMembersByName(compiler, element, name); | |
628 } | |
629 | |
630 void checkClass(ClassElement element) { | |
631 computeClassMembers(element); | |
632 if (element.isMixinApplication) { | |
633 checkMixinApplication(element); | |
634 } else { | |
635 checkClassMembers(element); | |
636 } | |
637 } | |
638 | |
639 void checkMixinApplication(MixinApplicationElementX mixinApplication) { | |
640 Modifiers modifiers = mixinApplication.modifiers; | |
641 int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT; | |
642 if (illegalFlags != 0) { | |
643 Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags); | |
644 compiler.reportError( | |
645 modifiers, | |
646 MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS, | |
647 {'modifiers': illegalModifiers}); | |
648 } | |
649 | |
650 // In case of cyclic mixin applications, the mixin chain will have | |
651 // been cut. If so, we have already reported the error to the | |
652 // user so we just return from here. | |
653 ClassElement mixin = mixinApplication.mixin; | |
654 if (mixin == null) return; | |
655 | |
656 // Check that we're not trying to use Object as a mixin. | |
657 if (mixin.superclass == null) { | |
658 compiler.reportError(mixinApplication, | |
659 MessageKind.ILLEGAL_MIXIN_OBJECT); | |
660 // Avoid reporting additional errors for the Object class. | |
661 return; | |
662 } | |
663 | |
664 if (mixin.isEnumClass) { | |
665 // Mixing in an enum has already caused a compile-time error. | |
666 return; | |
667 } | |
668 | |
669 // Check that the mixed in class has Object as its superclass. | |
670 if (!mixin.superclass.isObject) { | |
671 compiler.reportError(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS); | |
672 } | |
673 | |
674 // Check that the mixed in class doesn't have any constructors and | |
675 // make sure we aren't mixing in methods that use 'super'. | |
676 mixin.forEachLocalMember((AstElement member) { | |
677 if (member.isGenerativeConstructor && !member.isSynthesized) { | |
678 compiler.reportError(member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR); | |
679 } else { | |
680 // Get the resolution tree and check that the resolved member | |
681 // doesn't use 'super'. This is the part of the 'super' mixin | |
682 // check that happens when a function is resolved before the | |
683 // mixin application has been performed. | |
684 // TODO(johnniwinther): Obtain the [TreeElements] for [member] | |
685 // differently. | |
686 if (compiler.enqueuer.resolution.hasBeenResolved(member)) { | |
687 checkMixinSuperUses( | |
688 member.resolvedAst.elements, | |
689 mixinApplication, | |
690 mixin); | |
691 } | |
692 } | |
693 }); | |
694 } | |
695 | |
696 void checkMixinSuperUses(TreeElements resolutionTree, | |
697 MixinApplicationElement mixinApplication, | |
698 ClassElement mixin) { | |
699 // TODO(johnniwinther): Avoid the use of [TreeElements] here. | |
700 if (resolutionTree == null) return; | |
701 Iterable<Node> superUses = resolutionTree.superUses; | |
702 if (superUses.isEmpty) return; | |
703 compiler.reportError(mixinApplication, | |
704 MessageKind.ILLEGAL_MIXIN_WITH_SUPER, | |
705 {'className': mixin.name}); | |
706 // Show the user the problematic uses of 'super' in the mixin. | |
707 for (Node use in superUses) { | |
708 compiler.reportInfo( | |
709 use, | |
710 MessageKind.ILLEGAL_MIXIN_SUPER_USE); | |
711 } | |
712 } | |
713 | |
714 void checkClassMembers(ClassElement cls) { | |
715 assert(invariant(cls, cls.isDeclaration)); | |
716 if (cls.isObject) return; | |
717 // TODO(johnniwinther): Should this be done on the implementation element as | |
718 // well? | |
719 List<Element> constConstructors = <Element>[]; | |
720 List<Element> nonFinalInstanceFields = <Element>[]; | |
721 cls.forEachMember((holder, member) { | |
722 compiler.withCurrentElement(member, () { | |
723 // Perform various checks as side effect of "computing" the type. | |
724 member.computeType(compiler); | |
725 | |
726 // Check modifiers. | |
727 if (member.isFunction && member.modifiers.isFinal) { | |
728 compiler.reportError( | |
729 member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER); | |
730 } | |
731 if (member.isConstructor) { | |
732 final mismatchedFlagsBits = | |
733 member.modifiers.flags & | |
734 (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT); | |
735 if (mismatchedFlagsBits != 0) { | |
736 final mismatchedFlags = | |
737 new Modifiers.withFlags(null, mismatchedFlagsBits); | |
738 compiler.reportError( | |
739 member, | |
740 MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS, | |
741 {'modifiers': mismatchedFlags}); | |
742 } | |
743 if (member.modifiers.isConst) { | |
744 constConstructors.add(member); | |
745 } | |
746 } | |
747 if (member.isField) { | |
748 if (member.modifiers.isConst && !member.modifiers.isStatic) { | |
749 compiler.reportError( | |
750 member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER); | |
751 } | |
752 if (!member.modifiers.isStatic && !member.modifiers.isFinal) { | |
753 nonFinalInstanceFields.add(member); | |
754 } | |
755 } | |
756 checkAbstractField(member); | |
757 checkUserDefinableOperator(member); | |
758 }); | |
759 }); | |
760 if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) { | |
761 Spannable span = constConstructors.length > 1 | |
762 ? cls : constConstructors[0]; | |
763 compiler.reportError(span, | |
764 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS, | |
765 {'className': cls.name}); | |
766 if (constConstructors.length > 1) { | |
767 for (Element constructor in constConstructors) { | |
768 compiler.reportInfo(constructor, | |
769 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR); | |
770 } | |
771 } | |
772 for (Element field in nonFinalInstanceFields) { | |
773 compiler.reportInfo(field, | |
774 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD); | |
775 } | |
776 } | |
777 } | |
778 | |
779 void checkAbstractField(Element member) { | |
780 // Only check for getters. The test can only fail if there is both a setter | |
781 // and a getter with the same name, and we only need to check each abstract | |
782 // field once, so we just ignore setters. | |
783 if (!member.isGetter) return; | |
784 | |
785 // Find the associated abstract field. | |
786 ClassElement classElement = member.enclosingClass; | |
787 Element lookupElement = classElement.lookupLocalMember(member.name); | |
788 if (lookupElement == null) { | |
789 compiler.internalError(member, | |
790 "No abstract field for accessor"); | |
791 } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) { | |
792 if (lookupElement.isErroneous || lookupElement.isAmbiguous) return; | |
793 compiler.internalError(member, | |
794 "Inaccessible abstract field for accessor"); | |
795 } | |
796 AbstractFieldElement field = lookupElement; | |
797 | |
798 GetterElementX getter = field.getter; | |
799 if (getter == null) return; | |
800 SetterElementX setter = field.setter; | |
801 if (setter == null) return; | |
802 int getterFlags = getter.modifiers.flags | Modifiers.FLAG_ABSTRACT; | |
803 int setterFlags = setter.modifiers.flags | Modifiers.FLAG_ABSTRACT; | |
804 if (!identical(getterFlags, setterFlags)) { | |
805 final mismatchedFlags = | |
806 new Modifiers.withFlags(null, getterFlags ^ setterFlags); | |
807 compiler.reportError( | |
808 field.getter, | |
809 MessageKind.GETTER_MISMATCH, | |
810 {'modifiers': mismatchedFlags}); | |
811 compiler.reportError( | |
812 field.setter, | |
813 MessageKind.SETTER_MISMATCH, | |
814 {'modifiers': mismatchedFlags}); | |
815 } | |
816 } | |
817 | |
818 void checkUserDefinableOperator(Element member) { | |
819 FunctionElement function = member.asFunctionElement(); | |
820 if (function == null) return; | |
821 String value = member.name; | |
822 if (value == null) return; | |
823 if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return; | |
824 | |
825 bool isMinus = false; | |
826 int requiredParameterCount; | |
827 MessageKind messageKind; | |
828 if (identical(value, 'unary-')) { | |
829 isMinus = true; | |
830 messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; | |
831 requiredParameterCount = 0; | |
832 } else if (isMinusOperator(value)) { | |
833 isMinus = true; | |
834 messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; | |
835 requiredParameterCount = 1; | |
836 } else if (isUnaryOperator(value)) { | |
837 messageKind = MessageKind.UNARY_OPERATOR_BAD_ARITY; | |
838 requiredParameterCount = 0; | |
839 } else if (isBinaryOperator(value)) { | |
840 messageKind = MessageKind.BINARY_OPERATOR_BAD_ARITY; | |
841 requiredParameterCount = 1; | |
842 if (identical(value, '==')) checkOverrideHashCode(member); | |
843 } else if (isTernaryOperator(value)) { | |
844 messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY; | |
845 requiredParameterCount = 2; | |
846 } else { | |
847 compiler.internalError(function, | |
848 'Unexpected user defined operator $value'); | |
849 } | |
850 checkArity(function, requiredParameterCount, messageKind, isMinus); | |
851 } | |
852 | |
853 void checkOverrideHashCode(FunctionElement operatorEquals) { | |
854 if (operatorEquals.isAbstract) return; | |
855 ClassElement cls = operatorEquals.enclosingClass; | |
856 Element hashCodeImplementation = | |
857 cls.lookupLocalMember('hashCode'); | |
858 if (hashCodeImplementation != null) return; | |
859 compiler.reportHint( | |
860 operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE, | |
861 {'class': cls.name}); | |
862 } | |
863 | |
864 void checkArity(FunctionElement function, | |
865 int requiredParameterCount, MessageKind messageKind, | |
866 bool isMinus) { | |
867 FunctionExpression node = function.node; | |
868 FunctionSignature signature = function.functionSignature; | |
869 if (signature.requiredParameterCount != requiredParameterCount) { | |
870 Node errorNode = node; | |
871 if (node.parameters != null) { | |
872 if (isMinus || | |
873 signature.requiredParameterCount < requiredParameterCount) { | |
874 // If there are too few parameters, point to the whole parameter list. | |
875 // For instance | |
876 // | |
877 // int operator +() {} | |
878 // ^^ | |
879 // | |
880 // int operator []=(value) {} | |
881 // ^^^^^^^ | |
882 // | |
883 // For operator -, always point the whole parameter list, like | |
884 // | |
885 // int operator -(a, b) {} | |
886 // ^^^^^^ | |
887 // | |
888 // instead of | |
889 // | |
890 // int operator -(a, b) {} | |
891 // ^ | |
892 // | |
893 // since the correction might not be to remove 'b' but instead to | |
894 // remove 'a, b'. | |
895 errorNode = node.parameters; | |
896 } else { | |
897 errorNode = node.parameters.nodes.skip(requiredParameterCount).head; | |
898 } | |
899 } | |
900 compiler.reportError( | |
901 errorNode, messageKind, {'operatorName': function.name}); | |
902 } | |
903 if (signature.optionalParameterCount != 0) { | |
904 Node errorNode = | |
905 node.parameters.nodes.skip(signature.requiredParameterCount).head; | |
906 if (signature.optionalParametersAreNamed) { | |
907 compiler.reportError( | |
908 errorNode, | |
909 MessageKind.OPERATOR_NAMED_PARAMETERS, | |
910 {'operatorName': function.name}); | |
911 } else { | |
912 compiler.reportError( | |
913 errorNode, | |
914 MessageKind.OPERATOR_OPTIONAL_PARAMETERS, | |
915 {'operatorName': function.name}); | |
916 } | |
917 } | |
918 } | |
919 | |
920 reportErrorWithContext(Element errorneousElement, | |
921 MessageKind errorMessage, | |
922 Element contextElement, | |
923 MessageKind contextMessage) { | |
924 compiler.reportError( | |
925 errorneousElement, | |
926 errorMessage, | |
927 {'memberName': contextElement.name, | |
928 'className': contextElement.enclosingClass.name}); | |
929 compiler.reportInfo(contextElement, contextMessage); | |
930 } | |
931 | |
932 | |
933 FunctionSignature resolveSignature(FunctionElementX element) { | |
934 MessageKind defaultValuesError = null; | |
935 if (element.isFactoryConstructor) { | |
936 FunctionExpression body = element.parseNode(compiler); | |
937 if (body.isRedirectingFactory) { | |
938 defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT; | |
939 } | |
940 } | |
941 return compiler.withCurrentElement(element, () { | |
942 FunctionExpression node = | |
943 compiler.parser.measure(() => element.parseNode(compiler)); | |
944 return measure(() => SignatureResolver.analyze( | |
945 compiler, node.parameters, node.returnType, element, | |
946 new ResolutionRegistry(compiler, _ensureTreeElements(element)), | |
947 defaultValuesError: defaultValuesError, | |
948 createRealParameters: true)); | |
949 }); | |
950 } | |
951 | |
952 WorldImpact resolveTypedef(TypedefElementX element) { | |
953 if (element.isResolved) return const WorldImpact(); | |
954 compiler.world.allTypedefs.add(element); | |
955 return _resolveTypeDeclaration(element, () { | |
956 ResolutionRegistry registry = new ResolutionRegistry( | |
957 compiler, _ensureTreeElements(element)); | |
958 return compiler.withCurrentElement(element, () { | |
959 return measure(() { | |
960 assert(element.resolutionState == STATE_NOT_STARTED); | |
961 element.resolutionState = STATE_STARTED; | |
962 Typedef node = | |
963 compiler.parser.measure(() => element.parseNode(compiler)); | |
964 TypedefResolverVisitor visitor = | |
965 new TypedefResolverVisitor(compiler, element, registry); | |
966 visitor.visit(node); | |
967 element.resolutionState = STATE_DONE; | |
968 return registry.worldImpact; | |
969 }); | |
970 }); | |
971 }); | |
972 } | |
973 | |
974 void resolveMetadataAnnotation(MetadataAnnotationX annotation) { | |
975 compiler.withCurrentElement(annotation.annotatedElement, () => measure(() { | |
976 assert(annotation.resolutionState == STATE_NOT_STARTED); | |
977 annotation.resolutionState = STATE_STARTED; | |
978 | |
979 Node node = annotation.parseNode(compiler); | |
980 Element annotatedElement = annotation.annotatedElement; | |
981 AnalyzableElement context = annotatedElement.analyzableElement; | |
982 ClassElement classElement = annotatedElement.enclosingClass; | |
983 if (classElement != null) { | |
984 // The annotation is resolved in the scope of [classElement]. | |
985 classElement.ensureResolved(compiler); | |
986 } | |
987 assert(invariant(node, context != null, | |
988 message: "No context found for metadata annotation " | |
989 "on $annotatedElement.")); | |
990 ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true); | |
991 ResolutionRegistry registry = visitor.registry; | |
992 node.accept(visitor); | |
993 // TODO(johnniwinther): Avoid passing the [TreeElements] to | |
994 // [compileMetadata]. | |
995 annotation.constant = | |
996 constantCompiler.compileMetadata(annotation, node, registry.mapping); | |
997 // TODO(johnniwinther): Register the relation between the annotation | |
998 // and the annotated element instead. This will allow the backend to | |
999 // retrieve the backend constant and only register metadata on the | |
1000 // elements for which it is needed. (Issue 17732). | |
1001 registry.registerMetadataConstant(annotation, annotatedElement); | |
1002 annotation.resolutionState = STATE_DONE; | |
1003 })); | |
1004 } | |
1005 | |
1006 error(Spannable node, MessageKind kind, [arguments = const {}]) { | |
1007 compiler.reportError(node, kind, arguments); | |
1008 } | |
1009 | |
1010 Link<MetadataAnnotation> resolveMetadata(Element element, | |
1011 VariableDefinitions node) { | |
1012 LinkBuilder<MetadataAnnotation> metadata = | |
1013 new LinkBuilder<MetadataAnnotation>(); | |
1014 for (Metadata annotation in node.metadata.nodes) { | |
1015 ParameterMetadataAnnotation metadataAnnotation = | |
1016 new ParameterMetadataAnnotation(annotation); | |
1017 metadataAnnotation.annotatedElement = element; | |
1018 metadata.addLast(metadataAnnotation.ensureResolved(compiler)); | |
1019 } | |
1020 return metadata.toLink(); | |
1021 } | |
1022 } | |
1023 | |
1024 TreeElements _ensureTreeElements(AnalyzableElementX element) { | |
1025 if (element._treeElements == null) { | |
1026 element._treeElements = new TreeElementMapping(element); | |
1027 } | |
1028 return element._treeElements; | |
1029 } | |
1030 | |
1031 abstract class AnalyzableElementX implements AnalyzableElement { | |
1032 TreeElements _treeElements; | |
1033 | |
1034 bool get hasTreeElements => _treeElements != null; | |
1035 | |
1036 TreeElements get treeElements { | |
1037 assert(invariant(this, _treeElements !=null, | |
1038 message: "TreeElements have not been computed for $this.")); | |
1039 return _treeElements; | |
1040 } | |
1041 | |
1042 void reuseElement() { | |
1043 _treeElements = null; | |
1044 } | |
1045 } | |
OLD | NEW |