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