Search in sources :

Example 1 with FreeTypeListener

use of org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener in project ceylon by eclipse.

the class Attr method setFunctionalInfo.

/**
 * Set functional type info on the underlying AST. Note: as the target descriptor
 * might contain inference variables, we might need to register an hook in the
 * current inference context.
 */
private void setFunctionalInfo(final Env<AttrContext> env, final JCFunctionalExpression fExpr, final Type pt, final Type descriptorType, final Type primaryTarget, final CheckContext checkContext) {
    if (checkContext.inferenceContext().free(descriptorType)) {
        checkContext.inferenceContext().addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {

            public void typesInferred(InferenceContext inferenceContext) {
                setFunctionalInfo(env, fExpr, pt, inferenceContext.asInstType(descriptorType), inferenceContext.asInstType(primaryTarget), checkContext);
            }
        });
    } else {
        ListBuffer<Type> targets = new ListBuffer<>();
        if (pt.hasTag(CLASS)) {
            if (pt.isCompound()) {
                // this goes first
                targets.append(types.removeWildcards(primaryTarget));
                for (Type t : ((IntersectionClassType) pt()).interfaces_field) {
                    if (t != primaryTarget) {
                        targets.append(types.removeWildcards(t));
                    }
                }
            } else {
                targets.append(types.removeWildcards(primaryTarget));
            }
        }
        fExpr.targets = targets.toList();
        if (checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK && pt != Type.recoveryType) {
            // check that functional interface class is well-formed
            try {
                /* Types.makeFunctionalInterfaceClass() may throw an exception
                     * when it's executed post-inference. See the listener code
                     * above.
                     */
                ClassSymbol csym = types.makeFunctionalInterfaceClass(env, names.empty, List.of(fExpr.targets.head), ABSTRACT);
                if (csym != null) {
                    chk.checkImplementations(env.tree, csym, csym);
                }
            } catch (Types.FunctionDescriptorLookupError ex) {
                JCDiagnostic cause = ex.getDiagnostic();
                resultInfo.checkContext.report(env.tree, cause);
            }
        }
    }
}
Also used : Type(org.eclipse.ceylon.langtools.tools.javac.code.Type) InferenceContext(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.InferenceContext) FreeTypeListener(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener)

Example 2 with FreeTypeListener

use of org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener in project ceylon by eclipse.

the class Check method checkMethod.

Type checkMethod(final Type mtype, final Symbol sym, final Env<AttrContext> env, final List<JCExpression> argtrees, final List<Type> argtypes, final boolean useVarargs, InferenceContext inferenceContext) {
    // System.out.println("actuals: " + argtypes);
    if (inferenceContext.free(mtype)) {
        inferenceContext.addFreeTypeListener(List.of(mtype), new FreeTypeListener() {

            public void typesInferred(InferenceContext inferenceContext) {
                checkMethod(inferenceContext.asInstType(mtype), sym, env, argtrees, argtypes, useVarargs, inferenceContext);
            }
        });
        return mtype;
    }
    Type owntype = mtype;
    List<Type> formals = owntype.getParameterTypes();
    List<Type> nonInferred = sym.type.getParameterTypes();
    if (nonInferred.length() != formals.length())
        nonInferred = formals;
    Type last = useVarargs ? formals.last() : null;
    if (sym.name == names.init && sym.owner == syms.enumSym) {
        formals = formals.tail.tail;
        nonInferred = nonInferred.tail.tail;
    }
    List<JCExpression> args = argtrees;
    if (args != null) {
        // this is null when type-checking a method reference
        while (formals.head != last) {
            JCTree arg = args.head;
            Warner warn = convertWarner(arg.pos(), arg.type, nonInferred.head);
            assertConvertible(arg, arg.type, formals.head, warn);
            args = args.tail;
            formals = formals.tail;
            nonInferred = nonInferred.tail;
        }
        if (useVarargs) {
            Type varArg = types.elemtype(last);
            while (args.tail != null) {
                JCTree arg = args.head;
                Warner warn = convertWarner(arg.pos(), arg.type, varArg);
                assertConvertible(arg, arg.type, varArg, warn);
                args = args.tail;
            }
        } else if ((sym.flags() & (VARARGS | SIGNATURE_POLYMORPHIC)) == VARARGS && allowVarargs) {
            // non-varargs call to varargs method
            Type varParam = owntype.getParameterTypes().last();
            Type lastArg = argtypes.last();
            if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) && !types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
                log.warning(argtrees.last().pos(), "inexact.non-varargs.call", types.elemtype(varParam), varParam);
        }
    }
    if (useVarargs) {
        Type argtype = owntype.getParameterTypes().last();
        if (!types.isReifiable(argtype) && (!allowSimplifiedVarargs || sym.attribute(syms.trustMeType.tsym) == null || !isTrustMeAllowedOnMethod(sym))) {
            warnUnchecked(env.tree.pos(), "unchecked.generic.array.creation", argtype);
        }
        if ((sym.baseSymbol().flags() & SIGNATURE_POLYMORPHIC) == 0) {
            TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype));
        }
    }
    PolyKind pkind = (sym.type.hasTag(FORALL) && sym.type.getReturnType().containsAny(((ForAll) sym.type).tvars)) ? PolyKind.POLY : PolyKind.STANDALONE;
    TreeInfo.setPolyKind(env.tree, pkind);
    return owntype;
}
Also used : Type(org.eclipse.ceylon.langtools.tools.javac.code.Type) InferenceContext(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.InferenceContext) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) FreeTypeListener(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener)

Example 3 with FreeTypeListener

use of org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener in project ceylon by eclipse.

the class Attr method check.

/**
 * Check kind and type of given tree against protokind and prototype.
 *  If check succeeds, store type in tree and return it.
 *  If check fails, store errType in tree and return it.
 *  No checks are performed if the prototype is a method type.
 *  It is not necessary in this case since we know that kind and type
 *  are correct.
 *
 *  @param tree     The tree whose kind and type is checked
 *  @param ownkind  The computed kind of the tree
 *  @param resultInfo  The expected result of the tree
 */
Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
    InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
    Type owntype;
    boolean shouldCheck = !found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL);
    if (shouldCheck && (ownkind & ~resultInfo.pkind) != 0) {
        log.error(tree.pos(), "unexpected.type", kindNames(resultInfo.pkind), kindName(ownkind));
        owntype = types.createErrorType(found);
    } else if (allowPoly && inferenceContext.free(found)) {
        // delay the check if there are inference variables in the found type
        // this means we are dealing with a partially inferred poly expression
        owntype = shouldCheck ? resultInfo.pt : found;
        inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {

            @Override
            public void typesInferred(InferenceContext inferenceContext) {
                ResultInfo pendingResult = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
                check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
            }
        });
    } else {
        owntype = shouldCheck ? resultInfo.check(tree, found) : found;
    }
    if (tree != noCheckTree) {
        tree.type = owntype;
    }
    return owntype;
}
Also used : Type(org.eclipse.ceylon.langtools.tools.javac.code.Type) InferenceContext(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.InferenceContext) FreeTypeListener(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener)

Example 4 with FreeTypeListener

use of org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener in project ceylon by eclipse.

the class Attr method visitNewClass.

public void visitNewClass(final JCNewClass tree) {
    Type owntype = types.createErrorType(tree.type);
    // The local environment of a class creation is
    // a new environment nested in the current one.
    Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
    // The anonymous inner class definition of the new expression,
    // if one is defined by it.
    JCClassDecl cdef = tree.def;
    // If enclosing class is given, attribute it, and
    // complete class name to be fully qualified
    // Class field following new
    JCExpression clazz = tree.clazz;
    // Identifier in class field
    JCExpression clazzid;
    // Annotated type enclosing clazzid
    JCAnnotatedType annoclazzid;
    annoclazzid = null;
    if (clazz.hasTag(TYPEAPPLY)) {
        clazzid = ((JCTypeApply) clazz).clazz;
        if (clazzid.hasTag(ANNOTATED_TYPE)) {
            annoclazzid = (JCAnnotatedType) clazzid;
            clazzid = annoclazzid.underlyingType;
        }
    } else {
        if (clazz.hasTag(ANNOTATED_TYPE)) {
            annoclazzid = (JCAnnotatedType) clazz;
            clazzid = annoclazzid.underlyingType;
        } else {
            clazzid = clazz;
        }
    }
    // The same in fully qualified form
    JCExpression clazzid1 = clazzid;
    if (tree.encl != null) {
        // We are seeing a qualified new, of the form
        // <expr>.new C <...> (...) ...
        // In this case, we let clazz stand for the name of the
        // allocated class C prefixed with the type of the qualifier
        // expression, so that we can
        // resolve it with standard techniques later. I.e., if
        // <expr> has type T, then <expr>.new C <...> (...)
        // yields a clazz T.C.
        Type encltype = chk.checkRefType(tree.encl.pos(), attribExpr(tree.encl, env));
        // TODO 308: in <expr>.new C, do we also want to add the type annotations
        // from expr to the combined type, or not? Yes, do this.
        clazzid1 = make.at(clazz.pos).Select(make.Type(encltype), ((JCIdent) clazzid).name);
        EndPosTable endPosTable = this.env.toplevel.endPositions;
        endPosTable.storeEnd(clazzid1, tree.getEndPosition(endPosTable));
        if (clazz.hasTag(ANNOTATED_TYPE)) {
            JCAnnotatedType annoType = (JCAnnotatedType) clazz;
            List<JCAnnotation> annos = annoType.annotations;
            if (annoType.underlyingType.hasTag(TYPEAPPLY)) {
                clazzid1 = make.at(tree.pos).TypeApply(clazzid1, ((JCTypeApply) clazz).arguments);
            }
            clazzid1 = make.at(tree.pos).AnnotatedType(annos, clazzid1);
        } else if (clazz.hasTag(TYPEAPPLY)) {
            clazzid1 = make.at(tree.pos).TypeApply(clazzid1, ((JCTypeApply) clazz).arguments);
        }
        clazz = clazzid1;
    }
    // Attribute clazz expression and store
    // symbol + type back into the attributed tree.
    Type clazztype = TreeInfo.isEnumInit(env.tree) ? attribIdentAsEnumType(env, (JCIdent) clazz) : attribType(clazz, env);
    clazztype = chk.checkDiamond(tree, clazztype);
    chk.validate(clazz, localEnv);
    if (tree.encl != null) {
        // We have to work in this case to store
        // symbol + type back into the attributed tree.
        tree.clazz.type = clazztype;
        TreeInfo.setSymbol(clazzid, TreeInfo.symbol(clazzid1));
        clazzid.type = ((JCIdent) clazzid).sym.type;
        if (annoclazzid != null) {
            annoclazzid.type = clazzid.type;
        }
        if (!clazztype.isErroneous()) {
            if (cdef != null && clazztype.tsym.isInterface()) {
                log.error(tree.encl.pos(), "anon.class.impl.intf.no.qual.for.new");
            } else if (clazztype.tsym.isStatic()) {
                log.error(tree.encl.pos(), "qualified.new.of.static.class", clazztype.tsym);
            }
        }
    } else if (!clazztype.tsym.isInterface() && clazztype.getEnclosingType().hasTag(CLASS)) {
        // Check for the existence of an apropos outer instance
        rs.resolveImplicitThis(tree.pos(), env, clazztype);
    }
    // Attribute constructor arguments.
    ListBuffer<Type> argtypesBuf = new ListBuffer<>();
    int pkind = attribArgs(VAL, tree.args, localEnv, argtypesBuf);
    List<Type> argtypes = argtypesBuf.toList();
    List<Type> typeargtypes = attribTypes(tree.typeargs, localEnv);
    // If we have made no mistakes in the class type...
    if (clazztype.hasTag(CLASS)) {
        // Enums may not be instantiated except implicitly
        if (allowEnums && (clazztype.tsym.flags_field & Flags.ENUM) != 0 && (!env.tree.hasTag(VARDEF) || (((JCVariableDecl) env.tree).mods.flags & Flags.ENUM) == 0 || ((JCVariableDecl) env.tree).init != tree))
            log.error(tree.pos(), "enum.cant.be.instantiated");
        // Check that class is not abstract
        if (cdef == null && (clazztype.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
            log.error(tree.pos(), "abstract.cant.be.instantiated", clazztype.tsym);
        } else if (cdef != null && clazztype.tsym.isInterface()) {
            // anonymous classes implementing an interface
            if (!argtypes.isEmpty())
                log.error(tree.args.head.pos(), "anon.class.impl.intf.no.args");
            if (!typeargtypes.isEmpty())
                log.error(tree.typeargs.head.pos(), "anon.class.impl.intf.no.typeargs");
            // Error recovery: pretend no arguments were supplied.
            argtypes = List.nil();
            typeargtypes = List.nil();
        } else if (TreeInfo.isDiamond(tree)) {
            ClassType site = new ClassType(clazztype.getEnclosingType(), clazztype.tsym.type.getTypeArguments(), clazztype.tsym);
            Env<AttrContext> diamondEnv = localEnv.dup(tree);
            diamondEnv.info.selectSuper = cdef != null;
            diamondEnv.info.pendingResolutionPhase = null;
            // if the type of the instance creation expression is a class type
            // apply method resolution inference (JLS 15.12.2.7). The return type
            // of the resolved constructor will be a partially instantiated type
            Symbol constructor = rs.resolveDiamond(tree.pos(), diamondEnv, site, argtypes, typeargtypes);
            tree.constructor = constructor.baseSymbol();
            final TypeSymbol csym = clazztype.tsym;
            ResultInfo diamondResult = new ResultInfo(pkind, newMethodTemplate(resultInfo.pt, argtypes, typeargtypes), new Check.NestedCheckContext(resultInfo.checkContext) {

                @Override
                public void report(DiagnosticPosition _unused, JCDiagnostic details) {
                    enclosingContext.report(tree.clazz, diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", csym), details));
                }
            });
            Type constructorType = tree.constructorType = types.createErrorType(clazztype);
            constructorType = checkId(noCheckTree, site, constructor, diamondEnv, diamondResult);
            tree.clazz.type = types.createErrorType(clazztype);
            if (!constructorType.isErroneous()) {
                tree.clazz.type = clazztype = constructorType.getReturnType();
                tree.constructorType = types.createMethodTypeWithReturn(constructorType, syms.voidType);
            }
            clazztype = chk.checkClassType(tree.clazz, tree.clazz.type, true);
        } else // Resolve the called constructor under the assumption
        // that we are referring to a superclass instance of the
        // current instance (JLS ???).
        {
            // the following code alters some of the fields in the current
            // AttrContext - hence, the current context must be dup'ed in
            // order to avoid downstream failures
            Env<AttrContext> rsEnv = localEnv.dup(tree);
            rsEnv.info.selectSuper = cdef != null;
            rsEnv.info.pendingResolutionPhase = null;
            tree.constructor = rs.resolveConstructor(tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
            if (cdef == null) {
                // do not check twice!
                tree.constructorType = checkId(noCheckTree, clazztype, tree.constructor, rsEnv, new ResultInfo(pkind, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
                if (rsEnv.info.lastResolveVarargs())
                    Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
            }
            if (cdef == null && !clazztype.isErroneous() && clazztype.getTypeArguments().nonEmpty() && findDiamonds) {
                findDiamond(localEnv, tree, clazztype);
            }
        }
        if (cdef != null) {
            // }
            if (Resolve.isStatic(env))
                cdef.mods.flags |= STATIC;
            if (clazztype.tsym.isInterface()) {
                cdef.implementing = List.of(clazz);
            } else {
                cdef.extending = clazz;
            }
            if (resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK && isSerializable(clazztype)) {
                localEnv.info.isSerializable = true;
            }
            attribStat(cdef, localEnv);
            checkLambdaCandidate(tree, cdef.sym, clazztype);
            // and delete it from the new expression
            if (tree.encl != null && !clazztype.tsym.isInterface()) {
                tree.args = tree.args.prepend(makeNullCheck(tree.encl));
                argtypes = argtypes.prepend(tree.encl.type);
                tree.encl = null;
            }
            // Reassign clazztype and recompute constructor.
            clazztype = cdef.sym.type;
            Symbol sym = tree.constructor = rs.resolveConstructor(tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
            Assert.check(sym.kind < AMBIGUOUS);
            tree.constructor = sym;
            tree.constructorType = checkId(noCheckTree, clazztype, tree.constructor, localEnv, new ResultInfo(pkind, newMethodTemplate(syms.voidType, argtypes, typeargtypes)));
        }
        if (tree.constructor != null && tree.constructor.kind == MTH)
            owntype = clazztype;
    }
    result = check(tree, owntype, VAL, resultInfo);
    InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
    if (tree.constructorType != null && inferenceContext.free(tree.constructorType)) {
        // we need to wait for inference to finish and then replace inference vars in the constructor type
        inferenceContext.addFreeTypeListener(List.of(tree.constructorType), new FreeTypeListener() {

            @Override
            public void typesInferred(InferenceContext instantiatedContext) {
                tree.constructorType = instantiatedContext.asInstType(tree.constructorType);
            }
        });
    }
    chk.validate(tree.typeargs, localEnv);
}
Also used : Symbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol) DiagnosticPosition(org.eclipse.ceylon.langtools.tools.javac.util.JCDiagnostic.DiagnosticPosition) FreeTypeListener(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener) InferenceContext(org.eclipse.ceylon.langtools.tools.javac.comp.Infer.InferenceContext) Type(org.eclipse.ceylon.langtools.tools.javac.code.Type)

Aggregations

Type (org.eclipse.ceylon.langtools.tools.javac.code.Type)4 FreeTypeListener (org.eclipse.ceylon.langtools.tools.javac.comp.Infer.FreeTypeListener)4 InferenceContext (org.eclipse.ceylon.langtools.tools.javac.comp.Infer.InferenceContext)4 Symbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol)1 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)1 DiagnosticPosition (org.eclipse.ceylon.langtools.tools.javac.util.JCDiagnostic.DiagnosticPosition)1