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

Mon, 11 Nov 2013 09:47:46 -0500

author
emc
date
Mon, 11 Nov 2013 09:47:46 -0500
changeset 2187
4788eb38cac5
parent 2047
5f915a0c9615
child 2193
d4cbb671de1c
permissions
-rw-r--r--

8027439: Compile-time error in the case of ((Integer[] & Serializable)new Integer[1]).getClass()
8027253: javac illegally accepts array as bound
Summary: backing out change allowing arrays in intersection types
Reviewed-by: 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.source.tree.MemberReferenceTree;
    29 import com.sun.tools.javac.code.*;
    30 import com.sun.tools.javac.tree.*;
    31 import com.sun.tools.javac.util.*;
    32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    33 import com.sun.tools.javac.code.Symbol.*;
    34 import com.sun.tools.javac.code.Type.*;
    35 import com.sun.tools.javac.comp.Attr.ResultInfo;
    36 import com.sun.tools.javac.comp.Infer.InferenceContext;
    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.*;
    42 import java.util.ArrayList;
    43 import java.util.Collections;
    44 import java.util.EnumSet;
    45 import java.util.LinkedHashMap;
    46 import java.util.LinkedHashSet;
    47 import java.util.Map;
    48 import java.util.Set;
    49 import java.util.WeakHashMap;
    51 import static com.sun.tools.javac.code.TypeTag.*;
    52 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    54 /**
    55  * This is an helper class that is used to perform deferred type-analysis.
    56  * Each time a poly expression occurs in argument position, javac attributes it
    57  * with a temporary 'deferred type' that is checked (possibly multiple times)
    58  * against an expected formal type.
    59  *
    60  *  <p><b>This is NOT part of any supported API.
    61  *  If you write code that depends on this, you do so at your own risk.
    62  *  This code and its internal interfaces are subject to change or
    63  *  deletion without notice.</b>
    64  */
    65 public class DeferredAttr extends JCTree.Visitor {
    66     protected static final Context.Key<DeferredAttr> deferredAttrKey =
    67         new Context.Key<DeferredAttr>();
    69     final Attr attr;
    70     final Check chk;
    71     final JCDiagnostic.Factory diags;
    72     final Enter enter;
    73     final Infer infer;
    74     final Resolve rs;
    75     final Log log;
    76     final Symtab syms;
    77     final TreeMaker make;
    78     final Types types;
    80     public static DeferredAttr instance(Context context) {
    81         DeferredAttr instance = context.get(deferredAttrKey);
    82         if (instance == null)
    83             instance = new DeferredAttr(context);
    84         return instance;
    85     }
    87     protected DeferredAttr(Context context) {
    88         context.put(deferredAttrKey, this);
    89         attr = Attr.instance(context);
    90         chk = Check.instance(context);
    91         diags = JCDiagnostic.Factory.instance(context);
    92         enter = Enter.instance(context);
    93         infer = Infer.instance(context);
    94         rs = Resolve.instance(context);
    95         log = Log.instance(context);
    96         syms = Symtab.instance(context);
    97         make = TreeMaker.instance(context);
    98         types = Types.instance(context);
    99         Names names = Names.instance(context);
   100         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
   101         emptyDeferredAttrContext =
   102             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
   103                 @Override
   104                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
   105                     Assert.error("Empty deferred context!");
   106                 }
   107                 @Override
   108                 void complete() {
   109                     Assert.error("Empty deferred context!");
   110                 }
   111             };
   112     }
   114     /** shared tree for stuck expressions */
   115     final JCTree stuckTree;
   117     /**
   118      * This type represents a deferred type. A deferred type starts off with
   119      * no information on the underlying expression type. Such info needs to be
   120      * discovered through type-checking the deferred type against a target-type.
   121      * Every deferred type keeps a pointer to the AST node from which it originated.
   122      */
   123     public class DeferredType extends Type {
   125         public JCExpression tree;
   126         Env<AttrContext> env;
   127         AttrMode mode;
   128         SpeculativeCache speculativeCache;
   130         DeferredType(JCExpression tree, Env<AttrContext> env) {
   131             super(null);
   132             this.tree = tree;
   133             this.env = attr.copyEnv(env);
   134             this.speculativeCache = new SpeculativeCache();
   135         }
   137         @Override
   138         public TypeTag getTag() {
   139             return DEFERRED;
   140         }
   142         /**
   143          * A speculative cache is used to keep track of all overload resolution rounds
   144          * that triggered speculative attribution on a given deferred type. Each entry
   145          * stores a pointer to the speculative tree and the resolution phase in which the entry
   146          * has been added.
   147          */
   148         class SpeculativeCache {
   150             private Map<Symbol, List<Entry>> cache =
   151                     new WeakHashMap<Symbol, List<Entry>>();
   153             class Entry {
   154                 JCTree speculativeTree;
   155                 ResultInfo resultInfo;
   157                 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
   158                     this.speculativeTree = speculativeTree;
   159                     this.resultInfo = resultInfo;
   160                 }
   162                 boolean matches(MethodResolutionPhase phase) {
   163                     return resultInfo.checkContext.deferredAttrContext().phase == phase;
   164                 }
   165             }
   167             /**
   168              * Retrieve a speculative cache entry corresponding to given symbol
   169              * and resolution phase
   170              */
   171             Entry get(Symbol msym, MethodResolutionPhase phase) {
   172                 List<Entry> entries = cache.get(msym);
   173                 if (entries == null) return null;
   174                 for (Entry e : entries) {
   175                     if (e.matches(phase)) return e;
   176                 }
   177                 return null;
   178             }
   180             /**
   181              * Stores a speculative cache entry corresponding to given symbol
   182              * and resolution phase
   183              */
   184             void put(JCTree speculativeTree, ResultInfo resultInfo) {
   185                 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
   186                 List<Entry> entries = cache.get(msym);
   187                 if (entries == null) {
   188                     entries = List.nil();
   189                 }
   190                 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
   191             }
   192         }
   194         /**
   195          * Get the type that has been computed during a speculative attribution round
   196          */
   197         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
   198             SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
   199             return e != null ? e.speculativeTree.type : Type.noType;
   200         }
   202         /**
   203          * Check a deferred type against a potential target-type. Depending on
   204          * the current attribution mode, a normal vs. speculative attribution
   205          * round is performed on the underlying AST node. There can be only one
   206          * speculative round for a given target method symbol; moreover, a normal
   207          * attribution round must follow one or more speculative rounds.
   208          */
   209         Type check(ResultInfo resultInfo) {
   210             DeferredStuckPolicy deferredStuckPolicy;
   211             if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
   212                 deferredStuckPolicy = dummyStuckPolicy;
   213             } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
   214                 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
   215             } else {
   216                 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
   217             }
   218             return check(resultInfo, deferredStuckPolicy, basicCompleter);
   219         }
   221         private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
   222                 DeferredTypeCompleter deferredTypeCompleter) {
   223             DeferredAttrContext deferredAttrContext =
   224                     resultInfo.checkContext.deferredAttrContext();
   225             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
   226             if (deferredStuckPolicy.isStuck()) {
   227                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
   228                 return Type.noType;
   229             } else {
   230                 try {
   231                     return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
   232                 } finally {
   233                     mode = deferredAttrContext.mode;
   234                 }
   235             }
   236         }
   237     }
   239     /**
   240      * A completer for deferred types. Defines an entry point for type-checking
   241      * a deferred type.
   242      */
   243     interface DeferredTypeCompleter {
   244         /**
   245          * Entry point for type-checking a deferred type. Depending on the
   246          * circumstances, type-checking could amount to full attribution
   247          * or partial structural check (aka potential applicability).
   248          */
   249         Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
   250     }
   253     /**
   254      * A basic completer for deferred types. This completer type-checks a deferred type
   255      * using attribution; depending on the attribution mode, this could be either standard
   256      * or speculative attribution.
   257      */
   258     DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
   259         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   260             switch (deferredAttrContext.mode) {
   261                 case SPECULATIVE:
   262                     //Note: if a symbol is imported twice we might do two identical
   263                     //speculative rounds...
   264                     Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
   265                     JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
   266                     dt.speculativeCache.put(speculativeTree, resultInfo);
   267                     return speculativeTree.type;
   268                 case CHECK:
   269                     Assert.check(dt.mode != null);
   270                     return attr.attribTree(dt.tree, dt.env, resultInfo);
   271             }
   272             Assert.error();
   273             return null;
   274         }
   275     };
   277     DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
   278         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   279             Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
   280             return dt.tree.type = Type.stuckType;
   281         }
   282     };
   284     /**
   285      * Policy for detecting stuck expressions. Different criteria might cause
   286      * an expression to be judged as stuck, depending on whether the check
   287      * is performed during overload resolution or after most specific.
   288      */
   289     interface DeferredStuckPolicy {
   290         /**
   291          * Has the policy detected that a given expression should be considered stuck?
   292          */
   293         boolean isStuck();
   294         /**
   295          * Get the set of inference variables a given expression depends upon.
   296          */
   297         Set<Type> stuckVars();
   298         /**
   299          * Get the set of inference variables which might get new constraints
   300          * if a given expression is being type-checked.
   301          */
   302         Set<Type> depVars();
   303     }
   305     /**
   306      * Basic stuck policy; an expression is never considered to be stuck.
   307      */
   308     DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
   309         @Override
   310         public boolean isStuck() {
   311             return false;
   312         }
   313         @Override
   314         public Set<Type> stuckVars() {
   315             return Collections.emptySet();
   316         }
   317         @Override
   318         public Set<Type> depVars() {
   319             return Collections.emptySet();
   320         }
   321     };
   323     /**
   324      * The 'mode' in which the deferred type is to be type-checked
   325      */
   326     public enum AttrMode {
   327         /**
   328          * A speculative type-checking round is used during overload resolution
   329          * mainly to generate constraints on inference variables. Side-effects
   330          * arising from type-checking the expression associated with the deferred
   331          * type are reversed after the speculative round finishes. This means the
   332          * expression tree will be left in a blank state.
   333          */
   334         SPECULATIVE,
   335         /**
   336          * This is the plain type-checking mode. Produces side-effects on the underlying AST node
   337          */
   338         CHECK;
   339     }
   341     /**
   342      * Routine that performs speculative type-checking; the input AST node is
   343      * cloned (to avoid side-effects cause by Attr) and compiler state is
   344      * restored after type-checking. All diagnostics (but critical ones) are
   345      * disabled during speculative type-checking.
   346      */
   347     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
   348         final JCTree newTree = new TreeCopier<Object>(make).copy(tree);
   349         Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
   350         speculativeEnv.info.scope.owner = env.info.scope.owner;
   351         Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
   352                 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
   353             public boolean accepts(final JCDiagnostic d) {
   354                 class PosScanner extends TreeScanner {
   355                     boolean found = false;
   357                     @Override
   358                     public void scan(JCTree tree) {
   359                         if (tree != null &&
   360                                 tree.pos() == d.getDiagnosticPosition()) {
   361                             found = true;
   362                         }
   363                         super.scan(tree);
   364                     }
   365                 };
   366                 PosScanner posScanner = new PosScanner();
   367                 posScanner.scan(newTree);
   368                 return posScanner.found;
   369             }
   370         });
   371         try {
   372             attr.attribTree(newTree, speculativeEnv, resultInfo);
   373             unenterScanner.scan(newTree);
   374             return newTree;
   375         } finally {
   376             unenterScanner.scan(newTree);
   377             log.popDiagnosticHandler(deferredDiagnosticHandler);
   378         }
   379     }
   380     //where
   381         protected TreeScanner unenterScanner = new TreeScanner() {
   382             @Override
   383             public void visitClassDef(JCClassDecl tree) {
   384                 ClassSymbol csym = tree.sym;
   385                 //if something went wrong during method applicability check
   386                 //it is possible that nested expressions inside argument expression
   387                 //are left unchecked - in such cases there's nothing to clean up.
   388                 if (csym == null) return;
   389                 enter.typeEnvs.remove(csym);
   390                 chk.compiled.remove(csym.flatname);
   391                 syms.classes.remove(csym.flatname);
   392                 super.visitClassDef(tree);
   393             }
   394         };
   396     /**
   397      * A deferred context is created on each method check. A deferred context is
   398      * used to keep track of information associated with the method check, such as
   399      * the symbol of the method being checked, the overload resolution phase,
   400      * the kind of attribution mode to be applied to deferred types and so forth.
   401      * As deferred types are processed (by the method check routine) stuck AST nodes
   402      * are added (as new deferred attribution nodes) to this context. The complete()
   403      * routine makes sure that all pending nodes are properly processed, by
   404      * progressively instantiating all inference variables on which one or more
   405      * deferred attribution node is stuck.
   406      */
   407     class DeferredAttrContext {
   409         /** attribution mode */
   410         final AttrMode mode;
   412         /** symbol of the method being checked */
   413         final Symbol msym;
   415         /** method resolution step */
   416         final Resolve.MethodResolutionPhase phase;
   418         /** inference context */
   419         final InferenceContext inferenceContext;
   421         /** parent deferred context */
   422         final DeferredAttrContext parent;
   424         /** Warner object to report warnings */
   425         final Warner warn;
   427         /** list of deferred attribution nodes to be processed */
   428         ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
   430         DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
   431                 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
   432             this.mode = mode;
   433             this.msym = msym;
   434             this.phase = phase;
   435             this.parent = parent;
   436             this.warn = warn;
   437             this.inferenceContext = inferenceContext;
   438         }
   440         /**
   441          * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
   442          * Nodes added this way act as 'roots' for the out-of-order method checking process.
   443          */
   444         void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
   445                 DeferredStuckPolicy deferredStuckPolicy) {
   446             deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
   447         }
   449         /**
   450          * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
   451          * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
   452          * some inference variable might get eagerly instantiated so that all nodes
   453          * can be type-checked.
   454          */
   455         void complete() {
   456             while (!deferredAttrNodes.isEmpty()) {
   457                 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<Type, Set<Type>>();
   458                 List<Type> stuckVars = List.nil();
   459                 boolean progress = false;
   460                 //scan a defensive copy of the node list - this is because a deferred
   461                 //attribution round can add new nodes to the list
   462                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
   463                     if (!deferredAttrNode.process(this)) {
   464                         List<Type> restStuckVars =
   465                                 List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
   466                                 .intersect(inferenceContext.restvars());
   467                         stuckVars = stuckVars.prependList(restStuckVars);
   468                         //update dependency map
   469                         for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
   470                                 .intersect(inferenceContext.restvars())) {
   471                             Set<Type> prevDeps = depVarsMap.get(t);
   472                             if (prevDeps == null) {
   473                                 prevDeps = new LinkedHashSet<Type>();
   474                                 depVarsMap.put(t, prevDeps);
   475                             }
   476                             prevDeps.addAll(restStuckVars);
   477                         }
   478                     } else {
   479                         deferredAttrNodes.remove(deferredAttrNode);
   480                         progress = true;
   481                     }
   482                 }
   483                 if (!progress) {
   484                     DeferredAttrContext dac = this;
   485                     while (dac != emptyDeferredAttrContext) {
   486                         if (dac.mode == AttrMode.SPECULATIVE) {
   487                             //unsticking does not take place during overload
   488                             break;
   489                         }
   490                         dac = dac.parent;
   491                     }
   492                     //remove all variables that have already been instantiated
   493                     //from the list of stuck variables
   494                     try {
   495                         inferenceContext.solveAny(stuckVars, depVarsMap, warn);
   496                         inferenceContext.notifyChange();
   497                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
   498                         //this means that we are in speculative mode and the
   499                         //set of contraints are too tight for progess to be made.
   500                         //Just leave the remaining expressions as stuck.
   501                         break;
   502                     }
   503                 }
   504             }
   505         }
   506     }
   508     /**
   509      * Class representing a deferred attribution node. It keeps track of
   510      * a deferred type, along with the expected target type information.
   511      */
   512     class DeferredAttrNode {
   514         /** underlying deferred type */
   515         DeferredType dt;
   517         /** underlying target type information */
   518         ResultInfo resultInfo;
   520         /** stuck policy associated with this node */
   521         DeferredStuckPolicy deferredStuckPolicy;
   523         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
   524             this.dt = dt;
   525             this.resultInfo = resultInfo;
   526             this.deferredStuckPolicy = deferredStuckPolicy;
   527         }
   529         /**
   530          * Process a deferred attribution node.
   531          * Invariant: a stuck node cannot be processed.
   532          */
   533         @SuppressWarnings("fallthrough")
   534         boolean process(final DeferredAttrContext deferredAttrContext) {
   535             switch (deferredAttrContext.mode) {
   536                 case SPECULATIVE:
   537                     if (deferredStuckPolicy.isStuck()) {
   538                         dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
   539                         return true;
   540                     } else {
   541                         Assert.error("Cannot get here");
   542                     }
   543                 case CHECK:
   544                     if (deferredStuckPolicy.isStuck()) {
   545                         //stuck expression - see if we can propagate
   546                         if (deferredAttrContext.parent != emptyDeferredAttrContext &&
   547                                 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
   548                                         List.from(deferredStuckPolicy.stuckVars()))) {
   549                             deferredAttrContext.parent.addDeferredAttrNode(dt,
   550                                     resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
   551                                 @Override
   552                                 public InferenceContext inferenceContext() {
   553                                     return deferredAttrContext.parent.inferenceContext;
   554                                 }
   555                                 @Override
   556                                 public DeferredAttrContext deferredAttrContext() {
   557                                     return deferredAttrContext.parent;
   558                                 }
   559                             }), deferredStuckPolicy);
   560                             dt.tree.type = Type.stuckType;
   561                             return true;
   562                         } else {
   563                             return false;
   564                         }
   565                     } else {
   566                         ResultInfo instResultInfo =
   567                                 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
   568                         dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
   569                         return true;
   570                     }
   571                 default:
   572                     throw new AssertionError("Bad mode");
   573             }
   574         }
   576         /**
   577          * Structural checker for stuck expressions
   578          */
   579         class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
   581             ResultInfo resultInfo;
   582             InferenceContext inferenceContext;
   583             Env<AttrContext> env;
   585             public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   586                 this.resultInfo = resultInfo;
   587                 this.inferenceContext = deferredAttrContext.inferenceContext;
   588                 this.env = dt.env;
   589                 dt.tree.accept(this);
   590                 dt.speculativeCache.put(stuckTree, resultInfo);
   591                 return Type.noType;
   592             }
   594             @Override
   595             public void visitLambda(JCLambda tree) {
   596                 Check.CheckContext checkContext = resultInfo.checkContext;
   597                 Type pt = resultInfo.pt;
   598                 if (inferenceContext.inferencevars.contains(pt)) {
   599                     //ok
   600                     return;
   601                 } else {
   602                     //must be a functional descriptor
   603                     try {
   604                         Type desc = types.findDescriptorType(pt);
   605                         if (desc.getParameterTypes().length() != tree.params.length()) {
   606                             checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
   607                         }
   608                     } catch (Types.FunctionDescriptorLookupError ex) {
   609                         checkContext.report(null, ex.getDiagnostic());
   610                     }
   611                 }
   612             }
   614             @Override
   615             public void visitNewClass(JCNewClass tree) {
   616                 //do nothing
   617             }
   619             @Override
   620             public void visitApply(JCMethodInvocation tree) {
   621                 //do nothing
   622             }
   624             @Override
   625             public void visitReference(JCMemberReference tree) {
   626                 Check.CheckContext checkContext = resultInfo.checkContext;
   627                 Type pt = resultInfo.pt;
   628                 if (inferenceContext.inferencevars.contains(pt)) {
   629                     //ok
   630                     return;
   631                 } else {
   632                     try {
   633                         types.findDescriptorType(pt);
   634                     } catch (Types.FunctionDescriptorLookupError ex) {
   635                         checkContext.report(null, ex.getDiagnostic());
   636                     }
   637                     Env<AttrContext> localEnv = env.dup(tree);
   638                     JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
   639                             attr.memberReferenceQualifierResult(tree));
   640                     ListBuffer<Type> argtypes = new ListBuffer<>();
   641                     for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
   642                         argtypes.append(Type.noType);
   643                     }
   644                     JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
   645                     mref2.expr = exprTree;
   646                     Pair<Symbol, ?> lookupRes =
   647                             rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
   648                                 tree.name, argtypes.toList(), null, true, rs.arityMethodCheck, inferenceContext);
   649                     switch (lookupRes.fst.kind) {
   650                         //note: as argtypes are erroneous types, type-errors must
   651                         //have been caused by arity mismatch
   652                         case Kinds.ABSENT_MTH:
   653                         case Kinds.WRONG_MTH:
   654                         case Kinds.WRONG_MTHS:
   655                            checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
   656                     }
   657                 }
   658             }
   659         }
   660     }
   662     /** an empty deferred attribution context - all methods throw exceptions */
   663     final DeferredAttrContext emptyDeferredAttrContext;
   665     /**
   666      * Map a list of types possibly containing one or more deferred types
   667      * into a list of ordinary types. Each deferred type D is mapped into a type T,
   668      * where T is computed by retrieving the type that has already been
   669      * computed for D during a previous deferred attribution round of the given kind.
   670      */
   671     class DeferredTypeMap extends Type.Mapping {
   673         DeferredAttrContext deferredAttrContext;
   675         protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   676             super(String.format("deferredTypeMap[%s]", mode));
   677             this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
   678                     infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
   679         }
   681         @Override
   682         public Type apply(Type t) {
   683             if (!t.hasTag(DEFERRED)) {
   684                 return t.map(this);
   685             } else {
   686                 DeferredType dt = (DeferredType)t;
   687                 return typeOf(dt);
   688             }
   689         }
   691         protected Type typeOf(DeferredType dt) {
   692             switch (deferredAttrContext.mode) {
   693                 case CHECK:
   694                     return dt.tree.type == null ? Type.noType : dt.tree.type;
   695                 case SPECULATIVE:
   696                     return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
   697             }
   698             Assert.error();
   699             return null;
   700         }
   701     }
   703     /**
   704      * Specialized recovery deferred mapping.
   705      * Each deferred type D is mapped into a type T, where T is computed either by
   706      * (i) retrieving the type that has already been computed for D during a previous
   707      * attribution round (as before), or (ii) by synthesizing a new type R for D
   708      * (the latter step is useful in a recovery scenario).
   709      */
   710     public class RecoveryDeferredTypeMap extends DeferredTypeMap {
   712         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   713             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
   714         }
   716         @Override
   717         protected Type typeOf(DeferredType dt) {
   718             Type owntype = super.typeOf(dt);
   719             return owntype == Type.noType ?
   720                         recover(dt) : owntype;
   721         }
   723         /**
   724          * Synthesize a type for a deferred type that hasn't been previously
   725          * reduced to an ordinary type. Functional deferred types and conditionals
   726          * are mapped to themselves, in order to have a richer diagnostic
   727          * representation. Remaining deferred types are attributed using
   728          * a default expected type (j.l.Object).
   729          */
   730         private Type recover(DeferredType dt) {
   731             dt.check(attr.new RecoveryInfo(deferredAttrContext) {
   732                 @Override
   733                 protected Type check(DiagnosticPosition pos, Type found) {
   734                     return chk.checkNonVoid(pos, super.check(pos, found));
   735                 }
   736             });
   737             return super.apply(dt);
   738         }
   739     }
   741     /**
   742      * A special tree scanner that would only visit portions of a given tree.
   743      * The set of nodes visited by the scanner can be customized at construction-time.
   744      */
   745     abstract static class FilterScanner extends TreeScanner {
   747         final Filter<JCTree> treeFilter;
   749         FilterScanner(final Set<JCTree.Tag> validTags) {
   750             this.treeFilter = new Filter<JCTree>() {
   751                 public boolean accepts(JCTree t) {
   752                     return validTags.contains(t.getTag());
   753                 }
   754             };
   755         }
   757         @Override
   758         public void scan(JCTree tree) {
   759             if (tree != null) {
   760                 if (treeFilter.accepts(tree)) {
   761                     super.scan(tree);
   762                 } else {
   763                     skip(tree);
   764                 }
   765             }
   766         }
   768         /**
   769          * handler that is executed when a node has been discarded
   770          */
   771         abstract void skip(JCTree tree);
   772     }
   774     /**
   775      * A tree scanner suitable for visiting the target-type dependent nodes of
   776      * a given argument expression.
   777      */
   778     static class PolyScanner extends FilterScanner {
   780         PolyScanner() {
   781             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   782         }
   784         @Override
   785         void skip(JCTree tree) {
   786             //do nothing
   787         }
   788     }
   790     /**
   791      * A tree scanner suitable for visiting the target-type dependent nodes nested
   792      * within a lambda expression body.
   793      */
   794     static class LambdaReturnScanner extends FilterScanner {
   796         LambdaReturnScanner() {
   797             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   798                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   799         }
   801         @Override
   802         void skip(JCTree tree) {
   803             //do nothing
   804         }
   805     }
   807     /**
   808      * This visitor is used to check that structural expressions conform
   809      * to their target - this step is required as inference could end up
   810      * inferring types that make some of the nested expressions incompatible
   811      * with their corresponding instantiated target
   812      */
   813     class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
   815         Type pt;
   816         Infer.InferenceContext inferenceContext;
   817         Set<Type> stuckVars = new LinkedHashSet<Type>();
   818         Set<Type> depVars = new LinkedHashSet<Type>();
   820         @Override
   821         public boolean isStuck() {
   822             return !stuckVars.isEmpty();
   823         }
   825         @Override
   826         public Set<Type> stuckVars() {
   827             return stuckVars;
   828         }
   830         @Override
   831         public Set<Type> depVars() {
   832             return depVars;
   833         }
   835         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
   836             this.pt = resultInfo.pt;
   837             this.inferenceContext = resultInfo.checkContext.inferenceContext();
   838             scan(dt.tree);
   839             if (!stuckVars.isEmpty()) {
   840                 resultInfo.checkContext.inferenceContext()
   841                         .addFreeTypeListener(List.from(stuckVars), this);
   842             }
   843         }
   845         @Override
   846         public void typesInferred(InferenceContext inferenceContext) {
   847             stuckVars.clear();
   848         }
   850         @Override
   851         public void visitLambda(JCLambda tree) {
   852             if (inferenceContext.inferenceVars().contains(pt)) {
   853                 stuckVars.add(pt);
   854             }
   855             if (!types.isFunctionalInterface(pt)) {
   856                 return;
   857             }
   858             Type descType = types.findDescriptorType(pt);
   859             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   860             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
   861                     freeArgVars.nonEmpty()) {
   862                 stuckVars.addAll(freeArgVars);
   863                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
   864             }
   865             scanLambdaBody(tree, descType.getReturnType());
   866         }
   868         @Override
   869         public void visitReference(JCMemberReference tree) {
   870             scan(tree.expr);
   871             if (inferenceContext.inferenceVars().contains(pt)) {
   872                 stuckVars.add(pt);
   873                 return;
   874             }
   875             if (!types.isFunctionalInterface(pt)) {
   876                 return;
   877             }
   879             Type descType = types.findDescriptorType(pt);
   880             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   881             if (freeArgVars.nonEmpty() &&
   882                     tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
   883                 stuckVars.addAll(freeArgVars);
   884                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
   885             }
   886         }
   888         void scanLambdaBody(JCLambda lambda, final Type pt) {
   889             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
   890                 Type prevPt = this.pt;
   891                 try {
   892                     this.pt = pt;
   893                     scan(lambda.body);
   894                 } finally {
   895                     this.pt = prevPt;
   896                 }
   897             } else {
   898                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
   899                     @Override
   900                     public void visitReturn(JCReturn tree) {
   901                         if (tree.expr != null) {
   902                             Type prevPt = CheckStuckPolicy.this.pt;
   903                             try {
   904                                 CheckStuckPolicy.this.pt = pt;
   905                                 CheckStuckPolicy.this.scan(tree.expr);
   906                             } finally {
   907                                 CheckStuckPolicy.this.pt = prevPt;
   908                             }
   909                         }
   910                     }
   911                 };
   912                 lambdaScanner.scan(lambda.body);
   913             }
   914         }
   915     }
   917     /**
   918      * This visitor is used to check that structural expressions conform
   919      * to their target - this step is required as inference could end up
   920      * inferring types that make some of the nested expressions incompatible
   921      * with their corresponding instantiated target
   922      */
   923     class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
   925         boolean stuck;
   927         @Override
   928         public boolean isStuck() {
   929             return super.isStuck() || stuck;
   930         }
   932         public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
   933             super(resultInfo, dt);
   934         }
   936         @Override
   937         public void visitLambda(JCLambda tree) {
   938             super.visitLambda(tree);
   939             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
   940                 stuck = true;
   941             }
   942         }
   944         @Override
   945         public void visitReference(JCMemberReference tree) {
   946             super.visitReference(tree);
   947             if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
   948                 stuck = true;
   949             }
   950         }
   951     }
   953     /**
   954      * Does the argument expression {@code expr} need speculative type-checking?
   955      */
   956     boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
   957         DeferredChecker dc = new DeferredChecker(env);
   958         dc.scan(expr);
   959         return dc.result.isPoly();
   960     }
   962     /**
   963      * The kind of an argument expression. This is used by the analysis that
   964      * determines as to whether speculative attribution is necessary.
   965      */
   966     enum ArgumentExpressionKind {
   968         /** kind that denotes poly argument expression */
   969         POLY,
   970         /** kind that denotes a standalone expression */
   971         NO_POLY,
   972         /** kind that denotes a primitive/boxed standalone expression */
   973         PRIMITIVE;
   975         /**
   976          * Does this kind denote a poly argument expression
   977          */
   978         public final boolean isPoly() {
   979             return this == POLY;
   980         }
   982         /**
   983          * Does this kind denote a primitive standalone expression
   984          */
   985         public final boolean isPrimitive() {
   986             return this == PRIMITIVE;
   987         }
   989         /**
   990          * Compute the kind of a standalone expression of a given type
   991          */
   992         static ArgumentExpressionKind standaloneKind(Type type, Types types) {
   993             return types.unboxedTypeOrType(type).isPrimitive() ?
   994                     ArgumentExpressionKind.PRIMITIVE :
   995                     ArgumentExpressionKind.NO_POLY;
   996         }
   998         /**
   999          * Compute the kind of a method argument expression given its symbol
  1000          */
  1001         static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
  1002             Type restype = sym.type.getReturnType();
  1003             if (sym.type.hasTag(FORALL) &&
  1004                     restype.containsAny(((ForAll)sym.type).tvars)) {
  1005                 return ArgumentExpressionKind.POLY;
  1006             } else {
  1007                 return ArgumentExpressionKind.standaloneKind(restype, types);
  1012     /**
  1013      * Tree scanner used for checking as to whether an argument expression
  1014      * requires speculative attribution
  1015      */
  1016     final class DeferredChecker extends FilterScanner {
  1018         Env<AttrContext> env;
  1019         ArgumentExpressionKind result;
  1021         public DeferredChecker(Env<AttrContext> env) {
  1022             super(deferredCheckerTags);
  1023             this.env = env;
  1026         @Override
  1027         public void visitLambda(JCLambda tree) {
  1028             //a lambda is always a poly expression
  1029             result = ArgumentExpressionKind.POLY;
  1032         @Override
  1033         public void visitReference(JCMemberReference tree) {
  1034             //perform arity-based check
  1035             Env<AttrContext> localEnv = env.dup(tree);
  1036             JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
  1037                     attr.memberReferenceQualifierResult(tree));
  1038             JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
  1039             mref2.expr = exprTree;
  1040             Pair<Symbol, ReferenceLookupHelper> lookupRes =
  1041                     rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
  1042                         tree.name, List.<Type>nil(), null, true, rs.nilMethodCheck,
  1043                         infer.emptyContext);
  1044             Symbol res = tree.sym = lookupRes.fst;
  1045             if (res.kind >= Kinds.ERRONEOUS ||
  1046                     res.type.hasTag(FORALL) ||
  1047                     (res.flags() & Flags.VARARGS) != 0 ||
  1048                     (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
  1049                     exprTree.type.isRaw())) {
  1050                 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
  1051             } else {
  1052                 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
  1054             //a method reference is always a poly expression
  1055             result = ArgumentExpressionKind.POLY;
  1058         @Override
  1059         public void visitTypeCast(JCTypeCast tree) {
  1060             //a cast is always a standalone expression
  1061             result = ArgumentExpressionKind.NO_POLY;
  1064         @Override
  1065         public void visitConditional(JCConditional tree) {
  1066             scan(tree.truepart);
  1067             if (!result.isPrimitive()) {
  1068                 result = ArgumentExpressionKind.POLY;
  1069                 return;
  1071             scan(tree.falsepart);
  1072             result = reduce(ArgumentExpressionKind.PRIMITIVE);
  1075         @Override
  1076         public void visitNewClass(JCNewClass tree) {
  1077             result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
  1078                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
  1081         @Override
  1082         public void visitApply(JCMethodInvocation tree) {
  1083             Name name = TreeInfo.name(tree.meth);
  1085             //fast path
  1086             if (tree.typeargs.nonEmpty() ||
  1087                     name == name.table.names._this ||
  1088                     name == name.table.names._super) {
  1089                 result = ArgumentExpressionKind.NO_POLY;
  1090                 return;
  1093             //slow path
  1094             final JCExpression rec = tree.meth.hasTag(SELECT) ?
  1095                     ((JCFieldAccess)tree.meth).selected :
  1096                     null;
  1098             if (rec != null && !isSimpleReceiver(rec)) {
  1099                 //give up if receiver is too complex (to cut down analysis time)
  1100                 result = ArgumentExpressionKind.POLY;
  1101                 return;
  1104             Type site = rec != null ?
  1105                     attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
  1106                     env.enclClass.sym.type;
  1108             while (site.hasTag(TYPEVAR)) {
  1109                 site = site.getUpperBound();
  1112             List<Type> args = rs.dummyArgs(tree.args.length());
  1114             Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
  1115                 @Override
  1116                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
  1117                     return rec == null ?
  1118                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
  1119                         rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
  1121                 @Override
  1122                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
  1123                     return sym;
  1125             };
  1127             Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
  1129             if (sym.kind == Kinds.AMBIGUOUS) {
  1130                 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
  1131                 result = ArgumentExpressionKind.PRIMITIVE;
  1132                 for (Symbol s : err.ambiguousSyms) {
  1133                     if (result.isPoly()) break;
  1134                     if (s.kind == Kinds.MTH) {
  1135                         result = reduce(ArgumentExpressionKind.methodKind(s, types));
  1138             } else {
  1139                 result = (sym.kind == Kinds.MTH) ?
  1140                     ArgumentExpressionKind.methodKind(sym, types) :
  1141                     ArgumentExpressionKind.NO_POLY;
  1144         //where
  1145             private boolean isSimpleReceiver(JCTree rec) {
  1146                 switch (rec.getTag()) {
  1147                     case IDENT:
  1148                         return true;
  1149                     case SELECT:
  1150                         return isSimpleReceiver(((JCFieldAccess)rec).selected);
  1151                     case TYPEAPPLY:
  1152                     case TYPEARRAY:
  1153                         return true;
  1154                     case ANNOTATED_TYPE:
  1155                         return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
  1156                     default:
  1157                         return false;
  1160             private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
  1161                 switch (result) {
  1162                     case PRIMITIVE: return kind;
  1163                     case NO_POLY: return kind.isPoly() ? kind : result;
  1164                     case POLY: return result;
  1165                     default:
  1166                         Assert.error();
  1167                         return null;
  1171         @Override
  1172         public void visitLiteral(JCLiteral tree) {
  1173             Type litType = attr.litType(tree.typetag);
  1174             result = ArgumentExpressionKind.standaloneKind(litType, types);
  1177         @Override
  1178         void skip(JCTree tree) {
  1179             result = ArgumentExpressionKind.NO_POLY;
  1182     //where
  1183     private EnumSet<JCTree.Tag> deferredCheckerTags =
  1184             EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
  1185                     CONDEXPR, NEWCLASS, APPLY, LITERAL);

mercurial