Fixes for TPH4

This commit is contained in:
Victorious3 2023-02-21 10:28:00 +01:00
parent 99c46bf37f
commit b58b6c2288

View File

@ -14,6 +14,7 @@ import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.TargetBlock; import de.dhbwstuttgart.target.tree.expression.TargetBlock;
import de.dhbwstuttgart.target.tree.expression.TargetExpression; import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.constraints.Pair;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
import java.util.*; import java.util.*;
@ -80,11 +81,6 @@ public class ASTToTargetAST {
return result; return result;
} }
boolean hasBound(TypePlaceholder name, Set<ResultPair<?, ?>> generics) {
TypePlaceholder finalName = equality.getOrDefault(name, name);
return generics.stream().anyMatch(generic -> generic.getLeft().equals(finalName));
}
boolean containsRelation(Set<ResultPair<?, ?>> result, PairTPHsmallerTPH pair) { boolean containsRelation(Set<ResultPair<?, ?>> result, PairTPHsmallerTPH pair) {
// Check if both the right and the left are already part of a relation // Check if both the right and the left are already part of a relation
var containsLeft = false; var containsLeft = false;
@ -117,6 +113,26 @@ public class ASTToTargetAST {
input.add(pair); input.add(pair);
} }
static Set<ResultPair<?, ?>> transitiveClosure(Set<ResultPair<?, ?>> generics) {
Set<ResultPair<?, ?>> all = new HashSet<>(generics);
HashSet<ResultPair<?, ?>> toAdd = new HashSet<>();
int sizeBefore;
do {
sizeBefore = all.size();
toAdd.clear();
for (var g1 : all) {
for (var g2 : all) {
if (g1 instanceof PairTPHsmallerTPH pair) {
if (g2.getLeft().equals(pair.getRight()) && g2.getRight() instanceof TypePlaceholder right)
toAdd.add(new PairTPHsmallerTPH(pair.left, right));
}
}
}
all.addAll(toAdd);
} while (sizeBefore < all.size());
return all;
}
// Family of generated Generics // Family of generated Generics
Set<ResultPair<?, ?>> generics(ClassOrInterface owner, Method method) { Set<ResultPair<?, ?>> generics(ClassOrInterface owner, Method method) {
if (computedGenericsOfMethods.containsKey(method)) if (computedGenericsOfMethods.containsKey(method))
@ -129,10 +145,10 @@ public class ASTToTargetAST {
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints); var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
HashSet<TypePlaceholder> typeVariables = new HashSet<>(); HashSet<TypePlaceholder> typeVariables = new HashSet<>();
HashSet<TypePlaceholder> typeVariablesOfFields = new HashSet<>(); HashSet<TypePlaceholder> typeVariablesOfClass = new HashSet<>();
for (var field : owner.getFieldDecl()) { for (var pair : genericsOfClass) {
typeVariablesOfFields.addAll(findTypeVariables(field.getType())); typeVariablesOfClass.add((TypePlaceholder) pair.getLeft());
} }
typeVariables.addAll(findTypeVariables(method.getReturnType())); typeVariables.addAll(findTypeVariables(method.getReturnType()));
@ -159,6 +175,7 @@ public class ASTToTargetAST {
// 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;
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(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
@ -167,7 +184,6 @@ public class ASTToTargetAST {
} }
} }
method.block.accept(new TracingStatementVisitor() { method.block.accept(new TracingStatementVisitor() {
private RefTypeOrTPHOrWildcardOrGeneric superType = new Void(new NullToken()); private RefTypeOrTPHOrWildcardOrGeneric superType = new Void(new NullToken());
@ -206,33 +222,22 @@ public class ASTToTargetAST {
var method = optMethod.get(); var method = optMethod.get();
var generics = generics(owner, method); var generics = generics(owner, method);
Set<ResultPair<?, ?>> all = new HashSet<>(generics);
// Reflexive and Transitive closure // transitive and
HashSet<ResultPair<?, ?>> toAdd = new HashSet<>(); var all = transitiveClosure(generics);
int sizeBefore; // reflexive
do { var toAdd = new HashSet<ResultPair<?, ?>>();
sizeBefore = all.size();
toAdd.clear();
for (var g1 : all) {
for (var g2 : all) {
if (g1 instanceof PairTPHsmallerTPH pair) {
if (g2.getLeft().equals(pair.getLeft()) && generics.stream().anyMatch(generic -> generic.getLeft().equals(pair.getRight())))
toAdd.add(new PairTPHsmallerTPH(pair.left, pair.right));
}
}
}
all.addAll(toAdd);
} while (sizeBefore < all.size());
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;
for (var generic : all) { for (var generic : all) {
if (!(generic.getRight() instanceof TypePlaceholder type)) if (!(generic.getRight() instanceof TypePlaceholder type))
continue; continue;
@ -267,19 +272,19 @@ public class ASTToTargetAST {
@Override @Override
public void visit(LambdaExpression lambdaExpression) { public void visit(LambdaExpression lambdaExpression) {
superType = new Void(new NullToken()); superType = new Void(new NullToken());
lambdaExpression.methodBody.accept(this); lambdaExpression.methodBody.accept(this);
} }
@Override @Override
public void visit(Assign assign) { public void visit(Assign assign) {
superType = assign.lefSide.getType(); superType = assign.lefSide.getType();
assign.rightSide.accept(this); assign.rightSide.accept(this);
} }
@Override @Override
public void visit(BinaryExpr binary) { public void visit(BinaryExpr binary) {
superType = new Void(new NullToken()); superType = new Void(new NullToken());
binary.lexpr.accept(this); binary.lexpr.accept(this);
superType = new Void(new NullToken()); superType = new Void(new NullToken());
binary.rexpr.accept(this); binary.rexpr.accept(this);
@ -288,7 +293,7 @@ public class ASTToTargetAST {
@Override @Override
public void visit(Block block) { public void visit(Block block) {
for (var expr : block.statements) { for (var expr : block.statements) {
superType = new Void(new NullToken()); superType = new Void(new NullToken());
expr.accept(this); expr.accept(this);
} }
} }
@ -315,9 +320,9 @@ public class ASTToTargetAST {
@Override @Override
public void visit(IfStmt ifStmt) { public void visit(IfStmt ifStmt) {
superType = new Void(new NullToken()); superType = new Void(new NullToken());
ifStmt.expr.accept(this); ifStmt.expr.accept(this);
superType = new Void(new NullToken()); superType = new Void(new NullToken());
ifStmt.then_block.accept(this); ifStmt.then_block.accept(this);
superType = new Void(new NullToken()); superType = new Void(new NullToken());
ifStmt.else_block.accept(this); ifStmt.else_block.accept(this);
@ -350,7 +355,7 @@ public class ASTToTargetAST {
@Override @Override
public void visit(Return aReturn) { public void visit(Return aReturn) {
superType = aReturn.getType(); superType = aReturn.getType();
aReturn.retexpr.accept(this); aReturn.retexpr.accept(this);
} }
@ -376,9 +381,9 @@ public class ASTToTargetAST {
@Override @Override
public void visit(WhileStmt whileStmt) { public void visit(WhileStmt whileStmt) {
superType = new Void(new NullToken()); superType = new Void(new NullToken());
whileStmt.expr.accept(this); whileStmt.expr.accept(this);
superType = new Void(new NullToken()); superType = new Void(new NullToken());
whileStmt.loopBlock.accept(this); whileStmt.loopBlock.accept(this);
} }
@ -416,36 +421,67 @@ public class ASTToTargetAST {
public void visit(Literal literal) { public void visit(Literal literal) {
} }
@Override @Override
public void visit(ArgumentList arglist) { public void visit(ArgumentList arglist) {
for(int i = 0;i<arglist.getArguments().size();i++){ for(int i = 0;i<arglist.getArguments().size();i++){
superType = arglist.getArguments().get(i).getType(); superType = arglist.getArguments().get(i).getType();
arglist.getArguments().get(i).accept(this); arglist.getArguments().get(i).accept(this);
} }
} }
}); });
// Type variables with bounds that are also type variables of fields var closure = transitiveClosure((Set) simplifiedConstraints);
// Type variables with bounds that are also type variables of the class
for (var typeVariable : new HashSet<>(typeVariables)) { for (var typeVariable : new HashSet<>(typeVariables)) {
for (var pair : simplifiedConstraints) { if (typeVariablesOfClass.contains(typeVariable)) continue;
if (pair.left.equals(typeVariable) && typeVariablesOfFields.contains(pair.right)) {
addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right))); var pairs = new HashSet<PairTPHsmallerTPH>();
typeVariables.add(pair.right); for (var pair : closure) {
if (!(pair instanceof PairTPHsmallerTPH ptph)) continue;
if (ptph.left.equals(typeVariable) && typeVariablesOfClass.contains(ptph.right)) {
pairs.add(new PairTPHsmallerTPH(ptph.left, equality.getOrDefault(ptph.right, ptph.right)));
} }
} }
// Find the closest pair with the minimum amount of steps
PairTPHsmallerTPH minimalPair = null;
var minSteps = Integer.MAX_VALUE;
for (var pair : pairs) {
var left = pair.left;
var visited = new HashSet<TypePlaceholder>();
var steps = 0;
while (!left.equals(pair.right)) {
visited.add(left);
var found = false;
for (var pair2 : simplifiedConstraints) {
if (left.equals(pair2.left) && !visited.contains(pair2.right)) {
left = pair2.right;
steps += 1;
found = true;
break;
}
}
if (!found) break;
}
if (steps < minSteps) {
minSteps = steps;
minimalPair = pair;
}
}
if (minimalPair != null)
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) {
for (var pair : simplifiedConstraints) { if (typeVariablesOfClass.contains(typeVariable)) continue;
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) for (var pair : result) {
if (pair.getLeft().equals(typeVariable))
continue outer; continue outer;
} }
if (!hasBound(typeVariable, genericsOfClass)) addToPairs(result, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
} }
// All unbounded bounds // All unbounded bounds
@ -455,7 +491,7 @@ public class ASTToTargetAST {
if (pair.right.equals(pair2.left)) if (pair.right.equals(pair2.left))
continue outer; continue outer;
} }
if (!hasBound(pair.right, genericsOfClass) && typeVariables.contains(pair.right)) { if (!typeVariablesOfClass.contains(pair.right) && typeVariables.contains(pair.right)) {
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT)); addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
} }
} }
@ -468,10 +504,7 @@ public class ASTToTargetAST {
referenced.addAll(findTypeVariables(param.getType())); referenced.addAll(findTypeVariables(param.getType()));
} }
referenced.addAll(findTypeVariables(method.getReturnType())); referenced.addAll(findTypeVariables(method.getReturnType()));
for (var g : genericsOfClass) { referenced.addAll(typeVariablesOfClass);
if (g.getLeft() instanceof TypePlaceholder left)
referenced.add(left);
}
eliminateInnerTypeVariables(referenced, result); eliminateInnerTypeVariables(referenced, result);
usedTPHsOfMethods.put(method, referenced); usedTPHsOfMethods.put(method, referenced);
@ -524,7 +557,6 @@ public class ASTToTargetAST {
eliminateInnerTypeVariablesOfClass(classOrInterface, result); eliminateInnerTypeVariablesOfClass(classOrInterface, result);
equalizeTypeVariables(result); equalizeTypeVariables(result);
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + result); System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + result);
return result; return result;
} }