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 java.util.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.Consumer;
31 import java.util.stream.Stream;
32
33 import javax.lang.model.element.ElementKind;
34 import javax.tools.JavaFileObject;
35
36 import com.sun.source.tree.CaseTree;
37 import com.sun.source.tree.IdentifierTree;
38 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
39 import com.sun.source.tree.MemberSelectTree;
40 import com.sun.source.tree.TreeVisitor;
41 import com.sun.source.util.SimpleTreeVisitor;
42 import com.sun.tools.javac.code.*;
43 import com.sun.tools.javac.code.Lint.LintCategory;
44 import com.sun.tools.javac.code.Scope.WriteableScope;
45 import com.sun.tools.javac.code.Source.Feature;
46 import com.sun.tools.javac.code.Symbol.*;
47 import com.sun.tools.javac.code.Type.*;
48 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
49 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
50 import com.sun.tools.javac.comp.Check.CheckContext;
51 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
52 import com.sun.tools.javac.comp.MatchBindingsComputer.MatchBindings;
53 import com.sun.tools.javac.jvm.*;
54
55 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
56 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
57 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArgs;
58
59 import com.sun.tools.javac.resources.CompilerProperties.Errors;
60 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
61 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
62 import com.sun.tools.javac.tree.*;
63 import com.sun.tools.javac.tree.JCTree.*;
64 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
65 import com.sun.tools.javac.util.*;
66 import com.sun.tools.javac.util.DefinedBy.Api;
67 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
68 import com.sun.tools.javac.util.JCDiagnostic.Error;
69 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
70 import com.sun.tools.javac.util.JCDiagnostic.Warning;
71 import com.sun.tools.javac.util.List;
72
73 import static com.sun.tools.javac.code.Flags.*;
74 import static com.sun.tools.javac.code.Flags.ANNOTATION;
75 import static com.sun.tools.javac.code.Flags.BLOCK;
76 import static com.sun.tools.javac.code.Kinds.*;
77 import static com.sun.tools.javac.code.Kinds.Kind.*;
78 import static com.sun.tools.javac.code.TypeTag.*;
79 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
80 import static com.sun.tools.javac.tree.JCTree.Tag.*;
81 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
82
83 /** This is the main context-dependent analysis phase in GJC. It
426 try {
427 deferredAttr.attribSpeculative(root, env, resultInfo,
428 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
429 argumentAttr.withLocalCacheContext());
430 attrRecover.doRecovery();
431 } catch (BreakAttr b) {
432 return b.env;
433 } catch (AssertionError ae) {
434 if (ae.getCause() instanceof BreakAttr breakAttr) {
435 return breakAttr.env;
436 } else {
437 throw ae;
438 }
439 } finally {
440 breakTree = null;
441 log.useSource(prev);
442 }
443 return env;
444 }
445
446 private JCTree breakTree = null;
447
448 private static class BreakAttr extends RuntimeException {
449 static final long serialVersionUID = -6924771130405446405L;
450 private transient Env<AttrContext> env;
451 private BreakAttr(Env<AttrContext> env) {
452 this.env = env;
453 }
454 }
455
456 /**
457 * Mode controlling behavior of Attr.Check
458 */
459 enum CheckMode {
460
461 NORMAL,
462
463 /**
464 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
465 * that the captured var cache in {@code InferenceContext} will be used in read-only
3119 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3120 }
3121
3122 /*
3123 * A lambda expression can only be attributed when a target-type is available.
3124 * In addition, if the target-type is that of a functional interface whose
3125 * descriptor contains inference variables in argument position the lambda expression
3126 * is 'stuck' (see DeferredAttr).
3127 */
3128 @Override
3129 public void visitLambda(final JCLambda that) {
3130 boolean wrongContext = false;
3131 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3132 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3133 //lambda only allowed in assignment or method invocation/cast context
3134 log.error(that.pos(), Errors.UnexpectedLambda);
3135 }
3136 resultInfo = recoveryInfo;
3137 wrongContext = true;
3138 }
3139 //create an environment for attribution of the lambda expression
3140 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3141 boolean needsRecovery =
3142 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3143 try {
3144 if (needsRecovery && rs.isSerializable(pt())) {
3145 localEnv.info.isSerializable = true;
3146 localEnv.info.isSerializableLambda = true;
3147 }
3148 List<Type> explicitParamTypes = null;
3149 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3150 //attribute lambda parameters
3151 attribStats(that.params, localEnv);
3152 explicitParamTypes = TreeInfo.types(that.params);
3153 }
3154
3155 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3156 Type currentTarget = targetInfo.target;
3157 Type lambdaType = targetInfo.descriptor;
3158
3262 chk.completionError(that.pos(), cf);
3263 } catch (Throwable t) {
3264 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3265 //as that would likely cause the same exception again.
3266 needsRecovery = false;
3267 throw t;
3268 } finally {
3269 localEnv.info.scope.leave();
3270 if (needsRecovery) {
3271 Type prevResult = result;
3272 try {
3273 attribTree(that, env, recoveryInfo);
3274 } finally {
3275 if (result == Type.recoveryType) {
3276 result = prevResult;
3277 }
3278 }
3279 }
3280 }
3281 }
3282 //where
3283 class TargetInfo {
3284 Type target;
3285 Type descriptor;
3286
3287 public TargetInfo(Type target, Type descriptor) {
3288 this.target = target;
3289 this.descriptor = descriptor;
3290 }
3291 }
3292
3293 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3294 Type lambdaType;
3295 Type currentTarget = resultInfo.pt;
3296 if (resultInfo.pt != Type.recoveryType) {
3297 /* We need to adjust the target. If the target is an
3298 * intersection type, for example: SAM & I1 & I2 ...
3299 * the target will be updated to SAM
3300 */
3301 currentTarget = targetChecker.visit(currentTarget, that);
|
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 java.util.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.Consumer;
31 import java.util.function.Function;
32 import java.util.stream.Stream;
33
34 import javax.lang.model.element.ElementKind;
35 import javax.tools.JavaFileObject;
36
37 import com.sun.source.tree.CaseTree;
38 import com.sun.source.tree.IdentifierTree;
39 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
40 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
41 import com.sun.source.tree.MemberSelectTree;
42 import com.sun.source.tree.TreeVisitor;
43 import com.sun.source.util.SimpleTreeVisitor;
44 import com.sun.tools.javac.code.*;
45 import com.sun.tools.javac.code.Lint.LintCategory;
46 import com.sun.tools.javac.code.Scope.WriteableScope;
47 import com.sun.tools.javac.code.Source.Feature;
48 import com.sun.tools.javac.code.Symbol.*;
49 import com.sun.tools.javac.code.Type.*;
50 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
51 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
52 import com.sun.tools.javac.comp.Attr.ResultInfo;
53 import com.sun.tools.javac.comp.Check.CheckContext;
54 import com.sun.tools.javac.comp.Check.NestedCheckContext;
55 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
56 import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
57 import com.sun.tools.javac.comp.MatchBindingsComputer.MatchBindings;
58 import com.sun.tools.javac.jvm.*;
59
60 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
61 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
62 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArgs;
63
64 import com.sun.tools.javac.resources.CompilerProperties.Errors;
65 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
66 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
67 import com.sun.tools.javac.tree.*;
68 import com.sun.tools.javac.tree.JCTree.*;
69 import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
70 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
71 import com.sun.tools.javac.util.*;
72 import com.sun.tools.javac.util.DefinedBy.Api;
73 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
74 import com.sun.tools.javac.util.JCDiagnostic.Error;
75 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
76 import com.sun.tools.javac.util.JCDiagnostic.Warning;
77 import com.sun.tools.javac.util.List;
78
79 import static com.sun.tools.javac.code.Flags.*;
80 import static com.sun.tools.javac.code.Flags.ANNOTATION;
81 import static com.sun.tools.javac.code.Flags.BLOCK;
82 import static com.sun.tools.javac.code.Kinds.*;
83 import static com.sun.tools.javac.code.Kinds.Kind.*;
84 import static com.sun.tools.javac.code.TypeTag.*;
85 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
86 import static com.sun.tools.javac.tree.JCTree.Tag.*;
87 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
88
89 /** This is the main context-dependent analysis phase in GJC. It
432 try {
433 deferredAttr.attribSpeculative(root, env, resultInfo,
434 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
435 argumentAttr.withLocalCacheContext());
436 attrRecover.doRecovery();
437 } catch (BreakAttr b) {
438 return b.env;
439 } catch (AssertionError ae) {
440 if (ae.getCause() instanceof BreakAttr breakAttr) {
441 return breakAttr.env;
442 } else {
443 throw ae;
444 }
445 } finally {
446 breakTree = null;
447 log.useSource(prev);
448 }
449 return env;
450 }
451
452 public <R> R runWithAttributedMethod(Env<AttrContext> env, JCMethodDecl tree, Function<JCBlock, R> attributedAction) {
453 JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
454 try {
455 JCBlock dupTree = (JCBlock)deferredAttr.attribSpeculative(tree.body, env, statInfo,
456 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
457 argumentAttr.withLocalCacheContext());
458 return attributedAction.apply(dupTree);
459 } finally {
460 attrRecover.doRecovery();
461 log.useSource(prevSource);
462 }
463 }
464
465 private JCTree breakTree = null;
466
467 private static class BreakAttr extends RuntimeException {
468 static final long serialVersionUID = -6924771130405446405L;
469 private transient Env<AttrContext> env;
470 private BreakAttr(Env<AttrContext> env) {
471 this.env = env;
472 }
473 }
474
475 /**
476 * Mode controlling behavior of Attr.Check
477 */
478 enum CheckMode {
479
480 NORMAL,
481
482 /**
483 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
484 * that the captured var cache in {@code InferenceContext} will be used in read-only
3138 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3139 }
3140
3141 /*
3142 * A lambda expression can only be attributed when a target-type is available.
3143 * In addition, if the target-type is that of a functional interface whose
3144 * descriptor contains inference variables in argument position the lambda expression
3145 * is 'stuck' (see DeferredAttr).
3146 */
3147 @Override
3148 public void visitLambda(final JCLambda that) {
3149 boolean wrongContext = false;
3150 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3151 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3152 //lambda only allowed in assignment or method invocation/cast context
3153 log.error(that.pos(), Errors.UnexpectedLambda);
3154 }
3155 resultInfo = recoveryInfo;
3156 wrongContext = true;
3157 }
3158 if (types.isQuoted(pt())) {
3159 attribQuotedLambda(that);
3160 } else {
3161 attribFunctionalLambda(that, wrongContext);
3162 }
3163 }
3164
3165 void attribFunctionalLambda(JCLambda that, boolean wrongContext) {
3166 //create an environment for attribution of the lambda expression
3167 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3168 boolean needsRecovery =
3169 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3170 try {
3171 if (needsRecovery && rs.isSerializable(pt())) {
3172 localEnv.info.isSerializable = true;
3173 localEnv.info.isSerializableLambda = true;
3174 }
3175 List<Type> explicitParamTypes = null;
3176 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3177 //attribute lambda parameters
3178 attribStats(that.params, localEnv);
3179 explicitParamTypes = TreeInfo.types(that.params);
3180 }
3181
3182 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3183 Type currentTarget = targetInfo.target;
3184 Type lambdaType = targetInfo.descriptor;
3185
3289 chk.completionError(that.pos(), cf);
3290 } catch (Throwable t) {
3291 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3292 //as that would likely cause the same exception again.
3293 needsRecovery = false;
3294 throw t;
3295 } finally {
3296 localEnv.info.scope.leave();
3297 if (needsRecovery) {
3298 Type prevResult = result;
3299 try {
3300 attribTree(that, env, recoveryInfo);
3301 } finally {
3302 if (result == Type.recoveryType) {
3303 result = prevResult;
3304 }
3305 }
3306 }
3307 }
3308 }
3309
3310 void attribQuotedLambda(JCLambda that) {
3311 // create an environment for attribution of the lambda expression
3312 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3313 try {
3314 // if quoted lambda is implicit, issue error, and recover
3315 if (that.paramKind == ParameterKind.IMPLICIT) {
3316 log.error(that, Errors.QuotedLambdaMustBeExplicit);
3317 // recovery
3318 List<JCVariableDecl> params = that.params;
3319 while (params.nonEmpty()) {
3320 Type argType = syms.errType;
3321 if (params.head.isImplicitlyTyped()) {
3322 setSyntheticVariableType(params.head, argType);
3323 }
3324 params = params.tail;
3325 }
3326 }
3327 // attribute lambda parameters
3328 attribStats(that.params, localEnv);
3329 List<Type> explicitParamTypes = TreeInfo.types(that.params);
3330
3331 ListBuffer<Type> restypes = new ListBuffer<>();
3332 ListBuffer<DiagnosticPosition> resPositions = new ListBuffer<>();
3333 ResultInfo bodyResultInfo = localEnv.info.returnResult = unknownExprInfo;
3334
3335 // type-check lambda body, and capture return types
3336 if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3337 attribTree(that.getBody(), localEnv, bodyResultInfo);
3338 restypes.add(that.getBody().type);
3339 } else {
3340 JCBlock body = (JCBlock)that.body;
3341 if (body == breakTree &&
3342 resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
3343 breakTreeFound(copyEnv(localEnv));
3344 }
3345 attribStats(body.stats, localEnv);
3346 new LambdaReturnScanner() {
3347 @Override
3348 public void visitReturn(JCReturn tree) {
3349 if (tree.expr != null) {
3350 resPositions.add(tree);
3351 }
3352 restypes.add(tree.expr == null ? syms.voidType : tree.expr.type);
3353 }
3354 }.scan(body);
3355 }
3356
3357 // check if lambda body can complete normally
3358 preFlow(that);
3359 flow.analyzeLambda(localEnv, that, make, false);
3360
3361 final Type restype;
3362 if (that.getBodyKind() == BodyKind.STATEMENT) {
3363 if (that.canCompleteNormally) {
3364 // a lambda that completes normally has an implicit void return
3365 restypes.add(syms.voidType);
3366 }
3367
3368 boolean hasNonVoidReturn = restypes.toList()
3369 .stream().anyMatch(t -> t != syms.voidType);
3370 boolean hasVoidReturn = restypes.toList()
3371 .stream().anyMatch(t -> t == syms.voidType);
3372
3373 if (hasVoidReturn && hasNonVoidReturn) {
3374 // void vs. non-void mismatch
3375 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3376 restype = syms.errorType;
3377 } else if (hasVoidReturn) {
3378 restype = syms.voidType;
3379 } else {
3380 restype = condType(resPositions.toList(), restypes.toList());
3381 }
3382 } else {
3383 restype = restypes.first();
3384 }
3385
3386 // infer lambda return type using lub
3387 if (restype.hasTag(ERROR)) {
3388 // some other error occurred
3389 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3390 }
3391
3392 // infer thrown types
3393 List<Type> thrownTypes = flow.analyzeLambdaThrownTypes(localEnv, that, make);
3394
3395 // set up target descriptor with explicit parameter types, and inferred thrown/return types
3396 that.target = new MethodType(explicitParamTypes, restype, thrownTypes, syms.methodClass);
3397 result = that.type = pt();
3398 } finally {
3399 localEnv.info.scope.leave();
3400 }
3401 }
3402 //where
3403 class TargetInfo {
3404 Type target;
3405 Type descriptor;
3406
3407 public TargetInfo(Type target, Type descriptor) {
3408 this.target = target;
3409 this.descriptor = descriptor;
3410 }
3411 }
3412
3413 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3414 Type lambdaType;
3415 Type currentTarget = resultInfo.pt;
3416 if (resultInfo.pt != Type.recoveryType) {
3417 /* We need to adjust the target. If the target is an
3418 * intersection type, for example: SAM & I1 & I2 ...
3419 * the target will be updated to SAM
3420 */
3421 currentTarget = targetChecker.visit(currentTarget, that);
|