< 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

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