// 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 '../common/resolution.dart' show
    Resolution;
import '../compiler.dart' show
    Compiler;
import '../dart_types.dart';
import '../diagnostics/diagnostic_listener.dart' show
    DiagnosticMessage,
    DiagnosticReporter;
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."));
  }

  DiagnosticReporter get reporter => compiler.reporter;

  Resolution get resolution => compiler.resolution;

  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(resolution);
          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(resolution);
          DartType type = functionType.returnType;
          addDeclaredMember(name, type, functionType);
        } else if (element.isSetter) {
          FunctionType functionType = element.computeType(resolution);
          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(resolution);
          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, () {
        reporter.reportWarningMessage(
            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, () {
          DiagnosticMessage warning = reporter.createMessage(
              cls,
              interfaceMember.declarations.length == 1
                  ? singleKind : multipleKind,
              {'class': cls.name,
               'name': name.text,
               'method': interfaceMember,
               'declarer': inherited.declarer});
          List<DiagnosticMessage> infos = <DiagnosticMessage>[];
          for (Member inherited in interfaceMember.declarations) {
            infos.add(reporter.createMessage(
                inherited.element,
                inherited.isDeclaredByField ?
                    implicitlyDeclaredKind : explicitlyDeclaredKind,
                {'class': inherited.declarer.name,
                 'name': name.text}));
          }
          reporter.reportWarning(warning, infos);
        });
      }
      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, () {
      reporter.reportWarningMessage(
          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,
                () {
              reporter.reportWarning(
                  reporter.createMessage(
                      declared.element,
                      MessageKind.INSTANCE_STATIC_SAME_NAME,
                      {'memberName': declared.name,
                       'className': superclass.name}),
                  <DiagnosticMessage>[
                      reporter.createMessage(
                          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, () {
            reporter.reportError(
                reporter.createMessage(
                    declared.element,
                    errorKind,
                    {'name': declared.name.text,
                     'class': cls.thisType,
                     'inheritedClass': inherited.declarer}),
                <DiagnosticMessage>[
                    reporter.createMessage(
                        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, () {
                reporter.reportWarning(
                    reporter.createMessage(
                        declared.element,
                        warningKind,
                        {'declaredType': declared.type,
                         'name': declared.name.text,
                         'class': cls.thisType,
                         'inheritedType': inherited.type,
                         'inheritedClass': inherited.declarer}),
                    <DiagnosticMessage>[
                        reporter.createMessage(
                            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) {
    reporter.reportError(
        reporter.createMessage(
            errorneousElement,
            errorMessage,
            {'memberName': contextElement.name,
             'className': contextElement.enclosingClass.name}),
        <DiagnosticMessage>[
            reporter.createMessage(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) {
          DiagnosticMessage warning = reporter.createMessage(
              cls,
              MessageKind.INHERIT_GETTER_AND_METHOD,
              {'class': thisType, 'name': name.text });
          List<DiagnosticMessage> infos = <DiagnosticMessage>[];
          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;
              }
            }
            infos.add(reporter.createMessage(
                inherited.element,
                kind,
                {'class': inherited.declarer, 'name': name.text}));
          }
          reporter.reportWarning(warning, infos);
          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) {
      ensureResolved(compiler.resolution);
      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));
    }
  }
}
