Iteration

This commit is contained in:
Daniel Holle 2023-06-15 14:13:15 +02:00
parent bb0ee7d517
commit 9eb0dd1cf5
2 changed files with 54 additions and 24 deletions

View File

@ -23,7 +23,7 @@ public abstract class GenerateGenerics {
private final ASTToTargetAST astToTargetAST; private final ASTToTargetAST astToTargetAST;
public class TPH { public class TPH {
final TypePlaceholder wrap; private final TypePlaceholder wrap;
TPH(TypePlaceholder wrap) { TPH(TypePlaceholder wrap) {
this.wrap = wrap; this.wrap = wrap;
@ -212,6 +212,7 @@ public abstract class GenerateGenerics {
equality.put(entry.getKey(), to); equality.put(entry.getKey(), to);
} }
} }
to.setVariance(from.getVariance());
equality.put(from, to); equality.put(from, to);
referenced.remove(new TPH(from)); referenced.remove(new TPH(from));
referenced.add(new TPH(to)); referenced.add(new TPH(to));
@ -292,8 +293,10 @@ public abstract class GenerateGenerics {
if (expressionReceiver.expr instanceof This) { if (expressionReceiver.expr instanceof This) {
var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.getArgumentList()); var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.getArgumentList());
if (optMethod.isEmpty()) return; if (optMethod.isEmpty()) return;
var method = optMethod.get(); var method2 = optMethod.get();
var generics = generics(owner, method); System.out.println("In: " + method.getName() + " Method: " + method2.getName());
System.out.println(simplifiedConstraints);
var generics = family(owner, method2);
// transitive and // transitive and
var all = transitiveClosure(generics); var all = transitiveClosure(generics);
@ -325,6 +328,7 @@ public abstract class GenerateGenerics {
if (!T1s.contains(R1) || !T2s.contains(R2)) continue; if (!T1s.contains(R1) || !T2s.contains(R2)) continue;
var newPair = new PairLT(R1, R2); var newPair = new PairLT(R1, R2);
System.out.println("New pair: " + newPair);
newPairs.add(newPair); newPairs.add(newPair);
if (!containsRelation(result, newPair)) if (!containsRelation(result, newPair))
@ -501,10 +505,10 @@ public abstract class GenerateGenerics {
abstract void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> javaTypeVariablesOfClass); abstract void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> javaTypeVariablesOfClass);
Set<Pair> family(ClassOrInterface owner, Method method) { Set<Pair> family(ClassOrInterface owner, Method method) {
Set<Pair> result = new HashSet<>();
if (familyOfMethods.containsKey(method)) if (familyOfMethods.containsKey(method))
return familyOfMethods.get(method); return familyOfMethods.get(method);
var result = new HashSet<Pair>();
familyOfMethods.put(method, result); familyOfMethods.put(method, result);
var classGenerics = generics(owner); var classGenerics = generics(owner);
@ -524,19 +528,22 @@ public abstract class GenerateGenerics {
} }
Set<Pair> generics(ClassOrInterface owner, Method method) { Set<Pair> generics(ClassOrInterface owner, Method method) {
if (computedGenericsOfMethods.containsKey(method)) if (computedGenericsOfMethods.containsKey(method)) {
return computedGenericsOfMethods.get(method); var cached = computedGenericsOfMethods.get(method);
System.out.println("Cached " + method.getName() + ": " + cached);
return cached;
}
var result = new HashSet<Pair>();
computedGenericsOfMethods.put(method, result);
var classGenerics = generics(owner); var classGenerics = generics(owner);
HashSet<TPH> typeVariablesOfClass = new HashSet<>(); HashSet<TPH> typeVariablesOfClass = new HashSet<>();
for (var pair : classGenerics) { for (var pair : classGenerics) {
typeVariablesOfClass.add(pair.left); typeVariablesOfClass.add(pair.left);
} }
var result = new HashSet<>(family(owner, method)); result.addAll(family(owner, method));
computedGenericsOfMethods.put(method, result);
var referenced = new HashSet<TPH>(); var referenced = new HashSet<TPH>();
@ -552,7 +559,7 @@ public abstract class GenerateGenerics {
generics(owner, method, result, referenced); generics(owner, method, result, referenced);
usedTPHsOfMethods.put(method, usedTphs); usedTPHsOfMethods.put(method, usedTphs);
addMissingObjectBounds(result, classGenerics, usedTphs); normalize(result, classGenerics, usedTphs);
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result); System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
return result; return result;
@ -631,16 +638,18 @@ public abstract class GenerateGenerics {
findTphs(field.getType(), referencedByClass); findTphs(field.getType(), referencedByClass);
} }
addMissingObjectBounds(javaResult, null, referencedByClass); normalize(javaResult, null, referencedByClass);
System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult); System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult);
return javaResult; return javaResult;
} }
void addMissingObjectBounds(Set<Pair> result, Set<Pair> classGenerics, Set<TPH> usedTphs) { void normalize(Set<Pair> result, Set<Pair> classGenerics, Set<TPH> usedTphs) {
outer: outer:
for (var tph : usedTphs) { for (var tph : usedTphs) {
for (var p1 : new HashSet<>(result)) { for (var p1 : new HashSet<>(result)) {
if (p1 instanceof PairLT ptph && ptph.left.equals(ptph.right))
result.remove(p1); // TODO This is a bit strange
if (p1.left.equals(tph)) continue outer; if (p1.left.equals(tph)) continue outer;
} }
@ -683,12 +692,13 @@ public abstract class GenerateGenerics {
} }
if (variance == 1) continue; if (variance == 1) continue;
var start = chain.get(0); var start = chain.get(0);
var prev = start; var prev = start;
for (var i = 1; i < index; i++) { for (var i = 1; i < index; i++) {
var cur = chain.get(i); var cur = chain.get(i);
if (!referenced.contains(cur)) continue; if (!referenced.contains(cur)) continue;
addToEquality(cur.wrap, start.resolve(), referenced); addToEquality(cur.resolve(), start.resolve(), referenced);
TPH finalPrev = prev; TPH finalPrev = prev;
input.removeIf(p -> p.equals(new PairLT(finalPrev, cur))); input.removeIf(p -> p.equals(new PairLT(finalPrev, cur)));
for (var pair2 : new HashSet<>(input)) { for (var pair2 : new HashSet<>(input)) {
@ -722,13 +732,32 @@ public abstract class GenerateGenerics {
for (var field : classOrInterface.getFieldDecl()) { for (var field : classOrInterface.getFieldDecl()) {
findTphs(field.getType(), referenced); findTphs(field.getType(), referenced);
} }
doIterationForMethods(classOrInterface);
for (var method : classOrInterface.getMethods()) { for (var method : classOrInterface.getMethods()) {
generics(classOrInterface, method);
referenced.addAll(usedTPHsOfMethods.get(method)); referenced.addAll(usedTPHsOfMethods.get(method));
} }
eliminateInnerTypeVariables(referenced, input); eliminateInnerTypeVariables(referenced, input);
} }
void doIterationForMethods(ClassOrInterface classOrInterface) {
familyOfMethods.clear();
var oldFamily = new HashMap<Method, Set<Pair>>();
do {
oldFamily.clear();
oldFamily.putAll(familyOfMethods);
familyOfMethods.clear();
for (var method : classOrInterface.getMethods()) {
family(classOrInterface, method);
}
System.out.println(familyOfMethods);
} while(!oldFamily.equals(familyOfMethods));
for (var method : classOrInterface.getMethods()) {
generics(classOrInterface, method);
}
}
private void findChain(Set<TPH> referenced, Set<Pair> input, Set<Pair> output, TPH start, TPH end, Set<TPH> chain) { private void findChain(Set<TPH> referenced, Set<Pair> input, Set<Pair> output, TPH start, TPH end, Set<TPH> chain) {
if (referenced.contains(end)) { if (referenced.contains(end)) {
var pair = new PairLT(start, end); var pair = new PairLT(start, end);
@ -793,7 +822,7 @@ public abstract class GenerateGenerics {
var right = cycle.get(i + 1); var right = cycle.get(i + 1);
var pair = new PairLT(left, right); var pair = new PairLT(left, right);
input.remove(pair); input.remove(pair);
addToEquality(left.wrap, newTph, referenced); addToEquality(left.resolve(), newTph, referenced);
} }
} }
} }
@ -806,9 +835,10 @@ public abstract class GenerateGenerics {
var left = constraint.left; var left = constraint.left;
Set<PairLT> infima = new HashSet<>(); Set<PairLT> infima = new HashSet<>();
for (var pair : input) { for (var pair : input) {
if (pair instanceof PairLT stph) if (pair instanceof PairLT stph) {
if (pair.left.wrap.equals(constraint.left.wrap)) if (pair.left.equals(constraint.left))
infima.add(stph); infima.add(stph);
}
} }
if (infima.size() > 1) { if (infima.size() > 1) {
foundInfima = true; foundInfima = true;
@ -826,19 +856,19 @@ public abstract class GenerateGenerics {
addToPairs(input, new PairLT(left, new TPH(newTph))); addToPairs(input, new PairLT(left, new TPH(newTph)));
input.removeAll(infima); input.removeAll(infima);
for (var infimum : infima) { for (var infimum : infima) {
addToEquality(infimum.right.wrap, newTph, referenced); addToEquality(infimum.right.resolve(), newTph, referenced);
new HashSet<>(input).forEach(pair -> { new HashSet<>(input).forEach(pair -> {
if (pair.left.wrap.equals(infimum.right.wrap)) { if (pair.left.equals(infimum.right)) {
input.remove(pair); input.remove(pair);
if (pair instanceof PairLT stph) { if (pair instanceof PairLT stph) {
if (!newTph.equals(stph.right.wrap)) if (!newTph.equals(stph.right.resolve()))
addToPairs(input, new PairLT(new TPH(newTph), stph.right)); addToPairs(input, new PairLT(new TPH(newTph), stph.right));
} else if (pair instanceof PairEQ rtph) { } else if (pair instanceof PairEQ rtph) {
addToPairs(input, new PairEQ(new TPH(newTph), rtph.right)); addToPairs(input, new PairEQ(new TPH(newTph), rtph.right));
} }
} else if (pair instanceof PairLT stph && stph.right.wrap.equals(infimum.right.wrap)) { } else if (pair instanceof PairLT stph && stph.right.equals(infimum.right)) {
input.remove(pair); input.remove(pair);
if (!newTph.equals(stph.left.wrap)) if (!newTph.equals(stph.left.resolve()))
addToPairs(input, new PairLT(stph.left, new TPH(newTph))); addToPairs(input, new PairLT(stph.left, new TPH(newTph)));
} }
}); });

View File

@ -15,7 +15,7 @@ final class JavaGenerics extends GenerateGenerics {
void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> referenced) { void generics(ClassOrInterface owner, Method method, Set<Pair> result, Set<TPH> referenced) {
eliminateCycles(result, referenced); eliminateCycles(result, referenced);
eliminateInfima(result, referenced); eliminateInfima(result, referenced);
//equalizeTypeVariables(result, referenced); equalizeTypeVariables(result, referenced);
eliminateInnerTypeVariables(referenced, result); eliminateInnerTypeVariables(referenced, result);
} }