Incoherent invocation type inference?
B. Blaser
bsrbnd at gmail.com
Fri Aug 25 07:23:15 UTC 2017
Maurizio,
On 22 January 2017 at 17:26, B. Blaser <bsrbnd at gmail.com> wrote:
> Hi,
>
> 2017-01-19 18:22 GMT+01:00 Maurizio Cimadamore <maurizio.cimadamore at oracle.com>:
>> Not sure about your proposed patch.
>>
>> To me the warning should be a property of the method declaration, not of the
>> specific inference.
>>
>> If a method returns a naked type-variable which is not mentioned anywhere in
>> the method parameter types -> Lint warning (not an unchecked warning - just
>> an optional Lint one - category TBD).
>>
>> It's true that, by looking at the callsite, you can also warn for clients
>> passing 'null' arguments, but the extra benefit is not worth the extra
>> complexity IMHO. And, I think this is a problem of bad API, not one of bad
>> clients. A well-designed API should not have any methods that match the
>> criteria stated above - as their behavior would ultimately be at the
>> client's mercy.
>>
>> Maurizio
>
> Here under is a suggestion for the implementation of the rule you
> stated above (Attr.visitMethodDef(), upon rev. b6960e2da008).
>
> I kept a check on the callsite for further evaluation (in
> Attr.checkMethod() to be more general). I think both are
> complementary.
>
> "<T> T[] List.toArray(T[])" is a good example of a well designed API.
> But an invocation of the form "a = l.toArray(null)" is dangerous due
> to the obvious API's lack of control over T and might be warned.
>
> For the Lint category, I suggest to name it "generic" and to use it
> for warnings about type variables. Other checks like the "final" one
> could fall into the same category.
>
> Does this look better?
Should I create a JBS issue for that?
Bernard
> Thanks,
> Bernard
>
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
> @@ -268,6 +268,11 @@
> UNCHECKED("unchecked"),
>
> /**
> + * Warn about issues relating to type variables.
> + */
> + GENERIC("generic"),
> +
> + /**
> * Warn about potentially unsafe vararg methods
> */
> VARARGS("varargs");
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
> @@ -947,6 +947,7 @@
> deferredLintHandler.flush(tree.pos());
> chk.checkDeprecatedAnnotation(tree.pos(), m);
>
> + chk.checkGenMethDeclaration(tree.pos(), m);
>
> // Create a new environment with local scope
> // for attributing the method.
> @@ -3918,6 +3919,8 @@
> final List<JCExpression> argtrees,
> List<Type> argtypes,
> List<Type> typeargtypes) {
> + chk.checkGenMethInvocation(env.tree.pos(), sym, resultInfo, argtypes);
> +
> // Test (5): if symbol is an instance method of a raw type, issue
> // an unchecked warning if its argument types change under erasure.
> if ((sym.flags() & STATIC) == 0 &&
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
> @@ -3876,4 +3876,76 @@
> }
> }
>
> + // Check the declaration's precision for type variables.
> + void checkGenMethDeclaration(DiagnosticPosition pos, Symbol sym) {
> + if (sym.type.hasTag(FORALL)) {
> + ForAll gmt = (ForAll)sym.type;
> + MethodType mt = (MethodType)gmt.qtype;
> + List<Type> tvars = gmt.tvars;
> +
> + Type elemResType = mt.restype;
> + while (elemResType.hasTag(ARRAY)) {
> + elemResType = ((ArrayType)elemResType).elemtype;
> + }
> + if (elemResType.hasTag(TYPEVAR) && tvars.contains(elemResType)) {
> + boolean ok = false;
> + for (Type t: mt.argtypes) {
> + if (t.contains(elemResType))
> + ok = true;
> + }
> + if (!ok)
> + warnGeneric(
> + pos,
> + "generic.imprecise.method.declaration",
> + Kinds.kindName(sym),
> + sym.name,
> + Kinds.kindName(sym.location()),
> + sym.location(),
> + elemResType);
> + }
> + }
> + }
> +
> + // Check the actual arguments' precision for type variables.
> + void checkGenMethInvocation(
> + DiagnosticPosition pos,
> + Symbol sym,
> + Attr.ResultInfo resultInfo,
> + List<Type> argtypes) {
> +
> + if (sym.type.hasTag(FORALL)) {
> + ForAll gmt = (ForAll)sym.type;
> + MethodType mt = (MethodType)gmt.qtype;
> +
> + Type elemResType = mt.restype;
> + while (elemResType.hasTag(ARRAY)) {
> + elemResType = ((ArrayType)elemResType).elemtype;
> + }
> + if (resultInfo != null && resultInfo.pt != Type.noType &&
> elemResType.hasTag(TYPEVAR)) {
> + boolean ok = false;
> + if (mt.argtypes.length() <= argtypes.length()) {
> + for (int i=0; i<mt.argtypes.length(); i++) {
> + Type pType = mt.argtypes.get(i);
> + Type aType = argtypes.get(i);
> + if (pType.contains(elemResType) && aType !=
> syms.botType)
> + ok = true;
> + }
> + }
> + if (!ok)
> + warnGeneric(
> + pos,
> + "generic.imprecise.method.invocation",
> + Kinds.kindName(sym),
> + sym.name,
> + Kinds.kindName(sym.location()),
> + sym.location(),
> + elemResType);
> + }
> + }
> + }
> +
> + void warnGeneric(DiagnosticPosition pos, String key, Object... args) {
> + if (lint.isEnabled(LintCategory.GENERIC))
> + log.warning(LintCategory.GENERIC, pos, key, args);
> + }
> }
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
> @@ -1756,6 +1756,14 @@
> compiler.warn.unchecked.varargs.non.reifiable.type=\
> Possible heap pollution from parameterized vararg type {0}
>
> +# 0: symbol kind, 1: name, 2: symbol kind, 3: symbol, 4: type
> +compiler.warn.generic.imprecise.method.declaration=\
> + Imprecise method declaration: parameters of {0} {1} in {2} {3}
> should refer to {4}
> +
> +# 0: symbol kind, 1: name, 2: symbol kind, 3: symbol, 4: type
> +compiler.warn.generic.imprecise.method.invocation=\
> + Imprecise method invocation: arguments of {0} {1} in {2} {3}
> should refer to {4}
> +
> # 0: symbol
> compiler.warn.varargs.unsafe.use.varargs.param=\
> Varargs method could cause heap pollution from non-reifiable
> varargs parameter {0}
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
> @@ -238,6 +238,9 @@
> javac.opt.Xlint.desc.unchecked=\
> Warn about unchecked operations.
>
> +javac.opt.Xlint.desc.generic=\
> + Warn about issues relating to type variables.
> +
> javac.opt.Xlint.desc.varargs=\
> Warn about potentially unsafe vararg methods
More information about the compiler-dev
mailing list