Filter out cycles and infima

This commit is contained in:
Victorious3 2022-07-03 15:17:12 +02:00
parent d7380c6cb7
commit 560f0c5a6f
5 changed files with 170 additions and 4 deletions

View File

@ -717,9 +717,8 @@ public class Codegen {
break;
}
case TargetReturn ret: {
generate(state, ret.expression());
if (ret.expression() != null) {
generate(state, ret.expression());
boxPrimitive(state, ret.expression().type());
mv.visitInsn(ARETURN);
} else mv.visitInsn(RETURN);

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.*;
@ -226,6 +227,7 @@ public class ASTToTargetAST {
result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
}
eliminateCyclesAndInfima(result);
System.out.println(method.name + ": " + result);
return result;
@ -265,9 +267,53 @@ public class ASTToTargetAST {
findAllBounds(field.getType(), result);
}
computedGenericsOfClasses.put(classOrInterface, result);
eliminateCyclesAndInfima(result);
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + result);
return result;
}
void eliminateCyclesAndInfima(Set<ResultPair<?, ?>> input) {
// Eliminate cycles
var cycles = findCycles(input);
for (var cycle : cycles) {
var newTph = TypePlaceholder.fresh(new NullToken());
input.add(new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
cycle.add(cycle.get(0)); // Make it a complete cycle
for (var i = 0; i < cycle.size() - 1; i++) {
var left = cycle.get(i);
var right = cycle.get(i + 1);
var pair = new PairTPHsmallerTPH(left, right);
input.remove(pair);
equality.put(left, newTph);
}
}
// Eliminate infima
var foundInfima = false;
do {
foundInfima = false;
for (var constraint : new HashSet<>(input)) {
var left = (TypePlaceholder) constraint.getLeft();
Set<PairTPHsmallerTPH> infima = new HashSet<>();
for (var pair : input) {
if (pair instanceof PairTPHsmallerTPH stph)
if (pair.getLeft().equals(constraint.getLeft()))
infima.add(stph);
}
if (infima.size() > 1) {
foundInfima = true;
var newTph = TypePlaceholder.fresh(new NullToken());
input.add(new PairTPHsmallerTPH(left, newTph));
input.add(new PairTPHequalRefTypeOrWildcardType(newTph, OBJECT));
input.removeAll(infima);
for (var infimum : infima) {
equality.put(infimum.right, newTph);
input.removeIf(pair -> pair.getLeft().equals(infimum.right));
}
}
}
} while (foundInfima);
}
TargetType get(TypePlaceholder tph) {
if (equality.containsKey(tph)) {
return get(equality.get(tph));
@ -286,6 +332,92 @@ public class ASTToTargetAST {
this.sigma = all.get(0);
}
static Set<TypePlaceholder> allNodes(Set<ResultPair<?, ?>> input) {
return input.stream().map(pair -> (TypePlaceholder) pair.getLeft()).collect(Collectors.toSet());
}
static Set<TypePlaceholder> outgoingEdgesOf(TypePlaceholder tph, Set<ResultPair<?, ?>> input) {
return input.stream()
.filter(pair -> pair instanceof PairTPHsmallerTPH && pair.getLeft().equals(tph))
.map(pair -> (TypePlaceholder) pair.getRight()).collect(Collectors.toSet());
}
static boolean containsEdge(TypePlaceholder a, TypePlaceholder b, Set<ResultPair<?, ?>> input) {
return input.stream().anyMatch(pair -> pair.getLeft().equals(a) && pair.getRight().equals(b));
}
// Tiernan simple cycles algorithm
static Set<List<TypePlaceholder>> findCycles(Set<ResultPair<?, ?>> input) {
Map<TypePlaceholder, Integer> indices = new HashMap<>();
List<TypePlaceholder> path = new ArrayList<>();
Set<TypePlaceholder> pathSet = new HashSet<>();
Map<TypePlaceholder, Set<TypePlaceholder>> blocked = new HashMap<>();
Set<List<TypePlaceholder>> cycles = new HashSet<>();
int index = 0;
for (var tph : allNodes(input)) {
blocked.put(tph, new HashSet<>());
indices.put(tph, index++);
}
var vertexIterator = allNodes(input).iterator();
if (!vertexIterator.hasNext()) return cycles;
TypePlaceholder startOfPath = null;
TypePlaceholder endOfPath = vertexIterator.next();
TypePlaceholder temp = null;
int endIndex = 0;
boolean extensionFound = false;
path.add(endOfPath);
pathSet.add(endOfPath);
while (true) {
do {
extensionFound = false;
for (TypePlaceholder n : outgoingEdgesOf(endOfPath, input)) {
int cmp = indices.get(n).compareTo(indices.get(path.get(0)));
if ((cmp > 0) && !pathSet.contains(n) && !blocked.get(endOfPath).contains(n)) {
path.add(n);
pathSet.add(n);
endOfPath = n;
extensionFound = true;
break;
}
}
} while (extensionFound);
startOfPath = path.get(0);
if (containsEdge(endOfPath, startOfPath, input)) {
List<TypePlaceholder> cycle = new ArrayList<>(path);
cycles.add(cycle);
}
if (path.size() > 1) {
blocked.get(endOfPath).clear();
endIndex = path.size() - 1;
path.remove(endIndex);
pathSet.remove(endOfPath);
--endIndex;
temp = endOfPath;
endOfPath = path.get(endIndex);
blocked.get(endOfPath).add(temp);
continue;
}
if (vertexIterator.hasNext()) {
path.clear();
pathSet.clear();
endOfPath = vertexIterator.next();
path.add(endOfPath);
pathSet.add(endOfPath);
for (TypePlaceholder tph : blocked.keySet()) {
blocked.get(tph).clear();
}
continue;
}
break;
}
return cycles;
}
Set<TargetGeneric> convert(Set<ResultPair<?, ?>> result) {
return result.stream().map(p -> {
if (p instanceof PairTPHsmallerTPH pair) {
@ -321,9 +453,10 @@ public class ASTToTargetAST {
for (var s : all) {
sigma = s;
var generics = sigma.generics(owner, input);
List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetConstructor(input.modifier, convert(sigma.generics(owner, input)), params, convert(input.block)));
result.add(new TargetConstructor(input.modifier, convert(generics), params, convert(input.block)));
parameterSet.add(params);
}
}
@ -339,11 +472,12 @@ public class ASTToTargetAST {
for (var s : all) {
sigma = s;
var generics = sigma.generics(owner, input);
List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetMethod(
input.modifier,
input.name, convert(sigma.generics(owner, input)), params,
input.name, convert(generics), params,
convert(input.getReturnType()),
convert(input.block)
));

View File

@ -62,4 +62,25 @@ public class ASTToTypedTargetAST {
var tphAndGenerics = TestCodegen.generateClass(converter.convert(classes.get(0)));
}
@Test
public void cycles() throws Exception {
var file = Path.of(System.getProperty("user.dir"), "/src/test/resources/bytecode/javFiles/Cycle.jav").toFile();
var compiler = new JavaTXCompiler(file);
var resultSet = compiler.typeInference();
var converter = new ASTToTargetAST(resultSet);
var classes = compiler.sourceFiles.get(file).getClasses();
var cycle = TestCodegen.generateClass(converter.convert(classes.get(0)));
}
@Test
public void infimum() throws Exception {
var file = Path.of(System.getProperty("user.dir"), "/src/test/resources/bytecode/javFiles/Infimum.jav").toFile();
var compiler = new JavaTXCompiler(file);
var resultSet = compiler.typeInference();
var converter = new ASTToTargetAST(resultSet);
var classes = compiler.sourceFiles.get(file).getClasses();
var infimum = TestCodegen.generateClass(converter.convert(classes.get(0)));
}
}

View File

@ -0,0 +1,6 @@
class Cycle {
m(x, y) {
y = x;
x = y;
}
}

View File

@ -0,0 +1,6 @@
class Infimum {
m(x, y, z) {
y = x;
z = x;
}
}