From b43afd40ee1936f582e0bb8b0f575968283e8462 Mon Sep 17 00:00:00 2001 From: Victorious3 Date: Sat, 2 Jul 2022 15:57:33 +0200 Subject: [PATCH] Decouple Sigma from Target --- .../target/generate/ASTToTargetAST.java | 89 +++++++++++-------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index f307b3925..e9d1805ed 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -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 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> computedGenericsOfMethods = new HashMap<>(); - Map> computedGenericsOfClasses = new HashMap<>(); + Map>> computedGenericsOfMethods = new HashMap<>(); + Map>> computedGenericsOfClasses = new HashMap<>(); - HashSet simplifiedConstraints = new HashSet<>(); + Set simplifiedConstraints = new HashSet<>(); Map concreteTypes = new HashMap<>(); Map equality = new HashMap<>(); @@ -93,20 +97,20 @@ public class ASTToTargetAST { } } - boolean hasBound(String name, Set generics) { - return generics.stream().anyMatch(generic -> generic.name().equals(name)); + boolean hasBound(TypePlaceholder name, Set> generics) { + return generics.stream().anyMatch(generic -> generic.getLeft().equals(name)); } // Family of generated Generics - HashSet generics(ClassOrInterface owner, Method method) { + Set> generics(ClassOrInterface owner, Method method) { if (computedGenericsOfMethods.containsKey(method)) return computedGenericsOfMethods.get(method); - HashSet result = new HashSet<>(); + Set> result = new HashSet<>(); computedGenericsOfMethods.put(method, result); var genericsOfClass = generics(owner); - var simplifiedConstraints = (HashSet) this.simplifiedConstraints.clone(); + var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints); HashSet typeVariables = new HashSet<>(); HashSet typeVariablesOfFields = new HashSet<>(); @@ -139,41 +143,42 @@ public class ASTToTargetAST { assert optMethod.isPresent(); var method = optMethod.get(); var generics = generics(owner, method); - HashSet all = new HashSet<>(generics); + Set> all = new HashSet<>(generics); // Reflexive and Transitive closure - HashSet toAdd = new HashSet<>(); + HashSet> 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 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)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 generics) { + void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set> 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 generics(ClassOrInterface classOrInterface) { + Set> generics(ClassOrInterface classOrInterface) { if (computedGenericsOfClasses.containsKey(classOrInterface)) return computedGenericsOfClasses.get(classOrInterface); - HashSet result = new HashSet<>(); + Set> 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 convert(Set> 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 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) ));