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 |