mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-10 05:29:48 +00:00
8176534: Missing check against target-type during applicability inference
PartiallyInferredMethodType should check against target if unchecked conversion occurred Reviewed-by: vromero
This commit is contained in:
parent
828abbabee
commit
5770a10028
@ -190,28 +190,29 @@ public class Infer {
|
||||
doIncorporation(inferenceContext, warn);
|
||||
//we are inside method attribution - just return a partially inferred type
|
||||
return new PartiallyInferredMethodType(mt, inferenceContext, env, warn);
|
||||
} else if (allowGraphInference &&
|
||||
resultInfo != null &&
|
||||
!warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
|
||||
} else if (allowGraphInference && resultInfo != null) {
|
||||
|
||||
//inject return constraints earlier
|
||||
doIncorporation(inferenceContext, warn); //propagation
|
||||
|
||||
boolean shouldPropagate = shouldPropagate(mt.getReturnType(), resultInfo, inferenceContext);
|
||||
if (!warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
|
||||
boolean shouldPropagate = shouldPropagate(mt.getReturnType(), resultInfo, inferenceContext);
|
||||
|
||||
InferenceContext minContext = shouldPropagate ?
|
||||
inferenceContext.min(roots(mt, deferredAttrContext), true, warn) :
|
||||
inferenceContext;
|
||||
InferenceContext minContext = shouldPropagate ?
|
||||
inferenceContext.min(roots(mt, deferredAttrContext), true, warn) :
|
||||
inferenceContext;
|
||||
|
||||
Type newRestype = generateReturnConstraints(env.tree, resultInfo, //B3
|
||||
mt, minContext);
|
||||
mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype);
|
||||
Type newRestype = generateReturnConstraints(env.tree, resultInfo, //B3
|
||||
mt, minContext);
|
||||
mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype);
|
||||
|
||||
//propagate outwards if needed
|
||||
if (shouldPropagate) {
|
||||
//propagate inference context outwards and exit
|
||||
minContext.dupTo(resultInfo.checkContext.inferenceContext());
|
||||
deferredAttrContext.complete();
|
||||
return mt;
|
||||
//propagate outwards if needed
|
||||
if (shouldPropagate) {
|
||||
//propagate inference context outwards and exit
|
||||
minContext.dupTo(resultInfo.checkContext.inferenceContext());
|
||||
deferredAttrContext.complete();
|
||||
return mt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +319,7 @@ public class Infer {
|
||||
*/
|
||||
saved_undet = inferenceContext.save();
|
||||
boolean unchecked = warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED);
|
||||
if (allowGraphInference && !unchecked) {
|
||||
if (!unchecked) {
|
||||
boolean shouldPropagate = shouldPropagate(getReturnType(), resultInfo, inferenceContext);
|
||||
|
||||
InferenceContext minContext = shouldPropagate ?
|
||||
@ -338,9 +339,13 @@ public class Infer {
|
||||
}
|
||||
inferenceContext.solve(noWarnings);
|
||||
Type ret = inferenceContext.asInstType(this).getReturnType();
|
||||
//inline logic from Attr.checkMethod - if unchecked conversion was required, erase
|
||||
//return type _after_ resolution
|
||||
return unchecked ? types.erasure(ret) : ret;
|
||||
if (unchecked) {
|
||||
//inline logic from Attr.checkMethod - if unchecked conversion was required, erase
|
||||
//return type _after_ resolution, and check against target
|
||||
ret = types.erasure(ret);
|
||||
resultInfo.check(env.tree, ret);
|
||||
}
|
||||
return ret;
|
||||
} catch (InferenceException ex) {
|
||||
resultInfo.checkContext.report(null, ex.getDiagnostic());
|
||||
Assert.error(); //cannot get here (the above should throw)
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8176534
|
||||
* @summary Missing check against target-type during applicability inference
|
||||
* @compile/fail/ref=T8176534.out -Werror -Xlint:unchecked -XDrawDiagnostics T8176534.java
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
|
||||
abstract class T8176534 {
|
||||
List<String> f(Enumeration e) {
|
||||
return newArrayList(forEnumeration(e));
|
||||
}
|
||||
|
||||
abstract <T> Iterator<T> forEnumeration(Enumeration<T> e);
|
||||
abstract <E> ArrayList<E> newArrayList(Iterator<? extends E> xs);
|
||||
abstract <E> ArrayList<E> newArrayList(Iterable<? extends E> xs);
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
T8176534.java:12:43: compiler.warn.unchecked.meth.invocation.applied: kindname.method, forEnumeration, java.util.Enumeration<T>, java.util.Enumeration, kindname.class, T8176534
|
||||
T8176534.java:12:44: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.Enumeration, java.util.Enumeration<T>
|
||||
T8176534.java:12:28: compiler.warn.unchecked.meth.invocation.applied: kindname.method, newArrayList, java.util.Iterator<? extends E>, java.util.Iterator, kindname.class, T8176534
|
||||
T8176534.java:12:43: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.Iterator, java.util.Iterator<? extends E>
|
||||
T8176534.java:12:28: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.ArrayList, java.util.List<java.lang.String>
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
5 warnings
|
||||
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import combo.ComboInstance;
|
||||
import combo.ComboParameter;
|
||||
import combo.ComboTask.Result;
|
||||
import combo.ComboTestHelper;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8176534
|
||||
* @summary Missing check against target-type during applicability inference
|
||||
* @library /tools/javac/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.code
|
||||
* jdk.compiler/com.sun.tools.javac.comp
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* jdk.compiler/com.sun.tools.javac.tree
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
* @build combo.ComboTestHelper
|
||||
*
|
||||
* @run main TestUncheckedCalls
|
||||
*/
|
||||
public class TestUncheckedCalls extends ComboInstance<TestUncheckedCalls> {
|
||||
enum InputExpressionKind implements ComboParameter {
|
||||
A("(A)null"),
|
||||
A_STRING("(A<String>)null"),
|
||||
B("(B)null"),
|
||||
B_STRING("(B<String>)null");
|
||||
|
||||
String inputExpr;
|
||||
|
||||
InputExpressionKind(String inputExpr) {
|
||||
this.inputExpr = inputExpr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return inputExpr;
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeKind implements ComboParameter {
|
||||
Z("Z"),
|
||||
C_T("#C<T>"),
|
||||
C_STRING("#C<String>"),
|
||||
C("#C");
|
||||
|
||||
String typeTemplate;
|
||||
|
||||
TypeKind(String typeTemplate) {
|
||||
this.typeTemplate = typeTemplate;
|
||||
}
|
||||
|
||||
boolean hasTypeVars() {
|
||||
return this == Z || this == C_T;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String className) {
|
||||
return typeTemplate.replaceAll("#C", className);
|
||||
}
|
||||
}
|
||||
|
||||
enum TypeVarsKind implements ComboParameter {
|
||||
NONE("", "Object"),
|
||||
Z_T("<Z extends #C<T>, T>", "Z");
|
||||
|
||||
String typeVarsTemplate;
|
||||
String paramString;
|
||||
|
||||
TypeVarsKind(String typeVarsTemplate, String paramString) {
|
||||
this.typeVarsTemplate = typeVarsTemplate;
|
||||
this.paramString = paramString;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String expand(String className) {
|
||||
if (className.equals("Z")) {
|
||||
return paramString;
|
||||
} else {
|
||||
return typeVarsTemplate.replaceAll("#C", className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum CallKind implements ComboParameter {
|
||||
M("M(#{IN}, #{IN})"),
|
||||
M_G("M(G(#{IN}, #{IN}), #{IN})"),
|
||||
M_G_G("M(G(#{IN}, #{IN}), G(#{IN}, #{IN}))");
|
||||
|
||||
String callExpr;
|
||||
|
||||
CallKind(String callExpr) {
|
||||
this.callExpr = callExpr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String expand(String optParameter) {
|
||||
return callExpr;
|
||||
}
|
||||
}
|
||||
|
||||
enum DeclKind implements ComboParameter {
|
||||
NONE(""),
|
||||
ONE("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }"),
|
||||
TWO("#{TVARS[#M_IDX].I1} #{RET[#M_IDX].A} #M(#{ARG[#M_IDX].A} x1, #{TVARS[#M_IDX].Z} x2) { return null; }\n" +
|
||||
" #{TVARS[#M_IDX].I2} #{RET[#M_IDX].B} #M(#{ARG[#M_IDX].B} x1, #{TVARS[#M_IDX].Z} x2) { return null; }");
|
||||
|
||||
String declTemplate;
|
||||
|
||||
DeclKind(String declTemplate) {
|
||||
this.declTemplate = declTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(String methName) {
|
||||
return declTemplate.replaceAll("#M_IDX", methName.equals("M") ? "0" : "1")
|
||||
.replaceAll("#M", methName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static final String sourceTemplate =
|
||||
"class Test {\n" +
|
||||
" interface I1<X> { }\n" +
|
||||
" interface I2<X> { }\n" +
|
||||
" static class A<X> implements I1<X> { }\n" +
|
||||
" static class B<X> implements I2<X> { }\n" +
|
||||
" #{DECL[0].M}\n" +
|
||||
" #{DECL[1].G}\n" +
|
||||
" void test() {\n" +
|
||||
" #{CALL};\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new ComboTestHelper<TestUncheckedCalls>()
|
||||
.withFilter(TestUncheckedCalls::arityFilter)
|
||||
.withFilter(TestUncheckedCalls::declFilter)
|
||||
.withFilter(TestUncheckedCalls::tvarFilter)
|
||||
.withFilter(TestUncheckedCalls::inputExprFilter)
|
||||
.withDimension("IN", (x, expr) -> x.inputExpressionKind = expr, InputExpressionKind.values())
|
||||
.withDimension("CALL", (x, expr) -> x.callKind = expr, CallKind.values())
|
||||
.withArrayDimension("DECL", (x, decl, idx) -> x.decls[idx] = x.new Decl(decl, idx), 2, DeclKind.values())
|
||||
.withArrayDimension("TVARS", (x, tvars, idx) -> x.typeVarsKinds[idx] = tvars, 2, TypeVarsKind.values())
|
||||
.withArrayDimension("RET", (x, ret, idx) -> x.returnKinds[idx] = ret, 2, TypeKind.values())
|
||||
.withArrayDimension("ARG", (x, arg, idx) -> x.argumentKinds[idx] = arg, 2, TypeKind.values())
|
||||
.run(TestUncheckedCalls::new);
|
||||
}
|
||||
|
||||
class Decl {
|
||||
private DeclKind declKind;
|
||||
private int index;
|
||||
|
||||
Decl(DeclKind declKind, int index) {
|
||||
this.declKind = declKind;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
boolean hasKind(DeclKind declKind) {
|
||||
return this.declKind == declKind;
|
||||
}
|
||||
|
||||
boolean isGeneric() {
|
||||
return typeVarsKind() == TypeVarsKind.Z_T;
|
||||
}
|
||||
|
||||
TypeKind returnKind() {
|
||||
return returnKinds[index];
|
||||
}
|
||||
|
||||
TypeKind argumentsKind() {
|
||||
return argumentKinds[index];
|
||||
}
|
||||
|
||||
TypeVarsKind typeVarsKind() {
|
||||
return typeVarsKinds[index];
|
||||
}
|
||||
}
|
||||
|
||||
CallKind callKind;
|
||||
InputExpressionKind inputExpressionKind;
|
||||
TypeKind[] returnKinds = new TypeKind[2];
|
||||
TypeKind[] argumentKinds = new TypeKind[2];
|
||||
TypeVarsKind[] typeVarsKinds = new TypeVarsKind[2];
|
||||
Decl[] decls = new Decl[2];
|
||||
|
||||
boolean arityFilter() {
|
||||
return (callKind == CallKind.M || !decls[1].hasKind(DeclKind.NONE)) &&
|
||||
!decls[0].hasKind(DeclKind.NONE);
|
||||
}
|
||||
|
||||
boolean declFilter() {
|
||||
return Stream.of(decls)
|
||||
.filter(d -> d.hasKind(DeclKind.NONE))
|
||||
.flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind(), d.typeVarsKind()))
|
||||
.noneMatch(tk -> tk.ordinal() != 0);
|
||||
}
|
||||
|
||||
boolean tvarFilter() {
|
||||
return Stream.of(decls)
|
||||
.filter(d -> !d.hasKind(DeclKind.NONE))
|
||||
.filter(d -> !d.isGeneric())
|
||||
.flatMap(d -> Stream.of(d.returnKind(), d.argumentsKind()))
|
||||
.noneMatch(TypeKind::hasTypeVars);
|
||||
}
|
||||
|
||||
boolean inputExprFilter() {
|
||||
return (inputExpressionKind != InputExpressionKind.B && inputExpressionKind != InputExpressionKind.B_STRING) ||
|
||||
Stream.of(decls).allMatch(d -> d.declKind == DeclKind.TWO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Throwable {
|
||||
check(newCompilationTask()
|
||||
.withSourceFromTemplate(sourceTemplate)
|
||||
.analyze());
|
||||
}
|
||||
|
||||
void check(Result<Iterable<? extends Element>> result) {
|
||||
if (result.hasErrors()) {
|
||||
fail("compiler error:\n" +
|
||||
result.compilationInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user