*/
private void concreteMembersFromSuperinterfaces(final Class model,
ClassDefinitionBuilder classBuilder,
ProducedType satisfiedType, Set<Interface> satisfiedInterfaces) {
satisfiedType = satisfiedType.resolveAliases();
Interface iface = (Interface)satisfiedType.getDeclaration();
if (satisfiedInterfaces.contains(iface)
|| iface.getType().isExactly(typeFact().getIdentifiableDeclaration().getType())) {
return;
}
// If there is no $impl (e.g. implementing a Java interface)
// then don't instantiate it...
if (hasImpl(iface)) {
// ... otherwise for each satisfied interface,
// instantiate an instance of the
// companion class in the constructor and assign it to a
// $Interface$impl field
transformInstantiateCompanions(classBuilder,
model, iface, satisfiedType);
}
if(!Decl.isCeylon(iface)){
// let's not try to implement CMI for Java interfaces
return;
}
// For each super interface
for (Declaration member : iface.getMembers()) {
if (member instanceof Class
&& Strategy.generateInstantiator(member)
&& !model.isAbstract() && !model.isFormal()
&& model.getDirectMember(member.getName(), null, false) == null) {
// instantiator method implementation
Class klass = (Class)member;
generateInstantiatorDelegate(classBuilder, satisfiedType,
iface, klass, model.getType());
}
// type aliases are on the $impl class
if(member instanceof TypeAlias)
continue;
if (Strategy.onlyOnCompanion(member)) {
// non-shared interface methods don't need implementing
// (they're just private methods on the $impl)
continue;
}
if (member instanceof Method) {
Method method = (Method)member;
final ProducedTypedReference typedMember = satisfiedType.getTypedMember(method, Collections.<ProducedType>emptyList());
Declaration sub = (Declaration)model.getMember(method.getName(), null, false);
if (sub instanceof Method) {
Method subMethod = (Method)sub;
if (subMethod.getParameterLists().isEmpty()) {
continue;
}
java.util.List<java.util.List<ProducedType>> producedTypeParameterBounds = producedTypeParameterBounds(
typedMember, subMethod);
final ProducedTypedReference refinedTypedMember = model.getType().getTypedMember(subMethod, Collections.<ProducedType>emptyList());
final java.util.List<TypeParameter> typeParameters = subMethod.getTypeParameters();
final java.util.List<Parameter> parameters = subMethod.getParameterLists().get(0).getParameters();
boolean hasOverloads = false;
if (!satisfiedInterfaces.contains((Interface)method.getContainer())) {
for (Parameter param : parameters) {
if (Strategy.hasDefaultParameterValueMethod(param)
&& CodegenUtil.getTopmostRefinedDeclaration(param.getModel()).getContainer().equals(member)) {
final ProducedTypedReference typedParameter = refinedTypedMember.getTypedParameter(param);
// If that method has a defaulted parameter,
// we need to generate a default value method
// which also delegates to the $impl
final MethodDefinitionBuilder defaultValueDelegate = makeDelegateToCompanion(iface,
typedParameter,
model.getType(),
PUBLIC | FINAL,
typeParameters, producedTypeParameterBounds,
typedParameter.getType(),
Naming.getDefaultedParamMethodName(method, param),
parameters.subList(0, parameters.indexOf(param)),
param.getModel().getTypeErased(),
null);
classBuilder.method(defaultValueDelegate);
}
if (Strategy.hasDefaultParameterOverload(param)) {
if ((method.isDefault() || method.isShared() && !method.isFormal())
&& Decl.equal(method, subMethod)) {
MethodDefinitionBuilder overloadBuilder = MethodDefinitionBuilder.method(this, subMethod);
MethodDefinitionBuilder overload = new DefaultedArgumentMethodTyped(daoThis, typedMember)
.makeOverload(
overloadBuilder,
subMethod.getParameterLists().get(0),
param,
typeParameters);
classBuilder.method(overload);
}
hasOverloads = true;
}
}
}
// if it has the *most refined* default concrete member,
// then generate a method on the class
// delegating to the $impl instance
if (needsCompanionDelegate(model, member)) {
final MethodDefinitionBuilder concreteMemberDelegate = makeDelegateToCompanion(iface,
typedMember,
model.getType(),
PUBLIC | (method.isDefault() ? 0 : FINAL),
typeParameters,
producedTypeParameterBounds,
typedMember.getType(),
naming.selector(method),
method.getParameterLists().get(0).getParameters(),
((Method) member).getTypeErased(),
null);
classBuilder.method(concreteMemberDelegate);
}
if (hasOverloads
&& (method.isDefault() || method.isShared() && !method.isFormal())
&& Decl.equal(method, subMethod)) {
final MethodDefinitionBuilder canonicalMethod = makeDelegateToCompanion(iface,
typedMember,
model.getType(),
PRIVATE,
subMethod.getTypeParameters(),
producedTypeParameterBounds,
typedMember.getType(),
Naming.selector(method, Naming.NA_CANONICAL_METHOD),
method.getParameterLists().get(0).getParameters(),
((Method) member).getTypeErased(),
naming.selector(method));
classBuilder.method(canonicalMethod);
}
}
} else if (member instanceof Value
|| member instanceof Setter) {
TypedDeclaration attr = (TypedDeclaration)member;
final ProducedTypedReference typedMember = satisfiedType.getTypedMember(attr, null);
if (needsCompanionDelegate(model, member)) {
if (member instanceof Value) {
final MethodDefinitionBuilder getterDelegate = makeDelegateToCompanion(iface,
typedMember,
model.getType(),
PUBLIC | (attr.isDefault() ? 0 : FINAL),
Collections.<TypeParameter>emptyList(),
Collections.<java.util.List<ProducedType>>emptyList(),
typedMember.getType(),
Naming.getGetterName(attr),
Collections.<Parameter>emptyList(),
attr.getTypeErased(),
null);
classBuilder.method(getterDelegate);
}
if (member instanceof Setter) {
final MethodDefinitionBuilder setterDelegate = makeDelegateToCompanion(iface,
typedMember,
model.getType(),
PUBLIC | (((Setter)member).getGetter().isDefault() ? 0 : FINAL),
Collections.<TypeParameter>emptyList(),
Collections.<java.util.List<ProducedType>>emptyList(),
typeFact().getAnythingDeclaration().getType(),
Naming.getSetterName(attr),
Collections.<Parameter>singletonList(((Setter)member).getParameter()),
((Setter) member).getTypeErased(),
null);
classBuilder.method(setterDelegate);
}
if (Decl.isValue(member)
&& ((Value)attr).isVariable()) {
// I don't *think* this can happen because although a
// variable Value can be declared on an interface it
// will need to we refined as a Getter+Setter on a
// subinterface in order for there to be a method in a
// $impl to delegate to
throw new BugException("assertion failed: " + member.getQualifiedNameString() + " was unexpectedly a variable value");
}
}
} else if (needsCompanionDelegate(model, member)) {
throw new BugException("unhandled concrete interface member " + member.getQualifiedNameString() + " " + member.getClass());
}
}
// Add $impl instances for the whole interface hierarchy
satisfiedInterfaces.add(iface);
for (ProducedType sat : iface.getSatisfiedTypes()) {
sat = model.getType().getSupertype(sat.getDeclaration());
concreteMembersFromSuperinterfaces(model, classBuilder, sat, satisfiedInterfaces);
}
}