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