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