From b22b4ec588d3ba343584ceee357d6ae33a567239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bendeg=C3=BAz=20Nagy?= Date: Thu, 3 Aug 2017 13:38:56 +0200 Subject: [PATCH] Java, typeres: compute variable's dependencies in type inference resolution step --- .../typeinference/BoundOrConstraint.java | 33 +++++++++ .../typeinference/TypeInferenceResolver.java | 73 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/BoundOrConstraint.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/BoundOrConstraint.java index 376536b26e..b5a2df094d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/BoundOrConstraint.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/BoundOrConstraint.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.java.typeresolution.typeinference; import java.util.List; +import java.util.Set; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -134,4 +135,36 @@ public abstract class BoundOrConstraint { } public abstract List reduce(); + + public void addVariablesToSet(Set variables) { + if(leftTypeVariable != null) { + variables.add(leftTypeVariable); + } + + if(rightTypeVariable != null) { + variables.add(rightTypeVariable); + } + } + + /** + * @return true, if the left-hand side mentions variables + */ + public boolean leftHasMentionedVariable() { + return leftTypeVariable != null; + } + + /** + * @return true, if the right-hand side mentions variales + */ + public boolean rightHasMentionedVariable() { + return rightTypeVariable != null; + } + + public Variable getLeftMentionedVariable() { + return leftTypeVariable; + } + + public Variable getRightMentionedVariable() { + return rightTypeVariable; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/TypeInferenceResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/TypeInferenceResolver.java index 2cce89db6f..081f00f329 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/TypeInferenceResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typeinference/TypeInferenceResolver.java @@ -8,7 +8,11 @@ import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.Inferen import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.InferenceRuleType.SUBTYPE; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; public final class TypeInferenceResolver { @@ -17,6 +21,75 @@ public final class TypeInferenceResolver { } + public static Map> getVariableDependencies(List bounds) { + Set variables = getMentionedVariables(bounds); + Map> dependencies = new HashMap<>(); + + for (Variable mentionedVariable : variables) { + Set set = new HashSet<>(); + // An inference variable α depends on the resolution of itself. + set.add(mentionedVariable); + + dependencies.put(mentionedVariable, set); + } + + // produce initial dependencies + for (Bound bound : bounds) { + // Given a bound of one of the following forms, where T is either an inference variable β or a type that + // mentions β: + + if (bound.leftVariable() != null && bound.rightHasMentionedVariable()) { + if (bound.ruleType == EQUALITY || bound.ruleType() == SUBTYPE) { + // α = T + // α <: T + dependencies.get(bound.leftVariable()).add(bound.getRightMentionedVariable()); + } + } else if (bound.leftHasMentionedVariable() && bound.rightVariable() != null) { + if (bound.ruleType == EQUALITY || bound.ruleType() == SUBTYPE) { + // T = α + // T <: α + dependencies.get(bound.getLeftMentionedVariable()).add(bound.rightVariable()); + } + } + + // If α appears on the left-hand side of another bound of the form G<..., α, ...> = capture(G<...>), then + // β depends on the resolution of α. Otherwise, α depends on the resolution of β. TODO + + // An inference variable α appearing on the left-hand side of a bound of the form G<..., α, ...> = + // capture(G<...>) depends on the resolution of every other inference variable mentioned in this bound + // (on both sides of the = sign). TODO + } + + + // An inference variable α depends on the resolution of an inference variable β if there exists an inference + // variable γ such that α depends on the resolution of γ and γ depends on the resolution of β. + + for(int i = 0; i < variables.size(); ++i) { // do this n times, where n is the count of variables + for (Map.Entry> entry : dependencies.entrySet()) { + // take the Variable's dependency list + for(Variable variable : entry.getValue()) { + // add those variable's dependencies + entry.getValue().addAll(dependencies.get(variable)); + } + } + } + + return dependencies; + } + + /** + * @return a set of variables mentioned by the bounds + */ + public static Set getMentionedVariables(List bounds) { + Set result = new HashSet<>(); + + for (Bound bound : bounds) { + bound.addVariablesToSet(result); + } + + return result; + } + /** * https://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html#jls-18.3 */