Search in sources :

Example 76 with JCExpression

use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.

the class ExpressionTransformer method transform.

public JCExpression transform(Tree.IsOp op) {
    // make sure we do not insert null checks if we're going to allow testing for null
    Type expectedType = getOptionalTypeForInteropIfAllowed(op.getType().getTypeModel(), op.getTerm().getTypeModel(), op.getTerm());
    // we don't need any erasure type cast for an "is" test
    JCExpression expression = transformExpression(op.getTerm(), BoxingStrategy.BOXED, expectedType);
    at(op);
    Naming.SyntheticName varName = naming.temp();
    JCExpression test = makeOptimizedTypeTest(null, varName, op.getType().getTypeModel(), op.getTerm().getTypeModel());
    return makeLetExpr(varName, List.<JCStatement>nil(), make().Type(syms().objectType), expression, test);
}
Also used : UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)

Example 77 with JCExpression

use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.

the class ExpressionTransformer method applyErasureAndBoxing.

JCExpression applyErasureAndBoxing(JCExpression result, Type exprType, boolean exprErased, boolean exprBoxed, boolean exprUntrustedType, boolean exprSmall, BoxingStrategy boxingStrategy, Type expectedType, int flags) {
    if (exprType != null)
        exprType = exprType.resolveAliases();
    if (expectedType != null)
        expectedType = expectedType.resolveAliases();
    boolean canCast = false;
    boolean coerced = (flags & EXPR_IS_COERCED) != 0;
    if (expectedType != null && // don't cast if we're coercing
    !coerced && // don't add cast to an erased type
    !willEraseToObject(expectedType)) {
        // only try to cast boxed types, no point otherwise
        if (exprBoxed) {
            boolean expectedTypeIsNotRaw = (flags & EXPR_EXPECTED_TYPE_NOT_RAW) != 0;
            boolean expectedTypeHasConstrainedTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_CONSTRAINED_TYPE_PARAMETERS) != 0;
            boolean expectedTypeHasDependentCovariantTypeParameters = (flags & EXPR_EXPECTED_TYPE_HAS_DEPENDENT_COVARIANT_TYPE_PARAMETERS) != 0;
            boolean downCast = (flags & EXPR_DOWN_CAST) != 0;
            boolean forceCast = (flags & EXPR_FORCE_CAST) != 0;
            int companionFlags = (flags & EXPR_WANTS_COMPANION) != 0 ? AbstractTransformer.JT_COMPANION : 0;
            // special case for returning Null expressions
            if (isNull(exprType)) {
                // don't add cast for null
                if (!isNullValue(exprType) || // temp vars whose type erase to Object
                (flags & EXPR_IS_NOT_BASE_MEMBER) != 0 || // of different types using the "of" operator
                downCast || // also add casts if we really want them
                forceCast) {
                    // in some cases we may have an instance of Null, which is of type java.lang.Object, being
                    // returned in a context where we expect a String? (aka ceylon.language.String) so even though
                    // the instance at hand will really be null, we need a up-cast to it
                    JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_RAW | companionFlags);
                    result = make().TypeCast(targetType, result);
                }
            } else if (exprType.isExactlyNothing()) {
                // type param erasure
                JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_NO_PRIMITIVES | companionFlags);
                result = make().TypeCast(make().QualIdent(syms().objectType.tsym), result);
                result = make().TypeCast(targetType, result);
            } else if (// expression was forcibly erased
            exprErased || // we want to cast
            forceCast || // bounds that are different from what we think the expression type should be
            exprUntrustedType || // see https://github.com/ceylon/ceylon-compiler/issues/1557
            expectedTypeHasDependentCovariantTypeParameters || // some type parameter somewhere needs a cast
            needsCast(exprType, expectedType, expectedTypeIsNotRaw, expectedTypeHasConstrainedTypeParameters, downCast) || // if the exprType is raw and the expected type isn't
            (exprType.isRaw() && (expectedTypeIsNotRaw || !isTurnedToRaw(expectedType)))) {
                // save this before we simplify it because we lose that flag doing so
                boolean exprIsRaw = exprType.isRaw();
                boolean expectedTypeIsRaw = isTurnedToRaw(expectedType) && !expectedTypeIsNotRaw;
                // (unless the other type is already raw)
                if ((!exprIsRaw && hasTypeParameters(expectedType)) || (downCast && !expectedTypeIsRaw && hasTypeParameters(exprType))) {
                    Type rawType = hasTypeParameters(expectedType) ? expectedType : exprType;
                    JCExpression rawTypeExpr = makeJavaType(rawType, AbstractTransformer.JT_TYPE_ARGUMENT | AbstractTransformer.JT_RAW | companionFlags);
                    result = make().TypeCast(rawTypeExpr, result);
                    // expr is now raw
                    exprIsRaw = true;
                    // let's not add another downcast if we got a cast: one is enough
                    downCast = false;
                    // same for forced erasure
                    exprErased = false;
                    exprUntrustedType = false;
                }
                // simplify the type
                // (without the underlying type, because the cast is always to a non-primitive)
                boolean wasOptional = isOptional(expectedType);
                exprType = simplifyType(expectedType).withoutUnderlyingType();
                // if the expected type was optional, respect that otherwise it fubars boxing
                if (wasOptional) {
                    exprType = typeFact().getOptionalType(exprType);
                }
                // if the expr is not raw, we need a cast
                // if the expr is raw:
                // don't even try making an actual cast if there are bounded type parameters in play, because going raw is much safer
                // also don't try making the cast if the expected type is raw because anything goes
                boolean needsTypedCast = !exprIsRaw || (!expectedTypeHasConstrainedTypeParameters && !expectedTypeHasDependentCovariantTypeParameters && !expectedTypeIsRaw);
                if (needsTypedCast || // make sure that downcasts get at least one cast
                downCast || // same for forced erasure
                exprUntrustedType) {
                    // it figures out that there's no intersection between the two types, but we know better
                    if (exprUntrustedType && !exprIsRaw) {
                        result = make().TypeCast(syms().objectType, result);
                    }
                    // Do the actual cast
                    JCExpression targetType = makeJavaType(expectedType, AbstractTransformer.JT_TYPE_ARGUMENT | companionFlags);
                    result = make().TypeCast(targetType, result);
                }
            } else
                canCast = true;
        } else
            canCast = true;
    }
    // If expr type if Self<T> and expected type is T we need to cast before any unboxing
    if (exprType.getDeclaration().getSelfType() != null && expectedType != null && expectedType.isExactly(exprType.getTypeArguments().get(exprType.getDeclaration().getSelfType().getDeclaration()))) {
        result = applySelfTypeCasts(result, exprType, exprBoxed, BoxingStrategy.BOXED, expectedType);
        exprType = expectedType;
    }
    // we must do the boxing after the cast to the proper type
    JCExpression ret = boxUnboxIfNecessary(result, exprBoxed ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, exprType, boxingStrategy, expectedType);
    // very special case for nothing that we need to "unbox" to a primitive type
    if (exprType != null && exprType.isExactlyNothing() && boxingStrategy == BoxingStrategy.UNBOXED) {
        // in this case we have to use the expected type
        ret = unboxType(ret, expectedType);
    }
    // now check if we need variance casts
    if (canCast) {
        ret = applyVarianceCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType, flags);
    }
    ret = applySelfTypeCasts(ret, exprType, exprBoxed, boxingStrategy, expectedType);
    ret = applyJavaTypeConversions(ret, exprType, expectedType, boxingStrategy, exprBoxed, exprSmall, flags);
    // _after_ we reset it in transformExpression()
    if (coerced)
        ret = applyJavaCoercions(ret, exprType, expectedType);
    return ret;
}
Also used : UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)

Example 78 with JCExpression

use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.

the class ExpressionTransformer method transform.

public JCTree transform(Tree.ObjectExpression expr) {
    at(expr);
    List<JCTree> klass = classGen().transformObjectExpression(expr);
    at(expr);
    JCExpression newCall = make().NewClass(null, null, makeUnquotedIdent(Naming.escapeClassName(expr.getAnonymousClass().getName()) + "_"), List.<JCTree.JCExpression>nil(), null);
    return make().LetExpr((List) klass, newCall);
}
Also used : JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)

Example 79 with JCExpression

use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.

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());
    Type returnType = term.getTypeModel();
    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.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varName), makeInteger(1));
            successor = unAutoPromote(successor, returnType, expr.getSmall());
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varName), operator.getCeylonMethodName()), 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 = makeAssignment(expr, term, transformAssignmentLhs(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.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varVName), makeInteger(1));
            successor = unAutoPromote(successor, returnType, expr.getSmall());
        } else {
            successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.getCeylonMethodName()), 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 = makeAssignment(expr, term, qualifyLhs(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(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) OperatorTranslation(org.eclipse.ceylon.compiler.java.codegen.Operators.OperatorTranslation) AssignmentOperatorTranslation(org.eclipse.ceylon.compiler.java.codegen.Operators.AssignmentOperatorTranslation) Name(org.eclipse.ceylon.langtools.tools.javac.util.Name) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) OptimisationStrategy(org.eclipse.ceylon.compiler.java.codegen.Operators.OptimisationStrategy)

Example 80 with JCExpression

use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression in project ceylon by eclipse.

the class ExpressionTransformer method comprehensionAsSequential.

public JCExpression comprehensionAsSequential(Tree.Comprehension comprehension, Type expectedType) {
    JCExpression sequential = iterableToSequential(transformComprehension(comprehension));
    Type elementType = comprehension.getInitialComprehensionClause().getTypeModel();
    Type sequentialType = typeFact().getSequentialType(elementType);
    return sequentialEmptiness(sequential, expectedType, sequentialType);
}
Also used : UnionType(org.eclipse.ceylon.model.typechecker.model.UnionType) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)

Aggregations

JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)224 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)95 Type (org.eclipse.ceylon.model.typechecker.model.Type)95 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)74 JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)53 ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)53 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)45 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)41 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)39 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)38 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)33 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)32 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)30 JCVariableDecl (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl)28 Function (org.eclipse.ceylon.model.typechecker.model.Function)26 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)22 Value (org.eclipse.ceylon.model.typechecker.model.Value)22 JCNewClass (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)21 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)21 Class (org.eclipse.ceylon.model.typechecker.model.Class)17