From ec92b5d5e137a7e30c46088a9cdf38bd5df4dc25 Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Thu, 13 Jun 2024 17:23:19 +0200 Subject: [PATCH] Work on Bug #332 --- resources/bytecode/javFiles/Bug332.jav | 15 ++ .../target/generate/ASTToTargetAST.java | 144 +++++++++--------- .../generate/StatementToTargetExpression.java | 5 + src/test/java/TestComplete.java | 7 + 4 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 resources/bytecode/javFiles/Bug332.jav diff --git a/resources/bytecode/javFiles/Bug332.jav b/resources/bytecode/javFiles/Bug332.jav new file mode 100644 index 00000000..240dba0c --- /dev/null +++ b/resources/bytecode/javFiles/Bug332.jav @@ -0,0 +1,15 @@ +import java.lang.Object; + +interface Visitor { + public void visit(Object obj); + public void visit(ClassA a); +} + +class ClassA { + void accept(Visitor v) { + v.visit(this); + } +} + +public class Bug332 { +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 3280f295..d6e73ba7 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -5,7 +5,6 @@ import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader; -import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.NullToken; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.*; @@ -18,23 +17,25 @@ import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.typeinference.result.*; -import javax.sql.rowset.RowSetWarning; -import java.lang.annotation.Target; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; /** * @author dholle */ public class ASTToTargetAST { + record SignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) {}; + record SignaturePairTarget(TargetType signature, TargetType parameter) {} + public static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change protected List all; public Generics generics; final Map> userDefinedGenerics = new HashMap<>(); + final Map> tphsInMethods = new HashMap<>(); + private Method currentMethod; public final JavaTXCompiler compiler; @@ -78,6 +79,12 @@ public class ASTToTargetAST { this.generics = all.get(0); } + public void addSignaturePair(TypePlaceholder signature, RefTypeOrTPHOrWildcardOrGeneric parameter) { + var set = tphsInMethods.getOrDefault(currentMethod, new HashSet<>()); + set.add(new SignaturePair(signature, parameter)); + tphsInMethods.put(currentMethod, set); + } + Optional findMethod(ClassOrInterface owner, String name, List argumentList) { Optional method = Optional.empty(); while (method.isEmpty()) { @@ -131,6 +138,40 @@ public class ASTToTargetAST { return ret; } + public List> groupOverloads(ClassOrInterface input, List methods) { + var res = new ArrayList>(); + for (var method : methods) { + // Convert all methods + var methodsWithTphs = convert(input, method); + // Then check for methods with the same signature + var mapOfSignatures = new HashMap>(); + for (var m : methodsWithTphs) { + var methodsWithSameSignature = mapOfSignatures.getOrDefault(m.method.signature(), new ArrayList<>()); + methodsWithSameSignature.add(m); + mapOfSignatures.put(m.method.signature(), methodsWithSameSignature); + } + + var resMethods = new HashSet(); + for (var methodsWithSignature : mapOfSignatures.values()) { + outer: for (var m1 : methodsWithSignature) { + for (var m2 : methodsWithSignature) { + for (var i = 0; i < m1.args.size(); i++) { + var arg1 = m1.args.get(i); + var arg2 = m2.args.get(i); + if (arg1.parameter.equals(arg2.parameter)) { + if (isSupertype(arg1.signature, arg2.signature) && + !arg1.signature.equals(arg2.signature)) continue outer; + } + } + } + resMethods.add(m1.method); + } + } + res.add(resMethods.stream().toList()); + } + return res; + } + public TargetStructure convert(ClassOrInterface input) { Set javaGenerics = new HashSet<>(); Set txGenerics = new HashSet<>(); @@ -161,11 +202,11 @@ public class ASTToTargetAST { var superInterfaces = input.getSuperInterfaces().stream().map(clazz -> convert(clazz, generics.javaGenerics)).toList(); var constructors = input.getConstructors().stream().map(constructor -> this.convert(input, constructor, finalFieldInitializer)).flatMap(List::stream).toList(); var fields = input.getFieldDecl().stream().map(this::convert).toList(); - var methods = groupOverloads(input.getMethods()).stream().map(m -> convert(input, m)).flatMap(Set::stream).toList(); + var methods = groupOverloads(input, input.getMethods()).stream().flatMap(List::stream).toList(); TargetMethod staticConstructor = null; if (input.getStaticInitializer().isPresent()) - staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow(); + staticConstructor = this.convert(input, input.getStaticInitializer().get()).stream().findFirst().orElseThrow().method; if (input instanceof Record) return new TargetRecord(input.getModifiers(), input.getClassName(), javaGenerics, txGenerics, superInterfaces, constructors, staticConstructor, fields, methods); @@ -206,6 +247,7 @@ public class ASTToTargetAST { generics = all.get(0); List result = new ArrayList<>(); Set> parameterSet = new HashSet<>(); + this.currentMethod = input; for (var s : all) { generics = s; @@ -225,56 +267,6 @@ public class ASTToTargetAST { return result; } - /** - * This only considers type patterns, all other methods aren't grouped together - * @param a - * @param b - * @return - */ - private boolean signatureEquals(Method a, Method b) { - if (!a.name.equals(b.name)) return false; - var para = a.getParameterList().getFormalparalist(); - var parb = b.getParameterList().getFormalparalist(); - if (para.size() != parb.size()) return false; - - for (var i = 0; i < para.size(); i++) { - var pa = para.get(i); - var pb = parb.get(i); - - if (pa instanceof RecordPattern rpa) { - if (pb instanceof RecordPattern rpb) { - if (rpa.getType().equals(rpb.getType())) continue; - } - return false; - } else if (pa.getType().equals(pb.getType())) { - continue; - } - return false; - } - - return true; - } - - // TODO Nested patterns - private List> groupOverloads(List input) { - var done = new HashSet(); - var res = new ArrayList>(); - for (var method : input) { - if (done.contains(method)) continue; - var overloads = new ArrayList(); - overloads.add(method); - done.add(method); - for (var method2 : input) { - if (!done.contains(method2) && signatureEquals(method, method2)) { - done.add(method2); - overloads.add(method2); - } - } - res.add(overloads); - } - return res; - } - private String encodeName(String name, ParameterList params) { var res = new StringBuilder(); res.append(name); @@ -290,9 +282,9 @@ public class ASTToTargetAST { return res.toString(); } - private Set convert(ClassOrInterface clazz, List overloadedMethods) { + private List convert(ClassOrInterface clazz, List overloadedMethods) { if (overloadedMethods.size() == 1) { - return convert(clazz, overloadedMethods.getFirst()); + return convert(clazz, overloadedMethods.getFirst()).stream().map(m -> m.method()).toList(); } var methods = new ArrayList(); for (var method : overloadedMethods) { @@ -329,10 +321,11 @@ public class ASTToTargetAST { var entryPoint = new Method(template.modifier, template.name, template.getReturnType(), params, block, template.getGenerics(), new NullToken()); res.add(entryPoint); // TODO*/ - var res = new HashSet(); + var res = new ArrayList(); for (var method : methods) { var overloads = convert(clazz, method); - for (var overload : overloads) { + for (var m : overloads) { + var overload = m.method; if (res.contains(overload)) throw new CodeGenException("Duplicate method found: " + overload.name() + " with signature " + overload.signature().getSignature()); res.add(overload); } @@ -381,10 +374,12 @@ public class ASTToTargetAST { }).findFirst(); } - private Set convert(ClassOrInterface currentClass, Method method) { - generics = all.get(0); - Set result = new HashSet<>(); - Set> parameterSet = new HashSet<>(); + record MethodWithTphs(TargetMethod method, List args) {} + + private List convert(ClassOrInterface currentClass, Method method) { + generics = all.getFirst(); + List result = new ArrayList<>(); + this.currentMethod = method; for (var s : all) { generics = s; @@ -402,19 +397,18 @@ public class ASTToTargetAST { } } - List finalParams = params; - if (parameterSet.stream().noneMatch(p -> p.equals(finalParams))) { - List txParams = convert(method.getParameterList(), this.generics.txGenerics); + List txParams = convert(method.getParameterList(), this.generics.txGenerics); - var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); - var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); + var javaMethodGenerics = collectMethodGenerics(currentClass, generics.javaGenerics(), javaGenerics, method); + var txMethodGenerics = collectMethodGenerics(currentClass, generics.txGenerics(), txGenerics, method); - var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); - var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); - var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); - result.add(newMethod); - parameterSet.add(params); - } + var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); + var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); + var newMethod = new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature); + + var concreteParams = tphsInMethods.getOrDefault(method, new HashSet<>()).stream().map(sig -> new SignaturePairTarget(convert(sig.signature), convert(sig.parameter))).toList(); + + result.add(new MethodWithTphs(newMethod, concreteParams)); } return result; diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 7e50585a..b94c37cd 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -208,6 +208,11 @@ public class StatementToTargetExpression implements ASTVisitor { var isPrivate = false; var signature = methodCall.signatureArguments().stream().map(converter::convert).toList(); + // Add used TPHs to containing method + for (var i = 0; i < methodCall.signatureArguments().size(); i++) { + converter.addSignaturePair(methodCall.signatureArguments().get(i), methodCall.arglist.getArguments().get(i).getType()); + } + var receiverClass = converter.compiler.getClass(receiverName); if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { if (receiverClass == null) throw new DebugException("Class " + receiverName + " does not exist!"); diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 7ca70857..5638e64a 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -1126,6 +1126,13 @@ public class TestComplete { var instance = clazz.getDeclaredConstructor().newInstance(); } + @Test + public void testBug332() throws Exception { + var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug332.jav"); + var clazz = classFiles.get("Bug332"); + var instance = clazz.getDeclaredConstructor().newInstance(); + } + @Test public void testBug333() throws Exception { var classFiles = generateClassFiles(new ByteArrayClassLoader(), "Bug333.jav");