Search in sources :

Example 1 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class AbstractTransformer method makeTypeArgs.

private ListBuffer<JCExpression> makeTypeArgs(boolean isCeylonCallable, int flags, Map<TypeParameter, Type> tas, java.util.List<TypeParameter> tps, Type simpleType) {
    ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>();
    for (TypeParameter tp : tps) {
        Type ta = tas.get(tp);
        // error handling
        if (ta == null)
            continue;
        boolean isDependedOn = hasDependentTypeParameters(tps, tp);
        // record whether we were initially working with Anything, because getNonNullType turns it into Object
        // and we need to treat "in Anything" specially below
        boolean isAnything = isAnything(ta);
        // we want, so we make sure it's not Null
        if (isOptional(ta) && !isNull(ta)) {
            // For an optional type T?:
            // - The Ceylon type Foo<T?> results in the Java type Foo<T>.
            ta = getNonNullType(ta);
        }
        // In a type argument Foo<X&Object> or Foo<X?> transform to just Foo<X>
        ta = simplifyType(ta);
        if (typeFact().isUnion(ta) || typeFact().isIntersection(ta)) {
            // conform with where raw types would be used between expressions and constructors
            if (((flags & (JT_EXTENDS | JT_SATISFIES)) != 0 && tp.getSelfTypedDeclaration() != null)) {
                // A bit ugly, but we need to escape from the loop and create a raw type, no generics
                if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
                    throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
                typeArgs = null;
                break;
            } else if ((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) == 0) {
                if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
                    throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
                typeArgs = null;
                break;
            }
        // otherwise just go on
        }
        if (isCeylonBoolean(ta) && !isTypeParameter(ta)) {
            ta = typeFact.getBooleanType();
        }
        JCExpression jta;
        if (!tp.getSatisfiedTypes().isEmpty()) {
            boolean needsCastForBounds = false;
            for (Type bound : tp.getSatisfiedTypes()) {
                bound = bound.substitute(tas, null);
                needsCastForBounds |= expressionGen().needsCast(ta, bound, false, false, false);
            }
            if (needsCastForBounds) {
                // replace with the first bound
                ta = tp.getSatisfiedTypes().get(0).substitute(tas, null);
                if (tp.getSatisfiedTypes().size() > 1 || isBoundsSelfDependant(tp) || isBoundsRecursive(simpleType, tp) || willEraseToObject(ta) || // we should reject it for all non-covariant types, unless we're in satisfies/extends
                ((flags & (JT_SATISFIES | JT_EXTENDS)) == 0 && !simpleType.isCovariant(tp))) {
                    if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
                        throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
                    // A bit ugly, but we need to escape from the loop and create a raw type, no generics
                    typeArgs = null;
                    break;
                }
            }
        }
        if (ta.isExactlyNothing() || // use the same erasure rules as bottom: prefer wildcards
        ((flags & (__JT_FULL_TYPE | JT_EXTENDS | JT_SATISFIES)) != 0 && (typeFact().isUnion(ta) || typeFact().isIntersection(ta)))) {
            // For the bottom type Bottom:
            if ((flags & (JT_CLASS_NEW)) != 0) {
                // A bit ugly, but we need to escape from the loop and create a raw type, no generics
                if ((flags & (JT_EXTENDS | JT_SATISFIES)) != 0)
                    throw new BugException("rawSupertype() should prevent this method going raw when JT_EXTENDS | JT_SATISFIES");
                typeArgs = null;
                break;
            } else {
                // Foo<Object> (see https://github.com/ceylon/ceylon-compiler/issues/633 for why)
                if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
                    if (ta.isExactlyNothing()) {
                        jta = make().Type(syms().objectType);
                    } else {
                        if (!tp.getSatisfiedTypes().isEmpty()) {
                            // union or intersection: Use the common upper bound of the types
                            jta = makeJavaType(tp.getSatisfiedTypes().get(0), JT_TYPE_ARGUMENT);
                        } else {
                            jta = make().Type(syms().objectType);
                        }
                    }
                } else if (ta.isExactlyNothing()) {
                    // see https://github.com/ceylon/ceylon-compiler/issues/1003
                    if (simpleType.isContravariant(tp)) {
                        typeArgs = null;
                        break;
                    } else if (tp.isCovariant() && !isDependedOn) {
                        // DO NOT trust use-site covariance for Nothing, because we consider "out Nothing" to be the same
                        // as "Nothing". Only look at declaration-site covariance
                        jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), make().Type(syms().objectType));
                    } else {
                        jta = make().Type(syms().objectType);
                    }
                } else {
                    // see https://github.com/ceylon/ceylon/issues/6365
                    if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp)) /* && !isDependedOn*/
                    {
                        jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
                    } else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
                        jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
                    } else {
                        jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
                    }
                }
            }
        } else {
            // For an ordinary class or interface type T:
            if ((flags & (JT_SATISFIES | JT_EXTENDS)) != 0) {
                // - The Ceylon type Foo<T> appearing in an extends or satisfies clause
                // results in the Java type Foo<T>
                jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
            } else {
                // - Foo<? super T> if Foo is contravariant in T
                if (((flags & JT_CLASS_NEW) == 0) && simpleType.isContravariant(tp) && (!isAnything || tp.isContravariant())) // FIXME: it may be necessary to uncomment this in the future,
                // see https://github.com/ceylon/ceylon/issues/6365
                /*&& !isDependedOn*/
                {
                    // DO NOT trust use-site contravariance for Anything, because we consider "in Anything" to be the same
                    // as "Anything". Only look at declaration-site contravariance
                    jta = make().Wildcard(make().TypeBoundKind(BoundKind.SUPER), makeJavaType(ta, JT_TYPE_ARGUMENT));
                } else if (((flags & JT_CLASS_NEW) == 0) && simpleType.isCovariant(tp) && !isDependedOn) {
                    jta = make().Wildcard(make().TypeBoundKind(BoundKind.EXTENDS), makeJavaType(ta, JT_TYPE_ARGUMENT));
                } else {
                    jta = makeJavaType(ta, JT_TYPE_ARGUMENT);
                }
            }
        }
        typeArgs.add(jta);
        if (isCeylonCallable) {
            // In the runtime Callable only has a single type param
            break;
        }
    }
    return typeArgs;
}
Also used : 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) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)

Example 2 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class AbstractTransformer method makeAtLocalContainer.

protected List<JCAnnotation> makeAtLocalContainer(List<String> path, String companionClassName) {
    if (path.isEmpty())
        return List.nil();
    ListBuffer<JCExpression> array = new ListBuffer<JCTree.JCExpression>();
    for (String val : path) array.add(make().Literal(val));
    JCExpression pathAttr = make().Assign(naming.makeUnquotedIdent("path"), make().NewArray(null, null, array.toList()));
    JCExpression companionAttr = make().Assign(naming.makeUnquotedIdent("companionClassName"), make().Literal(companionClassName == null ? "" : companionClassName));
    return makeModelAnnotation(syms().ceylonAtLocalContainerType, List.of(pathAttr, companionAttr));
}
Also used : JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)

Example 3 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class AbstractTransformer method getLicenseAuthorsDocAnnotationArguments.

/**
 * Returns a ListBuffer with assignment expressions for the doc, license and by arguments, as well as name,
 * to be used in an annotation which requires them (such as Module and Package)
 */
ListBuffer<JCExpression> getLicenseAuthorsDocAnnotationArguments(String name, java.util.List<Annotation> anns) {
    ListBuffer<JCExpression> authors = new ListBuffer<JCTree.JCExpression>();
    ListBuffer<JCExpression> res = new ListBuffer<JCExpression>();
    res.add(make().Assign(naming.makeUnquotedIdent("name"), make().Literal(name)));
    for (Annotation a : anns) {
        if (a.getPositionalArguments() != null && !a.getPositionalArguments().isEmpty()) {
            if (a.getName().equals("doc")) {
                res.add(make().Assign(naming.makeUnquotedIdent("doc"), make().Literal(a.getPositionalArguments().get(0))));
            } else if (a.getName().equals("label")) {
                res.add(make().Assign(naming.makeUnquotedIdent("label"), make().Literal(a.getPositionalArguments().get(0))));
            } else if (a.getName().equals("license")) {
                res.add(make().Assign(naming.makeUnquotedIdent("license"), make().Literal(a.getPositionalArguments().get(0))));
            } else if (a.getName().equals("by")) {
                for (String author : a.getPositionalArguments()) {
                    authors.add(make().Literal(author));
                }
            }
        }
    }
    if (!authors.isEmpty()) {
        res.add(make().Assign(naming.makeUnquotedIdent("by"), make().NewArray(null, null, authors.toList())));
    }
    return res;
}
Also used : JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Annotation(org.eclipse.ceylon.model.typechecker.model.Annotation) JCAnnotation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation) LanguageAnnotation(org.eclipse.ceylon.model.loader.LanguageAnnotation)

Example 4 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer 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 5 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class AbstractTransformer method makeAtAnnotation.

private JCExpression makeAtAnnotation(Annotation annotation) {
    JCExpression valueAttribute = make().Assign(naming.makeUnquotedIdent("value"), make().Literal(annotation.getName()));
    List<JCExpression> attributes;
    if (!annotation.getPositionalArguments().isEmpty()) {
        java.util.List<String> positionalArguments = annotation.getPositionalArguments();
        ListBuffer<JCExpression> array = new ListBuffer<JCTree.JCExpression>();
        for (String val : positionalArguments) array.add(make().Literal(val));
        JCExpression argumentsAttribute = make().Assign(naming.makeUnquotedIdent("arguments"), make().NewArray(null, null, array.toList()));
        attributes = List.of(valueAttribute, argumentsAttribute);
    } else if (!annotation.getNamedArguments().isEmpty()) {
        Map<String, String> namedArguments = annotation.getNamedArguments();
        ListBuffer<JCExpression> array = new ListBuffer<JCTree.JCExpression>();
        for (Entry<String, String> entry : namedArguments.entrySet()) {
            JCExpression argNameAttribute = make().Assign(naming.makeUnquotedIdent("name"), make().Literal(entry.getKey()));
            JCExpression argValueAttribute = make().Assign(naming.makeUnquotedIdent("value"), make().Literal(entry.getValue()));
            JCAnnotation namedArg = make().Annotation(makeIdent(syms().ceylonAtNamedArgumentType), List.of(argNameAttribute, argValueAttribute));
            array.add(namedArg);
        }
        JCExpression argumentsAttribute = make().Assign(naming.makeUnquotedIdent("namedArguments"), make().NewArray(null, null, array.toList()));
        attributes = List.of(valueAttribute, argumentsAttribute);
    } else
        attributes = List.of(valueAttribute);
    return make().Annotation(makeIdent(syms().ceylonAtAnnotationType), attributes);
}
Also used : Entry(java.util.Map.Entry) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Map(java.util.Map) HashMap(java.util.HashMap) LineMap(org.eclipse.ceylon.langtools.tools.javac.util.Position.LineMap) JCAnnotation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)

Aggregations

ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)67 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)53 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)30 Type (org.eclipse.ceylon.model.typechecker.model.Type)23 JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)22 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)20 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)16 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)16 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)15 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)14 JCAnnotation (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)13 JCNewClass (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)12 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)12 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)11 Function (org.eclipse.ceylon.model.typechecker.model.Function)10 Class (org.eclipse.ceylon.model.typechecker.model.Class)9 JCTypeParameter (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter)8 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)8 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)8 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)7