Search in sources :

Example 21 with Type

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

the class ExpressionTransformer method transformVariadicArgument.

private ExpressionAndType transformVariadicArgument(SimpleInvocation invocation, int numArguments, int argIndex, Type parameterType) {
    ExpressionAndType exprAndType;
    final Type iteratedType = typeFact().getIteratedType(parameterType);
    final JCExpression expr;
    final JCExpression type;
    // invoking f(a, b, c), where declared f(A a, B* b)
    // collect each remaining argument and box with an ArraySequence<T>
    List<JCExpression> x = List.<JCExpression>nil();
    for (int ii = argIndex; ii < numArguments; ii++) {
        x = x.append(invocation.getTransformedArgumentExpression(ii));
    }
    expr = makeSequence(x, iteratedType, JT_TYPE_ARGUMENT);
    type = makeJavaType(typeFact().getSequenceType(iteratedType).getType());
    exprAndType = new ExpressionAndType(expr, type);
    return exprAndType;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression)

Example 22 with Type

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

the class ExpressionTransformer method applyJavaTypeConversions.

private JCExpression applyJavaTypeConversions(JCExpression ret, Type exprType, Type expectedType, BoxingStrategy boxingStrategy, boolean exprBoxed, int flags) {
    if (exprType == null || boxingStrategy != BoxingStrategy.UNBOXED)
        return ret;
    Type definiteExprType = simplifyType(exprType);
    if (definiteExprType == null)
        return ret;
    // ignore the underlying type of the expr type if it was boxed, since we must have unboxed it to
    // something with no underlying type first
    String convertFrom = exprBoxed ? null : definiteExprType.getUnderlyingType();
    Type definiteExpectedType = null;
    String convertTo = null;
    if (expectedType != null) {
        definiteExpectedType = simplifyType(expectedType);
        convertTo = definiteExpectedType.getUnderlyingType();
    }
    // check for identity conversion
    if (convertFrom != null && convertFrom.equals(convertTo)) {
        return ret;
    }
    if (isCeylonByte(definiteExpectedType) && isCeylonInteger(exprType)) {
        if ((flags & EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK) == 0) {
            if (ret instanceof JCTree.JCUnary) {
                JCTree.JCUnary unary = (JCTree.JCUnary) ret;
                if (unary.getTag() == JCTree.NEG && unary.arg instanceof JCTree.JCLiteral) {
                    Object value = ((JCTree.JCLiteral) unary.arg).value;
                    if (value instanceof Integer) {
                        int val = (Integer) value;
                        // if it fits let's just leave it
                        if (val >= 0 && val <= -Byte.MIN_VALUE) {
                            // assignment, not for method calls, so it's simpler to always cast
                            return make().TypeCast(syms().byteType, ret);
                        }
                    }
                }
            }
        }
        ret = make().TypeCast(syms().byteType, ret);
    } else {
        if (convertTo != null) {
            if (convertTo.equals("short")) {
                if ((flags & EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK) == 0) {
                    ret = utilInvocation().toShort(ret);
                } else {
                    ret = make().TypeCast(syms().shortType, ret);
                }
            } else if (convertTo.equals("int")) {
                if ((flags & EXPR_UNSAFE_PRIMITIVE_TYPECAST_OK) == 0) {
                    ret = utilInvocation().toInt(ret);
                } else {
                    ret = make().TypeCast(syms().intType, ret);
                }
            } else if (convertTo.equals("float")) {
                ret = make().TypeCast(syms().floatType, ret);
            } else if (convertTo.equals("char")) {
                ret = make().TypeCast(syms().charType, ret);
            }
        } else if (convertFrom != null && (flags & EXPR_WIDEN_PRIM) != 0) {
            if (isCeylonInteger(exprType) && (convertFrom.equals("int") || convertFrom.equals("short") || convertFrom.equals("byte"))) {
                ret = make().TypeCast(syms().longType, ret);
            } else if (isCeylonFloat(exprType) && convertFrom.equals("float")) {
                ret = make().TypeCast(syms().doubleType, ret);
            }
        }
    }
    return ret;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCUnary(com.sun.tools.javac.tree.JCTree.JCUnary) JCUnary(com.sun.tools.javac.tree.JCTree.JCUnary) JCLiteral(com.sun.tools.javac.tree.JCTree.JCLiteral) JCTree(com.sun.tools.javac.tree.JCTree) JCLiteral(com.sun.tools.javac.tree.JCTree.JCLiteral)

Example 23 with Type

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

the class ExpressionTransformer method transform.

public JCTree transform(Tree.Exists op) {
    // for the purpose of checking if something is null, we need it boxed and optional, otherwise
    // for some Java calls if we consider it non-optional we will get an unwanted null check
    Type termType = op.getTerm().getTypeModel();
    if (!typeFact().isOptionalType(termType)) {
        termType = typeFact().getOptionalType(termType);
    }
    JCExpression expression = transformExpression(op.getTerm(), BoxingStrategy.BOXED, termType);
    at(op);
    return make().Binary(JCTree.NE, expression, makeNull());
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression)

Example 24 with Type

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

the class ExpressionTransformer method transform.

// Postfix operator
public JCExpression transform(Tree.PostfixOperatorExpression expr) {
    OperatorTranslation operator = Operators.getOperator(expr.getClass());
    if (operator == null) {
        return makeErroneous(expr, "compiler bug " + expr.getNodeType() + " is not yet supported");
    }
    OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
    boolean canOptimise = optimisationStrategy.useJavaOperator();
    // only fully optimise if we don't have to access the getter/setter
    if (canOptimise && CodegenUtil.isDirectAccessVariable(expr.getTerm())) {
        JCExpression term = transformExpression(expr.getTerm(), BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
        return at(expr).Unary(operator.javacOperator, term);
    }
    Tree.Term term = unwrapExpressionUntilTerm(expr.getTerm());
    Interface compoundType = expr.getUnit().getOrdinalDeclaration();
    Type valueType = getSupertype(expr.getTerm(), compoundType);
    Type returnType = getMostPreciseType(term, getTypeArgument(valueType, 0));
    List<JCVariableDecl> decls = List.nil();
    List<JCStatement> stats = List.nil();
    JCExpression result = null;
    // we can optimise that case a bit sometimes
    boolean boxResult = !canOptimise;
    // (let $tmp = attr; attr = $tmp.getSuccessor(); $tmp;)
    if (term instanceof Tree.BaseMemberExpression || // special case for java statics Foo.attr where Foo does not need to be evaluated
    (term instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) term).getStaticMethodReference())) {
        JCExpression getter;
        if (term instanceof Tree.BaseMemberExpression)
            getter = transform((Tree.BaseMemberExpression) term, null);
        else
            getter = transformMemberExpression((Tree.QualifiedMemberExpression) term, null, null);
        at(expr);
        // Type $tmp = attr
        JCExpression exprType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
        Name varName = naming.tempName("op");
        // make sure we box the results if necessary
        getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
        JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, getter);
        decls = decls.prepend(tmpVar);
        // attr = $tmp.getSuccessor()
        JCExpression successor;
        if (canOptimise) {
            // use +1/-1 if we can optimise a bit
            successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varName), makeInteger(1));
            successor = unAutoPromote(successor, returnType);
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varName), operator.ceylonMethod), List.<JCExpression>nil());
            // make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
            successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
        }
        JCExpression assignment = transformAssignment(expr, term, successor);
        stats = stats.prepend(at(expr).Exec(assignment));
        // $tmp
        result = make().Ident(varName);
    } else if (term instanceof Tree.QualifiedMemberExpression) {
        // e.attr++
        // (let $tmpE = e, $tmpV = $tmpE.attr; $tmpE.attr = $tmpV.getSuccessor(); $tmpV;)
        Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
        boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
        boolean isPackage = isPackageQualified(qualified);
        // transform the primary, this will get us a boxed primary 
        JCExpression e = transformQualifiedMemberPrimary(qualified);
        at(expr);
        // Type $tmpE = e
        JCExpression exprType = makeJavaType(qualified.getTarget().getQualifyingType(), JT_NO_PRIMITIVES);
        Name varEName = naming.tempName("opE");
        JCVariableDecl tmpEVar = make().VarDef(make().Modifiers(0), varEName, exprType, e);
        // Type $tmpV = $tmpE.attr
        JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
        Name varVName = naming.tempName("opV");
        JCExpression getter;
        if (isSuper) {
            getter = transformMemberExpression(qualified, transformSuper(qualified), null);
        } else if (isPackage) {
            getter = transformMemberExpression(qualified, null, null);
        } else {
            getter = transformMemberExpression(qualified, make().Ident(varEName), null);
        }
        // make sure we box the results if necessary
        getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
        JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, getter);
        decls = decls.prepend(tmpVVar);
        if (!isSuper && !isPackage) {
            // define all the variables
            decls = decls.prepend(tmpEVar);
        }
        // $tmpE.attr = $tmpV.getSuccessor()
        JCExpression successor;
        if (canOptimise) {
            // use +1/-1 if we can optimise a bit
            successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.PLUS : JCTree.MINUS, make().Ident(varVName), makeInteger(1));
            successor = unAutoPromote(successor, returnType);
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.ceylonMethod), List.<JCExpression>nil());
            //  make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
            successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
        }
        JCExpression assignment = transformAssignment(expr, term, isSuper ? transformSuper(qualified) : make().Ident(varEName), successor);
        stats = stats.prepend(at(expr).Exec(assignment));
        // $tmpV
        result = make().Ident(varVName);
    } else {
        return makeErroneous(term, "compiler bug: " + term.getNodeType() + " is not supported yet");
    }
    return make().LetExpr(decls, stats, result);
}
Also used : Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) Name(com.sun.tools.javac.util.Name) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(com.redhat.ceylon.compiler.java.codegen.Operators.OptimisationStrategy) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 25 with Type

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

the class ExpressionTransformer method transformOverridableBinaryOperator.

private JCExpression transformOverridableBinaryOperator(OperatorTranslation originalOperator, OptimisationStrategy optimisationStrategy, JCExpression left, JCExpression right, Tree.Term leftTerm, Type leftType, Tree.Term rightTerm, Type expectedType) {
    JCExpression result = null;
    // optimise if we can
    if (optimisationStrategy.useJavaOperator()) {
        result = make().Binary(originalOperator.javacOperator, left, right);
        if (rightTerm != null) {
            result = unAutoPromote(result, expectedType);
        }
        return result;
    }
    boolean loseComparison = originalOperator == OperatorTranslation.BINARY_SMALLER || originalOperator == OperatorTranslation.BINARY_SMALL_AS || originalOperator == OperatorTranslation.BINARY_LARGER || originalOperator == OperatorTranslation.BINARY_LARGE_AS;
    // for comparisons we need to invoke compare()
    OperatorTranslation actualOperator = originalOperator;
    if (loseComparison) {
        actualOperator = Operators.OperatorTranslation.BINARY_COMPARE;
    }
    List<JCExpression> args = List.of(right);
    List<JCExpression> typeArgs = null;
    // Set operators need reified generics
    if (originalOperator == OperatorTranslation.BINARY_UNION || originalOperator == OperatorTranslation.BINARY_INTERSECTION || originalOperator == OperatorTranslation.BINARY_COMPLEMENT) {
        Type otherSetElementType = typeFact().getIteratedType(rightTerm.getTypeModel());
        args = args.prepend(makeReifiedTypeArgument(otherSetElementType));
        typeArgs = List.<JCExpression>of(makeJavaType(otherSetElementType, JT_TYPE_ARGUMENT));
    }
    if (optimisationStrategy.useValueTypeMethod()) {
        int flags = JT_NO_PRIMITIVES;
        if (optimisationStrategy == OptimisationStrategy.OPTIMISE_VALUE_TYPE && leftType.getDeclaration().getSelfType() != null) {
            leftType = leftType.getTypeArguments().get(leftType.getDeclaration().getSelfType().getDeclaration());
        }
        result = make().Apply(typeArgs, naming.makeQualIdent(makeJavaType(leftType, flags), actualOperator.ceylonMethod), args.prepend(left));
    } else {
        if ((originalOperator == OperatorTranslation.BINARY_LARGE_AS || originalOperator == OperatorTranslation.BINARY_LARGER || originalOperator == OperatorTranslation.BINARY_SMALL_AS || originalOperator == OperatorTranslation.BINARY_SMALLER || originalOperator == OperatorTranslation.BINARY_COMPARE) && willEraseToObject(leftType)) {
            left = make().TypeCast(makeJavaType(typeFact().getComparableDeclaration().getType(), JT_RAW), left);
            args = List.<JCExpression>of(make().TypeCast(makeJavaType(typeFact().getComparableDeclaration().getType(), JT_RAW), right));
        }
        result = make().Apply(typeArgs, makeSelect(left, actualOperator.ceylonMethod), args);
    }
    if (loseComparison) {
        // We cheat slightly bu using == instead of equals, but since those values
        // don't override equals the effect is the same
        result = make().Binary(originalOperator.javacValueOperator, result, makeLanguageValue(originalOperator.ceylonValue));
    }
    return result;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) AssignmentOperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) OperatorTranslation(com.redhat.ceylon.compiler.java.codegen.Operators.OperatorTranslation)

Aggregations

Type (com.redhat.ceylon.model.typechecker.model.Type)237 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)98 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)87 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)56 JCTree (com.sun.tools.javac.tree.JCTree)53 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)51 ModelUtil.appliedType (com.redhat.ceylon.model.typechecker.model.ModelUtil.appliedType)46 Class (com.redhat.ceylon.model.typechecker.model.Class)45 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)43 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)41 IntersectionType (com.redhat.ceylon.model.typechecker.model.IntersectionType)37 UnionType (com.redhat.ceylon.model.typechecker.model.UnionType)37 Test (org.junit.Test)37 TypeParser (com.redhat.ceylon.model.loader.TypeParser)36 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)34 Function (com.redhat.ceylon.model.typechecker.model.Function)33 Interface (com.redhat.ceylon.model.typechecker.model.Interface)30 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)30 TypedReference (com.redhat.ceylon.model.typechecker.model.TypedReference)29 ArrayList (java.util.ArrayList)28