From 4654ecacafa0e8f9093094eb0d6c8b389e0a668f Mon Sep 17 00:00:00 2001 From: Daniel Holle Date: Thu, 2 Nov 2023 13:07:42 +0100 Subject: [PATCH] Some changes in how overload resolution works --- .../bytecode/javFiles/LambdaRunnable.jav | 8 +-- .../de/dhbwstuttgart/bytecode/Codegen.java | 29 ++++++++- .../de/dhbwstuttgart/core/JavaTXCompiler.java | 2 +- .../syntaxtree/statement/ThisCall.java | 1 + .../target/generate/ASTToTargetAST.java | 13 +++- .../generate/StatementToTargetExpression.java | 59 +++++-------------- src/test/java/targetast/TestCodegen.java | 4 +- 7 files changed, 59 insertions(+), 57 deletions(-) diff --git a/resources/bytecode/javFiles/LambdaRunnable.jav b/resources/bytecode/javFiles/LambdaRunnable.jav index dcedb1f5..f5f88dd5 100644 --- a/resources/bytecode/javFiles/LambdaRunnable.jav +++ b/resources/bytecode/javFiles/LambdaRunnable.jav @@ -2,12 +2,12 @@ import java.lang.Runnable; import java.lang.String; import java.lang.System; -public class LamRunnable{ +public class LambdaRunnable { - public LamRunnable(){ + public LambdaRunnable(){ - - Runnable lam = () -> {var a;}; + + Runnable lam = () -> {var a;}; lam.run(); } } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index 0462255a..5ef179d3 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -76,6 +76,8 @@ public class Codegen { int localCounter; MethodVisitor mv; TargetType returnType; + // This is used to remember the type from lambda expressions + TargetType contextType; Stack breakStack = new Stack<>(); Stack switchResultValue = new Stack<>(); @@ -747,14 +749,19 @@ public class Codegen { params.add(new TargetRefType(clazz.qualifiedName().getClassName())); params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList()); - var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new)); + var descriptor = TargetMethod.getDescriptor(state.contextType, params.toArray(TargetType[]::new)); mv.visitVarInsn(ALOAD, 0); for (var capture : lambda.captures()) { var pattern = (TargetTypePattern) capture.pattern(); mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index); } - mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new)))); + String methodName; + var intf = compiler.getClass(new JavaClassName(state.contextType.name())); + if (intf == null) methodName = "apply"; // TODO Weird fallback logic here + else methodName = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow().getName(); + + mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new)))); } private void generate(State state, TargetExpression expr) { @@ -781,7 +788,10 @@ public class Codegen { break; } case TargetCast cast: + var ctx = state.contextType; + state.contextType = cast.type(); generate(state, cast.expr()); + state.contextType = ctx; convertTo(state, cast.expr().type(), cast.type()); break; case TargetInstanceOf instanceOf: @@ -825,7 +835,11 @@ public class Codegen { case TargetAssign assign: { switch (assign.left()) { case TargetLocalVar localVar -> { + var ctype = state.contextType; + state.contextType = localVar.type(); generate(state, assign.right()); + state.contextType = ctype; + convertTo(state, assign.right().type(), localVar.type()); boxPrimitive(state, localVar.type()); var local = state.scope.get(localVar.name()); @@ -836,7 +850,12 @@ public class Codegen { var fieldType = dot.type(); if (!(dot.left() instanceof TargetThis && dot.isStatic())) generate(state, dot.left()); + + var ctype = state.contextType; + state.contextType = fieldType; generate(state, assign.right()); + state.contextType = ctype; + convertTo(state, assign.right().type(), fieldType); boxPrimitive(state, fieldType); if (dot.isStatic()) @@ -934,7 +953,10 @@ 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; convertTo(state, ret.expression().type(), state.returnType); boxPrimitive(state, state.returnType); mv.visitInsn(ARETURN); @@ -981,9 +1003,12 @@ public class Codegen { for (var i = 0; i < call.args().size(); i++) { var e = call.args().get(i); var arg = call.parameterTypes().get(i); + var ctype = state.contextType; + state.contextType = arg; generate(state, e); if (!(arg instanceof TargetPrimitiveType)) boxPrimitive(state, e.type()); + state.contextType = ctype; } var descriptor = call.getDescriptor(); if (call.owner() instanceof TargetFunNType) // Decay FunN diff --git a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java index c337dcd0..9952a9a8 100644 --- a/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java +++ b/src/main/java/de/dhbwstuttgart/core/JavaTXCompiler.java @@ -742,7 +742,7 @@ public class JavaTXCompiler { } public synchronized Map generateBytecode(SourceFile sf, List typeInferenceResult) { - var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader); + var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader); var generatedClasses = new HashMap(); for (var clazz : sf.getClasses()) { var codegen = new Codegen(converter.convert(clazz), this); diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/ThisCall.java b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/ThisCall.java index 26579d2f..14ec3977 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/statement/ThisCall.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/statement/ThisCall.java @@ -8,6 +8,7 @@ public class ThisCall extends MethodCall { public ThisCall(Receiver receiver, ArgumentList arglist, int offset) { + // TODO What is this? super(null, null, null, null, null, null, null); } diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 85feca0d..6d9de51d 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -1,6 +1,7 @@ package de.dhbwstuttgart.target.generate; 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; @@ -31,6 +32,8 @@ public class ASTToTargetAST { protected Generics generics; final Map> userDefinedGenerics = new HashMap<>(); + public final JavaTXCompiler compiler; + protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's public List txGenerics() { @@ -55,10 +58,14 @@ public class ASTToTargetAST { protected SourceFile sourceFile; public ASTToTargetAST(List resultSets) { - this(resultSets, null, new ByteArrayClassLoader()); + this(null, resultSets); + } + public ASTToTargetAST(JavaTXCompiler compiler, List resultSets) { + this(compiler, resultSets, null, new ByteArrayClassLoader()); } - public ASTToTargetAST(List resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) { + public ASTToTargetAST(JavaTXCompiler compiler, List resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) { + this.compiler = compiler; this.classLoader = classLoader; this.sourceFile = sourceFile; @@ -82,7 +89,7 @@ public class ASTToTargetAST { for (var i = 0; i < pars.size(); i++) { var type1 = convert(pars.get(i).getType(), generics.javaGenerics); var type2 = convert(arguments.get(i).getType(), generics.javaGenerics); - if (type2 instanceof TargetGenericType && type1 instanceof TargetGenericType) + if (type1 instanceof TargetGenericType) return true; if (!type1.equals(type2)) return false; diff --git a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java index 0cfc0a2f..868059ad 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/StatementToTargetExpression.java @@ -4,13 +4,15 @@ import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.syntaxtree.*; +import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator; import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.target.tree.MethodParameter; import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.type.*; -import java.lang.reflect.Method; +import javax.swing.text.html.Option; +import java.lang.reflect.Modifier; import java.util.*; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -169,67 +171,34 @@ public class StatementToTargetExpression implements ASTVisitor { return to.equals(from); } - Method findMethod(JavaClassName className, String name, List args) { - if (converter.sourceFile != null /*&& converter.sourceFile.imports.contains(className)*/) { - try { - var clazz = converter.classLoader.loadClass(className.toString()); - - outer: for (var method : clazz.getMethods()) { - if (method.getParameterTypes().length != args.size()) - continue; - if (!method.getName().equals(name)) - continue; - - for (var i = 0; i < method.getParameterTypes().length; i++) { - var param = method.getParameterTypes()[i]; - var arg = args.get(i); - if (param.isPrimitive()) { - arg = TargetType.toPrimitive(arg); - } - if (!convertsTo(arg, Objects.requireNonNull(TargetType.toTargetType(param)))) - continue outer; - } - return method; - } - } catch (ClassNotFoundException ignored) { - } - } - if (converter.sourceFile != null) { // TODO Multiple source files - var thisClass = converter.sourceFile.KlassenVektor.stream().filter(classOrInterface -> classOrInterface.getClassName().equals(className)).findFirst(); - - if (thisClass.isPresent()) { - var superClass = thisClass.get().getSuperClass().getName(); - return findMethod(superClass, name, args); - } - } - return null; + Optional findMethod(JavaClassName className, String name, ArgumentList args) { + return converter.findMethod(converter.compiler.getClass(className), name, args); } @Override public void visit(MethodCall methodCall) { var receiverType = converter.convert(methodCall.receiver.getType()); var isFunNType = receiverType instanceof TargetFunNType; + var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1)); var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name()); var argList = methodCall.signature.stream().map(converter::convert).toList(); argList = argList.subList(0, argList.size() - 1); - Method foundMethod = null; + Method foundMethod; + var receiverClass = converter.currentClass; if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) { var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist); - if (thisMethod.isEmpty()) { - foundMethod = findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, argList); - } + foundMethod = thisMethod.orElseGet(() -> findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, methodCall.arglist).orElseThrow()); } else { - foundMethod = findMethod(receiverName, methodCall.name, argList); + receiverClass = converter.compiler.getClass(receiverName); + foundMethod = findMethod(receiverName, methodCall.name, methodCall.arglist).orElseThrow(); } - if (foundMethod != null) { - returnType = TargetType.toTargetType(foundMethod.getReturnType()); - argList = Stream.of(foundMethod.getParameterTypes()).map(TargetType::toTargetType).toList(); - } + returnType = converter.convert(foundMethod.getReturnType()); + argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList(); - result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, false, isFunNType); + result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, Modifier.isStatic(foundMethod.modifier), receiverClass.isInterface()); } @Override diff --git a/src/test/java/targetast/TestCodegen.java b/src/test/java/targetast/TestCodegen.java index 716e4d6b..85f4a0d3 100644 --- a/src/test/java/targetast/TestCodegen.java +++ b/src/test/java/targetast/TestCodegen.java @@ -47,7 +47,7 @@ public class TestCodegen { var result = new HashMap>(); for (var file : filenames) { var sourceFile = compiler.sourceFiles.get(file); - var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader); + var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader); var classes = compiler.sourceFiles.get(file).getClasses(); result.putAll(classes.stream().map(cli -> { @@ -86,7 +86,7 @@ public class TestCodegen { var resultSet = compiler.typeInference(); var sourceFile = compiler.sourceFiles.get(file); - var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader); + var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader); var classes = compiler.sourceFiles.get(file).getClasses(); var result = classes.stream().map(cli -> {