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 (speculativeTree.isStandalone()) { 484 return localInfo.check(speculativeTree, speculativeTree.type); 485 } else if (resultInfo.pt.hasTag(VOID)) { 486 //this means we are returning a poly switch expression from void-compatible lambda expression 487 resultInfo.checkContext.report(tree, attr.diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid)); 488 return attr.types.createErrorType(resultInfo.pt); 489 } else { 490 //poly 491 for (JCBreak brk : breakExpressions()) { 492 checkSpeculative(brk.value, brk.value.type, resultInfo); 493 } 494 return localInfo.pt; 495 } 496 } 497 498 /** Compute return expressions (if needed). */ 499 List<JCBreak> breakExpressions() { 500 return breakExpressions.orElseGet(() -> { 501 final List<JCBreak> res; 502 ListBuffer<JCBreak> buf = new ListBuffer<>(); 503 new SwitchExpressionScanner() { 504 @Override 505 public void visitBreak(JCBreak tree) { 506 if (tree.target == speculativeTree) 507 buf.add(tree); 508 } 509 }.scan(speculativeTree.cases); 510 res = buf.toList(); 511 breakExpressions = Optional.of(res); 512 return res; 513 }); 514 } 515 516 @Override 517 ArgumentType<JCSwitchExpression> dup(JCSwitchExpression tree, Env<AttrContext> env) { 518 return new SwitchExpressionType(tree, env, speculativeTree, speculativeTypes); 519 } 520 } 521 522 /** 523 * Argument type for explicit lambdas. 524 */ 525 class ExplicitLambdaType extends ArgumentType<JCLambda> { 526 527 /** List of argument types (lazily populated). */ 528 Optional<List<Type>> argtypes = Optional.empty(); 529 530 /** List of return expressions (lazily populated). */ 531 Optional<List<JCReturn>> returnExpressions = Optional.empty(); 532 533 ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda) { 534 this(originalLambda, env, speculativeLambda, new HashMap<>()); 535 } 536 537 ExplicitLambdaType(JCLambda originalLambda, Env<AttrContext> env, JCLambda speculativeLambda, Map<ResultInfo, Type> speculativeTypes) { 538 super(originalLambda, env, speculativeLambda, speculativeTypes); 539 } 540 541 /** Compute argument types (if needed). */ 542 List<Type> argtypes() { 543 return argtypes.orElseGet(() -> { 544 List<Type> res = TreeInfo.types(speculativeTree.params); 545 argtypes = Optional.of(res); 546 return res; 547 }); 548 } 549 550 /** Compute return expressions (if needed). */ 551 List<JCReturn> returnExpressions() { 552 return returnExpressions.orElseGet(() -> { 553 final List<JCReturn> res; 554 ListBuffer<JCReturn> buf = new ListBuffer<>(); 555 new LambdaReturnScanner() { 556 @Override 557 public void visitReturn(JCReturn tree) { 558 buf.add(tree); 559 } 560 }.scan(speculativeTree.body); 561 res = buf.toList(); 562 returnExpressions = Optional.of(res); 563 return res; 564 }); 565 } 566 567 @Override 568 Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 569 try { 570 //compute target-type; this logic could be shared with Attr 571 TargetInfo targetInfo = attr.getTargetInfo(speculativeTree, resultInfo, argtypes()); 572 Type lambdaType = targetInfo.descriptor; 573 Type currentTarget = targetInfo.target; 574 //check compatibility 575 checkLambdaCompatible(lambdaType, resultInfo); 576 return currentTarget; 577 } catch (FunctionDescriptorLookupError ex) { 578 resultInfo.checkContext.report(null, ex.getDiagnostic()); 579 return null; //cannot get here 580 } 581 } 582 583 /** Check lambda against given target result */ 584 private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) { 585 CheckContext checkContext = resultInfo.checkContext; 586 ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo); 587 switch (speculativeTree.getBodyKind()) { 588 case EXPRESSION: 589 checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo); 590 break; 591 case STATEMENT: 592 for (JCReturn ret : returnExpressions()) { 593 checkReturnInStatementLambda(ret, bodyResultInfo); 594 } 595 break; 596 } 597 598 attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext); 599 } 600 601 /** 602 * This is an inlined version of {@link Attr#visitReturn(JCReturn)}. 603 */ 604 void checkReturnInStatementLambda(JCReturn ret, ResultInfo resultInfo) { 605 if (resultInfo.pt.hasTag(VOID) && ret.expr != null) { 606 //fail - if the function type's result is void, the lambda body must be a void-compatible block. 607 resultInfo.checkContext.report(speculativeTree.pos(), 608 diags.fragment("unexpected.ret.val")); 609 } else if (!resultInfo.pt.hasTag(VOID)) { 610 if (ret.expr == null) { 611 //fail - if the function type's result is non-void, the lambda body must be a value-compatible block. 612 resultInfo.checkContext.report(speculativeTree.pos(), 613 diags.fragment("missing.ret.val")); 614 } 615 checkSpeculative(ret.expr, ret.expr.type, resultInfo); 616 } 617 } 618 619 /** Get the type associated with given return expression. */ 620 Type getReturnType(JCReturn ret) { 621 if (ret.expr == null) { 622 return syms.voidType; 623 } else { 624 return ret.expr.type; 625 } 626 } 627 628 @Override 629 ArgumentType<JCLambda> dup(JCLambda tree, Env<AttrContext> env) { 630 return new ExplicitLambdaType(tree, env, speculativeTree, speculativeTypes); 631 } 632 } 633 634 /** 635 * Argument type for methods/constructors. 636 */ 637 abstract class ResolvedMemberType<E extends JCExpression> extends ArgumentType<E> { 638 639 public ResolvedMemberType(JCExpression tree, Env<AttrContext> env, E speculativeMethod, Map<ResultInfo, Type> speculativeTypes) { 640 super(tree, env, speculativeMethod, speculativeTypes); 641 } 642 643 @Override 644 Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 645 Type mtype = methodType(); 646 ResultInfo localInfo = resultInfo(resultInfo); 647 Type t; 648 if (mtype != null && mtype.hasTag(METHOD) && mtype.isPartial()) { 649 //poly invocation 650 t = ((PartiallyInferredMethodType)mtype).check(localInfo); 651 } else { 652 //standalone invocation 653 t = localInfo.check(tree.pos(), speculativeTree.type); 654 } 655 speculativeTypes.put(localInfo, t); 656 return t; 657 } 658 659 /** 660 * Get the result info to be used for performing an overload check. 661 */ 662 abstract ResultInfo resultInfo(ResultInfo resultInfo); 663 664 /** 665 * Get the method type to be used for performing an overload check. 666 */ 667 abstract Type methodType(); 668 } 669 670 /** 671 * Argument type for methods. 672 */ 673 class ResolvedMethodType extends ResolvedMemberType<JCMethodInvocation> { 674 675 public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree) { 676 this(tree, env, speculativeTree, new HashMap<>()); 677 } 678 679 public ResolvedMethodType(JCExpression tree, Env<AttrContext> env, JCMethodInvocation speculativeTree, Map<ResultInfo, Type> speculativeTypes) { 680 super(tree, env, speculativeTree, speculativeTypes); 681 } 682 683 @Override 684 ResultInfo resultInfo(ResultInfo resultInfo) { 685 return resultInfo; 686 } 687 688 @Override 689 Type methodType() { 690 return speculativeTree.meth.type; 691 } 692 693 @Override 694 ArgumentType<JCMethodInvocation> dup(JCMethodInvocation tree, Env<AttrContext> env) { 695 return new ResolvedMethodType(tree, env, speculativeTree, speculativeTypes); 696 } 697 } 698 699 /** 700 * Argument type for constructors. 701 */ 702 class ResolvedConstructorType extends ResolvedMemberType<JCNewClass> { 703 704 public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree) { 705 this(tree, env, speculativeTree, new HashMap<>()); 706 } 707 708 public ResolvedConstructorType(JCExpression tree, Env<AttrContext> env, JCNewClass speculativeTree, Map<ResultInfo, Type> speculativeTypes) { 709 super(tree, env, speculativeTree, speculativeTypes); 710 } 711 712 @Override 713 ResultInfo resultInfo(ResultInfo resultInfo) { 714 return resultInfo.dup(attr.diamondContext(speculativeTree, speculativeTree.clazz.type.tsym, resultInfo.checkContext)); 715 } 716 717 @Override 718 Type methodType() { 719 return (speculativeTree.constructorType != null) ? 720 speculativeTree.constructorType.baseType() : syms.errType; 721 } 722 723 @Override 724 ArgumentType<JCNewClass> dup(JCNewClass tree, Env<AttrContext> env) { 725 return new ResolvedConstructorType(tree, env, speculativeTree, speculativeTypes); 726 } 727 } 728 729 /** 730 * An instance of this class represents a unique position in a compilation unit. A unique 731 * position is made up of (i) a unique position in a source file (char offset) and (ii) 732 * a source file info. 733 */ 734 class UniquePos { 735 736 /** Char offset. */ 737 int pos; 738 739 /** Source info. */ 740 DiagnosticSource source; 741 742 UniquePos(JCTree tree) { 743 this.pos = tree.pos; 744 this.source = log.currentSource(); 745 } 746 747 @Override 748 public int hashCode() { 749 return pos << 16 + source.hashCode(); 750 } 751 752 @Override 753 public boolean equals(Object obj) { 754 if (obj instanceof UniquePos) { 755 UniquePos that = (UniquePos)obj; 756 return pos == that.pos && source == that.source; 757 } else { 758 return false; 759 } 760 } 761 762 @Override 763 public String toString() { 764 return source.getFile().getName() + " @ " + source.getLineNumber(pos); 765 } 766 } 767 }