Search in sources :

Example 6 with MethodType

use of org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType in project ceylon by eclipse.

the class LambdaToMethod method visitLambda.

/**
 * Translate a lambda into a method to be inserted into the class.
 * Then replace the lambda site with an invokedynamic call of to lambda
 * meta-factory, which will use the lambda method.
 * @param tree
 */
@Override
public void visitLambda(JCLambda tree) {
    LambdaAnalyzerPreprocessor.LambdaTranslationContext localContext = (LambdaAnalyzerPreprocessor.LambdaTranslationContext) context;
    MethodSymbol sym = localContext.translatedSym;
    MethodType lambdaType = (MethodType) sym.type;
    {
        Symbol owner = localContext.owner;
        ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
        ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
        for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
            if (tc.position.onLambda == tree) {
                lambdaTypeAnnos.append(tc);
            } else {
                ownerTypeAnnos.append(tc);
            }
        }
        if (lambdaTypeAnnos.nonEmpty()) {
            owner.setTypeAttributes(ownerTypeAnnos.toList());
            sym.setTypeAttributes(lambdaTypeAnnos.toList());
        }
    }
    // create the method declaration hoisting the lambda body
    JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), sym.name, make.QualIdent(lambdaType.getReturnType().tsym), List.<JCTypeParameter>nil(), localContext.syntheticParams, lambdaType.getThrownTypes() == null ? List.<JCExpression>nil() : make.Types(lambdaType.getThrownTypes()), null, null);
    lambdaDecl.sym = sym;
    lambdaDecl.type = lambdaType;
    // translate lambda body
    // As the lambda body is translated, all references to lambda locals,
    // captured variables, enclosing members are adjusted accordingly
    // to refer to the static method parameters (rather than i.e. acessing to
    // captured members directly).
    lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
    // Add the method to the list of methods to be added to this class.
    kInfo.addMethod(lambdaDecl);
    // now that we have generated a method for the lambda expression,
    // we can translate the lambda into a method reference pointing to the newly
    // created method.
    // 
    // Note that we need to adjust the method handle so that it will match the
    // signature of the SAM descriptor - this means that the method reference
    // should be added the following synthetic arguments:
    // 
    // * the "this" argument if it is an instance method
    // * enclosing locals captured by the lambda expression
    ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
    if (localContext.methodReferenceReceiver != null) {
        syntheticInits.append(localContext.methodReferenceReceiver);
    } else if (!sym.isStatic()) {
        syntheticInits.append(makeThis(sym.owner.enclClass().asType(), localContext.owner.enclClass()));
    }
    // add captured locals
    for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
        if (fv != localContext.self) {
            JCTree captured_local = make.Ident(fv).setType(fv.type);
            syntheticInits.append((JCExpression) captured_local);
        }
    }
    // then, determine the arguments to the indy call
    List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
    // build a sam instance using an indy call to the meta-factory
    int refKind = referenceKind(sym);
    // convert to an invokedynamic call
    result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
}
Also used : MethodType(org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType) LambdaAnalyzerPreprocessor(org.eclipse.ceylon.langtools.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor) Attribute(org.eclipse.ceylon.langtools.tools.javac.code.Attribute) VarSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.VarSymbol) MethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.MethodSymbol) Symbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol) TypeSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.TypeSymbol) DynamicMethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.DynamicMethodSymbol) ClassSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.ClassSymbol) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) MethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.MethodSymbol) DynamicMethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.DynamicMethodSymbol)

Example 7 with MethodType

use of org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType in project ceylon by eclipse.

the class LambdaToMethod method addDeserializationCase.

private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
    String functionalInterfaceClass = classSig(targetType);
    String functionalInterfaceMethodName = samSym.getSimpleName().toString();
    String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
    String implClass = classSig(types.erasure(refSym.owner.type));
    String implMethodName = refSym.getQualifiedName().toString();
    String implMethodSignature = typeSig(types.erasure(refSym.type));
    JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
    ListBuffer<JCExpression> serArgs = new ListBuffer<>();
    int i = 0;
    for (Type t : indyType.getParameterTypes()) {
        List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
        List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
        serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
        ++i;
    }
    JCStatement stmt = make.If(deserTest(deserTest(deserTest(deserTest(deserTest(kindTest, "getFunctionalInterfaceClass", functionalInterfaceClass), "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), "getImplClass", implClass), "getImplMethodSignature", implMethodSignature), make.Return(makeIndyCall(pos, syms.lambdaMetafactory, names.altMetafactory, staticArgs, indyType, serArgs.toList(), samSym.name)), null);
    ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
    if (stmts == null) {
        stmts = new ListBuffer<>();
        kInfo.deserializeCases.put(implMethodName, stmts);
    }
    /**
     **
     *        System.err.printf("+++++++++++++++++\n");
     *        System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
     *        System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
     *        System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
     *        System.err.printf("*implMethodKind: %d\n", implMethodKind);
     *        System.err.printf("*implClass: '%s'\n", implClass);
     *        System.err.printf("*implMethodName: '%s'\n", implMethodName);
     *        System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
     ***
     */
    stmts.append(stmt);
}
Also used : MethodType(org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType) Type(org.eclipse.ceylon.langtools.tools.javac.code.Type)

Example 8 with MethodType

use of org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType in project ceylon by eclipse.

the class CeylonModelLoader method isFunctionalInterfaceType.

@Override
protected boolean isFunctionalInterfaceType(TypeMirror typeMirror) {
    if (typeMirror.getKind() != TypeKind.DECLARED)
        return false;
    // FIXME: possibly apply other optimisations to lighten the lookup cost? see what javac does
    Type type = ((JavacType) typeMirror).type;
    try {
        Type descriptorType = types.findDescriptorType(type);
        // Let's be honest I've no idea what this means, but it happens and Javac seems to refuse it too
        if (descriptorType.hasTag(TypeTag.FORALL))
            return false;
        MethodType methodDescriptorType = (MethodType) descriptorType;
        MethodSymbol methodSymbol = (MethodSymbol) types.findDescriptorSymbol(type.tsym);
        // make sure we can load them
        methodDescriptorType.complete();
        methodSymbol.complete();
        return true;
    } catch (Symbol.CompletionFailure err) {
        // bad luck
        return false;
    } catch (FunctionDescriptorLookupError err) {
        return false;
    }
}
Also used : JavacType(org.eclipse.ceylon.compiler.java.loader.mirror.JavacType) MethodType(org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType) MethodType(org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType) Type(org.eclipse.ceylon.langtools.tools.javac.code.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) ArrayType(org.eclipse.ceylon.langtools.tools.javac.code.Type.ArrayType) JavacType(org.eclipse.ceylon.compiler.java.loader.mirror.JavacType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) MethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.MethodSymbol) CompletionFailure(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.CompletionFailure) MethodSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.MethodSymbol) TypeSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.TypeSymbol) ClassSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.ClassSymbol) Symbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol) PackageSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.PackageSymbol) FunctionDescriptorLookupError(org.eclipse.ceylon.langtools.tools.javac.code.Types.FunctionDescriptorLookupError)

Aggregations

MethodType (org.eclipse.ceylon.langtools.tools.javac.code.Type.MethodType)8 Symbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol)7 ClassSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.ClassSymbol)7 MethodSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.MethodSymbol)7 TypeSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.TypeSymbol)7 DynamicMethodSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.DynamicMethodSymbol)5 VarSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.VarSymbol)5 Type (org.eclipse.ceylon.langtools.tools.javac.code.Type)5 JavacType (org.eclipse.ceylon.compiler.java.loader.mirror.JavacType)2 CompletionFailure (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.CompletionFailure)2 PackageSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.PackageSymbol)2 ArrayType (org.eclipse.ceylon.langtools.tools.javac.code.Type.ArrayType)2 FunctionDescriptorLookupError (org.eclipse.ceylon.langtools.tools.javac.code.Types.FunctionDescriptorLookupError)2 FunctionalInterfaceType (org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType)2 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)2 JavacClass (org.eclipse.ceylon.compiler.java.loader.mirror.JavacClass)1 JavacMethod (org.eclipse.ceylon.compiler.java.loader.mirror.JavacMethod)1 Attribute (org.eclipse.ceylon.langtools.tools.javac.code.Attribute)1 LambdaAnalyzerPreprocessor (org.eclipse.ceylon.langtools.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor)1 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)1