OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library resolution.compute_members; | |
6 | |
7 import '../elements/elements.dart' | |
8 show Element, | |
9 Name, | |
10 PublicName, | |
11 Member, | |
12 MemberSignature, | |
13 LibraryElement, | |
14 ClassElement, | |
15 MixinApplicationElement; | |
16 import '../dart_types.dart'; | |
17 import '../dart2jslib.dart' | |
18 show Compiler, | |
19 MessageKind, | |
20 invariant, | |
21 isPrivateName; | |
22 import '../helpers/helpers.dart'; // Included for debug helpers. | |
23 import '../util/util.dart'; | |
24 | |
25 part 'member_impl.dart'; | |
26 | |
27 abstract class MembersCreator { | |
28 final ClassElement cls; | |
29 final Compiler compiler; | |
30 | |
31 final Iterable<String> computedMemberNames; | |
32 final Map<Name, Member> classMembers; | |
33 | |
34 Map<dynamic/* Member | Element */, Set<MessageKind>> reportedMessages = | |
35 new Map<dynamic, Set<MessageKind>>(); | |
36 | |
37 MembersCreator(Compiler this.compiler, | |
38 ClassElement this.cls, | |
39 Iterable<String> this.computedMemberNames, | |
40 Map<Name, Member> this.classMembers) { | |
41 assert(invariant(cls, cls.isDeclaration, | |
42 message: "Members may only be computed on declarations.")); | |
43 } | |
44 | |
45 void reportMessage(var marker, MessageKind kind, report()) { | |
46 Set<MessageKind> messages = | |
47 reportedMessages.putIfAbsent(marker, | |
48 () => new Set<MessageKind>()); | |
49 if (messages.add(kind)) { | |
50 report(); | |
51 } | |
52 } | |
53 | |
54 bool shouldSkipMember(MemberSignature member) { | |
55 return member == null || shouldSkipName(member.name.text); | |
56 | |
57 } | |
58 | |
59 bool shouldSkipName(String name) { | |
60 return computedMemberNames != null && | |
61 computedMemberNames.contains(name); | |
62 } | |
63 | |
64 /// Compute all members of [cls] with the given names. | |
65 void computeMembersByName(String name, Setlet<Name> names) { | |
66 computeMembers(name, names); | |
67 } | |
68 | |
69 /// Compute all members of [cls] and checked that [cls] implements its | |
70 /// interface unless it is abstract or declares a `noSuchMethod` method. | |
71 void computeAllMembers() { | |
72 Map<Name, Member> declaredMembers = computeMembers(null, null); | |
73 if (!cls.isAbstract && | |
74 !declaredMembers.containsKey(const PublicName('noSuchMethod'))) { | |
75 // Check for unimplemented members on concrete classes that neither have | |
76 // a `@proxy` annotation nor declare a `noSuchMethod` method. | |
77 checkInterfaceImplementation(); | |
78 } | |
79 } | |
80 | |
81 /// Compute declared and inherited members of [cls] and return a map of the | |
82 /// declared members. | |
83 /// | |
84 /// If [name] and [names] are not null, the computation is restricted to | |
85 /// members with these names. | |
86 Map<Name, Member> computeMembers(String name, Setlet<Name> names); | |
87 | |
88 /// Compute the members of the super type(s) of [cls] and store them in | |
89 /// [classMembers]. | |
90 /// | |
91 /// If [name] and [names] are not null, the computation is restricted to | |
92 /// members with these names. | |
93 void computeSuperMembers(String name, Setlet<Name> names); | |
94 | |
95 /// Compute the members of the super class of [cls] and store them in | |
96 /// [classMembers]. | |
97 /// | |
98 /// If [name] and [names] are not null, the computation is restricted to | |
99 /// members with these names. | |
100 void computeSuperClassMembers(String name, Setlet<Name> names) { | |
101 InterfaceType supertype = cls.supertype; | |
102 if (supertype == null) return; | |
103 ClassElement superclass = supertype.element; | |
104 | |
105 // Inherit class and interface members from superclass. | |
106 void inheritClassMember(DeclaredMember member) { | |
107 if (shouldSkipMember(member)) return; | |
108 if (!member.isStatic) { | |
109 DeclaredMember inherited = member.inheritFrom(supertype); | |
110 classMembers[member.name] = inherited; | |
111 } | |
112 } | |
113 | |
114 if (names != null) { | |
115 _computeClassMember(compiler, superclass, name, names); | |
116 for (Name memberName in names) { | |
117 inheritClassMember(superclass.lookupClassMember(memberName)); | |
118 } | |
119 } else { | |
120 computeAllClassMembers(compiler, superclass); | |
121 superclass.forEachClassMember(inheritClassMember); | |
122 } | |
123 } | |
124 | |
125 /// Compute the members declared or directly mixed in [cls]. | |
126 /// | |
127 /// If [name] and [names] are not null, the computation is restricted to | |
128 /// members with these names. | |
129 Map<Name, Member> computeClassMembers(String nameText, Setlet<Name> names) { | |
130 Map<Name, Member> declaredMembers = new Map<Name, Member>(); | |
131 | |
132 if (cls.isMixinApplication) { | |
133 MixinApplicationElement mixinApplication = cls; | |
134 if (mixinApplication.mixin != null) { | |
135 // Only mix in class members when the mixin type is not malformed. | |
136 | |
137 void inheritMixinMember(DeclaredMember member) { | |
138 if (shouldSkipMember(member)) return; | |
139 Name name = member.name; | |
140 if (!member.isAbstract && !member.isStatic) { | |
141 // Abstract and static members are not mixed in. | |
142 DeclaredMember mixedInMember = | |
143 member.inheritFrom(mixinApplication.mixinType); | |
144 DeclaredMember inherited = classMembers[name]; | |
145 classMembers[name] = mixedInMember; | |
146 checkValidOverride(mixedInMember, inherited); | |
147 } | |
148 } | |
149 | |
150 if (names != null) { | |
151 _computeClassMember(compiler, mixinApplication.mixin, | |
152 nameText, names); | |
153 for (Name memberName in names) { | |
154 inheritMixinMember( | |
155 mixinApplication.mixin.lookupClassMember(memberName)); | |
156 } | |
157 } else { | |
158 computeAllClassMembers(compiler, mixinApplication.mixin); | |
159 mixinApplication.mixin.forEachClassMember(inheritMixinMember); | |
160 } | |
161 } | |
162 } else { | |
163 LibraryElement library = cls.library; | |
164 InterfaceType thisType = cls.thisType; | |
165 | |
166 void createMember(Element element) { | |
167 if (element.isConstructor) return; | |
168 String elementName = element.name; | |
169 if (shouldSkipName(elementName)) return; | |
170 if (nameText != null && elementName != nameText) return; | |
171 | |
172 void addDeclaredMember(Name name, | |
173 DartType type, FunctionType functionType) { | |
174 DeclaredMember inherited = classMembers[name]; | |
175 DeclaredMember declared; | |
176 if (element.isAbstract) { | |
177 declared = new DeclaredAbstractMember( | |
178 name, element, thisType, type, functionType, | |
179 inherited); | |
180 } else { | |
181 declared = | |
182 new DeclaredMember(name, element, thisType, type, functionType); | |
183 } | |
184 declaredMembers[name] = declared; | |
185 classMembers[name] = declared; | |
186 checkValidOverride(declared, inherited); | |
187 } | |
188 | |
189 Name name = new Name(element.name, library); | |
190 if (element.isField) { | |
191 DartType type = element.computeType(compiler); | |
192 addDeclaredMember(name, type, new FunctionType.synthesized(type)); | |
193 if (!element.isConst && !element.isFinal) { | |
194 addDeclaredMember(name.setter, type, | |
195 new FunctionType.synthesized( | |
196 const VoidType(), | |
197 <DartType>[type])); | |
198 } | |
199 } else if (element.isGetter) { | |
200 FunctionType functionType = element.computeType(compiler); | |
201 DartType type = functionType.returnType; | |
202 addDeclaredMember(name, type, functionType); | |
203 } else if (element.isSetter) { | |
204 FunctionType functionType = element.computeType(compiler); | |
205 DartType type; | |
206 if (!functionType.parameterTypes.isEmpty) { | |
207 type = functionType.parameterTypes.first; | |
208 } else { | |
209 type = const DynamicType(); | |
210 } | |
211 name = name.setter; | |
212 addDeclaredMember(name, type, functionType); | |
213 } else { | |
214 assert(invariant(element, element.isFunction)); | |
215 FunctionType type = element.computeType(compiler); | |
216 addDeclaredMember(name, type, type); | |
217 } | |
218 } | |
219 | |
220 cls.forEachLocalMember(createMember); | |
221 if (cls.isPatched) { | |
222 cls.implementation.forEachLocalMember((Element element) { | |
223 if (element.isDeclaration) { | |
224 createMember(element); | |
225 } | |
226 }); | |
227 } | |
228 } | |
229 | |
230 return declaredMembers; | |
231 } | |
232 | |
233 /// Checks that [classMember] is a valid implementation for [interfaceMember]. | |
234 void checkInterfaceMember(Name name, | |
235 MemberSignature interfaceMember, | |
236 Member classMember) { | |
237 if (classMember != null) { | |
238 // TODO(johnniwinther): Check that the class member is a valid override | |
239 // of the interface member. | |
240 return; | |
241 } | |
242 if (interfaceMember is DeclaredMember && | |
243 interfaceMember.declarer.element == cls) { | |
244 // Abstract method declared in [cls]. | |
245 MessageKind kind = MessageKind.ABSTRACT_METHOD; | |
246 if (interfaceMember.isSetter) { | |
247 kind = MessageKind.ABSTRACT_SETTER; | |
248 } else if (interfaceMember.isGetter) { | |
249 kind = MessageKind.ABSTRACT_GETTER; | |
250 } | |
251 reportMessage( | |
252 interfaceMember.element, MessageKind.ABSTRACT_METHOD, () { | |
253 compiler.reportWarning( | |
254 interfaceMember.element, kind, | |
255 {'class': cls.name, 'name': name.text}); | |
256 }); | |
257 } else { | |
258 reportWarning(MessageKind singleKind, | |
259 MessageKind multipleKind, | |
260 MessageKind explicitlyDeclaredKind, | |
261 [MessageKind implicitlyDeclaredKind]) { | |
262 Member inherited = interfaceMember.declarations.first; | |
263 reportMessage( | |
264 interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () { | |
265 compiler.reportWarning(cls, | |
266 interfaceMember.declarations.length == 1 | |
267 ? singleKind : multipleKind, | |
268 {'class': cls.name, | |
269 'name': name.text, | |
270 'method': interfaceMember, | |
271 'declarer': inherited.declarer}); | |
272 for (Member inherited in interfaceMember.declarations) { | |
273 compiler.reportInfo(inherited.element, | |
274 inherited.isDeclaredByField ? | |
275 implicitlyDeclaredKind : explicitlyDeclaredKind, | |
276 {'class': inherited.declarer.name, | |
277 'name': name.text}); | |
278 } | |
279 }); | |
280 } | |
281 if (interfaceMember.isSetter) { | |
282 reportWarning(MessageKind.UNIMPLEMENTED_SETTER_ONE, | |
283 MessageKind.UNIMPLEMENTED_SETTER, | |
284 MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER, | |
285 MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER); | |
286 } else if (interfaceMember.isGetter) { | |
287 reportWarning(MessageKind.UNIMPLEMENTED_GETTER_ONE, | |
288 MessageKind.UNIMPLEMENTED_GETTER, | |
289 MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER, | |
290 MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER); | |
291 } else if (interfaceMember.isMethod) { | |
292 reportWarning(MessageKind.UNIMPLEMENTED_METHOD_ONE, | |
293 MessageKind.UNIMPLEMENTED_METHOD, | |
294 MessageKind.UNIMPLEMENTED_METHOD_CONT); | |
295 } | |
296 } | |
297 // TODO(johnniwinther): If [cls] is not abstract, check that for all | |
298 // interface members, there is a class member whose type is a subtype of | |
299 // the interface member. | |
300 } | |
301 | |
302 /// Checks that [cls], if it implements Function, has defined call(). | |
303 void checkImplementsFunctionWithCall() { | |
304 assert(!cls.isAbstract); | |
305 | |
306 if (cls.asInstanceOf(compiler.functionClass) == null) return; | |
307 if (cls.lookupMember(Compiler.CALL_OPERATOR_NAME) != null) return; | |
308 // TODO(johnniwinther): Make separate methods for backend exceptions. | |
309 // Avoid warnings on backend implementation classes for closures. | |
310 if (compiler.backend.isBackendLibrary(cls.library)) return; | |
311 | |
312 reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () { | |
313 compiler.reportWarning(cls, MessageKind.UNIMPLEMENTED_METHOD_ONE, | |
314 {'class': cls.name, | |
315 'name': Compiler.CALL_OPERATOR_NAME, | |
316 'method': Compiler.CALL_OPERATOR_NAME, | |
317 'declarer': compiler.functionClass.name}); | |
318 }); | |
319 } | |
320 | |
321 /// Checks that a class member exists for every interface member. | |
322 void checkInterfaceImplementation(); | |
323 | |
324 /// Check that [declared] is a valid override of [superMember]. | |
325 void checkValidOverride(Member declared, MemberSignature superMember) { | |
326 if (superMember == null) { | |
327 // No override. | |
328 if (!declared.isStatic) { | |
329 ClassElement superclass = cls.superclass; | |
330 while (superclass != null) { | |
331 Member superMember = | |
332 superclass.lookupClassMember(declared.name); | |
333 if (superMember != null && superMember.isStatic) { | |
334 reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME, | |
335 () { | |
336 compiler.reportWarning( | |
337 declared.element, | |
338 MessageKind.INSTANCE_STATIC_SAME_NAME, | |
339 {'memberName': declared.name, | |
340 'className': superclass.name}); | |
341 compiler.reportInfo(superMember.element, | |
342 MessageKind.INSTANCE_STATIC_SAME_NAME_CONT); | |
343 }); | |
344 break; | |
345 } | |
346 superclass = superclass.superclass; | |
347 } | |
348 } | |
349 } else { | |
350 assert(declared.name == superMember.name); | |
351 if (declared.isStatic) { | |
352 for (Member inherited in superMember.declarations) { | |
353 reportMessage( | |
354 inherited.element, MessageKind.NO_STATIC_OVERRIDE, () { | |
355 reportErrorWithContext( | |
356 declared.element, MessageKind.NO_STATIC_OVERRIDE, | |
357 inherited.element, MessageKind.NO_STATIC_OVERRIDE_CONT); | |
358 }); | |
359 } | |
360 } | |
361 | |
362 DartType declaredType = declared.functionType; | |
363 for (Member inherited in superMember.declarations) { | |
364 | |
365 void reportError(MessageKind errorKind, MessageKind infoKind) { | |
366 reportMessage( | |
367 inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () { | |
368 compiler.reportError(declared.element, errorKind, | |
369 {'name': declared.name.text, | |
370 'class': cls.thisType, | |
371 'inheritedClass': inherited.declarer}); | |
372 compiler.reportInfo(inherited.element, infoKind, | |
373 {'name': declared.name.text, | |
374 'class': inherited.declarer}); | |
375 }); | |
376 } | |
377 | |
378 if (declared.isDeclaredByField && inherited.isMethod) { | |
379 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, | |
380 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); | |
381 } else if (declared.isMethod && inherited.isDeclaredByField) { | |
382 reportError(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, | |
383 MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); | |
384 } else if (declared.isGetter && inherited.isMethod) { | |
385 reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER, | |
386 MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT); | |
387 } else if (declared.isMethod && inherited.isGetter) { | |
388 reportError(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD, | |
389 MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT); | |
390 } else { | |
391 DartType inheritedType = inherited.functionType; | |
392 if (!compiler.types.isSubtype(declaredType, inheritedType)) { | |
393 void reportWarning(var marker, | |
394 MessageKind warningKind, | |
395 MessageKind infoKind) { | |
396 reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () { | |
397 compiler.reportWarning(declared.element, warningKind, | |
398 {'declaredType': declared.type, | |
399 'name': declared.name.text, | |
400 'class': cls.thisType, | |
401 'inheritedType': inherited.type, | |
402 'inheritedClass': inherited.declarer}); | |
403 compiler.reportInfo(inherited.element, infoKind, | |
404 {'name': declared.name.text, | |
405 'class': inherited.declarer}); | |
406 }); | |
407 } | |
408 if (declared.isDeclaredByField) { | |
409 if (inherited.isDeclaredByField) { | |
410 reportWarning(inherited.element, | |
411 MessageKind.INVALID_OVERRIDE_FIELD, | |
412 MessageKind.INVALID_OVERRIDDEN_FIELD); | |
413 } else if (inherited.isGetter) { | |
414 reportWarning(inherited, | |
415 MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD, | |
416 MessageKind.INVALID_OVERRIDDEN_GETTER); | |
417 } else if (inherited.isSetter) { | |
418 reportWarning(inherited, | |
419 MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD, | |
420 MessageKind.INVALID_OVERRIDDEN_SETTER); | |
421 } | |
422 } else if (declared.isGetter) { | |
423 if (inherited.isDeclaredByField) { | |
424 reportWarning(inherited, | |
425 MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER, | |
426 MessageKind.INVALID_OVERRIDDEN_FIELD); | |
427 } else { | |
428 reportWarning(inherited, | |
429 MessageKind.INVALID_OVERRIDE_GETTER, | |
430 MessageKind.INVALID_OVERRIDDEN_GETTER); | |
431 } | |
432 } else if (declared.isSetter) { | |
433 if (inherited.isDeclaredByField) { | |
434 reportWarning(inherited, | |
435 MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER, | |
436 MessageKind.INVALID_OVERRIDDEN_FIELD); | |
437 } else { | |
438 reportWarning(inherited, | |
439 MessageKind.INVALID_OVERRIDE_SETTER, | |
440 MessageKind.INVALID_OVERRIDDEN_SETTER); | |
441 } | |
442 } else { | |
443 reportWarning(inherited, | |
444 MessageKind.INVALID_OVERRIDE_METHOD, | |
445 MessageKind.INVALID_OVERRIDDEN_METHOD); | |
446 } | |
447 } | |
448 } | |
449 } | |
450 } | |
451 } | |
452 | |
453 void reportErrorWithContext(Element errorneousElement, | |
454 MessageKind errorMessage, | |
455 Element contextElement, | |
456 MessageKind contextMessage) { | |
457 compiler.reportError( | |
458 errorneousElement, | |
459 errorMessage, | |
460 {'memberName': contextElement.name, | |
461 'className': contextElement.enclosingClass.name}); | |
462 compiler.reportInfo(contextElement, contextMessage); | |
463 } | |
464 | |
465 /// Compute all class and interface names by the [name] in [cls]. | |
466 static void computeClassMembersByName(Compiler compiler, | |
467 ClassMemberMixin cls, | |
468 String name) { | |
469 if (cls.isMemberComputed(name)) return; | |
470 LibraryElement library = cls.library; | |
471 _computeClassMember(compiler, cls, name, | |
472 new Setlet<Name>()..add(new Name(name, library)) | |
473 ..add(new Name(name, library, isSetter: true))); | |
474 } | |
475 | |
476 static void _computeClassMember(Compiler compiler, | |
477 ClassMemberMixin cls, | |
478 String name, | |
479 Setlet<Name> names) { | |
480 cls.computeClassMember(compiler, name, names); | |
481 } | |
482 | |
483 /// Compute all class and interface names in [cls]. | |
484 static void computeAllClassMembers(Compiler compiler, ClassMemberMixin cls) { | |
485 cls.computeAllClassMembers(compiler); | |
486 } | |
487 } | |
488 | |
489 /// Class member creator for classes where the interface members are known to | |
490 /// be a subset of the class members. | |
491 class ClassMembersCreator extends MembersCreator { | |
492 ClassMembersCreator(Compiler compiler, | |
493 ClassElement cls, | |
494 Iterable<String> computedMemberNames, | |
495 Map<Name, Member> classMembers) | |
496 : super(compiler, cls, computedMemberNames, classMembers); | |
497 | |
498 Map<Name, Member> computeMembers(String name, Setlet<Name> names) { | |
499 computeSuperMembers(name, names); | |
500 return computeClassMembers(name, names); | |
501 } | |
502 | |
503 void computeSuperMembers(String name, Setlet<Name> names) { | |
504 computeSuperClassMembers(name, names); | |
505 } | |
506 | |
507 void checkInterfaceImplementation() { | |
508 LibraryElement library = cls.library; | |
509 classMembers.forEach((Name name, Member classMember) { | |
510 if (!name.isAccessibleFrom(library)) return; | |
511 checkInterfaceMember(name, classMember, classMember.implementation); | |
512 }); | |
513 } | |
514 } | |
515 | |
516 /// Class Member creator for classes where the interface members might be | |
517 /// different from the class members. | |
518 class InterfaceMembersCreator extends MembersCreator { | |
519 final Map<Name, MemberSignature> interfaceMembers; | |
520 | |
521 InterfaceMembersCreator(Compiler compiler, | |
522 ClassElement cls, | |
523 Iterable<String> computedMemberNames, | |
524 Map<Name, Member> classMembers, | |
525 Map<Name, MemberSignature> this.interfaceMembers) | |
526 : super(compiler, cls, computedMemberNames, classMembers); | |
527 | |
528 Map<Name, Member> computeMembers(String name, Setlet<Name> names) { | |
529 Map<Name, Setlet<Member>> inheritedInterfaceMembers = | |
530 computeSuperMembers(name, names); | |
531 Map<Name, Member> declaredMembers = computeClassMembers(name, names); | |
532 computeInterfaceMembers(inheritedInterfaceMembers, declaredMembers); | |
533 return declaredMembers; | |
534 } | |
535 | |
536 /// Compute the members of the super type(s) of [cls]. The class members are | |
537 /// stored if the [classMembers] map and the inherited interface members are | |
538 /// returned. | |
539 /// | |
540 /// If [name] and [names] are not null, the computation is restricted to | |
541 /// members with these names. | |
542 Map<Name, Setlet<Member>> computeSuperMembers(String name, | |
543 Setlet<Name> names) { | |
544 computeSuperClassMembers(name, names); | |
545 return computeSuperInterfaceMembers(name, names); | |
546 } | |
547 | |
548 Map<Name, Setlet<Member>> computeSuperInterfaceMembers(String name, | |
549 Setlet<Name> names) { | |
550 | |
551 | |
552 InterfaceType supertype = cls.supertype; | |
553 assert(invariant(cls, supertype != null, | |
554 message: "Interface members computed for $cls.")); | |
555 ClassElement superclass = supertype.element; | |
556 | |
557 Map<Name, Setlet<Member>> inheritedInterfaceMembers = | |
558 new Map<Name, Setlet<Member>>(); | |
559 | |
560 void inheritInterfaceMember(InterfaceType supertype, | |
561 MemberSignature member) { | |
562 if (shouldSkipMember(member)) return; | |
563 Setlet<Member> members = | |
564 inheritedInterfaceMembers.putIfAbsent( | |
565 member.name, () => new Setlet<Member>()); | |
566 for (DeclaredMember declaredMember in member.declarations) { | |
567 members.add(declaredMember.inheritFrom(supertype)); | |
568 } | |
569 } | |
570 | |
571 void inheritInterfaceMembers(InterfaceType supertype) { | |
572 supertype.element.forEachInterfaceMember((MemberSignature member) { | |
573 inheritInterfaceMember(supertype, member); | |
574 }); | |
575 } | |
576 | |
577 if (names != null) { | |
578 for (Name memberName in names) { | |
579 inheritInterfaceMember(supertype, | |
580 superclass.lookupInterfaceMember(memberName)); | |
581 } | |
582 } else { | |
583 inheritInterfaceMembers(supertype); | |
584 } | |
585 | |
586 // Inherit interface members from superinterfaces. | |
587 for (Link<DartType> link = cls.interfaces; | |
588 !link.isEmpty; | |
589 link = link.tail) { | |
590 InterfaceType superinterface = link.head; | |
591 if (names != null) { | |
592 MembersCreator._computeClassMember( | |
593 compiler, superinterface.element, name, names); | |
594 for (Name memberName in names) { | |
595 inheritInterfaceMember(superinterface, | |
596 superinterface.element.lookupInterfaceMember(memberName)); | |
597 } | |
598 } else { | |
599 MembersCreator.computeAllClassMembers(compiler, superinterface.element); | |
600 inheritInterfaceMembers(superinterface); | |
601 } | |
602 } | |
603 | |
604 return inheritedInterfaceMembers; | |
605 } | |
606 | |
607 /// Checks that a class member exists for every interface member. | |
608 void checkInterfaceImplementation() { | |
609 LibraryElement library = cls.library; | |
610 checkImplementsFunctionWithCall(); | |
611 interfaceMembers.forEach((Name name, MemberSignature interfaceMember) { | |
612 if (!name.isAccessibleFrom(library)) return; | |
613 Member classMember = classMembers[name]; | |
614 if (classMember != null) classMember = classMember.implementation; | |
615 checkInterfaceMember(name, interfaceMember, classMember); | |
616 }); | |
617 } | |
618 | |
619 /// Compute the interface members of [cls] given the set of inherited | |
620 /// interface members [inheritedInterfaceMembers] and declared members | |
621 /// [declaredMembers]. The computed members are stored in [interfaceMembers]. | |
622 void computeInterfaceMembers( | |
623 Map<Name, Setlet<Member>> inheritedInterfaceMembers, | |
624 Map<Name, Member> declaredMembers) { | |
625 InterfaceType thisType = cls.thisType; | |
626 // Compute the interface members by overriding the inherited members with | |
627 // a declared member or by computing a single, possibly synthesized, | |
628 // inherited member. | |
629 inheritedInterfaceMembers.forEach( | |
630 (Name name, Setlet<Member> inheritedMembers) { | |
631 Member declared = declaredMembers[name]; | |
632 if (declared != null) { | |
633 // Check that [declaredMember] is a valid override | |
634 for (Member inherited in inheritedMembers) { | |
635 checkValidOverride(declared, inherited); | |
636 } | |
637 if (!declared.isStatic) { | |
638 interfaceMembers[name] = declared; | |
639 } | |
640 } else if (inheritedMembers.length == 1) { | |
641 interfaceMembers[name] = inheritedMembers.single; | |
642 } else { | |
643 bool someAreGetters = false; | |
644 bool allAreGetters = true; | |
645 Map<DartType, Setlet<Member>> subtypesOfAllInherited = | |
646 new Map<DartType, Setlet<Member>>(); | |
647 outer: for (Member inherited in inheritedMembers) { | |
648 if (inherited.isGetter) { | |
649 someAreGetters = true; | |
650 if (!allAreGetters) break outer; | |
651 } else { | |
652 allAreGetters = false; | |
653 if (someAreGetters) break outer; | |
654 } | |
655 for (MemberSignature other in inheritedMembers) { | |
656 if (!compiler.types.isSubtype(inherited.functionType, | |
657 other.functionType)) { | |
658 continue outer; | |
659 } | |
660 } | |
661 subtypesOfAllInherited.putIfAbsent(inherited.functionType, | |
662 () => new Setlet<Member>()).add(inherited); | |
663 } | |
664 if (someAreGetters && !allAreGetters) { | |
665 compiler.reportWarning(cls, | |
666 MessageKind.INHERIT_GETTER_AND_METHOD, | |
667 {'class': thisType, 'name': name.text }); | |
668 for (Member inherited in inheritedMembers) { | |
669 MessageKind kind; | |
670 if (inherited.isMethod) { | |
671 kind = MessageKind.INHERITED_METHOD; | |
672 } else { | |
673 assert(invariant(cls, inherited.isGetter, | |
674 message: 'Conflicting member is neither a method nor a ' | |
675 'getter.')); | |
676 if (inherited.isDeclaredByField) { | |
677 kind = MessageKind.INHERITED_IMPLICIT_GETTER; | |
678 } else { | |
679 kind = MessageKind.INHERITED_EXPLICIT_GETTER; | |
680 } | |
681 } | |
682 compiler.reportInfo(inherited.element, kind, | |
683 {'class': inherited.declarer, 'name': name.text }); | |
684 } | |
685 interfaceMembers[name] = new ErroneousMember(inheritedMembers); | |
686 } else if (subtypesOfAllInherited.length == 1) { | |
687 // All signatures have the same type. | |
688 Setlet<Member> members = subtypesOfAllInherited.values.first; | |
689 MemberSignature inherited = members.first; | |
690 if (members.length != 1) { | |
691 // Multiple signatures with the same type => return a | |
692 // synthesized signature. | |
693 inherited = new SyntheticMember( | |
694 members, inherited.type, inherited.functionType); | |
695 } | |
696 interfaceMembers[name] = inherited; | |
697 } else { | |
698 _inheritedSynthesizedMember(name, inheritedMembers); | |
699 } | |
700 } | |
701 }); | |
702 | |
703 // Add the non-overriding instance methods to the interface members. | |
704 declaredMembers.forEach((Name name, Member member) { | |
705 if (!member.isStatic) { | |
706 interfaceMembers.putIfAbsent(name, () => member); | |
707 } | |
708 }); | |
709 } | |
710 | |
711 /// Create and inherit a synthesized member for [inheritedMembers]. | |
712 void _inheritedSynthesizedMember(Name name, | |
713 Setlet<Member> inheritedMembers) { | |
714 // Multiple signatures with different types => create the synthesized | |
715 // version. | |
716 int minRequiredParameters; | |
717 int maxPositionalParameters; | |
718 Set<String> names = new Set<String>(); | |
719 for (MemberSignature member in inheritedMembers) { | |
720 int requiredParameters = 0; | |
721 int optionalParameters = 0; | |
722 if (member.isSetter) { | |
723 requiredParameters = 1; | |
724 } | |
725 if (member.type.isFunctionType) { | |
726 FunctionType type = member.type; | |
727 type.namedParameters.forEach( | |
728 (String name) => names.add(name)); | |
729 requiredParameters = type.parameterTypes.length; | |
730 optionalParameters = type.optionalParameterTypes.length; | |
731 } | |
732 int positionalParameters = requiredParameters + optionalParameters; | |
733 if (minRequiredParameters == null || | |
734 minRequiredParameters > requiredParameters) { | |
735 minRequiredParameters = requiredParameters; | |
736 } | |
737 if (maxPositionalParameters == null || | |
738 maxPositionalParameters < positionalParameters) { | |
739 maxPositionalParameters = positionalParameters; | |
740 } | |
741 } | |
742 int optionalParameters = | |
743 maxPositionalParameters - minRequiredParameters; | |
744 // TODO(johnniwinther): Support function types with both optional | |
745 // and named parameters? | |
746 if (optionalParameters == 0 || names.isEmpty) { | |
747 DartType dynamic = const DynamicType(); | |
748 List<DartType> requiredParameterTypes = | |
749 new List.filled(minRequiredParameters, dynamic); | |
750 List<DartType> optionalParameterTypes = | |
751 new List.filled(optionalParameters, dynamic); | |
752 List<String> namedParameters = | |
753 names.toList()..sort((a, b) => a.compareTo(b)); | |
754 List<DartType> namedParameterTypes = | |
755 new List.filled(namedParameters.length, dynamic); | |
756 FunctionType memberType = new FunctionType.synthesized( | |
757 const DynamicType(), | |
758 requiredParameterTypes, | |
759 optionalParameterTypes, | |
760 namedParameters, namedParameterTypes); | |
761 DartType type = memberType; | |
762 if (inheritedMembers.first.isGetter || | |
763 inheritedMembers.first.isSetter) { | |
764 type = const DynamicType(); | |
765 } | |
766 interfaceMembers[name] = | |
767 new SyntheticMember(inheritedMembers, type, memberType); | |
768 } | |
769 } | |
770 } | |
771 | |
772 abstract class ClassMemberMixin implements ClassElement { | |
773 /// When [classMembers] and [interfaceMembers] have not been fully computed | |
774 /// [computedMembersNames] holds the names for which members have already been | |
775 /// computed. | |
776 /// | |
777 /// If [computedMemberNames], [classMembers] and [interfaceMembers] are `null` | |
778 /// no members have been computed, if only [computedMemberNames] is `null` all | |
779 /// members have been computed. A non-null [computedMemberNames] implicitly | |
780 /// includes `call`. | |
781 Iterable<String> computedMemberNames; | |
782 | |
783 /// If `true` interface members are the non-static class member. | |
784 bool interfaceMembersAreClassMembers = true; | |
785 | |
786 Map<Name, Member> classMembers; | |
787 Map<Name, MemberSignature> interfaceMembers; | |
788 | |
789 /// Creates the necessary maps and [MembersCreator] for compute members of | |
790 /// this class. | |
791 MembersCreator _prepareCreator(Compiler compiler) { | |
792 if (classMembers == null) { | |
793 classMembers = new Map<Name, Member>(); | |
794 | |
795 if (interfaceMembersAreClassMembers) { | |
796 ClassMemberMixin superclass = this.superclass; | |
797 if ((superclass != null && | |
798 (!superclass.interfaceMembersAreClassMembers || | |
799 superclass.isMixinApplication)) || | |
800 !interfaces.isEmpty) { | |
801 interfaceMembersAreClassMembers = false; | |
802 } | |
803 } | |
804 if (!interfaceMembersAreClassMembers) { | |
805 interfaceMembers = new Map<Name, MemberSignature>(); | |
806 } | |
807 } | |
808 return interfaceMembersAreClassMembers | |
809 ? new ClassMembersCreator(compiler, this, | |
810 computedMemberNames, classMembers) | |
811 : new InterfaceMembersCreator(compiler, this, | |
812 computedMemberNames, classMembers, interfaceMembers); | |
813 } | |
814 | |
815 static Iterable<String> _EMPTY_MEMBERS_NAMES = const <String>[]; | |
816 | |
817 /// Compute the members by the name [name] for this class. [names] collects | |
818 /// the set of possible variations of [name], including getter, setter and | |
819 /// and private names. | |
820 void computeClassMember(Compiler compiler, String name, Setlet<Name> names) { | |
821 if (isMemberComputed(name)) return; | |
822 if (isPrivateName(name)) { | |
823 names..add(new Name(name, library)) | |
824 ..add(new Name(name, library, isSetter: true)); | |
825 } | |
826 MembersCreator creator = _prepareCreator(compiler); | |
827 creator.computeMembersByName(name, names); | |
828 if (computedMemberNames == null) { | |
829 computedMemberNames = _EMPTY_MEMBERS_NAMES; | |
830 } | |
831 if (name != Compiler.CALL_OPERATOR_NAME) { | |
832 Setlet<String> set; | |
833 if (identical(computedMemberNames, _EMPTY_MEMBERS_NAMES)) { | |
834 computedMemberNames = set = new Setlet<String>(); | |
835 } else { | |
836 set = computedMemberNames; | |
837 } | |
838 set.add(name); | |
839 } | |
840 } | |
841 | |
842 void computeAllClassMembers(Compiler compiler) { | |
843 if (areAllMembersComputed()) return; | |
844 MembersCreator creator = _prepareCreator(compiler); | |
845 creator.computeAllMembers(); | |
846 computedMemberNames = null; | |
847 assert(invariant(this, areAllMembersComputed())); | |
848 } | |
849 | |
850 bool areAllMembersComputed() { | |
851 return computedMemberNames == null && classMembers != null; | |
852 } | |
853 | |
854 bool isMemberComputed(String name) { | |
855 if (computedMemberNames == null) { | |
856 return classMembers != null; | |
857 } else { | |
858 return name == Compiler.CALL_OPERATOR_NAME || | |
859 computedMemberNames.contains(name); | |
860 } | |
861 } | |
862 | |
863 Member lookupClassMember(Name name) { | |
864 assert(invariant(this, | |
865 isMemberComputed(name.text), | |
866 message: "Member ${name} has not been computed for $this.")); | |
867 return classMembers[name]; | |
868 } | |
869 | |
870 void forEachClassMember(f(Member member)) { | |
871 assert(invariant(this, areAllMembersComputed(), | |
872 message: "Members have not been fully computed for $this.")); | |
873 classMembers.forEach((_, member) => f(member)); | |
874 } | |
875 | |
876 MemberSignature lookupInterfaceMember(Name name) { | |
877 assert(invariant(this, isMemberComputed(name.text), | |
878 message: "Member ${name.text} has not been computed for $this.")); | |
879 if (interfaceMembersAreClassMembers) { | |
880 Member member = classMembers[name]; | |
881 if (member != null && member.isStatic) return null; | |
882 return member; | |
883 } | |
884 return interfaceMembers[name]; | |
885 } | |
886 | |
887 void forEachInterfaceMember(f(MemberSignature member)) { | |
888 assert(invariant(this, areAllMembersComputed(), | |
889 message: "Members have not been fully computed for $this.")); | |
890 if (interfaceMembersAreClassMembers) { | |
891 classMembers.forEach((_, member) { | |
892 if (!member.isStatic) f(member); | |
893 }); | |
894 } else { | |
895 interfaceMembers.forEach((_, member) => f(member)); | |
896 } | |
897 } | |
898 } | |
OLD | NEW |