forked from JavaTX/JavaCompilerCore
Decouple Sigma from Target
This commit is contained in:
parent
a8be387dd9
commit
b43afd40ee
@ -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),
|
||||
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
|
||||
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)
|
||||
));
|
||||
|
Loading…
Reference in New Issue
Block a user