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