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
406 try {
407 deferredAttr.attribSpeculative(root, env, resultInfo,
408 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
409 argumentAttr.withLocalCacheContext());
410 attrRecover.doRecovery();
411 } catch (BreakAttr b) {
412 return b.env;
413 } catch (AssertionError ae) {
414 if (ae.getCause() instanceof BreakAttr breakAttr) {
415 return breakAttr.env;
416 } else {
417 throw ae;
418 }
419 } finally {
420 breakTree = null;
421 log.useSource(prev);
422 }
423 return env;
424 }
425
426 private JCTree breakTree = null;
427
428 private static class BreakAttr extends RuntimeException {
429 static final long serialVersionUID = -6924771130405446405L;
430 private transient Env<AttrContext> env;
431 private BreakAttr(Env<AttrContext> env) {
432 this.env = env;
433 }
434 }
435
436 /**
437 * Mode controlling behavior of Attr.Check
438 */
439 enum CheckMode {
440
441 NORMAL,
442
443 /**
444 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
445 * that the captured var cache in {@code InferenceContext} will be used in read-only
3098 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3099 }
3100
3101 /*
3102 * A lambda expression can only be attributed when a target-type is available.
3103 * In addition, if the target-type is that of a functional interface whose
3104 * descriptor contains inference variables in argument position the lambda expression
3105 * is 'stuck' (see DeferredAttr).
3106 */
3107 @Override
3108 public void visitLambda(final JCLambda that) {
3109 boolean wrongContext = false;
3110 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3111 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3112 //lambda only allowed in assignment or method invocation/cast context
3113 log.error(that.pos(), Errors.UnexpectedLambda);
3114 }
3115 resultInfo = recoveryInfo;
3116 wrongContext = true;
3117 }
3118 //create an environment for attribution of the lambda expression
3119 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3120 boolean needsRecovery =
3121 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3122 try {
3123 if (needsRecovery && rs.isSerializable(pt())) {
3124 localEnv.info.isSerializable = true;
3125 localEnv.info.isSerializableLambda = true;
3126 }
3127 List<Type> explicitParamTypes = null;
3128 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3129 //attribute lambda parameters
3130 attribStats(that.params, localEnv);
3131 explicitParamTypes = TreeInfo.types(that.params);
3132 }
3133
3134 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3135 Type currentTarget = targetInfo.target;
3136 Type lambdaType = targetInfo.descriptor;
3137
3241 chk.completionError(that.pos(), cf);
3242 } catch (Throwable t) {
3243 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3244 //as that would likely cause the same exception again.
3245 needsRecovery = false;
3246 throw t;
3247 } finally {
3248 localEnv.info.scope.leave();
3249 if (needsRecovery) {
3250 Type prevResult = result;
3251 try {
3252 attribTree(that, env, recoveryInfo);
3253 } finally {
3254 if (result == Type.recoveryType) {
3255 result = prevResult;
3256 }
3257 }
3258 }
3259 }
3260 }
3261 //where
3262 class TargetInfo {
3263 Type target;
3264 Type descriptor;
3265
3266 public TargetInfo(Type target, Type descriptor) {
3267 this.target = target;
3268 this.descriptor = descriptor;
3269 }
3270 }
3271
3272 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3273 Type lambdaType;
3274 Type currentTarget = resultInfo.pt;
3275 if (resultInfo.pt != Type.recoveryType) {
3276 /* We need to adjust the target. If the target is an
3277 * intersection type, for example: SAM & I1 & I2 ...
3278 * the target will be updated to SAM
3279 */
3280 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
412 try {
413 deferredAttr.attribSpeculative(root, env, resultInfo,
414 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
415 argumentAttr.withLocalCacheContext());
416 attrRecover.doRecovery();
417 } catch (BreakAttr b) {
418 return b.env;
419 } catch (AssertionError ae) {
420 if (ae.getCause() instanceof BreakAttr breakAttr) {
421 return breakAttr.env;
422 } else {
423 throw ae;
424 }
425 } finally {
426 breakTree = null;
427 log.useSource(prev);
428 }
429 return env;
430 }
431
432 public <R> R runWithAttributedMethod(Env<AttrContext> env, JCMethodDecl tree, Function<JCBlock, R> attributedAction) {
433 JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
434 try {
435 JCBlock dupTree = (JCBlock)deferredAttr.attribSpeculative(tree.body, env, statInfo,
436 null, DeferredAttr.AttributionMode.ATTRIB_TO_TREE,
437 argumentAttr.withLocalCacheContext());
438 return attributedAction.apply(dupTree);
439 } finally {
440 attrRecover.doRecovery();
441 log.useSource(prevSource);
442 }
443 }
444
445 private JCTree breakTree = null;
446
447 private static class BreakAttr extends RuntimeException {
448 static final long serialVersionUID = -6924771130405446405L;
449 private transient Env<AttrContext> env;
450 private BreakAttr(Env<AttrContext> env) {
451 this.env = env;
452 }
453 }
454
455 /**
456 * Mode controlling behavior of Attr.Check
457 */
458 enum CheckMode {
459
460 NORMAL,
461
462 /**
463 * Mode signalling 'fake check' - skip tree update. A side-effect of this mode is
464 * that the captured var cache in {@code InferenceContext} will be used in read-only
3117 result = check(tree, owntype, KindSelector.VAL, resultInfo);
3118 }
3119
3120 /*
3121 * A lambda expression can only be attributed when a target-type is available.
3122 * In addition, if the target-type is that of a functional interface whose
3123 * descriptor contains inference variables in argument position the lambda expression
3124 * is 'stuck' (see DeferredAttr).
3125 */
3126 @Override
3127 public void visitLambda(final JCLambda that) {
3128 boolean wrongContext = false;
3129 if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
3130 if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
3131 //lambda only allowed in assignment or method invocation/cast context
3132 log.error(that.pos(), Errors.UnexpectedLambda);
3133 }
3134 resultInfo = recoveryInfo;
3135 wrongContext = true;
3136 }
3137 if (types.isQuoted(pt())) {
3138 attribQuotedLambda(that);
3139 } else {
3140 attribFunctionalLambda(that, wrongContext);
3141 }
3142 }
3143
3144 void attribFunctionalLambda(JCLambda that, boolean wrongContext) {
3145 //create an environment for attribution of the lambda expression
3146 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3147 boolean needsRecovery =
3148 resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
3149 try {
3150 if (needsRecovery && rs.isSerializable(pt())) {
3151 localEnv.info.isSerializable = true;
3152 localEnv.info.isSerializableLambda = true;
3153 }
3154 List<Type> explicitParamTypes = null;
3155 if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
3156 //attribute lambda parameters
3157 attribStats(that.params, localEnv);
3158 explicitParamTypes = TreeInfo.types(that.params);
3159 }
3160
3161 TargetInfo targetInfo = getTargetInfo(that, resultInfo, explicitParamTypes);
3162 Type currentTarget = targetInfo.target;
3163 Type lambdaType = targetInfo.descriptor;
3164
3268 chk.completionError(that.pos(), cf);
3269 } catch (Throwable t) {
3270 //when an unexpected exception happens, avoid attempts to attribute the same tree again
3271 //as that would likely cause the same exception again.
3272 needsRecovery = false;
3273 throw t;
3274 } finally {
3275 localEnv.info.scope.leave();
3276 if (needsRecovery) {
3277 Type prevResult = result;
3278 try {
3279 attribTree(that, env, recoveryInfo);
3280 } finally {
3281 if (result == Type.recoveryType) {
3282 result = prevResult;
3283 }
3284 }
3285 }
3286 }
3287 }
3288
3289 void attribQuotedLambda(JCLambda that) {
3290 // create an environment for attribution of the lambda expression
3291 final Env<AttrContext> localEnv = lambdaEnv(that, env);
3292 try {
3293 // if quoted lambda is implicit, issue error, and recover
3294 if (that.paramKind == ParameterKind.IMPLICIT) {
3295 log.error(that, Errors.QuotedLambdaMustBeExplicit);
3296 // recovery
3297 List<JCVariableDecl> params = that.params;
3298 while (params.nonEmpty()) {
3299 Type argType = syms.errType;
3300 if (params.head.isImplicitlyTyped()) {
3301 setSyntheticVariableType(params.head, argType);
3302 }
3303 params = params.tail;
3304 }
3305 }
3306 // attribute lambda parameters
3307 attribStats(that.params, localEnv);
3308 List<Type> explicitParamTypes = TreeInfo.types(that.params);
3309
3310 ListBuffer<Type> restypes = new ListBuffer<>();
3311 ListBuffer<DiagnosticPosition> resPositions = new ListBuffer<>();
3312 ResultInfo bodyResultInfo = localEnv.info.returnResult = unknownExprInfo;
3313
3314 // type-check lambda body, and capture return types
3315 if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3316 attribTree(that.getBody(), localEnv, bodyResultInfo);
3317 restypes.add(that.getBody().type);
3318 } else {
3319 JCBlock body = (JCBlock)that.body;
3320 if (body == breakTree &&
3321 resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
3322 breakTreeFound(copyEnv(localEnv));
3323 }
3324 attribStats(body.stats, localEnv);
3325 new LambdaReturnScanner() {
3326 @Override
3327 public void visitReturn(JCReturn tree) {
3328 if (tree.expr != null) {
3329 resPositions.add(tree);
3330 }
3331 restypes.add(tree.expr == null ? syms.voidType : tree.expr.type);
3332 }
3333 }.scan(body);
3334 }
3335
3336 // check if lambda body can complete normally
3337 preFlow(that);
3338 flow.analyzeLambda(localEnv, that, make, false);
3339
3340 final Type restype;
3341 if (that.getBodyKind() == BodyKind.STATEMENT) {
3342 if (that.canCompleteNormally) {
3343 // a lambda that completes normally has an implicit void return
3344 restypes.add(syms.voidType);
3345 }
3346
3347 boolean hasNonVoidReturn = restypes.toList()
3348 .stream().anyMatch(t -> t != syms.voidType);
3349 boolean hasVoidReturn = restypes.toList()
3350 .stream().anyMatch(t -> t == syms.voidType);
3351
3352 if (hasVoidReturn && hasNonVoidReturn) {
3353 // void vs. non-void mismatch
3354 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3355 restype = syms.errorType;
3356 } else if (hasVoidReturn) {
3357 restype = syms.voidType;
3358 } else {
3359 restype = condType(resPositions.toList(), restypes.toList());
3360 }
3361 } else {
3362 restype = restypes.first();
3363 }
3364
3365 // infer lambda return type using lub
3366 if (restype.hasTag(ERROR)) {
3367 // some other error occurred
3368 log.error(that.body, Errors.CantInferQuotedLambdaReturnType(restypes.toList()));
3369 }
3370
3371 // infer thrown types
3372 List<Type> thrownTypes = flow.analyzeLambdaThrownTypes(localEnv, that, make);
3373
3374 // set up target descriptor with explicit parameter types, and inferred thrown/return types
3375 that.target = new MethodType(explicitParamTypes, restype, thrownTypes, syms.methodClass);
3376 result = that.type = pt();
3377 } finally {
3378 localEnv.info.scope.leave();
3379 }
3380 }
3381 //where
3382 class TargetInfo {
3383 Type target;
3384 Type descriptor;
3385
3386 public TargetInfo(Type target, Type descriptor) {
3387 this.target = target;
3388 this.descriptor = descriptor;
3389 }
3390 }
3391
3392 TargetInfo getTargetInfo(JCPolyExpression that, ResultInfo resultInfo, List<Type> explicitParamTypes) {
3393 Type lambdaType;
3394 Type currentTarget = resultInfo.pt;
3395 if (resultInfo.pt != Type.recoveryType) {
3396 /* We need to adjust the target. If the target is an
3397 * intersection type, for example: SAM & I1 & I2 ...
3398 * the target will be updated to SAM
3399 */
3400 currentTarget = targetChecker.visit(currentTarget, that);
|