1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.tools.javac.code.Flags;
  29 import com.sun.tools.javac.code.Symbol;
  30 import com.sun.tools.javac.code.Symtab;
  31 import com.sun.tools.javac.code.Type;
  32 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
  33 import com.sun.tools.javac.comp.Attr.ResultInfo;
  34 import com.sun.tools.javac.comp.Attr.TargetInfo;
  35 import com.sun.tools.javac.comp.Check.CheckContext;
  36 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
  37 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
  38 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
  39 import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
  40 import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
  41 import com.sun.tools.javac.comp.DeferredAttr.SwitchExpressionScanner;
  42 import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
  43 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
  44 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  45 import com.sun.tools.javac.tree.JCTree;
  46 import com.sun.tools.javac.tree.JCTree.JCBreak;
  47 import com.sun.tools.javac.tree.JCTree.JCConditional;
  48 import com.sun.tools.javac.tree.JCTree.JCExpression;
  49 import com.sun.tools.javac.tree.JCTree.JCLambda;
  50 import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
  51 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
  52 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
  53 import com.sun.tools.javac.tree.JCTree.JCNewClass;
  54 import com.sun.tools.javac.tree.JCTree.JCParens;
  55 import com.sun.tools.javac.tree.JCTree.JCReturn;
  56 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  57 import com.sun.tools.javac.tree.TreeCopier;
  58 import com.sun.tools.javac.tree.TreeInfo;
  59 import com.sun.tools.javac.util.Assert;
  60 import com.sun.tools.javac.util.Context;
  61 import com.sun.tools.javac.util.DiagnosticSource;
  62 import com.sun.tools.javac.util.JCDiagnostic;
  63 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  64 import com.sun.tools.javac.util.List;
  65 import com.sun.tools.javac.util.ListBuffer;
  66 import com.sun.tools.javac.util.Log;
  67 
  68 import java.util.HashMap;
  69 import java.util.LinkedHashMap;
  70 import java.util.Map;
  71 import java.util.Optional;
  72 import java.util.function.Function;
  73 import java.util.function.Supplier;
  74 
  75 import static com.sun.tools.javac.code.TypeTag.ARRAY;
  76 import static com.sun.tools.javac.code.TypeTag.DEFERRED;
  77 import static com.sun.tools.javac.code.TypeTag.FORALL;
  78 import static com.sun.tools.javac.code.TypeTag.METHOD;
  79 import static com.sun.tools.javac.code.TypeTag.VOID;
  80 
  81 /**
  82  * This class performs attribution of method/constructor arguments when target-typing is enabled
  83  * (source >= 8); for each argument that is potentially a poly expression, this class builds
  84  * a rich representation (see {@link ArgumentType} which can then be used for performing fast overload
  85  * checks without requiring multiple attribution passes over the same code.
  86  *
  87  * The attribution strategy for a given method/constructor argument A is as follows:
  88  *
  89  * - if A is potentially a poly expression (i.e. diamond instance creation expression), a speculative
  90  * pass over A is performed; the results of such speculative attribution are then saved in a special
  91  * type, so that enclosing overload resolution can be carried by simply checking compatibility against the
  92  * type determined during this speculative pass.
  93  *
  94  * - if A is a standalone expression, regular atributtion takes place.
  95  *
  96  * To minimize the speculative work, a cache is used, so that already computed argument types
  97  * associated with a given unique source location are never recomputed multiple times.
  98  */
  99 public class ArgumentAttr extends JCTree.Visitor {
 100 
 101     protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>();
 102 
 103     private final DeferredAttr deferredAttr;
 104     private final JCDiagnostic.Factory diags;
 105     private final Attr attr;
 106     private final Symtab syms;
 107     private final Log log;
 108 
 109     /** Attribution environment to be used. */
 110     private Env<AttrContext> env;
 111 
 112     /** Result of method attribution. */
 113     Type result;
 114 
 115     /** Cache for argument types; behavior is influences by the currrently selected cache policy. */
 116     Map<UniquePos, ArgumentType<?>> argumentTypeCache = new LinkedHashMap<>();
 117 
 118     public static ArgumentAttr instance(Context context) {
 119         ArgumentAttr instance = context.get(methodAttrKey);
 120         if (instance == null)
 121             instance = new ArgumentAttr(context);
 122         return instance;
 123     }
 124 
 125     protected ArgumentAttr(Context context) {
 126         context.put(methodAttrKey, this);
 127         deferredAttr = DeferredAttr.instance(context);
 128         diags = JCDiagnostic.Factory.instance(context);
 129         attr = Attr.instance(context);
 130         syms = Symtab.instance(context);
 131         log = Log.instance(context);
 132     }
 133 
 134     /**
 135      * Set the results of method attribution.
 136      */
 137     void setResult(JCExpression tree, Type type) {
 138         result = type;
 139         if (env.info.isSpeculative) {
 140             //if we are in a speculative branch we can save the type in the tree itself
 141             //as there's no risk of polluting the original tree.
 142             tree.type = result;
 143         }
 144     }
 145 
 146     /**
 147      * Checks a type in the speculative tree against a given result; the type can be either a plain
 148      * type or an argument type,in which case a more complex check is required.
 149      */
 150     Type checkSpeculative(JCTree expr, ResultInfo resultInfo) {
 151         return checkSpeculative(expr, expr.type, resultInfo);
 152     }
 153 
 154     /**
 155      * Checks a type in the speculative tree against a given result; the type can be either a plain
 156      * type or an argument type,in which case a more complex check is required.
 157      */
 158     Type checkSpeculative(DiagnosticPosition pos, Type t, ResultInfo resultInfo) {
 159         if (t.hasTag(DEFERRED)) {
 160             return ((DeferredType)t).check(resultInfo);
 161         } else {
 162             return resultInfo.check(pos, t);
 163         }
 164     }
 165 
 166     /**
 167      * Returns a local caching context in which argument types can safely be cached without
 168      * the risk of polluting enclosing contexts. This is useful when attempting speculative
 169      * attribution of potentially erroneous expressions, which could end up polluting the cache.
 170      */
 171     LocalCacheContext withLocalCacheContext() {
 172         return new LocalCacheContext();
 173     }
 174 
 175     /**
 176      * Local cache context; this class keeps track of the previous cache and reverts to it
 177      * when the {@link LocalCacheContext#leave()} method is called.
 178      */
 179     class LocalCacheContext {
 180         Map<UniquePos, ArgumentType<?>> prevCache;
 181 
 182         public LocalCacheContext() {
 183             this.prevCache = argumentTypeCache;
 184             argumentTypeCache = new HashMap<>();
 185         }
 186 
 187         public void leave() {
 188             argumentTypeCache = prevCache;
 189         }
 190     }
 191 
 192     /**
 193      * Main entry point for attributing an argument with given tree and attribution environment.
 194      */
 195     Type attribArg(JCTree tree, Env<AttrContext> env) {
 196         Env<AttrContext> prevEnv = this.env;
 197         try {
 198             this.env = env;
 199             tree.accept(this);
 200             return result;
 201         } finally {
 202             this.env = prevEnv;
 203         }
 204     }
 205 
 206     @Override
 207     public void visitTree(JCTree that) {
 208         //delegates to Attr
 209         that.accept(attr);
 210         result = attr.result;
 211     }
 212 
 213     /**
 214      * Process a method argument; this method takes care of performing a speculative pass over the
 215      * argument tree and calling a well-defined entry point to build the argument type associated
 216      * with such tree.
 217      */
 218     @SuppressWarnings("unchecked")
 219     <T extends JCExpression, Z extends ArgumentType<T>> void processArg(T that, Function<T, Z> argumentTypeFactory) {
 220         UniquePos pos = new UniquePos(that);
 221         processArg(that, () -> {
 222             T speculativeTree = (T)deferredAttr.attribSpeculative(that, env, attr.new MethodAttrInfo() {
 223                 @Override
 224                 protected boolean needsArgumentAttr(JCTree tree) {
 225                     return !new UniquePos(tree).equals(pos);
 226                 }
 227             });
 228             return argumentTypeFactory.apply(speculativeTree);
 229         });
 230     }
 231 
 232     /**
 233      * Process a method argument; this method allows the caller to specify a custom speculative attribution
 234      * logic (this is used e.g. for lambdas).
 235      */
 236     @SuppressWarnings("unchecked")
 237     <T extends JCExpression, Z extends ArgumentType<T>> void processArg(T that, Supplier<Z> argumentTypeFactory) {
 238         UniquePos pos = new UniquePos(that);
 239         Z cached = (Z)argumentTypeCache.get(pos);
 240         if (cached != null) {
 241             //dup existing speculative type
 242             setResult(that, cached.dup(that, env));
 243         } else {
 244             Z res = argumentTypeFactory.get();
 245             argumentTypeCache.put(pos, res);
 246             setResult(that, res);
 247         }
 248     }
 249 
 250     @Override
 251     public void visitParens(JCParens that) {
 252         processArg(that, speculativeTree -> new ParensType(that, env, speculativeTree));
 253     }
 254 
 255     @Override
 256     public void visitConditional(JCConditional that) {
 257         processArg(that, speculativeTree -> new ConditionalType(that, env, speculativeTree));
 258     }
 259 
 260     @Override
 261     public void visitSwitchExpression(JCSwitchExpression that) {
 262         processArg(that, speculativeTree -> new SwitchExpressionType(that, env, speculativeTree));
 263     }
 264 
 265     @Override
 266     public void visitReference(JCMemberReference tree) {
 267         //perform arity-based check
 268         Env<AttrContext> localEnv = env.dup(tree);
 269         JCExpression exprTree;
 270         exprTree = (JCExpression)deferredAttr.attribSpeculative(tree.getQualifierExpression(), localEnv,
 271                 attr.memberReferenceQualifierResult(tree),
 272                 withLocalCacheContext());
 273         JCMemberReference mref2 = new TreeCopier<Void>(attr.make).copy(tree);
 274         mref2.expr = exprTree;
 275         Symbol lhsSym = TreeInfo.symbol(exprTree);
 276         localEnv.info.selectSuper = lhsSym != null && lhsSym.name == lhsSym.name.table.names._super;
 277         Symbol res =
 278                 attr.rs.getMemberReference(tree, localEnv, mref2,
 279                         exprTree.type, tree.name);
 280         if (!res.kind.isResolutionError()) {
 281             tree.sym = res;
 282         }
 283         if (res.kind.isResolutionTargetError() ||
 284                 res.type != null && res.type.hasTag(FORALL) ||
 285                 (res.flags() & Flags.VARARGS) != 0 ||
 286                 (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
 287                 exprTree.type.isRaw() && !exprTree.type.hasTag(ARRAY))) {
 288             tree.setOverloadKind(JCMemberReference.OverloadKind.OVERLOADED);
 289         } else {
 290             tree.setOverloadKind(JCMemberReference.OverloadKind.UNOVERLOADED);
 291         }
 292         //return a plain old deferred type for this
 293         setResult(tree, deferredAttr.new DeferredType(tree, env));
 294     }
 295 
 296     @Override
 297     public void visitLambda(JCLambda that) {
 298         if (that.paramKind == ParameterKind.EXPLICIT) {
 299             //if lambda is explicit, we can save info in the corresponding argument type
 300             processArg(that, () -> {
 301                 JCLambda speculativeLambda =
 302                         deferredAttr.attribSpeculativeLambda(that, env, attr.methodAttrInfo);
 303                 return new ExplicitLambdaType(that, env, speculativeLambda);
 304             });
 305         } else {
 306             //otherwise just use a deferred type
 307             setResult(that, deferredAttr.new DeferredType(that, env));
 308         }
 309     }
 310 
 311     @Override
 312     public void visitApply(JCMethodInvocation that) {
 313         if (that.getTypeArguments().isEmpty()) {
 314             processArg(that, speculativeTree -> new ResolvedMethodType(that, env, speculativeTree));
 315         } else {
 316             //not a poly expression, just call Attr
 317             setResult(that, attr.attribTree(that, env, attr.unknownExprInfo));
 318         }
 319     }
 320 
 321     @Override
 322     public void visitNewClass(JCNewClass that) {
 323         if (TreeInfo.isDiamond(that)) {
 324             processArg(that, speculativeTree -> new ResolvedConstructorType(that, env, speculativeTree));
 325         } else {
 326             //not a poly expression, just call Attr
 327             setResult(that, attr.attribTree(that, env, attr.unknownExprInfo));
 328         }
 329     }
 330 
 331     /**
 332      * An argument type is similar to a plain deferred type; the most important difference is that
 333      * the completion logic associated with argument types allows speculative attribution to be skipped
 334      * during overload resolution - that is, an argument type always has enough information to
 335      * perform an overload check without the need of calling back to Attr. This extra information
 336      * is typically stored in the form of a speculative tree.
 337      */
 338     abstract class ArgumentType<T extends JCExpression> extends DeferredType implements DeferredTypeCompleter {
 339 
 340         /** The speculative tree carrying type information. */
 341         T speculativeTree;
 342 
 343         /** Types associated with this argument (one type per possible target result). */
 344         Map<ResultInfo, Type> speculativeTypes;
 345 
 346         public ArgumentType(JCExpression tree, Env<AttrContext> env, T speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
 347             deferredAttr.super(tree, env);
 348             this.speculativeTree = speculativeTree;
 349             this.speculativeTypes = speculativeTypes;
 350         }
 351 
 352         @Override
 353         final DeferredTypeCompleter completer() {
 354             return this;
 355         }
 356 
 357         @Override
 358         final public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 359             Assert.check(dt == this);
 360             if (deferredAttrContext.mode == AttrMode.SPECULATIVE) {
 361                 Type t = (resultInfo.pt == Type.recoveryType) ?
 362                         deferredAttr.basicCompleter.complete(dt, resultInfo, deferredAttrContext) :
 363                         overloadCheck(resultInfo, deferredAttrContext);
 364                 speculativeTypes.put(resultInfo, t);
 365                 return t;
 366             } else {
 367                 if (!env.info.isSpeculative) {
 368                     argumentTypeCache.remove(new UniquePos(dt.tree));
 369                 }
 370                 return deferredAttr.basicCompleter.complete(dt, resultInfo, deferredAttrContext);
 371             }
 372         }
 373 
 374         @Override
 375         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
 376             if (notPertinentToApplicability.contains(msym)) {
 377                 return super.speculativeType(msym, phase);
 378             } else {
 379                 for (Map.Entry<ResultInfo, Type> _entry : speculativeTypes.entrySet()) {
 380                     DeferredAttrContext deferredAttrContext = _entry.getKey().checkContext.deferredAttrContext();
 381                     if (deferredAttrContext.phase == phase && deferredAttrContext.msym == msym) {
 382                         return _entry.getValue();
 383                     }
 384                 }
 385                 return Type.noType;
 386             }
 387         }
 388 
 389         @Override
 390         JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
 391             return notPertinentToApplicability.contains(deferredAttrContext.msym) ?
 392                     super.speculativeTree(deferredAttrContext) :
 393                     speculativeTree;
 394         }
 395 
 396         /**
 397          * Performs an overload check against a given target result.
 398          */
 399         abstract Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
 400 
 401         /**
 402          * Creates a copy of this argument type with given tree and environment.
 403          */
 404         abstract ArgumentType<T> dup(T tree, Env<AttrContext> env);
 405     }
 406 
 407     /**
 408      * Argument type for parenthesized expression.
 409      */
 410     class ParensType extends ArgumentType<JCParens> {
 411         ParensType(JCExpression tree, Env<AttrContext> env, JCParens speculativeParens) {
 412             this(tree, env, speculativeParens, new HashMap<>());
 413         }
 414 
 415         ParensType(JCExpression tree, Env<AttrContext> env, JCParens speculativeParens, Map<ResultInfo, Type> speculativeTypes) {
 416            super(tree, env, speculativeParens, speculativeTypes);
 417         }
 418 
 419         @Override
 420         Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 421             return checkSpeculative(speculativeTree.expr, resultInfo);
 422         }
 423 
 424         @Override
 425         ArgumentType<JCParens> dup(JCParens tree, Env<AttrContext> env) {
 426             return new ParensType(tree, env, speculativeTree, speculativeTypes);
 427         }
 428     }
 429 
 430     /**
 431      * Argument type for conditionals.
 432      */
 433     class ConditionalType extends ArgumentType<JCConditional> {
 434         ConditionalType(JCExpression tree, Env<AttrContext> env, JCConditional speculativeCond) {
 435             this(tree, env, speculativeCond, new HashMap<>());
 436         }
 437 
 438         ConditionalType(JCExpression tree, Env<AttrContext> env, JCConditional speculativeCond, Map<ResultInfo, Type> speculativeTypes) {
 439            super(tree, env, speculativeCond, speculativeTypes);
 440         }
 441 
 442         @Override
 443         Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 444             ResultInfo localInfo = resultInfo.dup(attr.conditionalContext(resultInfo.checkContext));
 445             if (speculativeTree.isStandalone()) {
 446                 return localInfo.check(speculativeTree, speculativeTree.type);
 447             } else if (resultInfo.pt.hasTag(VOID)) {
 448                 //this means we are returning a poly conditional from void-compatible lambda expression
 449                 resultInfo.checkContext.report(tree, attr.diags.fragment(Fragments.ConditionalTargetCantBeVoid));
 450                 return attr.types.createErrorType(resultInfo.pt);
 451             } else {
 452                 //poly
 453                 checkSpeculative(speculativeTree.truepart, localInfo);
 454                 checkSpeculative(speculativeTree.falsepart, localInfo);
 455                 return localInfo.pt;
 456             }
 457         }
 458 
 459         @Override
 460         ArgumentType<JCConditional> dup(JCConditional tree, Env<AttrContext> env) {
 461             return new ConditionalType(tree, env, speculativeTree, speculativeTypes);
 462         }
 463     }
 464 
 465     /**
 466      * Argument type for switch expressions.
 467      */
 468     class SwitchExpressionType extends ArgumentType<JCSwitchExpression> {
 469         /** List of break expressions (lazily populated). */
 470         Optional<List<JCBreak>> breakExpressions = Optional.empty();
 471 
 472         SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond) {
 473             this(tree, env, speculativeCond, new HashMap<>());
 474         }
 475 
 476         SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond, Map<ResultInfo, Type> speculativeTypes) {
 477            super(tree, env, speculativeCond, speculativeTypes);
 478         }
 479 
 480         @Override
 481         Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 482             ResultInfo localInfo = resultInfo.dup(attr.conditionalContext(resultInfo.checkContext));
 483             if (resultInfo.pt.hasTag(VOID)) {
 484                 //this means we are returning a poly switch expression from void-compatible lambda expression
 485                 resultInfo.checkContext.report(tree, attr.diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
 486                 return attr.types.createErrorType(resultInfo.pt);
 487             } else {
 488                 //poly
 489                 for (JCBreak brk : breakExpressions()) {
 490                     checkSpeculative(brk.value, brk.value.type, resultInfo);
 491                 }
 492                 return localInfo.pt;
 493             }
 494         }
 495 
 496         /** Compute return expressions (if needed). */
 497         List<JCBreak> breakExpressions() {
 498             return breakExpressions.orElseGet(() -> {
 499                 final List<JCBreak> res;
 500                 ListBuffer<JCBreak> buf = new ListBuffer<>();
 501                 new SwitchExpressionScanner() {
 502                     @Override
 503                     public void visitBreak(JCBreak tree) {
 504                         if (tree.target == speculativeTree)
 505                             buf.add(tree);
 506                     }
 507                 }.scan(speculativeTree.cases);
 508                 res = buf.toList();
 509                 breakExpressions = Optional.of(res);
 510                 return res;
 511             });
 512         }
 513 
 514         @Override
 515         ArgumentType<JCSwitchExpression> dup(JCSwitchExpression tree, Env<AttrContext> env) {
 516             return new SwitchExpressionType(tree, env, speculativeTree, speculativeTypes);
 517         }
 518     }
 519 
 520     /**
 521      * Argument type for explicit lambdas.
 522      */
 523     class ExplicitLambdaType extends ArgumentType<JCLambda> {
 524 
 525         /** List of argument types (lazily populated). */
 526         Optional<List<Type>> argtypes = Optional.empty();
 527 
 528         /** List of return expressions (lazily populated). */
 529         Optional<List<JCReturn>> returnExpressions = Optional.empty();
 530 
 531         ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda) {
 532             this(originalLambda, env, speculativeLambda, new HashMap<>());
 533         }
 534 
 535         ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda, Map<ResultInfo, Type> speculativeTypes) {
 536             super(originalLambda, env, speculativeLambda, speculativeTypes);
 537         }
 538 
 539         /** Compute argument types (if needed). */
 540         List<Type> argtypes() {
 541             return argtypes.orElseGet(() -> {
 542                 List<Type> res = TreeInfo.types(speculativeTree.params);
 543                 argtypes = Optional.of(res);
 544                 return res;
 545             });
 546         }
 547 
 548         /** Compute return expressions (if needed). */
 549         List<JCReturn> returnExpressions() {
 550             return returnExpressions.orElseGet(() -> {
 551                 final List<JCReturn> res;
 552                 ListBuffer<JCReturn> buf = new ListBuffer<>();
 553                 new LambdaReturnScanner() {
 554                     @Override
 555                     public void visitReturn(JCReturn tree) {
 556                         buf.add(tree);
 557                     }
 558                 }.scan(speculativeTree.body);
 559                 res = buf.toList();
 560                 returnExpressions = Optional.of(res);
 561                 return res;
 562             });
 563         }
 564 
 565         @Override
 566         Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 567             try {
 568                 //compute target-type; this logic could be shared with Attr
 569                 TargetInfo targetInfo = attr.getTargetInfo(speculativeTree, resultInfo, argtypes());
 570                 Type lambdaType = targetInfo.descriptor;
 571                 Type currentTarget = targetInfo.target;
 572                 //check compatibility
 573                 checkLambdaCompatible(lambdaType, resultInfo);
 574                 return currentTarget;
 575             } catch (FunctionDescriptorLookupError ex) {
 576                 resultInfo.checkContext.report(null, ex.getDiagnostic());
 577                 return null; //cannot get here
 578             }
 579         }
 580 
 581         /** Check lambda against given target result */
 582         private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) {
 583             CheckContext checkContext = resultInfo.checkContext;
 584             ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo);
 585             switch (speculativeTree.getBodyKind()) {
 586                 case EXPRESSION:
 587                     checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo);
 588                     break;
 589                 case STATEMENT:
 590                     for (JCReturn ret : returnExpressions()) {
 591                         checkReturnInStatementLambda(ret, bodyResultInfo);
 592                     }
 593                     break;
 594             }
 595 
 596             attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext);
 597         }
 598 
 599         /**
 600          * This is an inlined version of {@link Attr#visitReturn(JCReturn)}.
 601          */
 602         void checkReturnInStatementLambda(JCReturn ret, ResultInfo resultInfo) {
 603             if (resultInfo.pt.hasTag(VOID) && ret.expr != null) {
 604                 //fail - if the function type's result is void, the lambda body must be a void-compatible block.
 605                 resultInfo.checkContext.report(speculativeTree.pos(),
 606                         diags.fragment("unexpected.ret.val"));
 607             } else if (!resultInfo.pt.hasTag(VOID)) {
 608                 if (ret.expr == null) {
 609                     //fail - if the function type's result is non-void, the lambda body must be a value-compatible block.
 610                     resultInfo.checkContext.report(speculativeTree.pos(),
 611                             diags.fragment("missing.ret.val"));
 612                 }
 613                 checkSpeculative(ret.expr, ret.expr.type, resultInfo);
 614             }
 615         }
 616 
 617         /** Get the type associated with given return expression. */
 618         Type getReturnType(JCReturn ret) {
 619             if (ret.expr == null) {
 620                 return syms.voidType;
 621             } else {
 622                 return ret.expr.type;
 623             }
 624         }
 625 
 626         @Override
 627         ArgumentType<JCLambda> dup(JCLambda tree, Env<AttrContext> env) {
 628             return new ExplicitLambdaType(tree, env, speculativeTree, speculativeTypes);
 629         }
 630     }
 631 
 632     /**
 633      * Argument type for methods/constructors.
 634      */
 635     abstract class ResolvedMemberType<E extends JCExpression> extends ArgumentType<E> {
 636 
 637         public ResolvedMemberType(JCExpression tree, Env<AttrContext> env, E speculativeMethod, Map<ResultInfo, Type> speculativeTypes) {
 638             super(tree, env, speculativeMethod, speculativeTypes);
 639         }
 640 
 641         @Override
 642         Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 643             Type mtype = methodType();
 644             ResultInfo localInfo = resultInfo(resultInfo);
 645             Type t;
 646             if (mtype != null && mtype.hasTag(METHOD) && mtype.isPartial()) {
 647                 //poly invocation
 648                 t = ((PartiallyInferredMethodType)mtype).check(localInfo);
 649             } else {
 650                 //standalone invocation
 651                 t = localInfo.check(tree.pos(), speculativeTree.type);
 652             }
 653             speculativeTypes.put(localInfo, t);
 654             return t;
 655         }
 656 
 657         /**
 658          * Get the result info to be used for performing an overload check.
 659          */
 660         abstract ResultInfo resultInfo(ResultInfo resultInfo);
 661 
 662         /**
 663          * Get the method type to be used for performing an overload check.
 664          */
 665         abstract Type methodType();
 666     }
 667 
 668     /**
 669      * Argument type for methods.
 670      */
 671     class ResolvedMethodType extends ResolvedMemberType<JCMethodInvocation> {
 672 
 673         public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree) {
 674             this(tree, env, speculativeTree, new HashMap<>());
 675         }
 676 
 677         public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
 678             super(tree, env, speculativeTree, speculativeTypes);
 679         }
 680 
 681         @Override
 682         ResultInfo resultInfo(ResultInfo resultInfo) {
 683             return resultInfo;
 684         }
 685 
 686         @Override
 687         Type methodType() {
 688             return speculativeTree.meth.type;
 689         }
 690 
 691         @Override
 692         ArgumentType<JCMethodInvocation> dup(JCMethodInvocation tree, Env<AttrContext> env) {
 693             return new ResolvedMethodType(tree, env, speculativeTree, speculativeTypes);
 694         }
 695     }
 696 
 697     /**
 698      * Argument type for constructors.
 699      */
 700     class ResolvedConstructorType extends ResolvedMemberType<JCNewClass> {
 701 
 702         public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree) {
 703             this(tree, env, speculativeTree, new HashMap<>());
 704         }
 705 
 706         public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree, Map<ResultInfo, Type> speculativeTypes) {
 707             super(tree, env, speculativeTree, speculativeTypes);
 708         }
 709 
 710         @Override
 711         ResultInfo resultInfo(ResultInfo resultInfo) {
 712             return resultInfo.dup(attr.diamondContext(speculativeTree, speculativeTree.clazz.type.tsym, resultInfo.checkContext));
 713         }
 714 
 715         @Override
 716         Type methodType() {
 717             return (speculativeTree.constructorType != null) ?
 718                     speculativeTree.constructorType.baseType() : syms.errType;
 719         }
 720 
 721         @Override
 722         ArgumentType<JCNewClass> dup(JCNewClass tree, Env<AttrContext> env) {
 723             return new ResolvedConstructorType(tree, env, speculativeTree, speculativeTypes);
 724         }
 725     }
 726 
 727     /**
 728      * An instance of this class represents a unique position in a compilation unit. A unique
 729      * position is made up of (i) a unique position in a source file (char offset) and (ii)
 730      * a source file info.
 731      */
 732     class UniquePos {
 733 
 734         /** Char offset. */
 735         int pos;
 736 
 737         /** Source info. */
 738         DiagnosticSource source;
 739 
 740         UniquePos(JCTree tree) {
 741             this.pos = tree.pos;
 742             this.source = log.currentSource();
 743         }
 744 
 745         @Override
 746         public int hashCode() {
 747             return pos << 16 + source.hashCode();
 748         }
 749 
 750         @Override
 751         public boolean equals(Object obj) {
 752             if (obj instanceof UniquePos) {
 753                 UniquePos that = (UniquePos)obj;
 754                 return pos == that.pos && source == that.source;
 755             } else {
 756                 return false;
 757             }
 758         }
 759 
 760         @Override
 761         public String toString() {
 762             return source.getFile().getName() + " @ " + source.getLineNumber(pos);
 763         }
 764     }
 765 }