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);
|
return fact.apply(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package de.dhbwstuttgart.bytecode;
|
package de.dhbwstuttgart.bytecode;
|
||||||
|
|
||||||
import de.dhbwstuttgart.target.tree.TargetGeneric;
|
import de.dhbwstuttgart.target.tree.TargetGeneric;
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetGenericType;
|
import de.dhbwstuttgart.target.tree.type.*;
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetRefType;
|
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetSpecializedType;
|
|
||||||
import de.dhbwstuttgart.target.tree.type.TargetType;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
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 objectSuperType = Type.getInternalName(Object.class).replace('.','/');
|
||||||
private static final String objectSignature = applySignature(TargetType.Object);
|
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 applySignature(TargetType a) { return a.toSignature(); }
|
||||||
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s;", applySignature(a)); }
|
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) {
|
public static byte[] generateSpecializedBytecode(List<TargetType> argumentTypes, TargetType returnType) {
|
||||||
List<TargetType> parameters = Stream
|
List<TargetType> parameters = Stream
|
||||||
.concat(argumentTypes.stream(), Stream.of(returnType))
|
.concat(argumentTypes.stream(), Stream.of(returnType))
|
||||||
.collect(Collectors.toList());
|
.toList();
|
||||||
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters)));
|
|
||||||
|
var start = new int[]{0};
|
||||||
|
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters), start));
|
||||||
boolean containsGeneric = false;
|
boolean containsGeneric = false;
|
||||||
|
|
||||||
String genericSignature = "<";
|
String genericSignature = "<";
|
||||||
var generics = new HashSet<TargetGenericType>();
|
for (var i = 0; i < start[0]; i++)
|
||||||
for (TargetType typeArgument : parameters) {
|
genericSignature += String.format("T%d:%s", i, objectSignature);
|
||||||
collectGenericTypeArguments(generics, typeArgument);
|
|
||||||
}
|
|
||||||
for (var generic : generics) {
|
|
||||||
genericSignature += String.format("%s:%s", generic.name(), objectSignature);
|
|
||||||
containsGeneric = true;
|
containsGeneric = true;
|
||||||
}
|
|
||||||
|
|
||||||
genericSignature += ">";
|
genericSignature += ">";
|
||||||
if (containsGeneric) funNClassSignature.insert(0, genericSignature);
|
if (containsGeneric) funNClassSignature.insert(0, genericSignature);
|
||||||
|
System.out.println(funNClassSignature.toString());
|
||||||
|
|
||||||
ClassWriter classWriter = new ClassWriter(0);
|
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())});
|
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();
|
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) {
|
if (typeArgument instanceof TargetSpecializedType specializedType) {
|
||||||
for (var arg : specializedType.params())
|
for (var arg : specializedType.params())
|
||||||
collectGenericTypeArguments(generics, arg);
|
collectGenericTypeArguments(generics, arg);
|
||||||
} else if (typeArgument instanceof TargetGenericType genericType) {
|
} 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(";", "$_$");
|
.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) {
|
public static List<TargetType> getArguments(List<TargetType> list) {
|
||||||
return list
|
return list
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -898,7 +898,7 @@ public class JavaTXCompiler {
|
|||||||
return generatedClasses;
|
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;
|
FileOutputStream output;
|
||||||
for (JavaClassName name : classFiles.keySet()) {
|
for (JavaClassName name : classFiles.keySet()) {
|
||||||
byte[] bytecode = classFiles.get(name);
|
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.target.tree.type.*;
|
||||||
import de.dhbwstuttgart.typeinference.result.*;
|
import de.dhbwstuttgart.typeinference.result.*;
|
||||||
|
|
||||||
|
import java.lang.annotation.Target;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -52,8 +53,7 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
|
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
|
||||||
var referenced = new HashSet<TypePlaceholder>();
|
|
||||||
eliminateInfima(result, referenced);
|
eliminateInfima(result, referenced);
|
||||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||||
}
|
}
|
||||||
@ -72,8 +72,7 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
|
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
|
||||||
var referenced = new HashSet<TypePlaceholder>();
|
|
||||||
eliminateCycles(result, referenced);
|
eliminateCycles(result, referenced);
|
||||||
eliminateInfima(result, referenced);
|
eliminateInfima(result, referenced);
|
||||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
|
||||||
@ -523,7 +522,7 @@ public class ASTToTargetAST {
|
|||||||
usedTPHsOfMethods.put(method, usedTphs);
|
usedTPHsOfMethods.put(method, usedTphs);
|
||||||
|
|
||||||
eliminateInnerTypeVariables(referenced, result);
|
eliminateInnerTypeVariables(referenced, result);
|
||||||
addMissingObjectBounds(result, classGenerics);
|
addMissingObjectBounds(result, classGenerics, usedTphs);
|
||||||
|
|
||||||
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
|
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
|
||||||
return 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) {
|
Set<ResultPair<?, ?>> generics(ClassOrInterface classOrInterface) {
|
||||||
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
||||||
@ -595,24 +594,31 @@ public class ASTToTargetAST {
|
|||||||
findAllBounds(field.getType(), javaResult, equality);
|
findAllBounds(field.getType(), javaResult, equality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var referenced = new HashSet<TypePlaceholder>();
|
||||||
eliminateTransitives(javaResult);
|
eliminateTransitives(javaResult);
|
||||||
generics(classOrInterface, javaResult);
|
generics(classOrInterface, javaResult, referenced);
|
||||||
addMissingObjectBounds(javaResult, null);
|
|
||||||
|
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);
|
System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult);
|
||||||
return javaResult;
|
return javaResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics) {
|
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics, Set<TypePlaceholder> usedTphs) {
|
||||||
outer: for (var p1 : new HashSet<>(result)) {
|
outer: for (var tph : usedTphs) {
|
||||||
if (p1 instanceof PairTPHsmallerTPH ptph) {
|
tph = equality.getOrDefault(tph, tph);
|
||||||
for (var p2 : new HashSet<>(result)) {
|
for (var p1 : new HashSet<>(result)) {
|
||||||
if (ptph.right.equals(p2.getLeft()))
|
if (p1.getLeft().equals(tph)) continue outer;
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.getLeft().equals(ptph.right)))
|
|
||||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(ptph.right, OBJECT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
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) {
|
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
|
||||||
return input.acceptTV(new TypeVisitor<>() {
|
return input.acceptTV(new TypeVisitor<>() {
|
||||||
@Override
|
@Override
|
||||||
@ -1158,7 +1177,7 @@ public class ASTToTargetAST {
|
|||||||
var clazz = classLoader.loadClass(code);
|
var clazz = classLoader.loadClass(code);
|
||||||
auxiliaries.put(clazz.getName(), code);
|
auxiliaries.put(clazz.getName(), code);
|
||||||
}
|
}
|
||||||
return new TargetFunNType(params.size() - 1, params);
|
return flattenFunNType(params);
|
||||||
}
|
}
|
||||||
return new TargetRefType(name, params);
|
return new TargetRefType(name, params);
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ public class GenericsResultSet extends AbstractSet<ResultPair<?, ?>> {
|
|||||||
|
|
||||||
public Optional<ResultPair<?, ?>> getResultPairFor(TypePlaceholder tph) {
|
public Optional<ResultPair<?, ?>> getResultPairFor(TypePlaceholder tph) {
|
||||||
var tph2 = equality.getOrDefault(tph, 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;
|
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 static TargetFunNType fromParams(List<TargetType> params) {
|
||||||
public String getInternalName() {
|
return fromParams(params, params);
|
||||||
return FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(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
|
@Override
|
||||||
public String name() {
|
public String getInternalName() {
|
||||||
return getInternalName();
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -186,7 +186,13 @@ class TypeToInsertString implements ResultSetVisitor{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(TypePlaceholder typePlaceholder) {
|
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
|
@Override
|
||||||
|
@ -17,6 +17,7 @@ import static org.junit.Assert.*;
|
|||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
@ -341,7 +342,7 @@ public class TestCodegen {
|
|||||||
public void testLambda() throws Exception {
|
public void testLambda() throws Exception {
|
||||||
var classLoader = new ByteArrayClassLoader();
|
var classLoader = new ByteArrayClassLoader();
|
||||||
//var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class"));
|
//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");
|
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "CGLambda");
|
||||||
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(
|
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(
|
||||||
|
Loading…
Reference in New Issue
Block a user