Search in sources :

Example 1 with Declaration

use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.

the class AbstractTransformer method canOptimiseReifiedTypeTest.

/**
 * Determine whether we can use a plain {@code instanceof} instead of
 * a full {@code Util.isReified()} for a {@code is} test
 */
private boolean canOptimiseReifiedTypeTest(Type type) {
    if (isJavaArray(type)) {
        if (isJavaObjectArray(type)) {
            MultidimensionalArray multiArray = getMultiDimensionalArrayInfo(type);
            // we can test, even if not fully reified in Java
            return multiArray.type.getDeclaration() instanceof ClassOrInterface;
        } else {
            // primitive array we can test
            return true;
        }
    }
    // we can optimise it if we've got a ClassOrInterface with only Anything type parameters
    TypeDeclaration typeDeclaration = type.getDeclaration();
    if (typeDeclaration instanceof ClassOrInterface == false)
        return false;
    for (Entry<TypeParameter, Type> entry : type.getTypeArguments().entrySet()) {
        TypeParameter tp = entry.getKey();
        // skip type params for qualifying types
        if (!tp.getDeclaration().equals(typeDeclaration))
            continue;
        if (!type.isCovariant(tp)) {
            return false;
        }
        java.util.List<Type> bounds = tp.getSatisfiedTypes();
        Type ta = entry.getValue();
        if ((bounds == null || bounds.isEmpty()) && !isAnything(ta)) {
            return false;
        }
        for (Type bound : bounds) {
            if (!ta.isSupertypeOf(bound)) {
                return false;
            }
        }
    }
    // they're all Anything (or supertypes of their upper bound) we can optimise, unless we have a container with type arguments
    Type qualifyingType = type.getQualifyingType();
    if (qualifyingType == null && // ignore qualifying types of static java declarations
    (ModelUtil.isCeylonDeclaration(type.getDeclaration()) || !type.getDeclaration().isStatic())) {
        Declaration declaration = type.getDeclaration();
        do {
            // it may be contained in a function or value, and we want its type
            Declaration enclosingDeclaration = getDeclarationContainer(declaration);
            if (enclosingDeclaration instanceof TypedDeclaration) {
                // must be in scope
                if (enclosingDeclaration.isParameterized())
                    return false;
                // look up the containers
                declaration = enclosingDeclaration;
            } else if (enclosingDeclaration instanceof TypeDeclaration) {
                // we can't optimise if that container has type arguments as they are not provided
                if (enclosingDeclaration.isParameterized())
                    return false;
                // look up the containers
                declaration = enclosingDeclaration;
            } else {
                // that's fucked up
                break;
            }
        // go up every containing typed declaration
        } while (declaration != null);
        // we can optimise!
        return true;
    } else if (qualifyingType != null) {
        // we can only optimise if the qualifying type can also be optimised
        return canOptimiseReifiedTypeTest(qualifyingType);
    } else {
        // we can optimise!
        return true;
    }
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 2 with Declaration

use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.

the class AbstractTransformer method getFirstRefinedDeclaration.

private TypedDeclaration getFirstRefinedDeclaration(TypedDeclaration decl) {
    if (decl.getContainer() instanceof ClassOrInterface == false)
        return decl;
    java.util.List<Type> signature = org.eclipse.ceylon.model.typechecker.model.ModelUtil.getSignature(decl);
    boolean variadic = org.eclipse.ceylon.model.typechecker.model.ModelUtil.isVariadic(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, variadic, 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(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) HashSet(java.util.HashSet)

Example 3 with Declaration

use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.

the class AbstractTransformer method makeReifiedTypeArgumentResolved.

private JCExpression makeReifiedTypeArgumentResolved(Type pt, boolean qualified, TypeArgumentAccessor typeArgumentAccessor, boolean wantsRaw) {
    if (pt.isUnion()) {
        // FIXME: refactor this shite
        List<JCExpression> typeTestArguments = List.nil();
        java.util.List<Type> typeParameters = pt.getCaseTypes();
        if (typeParameters.size() == 2) {
            Type alternative = null;
            if (typeParameters.get(0).isEmpty())
                alternative = typeParameters.get(1);
            else if (typeParameters.get(1).isEmpty())
                alternative = typeParameters.get(0);
            if (alternative != null && alternative.isTuple()) {
                JCExpression tupleType = makeTupleTypeDescriptor(alternative, true);
                if (tupleType != null)
                    return tupleType;
            }
        }
        for (int i = typeParameters.size() - 1; i >= 0; i--) {
            typeTestArguments = typeTestArguments.prepend(makeReifiedTypeArgument(typeParameters.get(i)));
        }
        return make().Apply(null, makeSelect(makeTypeDescriptorType(), "union"), typeTestArguments);
    } else if (pt.isIntersection()) {
        List<JCExpression> typeTestArguments = List.nil();
        java.util.List<Type> typeParameters = pt.getSatisfiedTypes();
        for (int i = typeParameters.size() - 1; i >= 0; i--) {
            typeTestArguments = typeTestArguments.prepend(makeReifiedTypeArgument(typeParameters.get(i)));
        }
        return make().Apply(null, makeSelect(makeTypeDescriptorType(), "intersection"), typeTestArguments);
    } else if (pt.isNothing()) {
        return makeNothingTypeDescriptor();
    }
    TypeDeclaration declaration = pt.getDeclaration();
    if (declaration instanceof Constructor) {
        pt = pt.getExtendedType();
        declaration = pt.getDeclaration();
    }
    if (pt.isClassOrInterface()) {
        // see if we have an alias for it
        if (supportsReifiedAlias((ClassOrInterface) declaration)) {
            JCExpression qualifier = naming.makeDeclarationName(declaration, DeclNameFlag.QUALIFIED);
            return makeSelect(qualifier, naming.getTypeDescriptorAliasName());
        }
        if (pt.isTuple()) {
            JCExpression tupleType = makeTupleTypeDescriptor(pt, false);
            if (tupleType != null)
                return tupleType;
        }
        // no alias, must build it
        List<JCExpression> typeTestArguments;
        JCExpression thisType = makeUnerasedClassLiteral(declaration);
        if (!wantsRaw) {
            typeTestArguments = makeReifiedTypeArgumentsResolved(pt.getTypeArgumentList(), qualified, typeArgumentAccessor);
            // do we have variance overrides?
            Map<TypeParameter, SiteVariance> varianceOverrides = pt.getVarianceOverrides();
            if (!varianceOverrides.isEmpty()) {
                // we need to pass them as second argument then, in an array
                ListBuffer<JCExpression> varianceElements = new ListBuffer<JCExpression>();
                for (TypeParameter typeParameter : declaration.getTypeParameters()) {
                    SiteVariance useSiteVariance = varianceOverrides.get(typeParameter);
                    String selector;
                    if (useSiteVariance != null) {
                        switch(useSiteVariance) {
                            case IN:
                                selector = "IN";
                                break;
                            case OUT:
                                selector = "OUT";
                                break;
                            default:
                                selector = "NONE";
                                break;
                        }
                    } else {
                        selector = "NONE";
                    }
                    JCExpression varianceElement = make().Select(makeIdent(syms().ceylonVarianceType), names().fromString(selector));
                    varianceElements.append(varianceElement);
                }
                JCNewArray varianceArray = make().NewArray(makeIdent(syms().ceylonVarianceType), List.<JCExpression>nil(), varianceElements.toList());
                typeTestArguments = typeTestArguments.prepend(varianceArray);
            }
        } else {
            typeTestArguments = List.nil();
        }
        typeTestArguments = typeTestArguments.prepend(thisType);
        JCExpression classDescriptor = make().Apply(null, makeSelect(makeTypeDescriptorType(), "klass"), typeTestArguments);
        Type qualifyingType = pt.getQualifyingType();
        JCExpression containerType = null;
        if (qualifyingType == null) {
            // it may be contained in a function or value, and we want its type
            // or static class members may have no qualifying type but we want the TDs to treat
            // them as members anyway
            Declaration enclosingDeclaration = getDeclarationContainer(declaration);
            if (enclosingDeclaration instanceof TypedDeclaration)
                containerType = makeTypedDeclarationTypeDescriptorResolved((TypedDeclaration) enclosingDeclaration, typeArgumentAccessor);
            else if (enclosingDeclaration instanceof TypeDeclaration) {
                qualifyingType = ((TypeDeclaration) enclosingDeclaration).getType();
            }
        }
        if (qualifyingType != null && qualifyingType.isConstructor()) {
            qualifyingType = qualifyingType.getQualifyingType();
        }
        if (qualifyingType != null) {
            if (declaration.isStatic() && supportsReified(declaration)) {
                // There is no outer instance with a $reified$T field
                final Type t = pt;
                containerType = makeReifiedTypeArgumentResolved(qualifyingType, true, new TypeArgumentAccessor() {

                    public JCExpression getTypeDescriptor(TypeParameter tp, boolean qualified) {
                        return makeSelect(naming.makeQualifiedThis(makeJavaType(t, JT_RAW)), naming.getTypeArgumentDescriptorName(tp));
                    }
                }, false);
            } else {
                containerType = makeReifiedTypeArgumentResolved(qualifyingType, true, typeArgumentAccessor, // we want raw containers, since we can't capture their TPs
                declaration.isStatic());
            }
        }
        if (containerType == null) {
            return classDescriptor;
        } else {
            return make().Apply(null, makeSelect(makeTypeDescriptorType(), "member"), List.of(containerType, classDescriptor));
        }
    } else if (pt.isTypeParameter()) {
        return typeArgumentAccessor.getTypeDescriptor((TypeParameter) declaration, qualified);
    } else {
        throw BugException.unhandledDeclarationCase(declaration);
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) SiteVariance(org.eclipse.ceylon.model.typechecker.model.SiteVariance) ArrayList(java.util.ArrayList) List(org.eclipse.ceylon.langtools.tools.javac.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) LinkedList(java.util.LinkedList) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) JCNewArray(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewArray)

Example 4 with Declaration

use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.

the class AbstractTransformer method canUseFastFailTypeTest.

private boolean canUseFastFailTypeTest(Type type) {
    if (type.getDeclaration() instanceof ClassOrInterface == false)
        return false;
    boolean isRaw = type.getDeclaration().isParameterized();
    Type qualifyingType = type.getQualifyingType();
    if (qualifyingType == null && // ignore qualifying types of static java declarations
    (ModelUtil.isCeylonDeclaration(type.getDeclaration()) || !type.getDeclaration().isStatic())) {
        Declaration declaration = type.getDeclaration();
        boolean local = false;
        do {
            // getDeclarationContainer will skip some containers we don't want to consider, so it's not good
            // for checking locality, rely on isLocal for that.
            local |= Decl.isLocal(declaration);
            // it may be contained in a function or value, and we want its type
            Declaration enclosingDeclaration = getDeclarationContainer(declaration);
            if (enclosingDeclaration instanceof TypedDeclaration) {
                local = true;
                // look up the containers
                declaration = enclosingDeclaration;
            } else if (enclosingDeclaration instanceof TypeDeclaration) {
                // contain type parameters, unless the local is raw
                if (enclosingDeclaration.isParameterized() && local && !isRaw)
                    return false;
                // look up the containers
                declaration = enclosingDeclaration;
            } else {
                // that's fucked up
                break;
            }
        // go up every containing typed declaration
        } while (declaration != null);
        // we can fast-fail!
        return true;
    } else if (qualifyingType != null) {
        // we can only fast-fail if the qualifying type can also be fast-failed
        return canUseFastFailTypeTest(qualifyingType);
    } else {
        // we can fast-fail!
        return true;
    }
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Example 5 with Declaration

use of org.eclipse.ceylon.model.typechecker.model.Declaration in project ceylon by eclipse.

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 = 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(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Reference(org.eclipse.ceylon.model.typechecker.model.Reference) LinkedList(java.util.LinkedList) Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) ModelUtil.appliedType(org.eclipse.ceylon.model.typechecker.model.ModelUtil.appliedType) Scope(org.eclipse.ceylon.model.typechecker.model.Scope) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Package(org.eclipse.ceylon.model.typechecker.model.Package) HashSet(java.util.HashSet)

Aggregations

Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)370 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)309 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)264 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)129 Type (org.eclipse.ceylon.model.typechecker.model.Type)100 Class (org.eclipse.ceylon.model.typechecker.model.Class)78 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)74 Value (org.eclipse.ceylon.model.typechecker.model.Value)73 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)72 Function (org.eclipse.ceylon.model.typechecker.model.Function)71 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)71 AnalyzerUtil.getTypedDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTypedDeclaration)63 ArrayList (java.util.ArrayList)61 AnalyzerUtil.getPackageTypeDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getPackageTypeDeclaration)60 AnalyzerUtil.getTypeDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getTypeDeclaration)60 ModelUtil.getNativeDeclaration (org.eclipse.ceylon.model.typechecker.model.ModelUtil.getNativeDeclaration)57 AnalyzerUtil.getPackageTypedDeclaration (org.eclipse.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.getPackageTypedDeclaration)51 Scope (org.eclipse.ceylon.model.typechecker.model.Scope)50 Constructor (org.eclipse.ceylon.model.typechecker.model.Constructor)48 CustomTree (org.eclipse.ceylon.compiler.typechecker.tree.CustomTree)45