Mostly finish up populating generics
This commit is contained in:
parent
f00ee2598f
commit
7e259e2597
@ -1,6 +1,5 @@
|
||||
package de.dhbwstuttgart.target.generate;
|
||||
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
import de.dhbwstuttgart.syntaxtree.*;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||
@ -11,7 +10,6 @@ import de.dhbwstuttgart.target.tree.type.*;
|
||||
import de.dhbwstuttgart.typeinference.result.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ASTToTargetAST {
|
||||
|
||||
@ -19,10 +17,11 @@ public class ASTToTargetAST {
|
||||
protected Sigma sigma;
|
||||
|
||||
private class Sigma {
|
||||
HashMap<Method, Set<TargetGeneric>> computedGenerics = new HashMap<>();
|
||||
Map<Method, HashSet<TargetGeneric>> computedGenericsOfMethods = new HashMap<>();
|
||||
Map<ClassOrInterface, HashSet<TargetGeneric>> computedGenericsOfClasses = new HashMap<>();
|
||||
|
||||
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
||||
Map<TypePlaceholder, TargetType> result = new HashMap<>();
|
||||
HashSet<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
||||
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
||||
Map<TypePlaceholder, TypePlaceholder> equality = new HashMap<>();
|
||||
|
||||
Sigma(ResultSet constraints) {
|
||||
@ -62,11 +61,9 @@ public class ASTToTargetAST {
|
||||
right = unified.get(right).get(0);
|
||||
|
||||
simplifiedConstraints.add(new PairTPHsmallerTPH(left, right));
|
||||
result.put(right, new TargetGenericType(right.getName()));
|
||||
result.put(left, new TargetGenericType(left.getName()));
|
||||
}
|
||||
}
|
||||
System.out.println(simplifiedConstraints);
|
||||
System.out.println("Simplified constraints: " + simplifiedConstraints);
|
||||
|
||||
for (var equality : equalitySet) {
|
||||
var first = equality.get(0);
|
||||
@ -76,155 +73,190 @@ public class ASTToTargetAST {
|
||||
|
||||
for (var constraint : constraints.results) {
|
||||
if (constraint instanceof PairTPHequalRefTypeOrWildcardType p) {
|
||||
result.put(p.left, convert(p.right));
|
||||
concreteTypes.put(this.equality.getOrDefault(p.left, p.left), p.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findTypeVariables(RefTypeOrTPHOrWildcardOrGeneric type, Set<TypePlaceholder> typeVariables) {
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
tph = equality.getOrDefault(tph, tph);
|
||||
if (concreteTypes.containsKey(tph)) {
|
||||
findTypeVariables(concreteTypes.get(tph), typeVariables);
|
||||
return;
|
||||
}
|
||||
typeVariables.add(tph);
|
||||
} else if (type instanceof RefType refType) {
|
||||
for (var t : refType.getParaList())
|
||||
findTypeVariables(t, typeVariables);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasBound(String name, Set<TargetGeneric> generics) {
|
||||
return generics.stream().anyMatch(generic -> generic.name().equals(name));
|
||||
}
|
||||
|
||||
// Family of generated Generics
|
||||
Set<TargetGeneric> generics(ClassOrInterface owner, Method method) {
|
||||
if (computedGenerics.containsKey(method))
|
||||
return computedGenerics.get(method);
|
||||
HashSet<TargetGeneric> generics(ClassOrInterface owner, Method method) {
|
||||
if (computedGenericsOfMethods.containsKey(method))
|
||||
return computedGenericsOfMethods.get(method);
|
||||
|
||||
Set<TargetGeneric> result = new HashSet<>();
|
||||
computedGenerics.put(method, result);
|
||||
HashSet<TargetGeneric> result = new HashSet<>();
|
||||
computedGenericsOfMethods.put(method, result);
|
||||
|
||||
method.block.accept(new AbstractStatementVisitor() {
|
||||
// These two methods do the actual work
|
||||
var genericsOfClass = generics(owner);
|
||||
var simplifiedConstraints = (HashSet<PairTPHsmallerTPH>) this.simplifiedConstraints.clone();
|
||||
|
||||
HashSet<TypePlaceholder> typeVariables = new HashSet<>();
|
||||
HashSet<TypePlaceholder> typeVariablesOfFields = new HashSet<>();
|
||||
|
||||
for (var field : owner.getFieldDecl()) {
|
||||
findTypeVariables(field.getType(), typeVariablesOfFields);
|
||||
}
|
||||
|
||||
findTypeVariables(method.getReturnType(), typeVariables);
|
||||
for (var arg : method.getParameterList().getFormalparalist()) {
|
||||
findTypeVariables(arg.getType(), typeVariables);
|
||||
}
|
||||
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
@Override
|
||||
public void visit(LocalVarDecl localVarDecl) {
|
||||
// TODO
|
||||
findTypeVariables(localVarDecl.getType(), typeVariables);
|
||||
}
|
||||
});
|
||||
|
||||
method.block.accept(new TracingStatementVisitor() {
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
super.visit(methodCall);
|
||||
|
||||
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
|
||||
if (expressionReceiver.expr instanceof This) {
|
||||
// TODO This is going to fail spectacularly for overloaded methods
|
||||
var optMethod = owner.getMethods().stream().filter(m -> m.name.equals(methodCall.name)).findFirst();
|
||||
assert optMethod.isPresent();
|
||||
var method = optMethod.get();
|
||||
Set<TargetGeneric> generics = generics(owner, method);
|
||||
var generics = generics(owner, method);
|
||||
HashSet<TargetGeneric> all = new HashSet<>(generics);
|
||||
|
||||
// Reflexive and Transitive closure
|
||||
HashSet<TargetGeneric> 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
all.addAll(toAdd);
|
||||
} while (toAdd.size() > 0);
|
||||
for (var generic : all) {
|
||||
toAdd.add(new TargetGeneric(generic.name(), new TargetGenericType(generic.name())));
|
||||
}
|
||||
all.addAll(toAdd);
|
||||
|
||||
HashSet<PairTPHsmallerTPH> newPairs = new HashSet<>();
|
||||
// Loop from hell
|
||||
outer: for (var tph : typeVariables) {
|
||||
for (var generic : all) {
|
||||
if (!(generic.bound() instanceof TargetGenericType type))
|
||||
continue;
|
||||
|
||||
for (var pair : simplifiedConstraints) {
|
||||
if (!(pair.left.equals(tph) && pair.right.getName().equals(generic.name())))
|
||||
continue;
|
||||
|
||||
for (var tph2 : typeVariables) {
|
||||
for (var pair2 : simplifiedConstraints) {
|
||||
if (!(pair2.right.equals(tph2) && pair2.left.getName().equals(type.name())))
|
||||
continue;
|
||||
|
||||
newPairs.add(new PairTPHsmallerTPH(tph, tph2));
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
simplifiedConstraints.addAll(newPairs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Everything down here is just for walking the AST
|
||||
@Override
|
||||
public void visit(ArgumentList argumentList) {
|
||||
argumentList.getArguments().forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
lambdaExpression.methodBody.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
assign.rightSide.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr binary) {
|
||||
binary.lexpr.accept(this);
|
||||
binary.rexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
for (var expr : block.statements)
|
||||
expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStmt forStmt) {
|
||||
forStmt.body_Loop_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
ifStmt.then_block.accept(this);
|
||||
ifStmt.else_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewClass newClass) {
|
||||
newClass.arglist.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewArray newArray) {
|
||||
newArray.expr.forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Return aReturn) {
|
||||
aReturn.retexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStmt whileStmt) {
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoStmt whileStmt) {
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr unaryExpr) {
|
||||
unaryExpr.expr.accept(this);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void findAllBounds(String name, Set<TargetGeneric> generics) {
|
||||
for (var rsp : simplifiedConstraints) {
|
||||
var left = equality.getOrDefault(rsp.left, rsp.left);
|
||||
var right = equality.getOrDefault(rsp.right, rsp.right);
|
||||
if (left.getName().equals(name)) {
|
||||
generics.add(new TargetGeneric(name, new TargetGenericType(right.getName())));
|
||||
findAllBounds(right.getName(), generics);
|
||||
return;
|
||||
}
|
||||
}
|
||||
generics.add(new TargetGeneric(name, TargetType.Object));
|
||||
}
|
||||
|
||||
Set<TargetGeneric> findAllBounds(TargetGenericType type) {
|
||||
Set<TargetGeneric> result = new HashSet<>();
|
||||
findAllBounds(type.name(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Set<TargetGeneric> generics(ClassOrInterface classOrInterface) {
|
||||
Set<TargetGeneric> result = new HashSet<>();
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
if (field.getType() instanceof TypePlaceholder tph) {
|
||||
var tpe = get(tph);
|
||||
switch (tpe) {
|
||||
case TargetSpecializedType specializedType:
|
||||
specializedType.params().stream().flatMap(targetType -> {
|
||||
if (targetType instanceof TargetSpecializedType spc)
|
||||
return Stream.concat(Stream.of(targetType), spc.params().stream());
|
||||
return Stream.of(targetType);
|
||||
}).forEach(param -> {
|
||||
if (param instanceof TargetGenericType genericType) {
|
||||
result.addAll(findAllBounds(genericType));
|
||||
}
|
||||
});
|
||||
break;
|
||||
case TargetGenericType genericType:
|
||||
result.addAll(findAllBounds(genericType));
|
||||
default: break;
|
||||
// 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 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)));
|
||||
typeVariables.add(pair.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All unbounded type variables
|
||||
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));
|
||||
}
|
||||
|
||||
// All unbounded bounds
|
||||
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));
|
||||
}
|
||||
|
||||
System.out.println(method.name + ": " + result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<TargetGeneric> generics) {
|
||||
if (type instanceof TypePlaceholder tph) {
|
||||
tph = equality.getOrDefault(tph, tph);
|
||||
|
||||
var concreteType = concreteTypes.get(tph);
|
||||
if (concreteType != null) {
|
||||
findAllBounds(concreteType, generics);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var rsp : simplifiedConstraints) {
|
||||
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())));
|
||||
findAllBounds(right, generics);
|
||||
return;
|
||||
}
|
||||
}
|
||||
generics.add(new TargetGeneric(tph.getName(), TargetType.Object));
|
||||
} else if (type instanceof RefType refType) {
|
||||
refType.getParaList().forEach(t -> findAllBounds(t, generics));
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<TargetGeneric> generics(ClassOrInterface classOrInterface) {
|
||||
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
||||
return computedGenericsOfClasses.get(classOrInterface);
|
||||
|
||||
HashSet<TargetGeneric> result = new HashSet<>();
|
||||
for (var field : classOrInterface.getFieldDecl()) {
|
||||
findAllBounds(field.getType(), result);
|
||||
}
|
||||
computedGenericsOfClasses.put(classOrInterface, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -232,7 +264,9 @@ public class ASTToTargetAST {
|
||||
if (equality.containsKey(tph)) {
|
||||
return get(equality.get(tph));
|
||||
}
|
||||
return result.get(tph);
|
||||
var type = concreteTypes.get(tph);
|
||||
if (type == null) return new TargetGenericType(tph.getName());
|
||||
return convert(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,30 +4,41 @@ import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
|
||||
public abstract class AbstractStatementVisitor implements StatementVisitor {
|
||||
|
||||
// This visitor walks the entire tree, individual methods may be overridden
|
||||
public abstract class TracingStatementVisitor implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
methodCall.receiver.accept(this);
|
||||
methodCall.getArgumentList().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArgumentList argumentList) {
|
||||
|
||||
argumentList.getArguments().forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
|
||||
lambdaExpression.methodBody.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Assign assign) {
|
||||
|
||||
assign.rightSide.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BinaryExpr binary) {
|
||||
|
||||
binary.lexpr.accept(this);
|
||||
binary.rexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Block block) {
|
||||
|
||||
for (var expr : block.statements)
|
||||
expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -47,12 +58,13 @@ public abstract class AbstractStatementVisitor implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ForStmt forStmt) {
|
||||
|
||||
forStmt.body_Loop_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfStmt ifStmt) {
|
||||
|
||||
ifStmt.then_block.accept(this);
|
||||
ifStmt.else_block.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,23 +83,18 @@ public abstract class AbstractStatementVisitor implements StatementVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCall methodCall) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewClass methodCall) {
|
||||
|
||||
public void visit(NewClass newClass) {
|
||||
this.visit((MethodCall) newClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewArray newArray) {
|
||||
|
||||
newArray.expr.forEach(expr -> expr.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Return aReturn) {
|
||||
|
||||
aReturn.retexpr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,12 +119,12 @@ public abstract class AbstractStatementVisitor implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(WhileStmt whileStmt) {
|
||||
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DoStmt whileStmt) {
|
||||
|
||||
whileStmt.loopBlock.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -142,7 +149,7 @@ public abstract class AbstractStatementVisitor implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr unaryExpr) {
|
||||
|
||||
unaryExpr.expr.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
Loading…
Reference in New Issue
Block a user