Test more thoroughly and add a new infimum deletion strategy

This commit is contained in:
Daniel Holle 2023-06-27 15:00:43 +02:00
parent f5aa90bdbd
commit 6079e96efa
5 changed files with 100 additions and 22 deletions

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import java.util.AbstractList;
@ -7,12 +8,19 @@ import java.util.List;
public class BoundsList extends AbstractList<Bound> {
private final List<Bound> bounds;
public final RefTypeOrTPHOrWildcardOrGeneric base;
public BoundsList(List<Bound> bounds) {
public BoundsList(RefTypeOrTPHOrWildcardOrGeneric base, List<Bound> bounds) {
this.base = base;
this.bounds = bounds;
}
public BoundsList(List<Bound> bounds) {
this(null, bounds);
}
public BoundsList(Bound... bounds) {
this.bounds = List.of(bounds);
this(null, List.of(bounds));
}
@Override

View File

@ -826,6 +826,50 @@ public abstract class GenerateGenerics {
}
}
TPH findConnectionToReturnType(Set<TPH> returnTypes, Set<Pair> input, Set<TPH> visited, TPH tph) {
if (returnTypes.contains(tph)) {
return tph;
} else {
for (var pair : input) if (pair instanceof PairLT ptph) {
if (ptph.left.equals(tph) && !visited.contains(ptph.right)) {
visited.add(ptph.right);
var result = findConnectionToReturnType(returnTypes, input, visited, ptph.right);
if (result != null) return result;
}
}
}
return null;
}
void eliminateInfimaConnectedToReturnType(Method method, Set<Pair> input, Set<TPH> referenced) {
var foundInfima = false;
do {
foundInfima = false;
for (var constraint : new HashSet<>(input)) {
var left = constraint.left;
Set<PairLT> infima = new HashSet<>();
for (var pair : input) {
if (pair instanceof PairLT stph) {
if (pair.left.equals(constraint.left))
infima.add(stph);
}
}
if (infima.size() > 1) {
for (var pair : infima) {
var returnTypes = findTypeVariables(method.getReturnType());
var returnType = findConnectionToReturnType(returnTypes, input, new HashSet<>(), pair.left);
if (returnType != null && !returnType.equals(pair.left)) {
System.out.println("Equals now: " + pair.left.resolve() + " " + returnType.resolve());
addToEquality(pair.left.resolve(), returnType.resolve(), referenced);
foundInfima = true;
}
}
}
}
} while (foundInfima);
input.removeIf((i) -> !(i instanceof PairLT lt) || lt.left.equals(lt.right));
}
void eliminateInfima(Set<Pair> input, Set<TPH> referenced) {
var foundInfima = false;
do {

View File

@ -31,7 +31,8 @@ public class GenericsResult {
}
public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz, Method method) {
type = resolve(type);
var resolvedType = resolve(type);
type = resolvedType;
if (type instanceof TypePlaceholder) {
var methodGenerics = get(method);
var classGenerics = get(clazz);
@ -58,9 +59,9 @@ public class GenericsResult {
}
bound.ifPresent(result::add);
} while (bound.isPresent());
return new BoundsList(result);
return new BoundsList(resolvedType, result);
}
return new BoundsList(List.of());
return new BoundsList(resolvedType, List.of());
}
public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) {

View File

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

View File

@ -37,6 +37,15 @@ public class TestGenerics {
}
}
private static void assertStrictlyEquals(BoundsList a, BoundsList b) {
assertEquals(a.base, b.base);
assertEquals(a, b);
}
private static void assertStrictlyNotEquals(BoundsList a, BoundsList b) {
assertNotEquals(a.base, b.base);
}
private static Result computeGenerics(String filename) throws IOException, ClassNotFoundException {
var file = Path.of(rootDirectory + filename).toFile();
var compiler = new JavaTXCompiler(List.of(file), List.of(file.getParentFile()));
@ -62,7 +71,7 @@ public class TestGenerics {
var ECK1 = generics.getBounds(otherMethod.getParameterList().getParameterAt(0).getType(), result.clazz, anyMethod);
var ECK2 = generics.getBounds(otherMethod.getReturnType(), result.clazz, anyMethod);
var ECKChain = new BoundsList(onClass(OBJECT));
assertEquals(ECK1, ECK2);
assertStrictlyEquals(ECK1, ECK2);
assertEquals(ECK2, generics.getBounds(b.getType(), result.clazz));
var M = generics.getBounds(a.getType(), result.clazz);
@ -92,21 +101,36 @@ public class TestGenerics {
var generics = result.genericsResults.get(0);
assertEquals(0, generics.get(result.clazz).size());
assertEquals(1, generics.get(m).size());
assertEquals(2, generics.get(main).size());
assertEquals(3, generics.get(m).size());
assertEquals(3, generics.get(main).size());
var N = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
var N2 = generics.getBounds(m.getReturnType(), result.clazz, m);
{
var AJ = generics.getBounds(m.getParameterList().getParameterAt(0).getType(), result.clazz, m);
var AK = generics.getBounds(m.getParameterList().getParameterAt(1).getType(), result.clazz, m);
var KWU = generics.getBounds(((RefType) generics.resolve(m.getReturnType())).getParaList().get(0), result.clazz, m);
var AK2 = generics.getBounds(((RefType) generics.resolve(m.getReturnType())).getParaList().get(1), result.clazz, m);
var NChain = new BoundsList(onMethod(OBJECT));
assertEquals(N, N2);
assertEquals(N2, NChain);
assertStrictlyEquals(AK, AK2);
assertStrictlyNotEquals(AJ, KWU);
var NChain = new BoundsList(onMethod(OBJECT));
assertEquals(AJ, NChain);
assertEquals(AK, NChain);
assertEquals(KWU, NChain);
}
var R = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
assertEquals(R, NChain);
{
var O = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
var P = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
var KWQ = generics.getBounds(((RefType) generics.resolve(main.getReturnType())).getParaList().get(1), result.clazz, main);
var O2 = generics.getBounds(((RefType) generics.resolve(main.getReturnType())).getParaList().get(0), result.clazz, main);
var Q2 = generics.getBounds(main.getReturnType(), result.clazz, main);
assertEquals(Q2, NChain);
assertStrictlyEquals(O, O2);
assertStrictlyNotEquals(P, KWQ);
var NChain = new BoundsList(onMethod(OBJECT));
assertEquals(O, NChain);
assertEquals(P, NChain);
assertEquals(KWQ, NChain);
}
}
@Test
@ -307,14 +331,14 @@ public class TestGenerics {
var generics = result.genericsResults.get(0);
var O = generics.getBounds(id.getReturnType(), result.clazz, id);
var O2 = generics.getBounds(id.getParameterList().getParameterAt(0).getType(), result.clazz, id);
assertEquals(O, O2);
assertStrictlyEquals(O, O2);
assertEquals(O2, new BoundsList(onMethod(OBJECT)));
// TODO Maybe test in other ways if the parameter generics equals the return generics
var S = generics.getBounds(main.getReturnType(), result.clazz, main);
var S2 = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
var T = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
assertEquals(S, S2);
var S2 = generics.getBounds(main.getParameterList().getParameterAt(1).getType(), result.clazz, main);
var T = generics.getBounds(main.getParameterList().getParameterAt(0).getType(), result.clazz, main);
assertStrictlyEquals(S, S2);
assertEquals(S2, new BoundsList(onMethod(OBJECT)));
assertEquals(T, new BoundsList(onMethod(OBJECT)));
}
@ -355,7 +379,7 @@ public class TestGenerics {
var par2 = generics.resolve(main.getParameterList().getParameterAt(0).getType());
var ACK2 = generics.getBounds(((RefType) par2).getParaList().get(0), result.clazz, add);
var V = generics.getBounds(add.getParameterList().getParameterAt(1).getType(), result.clazz, add);
assertEquals(ACK2, ACK);
assertStrictlyEquals(ACK2, ACK);
assertEquals(V, O);
}