Complexity reduction when choosing the best inference leaf to be solved

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Oct 18 18:08:30 UTC 2017


For the records, the fix I'm working on is slightly more general than 
the one provided here - I think we have to take transitivity into 
account, it's not enough to look at the bounds of a given input variable 
and see if it contains any of the output vars. Consider this case:

alpha <: List<beta>
beta <: List<gamma>
gamma <: String

In this case you get three inference nodes, one for each inference var - 
and you have

Node(alpha) depends on Node(beta) depends on Node(gamma)

so, technically speaking, gamma can influence alpha, but gamma does not 
appear among alpha's bounds, even after incorporation.

I think in certain cases (like in the one described in the bug) 
incorporation copies some of the bounds from one var to another and that 
gives you the illusion of transitivity, but that doesn't always happen. 
See slightly tweaked example at the end of this email

So, unless I'm missing something, I think that for the can-influence 
relation we should piggy back to the inference graph dependencies.

Maurizio


class T8178150_transitive {

     public static void test(List<List<String>> testList, Logger LOGGER) {
         testList.forEach(T8178150.bind(cast(LOGGER::info), iterable -> 
""));
     }

     private static <T1, T2, U extends T2> TestProcedure<T1, T2> 
bind(Consumer<U> delegate, Function<? super T1, T2> function) {
         return null;
     }

     private static <C> C cast(C consumer) {
         return consumer;
     }

     private static final class TestProcedure<X1, X2> implements 
Consumer<X1> {
         @Override
         public void accept(final X1 t1) { }
     }
}


On 15/10/17 12:48, B. Blaser wrote:
> On 13 October 2017 at 21:59, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> wrote:
>> Hi,
>> I think the affected area is close to this:
>>
>> https://bugs.openjdk.java.net/browse/JDK-8178150
> Quoting from your JBS comment, here are the two stuck expressions:
>
> * LOGGER::info - input vars = { C }, output vars = { }
> * iterable -> "" - input vars = { T1 }, output vars = { T2 }
>
> The problem here is that the input var 'C' is influenced by the output
> var 'T2' via the bound set of 'C' which doesn't seem to be currently
> implemented in javac.
>
> I wrote a fix, here under, that adds the corresponding dependencies
> before computing the acyclic stuck graph in
> 'DeferredAttr.pickDeferredNode()'.
>
> I tried this fix using the "lazy" leaf heuristic (the last one I
> suggested) that picks a node to be solved in O(log(n)).
>
> Note that this fix shouldn't interfere with any leaf solving heuristic
> so that it should be possible to choose the best one between:
> * the current one (with optimization?) that chooses the smallest subtree
> * the "lazy" one that minimizes the effort to choose a leaf in O(log(n))
> * the "conservative" one (from Vicente) that picks the nearest leaf
> * or any other heuristic like the "aggressive" one
>
> Does this fix look reasonable to you?
>
> Cheers,
> Bernard
>
>
> diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
> b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
> --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
> +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
> @@ -29,6 +29,8 @@
>   import com.sun.source.tree.NewClassTree;
>   import com.sun.tools.javac.code.*;
>   import com.sun.tools.javac.code.Type.StructuralTypeMapping;
> +import com.sun.tools.javac.code.Type.UndetVar;
> +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
>   import com.sun.tools.javac.code.Types.TypeMapping;
>   import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
>   import com.sun.tools.javac.comp.Resolve.ResolveError;
> @@ -668,10 +670,15 @@
>               //the intersection between A's input variable and B's
> output variable is non-empty.
>               for (StuckNode sn1 : nodes) {
>                   for (Type t : sn1.data.deferredStuckPolicy.stuckVars()) {
> +                    UndetVar uv = (UndetVar)inferenceContext.asUndetVar(t);
>                       for (StuckNode sn2 : nodes) {
> -                        if (sn1 != sn2 &&
> sn2.data.deferredStuckPolicy.depVars().contains(t)) {
> +                        if (sn1 == sn2) continue;
> +
> +                        Set<Type> depVars =
> sn2.data.deferredStuckPolicy.depVars();
> +
> +                        if (depVars.contains(t) || Type.containsAny(
> +
> uv.getBounds(InferenceBound.values()), List.from(depVars)))
>                               sn1.deps.add(sn2);
> -                        }
>                       }
>                   }
>               }
>
>
>> for which I have a fix in the work which I will submit for review soon.
>>
>> After that fix is in, we can consider deeper refactorings in the area.
>>
>> Cheers
>> Maurizio



More information about the compiler-dev mailing list