diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index d9e5cfdd2..310d24a36 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -106,6 +106,25 @@ public class ASTToTargetAST { return generics.stream().anyMatch(generic -> generic.getLeft().equals(name)); } + boolean containsRelation(Set> result, PairTPHsmallerTPH pair) { + // Check if both the right and the left are already part of a relation + var containsLeft = false; + for (var pair2 : result) { + if (pair2.getLeft().equals(pair.left)) { + containsLeft = true; + break; + } + } + var containsRight = false; + for (var pair2 : result) { + if (pair2.getRight().equals(pair.right)) { + containsRight = true; + break; + } + } + return containsLeft && containsRight; + } + // Family of generated Generics Set> generics(ClassOrInterface owner, Method method) { if (computedGenericsOfMethods.containsKey(method)) @@ -119,6 +138,7 @@ public class ASTToTargetAST { HashSet typeVariables = new HashSet<>(); HashSet typeVariablesOfFields = new HashSet<>(); + HashSet allTypeVariables = new HashSet<>(); for (var field : owner.getFieldDecl()) { findTypeVariables(field.getType(), typeVariablesOfFields); @@ -136,6 +156,17 @@ public class ASTToTargetAST { } }); + // Type variables with bounds that are also type variables of the method + for (var typeVariable : new HashSet<>(typeVariables)) { + for (var pair : simplifiedConstraints) { + if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) { + result.add(new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); + typeVariables.add(pair.right); + } + } + } + + var visitedMethods = new HashSet(); method.block.accept(new TracingStatementVisitor() { @Override public void visit(MethodCall methodCall) { @@ -148,6 +179,9 @@ public class ASTToTargetAST { ).findFirst(); if (optMethod.isEmpty()) return; var method = optMethod.get(); + if (visitedMethods.contains(method)) return; + visitedMethods.add(method); + var generics = generics(owner, method); Set> all = new HashSet<>(generics); @@ -189,7 +223,11 @@ public class ASTToTargetAST { if (!(pair2.right.equals(tph2) && pair2.left.equals(type))) continue; - newPairs.add(new PairTPHsmallerTPH(tph, tph2)); + var newPair = new PairTPHsmallerTPH(tph, tph2); + newPairs.add(newPair); + + if (!containsRelation(result, newPair)) + result.add(newPair); continue outer; } } @@ -202,10 +240,10 @@ public class ASTToTargetAST { } }); - // Type variables with bounds that are also type variables of the method or type variables of fields + // Type variables with bounds that are also type variables of fields for (var typeVariable : new HashSet<>(typeVariables)) { for (var pair : simplifiedConstraints) { - if (pair.left.equals(typeVariable) && (typeVariables.contains(pair.right) || typeVariablesOfFields.contains(pair.right))) { + if (pair.left.equals(typeVariable) && typeVariablesOfFields.contains(pair.right)) { result.add(new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); typeVariables.add(pair.right); } diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 279e36254..86c4e8de6 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -11,6 +11,7 @@ import de.dhbwstuttgart.target.tree.MethodParameter; import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.TargetFunNType; import de.dhbwstuttgart.target.tree.type.TargetRefType; +import de.dhbwstuttgart.target.tree.type.TargetSpecializedType; import de.dhbwstuttgart.target.tree.type.TargetType; import java.util.List; @@ -135,12 +136,12 @@ public class StatementToTargetExpression implements StatementVisitor { var receiverType = converter.convert(methodCall.receiver.getType()); var isFunNType = receiverType instanceof TargetFunNType; var returnType = converter.convert(methodCall.getType()); - var receiverName = new JavaClassName(((TargetRefType) converter.convert(methodCall.receiver.getType())).name()); + var receiverName = new JavaClassName(((TargetSpecializedType) converter.convert(methodCall.receiver.getType())).name()); var argList = methodCall.arglist.getArguments().stream().map(expr -> converter.convert(expr.getType())).toList(); java.lang.reflect.Method foundMethod = null; - if (converter.sourceFile.imports.contains(receiverName)) { + if (converter.sourceFile != null && converter.sourceFile.imports.contains(receiverName)) { try { var clazz = converter.classLoader.loadClass(receiverName.toString()); diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java index 531aae1c3..9012a868b 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetFunNType.java @@ -8,6 +8,11 @@ public record TargetFunNType(int N, List params) implements TargetSp return "Fun" + N + "$$"; } + @Override + public String name() { + return getName(); + } + @Override public String toSignature() { return "L" + getName() + ";"; diff --git a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java index c1f4dfc9d..8bece1832 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/type/TargetSpecializedType.java @@ -18,4 +18,6 @@ public sealed interface TargetSpecializedType extends TargetType permits TargetF ret += ";"; return ret; } + + String name(); } diff --git a/src/test/java/targetast/TestComplete.java b/src/test/java/targetast/TestComplete.java index f75520dff..f12711088 100644 --- a/src/test/java/targetast/TestComplete.java +++ b/src/test/java/targetast/TestComplete.java @@ -359,6 +359,13 @@ public class TestComplete { var m = tph5.getDeclaredMethod("m", Object.class, Object.class); } + @Test + public void tph7Test() throws Exception { + var classFiles = generateClassFiles("Tph7.jav", new ByteArrayClassLoader()); + var tph5 = classFiles.get("Tph7"); + var instance = tph5.getDeclaredConstructor().newInstance(); + } + @Test public void typedIdTest() throws Exception { var classFiles = generateClassFiles("TypedID.jav", new ByteArrayClassLoader()); diff --git a/src/test/resources/bytecode/javFiles/Tph7.jav b/src/test/resources/bytecode/javFiles/Tph7.jav new file mode 100644 index 000000000..e62e22881 --- /dev/null +++ b/src/test/resources/bytecode/javFiles/Tph7.jav @@ -0,0 +1,10 @@ +public class Tph7 { + m(a,b) { + var c = m2(b); + return m2(b); + } + + m2(b) { + return b; + } +} \ No newline at end of file