use of org.eclipse.ceylon.model.typechecker.model.Interface in project ceylon by eclipse.
the class ClassTransformer method satisfaction.
private void satisfaction(Tree.SatisfiedTypes satisfied, final Class model, ClassDefinitionBuilder classBuilder) {
Set<Interface> satisfiedInterfaces = new HashSet<Interface>();
// start by saying that we already satisfied each interface from superclasses
Type superClass = model.getExtendedType();
while (superClass != null) {
for (Type interfaceDecl : superClass.getSatisfiedTypes()) {
collectInterfaces((Interface) interfaceDecl.getDeclaration(), satisfiedInterfaces);
}
superClass = superClass.getExtendedType();
}
// now satisfy each new interface
if (satisfied != null) {
for (Tree.StaticType type : satisfied.getTypes()) {
try {
Type satisfiedType = type.getTypeModel();
TypeDeclaration decl = satisfiedType.getDeclaration();
if (!(decl instanceof Interface)) {
continue;
}
// make sure we get the right instantiation of the interface
satisfiedType = model.getType().getSupertype(decl);
concreteMembersFromSuperinterfaces(model, classBuilder, satisfiedType, satisfiedInterfaces);
} catch (BugException e) {
e.addError(type);
}
}
}
// now find the set of interfaces we implemented twice with more refined type parameters
if (model.getExtendedType() != null) {
// reuse that Set
satisfiedInterfaces.clear();
for (Type interfaceDecl : model.getSatisfiedTypes()) {
collectInterfaces((Interface) interfaceDecl.getDeclaration(), satisfiedInterfaces);
}
if (!satisfiedInterfaces.isEmpty()) {
// sort it to facilitate test comparisons that work in JDK7 and 8
ArrayList<Interface> sortedInterfaces = new ArrayList<Interface>(satisfiedInterfaces.size());
sortedInterfaces.addAll(satisfiedInterfaces);
Collections.sort(sortedInterfaces, DeclarationComparator);
// now see if we refined them
for (Interface iface : sortedInterfaces) {
// skip those we can't do anything about
if (!supportsReified(iface) || !CodegenUtil.isCompanionClassNeeded(iface))
continue;
Type thisType = model.getType().getSupertype(iface);
Type superClassType = model.getExtendedType().getSupertype(iface);
if (thisType != null && superClassType != null && !thisType.isExactly(superClassType) && thisType.isSubtypeOf(superClassType)) {
// we're refining it
classBuilder.refineReifiedType(thisType);
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Interface in project ceylon by eclipse.
the class ClassTransformer method concreteMembersFromSuperinterfaces.
/**
* Generates companion fields ($Foo$impl) and methods
*/
private void concreteMembersFromSuperinterfaces(final Class model, ClassDefinitionBuilder classBuilder, Type satisfiedType, Set<Interface> satisfiedInterfaces) {
satisfiedType = satisfiedType.resolveAliases();
Interface iface = (Interface) satisfiedType.getDeclaration();
if (satisfiedInterfaces.contains(iface) || iface.isIdentifiable()) {
return;
}
// 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 (!ModelUtil.isCeylonDeclaration(iface)) {
// let's not try to implement CMI for Java interfaces
return;
}
// For each super interface
for (Declaration member : sortedMembers(iface.getMembers())) {
if (member instanceof Class) {
Class klass = (Class) member;
final Type typedMember = satisfiedType.getTypeMember(klass, Collections.<Type>emptyList());
if (Strategy.generateInstantiator(member) && !klass.hasConstructors() && !model.isFormal() && needsCompanionDelegate(model, typedMember) && model.getDirectMember(member.getName(), null, false) == null) {
// instantiator method implementation
generateInstantiatorDelegate(classBuilder, satisfiedType, iface, klass, null, model.getType(), !member.isFormal());
}
if (klass.hasConstructors()) {
for (Declaration m : klass.getMembers()) {
if (m instanceof Constructor && Strategy.generateInstantiator(m)) {
Constructor ctor = (Constructor) m;
generateInstantiatorDelegate(classBuilder, satisfiedType, iface, klass, ctor, model.getType(), true);
}
}
}
}
// type aliases are on the $impl class
if (member instanceof TypeAlias)
continue;
if (Strategy.onlyOnCompanion(member)) {
// (they're just private methods on the $impl)
continue;
}
if (member instanceof Function) {
Function method = (Function) member;
final TypedReference typedMember = satisfiedType.getTypedMember(method, typesOfTypeParameters(method.getTypeParameters()));
Declaration sub = (Declaration) model.getMember(method.getName(), getSignatureIfRequired(typedMember), false, true);
if (sub instanceof Function) /* && !sub.isAbstraction()*/
{
Function subMethod = (Function) sub;
if (subMethod.getParameterLists().isEmpty()) {
continue;
}
java.util.List<java.util.List<Type>> producedTypeParameterBounds = producedTypeParameterBounds(typedMember, subMethod);
// final TypedReference refinedTypedMember = model.getType().getTypedMember(subMethod, Collections.<Type>emptyList());
final java.util.List<TypeParameter> typeParameters = subMethod.getTypeParameters();
final java.util.List<Parameter> parameters = subMethod.getFirstParameterList().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 TypedReference typedParameter = typedMember.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, typedMember, model.getType(), modifierTransformation().defaultValueMethodBridge(), typeParameters, producedTypeParameterBounds, typedParameter.getFullType(), Naming.getDefaultedParamMethodName(method, param), parameters.subList(0, parameters.indexOf(param)), param.getModel().getTypeErased(), null, param);
classBuilder.method(defaultValueDelegate);
}
if (Strategy.hasDefaultParameterOverload(param)) {
if ((method.isDefault() || method.isShared() && !method.isFormal()) && Decl.equal(method, subMethod)) {
MethodDefinitionBuilder overload = new DefaultedArgumentMethodTyped(new DaoThis((Tree.AnyMethod) null, null), MethodDefinitionBuilder.method(this, subMethod), typedMember, true).makeOverload(subMethod.getFirstParameterList(), param, typeParameters);
classBuilder.method(overload);
}
hasOverloads = true;
}
}
}
// delegating to the $impl instance
if (needsCompanionDelegate(model, typedMember)) {
final MethodDefinitionBuilder concreteMemberDelegate = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().methodBridge(method), typeParameters, producedTypeParameterBounds, typedMember.getType(), naming.selector(method), method.getFirstParameterList().getParameters(), ((Function) member).getTypeErased(), null, null);
classBuilder.method(concreteMemberDelegate);
}
if (hasOverloads && (method.isDefault() || method.isShared() && !method.isFormal()) && Decl.equal(method, subMethod)) {
final MethodDefinitionBuilder canonicalMethod = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().canonicalMethodBridge(), subMethod.getTypeParameters(), producedTypeParameterBounds, typedMember.getType(), Naming.selector(method, Naming.NA_CANONICAL_METHOD), method.getFirstParameterList().getParameters(), ((Function) member).getTypeErased(), naming.selector(method), null);
classBuilder.method(canonicalMethod);
}
}
} else if (member instanceof Value || member instanceof Setter) {
TypedDeclaration attr = (TypedDeclaration) member;
final TypedReference typedMember = satisfiedType.getTypedMember(attr, null);
if (needsCompanionDelegate(model, typedMember)) {
Setter setter = (member instanceof Setter) ? (Setter) member : null;
if (member instanceof Value) {
Value getter = (Value) member;
if (member instanceof JavaBeanValue) {
setter = ((Value) member).getSetter();
}
final MethodDefinitionBuilder getterDelegate = makeDelegateToCompanion(iface, typedMember, model.getType(), modifierTransformation().getterBridge(getter), Collections.<TypeParameter>emptyList(), Collections.<java.util.List<Type>>emptyList(), typedMember.getType(), Naming.getGetterName(getter), Collections.<Parameter>emptyList(), getter.getTypeErased(), null, null);
classBuilder.method(getterDelegate);
}
if (setter != null) {
final MethodDefinitionBuilder setterDelegate = makeDelegateToCompanion(iface, satisfiedType.getTypedMember(setter, null), model.getType(), modifierTransformation().setterBridge(setter), Collections.<TypeParameter>emptyList(), Collections.<java.util.List<Type>>emptyList(), typeFact().getAnythingType(), Naming.getSetterName(attr), Collections.<Parameter>singletonList(setter.getParameter()), setter.getTypeErased(), null, null);
classBuilder.method(setterDelegate);
}
if (Decl.isValue(member) && ((Value) attr).isVariable()) {
// $impl to delegate to
throw new BugException("assertion failed: " + member.getQualifiedNameString() + " was unexpectedly a variable value");
}
}
} else {
Reference typedMember = member instanceof TypeDeclaration ? satisfiedType.getTypeMember((TypeDeclaration) member, Collections.<Type>emptyList()) : satisfiedType.getTypedMember((TypedDeclaration) member, Collections.<Type>emptyList());
if (needsCompanionDelegate(model, typedMember)) {
throw new BugException("unhandled concrete interface member " + member.getQualifiedNameString() + " " + member.getClass());
}
}
}
// Add $impl instances for the whole interface hierarchy
satisfiedInterfaces.add(iface);
for (Type sat : iface.getSatisfiedTypes()) {
sat = model.getType().getSupertype(sat.getDeclaration());
concreteMembersFromSuperinterfaces(model, classBuilder, sat, satisfiedInterfaces);
}
}
use of org.eclipse.ceylon.model.typechecker.model.Interface in project ceylon by eclipse.
the class ClassTransformer method buildFieldInits.
protected void buildFieldInits(Class model, ClassDefinitionBuilder classBuilder, final ListBuffer<JCStatement> stmts) {
final HashSet<String> excludeFields = new HashSet<String>();
// initialize reified type arguments to according to parameters
for (TypeParameter tp : model.getTypeParameters()) {
excludeFields.add(naming.getTypeArgumentDescriptorName(tp));
stmts.add(makeReifiedTypeParameterAssignment(tp));
}
// initialize companion instances to a new companion instance
if (!model.getSatisfiedTypes().isEmpty()) {
SatisfactionVisitor visitor = new SatisfactionVisitor() {
@Override
public void satisfiesDirectly(Class model, Interface iface, boolean alreadySatisfied) {
if (!alreadySatisfied) {
assignCompanion(model, iface);
}
}
@Override
public void satisfiesIndirectly(Class model, Interface iface, boolean alreadySatisfied) {
if (!alreadySatisfied) {
assignCompanion(model, iface);
}
}
private void assignCompanion(Class model, Interface iface) {
if (hasImpl(iface) && excludeFields.add(getCompanionFieldName(iface))) {
stmts.add(makeCompanionInstanceAssignment(model, iface, model.getType().getSupertype(iface)));
}
}
@Override
public void satisfiesIndirectlyViaClass(Class model, Interface iface, Class via, boolean alreadySatisfied) {
// don't care
}
};
walkSatisfiedInterfaces(model, model.getType(), visitor);
}
// initialize attribute fields to null or a zero
appendDefaultFieldInits(classBuilder, stmts, excludeFields);
}
use of org.eclipse.ceylon.model.typechecker.model.Interface in project ceylon by eclipse.
the class CeylonVisitor method visit.
public void visit(Tree.ClassOrInterface decl) {
TransformationPlan plan = gen.errors().hasDeclarationAndMarkBrokenness(decl);
if (plan instanceof Drop) {
return;
}
if (skipHeaderMergeLater(decl)) {
return;
}
// To accept this class it is either not native or native for this backend
if (!acceptDeclaration(decl))
return;
int annots = gen.checkCompilerAnnotations(decl, defs);
if (decl.getDeclarationModel().isClassOrInterfaceMember()) {
if (decl.getDeclarationModel().isInterfaceMember()) {
classBuilder.getCompanionBuilder((Interface) decl.getDeclarationModel().getContainer()).defs(gen.classGen().transform(decl));
} else {
classBuilder.defs(gen.classGen().transform(decl));
}
} else {
appendList(gen.classGen().transform(decl));
}
gen.resetCompilerAnnotations(annots);
}
use of org.eclipse.ceylon.model.typechecker.model.Interface in project ceylon by eclipse.
the class ExpressionTransformer method getVarianceCastResult.
private VarianceCastResult getVarianceCastResult(Type expectedType, Type exprType) {
// exactly the same type, doesn't need casting
if (expectedType == null || exprType.isExactly(expectedType))
return null;
// if we're not trying to put it into an interface, there's no need
if (!(expectedType.getDeclaration() instanceof Interface))
return null;
// the interface must have type arguments, otherwise we can't use raw types
if (expectedType.getTypeArguments().isEmpty())
return null;
// see if any of those type arguments has variance
boolean hasVariance = false;
for (TypeParameter t : expectedType.getTypeArguments().keySet()) {
if (expectedType.isContravariant(t) || expectedType.isCovariant(t)) {
hasVariance = true;
break;
}
}
if (!hasVariance)
return null;
// see if we're inheriting the interface twice with different type parameters
java.util.List<Type> satisfiedTypes = new LinkedList<Type>();
for (Type superType : simplifyType(exprType).getSupertypes()) {
if (Decl.equal(superType.getDeclaration(), expectedType.getDeclaration()))
satisfiedTypes.add(superType);
}
// discard the supertypes that have the same erasure
for (int i = 0; i < satisfiedTypes.size(); i++) {
Type pt = satisfiedTypes.get(i);
for (int j = i + 1; j < satisfiedTypes.size(); j++) {
Type other = satisfiedTypes.get(j);
if (pt.isExactly(other) || haveSameErasure(pt, other)) {
satisfiedTypes.remove(j);
break;
}
}
}
// we need at least two instantiations
if (satisfiedTypes.size() <= 1)
return null;
boolean needsCast = false;
// we need at least one that differs
for (Type superType : satisfiedTypes) {
if (!exprType.isExactly(superType)) {
needsCast = true;
break;
}
}
// no cast needed if they are all the same type
if (!needsCast)
return null;
// find the better cast match
for (Type superType : satisfiedTypes) {
if (expectedType.isExactly(superType))
return new VarianceCastResult(superType);
}
// nothing better than a raw cast (Stef: not sure that can happen)
return RawCastVarianceResult;
}
Aggregations