Merge branch 'targetBytecode' into bigRefactoring
This commit is contained in:
commit
2197e09307
@ -9,5 +9,11 @@ public class OLFun {
|
|||||||
//f = x -> {return x + x;};
|
//f = x -> {return x + x;};
|
||||||
m(f, x) {
|
m(f, x) {
|
||||||
x = f.apply(x+x);
|
x = f.apply(x+x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
m2(y) {
|
||||||
|
m(x -> x * 2, y);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,6 @@ public class OLFun2 {
|
|||||||
|
|
||||||
x;
|
x;
|
||||||
m(f){
|
m(f){
|
||||||
x = f.apply(x + x)
|
x = f.apply(x + x);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -82,6 +82,13 @@ public class Codegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void popValue(State state, TargetType type) {
|
||||||
|
if (type.equals(TargetType.Double) || type.equals(TargetType.Long))
|
||||||
|
state.mv.visitInsn(POP2);
|
||||||
|
else
|
||||||
|
state.mv.visitInsn(POP);
|
||||||
|
}
|
||||||
|
|
||||||
private void boxPrimitive(State state, TargetType type) {
|
private void boxPrimitive(State state, TargetType type) {
|
||||||
var mv = state.mv;
|
var mv = state.mv;
|
||||||
if (type.equals(TargetType.Boolean) || type.equals(TargetType.boolean_)) {
|
if (type.equals(TargetType.Boolean) || type.equals(TargetType.boolean_)) {
|
||||||
@ -705,11 +712,15 @@ public class Codegen {
|
|||||||
} else {
|
} else {
|
||||||
var name = "lambda$" + lambdaCounter++;
|
var name = "lambda$" + lambdaCounter++;
|
||||||
var parameters = new ArrayList<>(lambda.captures());
|
var parameters = new ArrayList<>(lambda.captures());
|
||||||
parameters.addAll(lambda.params());
|
parameters.addAll(lambda.params().stream()
|
||||||
|
.map(param -> param.type() instanceof TargetGenericType ? new MethodParameter(TargetType.Object, param.name()) : param)
|
||||||
|
.toList());
|
||||||
|
|
||||||
impl = new TargetMethod(
|
impl = new TargetMethod(
|
||||||
0, name, Set.of(),
|
0, name, Set.of(), Set.of(),
|
||||||
parameters, lambda.returnType(), lambda.block()
|
parameters,
|
||||||
|
lambda.returnType() instanceof TargetGenericType ? TargetType.Object : lambda.returnType(),
|
||||||
|
lambda.block()
|
||||||
);
|
);
|
||||||
generateMethod(impl);
|
generateMethod(impl);
|
||||||
lambdas.put(lambda, impl);
|
lambdas.put(lambda, impl);
|
||||||
@ -736,7 +747,9 @@ public class Codegen {
|
|||||||
|
|
||||||
var params = new ArrayList<TargetType>();
|
var params = new ArrayList<TargetType>();
|
||||||
params.add(new TargetRefType(clazz.qualifiedName()));
|
params.add(new TargetRefType(clazz.qualifiedName()));
|
||||||
params.addAll(lambda.captures().stream().map(MethodParameter::type).toList());
|
params.addAll(lambda.captures().stream()
|
||||||
|
.map(MethodParameter::type)
|
||||||
|
.toList());
|
||||||
|
|
||||||
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
|
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
@ -760,9 +773,11 @@ public class Codegen {
|
|||||||
for (var e : block.statements()) {
|
for (var e : block.statements()) {
|
||||||
generate(state, e);
|
generate(state, e);
|
||||||
if (e instanceof TargetMethodCall) {
|
if (e instanceof TargetMethodCall) {
|
||||||
if (e.type() != null) mv.visitInsn(POP);
|
if (e.type() != null) popValue(state, e.type());
|
||||||
} else if (e instanceof TargetStatementExpression) {
|
} else if (e instanceof TargetAssign) {
|
||||||
mv.visitInsn(POP);
|
mv.visitInsn(POP); // TODO Nasty fix, we don't know if it is a primitive double or long
|
||||||
|
} else if (e instanceof TargetStatementExpression se) {
|
||||||
|
popValue(state, se.type());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.exitScope();
|
state.exitScope();
|
||||||
@ -879,7 +894,7 @@ public class Codegen {
|
|||||||
if (_for.increment() != null) {
|
if (_for.increment() != null) {
|
||||||
generate(state, _for.increment());
|
generate(state, _for.increment());
|
||||||
if (_for.increment().type() != null) {
|
if (_for.increment().type() != null) {
|
||||||
mv.visitInsn(POP);
|
popValue(state, _for.increment().type());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mv.visitJumpInsn(GOTO, start);
|
mv.visitJumpInsn(GOTO, start);
|
||||||
@ -980,6 +995,9 @@ public class Codegen {
|
|||||||
|
|
||||||
private void generateConstructor(TargetConstructor constructor) {
|
private void generateConstructor(TargetConstructor constructor) {
|
||||||
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
||||||
|
if (!constructor.txGenerics().isEmpty())
|
||||||
|
mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature()));
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
var state = new State(null, mv, 1);
|
var state = new State(null, mv, 1);
|
||||||
for (var param: constructor.parameters())
|
for (var param: constructor.parameters())
|
||||||
@ -1004,6 +1022,9 @@ public class Codegen {
|
|||||||
private void generateMethod(TargetMethod method) {
|
private void generateMethod(TargetMethod method) {
|
||||||
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
|
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
|
||||||
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
|
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||||
|
if (!method.txGenerics().isEmpty())
|
||||||
|
mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
var state = new State(method.returnType(), mv, method.isStatic() ? 0 : 1);
|
var state = new State(method.returnType(), mv, method.isStatic() ? 0 : 1);
|
||||||
for (var param: method.parameters())
|
for (var param: method.parameters())
|
||||||
@ -1015,9 +1036,9 @@ public class Codegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateSignature(TargetClass clazz) {
|
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
|
||||||
String ret = "<";
|
String ret = "<";
|
||||||
for (var generic : clazz.generics()) {
|
for (var generic : generics) {
|
||||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||||
}
|
}
|
||||||
ret += ">";
|
ret += ">";
|
||||||
@ -1028,9 +1049,12 @@ public class Codegen {
|
|||||||
|
|
||||||
public byte[] generate() {
|
public byte[] generate() {
|
||||||
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(),
|
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(),
|
||||||
generateSignature(clazz), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object",
|
generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object",
|
||||||
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
||||||
);
|
);
|
||||||
|
if (!clazz.txGenerics().isEmpty())
|
||||||
|
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
|
||||||
|
|
||||||
clazz.fields().forEach(this::generateField);
|
clazz.fields().forEach(this::generateField);
|
||||||
clazz.constructors().forEach(this::generateConstructor);
|
clazz.constructors().forEach(this::generateConstructor);
|
||||||
clazz.methods().forEach(this::generateMethod);
|
clazz.methods().forEach(this::generateMethod);
|
||||||
|
@ -31,7 +31,7 @@ public class FunNGenerator {
|
|||||||
|
|
||||||
private static String applyDescriptor(TargetType a) { return a.toDescriptor(); }
|
private static String applyDescriptor(TargetType a) { return a.toDescriptor(); }
|
||||||
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("L%s;", applySignature(a)); }
|
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s;", applySignature(a)); }
|
||||||
|
|
||||||
public static byte[] generateSuperBytecode(int numberArguments) {
|
public static byte[] generateSuperBytecode(int numberArguments) {
|
||||||
StringBuilder superFunNClassSignature = new StringBuilder("<");
|
StringBuilder superFunNClassSignature = new StringBuilder("<");
|
||||||
@ -40,13 +40,15 @@ public class FunNGenerator {
|
|||||||
|
|
||||||
for (int currentParameter = 1; currentParameter <= numberArguments; currentParameter++){
|
for (int currentParameter = 1; currentParameter <= numberArguments; currentParameter++){
|
||||||
superFunNClassSignature.append(String.format("%s%d:%s",argumentGenericBase, currentParameter, objectSignature));
|
superFunNClassSignature.append(String.format("%s%d:%s",argumentGenericBase, currentParameter, objectSignature));
|
||||||
superFunNMethodSignature.append(String.format("T%s;", applySignature(new TargetRefType(argumentGenericBase + currentParameter))));
|
superFunNMethodSignature.append(String.format("%s", applySignature(new TargetRefType(argumentGenericBase + currentParameter))));
|
||||||
superFunNMethodDescriptor.append(objectSignature);
|
superFunNMethodDescriptor.append(objectSignature);
|
||||||
}
|
}
|
||||||
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
|
superFunNClassSignature.append(String.format("%s:%s>%s", returnGeneric, objectSignature, objectSignature));
|
||||||
superFunNMethodSignature.append(String.format(")T%s;", applySignature(new TargetRefType(returnGeneric))));
|
superFunNMethodSignature.append(String.format(")%s", applySignature(new TargetRefType(returnGeneric))));
|
||||||
superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
|
superFunNMethodDescriptor.append(String.format(")%s", objectSignature));
|
||||||
|
|
||||||
|
System.out.println(superFunNMethodSignature);
|
||||||
|
|
||||||
ClassWriter classWriter = new ClassWriter(0);
|
ClassWriter classWriter = new ClassWriter(0);
|
||||||
MethodVisitor methodVisitor;
|
MethodVisitor methodVisitor;
|
||||||
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments), superFunNClassSignature.toString(), objectSuperType, null);
|
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSuperClassName(numberArguments), superFunNClassSignature.toString(), objectSuperType, null);
|
||||||
|
@ -2,6 +2,9 @@ package de.dhbwstuttgart.bytecode;
|
|||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class JavaTXSignatureAttribute extends Attribute {
|
public class JavaTXSignatureAttribute extends Attribute {
|
||||||
final String signature;
|
final String signature;
|
||||||
|
|
||||||
@ -12,7 +15,9 @@ public class JavaTXSignatureAttribute extends Attribute {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
||||||
return super.read(classReader, offset, length, charBuffer, codeAttributeOffset, labels);
|
var data = new byte[length];
|
||||||
|
System.arraycopy(classReader.b, offset, data, 0, length);
|
||||||
|
return new JavaTXSignatureAttribute(new String(data, StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,6 +2,7 @@ package de.dhbwstuttgart.parser.SyntaxTreeGenerator;
|
|||||||
|
|
||||||
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||||
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
import de.dhbwstuttgart.exceptions.TypeinferenceException;
|
||||||
|
import de.dhbwstuttgart.parser.NullToken;
|
||||||
import de.dhbwstuttgart.parser.antlr.Java8Parser;
|
import de.dhbwstuttgart.parser.antlr.Java8Parser;
|
||||||
import de.dhbwstuttgart.parser.antlr.Java8Parser.UnannClassType_lfno_unannClassOrInterfaceTypeContext;
|
import de.dhbwstuttgart.parser.antlr.Java8Parser.UnannClassType_lfno_unannClassOrInterfaceTypeContext;
|
||||||
import de.dhbwstuttgart.parser.scope.GenericsRegistry;
|
import de.dhbwstuttgart.parser.scope.GenericsRegistry;
|
||||||
@ -169,7 +170,7 @@ public class TypeGenerator {
|
|||||||
return new SuperWildcardType(convert(wildcardContext.wildcardBounds().referenceType(), reg, generics), wildcardContext.getStart());
|
return new SuperWildcardType(convert(wildcardContext.wildcardBounds().referenceType(), reg, generics), wildcardContext.getStart());
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
throw new NotImplementedException(); //Wildcard ohne Bound
|
return new ExtendsWildcardType(new RefType(new JavaClassName("Object"), new NullToken()), wildcardContext.getStart());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ public class ASTToTargetAST {
|
|||||||
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
||||||
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
||||||
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
|
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
|
||||||
|
Map<TypePlaceholder, TypePlaceholder> txEquality = new HashMap<>();
|
||||||
|
|
||||||
Sigma(ResultSet constraints) {
|
Sigma(ResultSet constraints) {
|
||||||
ASTToTargetAST.this.sigma = this;
|
ASTToTargetAST.this.sigma = this;
|
||||||
@ -55,6 +56,7 @@ public class ASTToTargetAST {
|
|||||||
simplifiedConstraints.add(p);
|
simplifiedConstraints.add(p);
|
||||||
} else if (constraint instanceof PairTPHEqualTPH p) {
|
} else if (constraint instanceof PairTPHEqualTPH p) {
|
||||||
equality.put(p.getLeft(), p.getRight());
|
equality.put(p.getLeft(), p.getRight());
|
||||||
|
txEquality.put(p.getLeft(), p.getRight());
|
||||||
} else if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) {
|
} else if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) {
|
||||||
concreteTypes.put(this.equality.getOrDefault(p.left, p.left), p.right);
|
concreteTypes.put(this.equality.getOrDefault(p.left, p.left), p.right);
|
||||||
}
|
}
|
||||||
@ -63,22 +65,22 @@ public class ASTToTargetAST {
|
|||||||
System.out.println("Simplified constraints: " + simplifiedConstraints);
|
System.out.println("Simplified constraints: " + simplifiedConstraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<TypePlaceholder> findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type) {
|
Set<TypePlaceholder> findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
var result = new HashSet<TypePlaceholder>();
|
var result = new HashSet<TypePlaceholder>();
|
||||||
if (type instanceof TypePlaceholder tph) {
|
if (type instanceof TypePlaceholder tph) {
|
||||||
tph = equality.getOrDefault(tph, tph);
|
tph = equality.getOrDefault(tph, tph);
|
||||||
if (concreteTypes.containsKey(tph)) {
|
if (concreteTypes.containsKey(tph)) {
|
||||||
result.addAll(findTypeVariables(concreteTypes.get(tph)));
|
result.addAll(findTypeVariables(concreteTypes.get(tph), equality));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result.add(tph);
|
result.add(tph);
|
||||||
} else if (type instanceof RefType refType) {
|
} else if (type instanceof RefType refType) {
|
||||||
for (var t : refType.getParaList())
|
for (var t : refType.getParaList())
|
||||||
result.addAll(findTypeVariables(t));
|
result.addAll(findTypeVariables(t, equality));
|
||||||
} else if (type instanceof ExtendsWildcardType wildcardType) {
|
} else if (type instanceof ExtendsWildcardType wildcardType) {
|
||||||
result.addAll(findTypeVariables(wildcardType.getInnerType()));
|
result.addAll(findTypeVariables(wildcardType.getInnerType(), equality));
|
||||||
} else if (type instanceof SuperWildcardType wildcardType) {
|
} else if (type instanceof SuperWildcardType wildcardType) {
|
||||||
result.addAll(findTypeVariables(wildcardType.getInnerType()));
|
result.addAll(findTypeVariables(wildcardType.getInnerType(), equality));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -135,143 +137,109 @@ public class ASTToTargetAST {
|
|||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Family of generated Generics
|
private void methodFindConstraints(
|
||||||
Generics generics(ClassOrInterface owner, Method method) {
|
ClassOrInterface owner, Method method,
|
||||||
if (computedGenericsOfMethods.containsKey(method))
|
Set<PairTPHsmallerTPH> simplifiedConstraints,
|
||||||
return computedGenericsOfMethods.get(method);
|
HashSet<TypePlaceholder> typeVariables,
|
||||||
|
HashSet<TypePlaceholder> typeVariablesOfClass,
|
||||||
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
Set<ResultPair<?, ?>> result,
|
||||||
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
Map<TypePlaceholder, TypePlaceholder> equality
|
||||||
var generics = new Generics(javaResult, txResult);
|
) {
|
||||||
computedGenericsOfMethods.put(method, generics);
|
|
||||||
|
|
||||||
var genericsOfClass = generics(owner).txGenerics();
|
|
||||||
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
|
|
||||||
|
|
||||||
HashSet<TypePlaceholder> typeVariables = new HashSet<>();
|
|
||||||
HashSet<TypePlaceholder> typeVariablesOfClass = new HashSet<>();
|
|
||||||
|
|
||||||
for (var pair : genericsOfClass) {
|
|
||||||
typeVariablesOfClass.add((TypePlaceholder) pair.getLeft());
|
|
||||||
}
|
|
||||||
|
|
||||||
typeVariables.addAll(findTypeVariables(method.getReturnType()));
|
|
||||||
for (var arg : method.getParameterList().getFormalparalist()) {
|
|
||||||
typeVariables.addAll(findTypeVariables(arg.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
method.block.accept(new TracingStatementVisitor() {
|
|
||||||
@Override
|
|
||||||
public void visit(LocalVarDecl localVarDecl) {
|
|
||||||
typeVariables.addAll(findTypeVariables(localVarDecl.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(MethodCall methodCall) {
|
|
||||||
super.visit(methodCall);
|
|
||||||
typeVariables.addAll(findTypeVariables(methodCall.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Assign assign) {}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Type variables with bounds that are also type variables of the method
|
// Type variables with bounds that are also type variables of the method
|
||||||
for (var typeVariable : new HashSet<>(typeVariables)) {
|
for (var typeVariable : new HashSet<>(typeVariables)) {
|
||||||
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
||||||
for (var pair : simplifiedConstraints) {
|
for (var pair : simplifiedConstraints) {
|
||||||
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
|
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
|
||||||
addToPairs(txResult, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
|
addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
|
||||||
typeVariables.add(pair.right);
|
typeVariables.add(pair.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
method.block.accept(new TracingStatementVisitor() {
|
method.block.accept(new TracingStatementVisitor() {
|
||||||
|
|
||||||
private RefTypeOrTPHOrWildcardOrGeneric superType = new Void(new NullToken());
|
private RefTypeOrTPHOrWildcardOrGeneric superType = new Void(new NullToken());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MethodCall methodCall) {
|
public void visit(MethodCall methodCall) {
|
||||||
//Anfang es werden Paare von TPHs gespeichert, die bei den Generated Generics ueber die Methodengrenzen hinweg
|
//Anfang es werden Paare von TPHs gespeichert, die bei den Generated Generics ueber die Methodengrenzen hinweg
|
||||||
//betrachtet werden muessen
|
//betrachtet werden muessen
|
||||||
//Definition 7.2 (Family of generated generics). T1 <. R1 <.^∗ R2 <. T2
|
//Definition 7.2 (Family of generated generics). T1 <. R1 <.^∗ R2 <. T2
|
||||||
Set<RefTypeOrTPHOrWildcardOrGeneric> T1s =
|
Set<RefTypeOrTPHOrWildcardOrGeneric> T1s =
|
||||||
methodCall.getArgumentList()
|
methodCall.getArgumentList()
|
||||||
.getArguments()
|
.getArguments()
|
||||||
.stream()
|
.stream()
|
||||||
.map(TypableStatement::getType)
|
.map(TypableStatement::getType)
|
||||||
.collect(Collectors.toCollection(HashSet::new))
|
.collect(Collectors.toCollection(HashSet::new))
|
||||||
.stream().filter(x -> x instanceof TypePlaceholder)
|
.stream().filter(x -> x instanceof TypePlaceholder)
|
||||||
.map(tph -> equality.getOrDefault(tph, (TypePlaceholder) tph))
|
.map(tph -> equality.getOrDefault(tph, (TypePlaceholder) tph))
|
||||||
.collect(Collectors.toCollection(HashSet::new));
|
.collect(Collectors.toCollection(HashSet::new));
|
||||||
RefTypeOrTPHOrWildcardOrGeneric T2 = superType;
|
RefTypeOrTPHOrWildcardOrGeneric T2 = superType;
|
||||||
if (T2 instanceof TypePlaceholder tph) T2 = equality.getOrDefault(tph, tph);
|
if (T2 instanceof TypePlaceholder tph) T2 = equality.getOrDefault(tph, tph);
|
||||||
|
|
||||||
System.out.println("T1s: " + T1s + "\nT2: " + T2);
|
System.out.println("T1s: " + T1s + "\nT2: " + T2);
|
||||||
//Ende
|
//Ende
|
||||||
|
|
||||||
superType = methodCall.receiverType;
|
superType = methodCall.receiverType;
|
||||||
methodCall.receiver.accept(this);
|
methodCall.receiver.accept(this);
|
||||||
for(int i = 0;i<methodCall.arglist.getArguments().size();i++){
|
for(int i = 0;i<methodCall.arglist.getArguments().size();i++){
|
||||||
superType = methodCall.signature.get(i);
|
superType = methodCall.signature.get(i);
|
||||||
methodCall.arglist.getArguments().get(i).accept(this);
|
methodCall.arglist.getArguments().get(i).accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
|
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
|
||||||
if (expressionReceiver.expr instanceof This) {
|
if (expressionReceiver.expr instanceof This) {
|
||||||
var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList());
|
var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList());
|
||||||
if (optMethod.isEmpty()) return;
|
if (optMethod.isEmpty()) return;
|
||||||
var method = optMethod.get();
|
var method = optMethod.get();
|
||||||
|
|
||||||
var generics = generics(owner, method).txGenerics();
|
var generics = generics(owner, method).javaGenerics();
|
||||||
|
|
||||||
// transitive and
|
// transitive and
|
||||||
var all = transitiveClosure(generics);
|
var all = transitiveClosure(generics);
|
||||||
// reflexive
|
// reflexive
|
||||||
var toAdd = new HashSet<ResultPair<?, ?>>();
|
var toAdd = new HashSet<ResultPair<?, ?>>();
|
||||||
for (var generic : all) {
|
for (var generic : all) {
|
||||||
toAdd.add(new PairTPHsmallerTPH((TypePlaceholder) generic.getLeft(), (TypePlaceholder) generic.getLeft()));
|
toAdd.add(new PairTPHsmallerTPH((TypePlaceholder) generic.getLeft(), (TypePlaceholder) generic.getLeft()));
|
||||||
}
|
}
|
||||||
all.addAll(toAdd);
|
all.addAll(toAdd);
|
||||||
|
|
||||||
HashSet<PairTPHsmallerTPH> newPairs = new HashSet<>();
|
HashSet<PairTPHsmallerTPH> newPairs = new HashSet<>();
|
||||||
|
|
||||||
// Loop from hell
|
// Loop from hell
|
||||||
outer:
|
outer:
|
||||||
for (var tph : typeVariables) {
|
for (var tph : typeVariables) {
|
||||||
if (typeVariablesOfClass.contains(tph)) continue;
|
if (typeVariablesOfClass.contains(tph)) continue;
|
||||||
for (var generic : all) {
|
for (var generic : all) {
|
||||||
if (!(generic.getRight() instanceof TypePlaceholder type))
|
if (!(generic.getRight() instanceof TypePlaceholder type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (var pair : simplifiedConstraints) {
|
for (var pair : simplifiedConstraints) {
|
||||||
if (!(pair.left.equals(tph) && pair.right.equals(generic.getLeft())))
|
if (!(pair.left.equals(tph) && pair.right.equals(generic.getLeft())))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (var tph2 : typeVariables) {
|
for (var tph2 : typeVariables) {
|
||||||
for (var pair2 : simplifiedConstraints) {
|
for (var pair2 : simplifiedConstraints) {
|
||||||
if (!(pair2.right.equals(tph2) && pair2.left.equals(type)))
|
if (!(pair2.right.equals(tph2) && pair2.left.equals(type)))
|
||||||
continue;
|
continue;
|
||||||
if (tph.equals(tph2)) continue;
|
if (tph.equals(tph2)) continue;
|
||||||
if (!T1s.contains(tph) || !tph2.equals(T2)) continue;
|
if (!T1s.contains(tph) || !tph2.equals(T2)) continue;
|
||||||
|
|
||||||
var newPair = new PairTPHsmallerTPH(tph, tph2);
|
var newPair = new PairTPHsmallerTPH(tph, tph2);
|
||||||
newPairs.add(newPair);
|
newPairs.add(newPair);
|
||||||
|
|
||||||
if (!containsRelation(txResult, newPair))
|
if (!containsRelation(result, newPair))
|
||||||
addToPairs(txResult, newPair);
|
addToPairs(result, newPair);
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
simplifiedConstraints.addAll(newPairs);
|
simplifiedConstraints.addAll(newPairs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -474,18 +442,19 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (minimalPair != null)
|
if (minimalPair != null)
|
||||||
addToPairs(txResult, minimalPair);
|
addToPairs(result, minimalPair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// All unbounded type variables (bounds not in method)
|
// All unbounded type variables (bounds not in method)
|
||||||
outer:
|
outer:
|
||||||
for (var typeVariable : typeVariables) {
|
for (var typeVariable : typeVariables) {
|
||||||
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
||||||
for (var pair : txResult) {
|
for (var pair : result) {
|
||||||
if (pair.getLeft().equals(typeVariable))
|
if (pair.getLeft().equals(typeVariable))
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
addToPairs(txResult, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
|
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// All unbounded bounds
|
// All unbounded bounds
|
||||||
@ -496,44 +465,112 @@ public class ASTToTargetAST {
|
|||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
if (!typeVariablesOfClass.contains(pair.right) && typeVariables.contains(pair.right)) {
|
if (!typeVariablesOfClass.contains(pair.right) && typeVariables.contains(pair.right)) {
|
||||||
addToPairs(txResult, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
javaResult.addAll(txResult); // Same result until here
|
private void methodFindTypeVariables(
|
||||||
eliminateCycles(javaResult);
|
Method method,
|
||||||
eliminateInfima(javaResult);
|
Set<ResultPair<?, ?>> genericsOfClass,
|
||||||
eliminateInfima(txResult);
|
Set<TypePlaceholder> typeVariablesOfClass,
|
||||||
|
Set<TypePlaceholder> typeVariables,
|
||||||
|
Map<TypePlaceholder, TypePlaceholder> equality
|
||||||
|
) {
|
||||||
|
|
||||||
// For eliminating inner type variables we need to figure out which ones are actually used
|
for (var pair : genericsOfClass) {
|
||||||
// TODO Maybe don't do this twice?
|
typeVariablesOfClass.add((TypePlaceholder) pair.getLeft());
|
||||||
var usedTphs = new HashSet<TypePlaceholder>();
|
|
||||||
for (var param : method.getParameterList().getFormalparalist()) {
|
|
||||||
usedTphs.addAll(findTypeVariables(param.getType()));
|
|
||||||
}
|
}
|
||||||
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
|
||||||
var referenced = new HashSet<>(usedTphs);
|
|
||||||
referenced.addAll(typeVariablesOfClass);
|
|
||||||
|
|
||||||
eliminateInnerTypeVariables(referenced, javaResult);
|
typeVariables.addAll(findTypeVariables(method.getReturnType(), equality));
|
||||||
eliminateInnerTypeVariables(referenced, txResult);
|
for (var arg : method.getParameterList().getFormalparalist()) {
|
||||||
|
typeVariables.addAll(findTypeVariables(arg.getType(), equality));
|
||||||
|
}
|
||||||
|
|
||||||
usedTPHsOfMethods.put(method, usedTphs);
|
method.block.accept(new TracingStatementVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visit(LocalVarDecl localVarDecl) {
|
||||||
|
typeVariables.addAll(findTypeVariables(localVarDecl.getType(), equality));
|
||||||
|
}
|
||||||
|
|
||||||
equalizeTypeVariables(javaResult);
|
@Override
|
||||||
|
public void visit(MethodCall methodCall) {
|
||||||
|
super.visit(methodCall);
|
||||||
|
typeVariables.addAll(findTypeVariables(methodCall.getType(), equality));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Assign assign) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Family of generated Generics
|
||||||
|
Generics generics(ClassOrInterface owner, Method method) {
|
||||||
|
if (computedGenericsOfMethods.containsKey(method))
|
||||||
|
return computedGenericsOfMethods.get(method);
|
||||||
|
|
||||||
|
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
||||||
|
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
||||||
|
var generics = new Generics(javaResult, txResult);
|
||||||
|
computedGenericsOfMethods.put(method, generics);
|
||||||
|
|
||||||
|
var genericsOfClass = generics(owner).javaGenerics();
|
||||||
|
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
|
||||||
|
|
||||||
|
HashSet<TypePlaceholder> txTypeVariables = new HashSet<>();
|
||||||
|
HashSet<TypePlaceholder> javaTypeVariables = new HashSet<>();
|
||||||
|
HashSet<TypePlaceholder> txTypeVariablesOfClass = new HashSet<>();
|
||||||
|
HashSet<TypePlaceholder> javaTypeVariablesOfClass = new HashSet<>();
|
||||||
|
|
||||||
|
methodFindTypeVariables(method, genericsOfClass, javaTypeVariablesOfClass, javaTypeVariables, equality);
|
||||||
|
methodFindTypeVariables(method, genericsOfClass, txTypeVariablesOfClass, txTypeVariables, txEquality);
|
||||||
|
|
||||||
|
methodFindConstraints(owner, method, simplifiedConstraints, javaTypeVariables, javaTypeVariablesOfClass, javaResult, equality);
|
||||||
|
methodFindConstraints(owner, method, simplifiedConstraints, txTypeVariables, txTypeVariablesOfClass, txResult, txEquality);
|
||||||
|
|
||||||
|
{ // Java Generics
|
||||||
|
eliminateCycles(javaResult, equality);
|
||||||
|
eliminateInfima(javaResult, equality);
|
||||||
|
|
||||||
|
var usedTphs = new HashSet<TypePlaceholder>();
|
||||||
|
// For eliminating inner type variables we need to figure out which ones are actually used
|
||||||
|
// TODO Maybe don't do this twice?
|
||||||
|
for (var param : method.getParameterList().getFormalparalist()) {
|
||||||
|
usedTphs.addAll(findTypeVariables(param.getType(), equality));
|
||||||
|
}
|
||||||
|
usedTphs.addAll(findTypeVariables(method.getReturnType(), equality));
|
||||||
|
var referenced = new HashSet<>(usedTphs);
|
||||||
|
referenced.addAll(javaTypeVariablesOfClass);
|
||||||
|
|
||||||
|
eliminateInnerTypeVariables(referenced, javaResult);
|
||||||
|
equalizeTypeVariables(javaResult, equality);
|
||||||
|
usedTPHsOfMethods.put(method, usedTphs);
|
||||||
|
}
|
||||||
|
{ // JavaTX Generics
|
||||||
|
eliminateInfima(txResult, txEquality);
|
||||||
|
|
||||||
|
var referenced = new HashSet<TypePlaceholder>();
|
||||||
|
for (var param : method.getParameterList().getFormalparalist()) {
|
||||||
|
referenced.addAll(findTypeVariables(param.getType(), txEquality));
|
||||||
|
}
|
||||||
|
referenced.addAll(findTypeVariables(method.getReturnType(), txEquality));
|
||||||
|
referenced.addAll(txTypeVariablesOfClass);
|
||||||
|
|
||||||
|
eliminateInnerTypeVariables(referenced, txResult);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
||||||
|
|
||||||
return generics;
|
return generics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics) {
|
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
if (type instanceof TypePlaceholder tph) {
|
if (type instanceof TypePlaceholder tph) {
|
||||||
tph = equality.getOrDefault(tph, tph);
|
tph = equality.getOrDefault(tph, tph);
|
||||||
|
|
||||||
var concreteType = concreteTypes.get(tph);
|
var concreteType = concreteTypes.get(tph);
|
||||||
if (concreteType != null) {
|
if (concreteType != null) {
|
||||||
findAllBounds(concreteType, generics);
|
findAllBounds(concreteType, generics, equality);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +582,7 @@ public class ASTToTargetAST {
|
|||||||
var pair = new PairTPHsmallerTPH(tph, right);
|
var pair = new PairTPHsmallerTPH(tph, right);
|
||||||
if (!generics.contains(pair)) {
|
if (!generics.contains(pair)) {
|
||||||
generics.add(pair);
|
generics.add(pair);
|
||||||
findAllBounds(right, generics);
|
findAllBounds(right, generics, equality);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,7 +590,7 @@ public class ASTToTargetAST {
|
|||||||
if (!found)
|
if (!found)
|
||||||
generics.add(new PairTPHequalRefTypeOrWildcardType(tph, OBJECT));
|
generics.add(new PairTPHequalRefTypeOrWildcardType(tph, OBJECT));
|
||||||
} else if (type instanceof RefType refType) {
|
} else if (type instanceof RefType refType) {
|
||||||
refType.getParaList().forEach(t -> findAllBounds(t, generics));
|
refType.getParaList().forEach(t -> findAllBounds(t, generics, equality));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,25 +601,29 @@ public class ASTToTargetAST {
|
|||||||
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
||||||
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
||||||
var generics = new Generics(javaResult, txResult);
|
var generics = new Generics(javaResult, txResult);
|
||||||
|
|
||||||
for (var field : classOrInterface.getFieldDecl()) {
|
|
||||||
findAllBounds(field.getType(), txResult);
|
|
||||||
}
|
|
||||||
computedGenericsOfClasses.put(classOrInterface, generics);
|
computedGenericsOfClasses.put(classOrInterface, generics);
|
||||||
|
|
||||||
javaResult.addAll(txResult);
|
for (var field : classOrInterface.getFieldDecl()) {
|
||||||
eliminateCycles(javaResult);
|
findAllBounds(field.getType(), javaResult, equality);
|
||||||
eliminateInfima(txResult);
|
findAllBounds(field.getType(), txResult, txEquality);
|
||||||
eliminateInfima(javaResult);
|
}
|
||||||
eliminateInnerTypeVariablesOfClass(classOrInterface, txResult);
|
|
||||||
eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult);
|
{ // Java Generics
|
||||||
equalizeTypeVariables(javaResult);
|
eliminateCycles(javaResult, equality);
|
||||||
|
eliminateInfima(javaResult, equality);
|
||||||
|
eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult, equality);
|
||||||
|
equalizeTypeVariables(javaResult, equality);
|
||||||
|
}
|
||||||
|
{ // TX Generics
|
||||||
|
eliminateInfima(txResult, txEquality);
|
||||||
|
eliminateInnerTypeVariablesOfClass(classOrInterface, txResult, txEquality);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult);
|
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult);
|
||||||
return generics;
|
return generics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void equalizeTypeVariables(Set<ResultPair<?, ?>> input) {
|
void equalizeTypeVariables(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
for (var pair : new HashSet<>(input)) {
|
for (var pair : new HashSet<>(input)) {
|
||||||
if (pair instanceof PairTPHsmallerTPH ptph) {
|
if (pair instanceof PairTPHsmallerTPH ptph) {
|
||||||
if (ptph.left.getVariance() == 1 && ptph.right.getVariance() == -1) {
|
if (ptph.left.getVariance() == 1 && ptph.right.getVariance() == -1) {
|
||||||
@ -599,24 +640,24 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void findTphs(RefTypeOrTPHOrWildcardOrGeneric type, Set<TypePlaceholder> tphs) {
|
void findTphs(RefTypeOrTPHOrWildcardOrGeneric type, Set<TypePlaceholder> tphs, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
if (type instanceof RefType refType) {
|
if (type instanceof RefType refType) {
|
||||||
refType.getParaList().forEach(t -> findTphs(t, tphs));
|
refType.getParaList().forEach(t -> findTphs(t, tphs, equality));
|
||||||
} else if (type instanceof TypePlaceholder tph) {
|
} else if (type instanceof TypePlaceholder tph) {
|
||||||
tph = equality.getOrDefault(tph, tph);
|
tph = equality.getOrDefault(tph, tph);
|
||||||
var concreteType = concreteTypes.get(tph);
|
var concreteType = concreteTypes.get(tph);
|
||||||
if (concreteType != null) {
|
if (concreteType != null) {
|
||||||
findTphs(concreteType, tphs);
|
findTphs(concreteType, tphs, equality);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tphs.add(tph);
|
tphs.add(tph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void eliminateInnerTypeVariablesOfClass(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> input) {
|
void eliminateInnerTypeVariablesOfClass(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
Set<TypePlaceholder> referenced = new HashSet<>();
|
Set<TypePlaceholder> referenced = new HashSet<>();
|
||||||
for (var field : classOrInterface.getFieldDecl()) {
|
for (var field : classOrInterface.getFieldDecl()) {
|
||||||
findTphs(field.getType(), referenced);
|
findTphs(field.getType(), referenced, equality);
|
||||||
}
|
}
|
||||||
for (var method : classOrInterface.getMethods()) {
|
for (var method : classOrInterface.getMethods()) {
|
||||||
generics(classOrInterface, method);
|
generics(classOrInterface, method);
|
||||||
@ -668,7 +709,7 @@ public class ASTToTargetAST {
|
|||||||
input.addAll(output);
|
input.addAll(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eliminateCycles(Set<ResultPair<?, ?>> input) {
|
void eliminateCycles(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
var cycles = findCycles(input);
|
var cycles = findCycles(input);
|
||||||
for (var cycle : cycles) {
|
for (var cycle : cycles) {
|
||||||
var newTph = TypePlaceholder.fresh(new NullToken());
|
var newTph = TypePlaceholder.fresh(new NullToken());
|
||||||
@ -684,7 +725,7 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void eliminateInfima(Set<ResultPair<?, ?>> input) {
|
void eliminateInfima(Set<ResultPair<?, ?>> input, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
var foundInfima = false;
|
var foundInfima = false;
|
||||||
do {
|
do {
|
||||||
foundInfima = false;
|
foundInfima = false;
|
||||||
@ -726,19 +767,19 @@ public class ASTToTargetAST {
|
|||||||
} while (foundInfima);
|
} while (foundInfima);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
if (type instanceof TypePlaceholder tph) {
|
if (type instanceof TypePlaceholder tph) {
|
||||||
if (equality.containsKey(tph)) {
|
if (equality.containsKey(tph)) {
|
||||||
return getType(equality.get(tph));
|
return getType(equality.get(tph), equality);
|
||||||
}
|
}
|
||||||
return concreteTypes.getOrDefault(tph, tph);
|
return concreteTypes.getOrDefault(tph, tph);
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetType getTargetType(TypePlaceholder tph) {
|
TargetType getTargetType(TypePlaceholder tph, Map<TypePlaceholder, TypePlaceholder> equality) {
|
||||||
if (equality.containsKey(tph)) {
|
if (equality.containsKey(tph)) {
|
||||||
return getTargetType(equality.get(tph));
|
return getTargetType(equality.get(tph), equality);
|
||||||
}
|
}
|
||||||
var type = concreteTypes.get(tph);
|
var type = concreteTypes.get(tph);
|
||||||
if (type == null) return new TargetGenericType(tph.getName());
|
if (type == null) return new TargetGenericType(tph.getName());
|
||||||
@ -898,18 +939,21 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
public TargetClass convert(ClassOrInterface input) {
|
public TargetClass convert(ClassOrInterface input) {
|
||||||
currentClass = input;
|
currentClass = input;
|
||||||
Set<TargetGeneric> generics = new HashSet<>();
|
Set<TargetGeneric> javaGenerics = new HashSet<>();
|
||||||
|
Set<TargetGeneric> txGenerics = new HashSet<>();
|
||||||
var genericsIter = input.getGenerics().iterator();
|
var genericsIter = input.getGenerics().iterator();
|
||||||
if (genericsIter.hasNext()) {
|
if (genericsIter.hasNext()) {
|
||||||
// Add empty set of generics to cache so that it doesn't try to calculate it later
|
// Add empty set of generics to cache so that it doesn't try to calculate it later
|
||||||
sigma.computedGenericsOfClasses.put(input, new Generics(new HashSet<>(), new HashSet<>()));
|
sigma.computedGenericsOfClasses.put(input, new Generics(new HashSet<>(), new HashSet<>()));
|
||||||
while (genericsIter.hasNext()) {
|
while (genericsIter.hasNext()) {
|
||||||
var next = genericsIter.next();
|
var next = genericsIter.next();
|
||||||
generics.addAll(convert(next));
|
javaGenerics.addAll(convert(next));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Generate generics only if there are no user defined ones
|
// Generate generics only if there are no user defined ones
|
||||||
generics = convert(sigma.generics(input).javaGenerics());
|
var generics = sigma.generics(input);
|
||||||
|
javaGenerics = convert(generics.javaGenerics());
|
||||||
|
txGenerics = convert(generics.txGenerics());
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetBlock fieldInitializer = null;
|
TargetBlock fieldInitializer = null;
|
||||||
@ -918,7 +962,7 @@ public class ASTToTargetAST {
|
|||||||
TargetBlock finalFieldInitializer = fieldInitializer;
|
TargetBlock finalFieldInitializer = fieldInitializer;
|
||||||
|
|
||||||
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
|
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
|
||||||
generics,
|
javaGenerics, txGenerics,
|
||||||
input.getSuperInterfaces().stream().map(this::convert).toList(),
|
input.getSuperInterfaces().stream().map(this::convert).toList(),
|
||||||
input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(),
|
input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(),
|
||||||
input.getFieldDecl().stream().map(this::convert).toList(),
|
input.getFieldDecl().stream().map(this::convert).toList(),
|
||||||
@ -935,7 +979,7 @@ public class ASTToTargetAST {
|
|||||||
return generics.stream().anyMatch(g -> g.name().equals(type.getParsedName()));
|
return generics.stream().anyMatch(g -> g.name().equals(type.getParsedName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<TargetGeneric> collectMethodGenerics(Set<ResultPair<?, ?>> generics, Method input) {
|
private Set<TargetGeneric> collectMethodGenerics(Set<ResultPair<?, ?>> generics, Map<TypePlaceholder, TypePlaceholder> equality, Method input) {
|
||||||
var convertedGenerics = new HashSet<>(convert(generics));
|
var convertedGenerics = new HashSet<>(convert(generics));
|
||||||
outer:
|
outer:
|
||||||
for (GenericTypeVar typeVar : input.getGenerics()) {
|
for (GenericTypeVar typeVar : input.getGenerics()) {
|
||||||
@ -946,12 +990,12 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
convertedGenerics.addAll(convert(typeVar));
|
convertedGenerics.addAll(convert(typeVar));
|
||||||
}
|
}
|
||||||
var returnType = sigma.getType(input.getReturnType());
|
var returnType = sigma.getType(input.getReturnType(), equality);
|
||||||
if ((returnType instanceof GenericRefType refType) && !hasGeneric(convertedGenerics, refType)) {
|
if ((returnType instanceof GenericRefType refType) && !hasGeneric(convertedGenerics, refType)) {
|
||||||
convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT)));
|
convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT)));
|
||||||
}
|
}
|
||||||
for (var param : input.getParameterList()) {
|
for (var param : input.getParameterList()) {
|
||||||
var type = sigma.getType(param.getType());
|
var type = sigma.getType(param.getType(), equality);
|
||||||
if (type instanceof GenericRefType refType && !hasGeneric(convertedGenerics, refType)) {
|
if (type instanceof GenericRefType refType && !hasGeneric(convertedGenerics, refType)) {
|
||||||
convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT)));
|
convertedGenerics.add(new TargetGeneric(refType.getParsedName(), convert(OBJECT)));
|
||||||
}
|
}
|
||||||
@ -970,8 +1014,10 @@ public class ASTToTargetAST {
|
|||||||
var generics = sigma.generics(currentClass, input);
|
var generics = sigma.generics(currentClass, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
var convertedGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
var javaGenerics = collectMethodGenerics(generics.javaGenerics(), sigma.equality, input);
|
||||||
result.add(new TargetConstructor(input.modifier, convertedGenerics, params, convert(input.block), fieldInitializer));
|
var txGenerics = collectMethodGenerics(generics.txGenerics(), sigma.txEquality, input);
|
||||||
|
|
||||||
|
result.add(new TargetConstructor(input.modifier, javaGenerics, txGenerics, params, convert(input.block), fieldInitializer));
|
||||||
parameterSet.add(params);
|
parameterSet.add(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,10 +1035,12 @@ public class ASTToTargetAST {
|
|||||||
var generics = sigma.generics(currentClass, input);
|
var generics = sigma.generics(currentClass, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
var convertedGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
var javaGenerics = collectMethodGenerics(generics.javaGenerics(), sigma.equality, input);
|
||||||
|
var txGenerics = collectMethodGenerics(generics.txGenerics(), sigma.txEquality, input);
|
||||||
|
|
||||||
result.add(new TargetMethod(
|
result.add(new TargetMethod(
|
||||||
input.modifier,
|
input.modifier,
|
||||||
input.name, convertedGenerics, params,
|
input.name, javaGenerics, txGenerics, params,
|
||||||
convert(input.getReturnType()),
|
convert(input.getReturnType()),
|
||||||
convert(input.block)
|
convert(input.block)
|
||||||
));
|
));
|
||||||
@ -1060,7 +1108,7 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetType visit(TypePlaceholder typePlaceholder) {
|
public TargetType visit(TypePlaceholder typePlaceholder) {
|
||||||
return sigma.getTargetType(typePlaceholder);
|
return sigma.getTargetType(typePlaceholder, sigma.equality);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,7 +16,7 @@ public class GenericsResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
||||||
var generics = this.sigma.computedGenericsOfClasses.get(clazz);
|
var generics = this.sigma.computedGenericsOfClasses.get(clazz);
|
||||||
if (generics == null) return Set.of();
|
if (generics == null) return Set.of();
|
||||||
return generics.txGenerics();
|
return generics.txGenerics();
|
||||||
}
|
}
|
||||||
@ -67,7 +67,13 @@ public class GenericsResult {
|
|||||||
|
|
||||||
public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) {
|
public RefTypeOrTPHOrWildcardOrGeneric resolve(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
if (type instanceof TypePlaceholder tph)
|
if (type instanceof TypePlaceholder tph)
|
||||||
return this.sigma.getType(tph);
|
return this.sigma.getType(tph, sigma.equality);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefTypeOrTPHOrWildcardOrGeneric resolveTx(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
|
if (type instanceof TypePlaceholder tph)
|
||||||
|
return this.sigma.getType(tph, sigma.txEquality);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,14 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, List<TargetType> implementingInterfaces,
|
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
|
||||||
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
|
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
|
||||||
|
|
||||||
public TargetClass(int modifiers, String qualifiedName) {
|
public TargetClass(int modifiers, String qualifiedName) {
|
||||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
|
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
|
||||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -25,7 +25,7 @@ public record TargetClass(int modifiers, String qualifiedName, TargetType superT
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
public void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||||
this.methods.add(new TargetMethod(access, name, generics, parameterTypes, returnType, block));
|
this.methods.add(new TargetMethod(access, name, generics, Set.of(), parameterTypes, returnType, block));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||||
@ -33,7 +33,7 @@ public record TargetClass(int modifiers, String qualifiedName, TargetType superT
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||||
this.constructors.add(new TargetConstructor(access, generics, paramterTypes, block, null));
|
this.constructors.add(new TargetConstructor(access, generics, Set.of(), paramterTypes, block, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||||
|
@ -6,7 +6,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetBlock block, TargetBlock fieldInitializer) {
|
public record TargetConstructor(int access, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, TargetBlock block, TargetBlock fieldInitializer) {
|
||||||
|
|
||||||
public String getDescriptor() {
|
public String getDescriptor() {
|
||||||
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
||||||
@ -15,5 +15,9 @@ public record TargetConstructor(int access, Set<TargetGeneric> generics, List<Me
|
|||||||
public String getSignature() {
|
public String getSignature() {
|
||||||
return TargetMethod.getSignature(generics, parameters, null);
|
return TargetMethod.getSignature(generics, parameters, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTXSignature() {
|
||||||
|
return TargetMethod.getSignature(txGenerics, parameters, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) {
|
public record TargetMethod(int access, String name, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) {
|
||||||
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
|
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
|
||||||
String ret = "(";
|
String ret = "(";
|
||||||
for (var parameterType : parameters) {
|
for (var parameterType : parameters) {
|
||||||
@ -42,6 +42,10 @@ public record TargetMethod(int access, String name, Set<TargetGeneric> generics,
|
|||||||
return getSignature(generics, parameters, returnType);
|
return getSignature(generics, parameters, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTXSignature() {
|
||||||
|
return getSignature(txGenerics, parameters, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStatic() {
|
public boolean isStatic() {
|
||||||
return (access & Opcodes.ACC_STATIC) != 0;
|
return (access & Opcodes.ACC_STATIC) != 0;
|
||||||
}
|
}
|
||||||
|
@ -575,8 +575,27 @@ public class TestComplete {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("This one isn't working")
|
||||||
public void boxTest() throws Exception {
|
public void boxTest() throws Exception {
|
||||||
var classFiles = generateClassFiles("Box.jav", new ByteArrayClassLoader());
|
var classFiles = generateClassFiles("Box.jav", new ByteArrayClassLoader());
|
||||||
var instance = classFiles.get("Box_Main").getDeclaredConstructor().newInstance();
|
var instance = classFiles.get("Box_Main").getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cycleTest() throws Exception {
|
||||||
|
var classFiles = generateClassFiles("Cycle.jav", new ByteArrayClassLoader());
|
||||||
|
var instance = classFiles.get("Cycle").getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void olFunTest() throws Exception {
|
||||||
|
var classFiles = generateClassFiles("OLFun.jav", new ByteArrayClassLoader());
|
||||||
|
var instance = classFiles.get("OLFun").getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void olFun2Test() throws Exception {
|
||||||
|
var classFiles = generateClassFiles("OLFun2.jav", new ByteArrayClassLoader());
|
||||||
|
var instance = classFiles.get("OLFun2").getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
public class Test {
|
|
||||||
public void lambda() {
|
|
||||||
Interface<Integer, Integer> mul2 = (Integer a) -> a * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Interface<R, T> {
|
|
||||||
R apply(T t);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user