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 }