langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
changeset 38516 b643c42e9d25
parent 38512 c71e1cdd6674
child 42827 36468b5fa7f4
equal deleted inserted replaced
38515:6ae7f7d9b44c 38516:b643c42e9d25
    33 import com.sun.tools.javac.comp.Resolve.ResolveError;
    33 import com.sun.tools.javac.comp.Resolve.ResolveError;
    34 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
    34 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
    35 import com.sun.tools.javac.tree.*;
    35 import com.sun.tools.javac.tree.*;
    36 import com.sun.tools.javac.util.*;
    36 import com.sun.tools.javac.util.*;
    37 import com.sun.tools.javac.util.DefinedBy.Api;
    37 import com.sun.tools.javac.util.DefinedBy.Api;
       
    38 import com.sun.tools.javac.util.GraphUtils.DependencyKind;
    38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    39 import com.sun.tools.javac.code.Symbol.*;
    40 import com.sun.tools.javac.code.Symbol.*;
    40 import com.sun.tools.javac.comp.Attr.ResultInfo;
    41 import com.sun.tools.javac.comp.Attr.ResultInfo;
    41 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
    42 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
    42 import com.sun.tools.javac.tree.JCTree.*;
    43 import com.sun.tools.javac.tree.JCTree.*;
    43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
    44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
    44 import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
    45 import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
    45 
    46 
    46 import java.util.ArrayList;
    47 import java.util.ArrayList;
       
    48 import java.util.Collection;
    47 import java.util.Collections;
    49 import java.util.Collections;
    48 import java.util.EnumSet;
    50 import java.util.EnumSet;
    49 import java.util.LinkedHashMap;
    51 import java.util.HashSet;
    50 import java.util.LinkedHashSet;
    52 import java.util.LinkedHashSet;
    51 import java.util.Map;
    53 import java.util.Map;
    52 import java.util.Set;
    54 import java.util.Set;
    53 import java.util.WeakHashMap;
    55 import java.util.WeakHashMap;
    54 import java.util.function.Function;
    56 import java.util.function.Function;
   574          * some inference variable might get eagerly instantiated so that all nodes
   576          * some inference variable might get eagerly instantiated so that all nodes
   575          * can be type-checked.
   577          * can be type-checked.
   576          */
   578          */
   577         void complete() {
   579         void complete() {
   578             while (!deferredAttrNodes.isEmpty()) {
   580             while (!deferredAttrNodes.isEmpty()) {
   579                 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
       
   580                 List<Type> stuckVars = List.nil();
       
   581                 boolean progress = false;
   581                 boolean progress = false;
   582                 //scan a defensive copy of the node list - this is because a deferred
   582                 //scan a defensive copy of the node list - this is because a deferred
   583                 //attribution round can add new nodes to the list
   583                 //attribution round can add new nodes to the list
   584                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
   584                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
   585                     if (!deferredAttrNode.process(this)) {
   585                     if (deferredAttrNode.process(this)) {
   586                         List<Type> restStuckVars =
       
   587                                 List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
       
   588                                 .intersect(inferenceContext.restvars());
       
   589                         stuckVars = stuckVars.prependList(restStuckVars);
       
   590                         //update dependency map
       
   591                         for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
       
   592                                 .intersect(inferenceContext.restvars())) {
       
   593                             Set<Type> prevDeps = depVarsMap.get(t);
       
   594                             if (prevDeps == null) {
       
   595                                 prevDeps = new LinkedHashSet<>();
       
   596                                 depVarsMap.put(t, prevDeps);
       
   597                             }
       
   598                             prevDeps.addAll(restStuckVars);
       
   599                         }
       
   600                     } else {
       
   601                         deferredAttrNodes.remove(deferredAttrNode);
   586                         deferredAttrNodes.remove(deferredAttrNode);
   602                         progress = true;
   587                         progress = true;
   603                     }
   588                     }
   604                 }
   589                 }
   605                 if (!progress) {
   590                 if (!progress) {
   610                         return;
   595                         return;
   611                     }
   596                     }
   612                     //remove all variables that have already been instantiated
   597                     //remove all variables that have already been instantiated
   613                     //from the list of stuck variables
   598                     //from the list of stuck variables
   614                     try {
   599                     try {
   615                         inferenceContext.solveAny(stuckVars, depVarsMap, warn);
   600                         //find stuck expression to unstuck
       
   601                         DeferredAttrNode toUnstuck = pickDeferredNode();
       
   602                         inferenceContext.solveAny(List.from(toUnstuck.deferredStuckPolicy.stuckVars()), warn);
   616                         inferenceContext.notifyChange();
   603                         inferenceContext.notifyChange();
   617                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
   604                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
   618                         //this means that we are in speculative mode and the
   605                         //this means that we are in speculative mode and the
   619                         //set of contraints are too tight for progess to be made.
   606                         //set of contraints are too tight for progess to be made.
   620                         //Just leave the remaining expressions as stuck.
   607                         //Just leave the remaining expressions as stuck.
   631             }
   618             }
   632             if (dac.mode == AttrMode.SPECULATIVE) {
   619             if (dac.mode == AttrMode.SPECULATIVE) {
   633                 return true;
   620                 return true;
   634             }
   621             }
   635             return dac.parent.insideOverloadPhase();
   622             return dac.parent.insideOverloadPhase();
       
   623         }
       
   624 
       
   625         /**
       
   626          * Pick the deferred node to be unstuck. The chosen node is the first strongly connected
       
   627          * component containing exactly one node found in the dependency graph induced by deferred nodes.
       
   628          * If no such component is found, the first deferred node is returned.
       
   629          */
       
   630         DeferredAttrNode pickDeferredNode() {
       
   631             List<StuckNode> nodes = deferredAttrNodes.stream()
       
   632                     .map(StuckNode::new)
       
   633                     .collect(List.collector());
       
   634             //init stuck expression graph; a deferred node A depends on a deferred node B iff
       
   635             //the intersection between A's input variable and B's output variable is non-empty.
       
   636             for (StuckNode sn1 : nodes) {
       
   637                 for (Type t : sn1.data.deferredStuckPolicy.stuckVars()) {
       
   638                     for (StuckNode sn2 : nodes) {
       
   639                         if (sn1 != sn2 && sn2.data.deferredStuckPolicy.depVars().contains(t)) {
       
   640                             sn1.deps.add(sn2);
       
   641                         }
       
   642                     }
       
   643                 }
       
   644             }
       
   645             //compute tarjan on the stuck graph
       
   646             List<? extends StuckNode> csn = GraphUtils.tarjan(nodes).get(0);
       
   647             return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0);
       
   648         }
       
   649 
       
   650         class StuckNode extends GraphUtils.TarjanNode<DeferredAttrNode, StuckNode> {
       
   651 
       
   652             Set<StuckNode> deps = new HashSet<>();
       
   653 
       
   654             StuckNode(DeferredAttrNode data) {
       
   655                 super(data);
       
   656             }
       
   657 
       
   658             @Override
       
   659             public DependencyKind[] getSupportedDependencyKinds() {
       
   660                 return new DependencyKind[] { Infer.DependencyKind.STUCK };
       
   661             }
       
   662 
       
   663             @Override
       
   664             public Collection<? extends StuckNode> getDependenciesByKind(DependencyKind dk) {
       
   665                 if (dk == Infer.DependencyKind.STUCK) {
       
   666                     return deps;
       
   667                 } else {
       
   668                     throw new IllegalStateException();
       
   669                 }
       
   670             }
       
   671 
       
   672             @Override
       
   673             public Iterable<? extends StuckNode> getAllDependencies() {
       
   674                 return deps;
       
   675             }
   636         }
   676         }
   637     }
   677     }
   638 
   678 
   639     /**
   679     /**
   640      * Class representing a deferred attribution node. It keeps track of
   680      * Class representing a deferred attribution node. It keeps track of