Some changes in how overload resolution works

This commit is contained in:
Daniel Holle 2023-11-02 13:07:42 +01:00
parent 1be27746e3
commit 4654ecacaf
7 changed files with 59 additions and 57 deletions

View File

@ -2,12 +2,12 @@ import java.lang.Runnable;
import java.lang.String; import java.lang.String;
import java.lang.System; import java.lang.System;
public class LamRunnable{ public class LambdaRunnable {
public LamRunnable(){ public LambdaRunnable(){
Runnable lam = () -> {var a;}; Runnable lam = () -> {var a;};
lam.run(); lam.run();
} }
} }

View File

@ -76,6 +76,8 @@ public class Codegen {
int localCounter; int localCounter;
MethodVisitor mv; MethodVisitor mv;
TargetType returnType; TargetType returnType;
// This is used to remember the type from lambda expressions
TargetType contextType;
Stack<BreakEnv> breakStack = new Stack<>(); Stack<BreakEnv> breakStack = new Stack<>();
Stack<Integer> switchResultValue = new Stack<>(); Stack<Integer> switchResultValue = new Stack<>();
@ -747,14 +749,19 @@ public class Codegen {
params.add(new TargetRefType(clazz.qualifiedName().getClassName())); params.add(new TargetRefType(clazz.qualifiedName().getClassName()));
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList()); 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); mv.visitVarInsn(ALOAD, 0);
for (var capture : lambda.captures()) { for (var capture : lambda.captures()) {
var pattern = (TargetTypePattern) capture.pattern(); var pattern = (TargetTypePattern) capture.pattern();
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index); 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) { private void generate(State state, TargetExpression expr) {
@ -781,7 +788,10 @@ public class Codegen {
break; break;
} }
case TargetCast cast: case TargetCast cast:
var ctx = state.contextType;
state.contextType = cast.type();
generate(state, cast.expr()); generate(state, cast.expr());
state.contextType = ctx;
convertTo(state, cast.expr().type(), cast.type()); convertTo(state, cast.expr().type(), cast.type());
break; break;
case TargetInstanceOf instanceOf: case TargetInstanceOf instanceOf:
@ -825,7 +835,11 @@ public class Codegen {
case TargetAssign assign: { case TargetAssign assign: {
switch (assign.left()) { switch (assign.left()) {
case TargetLocalVar localVar -> { case TargetLocalVar localVar -> {
var ctype = state.contextType;
state.contextType = localVar.type();
generate(state, assign.right()); generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), localVar.type()); convertTo(state, assign.right().type(), localVar.type());
boxPrimitive(state, localVar.type()); boxPrimitive(state, localVar.type());
var local = state.scope.get(localVar.name()); var local = state.scope.get(localVar.name());
@ -836,7 +850,12 @@ public class Codegen {
var fieldType = dot.type(); var fieldType = dot.type();
if (!(dot.left() instanceof TargetThis && dot.isStatic())) if (!(dot.left() instanceof TargetThis && dot.isStatic()))
generate(state, dot.left()); generate(state, dot.left());
var ctype = state.contextType;
state.contextType = fieldType;
generate(state, assign.right()); generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), fieldType); convertTo(state, assign.right().type(), fieldType);
boxPrimitive(state, fieldType); boxPrimitive(state, fieldType);
if (dot.isStatic()) if (dot.isStatic())
@ -934,7 +953,10 @@ public class Codegen {
} }
case TargetReturn ret: { case TargetReturn ret: {
if (ret.expression() != null && state.returnType != null) { if (ret.expression() != null && state.returnType != null) {
var ctype = state.contextType;
state.contextType = state.returnType;
generate(state, ret.expression()); generate(state, ret.expression());
state.contextType = ctype;
convertTo(state, ret.expression().type(), state.returnType); convertTo(state, ret.expression().type(), state.returnType);
boxPrimitive(state, state.returnType); boxPrimitive(state, state.returnType);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
@ -981,9 +1003,12 @@ public class Codegen {
for (var i = 0; i < call.args().size(); i++) { for (var i = 0; i < call.args().size(); i++) {
var e = call.args().get(i); var e = call.args().get(i);
var arg = call.parameterTypes().get(i); var arg = call.parameterTypes().get(i);
var ctype = state.contextType;
state.contextType = arg;
generate(state, e); generate(state, e);
if (!(arg instanceof TargetPrimitiveType)) if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type()); boxPrimitive(state, e.type());
state.contextType = ctype;
} }
var descriptor = call.getDescriptor(); var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType) // Decay FunN if (call.owner() instanceof TargetFunNType) // Decay FunN

View File

@ -742,7 +742,7 @@ public class JavaTXCompiler {
} }
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) { public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader); var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader);
var generatedClasses = new HashMap<JavaClassName, byte[]>(); var generatedClasses = new HashMap<JavaClassName, byte[]>();
for (var clazz : sf.getClasses()) { for (var clazz : sf.getClasses()) {
var codegen = new Codegen(converter.convert(clazz), this); var codegen = new Codegen(converter.convert(clazz), this);

View File

@ -8,6 +8,7 @@ public class ThisCall extends MethodCall
{ {
public ThisCall(Receiver receiver, ArgumentList arglist, int offset) public ThisCall(Receiver receiver, ArgumentList arglist, int offset)
{ {
// TODO What is this?
super(null, null, null, null, null, null, null); super(null, null, null, null, null, null, null);
} }

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.target.generate; package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.bytecode.FunNGenerator; import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.ByteArrayClassLoader; import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader; import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.exceptions.NotImplementedException;
@ -31,6 +32,8 @@ public class ASTToTargetAST {
protected Generics generics; protected Generics generics;
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>(); final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
public final JavaTXCompiler compiler;
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
public List<GenericsResult> txGenerics() { public List<GenericsResult> txGenerics() {
@ -55,10 +58,14 @@ public class ASTToTargetAST {
protected SourceFile sourceFile; protected SourceFile sourceFile;
public ASTToTargetAST(List<ResultSet> resultSets) { public ASTToTargetAST(List<ResultSet> resultSets) {
this(resultSets, null, new ByteArrayClassLoader()); this(null, resultSets);
}
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets) {
this(compiler, resultSets, null, new ByteArrayClassLoader());
} }
public ASTToTargetAST(List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) { public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
this.compiler = compiler;
this.classLoader = classLoader; this.classLoader = classLoader;
this.sourceFile = sourceFile; this.sourceFile = sourceFile;
@ -82,7 +89,7 @@ public class ASTToTargetAST {
for (var i = 0; i < pars.size(); i++) { for (var i = 0; i < pars.size(); i++) {
var type1 = convert(pars.get(i).getType(), generics.javaGenerics); var type1 = convert(pars.get(i).getType(), generics.javaGenerics);
var type2 = convert(arguments.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; return true;
if (!type1.equals(type2)) if (!type1.equals(type2))
return false; return false;

View File

@ -4,13 +4,15 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName; import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator;
import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.tree.MethodParameter; import de.dhbwstuttgart.target.tree.MethodParameter;
import de.dhbwstuttgart.target.tree.expression.*; import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*; 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.*;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
@ -169,67 +171,34 @@ public class StatementToTargetExpression implements ASTVisitor {
return to.equals(from); return to.equals(from);
} }
Method findMethod(JavaClassName className, String name, List<TargetType> args) { Optional<Method> findMethod(JavaClassName className, String name, ArgumentList args) {
if (converter.sourceFile != null /*&& converter.sourceFile.imports.contains(className)*/) { return converter.findMethod(converter.compiler.getClass(className), name, args);
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;
} }
@Override @Override
public void visit(MethodCall methodCall) { public void visit(MethodCall methodCall) {
var receiverType = converter.convert(methodCall.receiver.getType()); var receiverType = converter.convert(methodCall.receiver.getType());
var isFunNType = receiverType instanceof TargetFunNType; var isFunNType = receiverType instanceof TargetFunNType;
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1)); 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 receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
var argList = methodCall.signature.stream().map(converter::convert).toList(); var argList = methodCall.signature.stream().map(converter::convert).toList();
argList = argList.subList(0, argList.size() - 1); 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) { if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist); var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist);
if (thisMethod.isEmpty()) { foundMethod = thisMethod.orElseGet(() -> findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, methodCall.arglist).orElseThrow());
foundMethod = findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, argList);
}
} else { } else {
foundMethod = findMethod(receiverName, methodCall.name, argList); receiverClass = converter.compiler.getClass(receiverName);
foundMethod = findMethod(receiverName, methodCall.name, methodCall.arglist).orElseThrow();
} }
if (foundMethod != null) { returnType = converter.convert(foundMethod.getReturnType());
returnType = TargetType.toTargetType(foundMethod.getReturnType()); argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
argList = Stream.of(foundMethod.getParameterTypes()).map(TargetType::toTargetType).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 @Override

View File

@ -47,7 +47,7 @@ public class TestCodegen {
var result = new HashMap<String, Class<?>>(); var result = new HashMap<String, Class<?>>();
for (var file : filenames) { for (var file : filenames) {
var sourceFile = compiler.sourceFiles.get(file); 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 classes = compiler.sourceFiles.get(file).getClasses();
result.putAll(classes.stream().map(cli -> { result.putAll(classes.stream().map(cli -> {
@ -86,7 +86,7 @@ public class TestCodegen {
var resultSet = compiler.typeInference(); var resultSet = compiler.typeInference();
var sourceFile = compiler.sourceFiles.get(file); 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 classes = compiler.sourceFiles.get(file).getClasses();
var result = classes.stream().map(cli -> { var result = classes.stream().map(cli -> {