< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Print this page

  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);
< prev index next >