diff --git a/resources/bytecode/javFiles/Bug298.jav b/resources/bytecode/javFiles/Bug298.jav index fc22b3da..fd1c7164 100644 --- a/resources/bytecode/javFiles/Bug298.jav +++ b/resources/bytecode/javFiles/Bug298.jav @@ -7,7 +7,7 @@ import java.util.stream.Stream; import java.util.function.Function; public class Bug298 { - public Stream takes(Stream s, Function fun) { + public Stream takes(Stream s, Function fun) { return null; } diff --git a/resources/bytecode/javFiles/OverrideEquals.jav b/resources/bytecode/javFiles/OverrideEquals.jav new file mode 100644 index 00000000..cabb6d4c --- /dev/null +++ b/resources/bytecode/javFiles/OverrideEquals.jav @@ -0,0 +1,12 @@ +import java.lang.Object; +import java.lang.Boolean; + +public class OverrideEquals extends OverrideRoot { + public boolean equals(Object o) { + return true; + } + + public int method(int var1, float var2) { + return 0; + } +} diff --git a/resources/bytecode/javFiles/OverrideRoot.class b/resources/bytecode/javFiles/OverrideRoot.class new file mode 100644 index 00000000..52657698 Binary files /dev/null and b/resources/bytecode/javFiles/OverrideRoot.class differ diff --git a/resources/bytecode/javFiles/OverrideRoot.java b/resources/bytecode/javFiles/OverrideRoot.java new file mode 100644 index 00000000..5d097592 --- /dev/null +++ b/resources/bytecode/javFiles/OverrideRoot.java @@ -0,0 +1,3 @@ +public abstract class OverrideRoot { + public abstract int method(int a, float b); +} \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index 03fa2023..8c92abfb 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -962,13 +962,34 @@ public class Codegen { } case TargetReturn ret: { if (ret.expression() != null && state.returnType != null) { - var ctype = state.contextType; - state.contextType = state.returnType; - generate(state, ret.expression()); - state.contextType = ctype; - boxPrimitive(state, ret.expression().type()); - convertTo(state, ret.expression().type(), state.returnType); - mv.visitInsn(ARETURN); + if (state.returnType instanceof TargetPrimitiveType) { + var ctype = state.contextType; + state.contextType = state.returnType; + generate(state, ret.expression()); + state.contextType = ctype; + + unboxPrimitive(state, state.returnType); + if (state.returnType.equals(TargetType.boolean_) + || state.returnType.equals(TargetType.char_) + || state.returnType.equals(TargetType.int_) + || state.returnType.equals(TargetType.short_) + || state.returnType.equals(TargetType.byte_)) + mv.visitInsn(IRETURN); + else if (state.returnType.equals(TargetType.long_)) + mv.visitInsn(LRETURN); + else if (state.returnType.equals(TargetType.float_)) + mv.visitInsn(FRETURN); + else if (state.returnType.equals(TargetType.double_)) + mv.visitInsn(DRETURN); + } else { + var ctype = state.contextType; + state.contextType = state.returnType; + generate(state, ret.expression()); + state.contextType = ctype; + boxPrimitive(state, ret.expression().type()); + convertTo(state, ret.expression().type(), state.returnType); + mv.visitInsn(ARETURN); + } } else mv.visitInsn(RETURN); break; diff --git a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java index d227c167..4216da9f 100644 --- a/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java +++ b/src/main/java/de/dhbwstuttgart/parser/SyntaxTreeGenerator/TypeGenerator.java @@ -68,6 +68,8 @@ public class TypeGenerator { return new RefType(ASTFactory.createClass(Integer.class).getClassName(), typeContext.getStart()); case "double": return new RefType(ASTFactory.createClass(Double.class).getClassName(), typeContext.getStart()); + case "float": + return new RefType(ASTFactory.createClass(Float.class).getClassName(), typeContext.getStart()); default: throw new NotImplementedException(); } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index eb1538d0..020eb6a0 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -368,6 +368,8 @@ public class ASTFactory { return new RefType(new JavaClassName("java.lang.Character"), new ArrayList<>(), new NullToken(), true); } else if (type.getTypeName().equals("short")) { return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken(), true); + } else if (type.getTypeName().equals("float")) { + return new RefType(new JavaClassName("java.lang.Float"), new ArrayList<>(), new NullToken(), true); } else if (type.getTypeName().equals("double")) { return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken(), true); } else if (type.getTypeName().equals("long")) { diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index c8be711c..412fbc54 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -21,6 +21,7 @@ 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 @@ -348,6 +349,27 @@ public class ASTToTargetAST { return swtch; } + private Optional findSuperMethodToOverride(String name, List params) { + var superClass = compiler.getClass(currentClass.getSuperClass().getName()); + var methodStream = superClass.getMethods().stream(); + for (var superInterface : currentClass.getSuperInterfaces()) { + methodStream = Stream.concat(methodStream, compiler.getClass(superInterface.getName()).getMethods().stream()); + } + + return methodStream.filter(m -> { + if (!m.name.equals(name)) return false; + var sParams = m.getParameterList(); + if (sParams.getFormalparalist().size() != params.size()) return false; + for (var i = 0; i < params.size(); i++) { + var a = TargetType.toPrimitive(params.get(i).pattern().type()); + var b = convert(sParams.getFormalparalist().get(i).getType()); + System.out.println(a + " " + b); + if (!Objects.equals(a, b)) return false; + } + return true; + }).findFirst(); + } + private List convert(Method method) { generics = all.get(0); List result = new ArrayList<>(); @@ -358,13 +380,22 @@ public class ASTToTargetAST { var javaGenerics = this.generics.javaGenerics.generics(currentClass, method); var txGenerics = this.generics.txGenerics.generics(currentClass, method); List params = convert(method.getParameterList(), this.generics.javaGenerics); - if (parameterSet.stream().noneMatch(p -> p.equals(params))) { + var returnType = convert(method.getReturnType(), this.generics.javaGenerics); + var superMethod = findSuperMethodToOverride(method.getName(), params); + if (superMethod.isPresent()) { + // If we find a super method to override, use its parameters and return types + returnType = convert(superMethod.get().getReturnType(), this.generics.javaGenerics); + params = convert(superMethod.get().getParameterList(), this.generics.javaGenerics); + } + + List finalParams = params; + if (parameterSet.stream().noneMatch(p -> p.equals(finalParams))) { List txParams = convert(method.getParameterList(), this.generics.txGenerics); var javaMethodGenerics = collectMethodGenerics(generics.javaGenerics(), javaGenerics, method); var txMethodGenerics = collectMethodGenerics(generics.txGenerics(), txGenerics, method); - var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, convert(method.getReturnType(), this.generics.javaGenerics)); + var javaSignature = new TargetMethod.Signature(javaMethodGenerics, params, returnType); var txSignature = new TargetMethod.Signature(txMethodGenerics, txParams, convert(method.getReturnType(), this.generics.txGenerics)); result.add(new TargetMethod(method.modifier, method.name, convert(method.block), javaSignature, txSignature)); parameterSet.add(params); diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetGuard.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetGuard.java index 14466bf8..2a3f9355 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetGuard.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetGuard.java @@ -7,4 +7,9 @@ public record TargetGuard(TargetPattern inner, TargetExpression expression) impl public TargetGuard withType(TargetType type) { return new TargetGuard(inner.withType(type), expression); } + + @Override + public TargetType type() { + return inner.type(); + } } diff --git a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java index 58efa37c..d9354cb1 100644 --- a/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java +++ b/src/main/java/de/dhbwstuttgart/target/tree/expression/TargetPattern.java @@ -8,4 +8,6 @@ public sealed interface TargetPattern extends TargetExpression permits TargetCom } TargetPattern withType(TargetType type); + + TargetType type(); } diff --git a/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java b/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java index 1669b760..bed26163 100644 --- a/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java +++ b/src/main/java/de/dhbwstuttgart/typeinference/unify/RuleSet.java @@ -12,6 +12,7 @@ import java.util.Stack; import java.util.function.Function; import java.util.stream.Collectors; +import de.dhbwstuttgart.core.JavaTXCompiler; import de.dhbwstuttgart.exceptions.DebugException; import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; @@ -892,7 +893,6 @@ public class RuleSet implements IRuleSet{ //FunN$$<...> <. FunctinalInterface<...> wird umgewandelt in FunN$$<...> <. FunN$$<... args aus FuntionalInterface ...> if (rhsType instanceof ReferenceType) { - UnifyType typeFI = pair.getRhsType(); Optional opt = fc.getRightHandedFunctionalInterfaceType(typeFI.getName()); @@ -901,7 +901,7 @@ public class RuleSet implements IRuleSet{ // The generic Version of typeFI (FI) UnifyType typeDgen = opt.get(); - + // Actually greater+ because the types are ensured to have different names Set smaller = fc.getChildren(typeDgen); opt = smaller.stream().filter(x -> x.getName().equals(pair.getLhsType().getName())).findAny(); @@ -915,7 +915,7 @@ public class RuleSet implements IRuleSet{ Unifier unif = Unifier.identity(); for(int i = 0; i < typeDParams.size(); i++) { if (typeDgenParams.get(i) instanceof PlaceholderType) - unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); + unif.add((PlaceholderType) typeDgenParams.get(i), typeDParams.get(i)); else System.out.println("ERROR"); } diff --git a/src/test/java/TestComplete.java b/src/test/java/TestComplete.java index 8281844c..c3d6a39c 100644 --- a/src/test/java/TestComplete.java +++ b/src/test/java/TestComplete.java @@ -891,6 +891,14 @@ public class TestComplete { var instance = clazz.getDeclaredConstructor().newInstance(); } + @Test + public void testOverrideEquals() throws Exception { + var loader = new ByteArrayClassLoader(); + loader.loadClass(TestCodegen.path.resolve("OverrideRoot.class")); + var classFiles = generateClassFiles(loader, "OverrideEquals.jav"); + var clazz = classFiles.get("OverrideEquals"); + var instance = clazz.getDeclaredConstructor().newInstance(); + } @Test public void testBug122() throws Exception { diff --git a/src/test/java/targetast/TestCodegen.java b/src/test/java/targetast/TestCodegen.java index 7e82bf94..d737bf53 100644 --- a/src/test/java/targetast/TestCodegen.java +++ b/src/test/java/targetast/TestCodegen.java @@ -38,8 +38,9 @@ public class TestCodegen { Files.write(outputPath.resolve(name + ".class"), code); } + public static Path path = Path.of(System.getProperty("user.dir"), "resources/bytecode/javFiles/"); + public static Map> generateClassFiles(IByteArrayClassLoader classLoader, String... files) throws IOException, ClassNotFoundException { - var path = Path.of(System.getProperty("user.dir"), "resources/bytecode/javFiles/"); Files.createDirectories(outputPath); var filenames = Arrays.stream(files).map(filename -> Path.of(path.toString(), filename).toFile()).toList(); var compiler = new JavaTXCompiler(filenames, List.of(path.toFile(), outputPath.toFile()));