8067883: Javac misses some opportunities for diagnostic simplification
authormcimadamore
Tue, 06 Jan 2015 15:46:41 +0000
changeset 28331 43ed6b2e0e3b
parent 28330 d4bcdcac1211
child 28332 cd3ea1087d2b
8067883: Javac misses some opportunities for diagnostic simplification Summary: Javac always report full inference diagnostic, even when message does not mention inference variables. Reviewed-by: jlahoda
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883.java
langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883a.out
langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883b.out
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Jan 05 17:35:48 2015 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Jan 06 15:46:41 2015 +0000
@@ -39,7 +39,6 @@
 import com.sun.tools.javac.comp.Infer.InferenceContext;
 import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
-import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.DiagnosticRewriter;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.main.Option;
@@ -55,11 +54,12 @@
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.function.BiPredicate;
+import java.util.stream.Stream;
 
 import javax.lang.model.element.ElementVisitor;
 
@@ -2546,17 +2546,7 @@
                                 final JCDiagnostic details = sym.kind == WRONG_MTH ?
                                                 ((InapplicableSymbolError)sym.baseSymbol()).errCandidate().snd :
                                                 null;
-                                sym = new InapplicableSymbolError(sym.kind, "diamondError", currentResolutionContext) {
-                                    @Override
-                                    JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
-                                            Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
-                                        String key = details == null ?
-                                            "cant.apply.diamond" :
-                                            "cant.apply.diamond.1";
-                                        return diags.create(dkind, log.currentSource(), pos, key,
-                                                diags.fragment("diamond", site.tsym), details);
-                                    }
-                                };
+                                sym = new DiamondError(sym, currentResolutionContext);
                                 sym = accessMethod(sym, pos, site, names.init, true, argtypes, typeargtypes);
                                 env.info.pendingResolutionPhase = currentResolutionContext.step;
                             }
@@ -3724,15 +3714,10 @@
             else {
                 Pair<Symbol, JCDiagnostic> c = errCandidate();
                 if (compactMethodDiags) {
-                    for (Map.Entry<Template, DiagnosticRewriter> _entry :
-                            MethodResolutionDiagHelper.rewriters.entrySet()) {
-                        if (_entry.getKey().matches(c.snd)) {
-                            JCDiagnostic simpleDiag =
-                                    _entry.getValue().rewriteDiagnostic(diags, pos,
-                                        log.currentSource(), dkind, c.snd);
-                            simpleDiag.setFlag(DiagnosticFlag.COMPRESSED);
-                            return simpleDiag;
-                        }
+                    JCDiagnostic simpleDiag =
+                        MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
+                    if (simpleDiag != null) {
+                        return simpleDiag;
                     }
                 }
                 Symbol ws = c.fst.asMemberOf(site, types);
@@ -3765,9 +3750,8 @@
     }
 
     /**
-     * ResolveError error class indicating that a set of symbols
-     * (either methods, constructors or operands) is not applicable
-     * given an actual arguments/type argument list.
+     * ResolveError error class indicating that a symbol (either methods, constructors or operand)
+     * is not applicable given an actual arguments/type argument list.
      */
     class InapplicableSymbolsError extends InapplicableSymbolError {
 
@@ -3864,6 +3848,44 @@
     }
 
     /**
+     * DiamondError error class indicating that a constructor symbol is not applicable
+     * given an actual arguments/type argument list using diamond inference.
+     */
+    class DiamondError extends InapplicableSymbolError {
+
+        Symbol sym;
+
+        public DiamondError(Symbol sym, MethodResolutionContext context) {
+            super(sym.kind, "diamondError", context);
+            this.sym = sym;
+        }
+
+        JCDiagnostic getDetails() {
+            return (sym.kind == WRONG_MTH) ?
+                    ((InapplicableSymbolError)sym.baseSymbol()).errCandidate().snd :
+                    null;
+        }
+
+        @Override
+        JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos,
+                Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+            JCDiagnostic details = getDetails();
+            if (details != null && compactMethodDiags) {
+                JCDiagnostic simpleDiag =
+                        MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, details);
+                if (simpleDiag != null) {
+                    return simpleDiag;
+                }
+            }
+            String key = details == null ?
+                "cant.apply.diamond" :
+                "cant.apply.diamond.1";
+            return diags.create(dkind, log.currentSource(), pos, key,
+                    diags.fragment("diamond", site.tsym), details);
+        }
+    }
+
+    /**
      * An InvalidSymbolError error class indicating that a symbol is not
      * accessible from a given site
      */
@@ -4146,6 +4168,28 @@
             }
         }
 
+        /**
+         * Common rewriter for all argument mismatch simplifications.
+         */
+        static class ArgMismatchRewriter implements DiagnosticRewriter {
+
+            /** the index of the subdiagnostic to be used as primary. */
+            int causeIndex;
+
+            public ArgMismatchRewriter(int causeIndex) {
+                this.causeIndex = causeIndex;
+            }
+
+            @Override
+            public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
+                    DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
+                    DiagnosticType preferredKind, JCDiagnostic d) {
+                JCDiagnostic cause = (JCDiagnostic)d.getArgs()[causeIndex];
+                return diags.create(preferredKind, preferredSource, d.getDiagnosticPosition(),
+                        "prob.found.req", cause);
+            }
+        }
+
         /** a dummy template that match any diagnostic argument */
         static final Template skip = new Template("") {
             @Override
@@ -4154,22 +4198,61 @@
             }
         };
 
+        /** template for matching inference-free arguments mismatch failures */
+        static final Template argMismatchTemplate = new Template(MethodCheckDiag.ARG_MISMATCH.regex(), skip);
+
+        /** template for matching inference related arguments mismatch failures */
+        static final Template inferArgMismatchTemplate = new Template(MethodCheckDiag.ARG_MISMATCH.regex(), skip, skip) {
+            @Override
+            boolean matches(Object o) {
+                if (!super.matches(o)) {
+                    return false;
+                }
+                JCDiagnostic d = (JCDiagnostic)o;
+                @SuppressWarnings("unchecked")
+                List<Type> tvars = (List<Type>)d.getArgs()[0];
+                return !containsAny(d, tvars);
+            }
+
+            BiPredicate<Object, List<Type>> containsPredicate = (o, ts) -> {
+                if (o instanceof Type) {
+                    return ((Type)o).containsAny(ts);
+                } else if (o instanceof JCDiagnostic) {
+                    return containsAny((JCDiagnostic)o, ts);
+                } else {
+                    return false;
+                }
+            };
+
+            boolean containsAny(JCDiagnostic d, List<Type> ts) {
+                return Stream.of(d.getArgs())
+                        .anyMatch(o -> containsPredicate.test(o, ts));
+            }
+        };
+
         /** rewriter map used for method resolution simplification */
         static final Map<Template, DiagnosticRewriter> rewriters = new LinkedHashMap<>();
 
         static {
-            String argMismatchRegex = MethodCheckDiag.ARG_MISMATCH.regex();
-            rewriters.put(new Template(argMismatchRegex, skip),
-                    new DiagnosticRewriter() {
-                @Override
-                public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
-                        DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
-                        DiagnosticType preferredKind, JCDiagnostic d) {
-                    JCDiagnostic cause = (JCDiagnostic)d.getArgs()[0];
-                    return diags.create(preferredKind, preferredSource, d.getDiagnosticPosition(),
-                            "prob.found.req", cause);
+            rewriters.put(argMismatchTemplate, new ArgMismatchRewriter(0));
+            rewriters.put(inferArgMismatchTemplate, new ArgMismatchRewriter(1));
+        }
+
+        /**
+         * Main entry point for diagnostic rewriting - given a diagnostic, see if any templates matches it,
+         * and rewrite it accordingly.
+         */
+        static JCDiagnostic rewrite(JCDiagnostic.Factory diags, DiagnosticPosition pos, DiagnosticSource source,
+                                    DiagnosticType dkind, JCDiagnostic d) {
+            for (Map.Entry<Template, DiagnosticRewriter> _entry : rewriters.entrySet()) {
+                if (_entry.getKey().matches(d)) {
+                    JCDiagnostic simpleDiag =
+                            _entry.getValue().rewriteDiagnostic(diags, pos, source, dkind, d);
+                    simpleDiag.setFlag(DiagnosticFlag.COMPRESSED);
+                    return simpleDiag;
                 }
-            });
+            }
+            return null;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883.java	Tue Jan 06 15:46:41 2015 +0000
@@ -0,0 +1,29 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8067883
+ * @summary Javac misses some opportunities for diagnostic simplification
+ *
+ * @compile/fail/ref=T8067883a.out -Xdiags:compact -XDrawDiagnostics T8067883.java
+ * @compile/fail/ref=T8067883b.out -Xdiags:verbose -XDrawDiagnostics T8067883.java
+ *
+ */
+
+import java.util.List;
+
+class T8067883 {
+    void testMethod(List<Integer> li) {
+        m(null, li);
+        m(1, li);
+    }
+
+    void testDiamond(List<Integer> li) {
+        new Box<>(null, li);
+        new Box<>(1, li);
+    }
+
+    <Z> void m(List<Z> z, List<String> ls) { }
+
+    static class Box<X> {
+        Box(List<X> z, List<String> ls) { }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883a.out	Tue Jan 06 15:46:41 2015 +0000
@@ -0,0 +1,6 @@
+T8067883.java:15:17: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<java.lang.Integer>, java.util.List<java.lang.String>)
+T8067883.java:16:9: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List<Z>,java.util.List<java.lang.String>, int,java.util.List<java.lang.Integer>, kindname.class, T8067883, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.inconvertible.types: int, java.util.List<Z>))
+T8067883.java:20:25: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<java.lang.Integer>, java.util.List<java.lang.String>)
+T8067883.java:21:9: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: T8067883.Box), (compiler.misc.infer.no.conforming.assignment.exists: X, (compiler.misc.inconvertible.types: int, java.util.List<X>))
+- compiler.note.compressed.diags
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/Diagnostics/compressed/8067883/T8067883b.out	Tue Jan 06 15:46:41 2015 +0000
@@ -0,0 +1,5 @@
+T8067883.java:15:9: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List<Z>,java.util.List<java.lang.String>, compiler.misc.type.null,java.util.List<java.lang.Integer>, kindname.class, T8067883, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.inconvertible.types: java.util.List<java.lang.Integer>, java.util.List<java.lang.String>))
+T8067883.java:16:9: compiler.err.cant.apply.symbol: kindname.method, m, java.util.List<Z>,java.util.List<java.lang.String>, int,java.util.List<java.lang.Integer>, kindname.class, T8067883, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.inconvertible.types: int, java.util.List<Z>))
+T8067883.java:20:9: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: T8067883.Box), (compiler.misc.infer.no.conforming.assignment.exists: X, (compiler.misc.inconvertible.types: java.util.List<java.lang.Integer>, java.util.List<java.lang.String>))
+T8067883.java:21:9: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: T8067883.Box), (compiler.misc.infer.no.conforming.assignment.exists: X, (compiler.misc.inconvertible.types: int, java.util.List<X>))
+4 errors