From 6079e96efa8a37441940a2dbd748b2bef32a1938 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Tue, 27 Jun 2023 15:00:43 +0200 Subject: [PATCH] Test more thoroughly and add a new infimum deletion strategy --- .../target/generate/BoundsList.java | 12 +++- .../target/generate/GenerateGenerics.java | 44 ++++++++++++++ .../target/generate/GenericsResult.java | 7 ++- .../target/generate/JavaGenerics.java | 1 + src/test/java/targetast/TestGenerics.java | 58 +++++++++++++------ 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/target/generate/BoundsList.java b/src/main/java/de/dhbwstuttgart/target/generate/BoundsList.java index b92394d6..5a1f797d 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/BoundsList.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/BoundsList.java @@ -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 { private final List bounds; + public final RefTypeOrTPHOrWildcardOrGeneric base; - public BoundsList(List bounds) { + public BoundsList(RefTypeOrTPHOrWildcardOrGeneric base, List bounds) { + this.base = base; this.bounds = bounds; } + + public BoundsList(List bounds) { + this(null, bounds); + } + public BoundsList(Bound... bounds) { - this.bounds = List.of(bounds); + this(null, List.of(bounds)); } @Override diff --git a/src/main/java/de/dhbwstuttgart/target/generate/GenerateGenerics.java b/src/main/java/de/dhbwstuttgart/target/generate/GenerateGenerics.java index 53143235..9c4b1439 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/GenerateGenerics.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/GenerateGenerics.java @@ -826,6 +826,50 @@ public abstract class GenerateGenerics { } } + TPH findConnectionToReturnType(Set returnTypes, Set input, Set 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 input, Set referenced) { + var foundInfima = false; + do { + foundInfima = false; + for (var constraint : new HashSet<>(input)) { + var left = constraint.left; + Set 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 input, Set referenced) { var foundInfima = false; do { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/GenericsResult.java b/src/main/java/de/dhbwstuttgart/target/generate/GenericsResult.java index a30fdba9..44476211 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/GenericsResult.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/GenericsResult.java @@ -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) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/JavaGenerics.java b/src/main/java/de/dhbwstuttgart/target/generate/JavaGenerics.java index 16be617e..abe779ae 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/JavaGenerics.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/JavaGenerics.java @@ -14,6 +14,7 @@ final class JavaGenerics extends GenerateGenerics { @Override void generics(ClassOrInterface owner, Method method, Set result, Set referenced) { eliminateCycles(result, referenced); + eliminateInfimaConnectedToReturnType(method, result, referenced); eliminateInfima(result, referenced); equalizeTypeVariables(result, referenced); eliminateInnerTypeVariables(referenced, result); diff --git a/src/test/java/targetast/TestGenerics.java b/src/test/java/targetast/TestGenerics.java index 5f74ae3a..094ec4f0 100644 --- a/src/test/java/targetast/TestGenerics.java +++ b/src/test/java/targetast/TestGenerics.java @@ -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); }