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
3149 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3150 }
3151
3152 /*
3153 * A lambda expression can only be attributed when a target-type is available.
3154 * In addition, if the target-type is that of a functional interface whose
3155 * descriptor contains inference variables in argument position the lambda expression
3156 * is 'stuck' (see DeferredAttr).
3157 */
3158 @Override
3159 public void visitLambda(final JCLambda that) {
3160 boolean wrongContext = false;
3161 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3162 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3163 //lambda only allowed in assignment or method invocation/cast context
3164 log.error(that.pos(), Errors.UnexpectedLambda);
3165 }
3166 resultInfo = recoveryInfo;
3167 wrongContext = true;
3168 }
3169 //create an environment for attribution of the lambda expression
3170 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3171 boolean needsRecovery =
3172 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3173 try {
3174 if (needsRecovery && rs.isSerializable(pt())) {
3175 localEnv.info.isSerializable = true;
3176 localEnv.info.isSerializableLambda = true;
3177 }
3178 List<Type> explicitParamTypes = null;
3179 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3180 //attribute lambda parameters
3181 attribStats(that.params, localEnv);
3182 explicitParamTypes = TreeInfo.types(that.params);
3183 }
3184
3185 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3186 Type currentTarget = targetInfo.target;
3187 Type lambdaType = targetInfo.descriptor;
3188
3292 chk.completionError(that.pos(), cf);
3293 } catch (Throwable t) {
3294 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3295 //as that would likely cause the same exception again.
3296 needsRecovery = false;
3297 throw t;
3298 } finally {
3299 localEnv.info.scope.leave();
3300 if (needsRecovery) {
3301 Type prevResult = result;
3302 try {
3303 attribTree(that, env, recoveryInfo);
3304 } finally {
3305 if (result == Type.recoveryType) {
3306 result = prevResult;
3307 }
3308 }
3309 }
3310 }
3311 }
3312 //where
3313 class TargetInfo {
3314 Type target;
3315 Type descriptor;
3316
3317 public TargetInfo(Type target, Type descriptor) {
3318 this.target = target;
3319 this.descriptor = descriptor;
3320 }
3321 }
3322
3323 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3324 Type lambdaType;
3325 Type currentTarget = resultInfo.pt;
3326 if (resultInfo.pt != Type.recoveryType) {
3327 /* We need to adjust the target. If the target is an
3328 * intersection type, for example: SAM & I1 & I2 ...
3329 * the target will be updated to SAM
3330 */
3331 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
3168 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3169 }
3170
3171 /*
3172 * A lambda expression can only be attributed when a target-type is available.
3173 * In addition, if the target-type is that of a functional interface whose
3174 * descriptor contains inference variables in argument position the lambda expression
3175 * is 'stuck' (see DeferredAttr).
3176 */
3177 @Override
3178 public void visitLambda(final JCLambda that) {
3179 boolean wrongContext = false;
3180 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3181 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3182 //lambda only allowed in assignment or method invocation/cast context
3183 log.error(that.pos(), Errors.UnexpectedLambda);
3184 }
3185 resultInfo = recoveryInfo;
3186 wrongContext = true;
3187 }
3188 if (types.isQuoted(pt())) {
3189 attribQuotedLambda(that);
3190 } else {
3191 attribFunctionalLambda(that, wrongContext);
3192 }
3193 }
3194
3195 void attribFunctionalLambda(JCLambda that, boolean wrongContext) {
3196 //create an environment for attribution of the lambda expression
3197 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3198 boolean needsRecovery =
3199 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3200 try {
3201 if (needsRecovery && rs.isSerializable(pt())) {
3202 localEnv.info.isSerializable = true;
3203 localEnv.info.isSerializableLambda = true;
3204 }
3205 List<Type> explicitParamTypes = null;
3206 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3207 //attribute lambda parameters
3208 attribStats(that.params, localEnv);
3209 explicitParamTypes = TreeInfo.types(that.params);
3210 }
3211
3212 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3213 Type currentTarget = targetInfo.target;
3214 Type lambdaType = targetInfo.descriptor;
3215
3319 chk.completionError(that.pos(), cf);
3320 } catch (Throwable t) {
3321 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3322 //as that would likely cause the same exception again.
3323 needsRecovery = false;
3324 throw t;
3325 } finally {
3326 localEnv.info.scope.leave();
3327 if (needsRecovery) {
3328 Type prevResult = result;
3329 try {
3330 attribTree(that, env, recoveryInfo);
3331 } finally {
3332 if (result == Type.recoveryType) {
3333 result = prevResult;
3334 }
3335 }
3336 }
3337 }
3338 }
3339
3340 void attribQuotedLambda(JCLambda that) {
3341 // create an environment for attribution of the lambda expression
3342 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3343 try {
3344 // if quoted lambda is implicit, issue error, and recover
3345 if (that.paramKind == ParameterKind.IMPLICIT) {
3346 log.error(that, Errors.QuotedLambdaMustBeExplicit);
3347 // recovery
3348 List<JCVariableDecl> params = that.params;
3349 while (params.nonEmpty()) {
3350 Type argType = syms.errType;
3351 if (params.head.isImplicitlyTyped()) {
3352 setSyntheticVariableType(params.head, argType);
3353 }
3354 params = params.tail;
3355 }
3356 }
3357 // attribute lambda parameters
3358 attribStats(that.params, localEnv);
3359 List<Type> explicitParamTypes = TreeInfo.types(that.params);
3360
3361 ListBuffer<Type> restypes = new ListBuffer<>();
3362 ListBuffer<DiagnosticPosition> resPositions = new ListBuffer<>();
3363 ResultInfo bodyResultInfo = localEnv.info.returnResult = unknownExprInfo;
3364
3365 // type-check lambda body, and capture return types
3366 if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3367 attribTree(that.getBody(), localEnv, bodyResultInfo);
3368 restypes.add(that.getBody().type);
3369 } else {
3370 JCBlock body = (JCBlock)that.body;
3371 if (body == breakTree &&
3372 resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
3373 breakTreeFound(copyEnv(localEnv));
3374 }
3375 attribStats(body.stats, localEnv);
3376 new LambdaReturnScanner() {
3377 @Override
3378 public void visitReturn(JCReturn tree) {
3379 if (tree.expr != null) {
3380 resPositions.add(tree);
3381 }
3382 restypes.add(tree.expr == null ? syms.voidType : tree.expr.type);
3383 }
3384 }.scan(body);
3385 }
3386
3387 // check if lambda body can complete normally
3388 preFlow(that);
3389 flow.analyzeLambda(localEnv, that, make, false);
3390
3391 final Type restype;
3392 if (that.getBodyKind() == BodyKind.STATEMENT) {
3393 if (that.canCompleteNormally) {
3394 // a lambda that completes normally has an implicit void return
3395 restypes.add(syms.voidType);
3396 }
3397
3398 boolean hasNonVoidReturn = restypes.toList()
3399 .stream().anyMatch(t -> t != syms.voidType);
3400 boolean hasVoidReturn = restypes.toList()
3401 .stream().anyMatch(t -> t == syms.voidType);
3402
3403 if (hasVoidReturn && hasNonVoidReturn) {
3404 // void vs. non-void mismatch
3405 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3406 restype = syms.errorType;
3407 } else if (hasVoidReturn) {
3408 restype = syms.voidType;
3409 } else {
3410 restype = condType(resPositions.toList(), restypes.toList());
3411 }
3412 } else {
3413 restype = restypes.first();
3414 }
3415
3416 // infer lambda return type using lub
3417 if (restype.hasTag(ERROR)) {
3418 // some other error occurred
3419 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3420 }
3421
3422 // infer thrown types
3423 List<Type> thrownTypes = flow.analyzeLambdaThrownTypes(localEnv, that, make);
3424
3425 // set up target descriptor with explicit parameter types, and inferred thrown/return types
3426 that.target = new MethodType(explicitParamTypes, restype, thrownTypes, syms.methodClass);
3427 result = that.type = pt();
3428 } finally {
3429 localEnv.info.scope.leave();
3430 }
3431 }
3432 //where
3433 class TargetInfo {
3434 Type target;
3435 Type descriptor;
3436
3437 public TargetInfo(Type target, Type descriptor) {
3438 this.target = target;
3439 this.descriptor = descriptor;
3440 }
3441 }
3442
3443 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3444 Type lambdaType;
3445 Type currentTarget = resultInfo.pt;
3446 if (resultInfo.pt != Type.recoveryType) {
3447 /* We need to adjust the target. If the target is an
3448 * intersection type, for example: SAM & I1 & I2 ...
3449 * the target will be updated to SAM
3450 */
3451 currentTarget = targetChecker.visit(currentTarget, that);
|