Search in sources :

Example 51 with JCStatement

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

the class ExpressionTransformer method transformIf.

// this one trusts the expected type
private JCExpression transformIf(Tree.IfExpression op, Type expectedType) {
    String tmpVar = naming.newTemp("ifResult");
    Tree.Expression thenPart = op.getIfClause().getExpression();
    Tree.Expression elsePart = op.getElseClause() != null ? op.getElseClause().getExpression() : null;
    Tree.Variable elseVar = op.getElseClause() != null ? op.getElseClause().getVariable() : null;
    java.util.List<Tree.Condition> conditions = op.getIfClause().getConditionList().getConditions();
    List<JCStatement> statements = statementGen().transformIf(conditions, thenPart, elseVar, elsePart, tmpVar, op, expectedType);
    at(op);
    // use the op model for the variable, not expected type, because expected type may be optional, where op
    // says not optional (even in case of java interop which may return null), so we allow null values in j.l.String (unboxed)
    // because the caller will insert the null check if the expected type is optional
    Type typeModel = op.getTypeModel();
    if (willEraseToObject(typeModel)) {
        typeModel = typeFact().denotableType(typeModel);
    }
    JCExpression vartype = makeJavaType(typeModel, CodegenUtil.getBoxingStrategy(op) == BoxingStrategy.UNBOXED ? 0 : JT_NO_PRIMITIVES);
    return make().LetExpr(make().VarDef(make().Modifiers(0), names().fromString(tmpVar), vartype, null), statements, makeUnquotedIdent(tmpVar));
}
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) Expression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Expression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)

Example 52 with JCStatement

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

the class ExpressionTransformer method transform.

// Statement expressions
public JCStatement transform(Tree.ExpressionStatement tree) {
    // ExpressionStatements do not return any value, therefore we don't care about the type of the expressions.
    inStatement = true;
    JCStatement result;
    HasErrorException error = errors().getFirstExpressionErrorAndMarkBrokenness(tree.getExpression());
    if (error != null) {
        result = this.makeThrowUnresolvedCompilationError(error);
    } else {
        result = at(tree).Exec(transformExpression(tree.getExpression(), BoxingStrategy.INDIFFERENT, null));
    }
    inStatement = false;
    return result;
}
Also used : HasErrorException(org.eclipse.ceylon.compiler.java.codegen.recovery.HasErrorException) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)

Example 53 with JCStatement

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

the class ExpressionTransformer method transform.

JCExpression transform(Tree.FunctionArgument functionArg) {
    Function model = functionArg.getDeclarationModel();
    TypedReference functionalInterface = gen().checkForFunctionalInterface(expectedType);
    int flags = 0;
    // even if we are a Callable<X>, if the FI returns void don't check for non-null return types
    if (functionalInterface != null && Decl.isUnboxedVoid(functionalInterface.getDeclaration()))
        flags |= EXPR_TARGET_ACCEPTS_NULL;
    List<JCStatement> body;
    boolean prevNoExpressionlessReturn = statementGen().noExpressionlessReturn;
    boolean prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
    Function prevCoercedFunctionalInterfaceNeedsNoNullChecks = expressionGen().coercedFunctionalInterfaceNeedsNoNullChecks;
    try {
        statementGen().noExpressionlessReturn = isAnything(model.getType());
        expressionGen().coercedFunctionalInterfaceNeedsNoNullChecks = (flags & EXPR_TARGET_ACCEPTS_NULL) != 0 ? model : null;
        if (functionArg.getBlock() != null) {
            body = statementGen().transformBlock(functionArg.getBlock());
            if (!functionArg.getBlock().getDefinitelyReturns()) {
                if (isAnything(model.getType())) {
                    body = body.append(make().Return(makeNull()));
                } else {
                    body = body.append(make().Return(makeErroneous(functionArg.getBlock(), "compiler bug: non-void method does not definitely return")));
                }
            }
        } else {
            Tree.Expression expr = functionArg.getExpression();
            JCExpression transExpr = expressionGen().transformExpression(expr, flags);
            JCReturn returnStat = make().Return(transExpr);
            body = List.<JCStatement>of(returnStat);
        }
    } finally {
        expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
        expressionGen().coercedFunctionalInterfaceNeedsNoNullChecks = prevCoercedFunctionalInterfaceNeedsNoNullChecks;
        statementGen().noExpressionlessReturn = prevNoExpressionlessReturn;
    }
    Type callableType = functionArg.getTypeModel();
    CallableBuilder callableBuilder = CallableBuilder.methodArgument(gen(), functionArg, model, callableType, Collections.singletonList(functionArg.getParameterLists().get(0)), classGen().transformMplBody(functionArg.getParameterLists(), model, body));
    callableBuilder.checkForFunctionalInterface(expectedType);
    JCExpression result = callableBuilder.build();
    result = applyErasureAndBoxing(result, callableType, true, BoxingStrategy.BOXED, expectedType);
    return result;
}
Also used : Function(org.eclipse.ceylon.model.typechecker.model.Function) JCReturn(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCReturn) 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) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) Expression(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Expression) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)

Example 54 with JCStatement

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

the class ExpressionTransformer method transformLet.

// this one trusts the expected type
private JCExpression transformLet(LetExpression op, Type expectedType) {
    ListBuffer<JCStatement> defs = new ListBuffer<JCStatement>();
    for (Tree.Statement stmt : op.getLetClause().getVariables()) {
        defs.addAll(statementGen().transformVariableOrDestructure(stmt));
    }
    Tree.Term term = op.getLetClause().getExpression().getTerm();
    BoxingStrategy boxingStrategy = CodegenUtil.getBoxingStrategy(term);
    JCExpression expr = transformExpression(term, boxingStrategy, expectedType);
    at(op);
    if (isAnything(op.getTypeModel()) && CodegenUtil.isUnBoxed(term)) {
        defs.add(make().Exec(expr));
        expr = makeNull();
    }
    return make().LetExpr(defs.toList(), expr);
}
Also used : JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) Term(org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)

Example 55 with JCStatement

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

the class ExpressionTransformer method transformSpreadOperator.

private JCExpression transformSpreadOperator(final Tree.QualifiedMemberOrTypeExpression expr, TermTransformer transformer) {
    at(expr);
    boolean spreadMethodReferenceOuter = !expr.equals(spreading) && !isWithinInvocation() && isCeylonCallableSubtype(expr.getTypeModel());
    boolean spreadMethodReferenceInner = expr.equals(spreading) && isWithinInvocation();
    Tree.QualifiedMemberOrTypeExpression oldSpreading = spreading;
    if (spreadMethodReferenceOuter) {
        spreading = expr;
    }
    try {
        Naming.SyntheticName varBaseName = naming.alias("spread");
        ListBuffer<JCStatement> letStmts = new ListBuffer<JCStatement>();
        final Naming.SyntheticName srcIterableName;
        if (spreadMethodReferenceInner) {
            // use the var we initialized in the outer
            srcIterableName = this.memberPrimary;
        } else {
            srcIterableName = varBaseName.suffixedBy(Suffix.$iterable$);
        }
        if (spreadMethodReferenceOuter) {
            // if we're in the outer, note then name of the var for use in the inner.
            this.memberPrimary = srcIterableName;
        }
        Naming.SyntheticName srcIteratorName = varBaseName.suffixedBy(Suffix.$iterator$);
        Type srcElementType = expr.getTarget().getQualifyingType();
        JCExpression srcIterableExpr;
        boolean isSuperOrSuperOf = false;
        Type srcIterableType;
        if (typeFact().isIterableType(expr.getPrimary().getTypeModel())) {
            srcIterableType = typeFact().getIterableType(srcElementType);
        } else if (typeFact().isJavaIterableType(expr.getPrimary().getTypeModel())) {
            srcIterableType = typeFact().getJavaIterableDeclaration().appliedType(null, Collections.singletonList(srcElementType));
        } else if (typeFact().isJavaArrayType(expr.getPrimary().getTypeModel())) {
            srcIterableType = expr.getPrimary().getTypeModel();
            srcElementType = typeFact().getJavaArrayElementType(srcIterableType);
        } else {
            return makeErroneous(expr, "unhandled iterable type");
        }
        if (spreadMethodReferenceInner) {
            srcIterableExpr = srcIterableName.makeIdent();
        } else {
            boolean isSuper = isSuper(expr.getPrimary());
            isSuperOrSuperOf = isSuper || isSuperOf(expr.getPrimary());
            if (isSuperOrSuperOf) {
                // so we just refer to it later
                if (isSuper) {
                    Declaration member = expr.getPrimary().getTypeModel().getDeclaration().getMember("iterator", null, false);
                    srcIterableExpr = transformSuper(expr, (TypeDeclaration) member.getContainer());
                } else
                    srcIterableExpr = transformSuperOf(expr, expr.getPrimary(), "iterator");
            } else {
                srcIterableExpr = transformExpression(expr.getPrimary(), BoxingStrategy.BOXED, srcIterableType);
            }
        }
        // do not capture the iterable for super invocations: see above
        if (!spreadMethodReferenceInner && !isSuperOrSuperOf) {
            JCVariableDecl srcIterable = null;
            JCExpression srcIterableTypeExpr = makeJavaType(srcIterableType, JT_NO_PRIMITIVES);
            srcIterable = makeVar(Flags.FINAL, srcIterableName, srcIterableTypeExpr, srcIterableExpr);
            letStmts.prepend(srcIterable);
        }
        /* public Object next() {
             *     Object result;
             *     if (!((result = iterator.next()) instanceof Finished)) {
             *         result = transformedMember(result);
             *     }
             *     return result;
             */
        /* Any arguments in the member of the spread would get re-evaluated on each iteration
             * so we need to shift them to the scope of the Let to ensure they're evaluated once. 
             */
        boolean aliasArguments = transformer instanceof InvocationTermTransformer && ((InvocationTermTransformer) transformer).invocation.getNode() instanceof Tree.InvocationExpression && ((Tree.InvocationExpression) ((InvocationTermTransformer) transformer).invocation.getNode()).getPositionalArgumentList() != null;
        if (aliasArguments) {
            ((InvocationTermTransformer) transformer).callBuilder.argumentHandling(CallBuilder.CB_ALIAS_ARGS, varBaseName);
        }
        JCNewClass iterableClass;
        boolean prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
        try {
            Naming.SyntheticName iteratorResultName = varBaseName.suffixedBy(Suffix.$element$);
            JCExpression transformedElement = applyErasureAndBoxing(iteratorResultName.makeIdent(), typeFact().getAnythingType(), CodegenUtil.hasTypeErased(expr.getPrimary()), true, BoxingStrategy.BOXED, srcElementType, 0);
            transformedElement = transformMemberExpression(expr, transformedElement, transformer);
            // be handled by the previous recursion
            if (spreadMethodReferenceOuter) {
                return make().LetExpr(letStmts.toList(), transformedElement);
            }
            Type resultElementType = expr.getTarget().getType();
            final Type resultAbsentType;
            transformedElement = applyErasureAndBoxing(transformedElement, resultElementType, // not necessarily of the applied member
            expr.getTarget().getDeclaration() instanceof TypedDeclaration ? CodegenUtil.hasTypeErased((TypedDeclaration) expr.getTarget().getDeclaration()) : false, !CodegenUtil.isUnBoxed(expr), BoxingStrategy.BOXED, resultElementType, 0);
            MethodDefinitionBuilder nextMdb = MethodDefinitionBuilder.systemMethod(this, "next");
            nextMdb.isOverride(true);
            nextMdb.annotationFlags(Annotations.IGNORE);
            nextMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
            nextMdb.resultType(new TransformedType(make().Type(syms().objectType)));
            final List<JCTree> l;
            if (typeFact().isIterableType(expr.getPrimary().getTypeModel())) {
                // private Iterator<srcElementType> iterator = srcIterableName.iterator();
                JCVariableDecl srcIterator = makeVar(Flags.FINAL, srcIteratorName, makeJavaType(typeFact().getIteratorType(srcElementType)), make().Apply(null, // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "iterator"), List.<JCExpression>nil()));
                resultAbsentType = typeFact().getIteratedAbsentType(expr.getPrimary().getTypeModel());
                nextMdb.body(List.of(makeVar(iteratorResultName, make().Type(syms().objectType), null), make().If(make().Unary(JCTree.Tag.NOT, make().TypeTest(make().Assign(iteratorResultName.makeIdent(), make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "next"), List.<JCExpression>nil())), make().Type(syms().ceylonFinishedType))), make().Block(0, List.<JCStatement>of(make().Exec(make().Assign(iteratorResultName.makeIdent(), transformedElement)))), null), make().Return(iteratorResultName.makeIdent())));
                l = List.of(srcIterator, nextMdb.build());
            } else if (typeFact().isJavaIterableType(expr.getPrimary().getTypeModel())) {
                // private Iterator<srcElementType> iterator = srcIterableName.iterator();
                JCVariableDecl srcIterator = makeVar(Flags.PRIVATE | Flags.FINAL, srcIteratorName, makeJavaType(typeFact().getJavaIteratorType(srcElementType)), make().Apply(null, // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "iterator"), List.<JCExpression>nil()));
                resultAbsentType = typeFact().getNullType();
                nextMdb.body(List.<JCStatement>of(make().If(make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "hasNext"), List.<JCExpression>nil()), make().Block(0, List.<JCStatement>of(makeVar(iteratorResultName, make().Type(syms().objectType), make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "next"), List.<JCExpression>nil())), make().Return(transformedElement))), make().Return(makeFinished()))));
                l = List.of(srcIterator, nextMdb.build());
            } else if (typeFact().isJavaArrayType(expr.getPrimary().getTypeModel())) {
                resultAbsentType = typeFact().getNullType();
                JCVariableDecl srcIndex = makeVar(Flags.PRIVATE, srcIteratorName, make().Type(syms().intType), make().Literal(0));
                JCExpression indexed = make().Indexed(srcIterableName.makeIdent(), make().Unary(Tag.POSTINC, srcIteratorName.makeIdent()));
                if (typeFact().isJavaPrimitiveArrayType(expr.getPrimary().getTypeModel())) {
                    indexed = applyErasureAndBoxing(indexed, srcElementType, false, BoxingStrategy.BOXED, srcElementType);
                }
                nextMdb.body(List.<JCStatement>of(make().If(make().Binary(Tag.LT, srcIteratorName.makeIdent(), // for super we do not capture it because we can't and it's constant anyways
                naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "length")), make().Block(0, List.<JCStatement>of(makeVar(iteratorResultName, make().Type(syms().objectType), indexed), make().Return(transformedElement))), make().Return(makeFinished()))));
                l = List.of(srcIndex, nextMdb.build());
            } else {
                return makeErroneous(expr, "unhandled iterable type");
            }
            // new AbstractIterator()
            JCNewClass iteratorClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIteratorType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType)), make().AnonymousClassDef(make().Modifiers(0), l));
            MethodDefinitionBuilder iteratorMdb = MethodDefinitionBuilder.systemMethod(this, "iterator");
            iteratorMdb.isOverride(true);
            iteratorMdb.annotationFlags(Annotations.IGNORE);
            iteratorMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
            iteratorMdb.resultType(new TransformedType(makeJavaType(typeFact().getIteratorType(resultElementType)), makeAtNonNull()));
            iteratorMdb.body(make().Return(iteratorClass));
            // new AbstractIterable()
            iterableClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIterableType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT), makeJavaType(resultAbsentType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType), makeReifiedTypeArgument(resultAbsentType)), make().AnonymousClassDef(make().Modifiers(0), List.<JCTree>of(iteratorMdb.build())));
        } finally {
            expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
        }
        if (aliasArguments) {
            letStmts = letStmts.appendList(((InvocationTermTransformer) transformer).callBuilder.getStatements());
        }
        JCMethodInvocation result = make().Apply(null, naming.makeQualIdent(iterableClass, "sequence"), List.<JCExpression>nil());
        JCExpression spread = letStmts.isEmpty() ? result : make().LetExpr(letStmts.toList(), result);
        // Do we *statically* know the result must be a Sequence
        final boolean primaryIsSequence = typeFact().isNonemptyIterableType(expr.getPrimary().getTypeModel());
        Type returnElementType = expr.getTarget().getType();
        if (primaryIsSequence) {
            int flags = EXPR_DOWN_CAST;
            spread = applyErasureAndBoxing(spread, typeFact().getSequentialType(returnElementType), false, true, BoxingStrategy.BOXED, primaryIsSequence ? typeFact().getSequenceType(returnElementType) : typeFact().getSequentialType(returnElementType), flags);
        }
        return spread;
    } finally {
        spreading = oldSpreading;
    }
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) JCMethodInvocation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCMethodInvocation) 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) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)73 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)52 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)38 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)31 Type (org.eclipse.ceylon.model.typechecker.model.Type)29 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)25 ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)21 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)18 JCVariableDecl (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl)16 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)15 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)13 Value (org.eclipse.ceylon.model.typechecker.model.Value)13 Function (org.eclipse.ceylon.model.typechecker.model.Function)12 HasErrorException (org.eclipse.ceylon.compiler.java.codegen.recovery.HasErrorException)11 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)11 CustomTree (org.eclipse.ceylon.compiler.typechecker.tree.CustomTree)10 Expression (org.eclipse.ceylon.compiler.typechecker.tree.Tree.Expression)10 JCBlock (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCBlock)10 JCPrimitiveTypeTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree)10 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)10