Search in sources :

Example 1 with FunctionOrValue

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

the class CeylonTransformer method transformAttribute.

public List<JCTree> transformAttribute(TypedDeclaration declarationModel, String attrName, String attrClassName, final Tree.Declaration annotated, final Tree.Block block, final Tree.SpecifierOrInitializerExpression expression, final Tree.TypedDeclaration decl, final Tree.AttributeSetterDefinition setterDecl) {
    // For everything else generate a getter/setter method
    AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.wrapped(this, attrClassName, null, attrName, declarationModel, declarationModel.isToplevel()).is(Flags.PUBLIC, declarationModel.isShared());
    final JCExpression initialValue;
    final HasErrorException expressionError;
    if (expression != null) {
        expressionError = errors().getFirstExpressionErrorAndMarkBrokenness(expression.getExpression());
        if (expressionError != null) {
            initialValue = make().Erroneous();
        } else {
            initialValue = transformValueInit(declarationModel, attrName, expression);
        }
    } else {
        expressionError = null;
        initialValue = transformValueInit(declarationModel, attrName, expression);
    }
    // For captured local variable Values, use a VariableBox
    if (Decl.isBoxedVariable(declarationModel)) {
        if (expressionError != null) {
            return List.<JCTree>of(this.makeThrowUnresolvedCompilationError(expressionError));
        } else {
            return List.<JCTree>of(makeVariableBoxDecl(initialValue, declarationModel));
        }
    }
    // For late-bound getters we only generate a declaration
    if (block == null && expression == null && !Decl.isToplevel(declarationModel)) {
        JCExpression typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
        JCTree.JCVariableDecl var = makeVar(attrClassName, typeExpr, null);
        return List.<JCTree>of(var);
    }
    // Set the local declarations annotation
    if (decl != null) {
        List<JCAnnotation> scopeAnnotations;
        if (Decl.isToplevel(declarationModel) && setterDecl != null) {
            scopeAnnotations = makeAtLocalDeclarations(decl, setterDecl);
        } else {
            scopeAnnotations = makeAtLocalDeclarations(decl);
        }
        builder.classAnnotations(scopeAnnotations);
    } else if (block != null) {
        List<JCAnnotation> scopeAnnotations = makeAtLocalDeclarations(block);
        builder.classAnnotations(scopeAnnotations);
    }
    // Remember the setter class if we generate a getter
    if (Decl.isGetter(declarationModel) && declarationModel.isVariable() && Decl.isLocal(declarationModel)) {
        // we must have a setter class
        Setter setter = ((Value) declarationModel).getSetter();
        if (setter != null) {
            String setterClassName = Naming.getAttrClassName(setter, 0);
            JCExpression setterClassNameExpr = naming.makeUnquotedIdent(setterClassName);
            builder.setterClass(makeSelect(setterClassNameExpr, "class"));
        }
    }
    if (declarationModel instanceof Setter || (declarationModel instanceof FunctionOrValue && ((FunctionOrValue) declarationModel).isParameter())) {
        // For local setters
        JCBlock setterBlock = makeSetterBlock(declarationModel, block, expression);
        builder.setterBlock(setterBlock);
        builder.skipGetter();
        if (Decl.isLocal(decl)) {
            // we need to find back the Setter model for local setters, because 
            // in transformAttribute(Tree.TypedDeclaration decl, Tree.AttributeSetterDefinition setterDecl)
            // we turn the declaration model from the Setter to its single parameter
            Setter setter = (Setter) declarationModel.getContainer();
            String getterClassName = Naming.getAttrClassName(setter.getGetter(), 0);
            JCExpression getterClassNameExpr = naming.makeUnquotedIdent(getterClassName);
            builder.isSetter(makeSelect(getterClassNameExpr, "class"));
        }
    } else {
        if (Decl.isValue(declarationModel)) {
            // For local and toplevel value attributes
            if (!declarationModel.isVariable() && !declarationModel.isLate()) {
                builder.immutable();
            }
        } else {
            // For local and toplevel getters
            boolean prevSyntheticClassBody;
            if (Decl.isLocal(declarationModel)) {
                prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
            } else {
                prevSyntheticClassBody = expressionGen().isWithinSyntheticClassBody();
            }
            JCBlock getterBlock = makeGetterBlock(declarationModel, block, expression);
            prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
            builder.getterBlock(getterBlock);
            if (Decl.isLocal(declarationModel)) {
                // For local getters
                builder.immutable();
            } else {
                // For toplevel getters
                if (setterDecl != null) {
                    JCBlock setterBlock = makeSetterBlock(setterDecl.getDeclarationModel(), setterDecl.getBlock(), setterDecl.getSpecifierExpression());
                    builder.setterBlock(setterBlock);
                    //builder.userAnnotationsSetter(expressionGen().transformAnnotations(true, OutputElement.METHOD, setterDecl));
                    builder.userAnnotationsSetter(expressionGen().transformAnnotations(OutputElement.SETTER, setterDecl));
                } else {
                    builder.immutable();
                }
            }
        }
    }
    if (annotated != null) {
        builder.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, annotated));
    }
    if (Decl.isLocal(declarationModel)) {
        if (expressionError != null) {
            return List.<JCTree>of(this.makeThrowUnresolvedCompilationError(expressionError));
        }
        builder.classAnnotations(makeAtLocalDeclaration(declarationModel.getQualifier(), false));
        if (initialValue != null)
            builder.valueConstructor();
        JCExpression typeExpr;
        if (declarationModel instanceof Setter || (declarationModel instanceof FunctionOrValue && ((FunctionOrValue) declarationModel).isParameter())) {
            typeExpr = makeQuotedIdent(attrClassName);
        } else {
            typeExpr = makeJavaType(getGetterInterfaceType(declarationModel));
        }
        return builder.build().append(makeLocalIdentityInstance(typeExpr, attrClassName, attrClassName, declarationModel.isShared(), initialValue));
    } else {
        if (expressionError != null) {
            builder.initialValueError(expressionError);
        } else if (initialValue != null) {
            builder.initialValue(initialValue);
        }
        builder.is(Flags.STATIC, true);
        return builder.build();
    }
}
Also used : JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JCTree(com.sun.tools.javac.tree.JCTree) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) HasErrorException(com.redhat.ceylon.compiler.java.codegen.recovery.HasErrorException) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Setter(com.redhat.ceylon.model.typechecker.model.Setter) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue) Value(com.redhat.ceylon.model.typechecker.model.Value) List(com.sun.tools.javac.util.List) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Example 2 with FunctionOrValue

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

the class MethodOrValueReferenceVisitor method usedIn.

/**
     * Returns 1 if the declaration is captured in the given statements, 0 otherwise.
     */
private int usedIn(List<Statement> stmts) {
    for (Tree.Statement stmt : stmts) {
        // count declarations as usage
        if (stmt instanceof Tree.TypedDeclaration && ((Tree.TypedDeclaration) stmt).getDeclarationModel() == declaration)
            return 1;
        stmt.visit(this);
        if (declaration.isCaptured())
            break;
    }
    boolean used = declaration.isCaptured();
    FunctionOrValue fov = ((FunctionOrValue) declaration);
    fov.setCaptured(false);
    if (fov instanceof Value) {
        Value val = (Value) fov;
        if (val.getSetter() != null)
            val.getSetter().setCaptured(false);
    }
    return used ? 1 : 0;
}
Also used : TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Statement(com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue) Value(com.redhat.ceylon.model.typechecker.model.Value) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Example 3 with FunctionOrValue

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

the class MethodOrValueReferenceVisitor method visitConstructorPlan.

/**
     * Marks declarations as captured if they are used in more than one generated constructor, according
     * to the given plan and knowledge on how we split up constructor delegates.
     */
private void visitConstructorPlan(ConstructorPlan constructorPlan) {
    // if there is no delegation all statements are put in the same method so we can't capture
    if (constructorPlan.delegate == null && !constructorPlan.isDelegate)
        return;
    boolean cs = enterCapturingScope();
    int useCount = usedIn(constructorPlan, false);
    FunctionOrValue fov = ((FunctionOrValue) declaration);
    fov.setCaptured(useCount > 1);
    if (fov instanceof Value) {
        Value val = (Value) fov;
        if (val.getSetter() != null)
            val.getSetter().setCaptured(useCount > 1);
    }
    exitCapturingScope(cs);
}
Also used : FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue) Value(com.redhat.ceylon.model.typechecker.model.Value) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Example 4 with FunctionOrValue

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

the class MethodOrValueReferenceVisitor method visit.

@Override
public void visit(Tree.ClassDefinition that) {
    if (!that.getDeclarationModel().hasConstructors()) {
        boolean cs = enterCapturingScope();
        super.visit(that);
        exitCapturingScope(cs);
    } else {
        // super special case for unshared members when we have constructors
        if (!declaration.isCaptured() && declaration instanceof FunctionOrValue && declaration.isClassMember()) {
            Map<Constructor, ConstructorPlan> constructorPlans = new HashMap<Constructor, ConstructorPlan>();
            List<Tree.Statement> statements = new ArrayList<>(that.getClassBody().getStatements().size());
            // find every constructor, and build a model of how they delegate
            for (Tree.Statement stmt : that.getClassBody().getStatements()) {
                if (stmt instanceof Tree.Constructor) {
                    Tree.Constructor ctor = (Tree.Constructor) stmt;
                    // build a new plan for it
                    ConstructorPlan plan = new ConstructorPlan();
                    plan.constructor = ctor;
                    constructorPlans.put(ctor.getConstructor(), plan);
                    // find every constructor which delegates to another constructor
                    if (ctor.getDelegatedConstructor() != null && ctor.getDelegatedConstructor().getInvocationExpression() != null) {
                        if (ctor.getDelegatedConstructor().getInvocationExpression().getPrimary() instanceof Tree.ExtendedTypeExpression) {
                            Tree.ExtendedTypeExpression ete = (Tree.ExtendedTypeExpression) ctor.getDelegatedConstructor().getInvocationExpression().getPrimary();
                            // are we delegating to a constructor (not a supertype) of the same class (this class)?
                            if (Decl.isConstructor(ete.getDeclaration()) && Decl.getConstructedClass(ete.getDeclaration()).equals(that.getDeclarationModel())) {
                                // remember the delegation
                                Constructor delegate = Decl.getConstructor(ete.getDeclaration());
                                ConstructorPlan delegatePlan = constructorPlans.get(delegate);
                                plan.delegate = delegatePlan;
                                // mark the delegate as delegated
                                delegatePlan.isDelegate = true;
                                // we have all the statements before us and after our delegate
                                plan.before.addAll(delegatePlan.after);
                            }
                        }
                    }
                    // if we have no delegate, we start with every common statement
                    if (plan.delegate == null)
                        plan.before.addAll(statements);
                    // also add all the constructor's statements
                    if (ctor.getBlock() != null) {
                        plan.before.addAll(ctor.getBlock().getStatements());
                    }
                } else {
                    statements.add(stmt);
                    // make sure all existing constructors get this statement too
                    for (ConstructorPlan constructorPlan : constructorPlans.values()) constructorPlan.after.add(stmt);
                }
            }
            // try every constructor plan and see if it's used in two methods
            for (ConstructorPlan constructorPlan : constructorPlans.values()) {
                visitConstructorPlan(constructorPlan);
                // are we done?
                if (declaration.isCaptured())
                    break;
            }
        }
        // do regular capturing after that (for members), if required
        if (!declaration.isCaptured())
            super.visit(that);
    }
}
Also used : HashMap(java.util.HashMap) Constructor(com.redhat.ceylon.model.typechecker.model.Constructor) SpecifierStatement(com.redhat.ceylon.compiler.typechecker.tree.Tree.SpecifierStatement) Statement(com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement) ArrayList(java.util.ArrayList) Statement(com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Example 5 with FunctionOrValue

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

the class MethodOrValueReferenceVisitor method isCapturableMplParameter.

/**
     * Because methods with MPL use nested anonymous AbstractCallables
     * if the declaration is a parameter in all but the last parameter list
     * it should be captured.
     */
private boolean isCapturableMplParameter(Declaration d) {
    if (!(d instanceof FunctionOrValue)) {
        return false;
    }
    com.redhat.ceylon.model.typechecker.model.Parameter param = ((FunctionOrValue) d).getInitializerParameter();
    if (param == null) {
        return false;
    }
    Declaration paramDecl = param.getDeclaration();
    if (paramDecl instanceof Functional) {
        List<com.redhat.ceylon.model.typechecker.model.ParameterList> parameterLists = ((Functional) paramDecl).getParameterLists();
        for (int i = 0; i < parameterLists.size() - 1; i++) {
            if (parameterLists.get(i).getParameters().contains(param)) {
                return true;
            }
        }
    }
    return false;
}
Also used : Functional(com.redhat.ceylon.model.typechecker.model.Functional) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) FunctionOrValue(com.redhat.ceylon.model.typechecker.model.FunctionOrValue)

Aggregations

FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)18 Value (com.redhat.ceylon.model.typechecker.model.Value)10 Function (com.redhat.ceylon.model.typechecker.model.Function)9 Type (com.redhat.ceylon.model.typechecker.model.Type)7 Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)6 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)6 Parameter (com.redhat.ceylon.model.typechecker.model.Parameter)5 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)5 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)5 TypedReference (com.redhat.ceylon.model.typechecker.model.TypedReference)5 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)4 ArrayList (java.util.ArrayList)4 Class (com.redhat.ceylon.model.typechecker.model.Class)3 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)3 Statement (com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement)2 JavaBeanValue (com.redhat.ceylon.model.loader.model.JavaBeanValue)2 Functional (com.redhat.ceylon.model.typechecker.model.Functional)2 ParameterList (com.redhat.ceylon.model.typechecker.model.ParameterList)2 Scope (com.redhat.ceylon.model.typechecker.model.Scope)2 JCTree (com.sun.tools.javac.tree.JCTree)2