src/share/classes/com/sun/tools/javac/comp/Resolve.java

changeset 1759
05ec778794d0
parent 1697
950e8ac120f0
child 1779
97a9b4b3e63a
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed May 15 00:00:39 2013 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed May 15 14:00:31 2013 +0100
     1.3 @@ -37,7 +37,10 @@
     1.4  import com.sun.tools.javac.comp.Infer.InferenceContext;
     1.5  import com.sun.tools.javac.comp.Infer.FreeTypeListener;
     1.6  import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
     1.7 +import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.DiagnosticRewriter;
     1.8 +import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template;
     1.9  import com.sun.tools.javac.jvm.*;
    1.10 +import com.sun.tools.javac.main.Option;
    1.11  import com.sun.tools.javac.tree.*;
    1.12  import com.sun.tools.javac.tree.JCTree.*;
    1.13  import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    1.14 @@ -94,6 +97,7 @@
    1.15      public final boolean allowDefaultMethods;
    1.16      public final boolean allowStructuralMostSpecific;
    1.17      private final boolean debugResolve;
    1.18 +    private final boolean compactMethodDiags;
    1.19      final EnumSet<VerboseResolutionMode> verboseResolutionMode;
    1.20  
    1.21      Scope polymorphicSignatureScope;
    1.22 @@ -124,6 +128,8 @@
    1.23          varargsEnabled = source.allowVarargs();
    1.24          Options options = Options.instance(context);
    1.25          debugResolve = options.isSet("debugresolve");
    1.26 +        compactMethodDiags = options.isSet(Option.XDIAGS, "compact") ||
    1.27 +                options.isUnset(Option.XDIAGS) && options.isUnset("rawDiagnostics");
    1.28          verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
    1.29          Target target = Target.instance(context);
    1.30          allowMethodHandles = target.hasMethodHandles();
    1.31 @@ -661,6 +667,10 @@
    1.32              this.basicKey = basicKey;
    1.33              this.inferKey = inferKey;
    1.34          }
    1.35 +
    1.36 +        String regex() {
    1.37 +            return String.format("([a-z]*\\.)*(%s|%s)", basicKey, inferKey);
    1.38 +        }
    1.39      }
    1.40  
    1.41      /**
    1.42 @@ -691,6 +701,7 @@
    1.43                                      Warner warn) {
    1.44              //should we expand formals?
    1.45              boolean useVarargs = deferredAttrContext.phase.isVarargsRequired();
    1.46 +            List<JCExpression> trees = TreeInfo.args(env.tree);
    1.47  
    1.48              //inference context used during this method check
    1.49              InferenceContext inferenceContext = deferredAttrContext.inferenceContext;
    1.50 @@ -699,17 +710,19 @@
    1.51  
    1.52              if (varargsFormal == null &&
    1.53                      argtypes.size() != formals.size()) {
    1.54 -                reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
    1.55 +                reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
    1.56              }
    1.57  
    1.58              while (argtypes.nonEmpty() && formals.head != varargsFormal) {
    1.59 -                checkArg(false, argtypes.head, formals.head, deferredAttrContext, warn);
    1.60 +                DiagnosticPosition pos = trees != null ? trees.head : null;
    1.61 +                checkArg(pos, false, argtypes.head, formals.head, deferredAttrContext, warn);
    1.62                  argtypes = argtypes.tail;
    1.63                  formals = formals.tail;
    1.64 +                trees = trees != null ? trees.tail : trees;
    1.65              }
    1.66  
    1.67              if (formals.head != varargsFormal) {
    1.68 -                reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
    1.69 +                reportMC(env.tree, MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
    1.70              }
    1.71  
    1.72              if (useVarargs) {
    1.73 @@ -717,8 +730,10 @@
    1.74                  //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
    1.75                  final Type elt = types.elemtype(varargsFormal);
    1.76                  while (argtypes.nonEmpty()) {
    1.77 -                    checkArg(true, argtypes.head, elt, deferredAttrContext, warn);
    1.78 +                    DiagnosticPosition pos = trees != null ? trees.head : null;
    1.79 +                    checkArg(pos, true, argtypes.head, elt, deferredAttrContext, warn);
    1.80                      argtypes = argtypes.tail;
    1.81 +                    trees = trees != null ? trees.tail : trees;
    1.82                  }
    1.83              }
    1.84          }
    1.85 @@ -726,9 +741,9 @@
    1.86          /**
    1.87           * Does the actual argument conforms to the corresponding formal?
    1.88           */
    1.89 -        abstract void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn);
    1.90 -
    1.91 -        protected void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
    1.92 +        abstract void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn);
    1.93 +
    1.94 +        protected void reportMC(DiagnosticPosition pos, MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
    1.95              boolean inferDiag = inferenceContext != infer.emptyContext;
    1.96              InapplicableMethodException ex = inferDiag ?
    1.97                      infer.inferenceException : inapplicableMethodException;
    1.98 @@ -738,7 +753,8 @@
    1.99                  args2[0] = inferenceContext.inferenceVars();
   1.100                  args = args2;
   1.101              }
   1.102 -            throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args);
   1.103 +            String key = inferDiag ? diag.inferKey : diag.basicKey;
   1.104 +            throw ex.setMessage(diags.create(DiagnosticType.FRAGMENT, log.currentSource(), pos, key, args));
   1.105          }
   1.106  
   1.107          public MethodCheck mostSpecificCheck(List<Type> actuals, boolean strict) {
   1.108 @@ -752,7 +768,7 @@
   1.109       */
   1.110      MethodCheck arityMethodCheck = new AbstractMethodCheck() {
   1.111          @Override
   1.112 -        void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
   1.113 +        void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
   1.114              //do nothing - actual always compatible to formals
   1.115          }
   1.116      };
   1.117 @@ -778,9 +794,9 @@
   1.118      MethodCheck resolveMethodCheck = new AbstractMethodCheck() {
   1.119  
   1.120          @Override
   1.121 -        void checkArg(boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
   1.122 +        void checkArg(DiagnosticPosition pos, boolean varargs, Type actual, Type formal, DeferredAttrContext deferredAttrContext, Warner warn) {
   1.123              ResultInfo mresult = methodCheckResult(varargs, formal, deferredAttrContext, warn);
   1.124 -            mresult.check(null, actual);
   1.125 +            mresult.check(pos, actual);
   1.126          }
   1.127  
   1.128          @Override
   1.129 @@ -809,7 +825,7 @@
   1.130              } else {
   1.131                  if (!isAccessible(env, t)) {
   1.132                      Symbol location = env.enclClass.sym;
   1.133 -                    reportMC(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
   1.134 +                    reportMC(env.tree, MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
   1.135                  }
   1.136              }
   1.137          }
   1.138 @@ -822,7 +838,7 @@
   1.139  
   1.140                  @Override
   1.141                  public void report(DiagnosticPosition pos, JCDiagnostic details) {
   1.142 -                    reportMC(methodDiag, deferredAttrContext.inferenceContext, details);
   1.143 +                    reportMC(pos, methodDiag, deferredAttrContext.inferenceContext, details);
   1.144                  }
   1.145              };
   1.146              return new MethodResultInfo(to, checkContext);
   1.147 @@ -3327,6 +3343,18 @@
   1.148              }
   1.149              else {
   1.150                  Candidate c = errCandidate();
   1.151 +                if (compactMethodDiags) {
   1.152 +                    for (Map.Entry<Template, DiagnosticRewriter> _entry :
   1.153 +                            MethodResolutionDiagHelper.rewriters.entrySet()) {
   1.154 +                        if (_entry.getKey().matches(c.details)) {
   1.155 +                            JCDiagnostic simpleDiag =
   1.156 +                                    _entry.getValue().rewriteDiagnostic(diags, pos,
   1.157 +                                        log.currentSource(), dkind, c.details);
   1.158 +                            simpleDiag.setFlag(DiagnosticFlag.COMPRESSED);
   1.159 +                            return simpleDiag;
   1.160 +                        }
   1.161 +                    }
   1.162 +                }
   1.163                  Symbol ws = c.sym.asMemberOf(site, types);
   1.164                  return diags.create(dkind, log.currentSource(), pos,
   1.165                            "cant.apply.symbol",
   1.166 @@ -3375,35 +3403,75 @@
   1.167                  Name name,
   1.168                  List<Type> argtypes,
   1.169                  List<Type> typeargtypes) {
   1.170 -            if (!resolveContext.candidates.isEmpty()) {
   1.171 +            Map<Symbol, JCDiagnostic> candidatesMap = mapCandidates();
   1.172 +            Map<Symbol, JCDiagnostic> filteredCandidates = filterCandidates(candidatesMap);
   1.173 +            if (filteredCandidates.isEmpty()) {
   1.174 +                filteredCandidates = candidatesMap;
   1.175 +            }
   1.176 +            boolean truncatedDiag = candidatesMap.size() != filteredCandidates.size();
   1.177 +            if (filteredCandidates.size() > 1) {
   1.178                  JCDiagnostic err = diags.create(dkind,
   1.179 +                        null,
   1.180 +                        truncatedDiag ?
   1.181 +                            EnumSet.of(DiagnosticFlag.COMPRESSED) :
   1.182 +                            EnumSet.noneOf(DiagnosticFlag.class),
   1.183                          log.currentSource(),
   1.184                          pos,
   1.185                          "cant.apply.symbols",
   1.186                          name == names.init ? KindName.CONSTRUCTOR : absentKind(kind),
   1.187                          name == names.init ? site.tsym.name : name,
   1.188                          methodArguments(argtypes));
   1.189 -                return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(site));
   1.190 +                return new JCDiagnostic.MultilineDiagnostic(err, candidateDetails(filteredCandidates, site));
   1.191 +            } else if (filteredCandidates.size() == 1) {
   1.192 +                JCDiagnostic d =  new InapplicableSymbolError(resolveContext).getDiagnostic(dkind, pos,
   1.193 +                    location, site, name, argtypes, typeargtypes);
   1.194 +                if (truncatedDiag) {
   1.195 +                    d.setFlag(DiagnosticFlag.COMPRESSED);
   1.196 +                }
   1.197 +                return d;
   1.198              } else {
   1.199                  return new SymbolNotFoundError(ABSENT_MTH).getDiagnostic(dkind, pos,
   1.200                      location, site, name, argtypes, typeargtypes);
   1.201              }
   1.202          }
   1.203 -
   1.204          //where
   1.205 -        List<JCDiagnostic> candidateDetails(Type site) {
   1.206 -            Map<Symbol, JCDiagnostic> details = new LinkedHashMap<Symbol, JCDiagnostic>();
   1.207 -            for (Candidate c : resolveContext.candidates) {
   1.208 -                if (c.isApplicable()) continue;
   1.209 -                JCDiagnostic detailDiag = diags.fragment("inapplicable.method",
   1.210 -                        Kinds.kindName(c.sym),
   1.211 -                        c.sym.location(site, types),
   1.212 -                        c.sym.asMemberOf(site, types),
   1.213 -                        c.details);
   1.214 -                details.put(c.sym, detailDiag);
   1.215 +            private Map<Symbol, JCDiagnostic> mapCandidates() {
   1.216 +                Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>();
   1.217 +                for (Candidate c : resolveContext.candidates) {
   1.218 +                    if (c.isApplicable()) continue;
   1.219 +                    candidates.put(c.sym, c.details);
   1.220 +                }
   1.221 +                return candidates;
   1.222              }
   1.223 -            return List.from(details.values());
   1.224 -        }
   1.225 +
   1.226 +            Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
   1.227 +                Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<Symbol, JCDiagnostic>();
   1.228 +                for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
   1.229 +                    JCDiagnostic d = _entry.getValue();
   1.230 +                    if (!compactMethodDiags ||
   1.231 +                            !new Template(MethodCheckDiag.ARITY_MISMATCH.regex()).matches(d)) {
   1.232 +                        candidates.put(_entry.getKey(), d);
   1.233 +                    }
   1.234 +                }
   1.235 +                return candidates;
   1.236 +            }
   1.237 +
   1.238 +            private List<JCDiagnostic> candidateDetails(Map<Symbol, JCDiagnostic> candidatesMap, Type site) {
   1.239 +                List<JCDiagnostic> details = List.nil();
   1.240 +                for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
   1.241 +                    Symbol sym = _entry.getKey();
   1.242 +                    JCDiagnostic detailDiag = diags.fragment("inapplicable.method",
   1.243 +                            Kinds.kindName(sym),
   1.244 +                            sym.location(site, types),
   1.245 +                            sym.asMemberOf(site, types),
   1.246 +                            _entry.getValue());
   1.247 +                    details = details.prepend(detailDiag);
   1.248 +                }
   1.249 +                //typically members are visited in reverse order (see Scope)
   1.250 +                //so we need to reverse the candidate list so that candidates
   1.251 +                //conform to source order
   1.252 +                return details;
   1.253 +            }
   1.254      }
   1.255  
   1.256      /**
   1.257 @@ -3624,6 +3692,105 @@
   1.258          }
   1.259      }
   1.260  
   1.261 +    /**
   1.262 +     * Helper class for method resolution diagnostic simplification.
   1.263 +     * Certain resolution diagnostic are rewritten as simpler diagnostic
   1.264 +     * where the enclosing resolution diagnostic (i.e. 'inapplicable method')
   1.265 +     * is stripped away, as it doesn't carry additional info. The logic
   1.266 +     * for matching a given diagnostic is given in terms of a template
   1.267 +     * hierarchy: a diagnostic template can be specified programmatically,
   1.268 +     * so that only certain diagnostics are matched. Each templete is then
   1.269 +     * associated with a rewriter object that carries out the task of rewtiting
   1.270 +     * the diagnostic to a simpler one.
   1.271 +     */
   1.272 +    static class MethodResolutionDiagHelper {
   1.273 +
   1.274 +        /**
   1.275 +         * A diagnostic rewriter transforms a method resolution diagnostic
   1.276 +         * into a simpler one
   1.277 +         */
   1.278 +        interface DiagnosticRewriter {
   1.279 +            JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
   1.280 +                    DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
   1.281 +                    DiagnosticType preferredKind, JCDiagnostic d);
   1.282 +        }
   1.283 +
   1.284 +        /**
   1.285 +         * A diagnostic template is made up of two ingredients: (i) a regular
   1.286 +         * expression for matching a diagnostic key and (ii) a list of sub-templates
   1.287 +         * for matching diagnostic arguments.
   1.288 +         */
   1.289 +        static class Template {
   1.290 +
   1.291 +            /** regex used to match diag key */
   1.292 +            String regex;
   1.293 +
   1.294 +            /** templates used to match diagnostic args */
   1.295 +            Template[] subTemplates;
   1.296 +
   1.297 +            Template(String key, Template... subTemplates) {
   1.298 +                this.regex = key;
   1.299 +                this.subTemplates = subTemplates;
   1.300 +            }
   1.301 +
   1.302 +            /**
   1.303 +             * Returns true if the regex matches the diagnostic key and if
   1.304 +             * all diagnostic arguments are matches by corresponding sub-templates.
   1.305 +             */
   1.306 +            boolean matches(Object o) {
   1.307 +                JCDiagnostic d = (JCDiagnostic)o;
   1.308 +                Object[] args = d.getArgs();
   1.309 +                if (!d.getCode().matches(regex) ||
   1.310 +                        subTemplates.length != d.getArgs().length) {
   1.311 +                    return false;
   1.312 +                }
   1.313 +                for (int i = 0; i < args.length ; i++) {
   1.314 +                    if (!subTemplates[i].matches(args[i])) {
   1.315 +                        return false;
   1.316 +                    }
   1.317 +                }
   1.318 +                return true;
   1.319 +            }
   1.320 +        }
   1.321 +
   1.322 +        /** a dummy template that match any diagnostic argument */
   1.323 +        static final Template skip = new Template("") {
   1.324 +            @Override
   1.325 +            boolean matches(Object d) {
   1.326 +                return true;
   1.327 +            }
   1.328 +        };
   1.329 +
   1.330 +        /** rewriter map used for method resolution simplification */
   1.331 +        static final Map<Template, DiagnosticRewriter> rewriters =
   1.332 +                new LinkedHashMap<Template, DiagnosticRewriter>();
   1.333 +
   1.334 +        static {
   1.335 +            String argMismatchRegex = MethodCheckDiag.ARG_MISMATCH.regex();
   1.336 +            rewriters.put(new Template(argMismatchRegex, new Template("(.*)(bad.arg.types.in.lambda)", skip, skip)),
   1.337 +                    new DiagnosticRewriter() {
   1.338 +                @Override
   1.339 +                public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
   1.340 +                        DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
   1.341 +                        DiagnosticType preferredKind, JCDiagnostic d) {
   1.342 +                    return (JCDiagnostic)((JCDiagnostic)d.getArgs()[0]).getArgs()[1];
   1.343 +                }
   1.344 +            });
   1.345 +
   1.346 +            rewriters.put(new Template(argMismatchRegex, skip),
   1.347 +                    new DiagnosticRewriter() {
   1.348 +                @Override
   1.349 +                public JCDiagnostic rewriteDiagnostic(JCDiagnostic.Factory diags,
   1.350 +                        DiagnosticPosition preferedPos, DiagnosticSource preferredSource,
   1.351 +                        DiagnosticType preferredKind, JCDiagnostic d) {
   1.352 +                    JCDiagnostic cause = (JCDiagnostic)d.getArgs()[0];
   1.353 +                    return diags.create(preferredKind, preferredSource, d.getDiagnosticPosition(),
   1.354 +                            "prob.found.req", cause);
   1.355 +                }
   1.356 +            });
   1.357 +        }
   1.358 +    }
   1.359 +
   1.360      enum MethodResolutionPhase {
   1.361          BASIC(false, false),
   1.362          BOX(true, false),

mercurial