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.LintWarnings;
62 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
63 import com.sun.tools.javac.tree.*;
64 import com.sun.tools.javac.tree.JCTree.*;
65 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
66 import com.sun.tools.javac.util.*;
67 import com.sun.tools.javac.util.DefinedBy.Api;
68 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
69 import com.sun.tools.javac.util.JCDiagnostic.Error;
70 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
71 import com.sun.tools.javac.util.JCDiagnostic.Warning;
72 import com.sun.tools.javac.util.List;
73
74 import static com.sun.tools.javac.code.Flags.*;
75 import static com.sun.tools.javac.code.Flags.ANNOTATION;
76 import static com.sun.tools.javac.code.Flags.BLOCK;
77 import static com.sun.tools.javac.code.Kinds.*;
78 import static com.sun.tools.javac.code.Kinds.Kind.*;
79 import static com.sun.tools.javac.code.TypeTag.*;
80 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
81 import static com.sun.tools.javac.tree.JCTree.Tag.*;
82 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
83
84 /** This is the main context-dependent analysis phase in GJC. It
427 try {
428 deferredAttr.attribSpeculative(root, env, resultInfo,
429 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
430 argumentAttr.withLocalCacheContext());
431 attrRecover.doRecovery();
432 } catch (BreakAttr b) {
433 return b.env;
434 } catch (AssertionError ae) {
435 if (ae.getCause() instanceof BreakAttr breakAttr) {
436 return breakAttr.env;
437 } else {
438 throw ae;
439 }
440 } finally {
441 breakTree = null;
442 log.useSource(prev);
443 }
444 return env;
445 }
446
447 private JCTree breakTree = null;
448
449 private static class BreakAttr extends RuntimeException {
450 static final long serialVersionUID = -6924771130405446405L;
451 private transient Env<AttrContext> env;
452 private BreakAttr(Env<AttrContext> env) {
453 this.env = env;
454 }
455 }
456
457 /**
458 * Mode controlling behavior of Attr.Check
459 */
460 enum CheckMode {
461
462 NORMAL,
463
464 /**
465 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
466 * that the captured var cache in {@code InferenceContext} will be used in read-only
3144 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3145 }
3146
3147 /*
3148 * A lambda expression can only be attributed when a target-type is available.
3149 * In addition, if the target-type is that of a functional interface whose
3150 * descriptor contains inference variables in argument position the lambda expression
3151 * is 'stuck' (see DeferredAttr).
3152 */
3153 @Override
3154 public void visitLambda(final JCLambda that) {
3155 boolean wrongContext = false;
3156 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3157 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3158 //lambda only allowed in assignment or method invocation/cast context
3159 log.error(that.pos(), Errors.UnexpectedLambda);
3160 }
3161 resultInfo = recoveryInfo;
3162 wrongContext = true;
3163 }
3164 //create an environment for attribution of the lambda expression
3165 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3166 boolean needsRecovery =
3167 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3168 try {
3169 if (needsRecovery && rs.isSerializable(pt())) {
3170 localEnv.info.isSerializable = true;
3171 localEnv.info.isSerializableLambda = true;
3172 }
3173 List<Type> explicitParamTypes = null;
3174 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3175 //attribute lambda parameters
3176 attribStats(that.params, localEnv);
3177 explicitParamTypes = TreeInfo.types(that.params);
3178 }
3179
3180 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3181 Type currentTarget = targetInfo.target;
3182 Type lambdaType = targetInfo.descriptor;
3183
3287 chk.completionError(that.pos(), cf);
3288 } catch (Throwable t) {
3289 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3290 //as that would likely cause the same exception again.
3291 needsRecovery = false;
3292 throw t;
3293 } finally {
3294 localEnv.info.scope.leave();
3295 if (needsRecovery) {
3296 Type prevResult = result;
3297 try {
3298 attribTree(that, env, recoveryInfo);
3299 } finally {
3300 if (result == Type.recoveryType) {
3301 result = prevResult;
3302 }
3303 }
3304 }
3305 }
3306 }
3307 //where
3308 class TargetInfo {
3309 Type target;
3310 Type descriptor;
3311
3312 public TargetInfo(Type target, Type descriptor) {
3313 this.target = target;
3314 this.descriptor = descriptor;
3315 }
3316 }
3317
3318 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3319 Type lambdaType;
3320 Type currentTarget = resultInfo.pt;
3321 if (resultInfo.pt != Type.recoveryType) {
3322 /* We need to adjust the target. If the target is an
3323 * intersection type, for example: SAM & I1 & I2 ...
3324 * the target will be updated to SAM
3325 */
3326 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.LintWarnings;
67 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
68 import com.sun.tools.javac.tree.*;
69 import com.sun.tools.javac.tree.JCTree.*;
70 import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
71 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
72 import com.sun.tools.javac.util.*;
73 import com.sun.tools.javac.util.DefinedBy.Api;
74 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
75 import com.sun.tools.javac.util.JCDiagnostic.Error;
76 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
77 import com.sun.tools.javac.util.JCDiagnostic.Warning;
78 import com.sun.tools.javac.util.List;
79
80 import static com.sun.tools.javac.code.Flags.*;
81 import static com.sun.tools.javac.code.Flags.ANNOTATION;
82 import static com.sun.tools.javac.code.Flags.BLOCK;
83 import static com.sun.tools.javac.code.Kinds.*;
84 import static com.sun.tools.javac.code.Kinds.Kind.*;
85 import static com.sun.tools.javac.code.TypeTag.*;
86 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
87 import static com.sun.tools.javac.tree.JCTree.Tag.*;
88 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
89
90 /** This is the main context-dependent analysis phase in GJC. It
433 try {
434 deferredAttr.attribSpeculative(root, env, resultInfo,
435 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
436 argumentAttr.withLocalCacheContext());
437 attrRecover.doRecovery();
438 } catch (BreakAttr b) {
439 return b.env;
440 } catch (AssertionError ae) {
441 if (ae.getCause() instanceof BreakAttr breakAttr) {
442 return breakAttr.env;
443 } else {
444 throw ae;
445 }
446 } finally {
447 breakTree = null;
448 log.useSource(prev);
449 }
450 return env;
451 }
452
453 public <R> R runWithAttributedMethod(Env<AttrContext> env, JCMethodDecl tree, Function<JCBlock, R> attributedAction) {
454 JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
455 try {
456 JCBlock dupTree = (JCBlock)deferredAttr.attribSpeculative(tree.body, env, statInfo,
457 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
458 argumentAttr.withLocalCacheContext());
459 return attributedAction.apply(dupTree);
460 } finally {
461 attrRecover.doRecovery();
462 log.useSource(prevSource);
463 }
464 }
465
466 private JCTree breakTree = null;
467
468 private static class BreakAttr extends RuntimeException {
469 static final long serialVersionUID = -6924771130405446405L;
470 private transient Env<AttrContext> env;
471 private BreakAttr(Env<AttrContext> env) {
472 this.env = env;
473 }
474 }
475
476 /**
477 * Mode controlling behavior of Attr.Check
478 */
479 enum CheckMode {
480
481 NORMAL,
482
483 /**
484 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
485 * that the captured var cache in {@code InferenceContext} will be used in read-only
3163 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3164 }
3165
3166 /*
3167 * A lambda expression can only be attributed when a target-type is available.
3168 * In addition, if the target-type is that of a functional interface whose
3169 * descriptor contains inference variables in argument position the lambda expression
3170 * is 'stuck' (see DeferredAttr).
3171 */
3172 @Override
3173 public void visitLambda(final JCLambda that) {
3174 boolean wrongContext = false;
3175 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3176 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3177 //lambda only allowed in assignment or method invocation/cast context
3178 log.error(that.pos(), Errors.UnexpectedLambda);
3179 }
3180 resultInfo = recoveryInfo;
3181 wrongContext = true;
3182 }
3183 if (types.isQuoted(pt())) {
3184 attribQuotedLambda(that);
3185 } else {
3186 attribFunctionalLambda(that, wrongContext);
3187 }
3188 }
3189
3190 void attribFunctionalLambda(JCLambda that, boolean wrongContext) {
3191 //create an environment for attribution of the lambda expression
3192 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3193 boolean needsRecovery =
3194 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3195 try {
3196 if (needsRecovery && rs.isSerializable(pt())) {
3197 localEnv.info.isSerializable = true;
3198 localEnv.info.isSerializableLambda = true;
3199 }
3200 List<Type> explicitParamTypes = null;
3201 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3202 //attribute lambda parameters
3203 attribStats(that.params, localEnv);
3204 explicitParamTypes = TreeInfo.types(that.params);
3205 }
3206
3207 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3208 Type currentTarget = targetInfo.target;
3209 Type lambdaType = targetInfo.descriptor;
3210
3314 chk.completionError(that.pos(), cf);
3315 } catch (Throwable t) {
3316 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3317 //as that would likely cause the same exception again.
3318 needsRecovery = false;
3319 throw t;
3320 } finally {
3321 localEnv.info.scope.leave();
3322 if (needsRecovery) {
3323 Type prevResult = result;
3324 try {
3325 attribTree(that, env, recoveryInfo);
3326 } finally {
3327 if (result == Type.recoveryType) {
3328 result = prevResult;
3329 }
3330 }
3331 }
3332 }
3333 }
3334
3335 void attribQuotedLambda(JCLambda that) {
3336 // create an environment for attribution of the lambda expression
3337 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3338 try {
3339 // if quoted lambda is implicit, issue error, and recover
3340 if (that.paramKind == ParameterKind.IMPLICIT) {
3341 log.error(that, Errors.QuotedLambdaMustBeExplicit);
3342 // recovery
3343 List<JCVariableDecl> params = that.params;
3344 while (params.nonEmpty()) {
3345 Type argType = syms.errType;
3346 if (params.head.isImplicitlyTyped()) {
3347 setSyntheticVariableType(params.head, argType);
3348 }
3349 params = params.tail;
3350 }
3351 }
3352 // attribute lambda parameters
3353 attribStats(that.params, localEnv);
3354 List<Type> explicitParamTypes = TreeInfo.types(that.params);
3355
3356 ListBuffer<Type> restypes = new ListBuffer<>();
3357 ListBuffer<DiagnosticPosition> resPositions = new ListBuffer<>();
3358 ResultInfo bodyResultInfo = localEnv.info.returnResult = unknownExprInfo;
3359
3360 // type-check lambda body, and capture return types
3361 if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3362 attribTree(that.getBody(), localEnv, bodyResultInfo);
3363 restypes.add(that.getBody().type);
3364 } else {
3365 JCBlock body = (JCBlock)that.body;
3366 if (body == breakTree &&
3367 resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
3368 breakTreeFound(copyEnv(localEnv));
3369 }
3370 attribStats(body.stats, localEnv);
3371 new LambdaReturnScanner() {
3372 @Override
3373 public void visitReturn(JCReturn tree) {
3374 if (tree.expr != null) {
3375 resPositions.add(tree);
3376 }
3377 restypes.add(tree.expr == null ? syms.voidType : tree.expr.type);
3378 }
3379 }.scan(body);
3380 }
3381
3382 // check if lambda body can complete normally
3383 preFlow(that);
3384 flow.analyzeLambda(localEnv, that, make, false);
3385
3386 final Type restype;
3387 if (that.getBodyKind() == BodyKind.STATEMENT) {
3388 if (that.canCompleteNormally) {
3389 // a lambda that completes normally has an implicit void return
3390 restypes.add(syms.voidType);
3391 }
3392
3393 boolean hasNonVoidReturn = restypes.toList()
3394 .stream().anyMatch(t -> t != syms.voidType);
3395 boolean hasVoidReturn = restypes.toList()
3396 .stream().anyMatch(t -> t == syms.voidType);
3397
3398 if (hasVoidReturn && hasNonVoidReturn) {
3399 // void vs. non-void mismatch
3400 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3401 restype = syms.errorType;
3402 } else if (hasVoidReturn) {
3403 restype = syms.voidType;
3404 } else {
3405 restype = condType(resPositions.toList(), restypes.toList());
3406 }
3407 } else {
3408 restype = restypes.first();
3409 }
3410
3411 // infer lambda return type using lub
3412 if (restype.hasTag(ERROR)) {
3413 // some other error occurred
3414 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3415 }
3416
3417 // infer thrown types
3418 List<Type> thrownTypes = flow.analyzeLambdaThrownTypes(localEnv, that, make);
3419
3420 // set up target descriptor with explicit parameter types, and inferred thrown/return types
3421 that.target = new MethodType(explicitParamTypes, restype, thrownTypes, syms.methodClass);
3422 result = that.type = pt();
3423 } finally {
3424 localEnv.info.scope.leave();
3425 }
3426 }
3427 //where
3428 class TargetInfo {
3429 Type target;
3430 Type descriptor;
3431
3432 public TargetInfo(Type target, Type descriptor) {
3433 this.target = target;
3434 this.descriptor = descriptor;
3435 }
3436 }
3437
3438 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3439 Type lambdaType;
3440 Type currentTarget = resultInfo.pt;
3441 if (resultInfo.pt != Type.recoveryType) {
3442 /* We need to adjust the target. If the target is an
3443 * intersection type, for example: SAM & I1 & I2 ...
3444 * the target will be updated to SAM
3445 */
3446 currentTarget = targetChecker.visit(currentTarget, that);
|