use of org.eclipse.ceylon.langtools.tools.javac.code.Type in project ceylon by eclipse.
the class Infer method instantiateMethod.
// <editor-fold defaultstate="collapsed" desc="Inference routines">
/**
* Main inference entry point - instantiate a generic method type
* using given argument types and (possibly) an expected target-type.
*/
Type instantiateMethod(Env<AttrContext> env, List<Type> tvars, MethodType mt, Attr.ResultInfo resultInfo, MethodSymbol msym, List<Type> argtypes, boolean allowBoxing, boolean useVarargs, Resolve.MethodResolutionContext resolveContext, Warner warn) throws InferenceException {
// -System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
// B0
final InferenceContext inferenceContext = new InferenceContext(tvars);
inferenceException.clear();
try {
DeferredAttr.DeferredAttrContext deferredAttrContext = resolveContext.deferredAttrContext(msym, inferenceContext, resultInfo, warn);
// B2
resolveContext.methodCheck.argumentsAcceptable(// B2
env, // B2
deferredAttrContext, argtypes, mt.getParameterTypes(), warn);
if (allowGraphInference && resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
// inject return constraints earlier
// propagation
checkWithinBounds(inferenceContext, warn);
Type newRestype = generateReturnConstraints(// B3
env.tree, // B3
resultInfo, mt, inferenceContext);
mt = (MethodType) types.createMethodTypeWithReturn(mt, newRestype);
// propagate outwards if needed
if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
// propagate inference context outwards and exit
inferenceContext.dupTo(resultInfo.checkContext.inferenceContext());
deferredAttrContext.complete();
return mt;
}
}
deferredAttrContext.complete();
// minimize as yet undetermined type variables
if (allowGraphInference) {
inferenceContext.solve(warn);
} else {
// minimizeInst
inferenceContext.solveLegacy(true, warn, LegacyInferenceSteps.EQ_LOWER.steps);
}
mt = (MethodType) inferenceContext.asInstType(mt);
if (!allowGraphInference && inferenceContext.restvars().nonEmpty() && resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
generateReturnConstraints(env.tree, resultInfo, mt, inferenceContext);
// maximizeInst
inferenceContext.solveLegacy(false, warn, LegacyInferenceSteps.EQ_UPPER.steps);
mt = (MethodType) inferenceContext.asInstType(mt);
}
if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
}
// return instantiated version of method type
return mt;
} finally {
if (resultInfo != null || !allowGraphInference) {
inferenceContext.notifyChange();
} else {
inferenceContext.notifyChange(inferenceContext.boundedVars());
}
if (resultInfo == null) {
/* if the is no result info then we can clear the capture types
* cache without affecting any result info check
*/
inferenceContext.captureTypeCache.clear();
}
}
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Type in project ceylon by eclipse.
the class Infer method generateReturnConstraints.
/**
* Generate constraints from the generic method's return type. If the method
* call occurs in a context where a type T is expected, use the expected
* type to derive more constraints on the generic method inference variables.
*/
Type generateReturnConstraints(JCTree tree, Attr.ResultInfo resultInfo, MethodType mt, InferenceContext inferenceContext) {
InferenceContext rsInfoInfContext = resultInfo.checkContext.inferenceContext();
Type from = mt.getReturnType();
if (mt.getReturnType().containsAny(inferenceContext.inferencevars) && rsInfoInfContext != emptyContext) {
from = types.capture(from);
// add synthetic captured ivars
for (Type t : from.getTypeArguments()) {
if (t.hasTag(TYPEVAR) && ((TypeVar) t).isCaptured()) {
inferenceContext.addVar((TypeVar) t);
}
}
}
Type qtype = inferenceContext.asUndetVar(from);
Type to = resultInfo.pt;
if (qtype.hasTag(VOID)) {
to = syms.voidType;
} else if (to.hasTag(NONE)) {
to = from.isPrimitive() ? from : syms.objectType;
} else if (qtype.hasTag(UNDETVAR)) {
if (resultInfo.pt.isReference()) {
to = generateReturnConstraintsUndetVarToReference(tree, (UndetVar) qtype, to, resultInfo, inferenceContext);
} else {
if (to.isPrimitive()) {
to = generateReturnConstraintsPrimitive(tree, (UndetVar) qtype, to, resultInfo, inferenceContext);
}
}
}
Assert.check(allowGraphInference || !rsInfoInfContext.free(to), "legacy inference engine cannot handle constraints on both sides of a subtyping assertion");
// we need to skip capture?
Warner retWarn = new Warner();
if (!resultInfo.checkContext.compatible(qtype, rsInfoInfContext.asUndetVar(to), retWarn) || // unchecked conversion is not allowed in source 7 mode
(!allowGraphInference && retWarn.hasLint(Lint.LintCategory.UNCHECKED))) {
throw inferenceException.setMessage("infer.no.conforming.instance.exists", inferenceContext.restvars(), mt.getReturnType(), to);
}
return from;
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Type in project ceylon by eclipse.
the class LambdaToMethod method makeLambdaExpressionBody.
private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
Type restype = lambdaMethodDecl.type.getReturnType();
boolean isLambda_void = expr.type.hasTag(VOID);
boolean isTarget_void = restype.hasTag(VOID);
boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
int prevPos = make.pos;
try {
if (isTarget_void) {
// target is void:
// BODY;
JCStatement stat = make.at(expr).Exec(expr);
return make.Block(0, List.<JCStatement>of(stat));
} else if (isLambda_void && isTarget_Void) {
// void to Void conversion:
// BODY; return null;
ListBuffer<JCStatement> stats = new ListBuffer<>();
stats.append(make.at(expr).Exec(expr));
stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
return make.Block(0, stats.toList());
} else {
// non-void to non-void conversion:
// return (TYPE)BODY;
JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
}
} finally {
make.at(prevPos);
}
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Type in project ceylon by eclipse.
the class LambdaToMethod method makeMetafactoryIndyCall.
/**
* Generate an indy method call to the meta factory
*/
private JCExpression makeMetafactoryIndyCall(LambdaAnalyzerPreprocessor.TranslationContext<?> context, int refKind, Symbol refSym, List<JCExpression> indy_args) {
JCFunctionalExpression tree = context.tree;
// determine the static bsm args
MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
List<Object> staticArgs = List.<Object>of(typeToMethodType(samSym.type), new Pool.MethodHandle(refKind, refSym, types), typeToMethodType(tree.getDescriptorType(types)));
// computed indy arg types
ListBuffer<Type> indy_args_types = new ListBuffer<>();
for (JCExpression arg : indy_args) {
indy_args_types.append(arg.type);
}
// finally, compute the type of the indy call
MethodType indyType = new MethodType(indy_args_types.toList(), tree.type, List.<Type>nil(), syms.methodClass);
Name metafactoryName = context.needsAltMetafactory() ? names.altMetafactory : names.metafactory;
if (context.needsAltMetafactory()) {
ListBuffer<Object> markers = new ListBuffer<>();
for (Type t : tree.targets.tail) {
if (t.tsym != syms.serializableType.tsym) {
markers.append(t.tsym);
}
}
int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
boolean hasMarkers = markers.nonEmpty();
boolean hasBridges = context.bridges.nonEmpty();
if (hasMarkers) {
flags |= FLAG_MARKERS;
}
if (hasBridges) {
flags |= FLAG_BRIDGES;
}
staticArgs = staticArgs.append(flags);
if (hasMarkers) {
staticArgs = staticArgs.append(markers.length());
staticArgs = staticArgs.appendList(markers.toList());
}
if (hasBridges) {
staticArgs = staticArgs.append(context.bridges.length() - 1);
for (Symbol s : context.bridges) {
Type s_erasure = s.erasure(types);
if (!types.isSameType(s_erasure, samSym.erasure(types))) {
staticArgs = staticArgs.append(s.erasure(types));
}
}
}
if (context.isSerializable()) {
int prevPos = make.pos;
try {
make.at(kInfo.clazz);
addDeserializationCase(refKind, refSym, tree.type, samSym, tree, staticArgs, indyType);
} finally {
make.at(prevPos);
}
}
}
return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
}
use of org.eclipse.ceylon.langtools.tools.javac.code.Type in project ceylon by eclipse.
the class LambdaToMethod method makeLambdaStatementBody.
private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
final Type restype = lambdaMethodDecl.type.getReturnType();
final boolean isTarget_void = restype.hasTag(VOID);
boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
class LambdaBodyTranslator extends TreeTranslator {
@Override
public void visitClassDef(JCClassDecl tree) {
// do NOT recurse on any inner classes
result = tree;
}
@Override
public void visitLambda(JCLambda tree) {
// do NOT recurse on any nested lambdas
result = tree;
}
@Override
public void visitReturn(JCReturn tree) {
boolean isLambda_void = tree.expr == null;
if (isTarget_void && !isLambda_void) {
// Void to void conversion:
// { TYPE $loc = RET-EXPR; return; }
VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
JCVariableDecl varDef = make.VarDef(loc, tree.expr);
result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
} else if (!isTarget_void || !isLambda_void) {
// non-void to non-void conversion:
// return (TYPE)RET-EXPR;
tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
result = tree;
} else {
result = tree;
}
}
}
JCBlock trans_block = new LambdaBodyTranslator().translate(block);
if (completeNormally && isTarget_Void) {
// there's no return statement and the lambda (possibly inferred)
// return type is java.lang.Void; emit a synthetic return statement
trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
}
return trans_block;
}
Aggregations