Decouple Sigma from Target

This commit is contained in:
Victorious3 2022-07-02 15:57:33 +02:00
parent a8be387dd9
commit b43afd40ee

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.tree.*;
@ -10,18 +11,21 @@ import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*;
import java.util.*;
import java.util.stream.Collectors;
public class ASTToTargetAST {
static RefType OBJECT = ASTFactory.createObjectType(); // TODO It would be better if I could call this directly but the hashcode seems to change
protected List<Sigma> all;
protected Sigma sigma;
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's a better way?
private class Sigma {
Map<Method, HashSet<TargetGeneric>> computedGenericsOfMethods = new HashMap<>();
Map<ClassOrInterface, HashSet<TargetGeneric>> computedGenericsOfClasses = new HashMap<>();
Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods = new HashMap<>();
Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses = new HashMap<>();
HashSet<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
@ -93,20 +97,20 @@ public class ASTToTargetAST {
}
}
boolean hasBound(String name, Set<TargetGeneric> generics) {
return generics.stream().anyMatch(generic -> generic.name().equals(name));
boolean hasBound(TypePlaceholder name, Set<ResultPair<?, ?>> generics) {
return generics.stream().anyMatch(generic -> generic.getLeft().equals(name));
}
// Family of generated Generics
HashSet<TargetGeneric> generics(ClassOrInterface owner, Method method) {
Set<ResultPair<?, ?>> generics(ClassOrInterface owner, Method method) {
if (computedGenericsOfMethods.containsKey(method))
return computedGenericsOfMethods.get(method);
HashSet<TargetGeneric> result = new HashSet<>();
Set<ResultPair<?, ?>> result = new HashSet<>();
computedGenericsOfMethods.put(method, result);
var genericsOfClass = generics(owner);
var simplifiedConstraints = (HashSet<PairTPHsmallerTPH>) this.simplifiedConstraints.clone();
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
HashSet<TypePlaceholder> typeVariables = new HashSet<>();
HashSet<TypePlaceholder> typeVariablesOfFields = new HashSet<>();
@ -139,41 +143,42 @@ public class ASTToTargetAST {
assert optMethod.isPresent();
var method = optMethod.get();
var generics = generics(owner, method);
HashSet<TargetGeneric> all = new HashSet<>(generics);
Set<ResultPair<?, ?>> all = new HashSet<>(generics);
// Reflexive and Transitive closure
HashSet<TargetGeneric> toAdd = new HashSet<>();
HashSet<ResultPair<?, ?>> toAdd = new HashSet<>();
do {
toAdd.clear();
for (var g1 : all) {
for (var g2 : all) {
if (g1.bound() instanceof TargetGenericType type) {
if (g2.name().equals(type.name()) && generics.stream().anyMatch(generic -> generic.name().equals(type.name())))
toAdd.add(new TargetGeneric(g1.name(), g2.bound()));
if (g1 instanceof PairTPHsmallerTPH pair) {
if (g2.getLeft().equals(pair.getLeft()) && generics.stream().anyMatch(generic -> generic.getLeft().equals(pair.getRight())))
toAdd.add(new PairTPHsmallerTPH((TypePlaceholder) g1.getLeft(), (TypePlaceholder) g2.getRight()));
}
}
}
all.addAll(toAdd);
} while (toAdd.size() > 0);
for (var generic : all) {
toAdd.add(new TargetGeneric(generic.name(), new TargetGenericType(generic.name())));
toAdd.add(new PairTPHsmallerTPH((TypePlaceholder) generic.getLeft(), (TypePlaceholder) generic.getLeft()));
}
all.addAll(toAdd);
HashSet<PairTPHsmallerTPH> newPairs = new HashSet<>();
// Loop from hell
outer: for (var tph : typeVariables) {
outer:
for (var tph : typeVariables) {
for (var generic : all) {
if (!(generic.bound() instanceof TargetGenericType type))
if (!(generic.getRight() instanceof TypePlaceholder type))
continue;
for (var pair : simplifiedConstraints) {
if (!(pair.left.equals(tph) && pair.right.getName().equals(generic.name())))
if (!(pair.left.equals(tph) && pair.right.equals(generic.getLeft())))
continue;
for (var tph2 : typeVariables) {
for (var pair2 : simplifiedConstraints) {
if (!(pair2.right.equals(tph2) && pair2.left.getName().equals(type.name())))
if (!(pair2.right.equals(tph2) && pair2.left.equals(type)))
continue;
newPairs.add(new PairTPHsmallerTPH(tph, tph2));
@ -190,33 +195,35 @@ public class ASTToTargetAST {
});
// Type variables with bounds that are also type variables of the method or type variables of fields
for (var typeVariable : (HashSet<TypePlaceholder>)typeVariables.clone()) {
for (var typeVariable : new HashSet<>(typeVariables)) {
for (var pair : simplifiedConstraints) {
if (pair.left.equals(typeVariable) && (typeVariables.contains(pair.right) || typeVariablesOfFields.contains(pair.right))) {
result.add(new TargetGeneric(pair.left.getName(), convert(pair.right)));
result.add(new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
typeVariables.add(pair.right);
}
}
}
// All unbounded type variables
outer: for (var typeVariable : typeVariables) {
outer:
for (var typeVariable : typeVariables) {
for (var pair : simplifiedConstraints) {
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right))
continue outer;
}
if (!hasBound(typeVariable.getName(), genericsOfClass))
result.add(new TargetGeneric(typeVariable.getName(), TargetType.Object));
if (!hasBound(typeVariable, genericsOfClass))
result.add(new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
}
// All unbounded bounds
outer: for (var pair : simplifiedConstraints) {
outer:
for (var pair : simplifiedConstraints) {
for (var pair2 : simplifiedConstraints) {
if (pair.right.equals(pair2.left))
continue outer;
}
if (!hasBound(pair.right.getName(), genericsOfClass) && typeVariables.contains(pair.right))
result.add(new TargetGeneric(pair.right.getName(), TargetType.Object));
if (!hasBound(pair.right, genericsOfClass) && typeVariables.contains(pair.right))
result.add(new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
}
System.out.println(method.name + ": " + result);
@ -224,7 +231,7 @@ public class ASTToTargetAST {
return result;
}
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<TargetGeneric> generics) {
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics) {
if (type instanceof TypePlaceholder tph) {
tph = equality.getOrDefault(tph, tph);
@ -238,22 +245,22 @@ public class ASTToTargetAST {
var left = equality.getOrDefault(rsp.left, rsp.left);
var right = equality.getOrDefault(rsp.right, rsp.right);
if (left.equals(tph)) {
generics.add(new TargetGeneric(tph.getName(), new TargetGenericType(right.getName())));
generics.add(new PairTPHsmallerTPH(tph, right));
findAllBounds(right, generics);
return;
}
}
generics.add(new TargetGeneric(tph.getName(), TargetType.Object));
generics.add(new PairTPHequalRefTypeOrWildcardType(tph, OBJECT));
} else if (type instanceof RefType refType) {
refType.getParaList().forEach(t -> findAllBounds(t, generics));
}
}
HashSet<TargetGeneric> generics(ClassOrInterface classOrInterface) {
Set<ResultPair<?, ?>> generics(ClassOrInterface classOrInterface) {
if (computedGenericsOfClasses.containsKey(classOrInterface))
return computedGenericsOfClasses.get(classOrInterface);
HashSet<TargetGeneric> result = new HashSet<>();
Set<ResultPair<?, ?>> result = new HashSet<>();
for (var field : classOrInterface.getFieldDecl()) {
findAllBounds(field.getType(), result);
}
@ -279,9 +286,21 @@ public class ASTToTargetAST {
this.sigma = all.get(0);
}
Set<TargetGeneric> convert(Set<ResultPair<?, ?>> result) {
return result.stream().map(p -> {
if (p instanceof PairTPHsmallerTPH pair) {
return new TargetGeneric(pair.left.getName(), new TargetGenericType(pair.right.getName()));
} else if (p instanceof PairTPHequalRefTypeOrWildcardType pair) {
return new TargetGeneric(pair.left.getName(), convert(pair.right));
} else {
throw new IllegalArgumentException();
}
}).collect(Collectors.toSet());
}
public TargetClass convert(ClassOrInterface input) {
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
sigma.generics(input),
convert(sigma.generics(input)),
input.getSuperInterfaces().stream().map(this::convert).toList(),
input.getConstructors().stream().map(constructor -> this.convert(input, constructor)).flatMap(List::stream).toList(),
input.getFieldDecl().stream().map(this::convert).toList(),
@ -304,7 +323,7 @@ public class ASTToTargetAST {
sigma = s;
List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetConstructor(input.modifier, sigma.generics(owner, input), params, convert(input.block)));
result.add(new TargetConstructor(input.modifier, convert(sigma.generics(owner, input)), params, convert(input.block)));
parameterSet.add(params);
}
}
@ -324,7 +343,7 @@ public class ASTToTargetAST {
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetMethod(
input.modifier,
input.name, sigma.generics(owner, input), params,
input.name, convert(sigma.generics(owner, input)), params,
convert(input.getReturnType()),
convert(input.block)
));