src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java

Wed, 17 Jul 2013 14:09:46 +0100

author
mcimadamore
date
Wed, 17 Jul 2013 14:09:46 +0100
changeset 1897
866c87c01285
parent 1889
b0386f0dc28e
child 1899
c60a5099863a
permissions
-rw-r--r--

8016175: Add bottom-up type-checking support for unambiguous method references
Summary: Type-checking of non-overloaded method references should be independent from target-type
Reviewed-by: jjg, vromero

     1 /*
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     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
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    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  */
    26 package com.sun.tools.javac.comp;
    28 import com.sun.tools.javac.code.*;
    29 import com.sun.tools.javac.tree.*;
    30 import com.sun.tools.javac.util.*;
    31 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    32 import com.sun.tools.javac.code.Symbol.*;
    33 import com.sun.tools.javac.code.Type.*;
    34 import com.sun.tools.javac.comp.Attr.ResultInfo;
    35 import com.sun.tools.javac.comp.Infer.InferenceContext;
    36 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
    37 import com.sun.tools.javac.comp.Resolve.ReferenceLookupHelper;
    38 import com.sun.tools.javac.tree.JCTree.*;
    41 import java.util.ArrayList;
    42 import java.util.EnumSet;
    43 import java.util.LinkedHashSet;
    44 import java.util.Map;
    45 import java.util.Set;
    46 import java.util.WeakHashMap;
    48 import static com.sun.tools.javac.code.TypeTag.*;
    49 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    51 /**
    52  * This is an helper class that is used to perform deferred type-analysis.
    53  * Each time a poly expression occurs in argument position, javac attributes it
    54  * with a temporary 'deferred type' that is checked (possibly multiple times)
    55  * against an expected formal type.
    56  *
    57  *  <p><b>This is NOT part of any supported API.
    58  *  If you write code that depends on this, you do so at your own risk.
    59  *  This code and its internal interfaces are subject to change or
    60  *  deletion without notice.</b>
    61  */
    62 public class DeferredAttr extends JCTree.Visitor {
    63     protected static final Context.Key<DeferredAttr> deferredAttrKey =
    64         new Context.Key<DeferredAttr>();
    66     final Attr attr;
    67     final Check chk;
    68     final JCDiagnostic.Factory diags;
    69     final Enter enter;
    70     final Infer infer;
    71     final Resolve rs;
    72     final Log log;
    73     final Symtab syms;
    74     final TreeMaker make;
    75     final Types types;
    77     public static DeferredAttr instance(Context context) {
    78         DeferredAttr instance = context.get(deferredAttrKey);
    79         if (instance == null)
    80             instance = new DeferredAttr(context);
    81         return instance;
    82     }
    84     protected DeferredAttr(Context context) {
    85         context.put(deferredAttrKey, this);
    86         attr = Attr.instance(context);
    87         chk = Check.instance(context);
    88         diags = JCDiagnostic.Factory.instance(context);
    89         enter = Enter.instance(context);
    90         infer = Infer.instance(context);
    91         rs = Resolve.instance(context);
    92         log = Log.instance(context);
    93         syms = Symtab.instance(context);
    94         make = TreeMaker.instance(context);
    95         types = Types.instance(context);
    96         Names names = Names.instance(context);
    97         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
    98         emptyDeferredAttrContext =
    99             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
   100                 @Override
   101                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, List<Type> stuckVars) {
   102                     Assert.error("Empty deferred context!");
   103                 }
   104                 @Override
   105                 void complete() {
   106                     Assert.error("Empty deferred context!");
   107                 }
   108             };
   109     }
   111     /** shared tree for stuck expressions */
   112     final JCTree stuckTree;
   114     /**
   115      * This type represents a deferred type. A deferred type starts off with
   116      * no information on the underlying expression type. Such info needs to be
   117      * discovered through type-checking the deferred type against a target-type.
   118      * Every deferred type keeps a pointer to the AST node from which it originated.
   119      */
   120     public class DeferredType extends Type {
   122         public JCExpression tree;
   123         Env<AttrContext> env;
   124         AttrMode mode;
   125         SpeculativeCache speculativeCache;
   127         DeferredType(JCExpression tree, Env<AttrContext> env) {
   128             super(null);
   129             this.tree = tree;
   130             this.env = env.dup(tree, env.info.dup());
   131             this.speculativeCache = new SpeculativeCache();
   132         }
   134         @Override
   135         public TypeTag getTag() {
   136             return DEFERRED;
   137         }
   139         /**
   140          * A speculative cache is used to keep track of all overload resolution rounds
   141          * that triggered speculative attribution on a given deferred type. Each entry
   142          * stores a pointer to the speculative tree and the resolution phase in which the entry
   143          * has been added.
   144          */
   145         class SpeculativeCache {
   147             private Map<Symbol, List<Entry>> cache =
   148                     new WeakHashMap<Symbol, List<Entry>>();
   150             class Entry {
   151                 JCTree speculativeTree;
   152                 Resolve.MethodResolutionPhase phase;
   154                 public Entry(JCTree speculativeTree, MethodResolutionPhase phase) {
   155                     this.speculativeTree = speculativeTree;
   156                     this.phase = phase;
   157                 }
   159                 boolean matches(Resolve.MethodResolutionPhase phase) {
   160                     return this.phase == phase;
   161                 }
   162             }
   164             /**
   165              * Retrieve a speculative cache entry corresponding to given symbol
   166              * and resolution phase
   167              */
   168             Entry get(Symbol msym, MethodResolutionPhase phase) {
   169                 List<Entry> entries = cache.get(msym);
   170                 if (entries == null) return null;
   171                 for (Entry e : entries) {
   172                     if (e.matches(phase)) return e;
   173                 }
   174                 return null;
   175             }
   177             /**
   178              * Stores a speculative cache entry corresponding to given symbol
   179              * and resolution phase
   180              */
   181             void put(Symbol msym, JCTree speculativeTree, MethodResolutionPhase phase) {
   182                 List<Entry> entries = cache.get(msym);
   183                 if (entries == null) {
   184                     entries = List.nil();
   185                 }
   186                 cache.put(msym, entries.prepend(new Entry(speculativeTree, phase)));
   187             }
   188         }
   190         /**
   191          * Get the type that has been computed during a speculative attribution round
   192          */
   193         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
   194             SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
   195             return e != null ? e.speculativeTree.type : Type.noType;
   196         }
   198         /**
   199          * Check a deferred type against a potential target-type. Depending on
   200          * the current attribution mode, a normal vs. speculative attribution
   201          * round is performed on the underlying AST node. There can be only one
   202          * speculative round for a given target method symbol; moreover, a normal
   203          * attribution round must follow one or more speculative rounds.
   204          */
   205         Type check(ResultInfo resultInfo) {
   206             return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
   207         }
   209         Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
   210             DeferredAttrContext deferredAttrContext =
   211                     resultInfo.checkContext.deferredAttrContext();
   212             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
   213             if (stuckVars.nonEmpty()) {
   214                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
   215                 return Type.noType;
   216             } else {
   217                 try {
   218                     return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
   219                 } finally {
   220                     mode = deferredAttrContext.mode;
   221                 }
   222             }
   223         }
   224     }
   226     /**
   227      * A completer for deferred types. Defines an entry point for type-checking
   228      * a deferred type.
   229      */
   230     interface DeferredTypeCompleter {
   231         /**
   232          * Entry point for type-checking a deferred type. Depending on the
   233          * circumstances, type-checking could amount to full attribution
   234          * or partial structural check (aka potential applicability).
   235          */
   236         Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
   237     }
   239     /**
   240      * A basic completer for deferred types. This completer type-checks a deferred type
   241      * using attribution; depending on the attribution mode, this could be either standard
   242      * or speculative attribution.
   243      */
   244     DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
   245         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   246             switch (deferredAttrContext.mode) {
   247                 case SPECULATIVE:
   248                     //Note: if a symbol is imported twice we might do two identical
   249                     //speculative rounds...
   250                     Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
   251                     JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
   252                     dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
   253                     return speculativeTree.type;
   254                 case CHECK:
   255                     Assert.check(dt.mode != null);
   256                     return attr.attribTree(dt.tree, dt.env, resultInfo);
   257             }
   258             Assert.error();
   259             return null;
   260         }
   261     };
   263     DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
   264         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   265             Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
   266             return dt.tree.type = Type.noType;
   267         }
   268     };
   270     /**
   271      * The 'mode' in which the deferred type is to be type-checked
   272      */
   273     public enum AttrMode {
   274         /**
   275          * A speculative type-checking round is used during overload resolution
   276          * mainly to generate constraints on inference variables. Side-effects
   277          * arising from type-checking the expression associated with the deferred
   278          * type are reversed after the speculative round finishes. This means the
   279          * expression tree will be left in a blank state.
   280          */
   281         SPECULATIVE,
   282         /**
   283          * This is the plain type-checking mode. Produces side-effects on the underlying AST node
   284          */
   285         CHECK;
   286     }
   288     /**
   289      * Routine that performs speculative type-checking; the input AST node is
   290      * cloned (to avoid side-effects cause by Attr) and compiler state is
   291      * restored after type-checking. All diagnostics (but critical ones) are
   292      * disabled during speculative type-checking.
   293      */
   294     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
   295         final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
   296         Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
   297         speculativeEnv.info.scope.owner = env.info.scope.owner;
   298         Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
   299                 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
   300             public boolean accepts(final JCDiagnostic d) {
   301                 class PosScanner extends TreeScanner {
   302                     boolean found = false;
   304                     @Override
   305                     public void scan(JCTree tree) {
   306                         if (tree != null &&
   307                                 tree.pos() == d.getDiagnosticPosition()) {
   308                             found = true;
   309                         }
   310                         super.scan(tree);
   311                     }
   312                 };
   313                 PosScanner posScanner = new PosScanner();
   314                 posScanner.scan(newTree);
   315                 return posScanner.found;
   316             }
   317         });
   318         try {
   319             attr.attribTree(newTree, speculativeEnv, resultInfo);
   320             unenterScanner.scan(newTree);
   321             return newTree;
   322         } finally {
   323             unenterScanner.scan(newTree);
   324             log.popDiagnosticHandler(deferredDiagnosticHandler);
   325         }
   326     }
   327     //where
   328         protected TreeScanner unenterScanner = new TreeScanner() {
   329             @Override
   330             public void visitClassDef(JCClassDecl tree) {
   331                 ClassSymbol csym = tree.sym;
   332                 //if something went wrong during method applicability check
   333                 //it is possible that nested expressions inside argument expression
   334                 //are left unchecked - in such cases there's nothing to clean up.
   335                 if (csym == null) return;
   336                 enter.typeEnvs.remove(csym);
   337                 chk.compiled.remove(csym.flatname);
   338                 syms.classes.remove(csym.flatname);
   339                 super.visitClassDef(tree);
   340             }
   341         };
   343     /**
   344      * A deferred context is created on each method check. A deferred context is
   345      * used to keep track of information associated with the method check, such as
   346      * the symbol of the method being checked, the overload resolution phase,
   347      * the kind of attribution mode to be applied to deferred types and so forth.
   348      * As deferred types are processed (by the method check routine) stuck AST nodes
   349      * are added (as new deferred attribution nodes) to this context. The complete()
   350      * routine makes sure that all pending nodes are properly processed, by
   351      * progressively instantiating all inference variables on which one or more
   352      * deferred attribution node is stuck.
   353      */
   354     class DeferredAttrContext {
   356         /** attribution mode */
   357         final AttrMode mode;
   359         /** symbol of the method being checked */
   360         final Symbol msym;
   362         /** method resolution step */
   363         final Resolve.MethodResolutionPhase phase;
   365         /** inference context */
   366         final InferenceContext inferenceContext;
   368         /** parent deferred context */
   369         final DeferredAttrContext parent;
   371         /** Warner object to report warnings */
   372         final Warner warn;
   374         /** list of deferred attribution nodes to be processed */
   375         ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
   377         DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
   378                 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
   379             this.mode = mode;
   380             this.msym = msym;
   381             this.phase = phase;
   382             this.parent = parent;
   383             this.warn = warn;
   384             this.inferenceContext = inferenceContext;
   385         }
   387         /**
   388          * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
   389          * Nodes added this way act as 'roots' for the out-of-order method checking process.
   390          */
   391         void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
   392             deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, stuckVars));
   393         }
   395         /**
   396          * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
   397          * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
   398          * some inference variable might get eagerly instantiated so that all nodes
   399          * can be type-checked.
   400          */
   401         void complete() {
   402             while (!deferredAttrNodes.isEmpty()) {
   403                 Set<Type> stuckVars = new LinkedHashSet<Type>();
   404                 boolean progress = false;
   405                 //scan a defensive copy of the node list - this is because a deferred
   406                 //attribution round can add new nodes to the list
   407                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
   408                     if (!deferredAttrNode.process(this)) {
   409                         stuckVars.addAll(deferredAttrNode.stuckVars);
   410                     } else {
   411                         deferredAttrNodes.remove(deferredAttrNode);
   412                         progress = true;
   413                     }
   414                 }
   415                 if (!progress) {
   416                     //remove all variables that have already been instantiated
   417                     //from the list of stuck variables
   418                     inferenceContext.solveAny(List.from(stuckVars), warn);
   419                     inferenceContext.notifyChange();
   420                 }
   421             }
   422         }
   423     }
   425     /**
   426      * Class representing a deferred attribution node. It keeps track of
   427      * a deferred type, along with the expected target type information.
   428      */
   429     class DeferredAttrNode implements Infer.FreeTypeListener {
   431         /** underlying deferred type */
   432         DeferredType dt;
   434         /** underlying target type information */
   435         ResultInfo resultInfo;
   437         /** list of uninferred inference variables causing this node to be stuck */
   438         List<Type> stuckVars;
   440         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, List<Type> stuckVars) {
   441             this.dt = dt;
   442             this.resultInfo = resultInfo;
   443             this.stuckVars = stuckVars;
   444             if (!stuckVars.isEmpty()) {
   445                 resultInfo.checkContext.inferenceContext().addFreeTypeListener(stuckVars, this);
   446             }
   447         }
   449         @Override
   450         public void typesInferred(InferenceContext inferenceContext) {
   451             stuckVars = List.nil();
   452             resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
   453         }
   455         /**
   456          * Process a deferred attribution node.
   457          * Invariant: a stuck node cannot be processed.
   458          */
   459         @SuppressWarnings("fallthrough")
   460         boolean process(DeferredAttrContext deferredAttrContext) {
   461             switch (deferredAttrContext.mode) {
   462                 case SPECULATIVE:
   463                     dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker());
   464                     return true;
   465                 case CHECK:
   466                     if (stuckVars.nonEmpty()) {
   467                         //stuck expression - see if we can propagate
   468                         if (deferredAttrContext.parent != emptyDeferredAttrContext &&
   469                                 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars, List.from(stuckVars))) {
   470                             deferredAttrContext.parent.deferredAttrNodes.add(this);
   471                             dt.check(resultInfo, List.<Type>nil(), dummyCompleter);
   472                             return true;
   473                         } else {
   474                             return false;
   475                         }
   476                     } else {
   477                         dt.check(resultInfo, stuckVars, basicCompleter);
   478                         return true;
   479                     }
   480                 default:
   481                     throw new AssertionError("Bad mode");
   482             }
   483         }
   485         /**
   486          * Structural checker for stuck expressions
   487          */
   488         class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
   490             ResultInfo resultInfo;
   491             InferenceContext inferenceContext;
   493             public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   494                 this.resultInfo = resultInfo;
   495                 this.inferenceContext = deferredAttrContext.inferenceContext;
   496                 dt.tree.accept(this);
   497                 dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase);
   498                 return Type.noType;
   499             }
   501             @Override
   502             public void visitLambda(JCLambda tree) {
   503                 Check.CheckContext checkContext = resultInfo.checkContext;
   504                 Type pt = resultInfo.pt;
   505                 if (inferenceContext.inferencevars.contains(pt)) {
   506                     //ok
   507                     return;
   508                 } else {
   509                     //must be a functional descriptor
   510                     try {
   511                         Type desc = types.findDescriptorType(pt);
   512                         if (desc.getParameterTypes().length() != tree.params.length()) {
   513                             checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
   514                         }
   515                     } catch (Types.FunctionDescriptorLookupError ex) {
   516                         checkContext.report(null, ex.getDiagnostic());
   517                     }
   518                 }
   519             }
   521             @Override
   522             public void visitNewClass(JCNewClass tree) {
   523                 //do nothing
   524             }
   526             @Override
   527             public void visitApply(JCMethodInvocation tree) {
   528                 //do nothing
   529             }
   531             @Override
   532             public void visitReference(JCMemberReference tree) {
   533                 Check.CheckContext checkContext = resultInfo.checkContext;
   534                 Type pt = resultInfo.pt;
   535                 if (inferenceContext.inferencevars.contains(pt)) {
   536                     //ok
   537                     return;
   538                 } else {
   539                     try {
   540                         types.findDescriptorType(pt);
   541                     } catch (Types.FunctionDescriptorLookupError ex) {
   542                         checkContext.report(null, ex.getDiagnostic());
   543                     }
   544                     switch (tree.sym.kind) {
   545                         //note: as argtypes are erroneous types, type-errors must
   546                         //have been caused by arity mismatch
   547                         case Kinds.ABSENT_MTH:
   548                         case Kinds.WRONG_MTH:
   549                         case Kinds.WRONG_MTHS:
   550                         case Kinds.STATICERR:
   551                         case Kinds.MISSING_ENCL:
   552                            checkContext.report(null, diags.fragment("incompatible.arg.types.in.mref"));
   553                     }
   554                 }
   555             }
   556         }
   557     }
   559     /** an empty deferred attribution context - all methods throw exceptions */
   560     final DeferredAttrContext emptyDeferredAttrContext;
   562     /**
   563      * Map a list of types possibly containing one or more deferred types
   564      * into a list of ordinary types. Each deferred type D is mapped into a type T,
   565      * where T is computed by retrieving the type that has already been
   566      * computed for D during a previous deferred attribution round of the given kind.
   567      */
   568     class DeferredTypeMap extends Type.Mapping {
   570         DeferredAttrContext deferredAttrContext;
   572         protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   573             super(String.format("deferredTypeMap[%s]", mode));
   574             this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
   575                     infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
   576         }
   578         protected boolean validState(DeferredType dt) {
   579             return dt.mode != null &&
   580                     deferredAttrContext.mode.ordinal() <= dt.mode.ordinal();
   581         }
   583         @Override
   584         public Type apply(Type t) {
   585             if (!t.hasTag(DEFERRED)) {
   586                 return t.map(this);
   587             } else {
   588                 DeferredType dt = (DeferredType)t;
   589                 Assert.check(validState(dt));
   590                 return typeOf(dt);
   591             }
   592         }
   594         protected Type typeOf(DeferredType dt) {
   595             switch (deferredAttrContext.mode) {
   596                 case CHECK:
   597                     return dt.tree.type == null ? Type.noType : dt.tree.type;
   598                 case SPECULATIVE:
   599                     return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
   600             }
   601             Assert.error();
   602             return null;
   603         }
   604     }
   606     /**
   607      * Specialized recovery deferred mapping.
   608      * Each deferred type D is mapped into a type T, where T is computed either by
   609      * (i) retrieving the type that has already been computed for D during a previous
   610      * attribution round (as before), or (ii) by synthesizing a new type R for D
   611      * (the latter step is useful in a recovery scenario).
   612      */
   613     public class RecoveryDeferredTypeMap extends DeferredTypeMap {
   615         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   616             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
   617         }
   619         @Override
   620         protected Type typeOf(DeferredType dt) {
   621             Type owntype = super.typeOf(dt);
   622             return owntype == Type.noType ?
   623                         recover(dt) : owntype;
   624         }
   626         @Override
   627         protected boolean validState(DeferredType dt) {
   628             return true;
   629         }
   631         /**
   632          * Synthesize a type for a deferred type that hasn't been previously
   633          * reduced to an ordinary type. Functional deferred types and conditionals
   634          * are mapped to themselves, in order to have a richer diagnostic
   635          * representation. Remaining deferred types are attributed using
   636          * a default expected type (j.l.Object).
   637          */
   638         private Type recover(DeferredType dt) {
   639             dt.check(attr.new RecoveryInfo(deferredAttrContext) {
   640                 @Override
   641                 protected Type check(DiagnosticPosition pos, Type found) {
   642                     return chk.checkNonVoid(pos, super.check(pos, found));
   643                 }
   644             });
   645             return super.apply(dt);
   646         }
   647     }
   649     /**
   650      * Retrieves the list of inference variables that need to be inferred before
   651      * an AST node can be type-checked
   652      */
   653     @SuppressWarnings("fallthrough")
   654     List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
   655                 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
   656             return List.nil();
   657         } else {
   658             return stuckVarsInternal(tree, resultInfo.pt, env, resultInfo.checkContext.inferenceContext());
   659         }
   660     }
   661     //where
   662         private List<Type> stuckVarsInternal(JCTree tree, Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
   663             StuckChecker sc = new StuckChecker(pt, env, inferenceContext);
   664             sc.scan(tree);
   665             return List.from(sc.stuckVars);
   666         }
   668     /**
   669      * A special tree scanner that would only visit portions of a given tree.
   670      * The set of nodes visited by the scanner can be customized at construction-time.
   671      */
   672     abstract static class FilterScanner extends TreeScanner {
   674         final Filter<JCTree> treeFilter;
   676         FilterScanner(final Set<JCTree.Tag> validTags) {
   677             this.treeFilter = new Filter<JCTree>() {
   678                 public boolean accepts(JCTree t) {
   679                     return validTags.contains(t.getTag());
   680                 }
   681             };
   682         }
   684         @Override
   685         public void scan(JCTree tree) {
   686             if (tree != null) {
   687                 if (treeFilter.accepts(tree)) {
   688                     super.scan(tree);
   689                 } else {
   690                     skip(tree);
   691                 }
   692             }
   693         }
   695         /**
   696          * handler that is executed when a node has been discarded
   697          */
   698         abstract void skip(JCTree tree);
   699     }
   701     /**
   702      * A tree scanner suitable for visiting the target-type dependent nodes of
   703      * a given argument expression.
   704      */
   705     static class PolyScanner extends FilterScanner {
   707         PolyScanner() {
   708             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   709         }
   711         @Override
   712         void skip(JCTree tree) {
   713             //do nothing
   714         }
   715     }
   717     /**
   718      * A tree scanner suitable for visiting the target-type dependent nodes nested
   719      * within a lambda expression body.
   720      */
   721     static class LambdaReturnScanner extends FilterScanner {
   723         LambdaReturnScanner() {
   724             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   725                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   726         }
   728         @Override
   729         void skip(JCTree tree) {
   730             //do nothing
   731         }
   732     }
   734     /**
   735      * This visitor is used to check that structural expressions conform
   736      * to their target - this step is required as inference could end up
   737      * inferring types that make some of the nested expressions incompatible
   738      * with their corresponding instantiated target
   739      */
   740     class StuckChecker extends PolyScanner {
   742         Type pt;
   743         Env<AttrContext> env;
   744         Infer.InferenceContext inferenceContext;
   745         Set<Type> stuckVars = new LinkedHashSet<Type>();
   747         StuckChecker(Type pt, Env<AttrContext> env, Infer.InferenceContext inferenceContext) {
   748             this.pt = pt;
   749             this.env = env;
   750             this.inferenceContext = inferenceContext;
   751         }
   753         @Override
   754         public void visitLambda(JCLambda tree) {
   755             if (inferenceContext.inferenceVars().contains(pt)) {
   756                 stuckVars.add(pt);
   757             }
   758             if (!types.isFunctionalInterface(pt)) {
   759                 return;
   760             }
   761             Type descType = types.findDescriptorType(pt);
   762             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   763             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
   764                     freeArgVars.nonEmpty()) {
   765                 stuckVars.addAll(freeArgVars);
   766             }
   767             scanLambdaBody(tree, descType.getReturnType());
   768         }
   770         @Override
   771         public void visitReference(JCMemberReference tree) {
   772             scan(tree.expr);
   773             if (inferenceContext.inferenceVars().contains(pt)) {
   774                 stuckVars.add(pt);
   775                 return;
   776             }
   777             if (!types.isFunctionalInterface(pt)) {
   778                 return;
   779             }
   781             Type descType = types.findDescriptorType(pt);
   782             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   783             Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
   784             if (freeArgVars.nonEmpty()) {
   785                 //perform arity-based check
   786                 JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
   787                         attr.memberReferenceQualifierResult(tree));
   788                 ListBuffer<Type> argtypes = ListBuffer.lb();
   789                 for (Type t : descType.getParameterTypes()) {
   790                     argtypes.append(Type.noType);
   791                 }
   792                 JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
   793                 mref2.expr = exprTree;
   794                 Pair<Symbol, ReferenceLookupHelper> lookupRes =
   795                         rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
   796                             tree.name, argtypes.toList(), null, true, rs.arityMethodCheck,
   797                             inferenceContext);
   798                 Symbol res = tree.sym = lookupRes.fst;
   799                 if (res.kind >= Kinds.ERRONEOUS ||
   800                         res.type.hasTag(FORALL) ||
   801                         (res.flags() & Flags.VARARGS) != 0 ||
   802                         (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
   803                         exprTree.type.isRaw())) {
   804                     stuckVars.addAll(freeArgVars);
   805                 }
   806             }
   807         }
   809         void scanLambdaBody(JCLambda lambda, final Type pt) {
   810             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
   811                 stuckVars.addAll(stuckVarsInternal(lambda.body, pt, env, inferenceContext));
   812             } else {
   813                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
   814                     @Override
   815                     public void visitReturn(JCReturn tree) {
   816                         if (tree.expr != null) {
   817                             stuckVars.addAll(stuckVarsInternal(tree.expr, pt, env, inferenceContext));
   818                         }
   819                     }
   820                 };
   821                 lambdaScanner.scan(lambda.body);
   822             }
   823         }
   824     }
   826     /**
   827      * Does the argument expression {@code expr} need speculative type-checking?
   828      */
   829     boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
   830         DeferredChecker dc = new DeferredChecker(env);
   831         dc.scan(expr);
   832         return dc.result.isPoly();
   833     }
   835     /**
   836      * The kind of an argument expression. This is used by the analysis that
   837      * determines as to whether speculative attribution is necessary.
   838      */
   839     enum ArgumentExpressionKind {
   841         /** kind that denotes poly argument expression */
   842         POLY,
   843         /** kind that denotes a standalone expression */
   844         NO_POLY,
   845         /** kind that denotes a primitive/boxed standalone expression */
   846         PRIMITIVE;
   848         /**
   849          * Does this kind denote a poly argument expression
   850          */
   851         public final boolean isPoly() {
   852             return this == POLY;
   853         }
   855         /**
   856          * Does this kind denote a primitive standalone expression
   857          */
   858         public final boolean isPrimitive() {
   859             return this == PRIMITIVE;
   860         }
   862         /**
   863          * Compute the kind of a standalone expression of a given type
   864          */
   865         static ArgumentExpressionKind standaloneKind(Type type, Types types) {
   866             return types.unboxedTypeOrType(type).isPrimitive() ?
   867                     ArgumentExpressionKind.PRIMITIVE :
   868                     ArgumentExpressionKind.NO_POLY;
   869         }
   871         /**
   872          * Compute the kind of a method argument expression given its symbol
   873          */
   874         static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
   875             Type restype = sym.type.getReturnType();
   876             if (sym.type.hasTag(FORALL) &&
   877                     restype.containsAny(((ForAll)sym.type).tvars)) {
   878                 return ArgumentExpressionKind.POLY;
   879             } else {
   880                 return ArgumentExpressionKind.standaloneKind(restype, types);
   881             }
   882         }
   883     }
   885     /**
   886      * Tree scanner used for checking as to whether an argument expression
   887      * requires speculative attribution
   888      */
   889     final class DeferredChecker extends FilterScanner {
   891         Env<AttrContext> env;
   892         ArgumentExpressionKind result;
   894         public DeferredChecker(Env<AttrContext> env) {
   895             super(deferredCheckerTags);
   896             this.env = env;
   897         }
   899         @Override
   900         public void visitLambda(JCLambda tree) {
   901             //a lambda is always a poly expression
   902             result = ArgumentExpressionKind.POLY;
   903         }
   905         @Override
   906         public void visitReference(JCMemberReference tree) {
   907             //a method reference is always a poly expression
   908             result = ArgumentExpressionKind.POLY;
   909         }
   911         @Override
   912         public void visitTypeCast(JCTypeCast tree) {
   913             //a cast is always a standalone expression
   914             result = ArgumentExpressionKind.NO_POLY;
   915         }
   917         @Override
   918         public void visitConditional(JCConditional tree) {
   919             scan(tree.truepart);
   920             if (!result.isPrimitive()) {
   921                 result = ArgumentExpressionKind.POLY;
   922                 return;
   923             }
   924             scan(tree.falsepart);
   925             result = reduce(ArgumentExpressionKind.PRIMITIVE);
   926         }
   928         @Override
   929         public void visitNewClass(JCNewClass tree) {
   930             result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
   931                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
   932         }
   934         @Override
   935         public void visitApply(JCMethodInvocation tree) {
   936             Name name = TreeInfo.name(tree.meth);
   938             //fast path
   939             if (tree.typeargs.nonEmpty() ||
   940                     name == name.table.names._this ||
   941                     name == name.table.names._super) {
   942                 result = ArgumentExpressionKind.NO_POLY;
   943                 return;
   944             }
   946             //slow path
   947             final JCExpression rec = tree.meth.hasTag(SELECT) ?
   948                     ((JCFieldAccess)tree.meth).selected :
   949                     null;
   951             if (rec != null && !isSimpleReceiver(rec)) {
   952                 //give up if receiver is too complex (to cut down analysis time)
   953                 result = ArgumentExpressionKind.POLY;
   954                 return;
   955             }
   957             Type site = rec != null ?
   958                     attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
   959                     env.enclClass.sym.type;
   961             while (site.hasTag(TYPEVAR)) {
   962                 site = site.getUpperBound();
   963             }
   965             List<Type> args = rs.dummyArgs(tree.args.length());
   967             Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
   968                 @Override
   969                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
   970                     return rec == null ?
   971                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
   972                         rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
   973                 }
   974                 @Override
   975                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
   976                     return sym;
   977                 }
   978             };
   980             Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
   982             if (sym.kind == Kinds.AMBIGUOUS) {
   983                 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
   984                 result = ArgumentExpressionKind.PRIMITIVE;
   985                 for (Symbol s : err.ambiguousSyms) {
   986                     if (result.isPoly()) break;
   987                     if (s.kind == Kinds.MTH) {
   988                         result = reduce(ArgumentExpressionKind.methodKind(s, types));
   989                     }
   990                 }
   991             } else {
   992                 result = (sym.kind == Kinds.MTH) ?
   993                     ArgumentExpressionKind.methodKind(sym, types) :
   994                     ArgumentExpressionKind.NO_POLY;
   995             }
   996         }
   997         //where
   998             private boolean isSimpleReceiver(JCTree rec) {
   999                 switch (rec.getTag()) {
  1000                     case IDENT:
  1001                         return true;
  1002                     case SELECT:
  1003                         return isSimpleReceiver(((JCFieldAccess)rec).selected);
  1004                     case TYPEAPPLY:
  1005                     case TYPEARRAY:
  1006                         return true;
  1007                     case ANNOTATED_TYPE:
  1008                         return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
  1009                     default:
  1010                         return false;
  1013             private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
  1014                 switch (result) {
  1015                     case PRIMITIVE: return kind;
  1016                     case NO_POLY: return kind.isPoly() ? kind : result;
  1017                     case POLY: return result;
  1018                     default:
  1019                         Assert.error();
  1020                         return null;
  1024         @Override
  1025         public void visitLiteral(JCLiteral tree) {
  1026             Type litType = attr.litType(tree.typetag);
  1027             result = ArgumentExpressionKind.standaloneKind(litType, types);
  1030         @Override
  1031         void skip(JCTree tree) {
  1032             result = ArgumentExpressionKind.NO_POLY;
  1035     //where
  1036     private EnumSet<JCTree.Tag> deferredCheckerTags =
  1037             EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
  1038                     CONDEXPR, NEWCLASS, APPLY, LITERAL);

mercurial