Flatten generic function types
This commit is contained in:
parent
677d68428d
commit
67a582b4a2
@ -17,7 +17,7 @@ public class Faculty {
|
||||
|
||||
|
||||
|
||||
public getFact(x) {
|
||||
public getFact(java.lang.Integer x) {
|
||||
return fact.apply(x);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
public class Tph2 {
|
||||
id = x->x;
|
||||
id3 (x) {
|
||||
return id.apply(x);
|
||||
}
|
||||
id = x->x;
|
||||
id3 (x) {
|
||||
return id.apply(x);
|
||||
}
|
||||
|
||||
/*
|
||||
m(a,b){
|
||||
|
@ -1,16 +1,15 @@
|
||||
package de.dhbwstuttgart.bytecode;
|
||||
|
||||
import de.dhbwstuttgart.target.tree.TargetGeneric;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetGenericType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetSpecializedType;
|
||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -32,7 +31,24 @@ public class FunNGenerator {
|
||||
private static final String objectSuperType = Type.getInternalName(Object.class).replace('.','/');
|
||||
private static final String objectSignature = applySignature(TargetType.Object);
|
||||
|
||||
private static String applyDescriptor(TargetType a) { return a.toDescriptor(); }
|
||||
|
||||
private static String applyDescriptor(TargetType type, int[] start) {
|
||||
var res = "L" + type.getInternalName() + "<";
|
||||
if (type instanceof TargetSpecializedType a)
|
||||
for (var param : a.params()) {
|
||||
if (param instanceof TargetGenericType gp) {
|
||||
res += "TT" + start[0] + ";";
|
||||
start[0] += 1;
|
||||
} else {
|
||||
res += applyDescriptor(param, start);
|
||||
}
|
||||
}
|
||||
else return type.toDescriptor();
|
||||
res += ">;";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static String applySignature(TargetType a) { return a.toSignature(); }
|
||||
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s;", applySignature(a)); }
|
||||
|
||||
@ -68,22 +84,20 @@ public class FunNGenerator {
|
||||
public static byte[] generateSpecializedBytecode(List<TargetType> argumentTypes, TargetType returnType) {
|
||||
List<TargetType> parameters = Stream
|
||||
.concat(argumentTypes.stream(), Stream.of(returnType))
|
||||
.collect(Collectors.toList());
|
||||
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters)));
|
||||
.toList();
|
||||
|
||||
var start = new int[]{0};
|
||||
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters), start));
|
||||
boolean containsGeneric = false;
|
||||
|
||||
String genericSignature = "<";
|
||||
var generics = new HashSet<TargetGenericType>();
|
||||
for (TargetType typeArgument : parameters) {
|
||||
collectGenericTypeArguments(generics, typeArgument);
|
||||
}
|
||||
for (var generic : generics) {
|
||||
genericSignature += String.format("%s:%s", generic.name(), objectSignature);
|
||||
containsGeneric = true;
|
||||
}
|
||||
for (var i = 0; i < start[0]; i++)
|
||||
genericSignature += String.format("T%d:%s", i, objectSignature);
|
||||
containsGeneric = true;
|
||||
|
||||
genericSignature += ">";
|
||||
if (containsGeneric) funNClassSignature.insert(0, genericSignature);
|
||||
System.out.println(funNClassSignature.toString());
|
||||
|
||||
ClassWriter classWriter = new ClassWriter(0);
|
||||
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, new String[]{getSuperClassName(argumentTypes.size())});
|
||||
@ -91,12 +105,14 @@ public class FunNGenerator {
|
||||
return classWriter.toByteArray();
|
||||
}
|
||||
|
||||
private static void collectGenericTypeArguments(HashSet<TargetGenericType> generics, TargetType typeArgument) {
|
||||
private static void collectGenericTypeArguments(Map<TargetGenericType, Integer> generics, TargetType typeArgument) {
|
||||
if (typeArgument instanceof TargetSpecializedType specializedType) {
|
||||
for (var arg : specializedType.params())
|
||||
collectGenericTypeArguments(generics, arg);
|
||||
} else if (typeArgument instanceof TargetGenericType genericType) {
|
||||
generics.add(genericType);
|
||||
if (generics.containsKey(genericType))
|
||||
generics.put(genericType, generics.get(genericType) + 1);
|
||||
else generics.put(genericType, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,14 +128,6 @@ public class FunNGenerator {
|
||||
.replace(";", "$_$");
|
||||
}
|
||||
|
||||
public static String getSpecializedDescriptor(List<TargetType> argumentTypes, TargetType returnType) {
|
||||
return applyDescriptor(new TargetRefType(getSpecializedClassName(argumentTypes, returnType)));
|
||||
}
|
||||
|
||||
public static String getSpecializedSignature(List<TargetType> argumentTypes, TargetType returnType) {
|
||||
return applySignature(new TargetRefType(getSpecializedClassName(argumentTypes, returnType)));
|
||||
}
|
||||
|
||||
public static List<TargetType> getArguments(List<TargetType> list) {
|
||||
return list
|
||||
.stream()
|
||||
|
@ -898,7 +898,7 @@ public class JavaTXCompiler {
|
||||
return generatedClasses;
|
||||
}
|
||||
|
||||
private void writeClassFile(Map<JavaClassName, byte[]> classFiles, File path) throws IOException {
|
||||
public void writeClassFile(Map<JavaClassName, byte[]> classFiles, File path) throws IOException {
|
||||
FileOutputStream output;
|
||||
for (JavaClassName name : classFiles.keySet()) {
|
||||
byte[] bytecode = classFiles.get(name);
|
||||
|
@ -15,6 +15,7 @@ import de.dhbwstuttgart.target.tree.expression.TargetExpression;
|
||||
import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -52,8 +53,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
|
||||
eliminateInfima(result, referenced);
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||
}
|
||||
@ -72,8 +72,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
|
||||
@Override
|
||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
|
||||
eliminateCycles(result, referenced);
|
||||
eliminateInfima(result, referenced);
|
||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||
@ -523,7 +522,7 @@ public class ASTToTargetAST {
|
||||
usedTPHsOfMethods.put(method, usedTphs);
|
||||
|
||||
eliminateInnerTypeVariables(referenced, result);
|
||||
addMissingObjectBounds(result, classGenerics);
|
||||
addMissingObjectBounds(result, classGenerics, usedTphs);
|
||||
|
||||
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
|
||||
return result;
|
||||
@ -582,7 +581,7 @@ public class ASTToTargetAST {
|
||||
}
|
||||
}
|
||||
|
||||
abstract void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result);
|
||||
abstract void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced);
|
||||
|
||||
Set<ResultPair<?, ?>> generics(ClassOrInterface classOrInterface) {
|
||||
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
||||
@ -595,24 +594,31 @@ public class ASTToTargetAST {
|
||||
findAllBounds(field.getType(), javaResult, equality);
|
||||
}
|
||||
|
||||
var referenced = new HashSet<TypePlaceholder>();
|
||||
eliminateTransitives(javaResult);
|
||||
generics(classOrInterface, javaResult);
|
||||
addMissingObjectBounds(javaResult, null);
|
||||
generics(classOrInterface, javaResult, referenced);
|
||||
|
||||
var referencedByClass = new HashSet<TypePlaceholder>();
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
findTphs(field.getType(), referencedByClass);
|
||||
}
|
||||
|
||||
addMissingObjectBounds(javaResult, null, referencedByClass);
|
||||
|
||||
System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult);
|
||||
return javaResult;
|
||||
}
|
||||
|
||||
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics) {
|
||||
outer: for (var p1 : new HashSet<>(result)) {
|
||||
if (p1 instanceof PairTPHsmallerTPH ptph) {
|
||||
for (var p2 : new HashSet<>(result)) {
|
||||
if (ptph.right.equals(p2.getLeft()))
|
||||
continue outer;
|
||||
}
|
||||
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.getLeft().equals(ptph.right)))
|
||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(ptph.right, OBJECT));
|
||||
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics, Set<TypePlaceholder> usedTphs) {
|
||||
outer: for (var tph : usedTphs) {
|
||||
tph = equality.getOrDefault(tph, tph);
|
||||
for (var p1 : new HashSet<>(result)) {
|
||||
if (p1.getLeft().equals(tph)) continue outer;
|
||||
}
|
||||
|
||||
TypePlaceholder finalTph = tph;
|
||||
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.getLeft().equals(finalTph)))
|
||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(tph, OBJECT));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1136,6 +1142,19 @@ public class ASTToTargetAST {
|
||||
return convert(input, generics.javaGenerics);
|
||||
}
|
||||
|
||||
static TargetType flattenFunNType(List<TargetType> params) {
|
||||
var newParams = new ArrayList<TargetType>();
|
||||
for (var i = 0; i < params.size(); i++) {
|
||||
var param = params.get(i);
|
||||
if (param instanceof TargetSpecializedType fn) {
|
||||
newParams.addAll(fn.params());
|
||||
} else {
|
||||
newParams.add(param);
|
||||
}
|
||||
}
|
||||
return TargetFunNType.fromParams(params, newParams);
|
||||
}
|
||||
|
||||
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
|
||||
return input.acceptTV(new TypeVisitor<>() {
|
||||
@Override
|
||||
@ -1158,7 +1177,7 @@ public class ASTToTargetAST {
|
||||
var clazz = classLoader.loadClass(code);
|
||||
auxiliaries.put(clazz.getName(), code);
|
||||
}
|
||||
return new TargetFunNType(params.size() - 1, params);
|
||||
return flattenFunNType(params);
|
||||
}
|
||||
return new TargetRefType(name, params);
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ public class GenericsResultSet extends AbstractSet<ResultPair<?, ?>> {
|
||||
|
||||
public Optional<ResultPair<?, ?>> getResultPairFor(TypePlaceholder tph) {
|
||||
var tph2 = equality.getOrDefault(tph, tph);
|
||||
return this.stream().filter(pair -> pair.getLeft().equals(tph2)).findFirst();
|
||||
return this.stream().filter(pair -> {
|
||||
return pair.getLeft().equals(tph2);
|
||||
}).findFirst();
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,20 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record TargetFunNType(int N, List<TargetType> params) implements TargetSpecializedType {
|
||||
public record TargetFunNType(String name, List<TargetType> params) implements TargetSpecializedType {
|
||||
|
||||
@Override
|
||||
public String getInternalName() {
|
||||
return FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
|
||||
public static TargetFunNType fromParams(List<TargetType> params) {
|
||||
return fromParams(params, params);
|
||||
}
|
||||
|
||||
public static TargetFunNType fromParams(List<TargetType> params, List<TargetType> realParams) {
|
||||
var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
|
||||
return new TargetFunNType(name, realParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return getInternalName();
|
||||
public String getInternalName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -186,7 +186,13 @@ class TypeToInsertString implements ResultSetVisitor{
|
||||
|
||||
@Override
|
||||
public void visit(TypePlaceholder typePlaceholder) {
|
||||
insert += ((TypePlaceholder) constraints.getResultPairFor(typePlaceholder).get().getLeft()).getName();
|
||||
ResultPair<?, ?> resultPair = null;
|
||||
if (constraints != null)
|
||||
resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null);
|
||||
if (resultPair == null)
|
||||
resultPair = classConstraints.getResultPairFor(typePlaceholder).get();
|
||||
|
||||
insert += ((TypePlaceholder)resultPair.getLeft()).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,6 +17,7 @@ import static org.junit.Assert.*;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Target;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
@ -341,7 +342,7 @@ public class TestCodegen {
|
||||
public void testLambda() throws Exception {
|
||||
var classLoader = new ByteArrayClassLoader();
|
||||
//var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class"));
|
||||
var interfaceType = new TargetFunNType(1, List.of(TargetType.Integer));
|
||||
var interfaceType = TargetFunNType.fromParams(List.of(TargetType.Integer));
|
||||
|
||||
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "CGLambda");
|
||||
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(
|
||||
|
Loading…
Reference in New Issue
Block a user