forked from JavaTX/JavaCompilerCore
Fixes for TPH4
This commit is contained in:
parent
99c46bf37f
commit
b58b6c2288
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user