// 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.dart';
import '../common/names.dart' show Identifiers, Names;
import '../common/resolution.dart' show Resolution;
import '../elements/resolution_types.dart';
import '../elements/elements.dart'
    show
        ClassElement,
        Element,
        LibraryElement,
        Member,
        MemberElement,
        MemberSignature,
        MixinApplicationElement,
        Name;
import '../util/util.dart';

part 'member_impl.dart';

abstract class MembersCreator {
  final ClassElement cls;
  final Resolution resolution;

  final Iterable<String> computedMemberNames;
  final Map<Name, Member> classMembers;

  Map<dynamic /* Member | Element */, Set<MessageKind>> reportedMessages =
      new Map<dynamic, Set<MessageKind>>();

  MembersCreator(
      this.resolution, this.cls, this.computedMemberNames, this.classMembers) {
    assert(invariant(cls, cls.isDeclaration,
        message: "Members may only be computed on declarations."));
  }

  DiagnosticReporter get reporter => resolution.reporter;

  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() {
    computeMembers(null, null);
    if (!cls.isAbstract) {
      Member member = classMembers[Names.noSuchMethod_];
      if (member != null &&
          !resolution.target.isDefaultNoSuchMethod(member.element)) {
        return;
      }
      // 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) {
    ResolutionInterfaceType 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(resolution, superclass, name, names);
      for (Name memberName in names) {
        inheritClassMember(superclass.lookupClassMember(memberName));
      }
    } else {
      computeAllClassMembers(resolution, 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(
              resolution, mixinApplication.mixin, nameText, names);
          for (Name memberName in names) {
            inheritMixinMember(
                mixinApplication.mixin.lookupClassMember(memberName));
          }
        } else {
          computeAllClassMembers(resolution, mixinApplication.mixin);
          mixinApplication.mixin.forEachClassMember(inheritMixinMember);
        }
      }
    } else {
      LibraryElement library = cls.library;
      ResolutionInterfaceType 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, ResolutionDartType type,
            ResolutionFunctionType 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) {
          ResolutionDartType type = element.computeType(resolution);
          addDeclaredMember(
              name, type, new ResolutionFunctionType.synthesized(type));
          if (!element.isConst && !element.isFinal) {
            addDeclaredMember(
                name.setter,
                type,
                new ResolutionFunctionType.synthesized(
                    const ResolutionVoidType(), <ResolutionDartType>[type]));
          }
        } else if (element.isGetter) {
          ResolutionFunctionType functionType = element.computeType(resolution);
          ResolutionDartType type = functionType.returnType;
          addDeclaredMember(name, type, functionType);
        } else if (element.isSetter) {
          ResolutionFunctionType functionType = element.computeType(resolution);
          ResolutionDartType type;
          if (!functionType.parameterTypes.isEmpty) {
            type = functionType.parameterTypes.first;
          } else {
            type = const ResolutionDynamicType();
          }
          name = name.setter;
          addDeclaredMember(name, type, functionType);
        } else {
          assert(invariant(element, element.isFunction));
          ResolutionFunctionType 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);

    ClassElement functionClass = resolution.commonElements.functionClass;
    functionClass.ensureResolved(resolution);
    if (cls.asInstanceOf(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 (resolution.target.isTargetSpecificLibrary(cls.library)) return;

    reportMessage(functionClass, MessageKind.UNIMPLEMENTED_METHOD, () {
      reporter.reportWarningMessage(cls, MessageKind.UNIMPLEMENTED_METHOD_ONE, {
        'class': cls.name,
        'name': Identifiers.call,
        'method': Identifiers.call,
        'declarer': 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, resolution.reporter.hasReportedError));
            continue;
          }

          reportMessage(inherited.element, MessageKind.NO_STATIC_OVERRIDE, () {
            reportErrorWithContext(
                declared.element,
                MessageKind.NO_STATIC_OVERRIDE,
                inherited.element,
                MessageKind.NO_STATIC_OVERRIDE_CONT);
          });
        }
      }

      ResolutionDartType 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, resolution.reporter.hasReportedError,
                  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 {
          ResolutionDartType inheritedType = inherited.functionType;
          if (!resolution.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(
      Resolution resolution, ClassMemberMixin cls, String name) {
    if (cls.isMemberComputed(name)) return;
    LibraryElement library = cls.library;
    _computeClassMember(
        resolution,
        cls,
        name,
        new Setlet<Name>()
          ..add(new Name(name, library))
          ..add(new Name(name, library, isSetter: true)));
  }

  static void _computeClassMember(Resolution resolution, ClassMemberMixin cls,
      String name, Setlet<Name> names) {
    cls.computeClassMember(resolution, name, names);
  }

  /// Compute all class and interface names in [cls].
  static void computeAllClassMembers(
      Resolution resolution, ClassMemberMixin cls) {
    cls.computeAllClassMembers(resolution);
  }
}

/// Class member creator for classes where the interface members are known to
/// be a subset of the class members.
class ClassMembersCreator extends MembersCreator {
  ClassMembersCreator(Resolution resolution, ClassElement cls,
      Iterable<String> computedMemberNames, Map<Name, Member> classMembers)
      : super(resolution, 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(
      Resolution resolution,
      ClassElement cls,
      Iterable<String> computedMemberNames,
      Map<Name, Member> classMembers,
      Map<Name, MemberSignature> this.interfaceMembers)
      : super(resolution, 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) {
    ResolutionInterfaceType 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(
        ResolutionInterfaceType 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(ResolutionInterfaceType 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<ResolutionDartType> link = cls.interfaces;
        !link.isEmpty;
        link = link.tail) {
      ResolutionInterfaceType superinterface = link.head;
      if (names != null) {
        MembersCreator._computeClassMember(
            resolution, superinterface.element, name, names);
        for (Name memberName in names) {
          inheritInterfaceMember(superinterface,
              superinterface.element.lookupInterfaceMember(memberName));
        }
      } else {
        MembersCreator.computeAllClassMembers(
            resolution, 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) {
    ResolutionInterfaceType 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<ResolutionDartType, Setlet<Member>> subtypesOfAllInherited =
            new Map<ResolutionDartType, 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 (!resolution.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) {
        ResolutionFunctionType 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) {
      ResolutionDartType dynamic = const ResolutionDynamicType();
      List<ResolutionDartType> requiredParameterTypes =
          new List.filled(minRequiredParameters, dynamic);
      List<ResolutionDartType> optionalParameterTypes =
          new List.filled(optionalParameters, dynamic);
      List<String> namedParameters = names.toList()
        ..sort((a, b) => a.compareTo(b));
      List<ResolutionDartType> namedParameterTypes =
          new List.filled(namedParameters.length, dynamic);
      ResolutionFunctionType memberType =
          new ResolutionFunctionType.synthesized(
              const ResolutionDynamicType(),
              requiredParameterTypes,
              optionalParameterTypes,
              namedParameters,
              namedParameterTypes);
      ResolutionDartType type = memberType;
      if (inheritedMembers.first.isGetter || inheritedMembers.first.isSetter) {
        type = const ResolutionDynamicType();
      }
      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;

  bool _interfaceMembersAreClassMembers;

  /// Compute value of the [_interfaceMembersAreClassMembers] for this class
  /// and its superclasses.
  void _computeInterfaceMembersAreClassMembers(Resolution resolution) {
    if (_interfaceMembersAreClassMembers == null) {
      ensureResolved(resolution);
      ClassMemberMixin superclass = this.superclass;
      if (superclass != null) {
        superclass._computeInterfaceMembersAreClassMembers(resolution);
      }
      if ((superclass != null &&
              (!superclass.interfaceMembersAreClassMembers ||
                  superclass.isMixinApplication)) ||
          !interfaces.isEmpty) {
        _interfaceMembersAreClassMembers = false;
      } else {
        _interfaceMembersAreClassMembers = true;
      }
    }
  }

  /// If `true` interface members are the non-static class member.
  bool get interfaceMembersAreClassMembers => _interfaceMembersAreClassMembers;

  Map<Name, Member> classMembers;
  Map<Name, MemberSignature> interfaceMembers;

  /// Creates the necessary maps and [MembersCreator] for compute members of
  /// this class.
  MembersCreator _prepareCreator(Resolution resolution) {
    if (classMembers == null) {
      _computeInterfaceMembersAreClassMembers(resolution);
      classMembers = new Map<Name, Member>();
      if (!interfaceMembersAreClassMembers) {
        interfaceMembers = new Map<Name, MemberSignature>();
      }
    }
    return interfaceMembersAreClassMembers
        ? new ClassMembersCreator(
            resolution, this, computedMemberNames, classMembers)
        : new InterfaceMembersCreator(resolution, 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(
      Resolution resolution, String name, Setlet<Name> names) {
    // TODO(johnniwinther): Should we assert that the class has been resolved
    // instead?
    ensureResolved(resolution);
    if (isMemberComputed(name)) return;
    if (Name.isPrivateName(name)) {
      names
        ..add(new Name(name, library))
        ..add(new Name(name, library, isSetter: true));
    }
    MembersCreator creator = _prepareCreator(resolution);
    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(Resolution resolution) {
    // TODO(johnniwinther): Should we assert that the class has been resolved
    // instead?
    ensureResolved(resolution);
    if (areAllMembersComputed()) return;
    MembersCreator creator = _prepareCreator(resolution);
    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));
    }
  }
}
