Search in sources :

Example 51 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method transformAnnotationClassConstructor.

/**
 * Generates a constructor for an annotation class which takes the
 * annotation type as parameter.
 * @param classBuilder
 */
private void transformAnnotationClassConstructor(Tree.AnyClass def, ClassDefinitionBuilder classBuilder) {
    Class klass = def.getDeclarationModel();
    MethodDefinitionBuilder annoCtor = classBuilder.addConstructor(klass.isDeprecated());
    annoCtor.ignoreModelAnnotations();
    // constructors are never final
    annoCtor.modifiers(modifierTransformation().classFlags(klass) & ~FINAL);
    ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(this, "anno");
    pdb.type(new TransformedType(makeJavaType(klass.getType(), JT_ANNOTATION), null, makeAtNonNull()));
    annoCtor.parameter(pdb);
    // It's up to the caller to invoke value() on the Java annotation for a sequenced
    // annotation
    ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
    for (Tree.Parameter parameter : def.getParameterList().getParameters()) {
        at(parameter);
        Parameter parameterModel = parameter.getParameterModel();
        JCExpression annoAttr = make().Apply(null, naming.makeQuotedQualIdent(naming.makeUnquotedIdent("anno"), parameter.getParameterModel().getName()), List.<JCExpression>nil());
        Type parameterType = parameterModel.getType();
        JCExpression argExpr;
        if (typeFact().isIterableType(parameterType) && !isCeylonString(parameterType)) {
            // Convert from array to Sequential
            Type iteratedType = typeFact().getIteratedType(parameterType);
            boolean nonEmpty = typeFact().isNonemptyIterableType(parameterType);
            if (isCeylonBasicType(iteratedType)) {
                argExpr = utilInvocation().sequentialWrapperBoxed(annoAttr);
            } else if (Decl.isAnnotationClass(iteratedType.getDeclaration())) {
                // Can't use Util.sequentialAnnotation becase we need to 'box'
                // the Java annotations in their Ceylon annotation class
                argExpr = make().Apply(null, naming.makeUnquotedIdent(naming.getAnnotationSequenceMethodName()), List.of(annoAttr));
                ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
                SyntheticName array = naming.synthetic(Unfix.$array$);
                SyntheticName sb = naming.synthetic(Unfix.$sb$);
                SyntheticName index = naming.synthetic(Unfix.$index$);
                SyntheticName element = naming.synthetic(Unfix.$element$);
                stmts.append(makeVar(FINAL, sb, make().TypeArray(make().Type(syms().objectType)), make().NewArray(make().Type(syms().objectType), List.of(naming.makeQualIdent(array.makeIdent(), "length")), null)));
                stmts.append(makeVar(index, make().Type(syms().intType), make().Literal(0)));
                stmts.append(make().ForeachLoop(makeVar(element, makeJavaType(iteratedType, JT_ANNOTATION), null), array.makeIdent(), make().Exec(make().Assign(make().Indexed(sb.makeIdent(), make().Unary(JCTree.Tag.POSTINC, index.makeIdent())), instantiateAnnotationClass(iteratedType, element.makeIdent())))));
                stmts.append(make().Return(make().NewClass(null, null, make().QualIdent(syms().ceylonTupleType.tsym), List.of(makeReifiedTypeArgument(iteratedType), sb.makeIdent(), makeEmpty(), make().Literal(false)), null)));
                classBuilder.method(MethodDefinitionBuilder.systemMethod(this, naming.getAnnotationSequenceMethodName()).ignoreModelAnnotations().modifiers(PRIVATE | STATIC).resultType(new TransformedType(makeJavaType(typeFact().getSequentialType(iteratedType)), null, makeAtNonNull())).parameter(ParameterDefinitionBuilder.systemParameter(this, array.getName()).type(new TransformedType(make().TypeArray(makeJavaType(iteratedType, JT_ANNOTATION))))).body(stmts.toList()));
            } else if (isCeylonMetamodelDeclaration(iteratedType)) {
                argExpr = makeMetamodelInvocation("parseMetamodelReferences", List.<JCExpression>of(makeReifiedTypeArgument(iteratedType), annoAttr), List.<JCExpression>of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT)));
            } else if (Decl.isEnumeratedTypeWithAnonCases(iteratedType)) {
                argExpr = makeMetamodelInvocation("parseEnumerationReferences", List.<JCExpression>of(makeReifiedTypeArgument(iteratedType), annoAttr), List.<JCExpression>of(makeJavaType(iteratedType, JT_TYPE_ARGUMENT)));
            } else {
                argExpr = makeErroneous(parameter, "compiler bug");
            }
            if (nonEmpty) {
                argExpr = make().TypeCast(makeJavaType(parameterType), argExpr);
            }
        } else if (Decl.isAnnotationClass(parameterType.getDeclaration())) {
            argExpr = instantiateAnnotationClass(parameterType, annoAttr);
        } else if (isCeylonMetamodelDeclaration(parameterType)) {
            argExpr = makeMetamodelInvocation("parseMetamodelReference", List.<JCExpression>of(annoAttr), List.<JCExpression>of(makeJavaType(parameterType, JT_TYPE_ARGUMENT)));
        } else if (Decl.isEnumeratedTypeWithAnonCases(parameterType)) {
            argExpr = makeMetamodelInvocation("parseEnumerationReference", List.<JCExpression>of(annoAttr), null);
        } else {
            argExpr = annoAttr;
            argExpr = expressionGen().applyErasureAndBoxing(annoAttr, parameterType.withoutUnderlyingType(), false, BoxingStrategy.UNBOXED, parameterType);
        }
        args.add(argExpr);
    }
    annoCtor.body(at(def).Exec(make().Apply(null, naming.makeThis(), args.toList())));
}
Also used : ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)

Example 52 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method transformMethod.

private List<MethodDefinitionBuilder> transformMethod(final Function methodModel, Tree.TypeParameterList typeParameterList, Tree.AnyMethod node, java.util.List<Tree.ParameterList> parameterLists, Tree.Declaration annotated, boolean transformMethod, boolean actual, boolean includeAnnotations, List<JCStatement> body, DaoBody daoTransformation, boolean defaultValuesBody) {
    ListBuffer<MethodDefinitionBuilder> lb = new ListBuffer<MethodDefinitionBuilder>();
    Declaration refinedDeclaration = methodModel.getRefinedDeclaration();
    final MethodDefinitionBuilder methodBuilder = MethodDefinitionBuilder.method(this, methodModel);
    // do the reified type param arguments
    if (AbstractTransformer.supportsReified(methodModel)) {
        methodBuilder.reifiedTypeParameters(Strategy.getEffectiveTypeParameters(methodModel));
    }
    if (methodModel.getParameterLists().size() > 1) {
        methodBuilder.mpl(methodModel.getParameterLists());
    }
    boolean hasOverloads = false;
    Tree.ParameterList parameterList = parameterLists.get(0);
    int flags = 0;
    if (rawParameters(methodModel)) {
        flags |= JT_RAW;
    }
    for (final Tree.Parameter parameter : parameterList.getParameters()) {
        Parameter parameterModel = parameter.getParameterModel();
        List<JCAnnotation> annotations = null;
        if (includeAnnotations) {
            Tree.TypedDeclaration typedDeclaration = Decl.getMemberDeclaration(annotated, parameter);
            // f = function(Integer param) => 2;
            if (typedDeclaration != null)
                annotations = expressionGen().transformAnnotations(OutputElement.PARAMETER, typedDeclaration);
        }
        // methodModel.getTypedReference().getTypedParameter(parameterModel).getType()
        // parameterModel.getModel().getTypedReference().getType()
        methodBuilder.parameter(parameter, parameterModel, annotations, flags, WideningRules.CAN_WIDEN);
        if (Strategy.hasDefaultParameterValueMethod(parameterModel) || Strategy.hasDefaultParameterOverload(parameterModel)) {
            if (Decl.equal(refinedDeclaration, methodModel) || (!methodModel.isInterfaceMember() && body != null) || methodModel.isInterfaceMember() && daoTransformation instanceof DaoCompanion == false) {
                if (daoTransformation != null && (daoTransformation instanceof DaoCompanion == false || body != null)) {
                    DaoBody daoTrans = (body == null && !methodModel.isJavaNative()) ? daoAbstract : new DaoThis(node, parameterList);
                    MethodDefinitionBuilder overloadedMethod = new DefaultedArgumentMethod(daoTrans, MethodDefinitionBuilder.method(this, methodModel), methodModel).makeOverload(parameterList.getModel(), parameter.getParameterModel(), Strategy.getEffectiveTypeParameters(methodModel));
                    overloadedMethod.location(null);
                    lb.append(overloadedMethod);
                }
                if (Decl.equal(refinedDeclaration, methodModel) && Strategy.hasDefaultParameterValueMethod(parameterModel)) {
                    lb.append(makeParamDefaultValueMethod(defaultValuesBody, methodModel, parameterList, parameter));
                }
            }
            hasOverloads = true;
        }
    }
    // Determine if we need to generate a "canonical" method
    boolean createCanonical = hasOverloads && methodModel.isClassOrInterfaceMember() && (body != null || methodModel.isJavaNative());
    if (createCanonical) {
        // Creates the private "canonical" method containing the actual body
        MethodDefinitionBuilder canonicalMethod = new CanonicalMethod(daoTransformation, methodModel, body).makeOverload(parameterList.getModel(), null, Strategy.getEffectiveTypeParameters(methodModel));
        lb.append(canonicalMethod);
    }
    if (transformMethod) {
        methodBuilder.modifiers(modifierTransformation().method(methodModel) | (methodModel.isJavaNative() && !createCanonical ? Flags.NATIVE : 0));
        if (actual) {
            methodBuilder.isOverride(methodModel.isActual());
        }
        if (includeAnnotations) {
            methodBuilder.userAnnotations(expressionGen().transformAnnotations(OutputElement.METHOD, annotated));
            methodBuilder.modelAnnotations(methodModel.getAnnotations());
            if (!methodModel.isDefault() && isEe(methodModel)) {
                methodBuilder.modelAnnotations(makeAtFinal());
            }
        } else {
            methodBuilder.ignoreModelAnnotations();
        }
        methodBuilder.resultType(methodModel, 0);
        copyTypeParameters(methodModel, methodBuilder);
        if (createCanonical) {
            // Creates method that redirects to the "canonical" method containing the actual body
            MethodDefinitionBuilder overloadedMethod = new CanonicalMethod(new DaoThis(node, parameterList), methodBuilder, methodModel).makeOverload(parameterList.getModel(), null, Strategy.getEffectiveTypeParameters(methodModel));
            lb.append(overloadedMethod);
        } else {
            if (body != null) {
                // Construct the outermost method using the body we've built so far
                methodBuilder.body(body);
            } else {
                methodBuilder.noBody();
            }
            lb.append(methodBuilder);
        }
    }
    return lb.toList();
}
Also used : ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) JCAnnotation(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)

Example 53 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method serializationSet.

private void serializationSet(Class model, ClassDefinitionBuilder classBuilder) {
    MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$set$.toString());
    mdb.isOverride(true);
    mdb.ignoreModelAnnotations();
    mdb.modifiers(PUBLIC);
    ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(this, Unfix.reference.toString());
    pdb.modifiers(FINAL);
    pdb.type(new TransformedType(make().Type(syms().ceylonReachableReferenceType), null, makeAtNonNull()));
    mdb.parameter(pdb);
    ParameterDefinitionBuilder pdb2 = ParameterDefinitionBuilder.systemParameter(this, Unfix.instance.toString());
    pdb2.modifiers(FINAL);
    pdb2.type(new TransformedType(make().Type(syms().objectType), null, makeAtNonNull()));
    mdb.parameter(pdb2);
    // mdb.resultType(null, naming.makeQuotedFQIdent("java.util.Collection"));
    /*
         * public void $set$(Object reference, Object instance) {
         *     switch((String)reference) {
         *     case ("attr1")
         *           this.field1 = ...;
         *           break;
         *     // ... other fields of this class
         *     default:
         *           super.set(reference, instance);
         */
    SyntheticName reference = naming.synthetic(Unfix.reference);
    SyntheticName instance = naming.synthetic(Unfix.instance);
    ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
    boolean[] needsLookup = new boolean[] { false };
    for (Declaration member : model.getMembers()) {
        if (hasField(member)) {
            if (member instanceof Function)
                // TODO: This class is not serializable
                continue;
            ListBuffer<JCStatement> caseStmts = new ListBuffer<JCStatement>();
            if (member instanceof Value && ((Value) member).isLate()) {
                caseStmts.add(make().If(make().TypeTest(instance.makeIdent(), make().Type(syms().ceylonUninitializedLateValueType)), make().Break(null), null));
            }
            caseStmts.add(makeDeserializationAssignment((Value) member, needsLookup));
            caseStmts.add(make().Break(null));
            cases.add(make().Case(make().Literal(member.getQualifiedNameString()), caseStmts.toList()));
        }
    }
    ListBuffer<JCStatement> defaultCase = new ListBuffer<JCStatement>();
    if (extendsSerializable(model)) {
        // super.set(reference, instance);
        defaultCase.add(make().Exec(make().Apply(null, naming.makeQualIdent(naming.makeSuper(), Unfix.$set$.toString()), List.<JCExpression>of(reference.makeIdent(), instance.makeIdent()))));
    } else {
        // throw (or pass to something else to throw, based on policy)
        defaultCase.add(make().Throw(make().NewClass(null, null, naming.makeQuotedFQIdent("java.lang.RuntimeException"), List.<JCExpression>of(make().Literal("unknown attribute")), null)));
    }
    cases.add(make().Case(null, defaultCase.toList()));
    ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
    if (needsLookup[0]) {
        // if we needed to use a lookup object to reset final fields,
        // prepend that variable
        stmts.add(makeVar(FINAL, "lookup", naming.makeQualIdent(make().Type(syms().methodHandlesType), "Lookup"), make().Apply(null, naming.makeQuotedFQIdent("java.lang.invoke.MethodHandles.lookup"), List.<JCExpression>nil())));
    }
    JCSwitch swtch = make().Switch(make().Apply(null, naming.makeSelect(make().Apply(null, naming.makeSelect(make().TypeCast(make().Type(syms().ceylonMemberType), reference.makeIdent()), "getAttribute"), List.<JCExpression>nil()), "getQualifiedName"), List.<JCExpression>nil()), cases.toList());
    stmts.add(make().If(make().TypeTest(reference.makeIdent(), make().Type(syms().ceylonMemberType)), swtch, make().Throw(make().NewClass(null, null, make().Type(syms().ceylonAssertionErrorType), List.<JCExpression>of(make().Binary(JCTree.Tag.PLUS, make().Literal("unexpected reachable reference "), reference.makeIdent())), null))));
    mdb.body(stmts.toList());
    classBuilder.method(mdb);
}
Also used : ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Function(org.eclipse.ceylon.model.typechecker.model.Function) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCSwitch(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCSwitch) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) JCCase(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCCase)

Example 54 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class CallableBuilder method unboundFunctionalMemberReference.

/**
 * Used for "static" method or class references. For example:
 * <pre>
 *     value x = Integer.plus;
 *     value y = Foo.method;
 *     value z = Outer.Inner;
 * </pre>
 */
public static JCExpression unboundFunctionalMemberReference(CeylonTransformer gen, Tree.QualifiedMemberOrTypeExpression qmte, Type typeModel, final Functional methodClassOrCtor, Reference producedReference, Type expectedType) {
    final ParameterList parameterList = methodClassOrCtor.getFirstParameterList();
    Type type = typeModel;
    JCExpression target;
    boolean memberClassCtorRef = ModelUtil.getConstructor((Declaration) methodClassOrCtor) != null && !ModelUtil.getConstructedClass((Declaration) methodClassOrCtor).isToplevel() && qmte.getPrimary() instanceof Tree.QualifiedTypeExpression;
    boolean hasOuter = !(Decl.isConstructor((Declaration) methodClassOrCtor) && gen.getNumParameterLists(typeModel) == 1);
    if (!hasOuter) {
        type = typeModel;
        if (memberClassCtorRef) {
            target = gen.naming.makeUnquotedIdent(Unfix.$instance$);
        } else {
            target = null;
        }
    } else {
        type = gen.getReturnTypeOfCallable(type);
        Type qualifyingType = qmte.getTarget().getQualifyingType();
        target = gen.naming.makeUnquotedIdent(Unfix.$instance$);
        target = gen.expressionGen().applyErasureAndBoxing(target, producedReference.getQualifyingType(), true, BoxingStrategy.BOXED, qualifyingType);
    }
    CallableBuilder inner = new CallableBuilder(gen, qmte, type, parameterList);
    // FromParameterModels();
    inner.parameterTypes = inner.getParameterTypesFromCallableModel();
    if (hasOuter) {
        inner.defaultValueCall = inner.new MemberReferenceDefaultValueCall(methodClassOrCtor);
    }
    CallBuilder callBuilder = CallBuilder.instance(gen);
    Type accessType = gen.getParameterTypeOfCallable(typeModel, 0);
    boolean needsCast = false;
    if (Decl.isConstructor((Declaration) methodClassOrCtor)) {
        Constructor ctor = ModelUtil.getConstructor((Declaration) methodClassOrCtor);
        Class cls = ModelUtil.getConstructedClass(ctor);
        if (Strategy.generateInstantiator(ctor)) {
            needsCast = Strategy.isInstantiatorUntyped(ctor);
            callBuilder.invoke(gen.naming.makeInstantiatorMethodName(target, cls));
        } else if (Decl.isJavaArrayWith(ctor)) {
            callBuilder.arrayWith(gen.getReturnTypeOfCallable(typeModel).getQualifyingType(), gen.makeJavaType(gen.getReturnTypeOfCallable(typeModel), JT_CLASS_NEW));
        } else {
            callBuilder.instantiate(gen.makeJavaType(gen.getReturnTypeOfCallable(typeModel), JT_CLASS_NEW));
            if (!ctor.isShared()) {
                accessType = Decl.getPrivateAccessType(qmte);
            }
        }
    } else if (methodClassOrCtor instanceof Function && ((Function) methodClassOrCtor).isParameter()) {
        callBuilder.invoke(gen.naming.makeQualifiedName(target, (Function) methodClassOrCtor, Naming.NA_MEMBER));
    } else if (methodClassOrCtor instanceof Function) {
        callBuilder.invoke(gen.naming.makeQualifiedName(target, (Function) methodClassOrCtor, Naming.NA_MEMBER));
        if (!((TypedDeclaration) methodClassOrCtor).isShared()) {
            accessType = Decl.getPrivateAccessType(qmte);
        }
    } else if (methodClassOrCtor instanceof Class) {
        Class cls = (Class) methodClassOrCtor;
        if (Strategy.generateInstantiator(cls)) {
            callBuilder.invoke(gen.naming.makeInstantiatorMethodName(target, cls));
        } else {
            callBuilder.instantiate(new ExpressionAndType(target, null), gen.makeJavaType(cls.getType(), JT_CLASS_NEW | AbstractTransformer.JT_NON_QUALIFIED));
            if (!cls.isShared()) {
                accessType = Decl.getPrivateAccessType(qmte);
            }
        }
    } else {
        throw BugException.unhandledDeclarationCase((Declaration) methodClassOrCtor, qmte);
    }
    ListBuffer<ExpressionAndType> reified = new ListBuffer<ExpressionAndType>();
    DirectInvocation.addReifiedArguments(gen, producedReference, reified);
    for (ExpressionAndType reifiedArgument : reified) {
        callBuilder.argument(reifiedArgument.expression);
    }
    if (Decl.isConstructor((Declaration) methodClassOrCtor) && !Decl.isDefaultConstructor(ModelUtil.getConstructor((Declaration) methodClassOrCtor)) && !Decl.isJavaArrayWith((Constructor) methodClassOrCtor)) {
        // invoke the param class ctor
        Constructor ctor = ModelUtil.getConstructor((Declaration) methodClassOrCtor);
        callBuilder.argument(gen.naming.makeNamedConstructorName(ctor, false));
    }
    for (Parameter parameter : parameterList.getParameters()) {
        callBuilder.argument(gen.naming.makeQuotedIdent(Naming.getAliasedParameterName(parameter)));
    }
    JCExpression innerInvocation = callBuilder.build();
    if (needsCast) {
        innerInvocation = gen.make().TypeCast(gen.makeJavaType(gen.getReturnTypeOfCallable(type)), innerInvocation);
    }
    // Need to worry about boxing for Function and FunctionalParameter
    if (methodClassOrCtor instanceof TypedDeclaration && !Decl.isConstructor((Declaration) methodClassOrCtor)) {
        // use the method return type since the function is actually applied
        Type returnType = gen.getReturnTypeOfCallable(type);
        innerInvocation = gen.expressionGen().applyErasureAndBoxing(innerInvocation, returnType, // expression is a Callable
        CodegenUtil.hasTypeErased((TypedDeclaration) methodClassOrCtor), !CodegenUtil.isUnBoxed((TypedDeclaration) methodClassOrCtor), BoxingStrategy.BOXED, returnType, 0);
    } else if (methodClassOrCtor instanceof Class && Strategy.isInstantiatorUntyped((Class) methodClassOrCtor)) {
        // $new method declared to return Object, so needs typecast
        innerInvocation = gen.make().TypeCast(gen.makeJavaType(((Class) methodClassOrCtor).getType()), innerInvocation);
    }
    List<JCStatement> innerBody = List.<JCStatement>of(gen.make().Return(innerInvocation));
    inner.useDefaultTransformation(innerBody);
    JCExpression callable = inner.build();
    if (!hasOuter) {
        if (memberClassCtorRef) {
            ;
            JCVariableDecl def = gen.makeVar(Unfix.$instance$.toString(), gen.makeJavaType(((QualifiedMemberOrTypeExpression) qmte.getPrimary()).getPrimary().getTypeModel()), gen.expressionGen().transformQualifiedMemberPrimary(qmte));
            return gen.make().LetExpr(def, callable);
        }
        return callable;
    }
    ParameterList outerPl = new ParameterList();
    Parameter instanceParameter = new Parameter();
    instanceParameter.setName(Naming.name(Unfix.$instance$));
    Value valueModel = new Value();
    instanceParameter.setModel(valueModel);
    valueModel.setName(instanceParameter.getName());
    valueModel.setInitializerParameter(instanceParameter);
    valueModel.setType(accessType);
    valueModel.setUnboxed(false);
    outerPl.getParameters().add(instanceParameter);
    CallableBuilder outer = new CallableBuilder(gen, qmte, typeModel, outerPl);
    outer.parameterTypes = outer.getParameterTypesFromParameterModels();
    List<JCStatement> outerBody = List.<JCStatement>of(gen.make().Return(callable));
    outer.useDefaultTransformation(outerBody);
    outer.companionAccess = Decl.isPrivateAccessRequiringCompanion(qmte);
    if (expectedType != null)
        outer.checkForFunctionalInterface(expectedType);
    return outer.build();
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) Value(org.eclipse.ceylon.model.typechecker.model.Value) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration)

Example 55 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class CallableBuilder method makeFunctionalInterfaceMethod.

public MethodDefinitionBuilder makeFunctionalInterfaceMethod() {
    FunctionOrValue methodOrValue = (FunctionOrValue) functionalInterfaceMethod.getDeclaration();
    MethodDefinitionBuilder callMethod = MethodDefinitionBuilder.method(gen, methodOrValue, 0);
    callMethod.isOverride(true);
    callMethod.modifiers(Flags.PUBLIC);
    Type returnType = functionalInterfaceMethod.getType();
    if (methodOrValue instanceof Value || !((Function) methodOrValue).isDeclaredVoid()) {
        int flags = CodegenUtil.isUnBoxed(methodOrValue) ? 0 : JT_NO_PRIMITIVES;
        callMethod.resultType(gen.makeJavaType(returnType, flags), null);
    }
    ListBuffer<JCExpression> args = new ListBuffer<>();
    // this depends on how we're declared to Java
    boolean turnedToRaw = gen.rawSupertype(functionalInterface, JT_EXTENDS | JT_CLASS_NEW);
    boolean variadic = false;
    if (methodOrValue instanceof Function) {
        int index = 0;
        java.util.List<Parameter> parameters = ((Function) methodOrValue).getFirstParameterList().getParameters();
        for (int i = 0; i < parameters.size(); i++) {
            Parameter param = parameters.get(i);
            Parameter targetParam = paramLists.getParameters().get(i);
            TypedReference typedParameter = functionalInterfaceMethod.getTypedParameter(param);
            ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(gen, param.getName());
            Type paramType = typedParameter.getType();
            if (param.isSequenced()) {
                paramType = gen.typeFact().getSequentialElementType(paramType);
                variadic = true;
            }
            // This is very special-casey, but is required and I haven't found more subtle
            if (turnedToRaw && gen.simplifyType(param.getType()).isTypeParameter()) {
                paramType = gen.typeFact().getObjectType();
            }
            long flags = Flags.FINAL;
            // that looks fishy, perhaps we need to call non-widening rules instead
            JCExpression javaType = gen.makeJavaType(paramType, paramType.isRaw() ? AbstractTransformer.JT_RAW : 0);
            if (param.isSequenced()) {
                flags |= Flags.VARARGS;
                javaType = gen.make().TypeArray(javaType);
            }
            pdb.type(new TransformedType(javaType));
            pdb.modifiers(flags);
            callMethod.parameter(pdb);
            JCExpression arg;
            if (param.isSequenced()) {
                arg = gen.javaVariadicToSequential(paramType, param);
            } else {
                arg = gen.makeUnquotedIdent(param.getName());
                Type argumentType = parameterTypes.get(index);
                if (gen.isOptional(paramType) && argumentType.isSubtypeOf(gen.typeFact().getObjectType()) && !targetParam.getModel().hasUncheckedNullType()) {
                    arg = gen.utilInvocation().checkNull(arg);
                }
                Type simpleParamType = gen.simplifyType(paramType);
                // make unboxed java strings pass for ceylon strings so we can box them
                boolean unboxedString = gen.isJavaStringExactly(simpleParamType);
                if (unboxedString)
                    simpleParamType = gen.typeFact().getStringType();
                BoxingStrategy boxingStrategy = BoxingStrategy.BOXED;
                // in rare cases we don't want boxes
                if (unboxedString && gen.isJavaStringExactly(argumentType))
                    boxingStrategy = BoxingStrategy.UNBOXED;
                arg = gen.expressionGen().applyErasureAndBoxing(arg, simpleParamType, !(CodegenUtil.isUnBoxed(param.getModel()) || unboxedString), boxingStrategy, argumentType);
            }
            args.append(arg);
            index++;
        }
    } else {
    // no-arg getter
    }
    String callMethodName;
    if (variadic)
        callMethodName = Naming.getCallableVariadicMethodName();
    else
        callMethodName = Naming.getCallableMethodName();
    JCExpression call = gen.make().Apply(null, gen.makeUnquotedIdent(callMethodName), args.toList());
    JCStatement body;
    if (methodOrValue instanceof Function && ((Function) methodOrValue).isDeclaredVoid())
        body = gen.make().Exec(call);
    else {
        Type callableReturnType = gen.getReturnTypeOfCallable(typeModel);
        Type simpleReturnType = gen.simplifyType(returnType);
        boolean unboxed = CodegenUtil.isUnBoxed(methodOrValue) || gen.isJavaStringExactly(simpleReturnType);
        if (unboxed) {
            call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.UNBOXED, returnType);
        } else if (callableReturnType.isNull()) {
            // if the callable returns null and the SAM does not, we need a cast
            call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.INDIFFERENT, returnType);
        }
        body = gen.make().Return(call);
    }
    callMethod.body(body);
    return callMethod;
}
Also used : TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) Value(org.eclipse.ceylon.model.typechecker.model.Value) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) JCTypeParameter(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter) BoxingStrategy(org.eclipse.ceylon.compiler.java.codegen.AbstractTransformer.BoxingStrategy) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)

Aggregations

ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)67 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)53 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)30 Type (org.eclipse.ceylon.model.typechecker.model.Type)23 JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)22 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)20 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)16 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)16 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)15 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)14 JCAnnotation (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)13 JCNewClass (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)12 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)12 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)11 Function (org.eclipse.ceylon.model.typechecker.model.Function)10 Class (org.eclipse.ceylon.model.typechecker.model.Class)9 JCTypeParameter (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter)8 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)8 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)8 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)7