Search in sources :

Example 91 with Interface

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);
                }
            }
        }
    }
}
Also used : Type(org.eclipse.ceylon.model.typechecker.model.Type) ArrayList(java.util.ArrayList) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) HashSet(java.util.HashSet)

Example 92 with Interface

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);
    }
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Function(org.eclipse.ceylon.model.typechecker.model.Function) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) ArrayList(java.util.ArrayList) AnnotationList(org.eclipse.ceylon.compiler.typechecker.tree.Tree.AnnotationList) List(org.eclipse.ceylon.langtools.tools.javac.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) ThrowerCatchallConstructor(org.eclipse.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Reference(org.eclipse.ceylon.model.typechecker.model.Reference) TypeAlias(org.eclipse.ceylon.model.typechecker.model.TypeAlias) Type(org.eclipse.ceylon.model.typechecker.model.Type) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Setter(org.eclipse.ceylon.model.typechecker.model.Setter) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface)

Example 93 with Interface

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);
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) HashSet(java.util.HashSet)

Example 94 with Interface

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);
}
Also used : TransformationPlan(org.eclipse.ceylon.compiler.java.codegen.recovery.TransformationPlan) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) Drop(org.eclipse.ceylon.compiler.java.codegen.recovery.Drop)

Example 95 with Interface

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;
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) LinkedList(java.util.LinkedList)

Aggregations

Interface (org.eclipse.ceylon.model.typechecker.model.Interface)105 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)99 Type (org.eclipse.ceylon.model.typechecker.model.Type)64 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)58 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)40 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)35 LazyInterface (org.eclipse.ceylon.model.loader.model.LazyInterface)34 Class (org.eclipse.ceylon.model.typechecker.model.Class)32 ModelUtil.getContainingClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ModelUtil.getContainingClassOrInterface)32 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)32 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)29 ModelUtil.appliedType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType)27 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)21 ModelUtil.getOuterClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ModelUtil.getOuterClassOrInterface)20 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)20 ModelUtil.intersectionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.intersectionType)19 ModelUtil.unionType (org.eclipse.ceylon.model.typechecker.model.ModelUtil.unionType)19 AnalyzerUtil.getTupleType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTupleType)18 AnalyzerUtil.spreadType (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.spreadType)18 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)18