// 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 '../compiler.dart' show Compiler;
import '../dart_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 && !member.declarer.isObject) {
        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) {
    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(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;
      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);

    ClassElement functionClass = resolution.coreClasses.functionClass;
    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);
          });
        }
      }

      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, 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 {
          DartType 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) {
    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(
            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) {
    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 (!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) {
        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(Resolution resolution) {
    if (classMembers == null) {
      ensureResolved(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(
            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) {
    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) {
    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));
    }
  }
}
