| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library dart2js.resolution.compute_members; |
| |
| import '../common/names.dart' show |
| Identifiers; |
| import '../compiler.dart' show |
| Compiler; |
| import '../dart_types.dart'; |
| import '../diagnostics/invariant.dart' show |
| invariant; |
| import '../diagnostics/messages.dart' show |
| MessageKind; |
| import '../elements/elements.dart' show |
| ClassElement, |
| Element, |
| LibraryElement, |
| Member, |
| MemberElement, |
| MemberSignature, |
| MixinApplicationElement, |
| Name, |
| PublicName; |
| import '../util/util.dart'; |
| |
| part 'member_impl.dart'; |
| |
| abstract class MembersCreator { |
| final ClassElement cls; |
| final Compiler compiler; |
| |
| final Iterable<String> computedMemberNames; |
| final Map<Name, Member> classMembers; |
| |
| Map<dynamic/* Member | Element */, Set<MessageKind>> reportedMessages = |
| new Map<dynamic, Set<MessageKind>>(); |
| |
| MembersCreator(Compiler this.compiler, |
| ClassElement this.cls, |
| Iterable<String> this.computedMemberNames, |
| Map<Name, Member> this.classMembers) { |
| assert(invariant(cls, cls.isDeclaration, |
| message: "Members may only be computed on declarations.")); |
| } |
| |
| void reportMessage(var marker, MessageKind kind, report()) { |
| Set<MessageKind> messages = |
| reportedMessages.putIfAbsent(marker, |
| () => new Set<MessageKind>()); |
| if (messages.add(kind)) { |
| report(); |
| } |
| } |
| |
| bool shouldSkipMember(MemberSignature member) { |
| return member == null || shouldSkipName(member.name.text); |
| |
| } |
| |
| bool shouldSkipName(String name) { |
| return computedMemberNames != null && |
| // 'call' is implicitly contained in [computedMemberNames]. |
| (name == Identifiers.call || computedMemberNames.contains(name)); |
| } |
| |
| /// Compute all members of [cls] with the given names. |
| void computeMembersByName(String name, Setlet<Name> names) { |
| computeMembers(name, names); |
| } |
| |
| /// Compute all members of [cls] and checked that [cls] implements its |
| /// interface unless it is abstract or declares a `noSuchMethod` method. |
| void computeAllMembers() { |
| Map<Name, Member> declaredMembers = computeMembers(null, null); |
| if (!cls.isAbstract && |
| !declaredMembers.containsKey(const PublicName('noSuchMethod'))) { |
| // Check for unimplemented members on concrete classes that neither have |
| // a `@proxy` annotation nor declare a `noSuchMethod` method. |
| checkInterfaceImplementation(); |
| } |
| } |
| |
| /// Compute declared and inherited members of [cls] and return a map of the |
| /// declared members. |
| /// |
| /// If [name] and [names] are not null, the computation is restricted to |
| /// members with these names. |
| Map<Name, Member> computeMembers(String name, Setlet<Name> names); |
| |
| /// Compute the members of the super type(s) of [cls] and store them in |
| /// [classMembers]. |
| /// |
| /// If [name] and [names] are not null, the computation is restricted to |
| /// members with these names. |
| void computeSuperMembers(String name, Setlet<Name> names); |
| |
| /// Compute the members of the super class of [cls] and store them in |
| /// [classMembers]. |
| /// |
| /// If [name] and [names] are not null, the computation is restricted to |
| /// members with these names. |
| void computeSuperClassMembers(String name, Setlet<Name> names) { |
| InterfaceType supertype = cls.supertype; |
| if (supertype == null) return; |
| ClassElement superclass = supertype.element; |
| |
| // Inherit class and interface members from superclass. |
| void inheritClassMember(DeclaredMember member) { |
| if (shouldSkipMember(member)) return; |
| if (!member.isStatic) { |
| DeclaredMember inherited = member.inheritFrom(supertype); |
| classMembers[member.name] = inherited; |
| } |
| } |
| |
| if (names != null) { |
| _computeClassMember(compiler, superclass, name, names); |
| for (Name memberName in names) { |
| inheritClassMember(superclass.lookupClassMember(memberName)); |
| } |
| } else { |
| computeAllClassMembers(compiler, superclass); |
| superclass.forEachClassMember(inheritClassMember); |
| } |
| } |
| |
| /// Compute the members declared or directly mixed in [cls]. |
| /// |
| /// If [name] and [names] are not null, the computation is restricted to |
| /// members with these names. |
| Map<Name, Member> computeClassMembers(String nameText, Setlet<Name> names) { |
| Map<Name, Member> declaredMembers = new Map<Name, Member>(); |
| |
| if (cls.isMixinApplication) { |
| MixinApplicationElement mixinApplication = cls; |
| if (mixinApplication.mixin != null) { |
| // Only mix in class members when the mixin type is not malformed. |
| |
| void inheritMixinMember(DeclaredMember member) { |
| if (shouldSkipMember(member)) return; |
| Name name = member.name; |
| if (!member.isAbstract && !member.isStatic) { |
| // Abstract and static members are not mixed in. |
| DeclaredMember mixedInMember = |
| member.inheritFrom(mixinApplication.mixinType); |
| DeclaredMember inherited = classMembers[name]; |
| classMembers[name] = mixedInMember; |
| checkValidOverride(mixedInMember, inherited); |
| } |
| } |
| |
| if (names != null) { |
| _computeClassMember(compiler, mixinApplication.mixin, |
| nameText, names); |
| for (Name memberName in names) { |
| inheritMixinMember( |
| mixinApplication.mixin.lookupClassMember(memberName)); |
| } |
| } else { |
| computeAllClassMembers(compiler, mixinApplication.mixin); |
| mixinApplication.mixin.forEachClassMember(inheritMixinMember); |
| } |
| } |
| } else { |
| LibraryElement library = cls.library; |
| InterfaceType thisType = cls.thisType; |
| |
| void createMember(MemberElement element) { |
| if (element.isConstructor) return; |
| String elementName = element.name; |
| if (shouldSkipName(elementName)) return; |
| if (nameText != null && elementName != nameText) return; |
| |
| void addDeclaredMember(Name name, |
| DartType type, FunctionType functionType) { |
| DeclaredMember inherited = classMembers[name]; |
| DeclaredMember declared; |
| if (element.isAbstract) { |
| declared = new DeclaredAbstractMember( |
| name, element, thisType, type, functionType, |
| inherited); |
| } else { |
| declared = |
| new DeclaredMember(name, element, thisType, type, functionType); |
| } |
| declaredMembers[name] = declared; |
| classMembers[name] = declared; |
| checkValidOverride(declared, inherited); |
| } |
| |
| Name name = new Name(element.name, library); |
| if (element.isField) { |
| DartType type = element.computeType(compiler); |
| addDeclaredMember(name, type, new FunctionType.synthesized(type)); |
| if (!element.isConst && !element.isFinal) { |
| addDeclaredMember(name.setter, type, |
| new FunctionType.synthesized( |
| const VoidType(), |
| <DartType>[type])); |
| } |
| } else if (element.isGetter) { |
| FunctionType functionType = element.computeType(compiler); |
| DartType type = functionType.returnType; |
| addDeclaredMember(name, type, functionType); |
| } else if (element.isSetter) { |
| FunctionType functionType = element.computeType(compiler); |
| DartType type; |
| if (!functionType.parameterTypes.isEmpty) { |
| type = functionType.parameterTypes.first; |
| } else { |
| type = const DynamicType(); |
| } |
| name = name.setter; |
| addDeclaredMember(name, type, functionType); |
| } else { |
| assert(invariant(element, element.isFunction)); |
| FunctionType type = element.computeType(compiler); |
| addDeclaredMember(name, type, type); |
| } |
| } |
| |
| cls.forEachLocalMember(createMember); |
| if (cls.isPatched) { |
| cls.implementation.forEachLocalMember((Element element) { |
| if (element.isDeclaration) { |
| createMember(element); |
| } |
| }); |
| } |
| } |
| |
| return declaredMembers; |
| } |
| |
| /// Checks that [classMember] is a valid implementation for [interfaceMember]. |
| void checkInterfaceMember(Name name, |
| MemberSignature interfaceMember, |
| Member classMember) { |
| if (classMember != null) { |
| // TODO(johnniwinther): Check that the class member is a valid override |
| // of the interface member. |
| return; |
| } |
| if (interfaceMember is DeclaredMember && |
| interfaceMember.declarer.element == cls) { |
| // Abstract method declared in [cls]. |
| MessageKind kind = MessageKind.ABSTRACT_METHOD; |
| if (interfaceMember.isSetter) { |
| kind = MessageKind.ABSTRACT_SETTER; |
| } else if (interfaceMember.isGetter) { |
| kind = MessageKind.ABSTRACT_GETTER; |
| } |
| reportMessage( |
| interfaceMember.element, MessageKind.ABSTRACT_METHOD, () { |
| compiler.reportWarning( |
| interfaceMember.element, kind, |
| {'class': cls.name, 'name': name.text}); |
| }); |
| } else { |
| reportWarning(MessageKind singleKind, |
| MessageKind multipleKind, |
| MessageKind explicitlyDeclaredKind, |
| [MessageKind implicitlyDeclaredKind]) { |
| Member inherited = interfaceMember.declarations.first; |
| reportMessage( |
| interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () { |
| compiler.reportWarning(cls, |
| interfaceMember.declarations.length == 1 |
| ? singleKind : multipleKind, |
| {'class': cls.name, |
| 'name': name.text, |
| 'method': interfaceMember, |
| 'declarer': inherited.declarer}); |
| for (Member inherited in interfaceMember.declarations) { |
| compiler.reportInfo(inherited.element, |
| inherited.isDeclaredByField ? |
| implicitlyDeclaredKind : explicitlyDeclaredKind, |
| {'class': inherited.declarer.name, |
| 'name': name.text}); |
| } |
| }); |
| } |
| if (interfaceMember.isSetter) { |
| reportWarning(MessageKind.UNIMPLEMENTED_SETTER_ONE, |
| MessageKind.UNIMPLEMENTED_SETTER, |
| MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER, |
| MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER); |
| } else if (interfaceMember.isGetter) { |
| reportWarning(MessageKind.UNIMPLEMENTED_GETTER_ONE, |
| MessageKind.UNIMPLEMENTED_GETTER, |
| MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER, |
| MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER); |
| } else if (interfaceMember.isMethod) { |
| reportWarning(MessageKind.UNIMPLEMENTED_METHOD_ONE, |
| MessageKind.UNIMPLEMENTED_METHOD, |
| MessageKind.UNIMPLEMENTED_METHOD_CONT); |
| } |
| } |
| // TODO(johnniwinther): If [cls] is not abstract, check that for all |
| // interface members, there is a class member whose type is a subtype of |
| // the interface member. |
| } |
| |
| /// Checks that [cls], if it implements Function, has defined call(). |
| void checkImplementsFunctionWithCall() { |
| assert(!cls.isAbstract); |
| |
| if (cls.asInstanceOf(compiler.functionClass) == null) return; |
| if (cls.lookupMember(Identifiers.call) != null) return; |
| // TODO(johnniwinther): Make separate methods for backend exceptions. |
| // Avoid warnings on backend implementation classes for closures. |
| if (compiler.backend.isBackendLibrary(cls.library)) return; |
| |
| reportMessage(compiler.functionClass, MessageKind.UNIMPLEMENTED_METHOD, () { |
| compiler.reportWarning(cls, MessageKind.UNIMPLEMENTED_METHOD_ONE, |
| {'class': cls.name, |
| 'name': Identifiers.call, |
| 'method': Identifiers.call, |
| 'declarer': compiler.functionClass.name}); |
| }); |
| } |
| |
| /// Checks that a class member exists for every interface member. |
| void checkInterfaceImplementation(); |
| |
| /// Check that [declared] is a valid override of [superMember]. |
| void checkValidOverride(Member declared, MemberSignature superMember) { |
| if (superMember == null) { |
| // No override. |
| if (!declared.isStatic) { |
| ClassElement superclass = cls.superclass; |
| while (superclass != null) { |
| Member superMember = |
| superclass.lookupClassMember(declared.name); |
| if (superMember != null && superMember.isStatic) { |
| reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME, |
| () { |
| compiler.reportWarning( |
| declared.element, |
| MessageKind.INSTANCE_STATIC_SAME_NAME, |
| {'memberName': declared.name, |
| 'className': superclass.name}); |
| compiler.reportInfo(superMember.element, |
| MessageKind.INSTANCE_STATIC_SAME_NAME_CONT); |
| }); |
| break; |
| } |
| superclass = superclass.superclass; |
| } |
| } |
| } else { |
| assert(declared.name == superMember.name); |
| |
| if (declared.isStatic) { |
| for (Member inherited in superMember.declarations) { |
| if (cls == inherited.declarer.element) { |
| // An error should already have been reported. |
| assert(invariant(declared.element, compiler.compilationFailed)); |
| continue; |
| } |
| |
| reportMessage( |
| inherited.element, MessageKind.NO_STATIC_OVERRIDE, () { |
| reportErrorWithContext( |
| declared.element, MessageKind.NO_STATIC_OVERRIDE, |
| inherited.element, MessageKind.NO_STATIC_OVERRIDE_CONT); |
| }); |
| } |
| } |
| |
| DartType declaredType = declared.functionType; |
| for (Member inherited in superMember.declarations) { |
| if (inherited.element == declared.element) { |
| // TODO(ahe): For some reason, "call" elements are repeated in |
| // superMember.declarations. Investigate why. |
| } else if (cls == inherited.declarer.element) { |
| // An error should already have been reported. |
| assert(invariant(declared.element, compiler.compilationFailed, |
| message: "Member $inherited inherited from its " |
| "declaring class: ${cls}.")); |
| continue; |
| } |
| |
| void reportError(MessageKind errorKind, MessageKind infoKind) { |
| reportMessage( |
| inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () { |
| compiler.reportError(declared.element, errorKind, |
| {'name': declared.name.text, |
| 'class': cls.thisType, |
| 'inheritedClass': inherited.declarer}); |
| compiler.reportInfo(inherited.element, infoKind, |
| {'name': declared.name.text, |
| 'class': inherited.declarer}); |
| }); |
| } |
| |
| if (declared.isDeclaredByField && inherited.isMethod) { |
| reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, |
| MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); |
| } else if (declared.isMethod && inherited.isDeclaredByField) { |
| reportError(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, |
| MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); |
| } else if (declared.isGetter && inherited.isMethod) { |
| reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER, |
| MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT); |
| } else if (declared.isMethod && inherited.isGetter) { |
| reportError(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD, |
| MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT); |
| } else { |
| DartType inheritedType = inherited.functionType; |
| if (!compiler.types.isSubtype(declaredType, inheritedType)) { |
| void reportWarning(var marker, |
| MessageKind warningKind, |
| MessageKind infoKind) { |
| reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () { |
| compiler.reportWarning(declared.element, warningKind, |
| {'declaredType': declared.type, |
| 'name': declared.name.text, |
| 'class': cls.thisType, |
| 'inheritedType': inherited.type, |
| 'inheritedClass': inherited.declarer}); |
| compiler.reportInfo(inherited.element, infoKind, |
| {'name': declared.name.text, |
| 'class': inherited.declarer}); |
| }); |
| } |
| if (declared.isDeclaredByField) { |
| if (inherited.isDeclaredByField) { |
| reportWarning(inherited.element, |
| MessageKind.INVALID_OVERRIDE_FIELD, |
| MessageKind.INVALID_OVERRIDDEN_FIELD); |
| } else if (inherited.isGetter) { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD, |
| MessageKind.INVALID_OVERRIDDEN_GETTER); |
| } else if (inherited.isSetter) { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD, |
| MessageKind.INVALID_OVERRIDDEN_SETTER); |
| } |
| } else if (declared.isGetter) { |
| if (inherited.isDeclaredByField) { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER, |
| MessageKind.INVALID_OVERRIDDEN_FIELD); |
| } else { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_GETTER, |
| MessageKind.INVALID_OVERRIDDEN_GETTER); |
| } |
| } else if (declared.isSetter) { |
| if (inherited.isDeclaredByField) { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER, |
| MessageKind.INVALID_OVERRIDDEN_FIELD); |
| } else { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_SETTER, |
| MessageKind.INVALID_OVERRIDDEN_SETTER); |
| } |
| } else { |
| reportWarning(inherited, |
| MessageKind.INVALID_OVERRIDE_METHOD, |
| MessageKind.INVALID_OVERRIDDEN_METHOD); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void reportErrorWithContext(Element errorneousElement, |
| MessageKind errorMessage, |
| Element contextElement, |
| MessageKind contextMessage) { |
| compiler.reportError( |
| errorneousElement, |
| errorMessage, |
| {'memberName': contextElement.name, |
| 'className': contextElement.enclosingClass.name}); |
| compiler.reportInfo(contextElement, contextMessage); |
| } |
| |
| /// Compute all class and interface names by the [name] in [cls]. |
| static void computeClassMembersByName(Compiler compiler, |
| ClassMemberMixin cls, |
| String name) { |
| if (cls.isMemberComputed(name)) return; |
| LibraryElement library = cls.library; |
| _computeClassMember(compiler, cls, name, |
| new Setlet<Name>()..add(new Name(name, library)) |
| ..add(new Name(name, library, isSetter: true))); |
| } |
| |
| static void _computeClassMember(Compiler compiler, |
| ClassMemberMixin cls, |
| String name, |
| Setlet<Name> names) { |
| cls.computeClassMember(compiler, name, names); |
| } |
| |
| /// Compute all class and interface names in [cls]. |
| static void computeAllClassMembers(Compiler compiler, ClassMemberMixin cls) { |
| cls.computeAllClassMembers(compiler); |
| } |
| } |
| |
| /// Class member creator for classes where the interface members are known to |
| /// be a subset of the class members. |
| class ClassMembersCreator extends MembersCreator { |
| ClassMembersCreator(Compiler compiler, |
| ClassElement cls, |
| Iterable<String> computedMemberNames, |
| Map<Name, Member> classMembers) |
| : super(compiler, cls, computedMemberNames, classMembers); |
| |
| Map<Name, Member> computeMembers(String name, Setlet<Name> names) { |
| computeSuperMembers(name, names); |
| return computeClassMembers(name, names); |
| } |
| |
| void computeSuperMembers(String name, Setlet<Name> names) { |
| computeSuperClassMembers(name, names); |
| } |
| |
| void checkInterfaceImplementation() { |
| LibraryElement library = cls.library; |
| classMembers.forEach((Name name, Member classMember) { |
| if (!name.isAccessibleFrom(library)) return; |
| checkInterfaceMember(name, classMember, classMember.implementation); |
| }); |
| } |
| } |
| |
| /// Class Member creator for classes where the interface members might be |
| /// different from the class members. |
| class InterfaceMembersCreator extends MembersCreator { |
| final Map<Name, MemberSignature> interfaceMembers; |
| |
| InterfaceMembersCreator(Compiler compiler, |
| ClassElement cls, |
| Iterable<String> computedMemberNames, |
| Map<Name, Member> classMembers, |
| Map<Name, MemberSignature> this.interfaceMembers) |
| : super(compiler, cls, computedMemberNames, classMembers); |
| |
| Map<Name, Member> computeMembers(String name, Setlet<Name> names) { |
| Map<Name, Setlet<Member>> inheritedInterfaceMembers = |
| computeSuperMembers(name, names); |
| Map<Name, Member> declaredMembers = computeClassMembers(name, names); |
| computeInterfaceMembers(inheritedInterfaceMembers, declaredMembers); |
| return declaredMembers; |
| } |
| |
| /// Compute the members of the super type(s) of [cls]. The class members are |
| /// stored if the [classMembers] map and the inherited interface members are |
| /// returned. |
| /// |
| /// If [name] and [names] are not null, the computation is restricted to |
| /// members with these names. |
| Map<Name, Setlet<Member>> computeSuperMembers(String name, |
| Setlet<Name> names) { |
| computeSuperClassMembers(name, names); |
| return computeSuperInterfaceMembers(name, names); |
| } |
| |
| Map<Name, Setlet<Member>> computeSuperInterfaceMembers(String name, |
| Setlet<Name> names) { |
| |
| |
| InterfaceType supertype = cls.supertype; |
| assert(invariant(cls, supertype != null, |
| message: "Interface members computed for $cls.")); |
| ClassElement superclass = supertype.element; |
| |
| Map<Name, Setlet<Member>> inheritedInterfaceMembers = |
| new Map<Name, Setlet<Member>>(); |
| |
| void inheritInterfaceMember(InterfaceType supertype, |
| MemberSignature member) { |
| if (shouldSkipMember(member)) return; |
| Setlet<Member> members = |
| inheritedInterfaceMembers.putIfAbsent( |
| member.name, () => new Setlet<Member>()); |
| for (DeclaredMember declaredMember in member.declarations) { |
| members.add(declaredMember.inheritFrom(supertype)); |
| } |
| } |
| |
| void inheritInterfaceMembers(InterfaceType supertype) { |
| supertype.element.forEachInterfaceMember((MemberSignature member) { |
| inheritInterfaceMember(supertype, member); |
| }); |
| } |
| |
| if (names != null) { |
| for (Name memberName in names) { |
| inheritInterfaceMember(supertype, |
| superclass.lookupInterfaceMember(memberName)); |
| } |
| } else { |
| inheritInterfaceMembers(supertype); |
| } |
| |
| // Inherit interface members from superinterfaces. |
| for (Link<DartType> link = cls.interfaces; |
| !link.isEmpty; |
| link = link.tail) { |
| InterfaceType superinterface = link.head; |
| if (names != null) { |
| MembersCreator._computeClassMember( |
| compiler, superinterface.element, name, names); |
| for (Name memberName in names) { |
| inheritInterfaceMember(superinterface, |
| superinterface.element.lookupInterfaceMember(memberName)); |
| } |
| } else { |
| MembersCreator.computeAllClassMembers(compiler, superinterface.element); |
| inheritInterfaceMembers(superinterface); |
| } |
| } |
| |
| return inheritedInterfaceMembers; |
| } |
| |
| /// Checks that a class member exists for every interface member. |
| void checkInterfaceImplementation() { |
| LibraryElement library = cls.library; |
| checkImplementsFunctionWithCall(); |
| interfaceMembers.forEach((Name name, MemberSignature interfaceMember) { |
| if (!name.isAccessibleFrom(library)) return; |
| Member classMember = classMembers[name]; |
| if (classMember != null) classMember = classMember.implementation; |
| checkInterfaceMember(name, interfaceMember, classMember); |
| }); |
| } |
| |
| /// Compute the interface members of [cls] given the set of inherited |
| /// interface members [inheritedInterfaceMembers] and declared members |
| /// [declaredMembers]. The computed members are stored in [interfaceMembers]. |
| void computeInterfaceMembers( |
| Map<Name, Setlet<Member>> inheritedInterfaceMembers, |
| Map<Name, Member> declaredMembers) { |
| InterfaceType thisType = cls.thisType; |
| // Compute the interface members by overriding the inherited members with |
| // a declared member or by computing a single, possibly synthesized, |
| // inherited member. |
| inheritedInterfaceMembers.forEach( |
| (Name name, Setlet<Member> inheritedMembers) { |
| Member declared = declaredMembers[name]; |
| if (declared != null) { |
| // Check that [declaredMember] is a valid override |
| for (Member inherited in inheritedMembers) { |
| checkValidOverride(declared, inherited); |
| } |
| if (!declared.isStatic) { |
| interfaceMembers[name] = declared; |
| } |
| } else if (inheritedMembers.length == 1) { |
| interfaceMembers[name] = inheritedMembers.single; |
| } else { |
| bool someAreGetters = false; |
| bool allAreGetters = true; |
| Map<DartType, Setlet<Member>> subtypesOfAllInherited = |
| new Map<DartType, Setlet<Member>>(); |
| outer: for (Member inherited in inheritedMembers) { |
| if (inherited.isGetter) { |
| someAreGetters = true; |
| if (!allAreGetters) break outer; |
| } else { |
| allAreGetters = false; |
| if (someAreGetters) break outer; |
| } |
| for (MemberSignature other in inheritedMembers) { |
| if (!compiler.types.isSubtype(inherited.functionType, |
| other.functionType)) { |
| continue outer; |
| } |
| } |
| subtypesOfAllInherited.putIfAbsent(inherited.functionType, |
| () => new Setlet<Member>()).add(inherited); |
| } |
| if (someAreGetters && !allAreGetters) { |
| compiler.reportWarning(cls, |
| MessageKind.INHERIT_GETTER_AND_METHOD, |
| {'class': thisType, 'name': name.text }); |
| for (Member inherited in inheritedMembers) { |
| MessageKind kind; |
| if (inherited.isMethod) { |
| kind = MessageKind.INHERITED_METHOD; |
| } else { |
| assert(invariant(cls, inherited.isGetter, |
| message: 'Conflicting member is neither a method nor a ' |
| 'getter.')); |
| if (inherited.isDeclaredByField) { |
| kind = MessageKind.INHERITED_IMPLICIT_GETTER; |
| } else { |
| kind = MessageKind.INHERITED_EXPLICIT_GETTER; |
| } |
| } |
| compiler.reportInfo(inherited.element, kind, |
| {'class': inherited.declarer, 'name': name.text }); |
| } |
| interfaceMembers[name] = new ErroneousMember(inheritedMembers); |
| } else if (subtypesOfAllInherited.length == 1) { |
| // All signatures have the same type. |
| Setlet<Member> members = subtypesOfAllInherited.values.first; |
| MemberSignature inherited = members.first; |
| if (members.length != 1) { |
| // Multiple signatures with the same type => return a |
| // synthesized signature. |
| inherited = new SyntheticMember( |
| members, inherited.type, inherited.functionType); |
| } |
| interfaceMembers[name] = inherited; |
| } else { |
| _inheritedSynthesizedMember(name, inheritedMembers); |
| } |
| } |
| }); |
| |
| // Add the non-overriding instance methods to the interface members. |
| declaredMembers.forEach((Name name, Member member) { |
| if (!member.isStatic) { |
| interfaceMembers.putIfAbsent(name, () => member); |
| } |
| }); |
| } |
| |
| /// Create and inherit a synthesized member for [inheritedMembers]. |
| void _inheritedSynthesizedMember(Name name, |
| Setlet<Member> inheritedMembers) { |
| // Multiple signatures with different types => create the synthesized |
| // version. |
| int minRequiredParameters; |
| int maxPositionalParameters; |
| Set<String> names = new Set<String>(); |
| for (MemberSignature member in inheritedMembers) { |
| int requiredParameters = 0; |
| int optionalParameters = 0; |
| if (member.isSetter) { |
| requiredParameters = 1; |
| } |
| if (member.type.isFunctionType) { |
| FunctionType type = member.type; |
| type.namedParameters.forEach( |
| (String name) => names.add(name)); |
| requiredParameters = type.parameterTypes.length; |
| optionalParameters = type.optionalParameterTypes.length; |
| } |
| int positionalParameters = requiredParameters + optionalParameters; |
| if (minRequiredParameters == null || |
| minRequiredParameters > requiredParameters) { |
| minRequiredParameters = requiredParameters; |
| } |
| if (maxPositionalParameters == null || |
| maxPositionalParameters < positionalParameters) { |
| maxPositionalParameters = positionalParameters; |
| } |
| } |
| int optionalParameters = |
| maxPositionalParameters - minRequiredParameters; |
| // TODO(johnniwinther): Support function types with both optional |
| // and named parameters? |
| if (optionalParameters == 0 || names.isEmpty) { |
| DartType dynamic = const DynamicType(); |
| List<DartType> requiredParameterTypes = |
| new List.filled(minRequiredParameters, dynamic); |
| List<DartType> optionalParameterTypes = |
| new List.filled(optionalParameters, dynamic); |
| List<String> namedParameters = |
| names.toList()..sort((a, b) => a.compareTo(b)); |
| List<DartType> namedParameterTypes = |
| new List.filled(namedParameters.length, dynamic); |
| FunctionType memberType = new FunctionType.synthesized( |
| const DynamicType(), |
| requiredParameterTypes, |
| optionalParameterTypes, |
| namedParameters, namedParameterTypes); |
| DartType type = memberType; |
| if (inheritedMembers.first.isGetter || |
| inheritedMembers.first.isSetter) { |
| type = const DynamicType(); |
| } |
| interfaceMembers[name] = |
| new SyntheticMember(inheritedMembers, type, memberType); |
| } |
| } |
| } |
| |
| abstract class ClassMemberMixin implements ClassElement { |
| /// When [classMembers] and [interfaceMembers] have not been fully computed |
| /// [computedMembersNames] holds the names for which members have already been |
| /// computed. |
| /// |
| /// If [computedMemberNames], [classMembers] and [interfaceMembers] are `null` |
| /// no members have been computed, if only [computedMemberNames] is `null` all |
| /// members have been computed. A non-null [computedMemberNames] implicitly |
| /// includes `call`. |
| Iterable<String> computedMemberNames; |
| |
| /// If `true` interface members are the non-static class member. |
| bool interfaceMembersAreClassMembers = true; |
| |
| Map<Name, Member> classMembers; |
| Map<Name, MemberSignature> interfaceMembers; |
| |
| /// Creates the necessary maps and [MembersCreator] for compute members of |
| /// this class. |
| MembersCreator _prepareCreator(Compiler compiler) { |
| if (classMembers == null) { |
| classMembers = new Map<Name, Member>(); |
| |
| if (interfaceMembersAreClassMembers) { |
| ClassMemberMixin superclass = this.superclass; |
| if ((superclass != null && |
| (!superclass.interfaceMembersAreClassMembers || |
| superclass.isMixinApplication)) || |
| !interfaces.isEmpty) { |
| interfaceMembersAreClassMembers = false; |
| } |
| } |
| if (!interfaceMembersAreClassMembers) { |
| interfaceMembers = new Map<Name, MemberSignature>(); |
| } |
| } |
| return interfaceMembersAreClassMembers |
| ? new ClassMembersCreator(compiler, this, |
| computedMemberNames, classMembers) |
| : new InterfaceMembersCreator(compiler, this, |
| computedMemberNames, classMembers, interfaceMembers); |
| } |
| |
| static Iterable<String> _EMPTY_MEMBERS_NAMES = const <String>[]; |
| |
| /// Compute the members by the name [name] for this class. [names] collects |
| /// the set of possible variations of [name], including getter, setter and |
| /// and private names. |
| void computeClassMember(Compiler compiler, String name, Setlet<Name> names) { |
| if (isMemberComputed(name)) return; |
| if (Name.isPrivateName(name)) { |
| names..add(new Name(name, library)) |
| ..add(new Name(name, library, isSetter: true)); |
| } |
| MembersCreator creator = _prepareCreator(compiler); |
| creator.computeMembersByName(name, names); |
| if (computedMemberNames == null) { |
| computedMemberNames = _EMPTY_MEMBERS_NAMES; |
| } |
| if (name != Identifiers.call) { |
| Setlet<String> set; |
| if (identical(computedMemberNames, _EMPTY_MEMBERS_NAMES)) { |
| computedMemberNames = set = new Setlet<String>(); |
| } else { |
| set = computedMemberNames; |
| } |
| set.add(name); |
| } |
| } |
| |
| void computeAllClassMembers(Compiler compiler) { |
| if (areAllMembersComputed()) return; |
| MembersCreator creator = _prepareCreator(compiler); |
| creator.computeAllMembers(); |
| computedMemberNames = null; |
| assert(invariant(this, areAllMembersComputed())); |
| } |
| |
| bool areAllMembersComputed() { |
| return computedMemberNames == null && classMembers != null; |
| } |
| |
| bool isMemberComputed(String name) { |
| if (computedMemberNames == null) { |
| return classMembers != null; |
| } else { |
| return name == Identifiers.call || |
| computedMemberNames.contains(name); |
| } |
| } |
| |
| Member lookupClassMember(Name name) { |
| assert(invariant(this, |
| isMemberComputed(name.text), |
| message: "Member ${name} has not been computed for $this.")); |
| return classMembers[name]; |
| } |
| |
| void forEachClassMember(f(Member member)) { |
| assert(invariant(this, areAllMembersComputed(), |
| message: "Members have not been fully computed for $this.")); |
| classMembers.forEach((_, member) => f(member)); |
| } |
| |
| MemberSignature lookupInterfaceMember(Name name) { |
| assert(invariant(this, isMemberComputed(name.text), |
| message: "Member ${name.text} has not been computed for $this.")); |
| if (interfaceMembersAreClassMembers) { |
| Member member = classMembers[name]; |
| if (member != null && member.isStatic) return null; |
| return member; |
| } |
| return interfaceMembers[name]; |
| } |
| |
| void forEachInterfaceMember(f(MemberSignature member)) { |
| assert(invariant(this, areAllMembersComputed(), |
| message: "Members have not been fully computed for $this.")); |
| if (interfaceMembersAreClassMembers) { |
| classMembers.forEach((_, member) { |
| if (!member.isStatic) f(member); |
| }); |
| } else { |
| interfaceMembers.forEach((_, member) => f(member)); |
| } |
| } |
| } |