提交 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 { ...@@ -156,6 +156,8 @@ public class Attr extends JCTree.Visitor {
unknownTypeInfo = new ResultInfo(TYP, Type.noType); unknownTypeInfo = new ResultInfo(TYP, Type.noType);
unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType); unknownTypeExprInfo = new ResultInfo(Kinds.TYP | Kinds.VAL, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext); recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
noCheckTree = make.at(-1).Skip();
} }
/** Switch: relax some constraints for retrofit mode. /** Switch: relax some constraints for retrofit mode.
...@@ -253,31 +255,34 @@ public class Attr extends JCTree.Visitor { ...@@ -253,31 +255,34 @@ public class Attr extends JCTree.Visitor {
Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) { Type check(final JCTree tree, final Type found, final int ownkind, final ResultInfo resultInfo) {
InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext(); InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
Type owntype; Type owntype;
if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) { boolean shouldCheck = !found.hasTag(ERROR) &&
if ((ownkind & ~resultInfo.pkind) != 0) { !resultInfo.pt.hasTag(METHOD) &&
log.error(tree.pos(), "unexpected.type", !resultInfo.pt.hasTag(FORALL);
if (shouldCheck && (ownkind & ~resultInfo.pkind) != 0) {
log.error(tree.pos(), "unexpected.type",
kindNames(resultInfo.pkind), kindNames(resultInfo.pkind),
kindName(ownkind)); kindName(ownkind));
owntype = types.createErrorType(found); owntype = types.createErrorType(found);
} else if (allowPoly && inferenceContext.free(found)) { } else if (allowPoly && inferenceContext.free(found)) {
//delay the check if there are inference variables in the found type //delay the check if there are inference variables in the found type
//this means we are dealing with a partially inferred poly expression //this means we are dealing with a partially inferred poly expression
owntype = resultInfo.pt; owntype = shouldCheck ? resultInfo.pt : found;
inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() { inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
@Override @Override
public void typesInferred(InferenceContext inferenceContext) { public void typesInferred(InferenceContext inferenceContext) {
ResultInfo pendingResult = ResultInfo pendingResult =
resultInfo.dup(inferenceContext.asInstType(resultInfo.pt)); resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
check(tree, inferenceContext.asInstType(found), ownkind, pendingResult); check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
} }
}); });
} else {
owntype = resultInfo.check(tree, found);
}
} else { } else {
owntype = found; owntype = shouldCheck ?
resultInfo.check(tree, found) :
found;
}
if (tree != noCheckTree) {
tree.type = owntype;
} }
tree.type = owntype;
return owntype; return owntype;
} }
...@@ -550,6 +555,10 @@ public class Attr extends JCTree.Visitor { ...@@ -550,6 +555,10 @@ public class Attr extends JCTree.Visitor {
*/ */
Type result; Type result;
/** Synthetic tree to be used during 'fake' checks.
*/
JCTree noCheckTree;
/** Visitor method: attribute a tree, catching any completion failure /** Visitor method: attribute a tree, catching any completion failure
* exceptions. Return the tree's type. * exceptions. Return the tree's type.
* *
...@@ -2043,7 +2052,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2043,7 +2052,7 @@ public class Attr extends JCTree.Visitor {
} }
}); });
Type constructorType = tree.constructorType = types.createErrorType(clazztype); Type constructorType = tree.constructorType = types.createErrorType(clazztype);
constructorType = checkId(tree, site, constructorType = checkId(noCheckTree, site,
constructor, constructor,
diamondEnv, diamondEnv,
diamondResult); diamondResult);
...@@ -2069,7 +2078,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2069,7 +2078,7 @@ public class Attr extends JCTree.Visitor {
tree.constructor = rs.resolveConstructor( tree.constructor = rs.resolveConstructor(
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes); tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
if (cdef == null) { //do not check twice! if (cdef == null) { //do not check twice!
tree.constructorType = checkId(tree, tree.constructorType = checkId(noCheckTree,
clazztype, clazztype,
tree.constructor, tree.constructor,
rsEnv, rsEnv,
...@@ -2150,7 +2159,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2150,7 +2159,7 @@ public class Attr extends JCTree.Visitor {
tree.pos(), localEnv, clazztype, argtypes, typeargtypes); tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
Assert.check(sym.kind < AMBIGUOUS); Assert.check(sym.kind < AMBIGUOUS);
tree.constructor = sym; tree.constructor = sym;
tree.constructorType = checkId(tree, tree.constructorType = checkId(noCheckTree,
clazztype, clazztype,
tree.constructor, tree.constructor,
localEnv, localEnv,
...@@ -2161,6 +2170,17 @@ public class Attr extends JCTree.Visitor { ...@@ -2161,6 +2170,17 @@ public class Attr extends JCTree.Visitor {
owntype = clazztype; owntype = clazztype;
} }
result = check(tree, owntype, VAL, resultInfo); 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); chk.validate(tree.typeargs, localEnv);
} }
//where //where
...@@ -2388,6 +2408,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2388,6 +2408,7 @@ public class Attr extends JCTree.Visitor {
preFlow(that); preFlow(that);
flow.analyzeLambda(env, that, make, isSpeculativeRound); flow.analyzeLambda(env, that, make, isSpeculativeRound);
that.type = currentTarget; //avoids recovery at this stage
checkLambdaCompatible(that, lambdaType, resultInfo.checkContext); checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
if (!isSpeculativeRound) { if (!isSpeculativeRound) {
...@@ -2826,7 +2847,7 @@ public class Attr extends JCTree.Visitor { ...@@ -2826,7 +2847,7 @@ public class Attr extends JCTree.Visitor {
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes), that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes),
new FunctionalReturnContext(resultInfo.checkContext)); 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() && if (that.kind.isUnbound() &&
resultInfo.checkContext.inferenceContext().free(argtypes.head)) { resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
...@@ -2848,6 +2869,8 @@ public class Attr extends JCTree.Visitor { ...@@ -2848,6 +2869,8 @@ public class Attr extends JCTree.Visitor {
//is a no-op (as this has been taken care during method applicability) //is a no-op (as this has been taken care during method applicability)
boolean isSpeculativeRound = boolean isSpeculativeRound =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE; resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
that.type = currentTarget; //avoids recovery at this stage
checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound); checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
if (!isSpeculativeRound) { if (!isSpeculativeRound) {
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget); checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
...@@ -3968,7 +3991,7 @@ public class Attr extends JCTree.Visitor { ...@@ -3968,7 +3991,7 @@ public class Attr extends JCTree.Visitor {
all_multicatchTypes.append(ctype); 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)) { if (t.hasTag(CLASS)) {
List<Type> alternatives = List<Type> alternatives =
((all_multicatchTypes == null) ? multicatchTypes : all_multicatchTypes).toList(); ((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.
先完成此消息的编辑!
想要评论请 注册