Some changes in how overload resolution works
This commit is contained in:
parent
1be27746e3
commit
4654ecacaf
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<BreakEnv> breakStack = new Stack<>();
|
||||
Stack<Integer> 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
|
||||
|
@ -742,7 +742,7 @@ public class JavaTXCompiler {
|
||||
}
|
||||
|
||||
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[]>();
|
||||
for (var clazz : sf.getClasses()) {
|
||||
var codegen = new Codegen(converter.convert(clazz), this);
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
|
||||
|
||||
public final JavaTXCompiler compiler;
|
||||
|
||||
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
|
||||
|
||||
public List<GenericsResult> txGenerics() {
|
||||
@ -55,10 +58,14 @@ public class ASTToTargetAST {
|
||||
protected SourceFile sourceFile;
|
||||
|
||||
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.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;
|
||||
|
@ -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<TargetType> 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<Method> 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
|
||||
|
@ -47,7 +47,7 @@ public class TestCodegen {
|
||||
var result = new HashMap<String, Class<?>>();
|
||||
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 -> {
|
||||
|
Loading…
Reference in New Issue
Block a user