Search in sources :

Example 36 with Declaration

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

the class ExpressionTransformer method transformConstructorDelegation.

/**
     * Transform a delegated constructor call ({@code extends XXX()})
     * which may be either a superclass initializer/constructor or a 
     * same-class constructor. 
     * @param extendedType
     * @param delegation The kind of delegation 
     * @param invocation
     * @param classBuilder
     * @return
     */
JCStatement transformConstructorDelegation(Node extendedType, CtorDelegation delegation, Tree.InvocationExpression invocation, ClassDefinitionBuilder classBuilder, boolean forDelegationConstructor) {
    if (delegation != null && delegation.isError()) {
        return delegation.makeThrow(this);
    }
    Declaration primaryDeclaration = ((Tree.MemberOrTypeExpression) invocation.getPrimary()).getDeclaration();
    java.util.List<ParameterList> paramLists = ((Functional) primaryDeclaration).getParameterLists();
    if (paramLists.isEmpty()) {
        classBuilder.getInitBuilder().delegateCall(at(extendedType).Exec(makeErroneous(extendedType, "compiler bug: super class " + primaryDeclaration.getName() + " is missing parameter list")));
        return null;
    }
    SuperInvocation builder = new SuperInvocation(this, classBuilder.getForDefinition(), delegation, invocation, paramLists.get(0), forDelegationConstructor);
    CallBuilder callBuilder = CallBuilder.instance(this);
    boolean prevFnCall = withinInvocation(true);
    try {
        if (invocation.getPrimary() instanceof Tree.StaticMemberOrTypeExpression) {
            transformTypeArguments(callBuilder, (Tree.StaticMemberOrTypeExpression) invocation.getPrimary());
        }
        at(builder.getNode());
        JCExpression expr = null;
        Scope outerDeclaration;
        if (Decl.isConstructor(primaryDeclaration)) {
            outerDeclaration = builder.getPrimaryDeclaration().getContainer().getContainer();
        } else {
            outerDeclaration = builder.getPrimaryDeclaration().getContainer();
        }
        if ((Strategy.generateInstantiator(builder.getPrimaryDeclaration()) || builder.getPrimaryDeclaration() instanceof Class) && outerDeclaration instanceof Interface) {
            // If the subclass is inner to an interface then it will be 
            // generated inner to the companion and we need to qualify the 
            // super(), *unless* the subclass is nested within the same 
            // interface as it's superclass.
            Scope outer = builder.getSub().getContainer();
            while (!(outer instanceof Package)) {
                if (outer == outerDeclaration) {
                    expr = naming.makeSuper();
                    break;
                }
                outer = outer.getContainer();
            }
            if (expr == null) {
                if (delegation.isSelfDelegation()) {
                    throw new BugException();
                }
                Interface iface = (Interface) outerDeclaration;
                JCExpression superQual;
                if (Decl.getClassOrInterfaceContainer(classBuilder.getForDefinition(), false) instanceof Interface) {
                    superQual = naming.makeCompanionAccessorCall(naming.makeQuotedThis(), iface);
                } else {
                    superQual = naming.makeCompanionFieldName(iface);
                }
                expr = naming.makeQualifiedSuper(superQual);
            }
        } else {
            expr = delegation.isSelfDelegation() ? naming.makeThis() : naming.makeSuper();
        }
        final List<JCExpression> superArguments = transformSuperInvocationArguments(classBuilder, builder, callBuilder);
        JCExpression superExpr = callBuilder.invoke(expr).arguments(superArguments).build();
        return at(extendedType).Exec(superExpr);
    //classBuilder.getInitBuilder().superCall(at(extendedType).Exec(superExpr));
    } finally {
        withinInvocation(prevFnCall);
    }
}
Also used : Functional(com.redhat.ceylon.model.typechecker.model.Functional) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) Scope(com.redhat.ceylon.model.typechecker.model.Scope) ParameterList(com.redhat.ceylon.model.typechecker.model.ParameterList) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) Class(com.redhat.ceylon.model.typechecker.model.Class) JCNewClass(com.sun.tools.javac.tree.JCTree.JCNewClass) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Package(com.redhat.ceylon.model.typechecker.model.Package) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 37 with Declaration

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

the class ExpressionTransformer method needDollarThis.

private boolean needDollarThis(Tree.StaticMemberOrTypeExpression expr) {
    if (expr instanceof Tree.BaseMemberExpression) {
        // We need to add a `$this` prefix to the member expression if:
        // * The member was declared on an interface I and
        // * The member is being used in the companion class of I or 
        //   // REMOVED: some subinterface of I, and
        //   some member type of I, and
        // * The member is shared (non-shared means its only on the companion class)
        // FIXME: https://github.com/ceylon/ceylon-compiler/issues/1019
        final Declaration decl = expr.getDeclaration();
        if (!Decl.withinInterface(decl))
            return false;
        // Find the method/getter/setter where the expr is being used
        Scope scope = expr.getScope();
        while (scope != null) {
            // Is it being used in an interface (=> impl)
            if (scope instanceof Interface && ((Interface) scope).getType().isSubtypeOf(scope.getDeclaringType(decl))) {
                return decl.isShared();
            }
            scope = scope.getContainer();
        }
    }
    return false;
}
Also used : Scope(com.redhat.ceylon.model.typechecker.model.Scope) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) Interface(com.redhat.ceylon.model.typechecker.model.Interface) ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface)

Example 38 with Declaration

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

the class ExpressionTransformer method transformSpreadOperator.

private JCExpression transformSpreadOperator(final Tree.QualifiedMemberOrTypeExpression expr, TermTransformer transformer) {
    at(expr);
    boolean spreadMethodReferenceOuter = !expr.equals(this.spreading) && !isWithinInvocation() && isCeylonCallableSubtype(expr.getTypeModel());
    boolean spreadMethodReferenceInner = expr.equals(this.spreading) && isWithinInvocation();
    Tree.QualifiedMemberOrTypeExpression oldSpreading = spreading;
    if (spreadMethodReferenceOuter) {
        spreading = expr;
    }
    try {
        Naming.SyntheticName varBaseName = naming.alias("spread");
        ListBuffer<JCStatement> letStmts = ListBuffer.<JCStatement>lb();
        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 srcIterableTypeExpr = makeJavaType(typeFact().getIterableType(srcElementType), JT_NO_PRIMITIVES);
        JCExpression srcIterableExpr;
        boolean isSuperOrSuperOf = false;
        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, typeFact().getIterableType(srcElementType));
            }
        }
        // do not capture the iterable for super invocations: see above
        if (!spreadMethodReferenceInner && !isSuperOrSuperOf) {
            JCVariableDecl srcIterable = null;
            srcIterable = makeVar(Flags.FINAL, srcIterableName, srcIterableTypeExpr, srcIterableExpr);
            letStmts.prepend(srcIterable);
        }
        Type resultElementType = expr.getTarget().getType();
        Type resultAbsentType = typeFact().getIteratedAbsentType(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()));
        Naming.SyntheticName iteratorResultName = varBaseName.suffixedBy(Suffix.$element$);
        /* 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 {
            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);
            }
            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(null, make().Type(syms().objectType));
            nextMdb.body(List.of(makeVar(iteratorResultName, make().Type(syms().objectType), null), make().If(make().Unary(JCTree.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())));
            JCMethodDecl nextMethod = nextMdb.build();
            // 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), List.of(srcIterator, nextMethod)));
            MethodDefinitionBuilder iteratorMdb = MethodDefinitionBuilder.systemMethod(this, "iterator");
            iteratorMdb.isOverride(true);
            iteratorMdb.annotationFlags(Annotations.IGNORE);
            iteratorMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
            iteratorMdb.resultType(null, makeJavaType(typeFact().getIteratorType(resultElementType)));
            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(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) 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) JCNewClass(com.sun.tools.javac.tree.JCTree.JCNewClass) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 39 with Declaration

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

the class ExpressionTransformer method makeTypeParameterDeclaration.

/**
     * Makes an expression equivalent to the result of {@code `given T`} 
     * @param node
     * @param declaration
     * @return
     */
JCExpression makeTypeParameterDeclaration(Node node, TypeParameter declaration) {
    Scope container = declaration.getContainer();
    if (container instanceof Declaration) {
        JCExpression containerExpr;
        Declaration containerDeclaration = (Declaration) container;
        if (containerDeclaration instanceof ClassOrInterface || containerDeclaration instanceof TypeAlias) {
            JCExpression metamodelCall = makeTypeDeclarationLiteral((TypeDeclaration) containerDeclaration);
            JCExpression metamodelCast = makeJavaType(typeFact().getLanguageModuleDeclarationTypeDeclaration("GenericDeclaration").getType(), JT_NO_PRIMITIVES);
            containerExpr = make().TypeCast(metamodelCast, metamodelCall);
        } else if (containerDeclaration.isToplevel()) {
            containerExpr = makeTopLevelValueOrFunctionDeclarationLiteral(containerDeclaration);
        } else {
            containerExpr = makeMemberValueOrFunctionDeclarationLiteral(node, containerDeclaration);
        }
        // now it must be a ClassOrInterfaceDeclaration or a FunctionDeclaration, both of which have the method we need
        return at(node).Apply(null, makeSelect(containerExpr, "getTypeParameterDeclaration"), List.of(ceylonLiteral(declaration.getName())));
    } else {
        return makeErroneous(node, "compiler bug: " + container + " is not a supported type parameter container");
    }
}
Also used : ClassOrInterface(com.redhat.ceylon.model.typechecker.model.ClassOrInterface) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) Scope(com.redhat.ceylon.model.typechecker.model.Scope) TypeAlias(com.redhat.ceylon.model.typechecker.model.TypeAlias) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Example 40 with Declaration

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

the class ExpressionTransformer method transform.

public JCExpression transform(Tree.InvocationExpression ce) {
    JCExpression ret = checkForInvocationExpressionOptimisation(ce);
    if (ret != null)
        return ret;
    Tree.Term primary = Decl.unwrapExpressionsUntilTerm(ce.getPrimary());
    Declaration primaryDeclaration = null;
    Reference producedReference = null;
    if (primary instanceof Tree.MemberOrTypeExpression) {
        producedReference = ((Tree.MemberOrTypeExpression) primary).getTarget();
        primaryDeclaration = ((Tree.MemberOrTypeExpression) primary).getDeclaration();
    }
    Invocation invocation;
    if (ce.getPositionalArgumentList() != null) {
        if ((isIndirectInvocation(ce) || isWithinDefaultParameterExpression(primaryDeclaration.getContainer())) && !Decl.isJavaStaticOrInterfacePrimary(ce.getPrimary())) {
            // indirect invocation
            invocation = new IndirectInvocation(this, primary, primaryDeclaration, ce);
        } else {
            // direct invocation
            java.util.List<Parameter> parameters = ((Functional) primaryDeclaration).getFirstParameterList().getParameters();
            invocation = new PositionalInvocation(this, primary, primaryDeclaration, producedReference, ce, parameters);
        }
    } else if (ce.getNamedArgumentList() != null) {
        invocation = new NamedArgumentInvocation(this, primary, primaryDeclaration, producedReference, ce);
    } else {
        return makeErroneous(ce, "no arguments");
    }
    return transformInvocation(invocation);
}
Also used : AnalyzerUtil.isIndirectInvocation(com.redhat.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.isIndirectInvocation) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) Reference(com.redhat.ceylon.model.typechecker.model.Reference) TypedReference(com.redhat.ceylon.model.typechecker.model.TypedReference) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) AnalyzerUtil.isIndirectInvocation(com.redhat.ceylon.compiler.typechecker.analyzer.AnalyzerUtil.isIndirectInvocation) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) TypeParameter(com.redhat.ceylon.model.typechecker.model.TypeParameter) Parameter(com.redhat.ceylon.model.typechecker.model.Parameter) TypedDeclaration(com.redhat.ceylon.model.typechecker.model.TypedDeclaration) Declaration(com.redhat.ceylon.model.typechecker.model.Declaration) TypeDeclaration(com.redhat.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

Declaration (com.redhat.ceylon.model.typechecker.model.Declaration)107 TypeDeclaration (com.redhat.ceylon.model.typechecker.model.TypeDeclaration)95 TypedDeclaration (com.redhat.ceylon.model.typechecker.model.TypedDeclaration)80 Type (com.redhat.ceylon.model.typechecker.model.Type)34 Function (com.redhat.ceylon.model.typechecker.model.Function)33 ClassOrInterface (com.redhat.ceylon.model.typechecker.model.ClassOrInterface)30 Class (com.redhat.ceylon.model.typechecker.model.Class)28 Value (com.redhat.ceylon.model.typechecker.model.Value)28 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)27 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)27 FunctionOrValue (com.redhat.ceylon.model.typechecker.model.FunctionOrValue)24 AttributeDeclaration (com.redhat.ceylon.compiler.typechecker.tree.Tree.AttributeDeclaration)22 JCTree (com.sun.tools.javac.tree.JCTree)22 TypeParameter (com.redhat.ceylon.model.typechecker.model.TypeParameter)21 MethodDeclaration (com.redhat.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration)20 Interface (com.redhat.ceylon.model.typechecker.model.Interface)20 Scope (com.redhat.ceylon.model.typechecker.model.Scope)20 Package (com.redhat.ceylon.model.typechecker.model.Package)17 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)17 ArrayList (java.util.ArrayList)16