提交 9dba3531 编写于 作者: M mcimadamore

8066974: Compiler doesn't infer method's generic type information in lambda body

Summary: Add logic to avoid post-inference triggers on temporarty AST types
Reviewed-by: vromero
上级 5a704c32
......@@ -156,6 +156,8 @@ public class Attr extends JCTree.Visitor {
unknownTypeInfo = new ResultInfo(TYP, Type.noType);
unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
noCheckTree = make.at(-1).Skip();
}
/** Switch: relax some constraints for retrofit mode.
......@@ -253,31 +255,34 @@ public class Attr extends JCTree.Visitor {
Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
Type owntype;
if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
if ((ownkind & ~resultInfo.pkind) != 0) {
log.error(tree.pos(), "unexpected.type",
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 = resultInfo.pt;
inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
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 = resultInfo.check(tree, found);
}
});
} else {
owntype = found;
owntype = shouldCheck ?
resultInfo.check(tree, found) :
found;
}
if (tree != noCheckTree) {
tree.type = owntype;
}
tree.type = owntype;
return owntype;
}
......@@ -550,6 +555,10 @@ public class Attr extends JCTree.Visitor {
*/
Type result;
/** Synthetic tree to be used during 'fake' checks.
*/
JCTree noCheckTree;
/** Visitor method: attribute a tree, catching any completion failure
* exceptions. Return the tree's type.
*
......@@ -2043,7 +2052,7 @@ public class Attr extends JCTree.Visitor {
}
});
Type constructorType = tree.constructorType = types.createErrorType(clazztype);
constructorType = checkId(tree, site,
constructorType = checkId(noCheckTree, site,
constructor,
diamondEnv,
diamondResult);
......@@ -2069,7 +2078,7 @@ public class Attr extends JCTree.Visitor {
tree.constructor = rs.resolveConstructor(
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
if (cdef == null) { //do not check twice!
tree.constructorType = checkId(tree,
tree.constructorType = checkId(noCheckTree,
clazztype,
tree.constructor,
rsEnv,
......@@ -2150,7 +2159,7 @@ public class Attr extends JCTree.Visitor {
tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
Assert.check(sym.kind < AMBIGUOUS);
tree.constructor = sym;
tree.constructorType = checkId(tree,
tree.constructorType = checkId(noCheckTree,
clazztype,
tree.constructor,
localEnv,
......@@ -2161,6 +2170,17 @@ public class Attr extends JCTree.Visitor {
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);
}
//where
......@@ -2388,6 +2408,7 @@ public class Attr extends JCTree.Visitor {
preFlow(that);
flow.analyzeLambda(env, that, make, isSpeculativeRound);
that.type = currentTarget; //avoids recovery at this stage
checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
if (!isSpeculativeRound) {
......@@ -2826,7 +2847,7 @@ public class Attr extends JCTree.Visitor {
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes),
new FunctionalReturnContext(resultInfo.checkContext));
Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
Type refType = checkId(noCheckTree, lookupHelper.site, refSym, localEnv, checkInfo);
if (that.kind.isUnbound() &&
resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
......@@ -2848,6 +2869,8 @@ public class Attr extends JCTree.Visitor {
//is a no-op (as this has been taken care during method applicability)
boolean isSpeculativeRound =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
that.type = currentTarget; //avoids recovery at this stage
checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
if (!isSpeculativeRound) {
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
......@@ -3968,7 +3991,7 @@ public class Attr extends JCTree.Visitor {
all_multicatchTypes.append(ctype);
}
}
Type t = check(tree, types.lub(multicatchTypes.toList()), TYP, resultInfo);
Type t = check(noCheckTree, types.lub(multicatchTypes.toList()), TYP, resultInfo);
if (t.hasTag(CLASS)) {
List<Type> alternatives =
((all_multicatchTypes == null) ? multicatchTypes : all_multicatchTypes).toList();
......
/*
* @test /nodynamiccopyright/
* @bug 8066974
* @summary Compiler doesn't infer method's generic type information in lambda body
* @compile/fail/ref=T8066974.out -XDrawDiagnostics T8066974.java
*/
class T8066974 {
static class Throwing<E extends Throwable> { }
static class RuntimeThrowing extends Throwing<RuntimeException> { }
static class CheckedThrowing extends Throwing<Exception> { }
interface Parameter {
<E extends Throwable> Object m(Throwing<E> tw) throws E;
}
interface Mapper<R> {
R m(Parameter p);
}
<Z> Z map(Mapper<Z> mz) { return null; }
<Z extends Throwable> Mapper<Throwing<Z>> mapper(Throwing<Z> tz) throws Z { return null; }
static class ThrowingMapper<X extends Throwable> implements Mapper<Throwing<X>> {
ThrowingMapper(Throwing<X> arg) throws X { }
@Override
public Throwing<X> m(Parameter p) {
return null;
}
}
void testRuntime(RuntimeThrowing rt) {
map(p->p.m(rt));
map(mapper(rt));
map(new ThrowingMapper<>(rt));
}
void testChecked(CheckedThrowing ct) {
map(p->p.m(ct));
map(mapper(ct));
map(new ThrowingMapper<>(ct));
}
}
T8066974.java:40:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
T8066974.java:41:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
T8066974.java:42:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
3 errors
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册