langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
changeset 24066 1dfb66929538
parent 22163 3651128c74eb
child 24226 08b586e22328
equal deleted inserted replaced
24065:fc4022e50129 24066:1dfb66929538
     1 /*
     1 /*
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package com.sun.tools.javac.comp;
    26 package com.sun.tools.javac.comp;
    27 
    27 
    28 import com.sun.source.tree.MemberReferenceTree;
    28 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
    29 import com.sun.tools.javac.code.*;
    29 import com.sun.tools.javac.code.*;
    30 import com.sun.tools.javac.tree.*;
    30 import com.sun.tools.javac.tree.*;
    31 import com.sun.tools.javac.util.*;
    31 import com.sun.tools.javac.util.*;
    32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    33 import com.sun.tools.javac.code.Symbol.*;
    33 import com.sun.tools.javac.code.Symbol.*;
    34 import com.sun.tools.javac.code.Type.*;
    34 import com.sun.tools.javac.code.Type.*;
    35 import com.sun.tools.javac.comp.Attr.ResultInfo;
    35 import com.sun.tools.javac.comp.Attr.ResultInfo;
    36 import com.sun.tools.javac.comp.Infer.InferenceContext;
    36 import com.sun.tools.javac.comp.Infer.InferenceContext;
    37 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
    37 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
    38 import com.sun.tools.javac.comp.Resolve.ReferenceLookupHelper;
       
    39 import com.sun.tools.javac.tree.JCTree.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 
       
    41 
    39 
    42 import java.util.ArrayList;
    40 import java.util.ArrayList;
    43 import java.util.Collections;
    41 import java.util.Collections;
    44 import java.util.EnumSet;
    42 import java.util.EnumSet;
    45 import java.util.LinkedHashMap;
    43 import java.util.LinkedHashMap;
    46 import java.util.LinkedHashSet;
    44 import java.util.LinkedHashSet;
    47 import java.util.Map;
    45 import java.util.Map;
    48 import java.util.Set;
    46 import java.util.Set;
    49 import java.util.WeakHashMap;
    47 import java.util.WeakHashMap;
    50 
    48 
       
    49 import static com.sun.tools.javac.code.Kinds.VAL;
    51 import static com.sun.tools.javac.code.TypeTag.*;
    50 import static com.sun.tools.javac.code.TypeTag.*;
    52 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    51 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    53 
    52 
    54 /**
    53 /**
    55  * This is an helper class that is used to perform deferred type-analysis.
    54  * This is an helper class that is used to perform deferred type-analysis.
    73     final Resolve rs;
    72     final Resolve rs;
    74     final Log log;
    73     final Log log;
    75     final Symtab syms;
    74     final Symtab syms;
    76     final TreeMaker make;
    75     final TreeMaker make;
    77     final Types types;
    76     final Types types;
       
    77     final Flow flow;
       
    78     final Names names;
    78 
    79 
    79     public static DeferredAttr instance(Context context) {
    80     public static DeferredAttr instance(Context context) {
    80         DeferredAttr instance = context.get(deferredAttrKey);
    81         DeferredAttr instance = context.get(deferredAttrKey);
    81         if (instance == null)
    82         if (instance == null)
    82             instance = new DeferredAttr(context);
    83             instance = new DeferredAttr(context);
    93         rs = Resolve.instance(context);
    94         rs = Resolve.instance(context);
    94         log = Log.instance(context);
    95         log = Log.instance(context);
    95         syms = Symtab.instance(context);
    96         syms = Symtab.instance(context);
    96         make = TreeMaker.instance(context);
    97         make = TreeMaker.instance(context);
    97         types = Types.instance(context);
    98         types = Types.instance(context);
    98         Names names = Names.instance(context);
    99         flow = Flow.instance(context);
       
   100         names = Names.instance(context);
    99         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
   101         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
   100         emptyDeferredAttrContext =
   102         emptyDeferredAttrContext =
   101             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
   103             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
   102                 @Override
   104                 @Override
   103                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
   105                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
   134         }
   136         }
   135 
   137 
   136         @Override
   138         @Override
   137         public TypeTag getTag() {
   139         public TypeTag getTag() {
   138             return DEFERRED;
   140             return DEFERRED;
       
   141         }
       
   142 
       
   143         @Override
       
   144         public String toString() {
       
   145             return "DeferredType";
   139         }
   146         }
   140 
   147 
   141         /**
   148         /**
   142          * A speculative cache is used to keep track of all overload resolution rounds
   149          * A speculative cache is used to keep track of all overload resolution rounds
   143          * that triggered speculative attribution on a given deferred type. Each entry
   150          * that triggered speculative attribution on a given deferred type. Each entry
   374             unenterScanner.scan(newTree);
   381             unenterScanner.scan(newTree);
   375             log.popDiagnosticHandler(deferredDiagnosticHandler);
   382             log.popDiagnosticHandler(deferredDiagnosticHandler);
   376         }
   383         }
   377     }
   384     }
   378     //where
   385     //where
   379         protected TreeScanner unenterScanner = new TreeScanner() {
   386         protected UnenterScanner unenterScanner = new UnenterScanner();
       
   387 
       
   388         class UnenterScanner extends TreeScanner {
   380             @Override
   389             @Override
   381             public void visitClassDef(JCClassDecl tree) {
   390             public void visitClassDef(JCClassDecl tree) {
   382                 ClassSymbol csym = tree.sym;
   391                 ClassSymbol csym = tree.sym;
   383                 //if something went wrong during method applicability check
   392                 //if something went wrong during method applicability check
   384                 //it is possible that nested expressions inside argument expression
   393                 //it is possible that nested expressions inside argument expression
   387                 enter.typeEnvs.remove(csym);
   396                 enter.typeEnvs.remove(csym);
   388                 chk.compiled.remove(csym.flatname);
   397                 chk.compiled.remove(csym.flatname);
   389                 syms.classes.remove(csym.flatname);
   398                 syms.classes.remove(csym.flatname);
   390                 super.visitClassDef(tree);
   399                 super.visitClassDef(tree);
   391             }
   400             }
   392         };
   401         }
   393 
   402 
   394     /**
   403     /**
   395      * A deferred context is created on each method check. A deferred context is
   404      * A deferred context is created on each method check. A deferred context is
   396      * used to keep track of information associated with the method check, such as
   405      * used to keep track of information associated with the method check, such as
   397      * the symbol of the method being checked, the overload resolution phase,
   406      * the symbol of the method being checked, the overload resolution phase,
   591 
   600 
   592             @Override
   601             @Override
   593             public void visitLambda(JCLambda tree) {
   602             public void visitLambda(JCLambda tree) {
   594                 Check.CheckContext checkContext = resultInfo.checkContext;
   603                 Check.CheckContext checkContext = resultInfo.checkContext;
   595                 Type pt = resultInfo.pt;
   604                 Type pt = resultInfo.pt;
   596                 if (inferenceContext.inferencevars.contains(pt)) {
   605                 if (!inferenceContext.inferencevars.contains(pt)) {
   597                     //ok
       
   598                     return;
       
   599                 } else {
       
   600                     //must be a functional descriptor
   606                     //must be a functional descriptor
       
   607                     Type descriptorType = null;
   601                     try {
   608                     try {
   602                         Type desc = types.findDescriptorType(pt);
   609                         descriptorType = types.findDescriptorType(pt);
   603                         if (desc.getParameterTypes().length() != tree.params.length()) {
       
   604                             checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
       
   605                         }
       
   606                     } catch (Types.FunctionDescriptorLookupError ex) {
   610                     } catch (Types.FunctionDescriptorLookupError ex) {
   607                         checkContext.report(null, ex.getDiagnostic());
   611                         checkContext.report(null, ex.getDiagnostic());
   608                     }
   612                     }
       
   613 
       
   614                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
       
   615                         checkContext.report(tree,
       
   616                                 diags.fragment("incompatible.arg.types.in.lambda"));
       
   617                     }
       
   618 
       
   619                     Type currentReturnType = descriptorType.getReturnType();
       
   620                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
       
   621                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
       
   622                         boolean isExpressionCompatible = !returnTypeIsVoid ||
       
   623                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
       
   624                         if (!isExpressionCompatible) {
       
   625                             resultInfo.checkContext.report(tree.pos(),
       
   626                                 diags.fragment("incompatible.ret.type.in.lambda",
       
   627                                     diags.fragment("missing.ret.val", currentReturnType)));
       
   628                         }
       
   629                     } else {
       
   630                         LambdaBodyStructChecker lambdaBodyChecker =
       
   631                                 new LambdaBodyStructChecker();
       
   632 
       
   633                         tree.body.accept(lambdaBodyChecker);
       
   634                         boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
       
   635 
       
   636                         if (returnTypeIsVoid) {
       
   637                             if (!isVoidCompatible) {
       
   638                                 resultInfo.checkContext.report(tree.pos(),
       
   639                                     diags.fragment("unexpected.ret.val"));
       
   640                             }
       
   641                         } else {
       
   642                             boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
       
   643                                 && !canLambdaBodyCompleteNormally(tree);
       
   644                             if (!isValueCompatible && !isVoidCompatible) {
       
   645                                 log.error(tree.body.pos(),
       
   646                                     "lambda.body.neither.value.nor.void.compatible");
       
   647                             }
       
   648 
       
   649                             if (!isValueCompatible) {
       
   650                                 resultInfo.checkContext.report(tree.pos(),
       
   651                                     diags.fragment("incompatible.ret.type.in.lambda",
       
   652                                         diags.fragment("missing.ret.val", currentReturnType)));
       
   653                             }
       
   654                         }
       
   655                     }
       
   656                 }
       
   657             }
       
   658 
       
   659             boolean canLambdaBodyCompleteNormally(JCLambda tree) {
       
   660                 JCLambda newTree = new TreeCopier<>(make).copy(tree);
       
   661                 /* attr.lambdaEnv will create a meaningful env for the
       
   662                  * lambda expression. This is specially useful when the
       
   663                  * lambda is used as the init of a field. But we need to
       
   664                  * remove any added symbol.
       
   665                  */
       
   666                 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
       
   667                 try {
       
   668                     List<JCVariableDecl> tmpParams = newTree.params;
       
   669                     while (tmpParams.nonEmpty()) {
       
   670                         tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
       
   671                         tmpParams = tmpParams.tail;
       
   672                     }
       
   673 
       
   674                     attr.attribStats(newTree.params, localEnv);
       
   675 
       
   676                     /* set pt to Type.noType to avoid generating any bound
       
   677                      * which may happen if lambda's return type is an
       
   678                      * inference variable
       
   679                      */
       
   680                     Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType);
       
   681                     localEnv.info.returnResult = bodyResultInfo;
       
   682 
       
   683                     // discard any log output
       
   684                     Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
       
   685                     try {
       
   686                         JCBlock body = (JCBlock)newTree.body;
       
   687                         /* we need to attribute the lambda body before
       
   688                          * doing the aliveness analysis. This is because
       
   689                          * constant folding occurs during attribution
       
   690                          * and the reachability of some statements depends
       
   691                          * on constant values, for example:
       
   692                          *
       
   693                          *     while (true) {...}
       
   694                          */
       
   695                         attr.attribStats(body.stats, localEnv);
       
   696 
       
   697                         attr.preFlow(newTree);
       
   698                         /* make an aliveness / reachability analysis of the lambda
       
   699                          * to determine if it can complete normally
       
   700                          */
       
   701                         flow.analyzeLambda(localEnv, newTree, make, true);
       
   702                     } finally {
       
   703                         log.popDiagnosticHandler(diagHandler);
       
   704                     }
       
   705                     return newTree.canCompleteNormally;
       
   706                 } finally {
       
   707                     JCBlock body = (JCBlock)newTree.body;
       
   708                     unenterScanner.scan(body.stats);
       
   709                     localEnv.info.scope.leave();
   609                 }
   710                 }
   610             }
   711             }
   611 
   712 
   612             @Override
   713             @Override
   613             public void visitNewClass(JCNewClass tree) {
   714             public void visitNewClass(JCNewClass tree) {
   621 
   722 
   622             @Override
   723             @Override
   623             public void visitReference(JCMemberReference tree) {
   724             public void visitReference(JCMemberReference tree) {
   624                 Check.CheckContext checkContext = resultInfo.checkContext;
   725                 Check.CheckContext checkContext = resultInfo.checkContext;
   625                 Type pt = resultInfo.pt;
   726                 Type pt = resultInfo.pt;
   626                 if (inferenceContext.inferencevars.contains(pt)) {
   727                 if (!inferenceContext.inferencevars.contains(pt)) {
   627                     //ok
       
   628                     return;
       
   629                 } else {
       
   630                     try {
   728                     try {
   631                         types.findDescriptorType(pt);
   729                         types.findDescriptorType(pt);
   632                     } catch (Types.FunctionDescriptorLookupError ex) {
   730                     } catch (Types.FunctionDescriptorLookupError ex) {
   633                         checkContext.report(null, ex.getDiagnostic());
   731                         checkContext.report(null, ex.getDiagnostic());
   634                     }
   732                     }
   654                            checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
   752                            checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
   655                     }
   753                     }
   656                 }
   754                 }
   657             }
   755             }
   658         }
   756         }
       
   757 
       
   758         /* This visitor looks for return statements, its analysis will determine if
       
   759          * a lambda body is void or value compatible. We must analyze return
       
   760          * statements contained in the lambda body only, thus any return statement
       
   761          * contained in an inner class or inner lambda body, should be ignored.
       
   762          */
       
   763         class LambdaBodyStructChecker extends TreeScanner {
       
   764             boolean isVoidCompatible = true;
       
   765             boolean isPotentiallyValueCompatible = true;
       
   766 
       
   767             @Override
       
   768             public void visitClassDef(JCClassDecl tree) {
       
   769                 // do nothing
       
   770             }
       
   771 
       
   772             @Override
       
   773             public void visitLambda(JCLambda tree) {
       
   774                 // do nothing
       
   775             }
       
   776 
       
   777             @Override
       
   778             public void visitNewClass(JCNewClass tree) {
       
   779                 // do nothing
       
   780             }
       
   781 
       
   782             @Override
       
   783             public void visitReturn(JCReturn tree) {
       
   784                 if (tree.expr != null) {
       
   785                     isVoidCompatible = false;
       
   786                 } else {
       
   787                     isPotentiallyValueCompatible = false;
       
   788                 }
       
   789             }
       
   790         }
   659     }
   791     }
   660 
   792 
   661     /** an empty deferred attribution context - all methods throw exceptions */
   793     /** an empty deferred attribution context - all methods throw exceptions */
   662     final DeferredAttrContext emptyDeferredAttrContext;
   794     final DeferredAttrContext emptyDeferredAttrContext;
   663 
   795 
   765         }
   897         }
   766 
   898 
   767         /**
   899         /**
   768          * handler that is executed when a node has been discarded
   900          * handler that is executed when a node has been discarded
   769          */
   901          */
   770         abstract void skip(JCTree tree);
   902         void skip(JCTree tree) {}
   771     }
   903     }
   772 
   904 
   773     /**
   905     /**
   774      * A tree scanner suitable for visiting the target-type dependent nodes of
   906      * A tree scanner suitable for visiting the target-type dependent nodes of
   775      * a given argument expression.
   907      * a given argument expression.
   776      */
   908      */
   777     static class PolyScanner extends FilterScanner {
   909     static class PolyScanner extends FilterScanner {
   778 
   910 
   779         PolyScanner() {
   911         PolyScanner() {
   780             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   912             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   781         }
       
   782 
       
   783         @Override
       
   784         void skip(JCTree tree) {
       
   785             //do nothing
       
   786         }
   913         }
   787     }
   914     }
   788 
   915 
   789     /**
   916     /**
   790      * A tree scanner suitable for visiting the target-type dependent nodes nested
   917      * A tree scanner suitable for visiting the target-type dependent nodes nested
   793     static class LambdaReturnScanner extends FilterScanner {
   920     static class LambdaReturnScanner extends FilterScanner {
   794 
   921 
   795         LambdaReturnScanner() {
   922         LambdaReturnScanner() {
   796             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   923             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   797                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   924                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   798         }
       
   799 
       
   800         @Override
       
   801         void skip(JCTree tree) {
       
   802             //do nothing
       
   803         }
   925         }
   804     }
   926     }
   805 
   927 
   806     /**
   928     /**
   807      * This visitor is used to check that structural expressions conform
   929      * This visitor is used to check that structural expressions conform