Search in sources :

Example 31 with ClassOrInterface

use of com.redhat.ceylon.model.typechecker.model.ClassOrInterface in project ceylon-compiler by ceylon.

the class AbstractTransformer method collectQualifyingTypeArguments.

/**
     * Collects all the type parameters and arguments required for an interface that's been pulled up to the
     * toplevel, including its containing type and method type parameters.
     */
private void collectQualifyingTypeArguments(java.util.List<TypeParameter> qualifyingTypeParameters, Map<TypeParameter, Type> qualifyingTypeArguments, java.util.List<Reference> qualifyingTypes) {
    // make sure we only add type parameters with the same name once, as duplicates are erased from the target interface
    // since they cannot be accessed
    Set<String> names = new HashSet<String>();
    // walk the qualifying types backwards to make sure we only add a TP with the same name once and the outer one wins
    for (int i = qualifyingTypes.size() - 1; i >= 0; i--) {
        Reference qualifiedType = qualifyingTypes.get(i);
        Map<TypeParameter, Type> tas = qualifiedType.getTypeArguments();
        java.util.List<TypeParameter> tps = ((Generic) qualifiedType.getDeclaration()).getTypeParameters();
        // add any type params for this type
        if (tps != null) {
            int index = 0;
            for (TypeParameter tp : tps) {
                // add it only once
                if (names.add(tp.getName())) {
                    // start putting all these type parameters at 0 and then in order
                    // so that outer type params end up before inner type params but
                    // order is preserved within each type
                    qualifyingTypeParameters.add(index++, tp);
                    qualifyingTypeArguments.put(tp, tas.get(tp));
                }
            }
        }
        // add any container method TP
        Declaration declaration = qualifiedType.getDeclaration();
        if (Decl.isLocal(declaration)) {
            Scope scope = declaration.getContainer();
            // collect every container method until the next type or package
            java.util.List<Function> methods = new LinkedList<Function>();
            while (scope != null && scope instanceof ClassOrInterface == false && scope instanceof Package == false) {
                if (scope instanceof Function) {
                    methods.add((Function) scope);
                }
                scope = scope.getContainer();
            }
            // methods are sorted inner to outer, which is the order we're following here for types
            for (Function method : methods) {
                java.util.List<TypeParameter> methodTypeParameters = method.getTypeParameters();
                if (methodTypeParameters != null) {
                    int index = 0;
                    for (TypeParameter tp : methodTypeParameters) {
                        // add it only once
                        if (names.add(tp.getName())) {
                            // start putting all these type parameters at 0 and then in order
                            // so that outer type params end up before inner type params but
                            // order is preserved within each type
                            qualifyingTypeParameters.add(index++, tp);
                            qualifyingTypeArguments.put(tp, tp.getType());
                        }
                    }
                }
            }
        }
    }
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) Reference(com.redhat.ceylon.model.typechecker.model.Reference) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference) Generic(com.redhat.ceylon.model.typechecker.model.Generic) LinkedList(java.util.LinkedList) Function(com.redhat.ceylon.model.typechecker.model.Function) Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) Scope(com.redhat.ceylon.model.typechecker.model.Scope) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Package(com.redhat.ceylon.model.typechecker.model.Package) HashSet(java.util.HashSet)

Example 32 with ClassOrInterface

use of com.redhat.ceylon.model.typechecker.model.ClassOrInterface in project ceylon-compiler by ceylon.

the class AbstractTransformer method makeTypeTest.

private <R> R makeTypeTest(TypeTestTransformation<R> typeTester, JCExpression firstTimeExpr, Naming.CName varName, Type testedType, Type expressionType) {
    R result = null;
    // make sure aliases are resolved
    testedType = testedType.resolveAliases();
    // optimisation when all we're doing is making sure it is not null
    if (expressionType != null && testedType.getSupertype(typeFact().getObjectDeclaration()) != null && expressionType.isExactly(typeFact().getOptionalType(testedType))) {
        JCExpression varExpr = firstTimeExpr != null ? firstTimeExpr : varName.makeIdent();
        return typeTester.nullTest(varExpr, JCTree.NE);
    }
    TypeDeclaration declaration = testedType.getDeclaration();
    if (declaration instanceof ClassOrInterface) {
        JCExpression varExpr = firstTimeExpr != null ? firstTimeExpr : varName.makeIdent();
        if (isAnything(testedType)) {
            // everything is Void, it's the root of the hierarchy
            return typeTester.eval(varExpr, true);
        } else if (isNull(testedType)) {
            // is Null => is null
            return typeTester.nullTest(varExpr, JCTree.EQ);
        } else if (testedType.isExactly(typeFact().getObjectType())) {
            // is Object => is not null
            return typeTester.nullTest(varExpr, JCTree.NE);
        } else if (testedType.isExactly(typeFact().getIdentifiableType())) {
            // it's erased
            return typeTester.isIdentifiable(varExpr);
        } else if (testedType.getDeclaration().equals(typeFact().getTrueValueDeclaration().getTypeDeclaration())) {
            return typeTester.isTrue(varExpr);
        } else if (testedType.getDeclaration().equals(typeFact().getFalseValueDeclaration().getTypeDeclaration())) {
            return typeTester.isFalse(varExpr);
        } else if (testedType.isExactly(typeFact().getBasicType())) {
            // it's erased
            return typeTester.isBasic(varExpr);
        } else if (testedType.getDeclaration().getQualifiedNameString().equals("java.lang::Error")) {
            // need to exclude AssertionError
            return typeTester.andOr(typeTester.isInstanceof(varExpr, testedType, expressionType), typeTester.not(typeTester.isInstanceof(varName.makeIdent(), typeFact().getAssertionErrorDeclaration().getType(), expressionType)), JCTree.AND);
        } else if (!hasTypeArguments(testedType)) {
            // non-generic Class or interface, use instanceof
            return typeTester.isInstanceof(varExpr, testedType, expressionType);
        } else {
            // generic class or interface...
            if (declaration.getSelfType() != null && // of TypeArg
            declaration.getSelfType().getDeclaration() instanceof TypeParameter && // given TypeArg satisfies SelfType<TypeArg>
            declaration.getSelfType().isSubtypeOf(declaration.getType())) {
                Type selfTypeArg = testedType.getTypeArguments().get(declaration.getSelfType().getDeclaration());
                if (selfTypeArg.getDeclaration() instanceof ClassOrInterface) {
                    // first check if the type is inhabited or not
                    if (selfTypeArg.getDeclaration().inherits(declaration)) {
                        // "is SelfType<ClassOrInterface>" can be written "is ClassOrInterface" 
                        return makeTypeTest(typeTester, firstTimeExpr, varName, selfTypeArg, expressionType);
                    } else {
                        // always false, for example Comparable<Anything> is uninhabited because Anything does not inherit from Comparable
                        return typeTester.eval(varExpr, false);
                    }
                }
            // if not, keep trying
            }
            if (canOptimiseReifiedTypeTest(testedType)) {
                // Use an instanceof
                return typeTester.isInstanceof(varExpr, testedType, expressionType);
            } else {
                // Have to use a reified test
                if (!Decl.equal(declaration, expressionType.getDeclaration()) && canUseFastFailTypeTest(testedType)) {
                    // instanceof shortcircuit doesn't achieve anything
                    return typeTester.andOr(typeTester.isInstanceof(varExpr, testedType, expressionType), typeTester.isReified(varName.makeIdent(), testedType), JCTree.AND);
                } else {
                    return typeTester.isReified(varExpr, testedType);
                }
            }
        }
    } else if (typeFact().isUnion(testedType)) {
        for (Type pt : testedType.getCaseTypes()) {
            R partExpr = makeTypeTest(typeTester, firstTimeExpr, varName, pt, expressionType);
            firstTimeExpr = null;
            if (result == null) {
                result = partExpr;
            } else {
                result = typeTester.andOr(result, partExpr, JCTree.OR);
            }
        }
        return result;
    } else if (typeFact().isIntersection(testedType)) {
        for (Type pt : testedType.getSatisfiedTypes()) {
            R partExpr = makeTypeTest(typeTester, firstTimeExpr, varName, pt, expressionType);
            firstTimeExpr = null;
            if (result == null) {
                result = partExpr;
            } else {
                result = typeTester.andOr(result, partExpr, JCTree.AND);
            }
        }
        return result;
    } else if (testedType.isNothing()) {
        // nothing is Bottom
        JCExpression varExpr = firstTimeExpr != null ? firstTimeExpr : varName.makeIdent();
        return typeTester.eval(varExpr, false);
    } else if (declaration instanceof TypeParameter) {
        JCExpression varExpr = firstTimeExpr != null ? firstTimeExpr : varName.makeIdent();
        if (!reifiableUpperBounds((TypeParameter) declaration, expressionType).isEmpty()) {
            // If we're testing against a type parameter with  
            // class or interface upper bounds we can again shortcircuit the 
            // Util.isReified() using instanceof against the bounds
            result = typeTester.isReified(varName.makeIdent(), testedType);
            Iterator<Type> iterator = reifiableUpperBounds((TypeParameter) declaration, expressionType).iterator();
            while (iterator.hasNext()) {
                Type type = iterator.next();
                ClassOrInterface c = ((ClassOrInterface) type.resolveAliases().getDeclaration());
                result = typeTester.andOr(typeTester.isInstanceof(iterator.hasNext() ? varName.makeIdent() : varExpr, c.getType(), expressionType), result, JCTree.AND);
            }
            return result;
        } else {
            return typeTester.isReified(varExpr, testedType);
        }
    } else {
        throw BugException.unhandledDeclarationCase(declaration);
    }
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 33 with ClassOrInterface

use of com.redhat.ceylon.model.typechecker.model.ClassOrInterface in project ceylon-compiler by ceylon.

the class AbstractTransformer method getFirstRefinedDeclaration.

private TypedDeclaration getFirstRefinedDeclaration(TypedDeclaration decl) {
    if (decl.getContainer() instanceof ClassOrInterface == false)
        return decl;
    java.util.List<Type> signature = com.redhat.ceylon.model.typechecker.model.ModelUtil.getSignature(decl);
    boolean overloaded = decl.isOverloaded() || decl.isAbstraction();
    Declaration refinedDeclaration = decl.getRefinedDeclaration();
    if (refinedDeclaration != null) {
        overloaded |= refinedDeclaration.isOverloaded() || refinedDeclaration.isAbstraction();
    }
    ClassOrInterface container = (ClassOrInterface) decl.getContainer();
    HashSet<TypeDeclaration> visited = new HashSet<TypeDeclaration>();
    // start looking for it, but skip this type, only lookup upwards of it
    TypedDeclaration firstRefinedDeclaration = getFirstRefinedDeclaration(container, decl, signature, visited, true, overloaded);
    // only keep the first refined decl if its type can be trusted: if it is not itself widening
    if (firstRefinedDeclaration != null) {
        if (CodegenUtil.hasUntrustedType(firstRefinedDeclaration))
            firstRefinedDeclaration = getFirstRefinedDeclaration(firstRefinedDeclaration);
    }
    return firstRefinedDeclaration != null ? firstRefinedDeclaration : decl;
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Type(com.redhat.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) HashSet(java.util.HashSet)

Example 34 with ClassOrInterface

use of com.redhat.ceylon.model.typechecker.model.ClassOrInterface in project ceylon-compiler by ceylon.

the class AbstractTransformer method supportsReified.

public static boolean supportsReified(Declaration declaration) {
    if (declaration instanceof ClassOrInterface) {
        // Java constructors don't support reified type arguments
        return Decl.isCeylon((TypeDeclaration) declaration);
    } else if (Decl.isConstructor(declaration)) {
        // Java constructors don't support reified type arguments
        return Decl.isCeylon(Decl.getConstructor(declaration));
    } else if (declaration instanceof Function) {
        if (((Function) declaration).isParameter()) {
            // those can never be parameterised
            return false;
        }
        if (Decl.isToplevel(declaration))
            return true;
        // Java methods don't support reified type arguments
        Function m = (Function) CodegenUtil.getTopmostRefinedDeclaration(declaration);
        // See what its container is
        ClassOrInterface container = Decl.getClassOrInterfaceContainer(m);
        // that must be Ceylon so it supports it
        if (container == null)
            return true;
        return supportsReified(container);
    } else {
        throw BugException.unhandledDeclarationCase(declaration);
    }
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Function(com.redhat.ceylon.model.typechecker.model.Function)

Example 35 with ClassOrInterface

use of com.redhat.ceylon.model.typechecker.model.ClassOrInterface in project ceylon-compiler by ceylon.

the class ClassTransformer method makeCompanionInstanceAssignment.

/**
     * Returns the companion instances assignment expression used in the constructor,
     * e.g.
     * <pre>
     * this.$ceylon$language$Enumerable$this$ = new .ceylon.language.Enumerable$impl<.com.redhat.ceylon.compiler.java.test.structure.klass.SerializableEnumerable>(.com.redhat.ceylon.compiler.java.test.structure.klass.SerializableEnumerable.$TypeDescriptor$, this);
     * </pre>
     * @param classBuilder 
     * @return 
     */
private JCExpressionStatement makeCompanionInstanceAssignment(final Class model, final Interface iface, final Type satisfiedType) {
    final Type bestSatisfiedType = getBestSatisfiedType(model.getType(), iface);
    JCExpression containerInstance = null;
    if (!Decl.isToplevel(iface) && !Decl.isLocal(iface)) {
        // if it's a member type we need to qualify the new instance with its $impl container
        ClassOrInterface interfaceContainer = Decl.getClassOrInterfaceContainer(iface, false);
        if (interfaceContainer instanceof Interface) {
            ClassOrInterface modelContainer = model;
            // first try to find exactly the interface we are looking for
            while ((modelContainer = Decl.getClassOrInterfaceContainer(modelContainer, false)) != null && !modelContainer.equals(interfaceContainer)) {
            // keep searching
            }
            // then find one that inherits it
            if (modelContainer == null) {
                modelContainer = model;
                while ((modelContainer = Decl.getClassOrInterfaceContainer(modelContainer, false)) != null && modelContainer.getType().getSupertype(interfaceContainer) == null) {
                // keep searching
                }
            }
            if (modelContainer == null) {
                throw new BugException("Could not find container that satisfies interface " + iface.getQualifiedNameString() + " to find qualifying instance for companion instance for " + model.getQualifiedNameString());
            }
            // if it's an interface we just qualify it properly
            if (modelContainer instanceof Interface) {
                JCExpression containerType = makeJavaType(modelContainer.getType(), JT_COMPANION | JT_SATISFIES | JT_RAW);
                containerInstance = makeSelect(containerType, "this");
            } else {
                // it's a class: find the right field used for the interface container impl
                String containerFieldName = getCompanionFieldName((Interface) interfaceContainer);
                JCExpression containerType = makeJavaType(modelContainer.getType(), JT_SATISFIES);
                containerInstance = makeSelect(makeSelect(containerType, "this"), containerFieldName);
            }
        }
    }
    List<JCExpression> state = List.nil();
    // pass all reified type info to the constructor
    for (JCExpression t : makeReifiedTypeArguments(satisfiedType)) {
        state = state.append(t);
    }
    // pass the instance of this
    state = state.append(expressionGen().applyErasureAndBoxing(naming.makeThis(), model.getType(), false, true, BoxingStrategy.BOXED, bestSatisfiedType, ExpressionTransformer.EXPR_FOR_COMPANION));
    final JCExpression ifaceImplType;
    if (!Decl.isToplevel(iface) && !Decl.isLocal(iface) && Decl.getClassOrInterfaceContainer(iface, false) instanceof Interface) {
        ifaceImplType = makeJavaType(bestSatisfiedType, JT_COMPANION | JT_CLASS_NEW | JT_NON_QUALIFIED);
    } else {
        ifaceImplType = makeJavaType(bestSatisfiedType, JT_COMPANION | JT_CLASS_NEW);
    }
    JCExpression newInstance = make().NewClass(containerInstance, null, ifaceImplType, state, null);
    JCExpressionStatement companionInstanceAssign = make().Exec(make().Assign(// TODO Use qualified name for quoting? 
    makeSelect("this", getCompanionFieldName(iface)), newInstance));
    return companionInstanceAssign;
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCExpressionStatement(com.sun.tools.javac.tree.JCTree.JCExpressionStatement) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(com.redhat.ceylon.model.loader.model.LazyInterface) Interface(com.redhat.ceylon.model.typechecker.model.Interface)

Aggregations

ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)37 Type (com.redhat.ceylon.model.typechecker.model.Type)21 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)20 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)16 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)15 Interface (com.redhat.ceylon.model.typechecker.model.Interface)13 ModelUtil.appliedType (com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType)11 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)11 Class (com.redhat.ceylon.model.typechecker.model.Class)9 Package (com.redhat.ceylon.model.typechecker.model.Package)7 Scope (com.redhat.ceylon.model.typechecker.model.Scope)7 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)7 Function (com.redhat.ceylon.model.typechecker.model.Function)6 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)6 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)5 Constructor (com.redhat.ceylon.model.typechecker.model.Constructor)5 TypeAlias (com.redhat.ceylon.model.typechecker.model.TypeAlias)5 JCTree (com.sun.tools.javac.tree.JCTree)5 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)5 ArrayList (java.util.ArrayList)5