diff --git a/notizen/stf/Notes b/notizen/stf/Notes index c9fe69a5..35b14871 100644 --- a/notizen/stf/Notes +++ b/notizen/stf/Notes @@ -13,4 +13,38 @@ - Wie kommen die Mengen des Unify-Algorithmus zustande? Siehe test: /* * Test b <. a, a <. b - */ \ No newline at end of file + */ + +- + + +- Transitiven Abschluss von FC bilden um schneller Subtypen bestimmen zu können + - Problem: 2 FCs für Pairs und MPairs durch das Mapping +- Equals der Typen schreiben um instanceof Prüfungen zu vermeiden + +- Refactoring der Klassen Menge und Pair erlaubt? +++++++++++++++++++++++++++++++++++++++++++++++ + + +Instanceof wird verwendet da: + -> Entscheidung für diese Lösung, da 2-Fach-Visitor oder DoubleDispatch Pattern + enorm viele überladene Methoden zur folge hätten, nicht intuitiv wären und die rules in die Typen verschoben hätten. + +Gilt reduce für alle Typen oder nur für simple und tphs? (Vermutlich nur s und tph sonst bräuchte man keine upLow regel) + ++++++++++++++++++++++++++++++++++++++++++++++++ + +HashCode implementierungen testen (type paramerte mit einbeziehen, hashcodes cachen -> da immutable) + + ++++++++++++++++++++++++++++++++++++++++++++++++ +- Typen sind anhand ihres identifiers durchgängig identifizierbar + +- ReduceEq nur auf SimpleTypes oder auf alles anwenden? (Momentan alles) +- ReduceEq Permutation? + +EED UP + - Anwendungsreihenfolge der Regeln (wahrscheinlichste zuerst, evtl ist nach regel 1 regel 2 nie möglich etc...) + - Erase vor Reduce + - Rechenarm vor rechenintensiv + diff --git a/src/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java b/src/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java index 428c08e2..6bbd023f 100644 --- a/src/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java +++ b/src/de/dhbwstuttgart/syntaxtree/factory/UnifyTypeFactory.java @@ -1,15 +1,13 @@ package de.dhbwstuttgart.syntaxtree.factory; -import de.dhbwstuttgart.syntaxtree.type.Type; -import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; -import de.dhbwstuttgart.syntaxtree.type.WildcardType; import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType; import de.dhbwstuttgart.syntaxtree.type.ObjectType; import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType; +import de.dhbwstuttgart.syntaxtree.type.Type; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.syntaxtree.type.WildcardType; import de.dhbwstuttgart.typeinference.Menge; -import de.dhbwstuttgart.typeinference.Pair; -import de.dhbwstuttgart.typeinference.Pair.PairOperator; public class UnifyTypeFactory { diff --git a/src/de/dhbwstuttgart/typeinference/unify/Unify.java b/src/de/dhbwstuttgart/typeinference/unify/Unify.java index e4b682f9..8cd2baa9 100755 --- a/src/de/dhbwstuttgart/typeinference/unify/Unify.java +++ b/src/de/dhbwstuttgart/typeinference/unify/Unify.java @@ -2582,6 +2582,8 @@ tempKlasse.get_Superclass_Name() ); System.out.println( "P. S.: */ // ino.end + /* Alte pi-Methode: +<<<<<<< HEAD // ino.method.pi.28118.definition public static int pi( int n, String C, String D, Menge tto ) throws SCException @@ -2681,6 +2683,59 @@ tempKlasse.get_Superclass_Name() ); System.out.println( "P. S.: return nPos; } } +======= +*/ + // ino.method.pi.28118.definition + public static int pi(int n, String C, String D, Menge tto) + throws SCException { + + if (C.equals(D)) + return n; // Reduktion mit gleichen Typkonstruktoren + + RefType KlasseC = null; + RefType KlasseD = null; + + for (int i = 0; i < tto.size(); i++) { + + KlasseC = (RefType) ((Pair) tto.elementAt(i)).TA1; + KlasseD = (RefType) ((Pair) tto.elementAt(i)).TA2; + + if (KlasseC.getTypeName().equals(C) + && KlasseD.getTypeName().equals(D)) + break; + else { + KlasseC = null; + KlasseD = null; + } + } + + SCException F = new SCException(); + if (KlasseC == null && KlasseD == null) + throw F; // Fehler + + // Vektorlisten extrahieren + Menge vC = KlasseC.get_ParaList(); + Menge vD = KlasseD.get_ParaList(); + + if (vC == null || vD == null) + throw F; + + if (n >= vD.size()) + throw F; + + // Permuationswert f�r 'n' berechnen + Type TV = (Type) vD.elementAt(n); + int nPos = -1; + for (int i = 0; i < vC.size(); i++) + if (((Type) vC.elementAt(i)).getName().equals(TV.getName())) { + nPos = i; + break; + } + + return nPos; + + } + // ino.end // ino.method.printMengeUnifier.28121.definition public static void printMengeUnifier(String strMenge, Menge> Uni, int nDebug ) diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java new file mode 100644 index 00000000..0601d70f --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IFiniteClosure.java @@ -0,0 +1,53 @@ +package de.dhbwstuttgart.typeinference.unify.interfaces; + +import java.util.Optional; +import java.util.Set; + +import de.dhbwstuttgart.typinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typinference.unify.model.SimpleType; +import de.dhbwstuttgart.typinference.unify.model.SuperType; +import de.dhbwstuttgart.typinference.unify.model.Type; + +public interface IFiniteClosure { + + /** + * Returns all types of the finite closure that are subtypes of the argument. + * @return The set of subtypes of the argument. + */ + public Set smaller(Type type); + + /** + * Returns all types of the finite closure that are supertypes of the argument. + * @return The set of supertypes of the argument. + */ + public Set greater(Type type); + + /** + * Wo passt Type rein? + * @param type + * @return + */ + public Set grArg(Type type); + + /** + * Was passt in Type rein? + * @param type + * @return + */ + public Set smArg(Type type); + + public Set grArg(SimpleType type); + public Set smArg(SimpleType type); + + public Set grArg(ExtendsType type); + public Set smArg(ExtendsType type); + + public Set grArg(SuperType type); + public Set smArg(SuperType type); + + public Set grArg(PlaceholderType type); + public Set smArg(PlaceholderType type); + + public Optional getGenericType(String typeName); +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java new file mode 100644 index 00000000..02611fd9 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/IRuleSet.java @@ -0,0 +1,31 @@ +package de.dhbwstuttgart.typeinference.unify.interfaces; + +import java.util.Optional; +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unifynew.Unifier; +import de.dhbwstuttgart.typinference.unify.model.MPair; + +public interface IRuleSet { + + public Optional reduceUp(MPair pair); + public Optional reduceLow(MPair pair); + public Optional reduceUpLow(MPair pair); + public Optional> reduceExt(MPair pair); + public Optional> reduceSup(MPair pair); + public Optional> reduceEq(MPair pair); + public Optional> reduce1(MPair pair); + public Optional> reduce2(MPair pair); + + public boolean erase1(MPair pair); + public boolean erase2(MPair pair); + public boolean erase3(MPair pair); + + public Optional swap(MPair pair); + + public Optional adapt(MPair pair); + public Optional adaptExt(MPair pair); + public Optional adaptSup(MPair pair); + + public Set subst(Set pair); +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/ISetOperations.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/ISetOperations.java new file mode 100644 index 00000000..caed79e4 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/ISetOperations.java @@ -0,0 +1,8 @@ +package de.dhbwstuttgart.typeinference.unify.interfaces; + +import java.util.List; +import java.util.Set; + +public interface ISetOperations { + Set> cartesianProduct(List> sets); +} diff --git a/src/de/dhbwstuttgart/typeinference/unify/interfaces/ITypeMapper.java b/src/de/dhbwstuttgart/typeinference/unify/interfaces/ITypeMapper.java new file mode 100644 index 00000000..85efc20a --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unify/interfaces/ITypeMapper.java @@ -0,0 +1,7 @@ +package de.dhbwstuttgart.typeinference.unify.interfaces; + +import de.dhbwstuttgart.typeinference.Menge; + +public interface ITypeMapper { + +} diff --git a/src/de/dhbwstuttgart/typeinference/unifynew/GuavaSetOperations.java b/src/de/dhbwstuttgart/typeinference/unifynew/GuavaSetOperations.java new file mode 100644 index 00000000..cc4e907c --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unifynew/GuavaSetOperations.java @@ -0,0 +1,17 @@ +package de.dhbwstuttgart.typeinference.unifynew; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.Sets; + +import de.dhbwstuttgart.typeinference.unify.interfaces.ISetOperations; + +public class GuavaSetOperations implements ISetOperations { + + @Override + public Set> cartesianProduct(List> sets) { + return Sets.cartesianProduct(sets); + } + +} diff --git a/src/de/dhbwstuttgart/typeinference/unifynew/Mapping.java b/src/de/dhbwstuttgart/typeinference/unifynew/Mapping.java new file mode 100644 index 00000000..d21c5b60 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unifynew/Mapping.java @@ -0,0 +1,69 @@ +package de.dhbwstuttgart.typeinference.unifynew; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType; +import de.dhbwstuttgart.syntaxtree.type.FunN; +import de.dhbwstuttgart.syntaxtree.type.RefType; +import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType; +import de.dhbwstuttgart.syntaxtree.type.Type; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.exceptions.NotImplementedException; + +/** + * First three bits indicate the meta type: + * 000b = 0 = Simpletype + * 001b = 1 = Extends + * 010b = 2 = Super + * 011b = 3 = Type Placeholder + * 100b = 4 = Function + * + * @author DH10STF + * + */ +public class Mapping { + + private static final int ST_MASK = 0; + private static final int EXTENDS_MASK = 536870912; + private static final int SUPER_MASK = 1073741824; + private static final int TPH_MASK = 1610612736; + private static final int FUN_MASK = -2147483648; + + private static HashMap mapping; + + public Set createMapping(Iterable types) { + mapping = new HashMap<>(); + + Iterator iterator = types.iterator(); + while(iterator.hasNext() && mapping.size() <= 536870911) + createMapping(iterator.next()); + + return mapping.keySet(); + } + + private void createMapping(Type type) { + /*if(type instanceof RefType) { + Set params = ((RefType) type).get_ParaList(); + params.stream().forEach(x -> createMapping(x)); + } + */ + int typeId = mapping.size(); + + if(type instanceof RefType) + typeId |= ST_MASK; + else if(type instanceof SuperWildcardType) + typeId |= SUPER_MASK; + else if(type instanceof ExtendsWildcardType) + typeId |= EXTENDS_MASK; + else if(type instanceof TypePlaceholder) + typeId |= TPH_MASK; + else if(type instanceof FunN) + typeId |= FUN_MASK; + + //mapping.put(new MType()) + } + +} diff --git a/src/de/dhbwstuttgart/typeinference/unifynew/RuleSet.java b/src/de/dhbwstuttgart/typeinference/unifynew/RuleSet.java new file mode 100644 index 00000000..3dff9384 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unifynew/RuleSet.java @@ -0,0 +1,524 @@ +package de.dhbwstuttgart.typeinference.unifynew; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import junit.framework.Assert; +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.IRuleSet; +import de.dhbwstuttgart.typinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; +import de.dhbwstuttgart.typinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typinference.unify.model.SimpleType; +import de.dhbwstuttgart.typinference.unify.model.SuperType; +import de.dhbwstuttgart.typinference.unify.model.Type; +import de.dhbwstuttgart.typinference.unify.model.TypeParams; + +public class RuleSet implements IRuleSet{ + + protected IFiniteClosure finiteClosure; + + public RuleSet(IFiniteClosure fc) { + finiteClosure = fc; + } + + @Override + public Optional reduceUp(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + if(!(rhsType instanceof SuperType)) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + if(!(lhsType instanceof SimpleType) && !(lhsType instanceof PlaceholderType)) + return Optional.empty(); + + return Optional.of(new MPair(lhsType, ((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT)); + } + + @Override + public Optional reduceLow(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + if(!(lhsType instanceof ExtendsType)) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + if(!(rhsType instanceof SimpleType) && !(rhsType instanceof PlaceholderType)) + return Optional.empty(); + + return Optional.of(new MPair(((ExtendsType) lhsType).getExtendedType(), rhsType, PairOperator.SMALLERDOT)); + } + + @Override + public Optional reduceUpLow(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + if(!(lhsType instanceof ExtendsType)) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + if(!(rhsType instanceof SuperType)) + return Optional.empty(); + + return Optional.of(new MPair(((ExtendsType) lhsType).getExtendedType(),((SuperType) rhsType).getSuperedType(), PairOperator.SMALLERDOT)); + } + + @Override + public Optional> reduceExt(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + + if(!(lhsType instanceof SimpleType) && !(lhsType instanceof ExtendsType)) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + + if(!(rhsType instanceof ExtendsType)) + return Optional.empty(); + + if(lhsType.getTypeParams().empty() || rhsType.getTypeParams().size() != lhsType.getTypeParams().size()) + return Optional.empty(); + + int[] pi = pi(lhsType, rhsType); + + if(pi.length == 0) + return Optional.empty(); + + TypeParams rhsTypeParams = rhsType.getTypeParams(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + Set result = new HashSet<>(); + + for(int rhsIdx = 0; rhsIdx < rhsTypeParams.size(); rhsIdx++) + result.add(new MPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC)); + + return Optional.of(result); + } + + @Override + public Optional> reduceSup(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + + if(!(lhsType instanceof SimpleType) && !(lhsType instanceof SuperType)) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + + if(!(rhsType instanceof SuperType)) + return Optional.empty(); + + if(lhsType.getTypeParams().empty() || rhsType.getTypeParams().size() != lhsType.getTypeParams().size()) + return Optional.empty(); + + int[] pi = pi(lhsType, rhsType); + + if(pi.length == 0) + return Optional.empty(); + + TypeParams rhsTypeParams = rhsType.getTypeParams(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + Set result = new HashSet<>(); + + for(int rhsIdx = 0; rhsIdx < rhsTypeParams.size(); rhsIdx++) + result.add(new MPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC)); + + return Optional.of(result); + } + + @Override + public Optional> reduceEq(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + if(lhsType instanceof PlaceholderType || lhsType.getTypeParams().empty()) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + + if(!rhsType.getName().equals(lhsType.getName())) + return Optional.empty(); + + if(rhsType instanceof PlaceholderType || rhsType.getTypeParams().empty()) + return Optional.empty(); + + if(rhsType.getTypeParams().size() != lhsType.getTypeParams().size()) + return Optional.empty(); + + // TODO Permutation? + Set result = new HashSet<>(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + TypeParams rhsTypeParams = rhsType.getTypeParams(); + + for(int i = 0; i < lhsTypeParams.size(); i++) + result.add(new MPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT)); + + return Optional.of(result); + } + + @Override + public Optional> reduce1(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + if(!(lhsType instanceof SimpleType)) + return Optional.empty(); + + Type rhsType = pair.getRhsType(); + if(!(rhsType instanceof SimpleType)) + return Optional.empty(); + + SimpleType lhsSType = (SimpleType) lhsType; + SimpleType rhsSType = (SimpleType) rhsType; + + if(lhsSType.getTypeParams().empty() || lhsSType.getTypeParams().size() != rhsSType.getTypeParams().size()) + return Optional.empty(); + + int[] pi = pi(lhsSType, rhsSType); + + if(pi.length == 0) + return Optional.empty(); + + TypeParams rhsTypeParams = rhsType.getTypeParams(); + TypeParams lhsTypeParams = lhsType.getTypeParams(); + Set result = new HashSet<>(); + + for(int rhsIdx = 0; rhsIdx < rhsTypeParams.size(); rhsIdx++) + result.add(new MPair(lhsTypeParams.get(pi[rhsIdx]), rhsTypeParams.get(rhsIdx), PairOperator.SMALLERDOTWC)); + + return Optional.of(result); + } + + @Override + public Optional> reduce2(MPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return Optional.empty(); + + Type lhsType = pair.getLhsType(); + SimpleType lhsSType; + + if(lhsType instanceof SimpleType) + lhsSType = (SimpleType) lhsType; + else if(lhsType instanceof ExtendsType) + lhsSType = (SimpleType) ((ExtendsType) lhsType).getExtendedType(); + else if(lhsType instanceof SuperType) + lhsSType = (SimpleType) ((SuperType) lhsType).getSuperedType(); + else + return Optional.empty(); + + if(lhsSType.getTypeParams().empty()) + return Optional.empty(); + + Type rhsType = pair.getLhsType(); + SimpleType rhsSType; + + if(rhsType instanceof SimpleType) + rhsSType = (SimpleType) rhsType; + else if(rhsType instanceof ExtendsType) + rhsSType = (SimpleType) ((ExtendsType) rhsType).getExtendedType(); + else if(rhsType instanceof SuperType) + rhsSType = (SimpleType) ((SuperType) rhsType).getSuperedType(); + else + return Optional.empty(); + + if(!rhsSType.getName().equals(lhsSType.getName())) + return Optional.empty(); + + Assert.assertEquals(lhsSType.getTypeParams().size(), rhsSType.getTypeParams().size()); + //if(rhsSType.getTypeParams().size() != lhsSType.getTypeParams().size()) + // return Optional.empty(); + + Set result = new HashSet<>(); + + TypeParams rhsTypeParams = rhsSType.getTypeParams(); + TypeParams lhsTypeParams = lhsSType.getTypeParams(); + for(int i = 0; i < rhsTypeParams.size(); i++) + result.add(new MPair(lhsTypeParams.get(i), rhsTypeParams.get(i), PairOperator.EQUALSDOT)); + + return Optional.of(result); + } + + @Override + public boolean erase1(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return false; + + Type lhsType = pair.getLhsType(); + if(!(lhsType instanceof SimpleType) && !(lhsType instanceof PlaceholderType)) + return false; + + Type rhsType = pair.getRhsType(); + if(!(rhsType instanceof SimpleType) && !(rhsType instanceof PlaceholderType)) + return false; + + return finiteClosure.greater(lhsType).contains(rhsType); + } + + @Override + public boolean erase2(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return false; + + Type lhsType = pair.getLhsType(); + Type rhsType = pair.getRhsType(); + + return finiteClosure.grArg(lhsType).contains(rhsType); + } + + @Override + public boolean erase3(MPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return false; + + return pair.getLhsType().equals(pair.getRhsType()); + } + + @Override + public Optional swap(MPair pair) { + if(pair.getPairOp() != PairOperator.EQUALSDOT) + return Optional.empty(); + + if(pair.getLhsType() instanceof PlaceholderType) + return Optional.empty(); + + if(!(pair.getRhsType() instanceof PlaceholderType)) + return Optional.empty(); + + return Optional.of(new MPair(pair.getRhsType(), pair.getLhsType(), PairOperator.EQUALSDOT)); + } + + @Override + public Optional adapt(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOT) + return Optional.empty(); + + Type typeD = pair.getLhsType(); + if(!(typeD instanceof SimpleType)) + return Optional.empty(); + + Type typeDs = pair.getRhsType(); + if(!(typeDs instanceof SimpleType)) + return Optional.empty(); + + if(typeD.getTypeParams().size() == 0 || typeDs.getTypeParams().size() == 0) + return Optional.empty(); + + if(typeD.getName().equals(typeDs.getName())) + return Optional.empty(); + + Optional opt = finiteClosure.getGenericType(typeD.getName()); + + if(!opt.isPresent()) + return Optional.empty(); + + // The generic Version of Type D (D) + Type typeDgen = opt.get(); + + // Actually greater+ because the types are ensured to have different names + Set greater = finiteClosure.greater(typeDgen); + opt = greater.stream().filter(x -> x.getName().equals(typeDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + Type newLhs = opt.get(); + + TypeParams typeDParams = typeD.getTypeParams(); + TypeParams typeDgenParams = typeDgen.getTypeParams(); + + Unifier unif = new Unifier(typeDgenParams.get(0), typeDParams.get(0)); + for(int i = 1; i < typeDParams.size(); i++) + unif.andThen(new Unifier(typeDgenParams.get(i), typeDParams.get(i))); + + return Optional.of(new MPair(newLhs.apply(unif), typeDs, PairOperator.SMALLERDOT)); + } + + @Override + public Optional adaptExt(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + Type typeD = pair.getLhsType(); + if(!(typeD instanceof SimpleType) && !(typeD instanceof ExtendsType)) + return Optional.empty(); + + Type typeExtDs = pair.getRhsType(); + if(!(typeExtDs instanceof ExtendsType)) + return Optional.empty(); + + if(typeD.getTypeParams().size() == 0 || typeExtDs.getTypeParams().size() == 0) + return Optional.empty(); + + Type typeDgen; + if(typeD instanceof SimpleType) + typeDgen = finiteClosure.getGenericType(typeD.getName()).orElse(null); + else { + Optional opt = finiteClosure.getGenericType(((ExtendsType) typeD).getExtendedType().getName()); + typeDgen = opt.isPresent() ? new ExtendsType(opt.get()) : null; + } + + if(typeDgen == null) + return Optional.empty(); + + Set grArg = finiteClosure.grArg(typeDgen); + + Optional opt = grArg.stream().filter(x -> x.getName().equals(typeExtDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + Type newLhs = ((ExtendsType) opt.get()).getExtendedType(); + + TypeParams typeDParams = typeD.getTypeParams(); + TypeParams typeDgenParams = typeDgen.getTypeParams(); + + Unifier unif = new Unifier(typeDgenParams.get(0), typeDParams.get(0)); + for(int i = 1; i < typeDParams.size(); i++) + unif.andThen(new Unifier(typeDgenParams.get(i), typeDParams.get(i))); + + return Optional.of(new MPair(newLhs.apply(unif), typeExtDs, PairOperator.SMALLERDOTWC)); + } + + @Override + public Optional adaptSup(MPair pair) { + if(pair.getPairOp() != PairOperator.SMALLERDOTWC) + return Optional.empty(); + + Type typeDs = pair.getLhsType(); + if(!(typeDs instanceof SimpleType) && !(typeDs instanceof SuperType)) + return Optional.empty(); + + Type typeSupD = pair.getRhsType(); + if(!(typeSupD instanceof SuperType)) + return Optional.empty(); + + if(typeDs.getTypeParams().size() == 0 || typeSupD.getTypeParams().size() == 0) + return Optional.empty(); + + + Optional opt = finiteClosure.getGenericType(((SuperType) typeSupD).getSuperedType().getName()); + + if(!opt.isPresent()) + return Optional.empty(); + + Type typeDgen = opt.get(); + Type typeSupDgen = new SuperType(typeDgen); + + // Use of smArg instead of grArg because + // a in grArg(b) => b in smArg(a) + Set smArg = finiteClosure.smArg(typeSupDgen); + opt = smArg.stream().filter(x -> x.getName().equals(typeDs.getName())).findAny(); + + if(!opt.isPresent()) + return Optional.empty(); + + // New RHS + Type newRhs = null; + if(typeDs instanceof SimpleType) + newRhs = new ExtendsType(typeDs); + else + newRhs = new ExtendsType(((SuperType) typeDs).getSuperedType()); + + // New LHS + Type newLhs = opt.get(); + TypeParams typeDParams = typeSupD.getTypeParams(); + TypeParams typeSupDsgenParams = typeSupDgen.getTypeParams(); + + Unifier unif = new Unifier(typeSupDsgenParams.get(0), typeDParams.get(0)); + for(int i = 1; i < typeDParams.size(); i++) + unif.andThen(new Unifier(typeSupDsgenParams.get(i), typeDParams.get(i))); + + return Optional.of(new MPair(newLhs.apply(unif), newRhs, PairOperator.SMALLERDOTWC)); + } + + /** + * Finds the permutation pi of the type arguments of two types based on the finite closure + * @param C The type which arguments are permuted + * @param D The other type + * @return An array containing the values of pi for every type argument of C or an empty array if the search failed. + */ + private int[] pi(Type C, Type D) { + Type cFromFc = null; + if(C instanceof SimpleType) + cFromFc = finiteClosure.getGenericType(C.getName()).orElse(null); + else if(C instanceof ExtendsType) { + Optional opt = finiteClosure.getGenericType(((ExtendsType) C).getExtendedType().getName()); + if(opt.isPresent()) cFromFc = new ExtendsType(opt.get()); + } + else if(C instanceof SuperType) { + Optional opt = finiteClosure.getGenericType(((SuperType) C).getSuperedType().getName()); + if(opt.isPresent()) cFromFc = new SuperType(opt.get()); + } + + if(cFromFc == null) + return new int[0]; + + Optional opt = Optional.empty(); + if(D instanceof ExtendsType) { + SimpleType dSType = (SimpleType) ((ExtendsType) D).getExtendedType(); + opt = finiteClosure.grArg(cFromFc).stream() + .filter(x -> x instanceof ExtendsType) + .filter(x -> ((ExtendsType) x).getExtendedType().getName().equals(dSType.getName())).findAny(); + } + else if(D instanceof SuperType) { + SimpleType dSType = (SimpleType) ((SuperType) D).getSuperedType(); + opt = finiteClosure.grArg(cFromFc).stream() + .filter(x -> x instanceof SuperType) + .filter(x -> ((SuperType) x).getSuperedType().getName().equals(dSType.getName())).findAny(); + } + else if (D instanceof SimpleType) + opt = finiteClosure.greater(cFromFc).stream() + .filter(x -> x.getName().equals(D.getName())).findAny(); + + if(!opt.isPresent()) + return new int[0]; + + Type dFromFc = opt.get(); + + Assert.assertEquals(cFromFc.getTypeParams().size(), dFromFc.getTypeParams().size()); + Assert.assertTrue(dFromFc.getTypeParams().size() > 0); + + TypeParams cArgs = cFromFc.getTypeParams(); + TypeParams dArgs = dFromFc.getTypeParams(); + + int[] permutation = new int[dArgs.size()]; + + boolean succ = true; + for (int dArgIdx = 0; dArgIdx < dArgs.size() && succ; dArgIdx++) { + Type dArg = dArgs.get(dArgIdx); + succ = false; + for (int pi = 0; pi < cArgs.size(); pi++) + if (cArgs.get(pi).getName().equals(dArg.getName())) { + permutation[dArgIdx] = pi; + succ = true; + break; + } + } + + if(succ) return permutation; + return new int[0]; + } + + @Override + public Set subst(Set pair) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/de/dhbwstuttgart/typeinference/unifynew/Unifier.java b/src/de/dhbwstuttgart/typeinference/unifynew/Unifier.java new file mode 100644 index 00000000..ecd56cf1 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unifynew/Unifier.java @@ -0,0 +1,29 @@ +package de.dhbwstuttgart.typeinference.unifynew; + +import java.util.function.Function; + +import de.dhbwstuttgart.typinference.unify.model.Type; +import de.dhbwstuttgart.typinference.unify.model.TypeParams; + +public class Unifier implements Function { + private Type source; + private Type target; + + public Unifier(Type source, Type target) { + this.source = source; + this.target = target; + } + + @Override + public Type apply(Type t) { + return t.apply(this); + } + + public Type getSource() { + return source; + } + + public Type getTarget() { + return target; + } +} diff --git a/src/de/dhbwstuttgart/typeinference/unifynew/Unify.java b/src/de/dhbwstuttgart/typeinference/unifynew/Unify.java new file mode 100644 index 00000000..33943e85 --- /dev/null +++ b/src/de/dhbwstuttgart/typeinference/unifynew/Unify.java @@ -0,0 +1,257 @@ +package de.dhbwstuttgart.typeinference.unifynew; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import de.dhbwstuttgart.typeinference.Menge; +import de.dhbwstuttgart.typeinference.Pair; +import de.dhbwstuttgart.typeinference.exceptions.NotImplementedException; +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unify.interfaces.IRuleSet; +import de.dhbwstuttgart.typeinference.unify.interfaces.ISetOperations; +import de.dhbwstuttgart.typinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; +import de.dhbwstuttgart.typinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typinference.unify.model.SuperType; +import de.dhbwstuttgart.typinference.unify.model.Type; + + +/** + * Implementation of the type unification algorithm + * @author Florian Steurer + */ +public class Unify { + + public Menge> unify(Set eq, IFiniteClosure fc) { + /* + * Step 1: Repeated application of reduce, adapt, erase, swap + */ + + Set eq0 = applyTypeUnificationRules(eq, fc); + + /* + * Step 2 and 3: Create a subset eq1s of pairs where both sides are TPH and eq2s of the other pairs + */ + + Set eq1s = new HashSet<>(); + Set eq2s = new HashSet<>(); + splitEq(eq0, eq1s, eq2s); + + /* + * Step 4: Create possible typings + */ + + // Sets that originate from pair pattern matching + // Sets of the "second level" + List>> pairSetsSet = calculatePairSets(eq2s, fc); + + // The sets of the "first level" + Set> sets = new HashSet>(); + sets.add(eq1s); // Add Eq1' + + // Add the set of [a =. Theta | (a=. Theta) in Eq2'] + sets.add(eq2s.stream() + .filter(x -> x.getPairOp() == PairOperator.EQUALSDOT && x.getLhsType() instanceof PlaceholderType) + .collect(Collectors.toSet())); + + /* Up to here, no cartesian products are calculated. + * Around here, filters for pairs and sets can be applied */ + + ISetOperations setOps = new GuavaSetOperations(); + + // Calculate the inner cartesian products + // Cartesian products of the second level + for(List> pairSets : pairSetsSet) // Prüfen ob addAll stimmt oder ob hier eigentlich nur 1 set sein sollte + setOps.cartesianProduct(pairSets).forEach(x -> sets.add(new HashSet(x))); + + // Calculate the outer cartesian products + // Cartesian products of the first level + Set> eqsSet = setOps.cartesianProduct(new ArrayList<>(sets)); + + /* + * Step 5: Substitution + */ + + + /* + * Step 6: a) Restart for pairs where subst was applied + * b) Union over everything + */ + + /* + * Step 7: Filter result for solved pairs + */ + + throw new NotImplementedException(); + } + + protected Set applyTypeUnificationRules(Set eq, IFiniteClosure fc) { + + /* + * Rule Application Strategy: + * + * 1. Swap all pairs and erase all erasable pairs + * 2. Apply all possible rules to a single pair, then move it to the result set. + * Iterating over pairs first, then iterating over rules prevents the application + * of rules to a "finished" pair over and over. + * 2.1 Apply all rules repeatedly except for erase rules. If + * the application of a rule creates new pairs, check immediately + * against the erase rules. + */ + + + LinkedHashSet targetSet = new LinkedHashSet(); + LinkedList eqQueue = new LinkedList<>(); + IRuleSet rules = new RuleSet(fc); + + /* + * Swap all pairs and erase all erasable pairs + */ + eq.forEach(x -> swapAddOrErase(x, rules, eqQueue)); + + /* + * Apply rules until the queue is empty + */ + while(!eqQueue.isEmpty()) { + MPair pair = eqQueue.pollFirst(); + + // ReduceUp, ReduceLow, ReduceUpLow + Optional opt = rules.reduceUpLow(pair); + opt = opt.isPresent() ? opt : rules.reduceLow(pair); + opt = opt.isPresent() ? opt : rules.reduceUp(pair); + + // One of the rules has been applied + if(opt.isPresent()) { + swapAddOrErase(opt.get(), rules, eqQueue); + continue; + } + + // Reduce1, Reduce2, ReduceExt, ReduceSup, ReduceEq + Optional> optSet = rules.reduce1(pair); + optSet = optSet.isPresent() ? optSet : rules.reduce2(pair); + optSet = optSet.isPresent() ? optSet : rules.reduceExt(pair); + optSet = optSet.isPresent() ? optSet : rules.reduceSup(pair); + optSet = optSet.isPresent() ? optSet : rules.reduceEq(pair); + + // One of the rules has been applied + if(optSet.isPresent()) { + optSet.get().forEach(x -> swapAddOrErase(x, rules, eqQueue)); + continue; + } + + // Adapt, AdaptExt, AdaptSup + opt = rules.adapt(pair); + opt = opt.isPresent() ? opt : rules.adaptExt(pair); + opt = opt.isPresent() ? opt : rules.adaptSup(pair); + + // One of the rules has been applied + if(opt.isPresent()) { + swapAddOrErase(opt.get(), rules, eqQueue); + continue; + } + + // None of the rules has been applied + targetSet.add(pair); + } + + return targetSet; + } + + protected void swapAddOrErase(MPair pair, IRuleSet rules, Collection collection) { + Optional opt = rules.swap(pair); + MPair pair2 = opt.isPresent() ? opt.get() : pair; + + if(rules.erase1(pair2) || rules.erase3(pair2) || rules.erase2(pair2)) + return; + + collection.add(pair2); + } + + protected void splitEq(Set eq, Set eq1s, Set eq2s) { + for(MPair pair : eq) + if(pair.getLhsType() instanceof PlaceholderType && pair.getRhsType() instanceof PlaceholderType) + eq1s.add(pair); + else + eq2s.add(pair); + } + + + protected List>> calculatePairSets(Set eq2s, IFiniteClosure fc) { + List>> result = new ArrayList>>(); + for(int i = 0; i < 8; i++) + result.add(new ArrayList>()); + + + for(MPair pair : eq2s) { + + PairOperator pairOp = pair.getPairOp(); + Type lhsType = pair.getLhsType(); + Type rhsType = pair.getRhsType(); + + // Case 1: (a <. Theta') + if(pairOp == PairOperator.SMALLERDOT && lhsType instanceof PlaceholderType) { + // TODO + } + + // Case 2: (a <.? ? ext Theta') + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof ExtendsType){ + // TODO + } + + // Case 3: (a <.? ? sup Theta') + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType && rhsType instanceof SuperType) { + Set set = new HashSet<>(); + for(Type theta : fc.smArg(rhsType)) + set.add(new MPair(lhsType, theta, PairOperator.EQUALSDOT)); + + result.get(2).add(set); + } + + // Case 4: (a <.? Theta') + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof PlaceholderType) { + Set set = new HashSet<>(); + set.add(new MPair(lhsType, ((ExtendsType) rhsType).getExtendedType(), PairOperator.EQUALSDOT)); + result.get(3).add(set); + } + + // Case 5: (Theta <. a) + else if(pairOp == PairOperator.SMALLERDOT && rhsType instanceof PlaceholderType) { + Set set = new HashSet<>(); + for(Type thetaS : fc.greater(lhsType)) + set.add(new MPair(rhsType, thetaS, PairOperator.EQUALSDOT)); + result.get(4).add(set); + } + + // Case 6: (? ext Theta <.? a) + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof ExtendsType && rhsType instanceof PlaceholderType) { + Set set = new HashSet<>(); + for(Type thetaS : fc.grArg(lhsType)) + set.add(new MPair(rhsType, thetaS, PairOperator.EQUALSDOT)); + result.get(5).add(set); + } + + // Case 7: (? sup Theta <.? a) + else if(pairOp == PairOperator.SMALLERDOTWC && lhsType instanceof SuperType && rhsType instanceof PlaceholderType) { + // TODO + } + + // Case 8: (Theta <.? a) + else if(pairOp == PairOperator.SMALLERDOTWC && rhsType instanceof PlaceholderType) { + Set set = new HashSet<>(); + for(Type thetaS : fc.grArg(lhsType)) + set.add(new MPair(rhsType, thetaS, PairOperator.EQUALSDOT)); + result.get(7).add(set); + } + } + + return result.stream().filter(x -> !x.isEmpty()).collect(Collectors.toList()); + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/ExtendsType.java b/src/de/dhbwstuttgart/typinference/unify/model/ExtendsType.java new file mode 100644 index 00000000..2b0facaf --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/ExtendsType.java @@ -0,0 +1,58 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public final class ExtendsType extends Type { + private Type extendedType; + + public ExtendsType(Type extendedType) { + super("? extends " + extendedType.getName(), extendedType.getTypeParams()); + this.extendedType = extendedType; + } + + public Type getExtendedType() { + return extendedType; + } + + @Override + public TypeParams getTypeParams() { + return extendedType.getTypeParams(); + } + + @Override + public String toString() { + return "? extends " + extendedType; + } + + @Override + public Set smArg(IFiniteClosure fc) { + return fc.smArg(this); + } + + @Override + public Set grArg(IFiniteClosure fc) { + return fc.grArg(this); + } + + @Override + public int hashCode() { + return extendedType.hashCode() + 17; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof ExtendsType)) + return false; + + ExtendsType other = (ExtendsType) obj; + return other.getExtendedType().equals(extendedType); + } + + @Override + public Type apply(Unifier unif) { + return new ExtendsType(extendedType.apply(unif)); + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/FiniteClosure.java b/src/de/dhbwstuttgart/typinference/unify/model/FiniteClosure.java new file mode 100644 index 00000000..ae36f465 --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/FiniteClosure.java @@ -0,0 +1,208 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; + +public class FiniteClosure implements IFiniteClosure { + + private HashMap> inheritanceGraph; + private HashMap>> strInheritanceGraph; + + public FiniteClosure(Set pairs) { + + inheritanceGraph = new HashMap>(); + + // Build the transitive closure of the inheritance tree + for(MPair pair : pairs) { + if(pair.getPairOp() != PairOperator.SMALLER) + continue; + + // Add nodes if not already in the graph + if(!inheritanceGraph.containsKey(pair.getLhsType())) + inheritanceGraph.put(pair.getLhsType(), new Node(pair.getLhsType())); + if(!inheritanceGraph.containsKey(pair.getRhsType())) + inheritanceGraph.put(pair.getRhsType(), new Node(pair.getRhsType())); + + Node childNode = inheritanceGraph.get(pair.getLhsType()); + Node parentNode = inheritanceGraph.get(pair.getRhsType()); + + // Add edge + parentNode.AddDescendant(childNode); + + // Add edges to build the transitive closure + parentNode.getPredecessors().stream().forEach(x -> x.AddDescendant(childNode)); + childNode.getDescendants().stream().forEach(x -> x.AddPredecessor(parentNode)); + } + + // Build the alternative representation with strings as keys + + strInheritanceGraph = new HashMap<>(); + for(Type key : inheritanceGraph.keySet()) { + if(!strInheritanceGraph.containsKey(key.getName())) + strInheritanceGraph.put(key.getName(), new HashSet<>()); + + strInheritanceGraph.get(key.getName()).add(inheritanceGraph.get(key)); + } + } + + /** + * Returns all types of the finite closure that are subtypes of the argument. + * @return The set of subtypes of the argument. + */ + @Override + public Set smaller(Type type) { + if(!inheritanceGraph.containsKey(type)) + return new HashSet<>(); + + Set result = inheritanceGraph.get(type).getContentOfDescendants(); + result.add(type); + + return result; + } + + /** + * Returns all types of the finite closure that are supertypes of the argument. + * @return The set of supertypes of the argument. + */ + @Override + public Set greater(Type type) { + if(!inheritanceGraph.containsKey(type)) + return new HashSet<>(); + + Set result = inheritanceGraph.get(type).getContentOfPredecessors(); + result.add(type); + return result; + } + + @Override + public Set grArg(Type type) { + return type.grArg(this); + } + + @Override + public Set grArg(SimpleType type) { + if(!inheritanceGraph.containsKey(type)) + return new HashSet(); + + Set result = new HashSet(); + + result.add(type); + smaller(type).forEach(x -> result.add(new SuperType(x))); + greater(type).forEach(x -> result.add(new ExtendsType(x))); + + return result; + } + + @Override + public Set grArg(ExtendsType type) { + if(!inheritanceGraph.containsKey(type.getExtendedType())) + return new HashSet(); + + Set result = new HashSet(); + + Type t = type.getExtendedType(); + + greater(t).forEach(x -> result.add(new ExtendsType(x))); + + return result; + } + + @Override + public Set grArg(SuperType type) { + if(!inheritanceGraph.containsKey(type.getSuperedType())) + return new HashSet(); + + Set result = new HashSet(); + + Type t = type.getSuperedType(); + + smaller(t).forEach(x -> result.add(new SuperType(x))); + + return result; + } + + @Override + public Set grArg(PlaceholderType type) { + return new HashSet<>(); + } + + @Override + public Set smArg(Type type) { + return type.smArg(this); + } + + @Override + public Set smArg(SimpleType type) { + if(!inheritanceGraph.containsKey(type)) + return new HashSet(); + + Set result = new HashSet(); + + result.add(type); + smaller(type).forEach(x -> result.add(new ExtendsType(x))); + + return result; + } + + public Set smArg(ExtendsType type) { + if(!inheritanceGraph.containsKey(type.getExtendedType())) + return new HashSet(); + + Set result = new HashSet(); + + Type t = type.getExtendedType(); + + result.add(t); + smaller(t).forEach(x -> { + result.add(new ExtendsType(x)); + result.add(x); + }); + + return result; + } + + + @Override + public Set smArg(SuperType type) { + if(!inheritanceGraph.containsKey(type.getSuperedType())) + return new HashSet(); + + Set result = new HashSet(); + + Type t = type.getSuperedType(); + + result.add(t); + greater(t).forEach(x -> { + result.add(new SuperType(x)); + result.add(x); + }); + + return result; + } + + @Override + public Set smArg(PlaceholderType type) { + return new HashSet<>(); + } + + @Override + public Optional getGenericType(String typeName) { + if(!strInheritanceGraph.containsKey(typeName)) + return Optional.empty(); + + HashSet> candidates = strInheritanceGraph.get(typeName); + + for(Node node : candidates) { + Type candidate = node.getContent(); + if(candidate.getTypeParams().arePlaceholders()) + return Optional.of(candidate); + } + + return Optional.empty(); + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/MPair.java b/src/de/dhbwstuttgart/typinference/unify/model/MPair.java new file mode 100644 index 00000000..9a76f2a9 --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/MPair.java @@ -0,0 +1,97 @@ +package de.dhbwstuttgart.typinference.unify.model; + +public class MPair { + + public enum PairOperator { + SMALLER, + SMALLERDOT, + SMALLERDOTWC, + EQUALS, + EQUALSDOT; + + @Override + public String toString() { + switch (this) { + case SMALLER: + return "<"; + case SMALLERDOT: + return "<."; + case SMALLERDOTWC: + return "<.?"; + case EQUALS: + return "="; + default: + return "=."; + } + }; + } + + private Type lhs; + private Type rhs; + private PairOperator pairOp; + + /*public MPair(Type t1, Type t2) { + lhs = t1; + rhs = t2; + pairOp = PairOperator.SMALLER; + }*/ + + public MPair(Type t1, Type t2, PairOperator op) { + lhs = t1; + rhs = t2; + pairOp = op; + } + + public Type getLhsType() { + return lhs; + } + + public Type getRhsType() { + return rhs; + } + + public PairOperator getPairOp() { + return pairOp; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof MPair)) + return false; + + MPair other = (MPair) obj; + + return other.getPairOp() == pairOp + && other.getLhsType().equals(lhs) + && other.getRhsType().equals(rhs); + } + + /** + * Substitutes the occurrences of Type t on the left or right side of the pair with the Type subst. + * @param t Type to be replaced. + * @param subst The type replacing t. + * @return A pair where occurrences of t are replaced by subst. + */ + public MPair substitute(Type t, Type subst) { + Type newlhs = lhs; + if(lhs.equals(t)) newlhs = subst; + + Type newrhs = rhs; + if(rhs.equals(t)) newrhs = subst; + + if(newlhs == lhs && newrhs == rhs) return this; + return new MPair(newlhs, newrhs, pairOp); + } + + @Override + public int hashCode() { + return 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode(); + } + + @Override + public String toString() { + return "(" + lhs + " " + pairOp + " " + rhs + ")"; + } +} + + diff --git a/src/de/dhbwstuttgart/typinference/unify/model/Node.java b/src/de/dhbwstuttgart/typinference/unify/model/Node.java new file mode 100644 index 00000000..e42a2608 --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/Node.java @@ -0,0 +1,57 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class Node { + private T content; + + private HashSet> predecessors = new HashSet<>(); + private HashSet> descendants = new HashSet<>(); + + public Node(T content) { + this.content = content; + } + + public void AddDescendant(Node descendant) { + if(descendants.contains(descendant)) + return; + + descendants.add(descendant); + descendant.AddPredecessor(this); + } + + public void AddPredecessor(Node predecessor) { + if(predecessors.contains(predecessor)) + return; + + predecessors.add(predecessor); + predecessor.AddDescendant(this); + } + + public T getContent() { + return content; + } + + public Set> getPredecessors() { + return predecessors; + } + + public Set> getDescendants() { + return descendants; + } + + public Set getContentOfDescendants() { + return descendants.stream().map(x -> x.getContent()).collect(Collectors.toSet()); + } + + public Set getContentOfPredecessors() { + return predecessors.stream().map(x -> x.getContent()).collect(Collectors.toSet()); + } + + @Override + public String toString() { + return "Node(" + content.toString() + ")"; + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/PlaceholderType.java b/src/de/dhbwstuttgart/typinference/unify/model/PlaceholderType.java new file mode 100644 index 00000000..7b7503ee --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/PlaceholderType.java @@ -0,0 +1,44 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public final class PlaceholderType extends Type{ + + public PlaceholderType(String name) { + super(name); + } + + @Override + public Set smArg(IFiniteClosure fc) { + return fc.smArg(this); + } + + @Override + public Set grArg(IFiniteClosure fc) { + return fc.grArg(this); + } + + @Override + public int hashCode() { + return typeName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof PlaceholderType)) + return false; + + return ((PlaceholderType) obj).getName().equals(typeName); + } + + @Override + public Type apply(Unifier unif) { + if(this.equals(unif.getSource())) + return unif.getTarget(); + + return this; + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/SimpleType.java b/src/de/dhbwstuttgart/typinference/unify/model/SimpleType.java new file mode 100644 index 00000000..8e9e8a3f --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/SimpleType.java @@ -0,0 +1,52 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public final class SimpleType extends Type { + public SimpleType(String name, Type... typeParams) { + super(name, new TypeParams(typeParams)); + } + + private SimpleType(String name, TypeParams params) { + super(name, params); + } + + @Override + public Set smArg(IFiniteClosure fc) { + return fc.smArg(this); + } + + @Override + public Set grArg(IFiniteClosure fc) { + return fc.grArg(this); + } + + @Override + public int hashCode() { + return typeName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof SimpleType)) + return false; + + SimpleType other = (SimpleType) obj; + + if(!other.getName().equals(typeName)) + return false; + + return other.getTypeParams().equals(typeParams); + } + + @Override + public Type apply(Unifier unif) { + if(this.equals(unif.getSource())) + return unif.getTarget(); + + return new SimpleType(typeName, typeParams.apply(unif)); + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/SuperType.java b/src/de/dhbwstuttgart/typinference/unify/model/SuperType.java new file mode 100644 index 00000000..15c432d2 --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/SuperType.java @@ -0,0 +1,59 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public final class SuperType extends Type { + + private Type superedType; + + public SuperType(Type superedType) { + super("? super " + superedType.getName(), superedType.getTypeParams()); + this.superedType = superedType; + } + + public Type getSuperedType() { + return superedType; + } + + @Override + public String toString() { + return "? super " + superedType; + } + + @Override + public TypeParams getTypeParams() { + return superedType.getTypeParams(); + } + + @Override + public Set smArg(IFiniteClosure fc) { + return fc.smArg(this); + } + + @Override + public Set grArg(IFiniteClosure fc) { + return fc.grArg(this); + } + + @Override + public int hashCode() { + return superedType.hashCode() + 17; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof SuperType)) + return false; + + SuperType other = (SuperType) obj; + return other.getSuperedType().equals(superedType); + } + + @Override + public Type apply(Unifier unif) { + return new SuperType(superedType.apply(unif)); + } +} diff --git a/src/de/dhbwstuttgart/typinference/unify/model/Type.java b/src/de/dhbwstuttgart/typinference/unify/model/Type.java new file mode 100644 index 00000000..a9e94862 --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/Type.java @@ -0,0 +1,48 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public abstract class Type { + + protected final String typeName; + protected final TypeParams typeParams; + + protected Type(String name, Type... typeParams) { + typeName = name; + this.typeParams = new TypeParams(typeParams); + } + + protected Type(String name, TypeParams p) { + typeName = name; + typeParams = p; + } + + public String getName() { + return typeName; + } + + public TypeParams getTypeParams() { + return typeParams; + } + + public abstract Set smArg(IFiniteClosure fc); + + public abstract Set grArg(IFiniteClosure fc); + + public abstract Type apply(Unifier unif); + + @Override + public String toString() { + String params = ""; + if(typeParams.size() != 0) { + for(Type param : typeParams) + params += param.toString() + ","; + params = "<" + params.substring(0, params.length()-1) + ">"; + } + + return typeName + params; + } +} \ No newline at end of file diff --git a/src/de/dhbwstuttgart/typinference/unify/model/TypeParams.java b/src/de/dhbwstuttgart/typinference/unify/model/TypeParams.java new file mode 100644 index 00000000..d723395d --- /dev/null +++ b/src/de/dhbwstuttgart/typinference/unify/model/TypeParams.java @@ -0,0 +1,83 @@ +package de.dhbwstuttgart.typinference.unify.model; + +import java.util.Arrays; +import java.util.Iterator; + +import de.dhbwstuttgart.typeinference.unifynew.Unifier; + +public final class TypeParams implements Iterable{ + private final Type[] typeParams; + + public TypeParams(Type... types) { + typeParams = types; + } + + public boolean arePlaceholders() { + for(Type t : typeParams) + if(!(t instanceof PlaceholderType)) + return false; + return true; + } + + @Override + public String toString() { + String res = ""; + for(Type t : typeParams) + res += t + ","; + return "<" + res.substring(0, res.length()-1) + ">"; + } + + public int size() { + return typeParams.length; + } + + public boolean empty() { + return typeParams.length == 0; + } + + public TypeParams apply(Unifier unif) { + Type[] newParams = new Type[typeParams.length]; + for(int i = 0; i < typeParams.length; i++) + newParams[i] = typeParams[i].apply(unif); + return new TypeParams(newParams); + } + + public boolean contains(Type t) { + for(Type t1 : typeParams) + if(t1.equals(t1)) + return true; + return false; + } + + public Type get(int i) { + return typeParams[i]; + } + + @Override + public Iterator iterator() { + return Arrays.stream(typeParams).iterator(); + } + + @Override + public int hashCode() { + return Arrays.hashCode(typeParams); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof TypeParams)) + return false; + + TypeParams other = (TypeParams) obj; + + if(other.size() != this.size()) + return false; + + for(int i = 0; i < this.size(); i++) + if(!(this.get(i).equals(other.get(i)))) + return false; + + return true; + } +} + diff --git a/test/unify/FiniteClosureBuilder.java b/test/unify/FiniteClosureBuilder.java new file mode 100644 index 00000000..815d637d --- /dev/null +++ b/test/unify/FiniteClosureBuilder.java @@ -0,0 +1,64 @@ +package unify; + +import java.util.HashSet; +import java.util.Set; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typinference.unify.model.FiniteClosure; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; +import de.dhbwstuttgart.typinference.unify.model.Type; + +public class FiniteClosureBuilder { + + private Set pairs = new HashSet<>(); + + public void add(Type sub, Type sup) { + pairs.add(new MPair(sub, sup, PairOperator.SMALLER)); + } + + public IFiniteClosure getFiniteClosure() { + return new FiniteClosure(pairs); + } + + public void clear() { + pairs = new HashSet<>(); + } + + public IFiniteClosure getCollectionExample() { + TypeFactory tf = new TypeFactory(); + + Type collection = tf.getSimpleType("Collection"); + Type set = tf.getSimpleType("Set", "T"); + Type sortedSet = tf.getSimpleType("Set", "T"); + Type TreeSet = tf.getSimpleType("TreeSet", "T"); + Type hashSet = tf.getSimpleType("HashSet", "T"); + Type linkedHashSet = tf.getSimpleType("LinkedHashSet", "T"); + Type queue = tf.getSimpleType("Queue", "T"); + Type deque = tf.getSimpleType("Deque", "T"); + Type linkedList = tf.getSimpleType("LinkedList", "T"); + Type list = tf.getSimpleType("List", "T"); + Type vector = tf.getSimpleType("Vector", "T"); + Type stack = tf.getSimpleType("Stack", "T"); + Type arrayList = tf.getSimpleType("ArrayList", "T"); + + add(set, collection); + add(sortedSet, set); + add(TreeSet, sortedSet); + add(hashSet, set); + add(linkedHashSet, set); + + add(queue, collection); + add(deque, queue); + add(linkedList, deque); + add(list, collection); + add(linkedList, list); + add(vector, list); + add(arrayList, list); + add(stack, vector); + + IFiniteClosure fc = getFiniteClosure(); + clear(); + return fc; + } +} diff --git a/test/unify/FiniteClosureTest.java b/test/unify/FiniteClosureTest.java new file mode 100644 index 00000000..d3744abe --- /dev/null +++ b/test/unify/FiniteClosureTest.java @@ -0,0 +1,57 @@ +package unify; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.Type; + +public class FiniteClosureTest { + + @Test + public void testGreater() { + IFiniteClosure fc = new FiniteClosureBuilder().getCollectionExample(); + TypeFactory tf = new TypeFactory(); + + System.out.println("\n\n----- Greater Test -----"); + System.out.println("Greater(LinkedList) = " + fc.greater(tf.getSimpleType("LinkedList", "T"))); + System.out.println("Greater(TreeSet) = " + fc.greater(tf.getSimpleType("TreeSet", "T"))); + System.out.println("Greater(Collection) = " + fc.greater(tf.getSimpleType("Collection"))); + } + + @Test + public void testGrArg() { + IFiniteClosure fc = new FiniteClosureBuilder().getCollectionExample(); + TypeFactory tf = new TypeFactory(); + + System.out.println("\n\n----- GrArg Test -----"); + System.out.println("GrArg(List) = " + fc.grArg(tf.getSimpleType("List", "T"))); + System.out.println("GrArg(? extends List) = " + fc.grArg(tf.getExtendsType(tf.getSimpleType("List", "T")))); + System.out.println("GrArg(? super List) = " + fc.grArg(tf.getSuperType(tf.getSimpleType("List", "T")))); + } + + @Test + public void testSmaller() { + IFiniteClosure fc = new FiniteClosureBuilder().getCollectionExample(); + TypeFactory tf = new TypeFactory(); + + System.out.println("\n\n----- Smaller Test -----"); + System.out.println("Smaller(List) = " + fc.smaller(tf.getSimpleType("List", "T"))); + System.out.println("Smaller(TreeSet) = " + fc.smaller(tf.getSimpleType("TreeSet", "T"))); + System.out.println("Smaller(Collection) = " + fc.smaller(tf.getSimpleType("Collection"))); + } + + @Test + public void testSmArg() { + IFiniteClosure fc = new FiniteClosureBuilder().getCollectionExample(); + TypeFactory tf = new TypeFactory(); + + System.out.println("\n\n----- SmArg Test -----"); + System.out.println("SmArg(List) = " + fc.smArg(tf.getSimpleType("List", "T"))); + System.out.println("SmArg(? extends List) = " + fc.smArg(tf.getExtendsType(tf.getSimpleType("List", "T")))); + System.out.println("SmArg(? super List) = " + fc.smArg(tf.getSuperType(tf.getSimpleType("List", "T")))); + } +} diff --git a/test/unify/RuleSetTest.java b/test/unify/RuleSetTest.java new file mode 100644 index 00000000..fa08b1e7 --- /dev/null +++ b/test/unify/RuleSetTest.java @@ -0,0 +1,686 @@ +package unify; + + +import java.util.Optional; +import java.util.Set; + +import junit.framework.Assert; + +import org.junit.Test; + +import de.dhbwstuttgart.typeinference.unify.interfaces.IRuleSet; +import de.dhbwstuttgart.typeinference.unifynew.RuleSet; +import de.dhbwstuttgart.typinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; +import de.dhbwstuttgart.typinference.unify.model.SimpleType; +import de.dhbwstuttgart.typinference.unify.model.SuperType; + + +public class RuleSetTest { + + @Test + public void testReduceUp() { + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getFiniteClosure()); + TypeFactory tf = new TypeFactory(); + + /* + * Positive Tests + */ + + MPair reduce1 = new MPair(tf.getSimpleType("type"), tf.getSuperType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair reduce2 = new MPair(tf.getPlaceholderType("T"), tf.getSuperType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + + MPair expected1 = new MPair(tf.getSimpleType("type"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair expected2 = new MPair(tf.getPlaceholderType("T"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + + Optional opt1 = rules.reduceUp(reduce1); + Optional opt2 = rules.reduceUp(reduce2); + + Assert.assertTrue(opt1.isPresent()); + Assert.assertTrue(opt2.isPresent()); + Assert.assertEquals(opt1.get(), expected1); + Assert.assertEquals(opt2.get(), expected2); + + /* + * Negative Tests + */ + + MPair noreduce1 = new MPair(tf.getSuperType(tf.getSimpleType("type")), tf.getSuperType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair noreduce2 = new MPair(tf.getPlaceholderType("T"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair noreduce3 = new MPair(tf.getPlaceholderType("T"), tf.getExtendsType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair noreduce4 = new MPair(tf.getPlaceholderType("T"), tf.getSuperType(tf.getSimpleType("type")), PairOperator.EQUALSDOT); + + Assert.assertFalse(rules.reduceUp(noreduce1).isPresent()); + Assert.assertFalse(rules.reduceUp(noreduce2).isPresent()); + Assert.assertFalse(rules.reduceUp(noreduce3).isPresent()); + Assert.assertFalse(rules.reduceUp(noreduce4).isPresent()); + } + + @Test + public void testReduceLow() { + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getFiniteClosure()); + TypeFactory tf = new TypeFactory(); + + /* + * Positive Tests + */ + MPair reduce1 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair reduce2 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getPlaceholderType("T"), PairOperator.SMALLERDOT); + + MPair expected1 = new MPair(tf.getSimpleType("type"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair expected2 = new MPair(tf.getSimpleType("type"), tf.getPlaceholderType("T"), PairOperator.SMALLERDOT); + + Optional opt1 = rules.reduceLow(reduce1); + Optional opt2 = rules.reduceLow(reduce2); + + Assert.assertTrue(opt1.isPresent()); + Assert.assertTrue(opt2.isPresent()); + Assert.assertEquals(opt1.get(), expected1); + Assert.assertEquals(opt2.get(), expected2); + + /* + * Negative Tests + */ + MPair noreduce1 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getExtendsType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair noreduce2 = new MPair(tf.getPlaceholderType("T"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair noreduce3 = new MPair(tf.getSuperType(tf.getPlaceholderType("T")), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair noreduce4 = new MPair(tf.getExtendsType(tf.getPlaceholderType("T")), tf.getSimpleType("type"), PairOperator.EQUALSDOT); + + Assert.assertFalse(rules.reduceLow(noreduce1).isPresent()); + Assert.assertFalse(rules.reduceLow(noreduce2).isPresent()); + Assert.assertFalse(rules.reduceLow(noreduce3).isPresent()); + Assert.assertFalse(rules.reduceLow(noreduce4).isPresent()); + } + + @Test + public void testReduceUpLow() { + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getFiniteClosure()); + TypeFactory tf = new TypeFactory(); + + /* + * Positive Tests + */ + MPair reduce1 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getSuperType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair reduce2 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getSuperType(tf.getPlaceholderType("T")), PairOperator.SMALLERDOT); + + MPair expected1 = new MPair(tf.getSimpleType("type"), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair expected2 = new MPair(tf.getSimpleType("type"), tf.getPlaceholderType("T"), PairOperator.SMALLERDOT); + + Optional opt1 = rules.reduceUpLow(reduce1); + Optional opt2 = rules.reduceUpLow(reduce2); + + Assert.assertTrue(opt1.isPresent()); + Assert.assertTrue(opt2.isPresent()); + Assert.assertEquals(opt1.get(), expected1); + Assert.assertEquals(opt2.get(), expected2); + + /* + * Negative Tests + */ + MPair noreduce1 = new MPair(tf.getExtendsType(tf.getSimpleType("type")), tf.getExtendsType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair noreduce2 = new MPair(tf.getSuperType(tf.getPlaceholderType("T")), tf.getExtendsType(tf.getSimpleType("type")), PairOperator.SMALLERDOT); + MPair noreduce3 = new MPair(tf.getSuperType(tf.getPlaceholderType("T")), tf.getSimpleType("type"), PairOperator.SMALLERDOT); + MPair noreduce4 = new MPair(tf.getExtendsType(tf.getPlaceholderType("T")), tf.getSimpleType("type"), PairOperator.EQUALSDOT); + + Assert.assertFalse(rules.reduceUpLow(noreduce1).isPresent()); + Assert.assertFalse(rules.reduceUpLow(noreduce2).isPresent()); + Assert.assertFalse(rules.reduceUpLow(noreduce3).isPresent()); + Assert.assertFalse(rules.reduceUpLow(noreduce4).isPresent()); + } + + @Test + public void testReduce1() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + /* + * Positive Tests + */ + + // C + SimpleType c1 = tf.getSimpleType("C", "T1", "T2", "T3", "T4"); + // D + SimpleType d1 = tf.getSimpleType("D", "T4", "T1", "T2", "T3"); + SimpleType buffer = tf.getSimpleType("Buffer"); + + //C + SimpleType c2 = tf.getSimpleType("C", tf.getSimpleType("Int"), tf.getExtendsType(tf.getSimpleType("Double")), tf.getPlaceholderType("M"), tf.getPlaceholderType("N")); + //D, Number, Double, N> + SimpleType d2 = tf.getSimpleType("D", tf.getSuperType(tf.getSimpleType("HashSet", "Int")), tf.getSimpleType("Number"), tf.getSimpleType("Double"), tf.getPlaceholderType("N")); + + // C<...> < buffer < D<...> + fcb.add(c1, buffer); + fcb.add(buffer, d1); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + MPair pair = new MPair(c2, d2, PairOperator.SMALLERDOT); + + System.out.println("------ Reduce1 ------"); + Optional> res = rules.reduce1(pair); + System.out.println(res); + + pair = new MPair(c2, c2, PairOperator.SMALLERDOT); + res = rules.reduce1(pair); + System.out.println(res); + + /* + * Negative Tests + */ + + // Case 1: D <. C and C <* D + pair = new MPair(d2, c2, PairOperator.SMALLERDOT); + Assert.assertFalse(rules.reduce1(pair).isPresent()); + + // Case 2: D =. C + pair = new MPair(c2, d2, PairOperator.EQUALSDOT); + Assert.assertFalse(rules.reduce1(pair).isPresent()); + + // Case 3: C <. D and !(C <* D) + fcb.clear(); + rules = new RuleSet(fcb.getFiniteClosure()); + pair = new MPair(c1, d1, PairOperator.SMALLERDOT); + Assert.assertFalse(rules.reduce1(pair).isPresent()); + } + + @Test + public void testReduce2() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + + /* + * Positive Tests + */ + System.out.println("----- Reduce2 ------"); + + // C + SimpleType c1 = tf.getSimpleType("C", tf.getPlaceholderType("T1"), tf.getSimpleType("SType1"), tf.getExtendsType(tf.getSimpleType("SType1"))); + // C + SimpleType c2 = tf.getSimpleType("C", tf.getPlaceholderType("T2"), tf.getSimpleType("SType2"), tf.getExtendsType(tf.getSimpleType("SType2"))); + + MPair pair1 = new MPair(c1, c2, PairOperator.EQUALSDOT); + MPair pair2 = new MPair(tf.getExtendsType(c1), tf.getExtendsType(c2), PairOperator.EQUALSDOT); + MPair pair3 = new MPair(tf.getSuperType(c1), tf.getSuperType(c2), PairOperator.EQUALSDOT); + + Optional> opt1 = rules.reduce2(pair1); + System.out.println(opt1); + + Optional> opt2 = rules.reduce2(pair2); + System.out.println(opt2); + + Optional> opt3 = rules.reduce2(pair3); + System.out.println(opt3); + + + /* + * Negative Tests + */ + + SimpleType d1 = tf.getSimpleType("D", tf.getPlaceholderType("T2"), tf.getSimpleType("SType2"), tf.getExtendsType(tf.getSimpleType("SType2"))); + pair1 = new MPair(d1, c1, PairOperator.EQUALSDOT); // Case 1: D =. C + pair2 = new MPair(tf.getExtendsType(c1), c2, PairOperator.EQUALSDOT); // Case 2: ? extends C =. C + pair3 = new MPair(tf.getExtendsType(c1), tf.getSuperType(c2), PairOperator.EQUALSDOT); // Case 3: ? extends C =. ? super C + MPair pair4 = new MPair(c1, c2, PairOperator.SMALLERDOT); // Case 4: C <. C + + Assert.assertFalse(rules.reduceEq(pair1).isPresent()); + Assert.assertFalse(rules.reduceEq(pair2).isPresent()); + Assert.assertFalse(rules.reduceEq(pair3).isPresent()); + Assert.assertFalse(rules.reduceEq(pair4).isPresent()); + } + + @Test + public void testReduceExt() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + /* + * Positive Tests + */ + + // X + SimpleType x1 = tf.getSimpleType("X", "T1", "T2", "T3", "T4"); + // Y + SimpleType y1 = tf.getSimpleType("Y", "T4", "T1", "T2", "T3"); + SimpleType buffer = tf.getSimpleType("Buffer"); + + //X + SimpleType x2 = tf.getSimpleType("X", tf.getSimpleType("Int"), tf.getExtendsType(tf.getSimpleType("Double")), tf.getPlaceholderType("M"), tf.getPlaceholderType("N")); + //? extends Y, Number, Double, N> + ExtendsType extY1 = tf.getExtendsType(tf.getSimpleType("Y", tf.getSuperType(tf.getSimpleType("HashSet", "Int")), tf.getSimpleType("Number"), tf.getSimpleType("Double"), tf.getPlaceholderType("N"))); + + // Y<...> < buffer < X<...> + fcb.add(x1, buffer); + fcb.add(buffer, y1); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + MPair pair1 = new MPair(x2, extY1, PairOperator.SMALLERDOTWC); + MPair pair2 = new MPair(tf.getExtendsType(x2), extY1, PairOperator.SMALLERDOTWC); + MPair pair3 = new MPair(extY1, extY1, PairOperator.SMALLERDOTWC); + + System.out.println("------ ReduceExt ------"); + Optional> opt1 = rules.reduceExt(pair1); + System.out.println(opt1); + + Optional> opt2 = rules.reduceExt(pair2); + System.out.println(opt2); + + Optional> opt3 = rules.reduceExt(pair3); + System.out.println(opt3); + + /* + * Negative Tests + */ + + // Case 1: X <.? Y + pair1 = new MPair(x2, extY1.getExtendedType(), PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceExt(pair1).isPresent()); + + // Case 2: X =. ? super Y + pair2 = new MPair(x2, extY1, PairOperator.EQUALSDOT); + Assert.assertFalse(rules.reduceExt(pair2).isPresent()); + + // Case 3: ? extends Y <.? ? extends X + pair3 = new MPair(extY1, tf.getExtendsType(x2), PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceExt(pair3).isPresent()); + + // Case 4: X <. ? extends Y and ? extends Y not in grArg(X) + fcb.clear(); + rules = new RuleSet(fcb.getFiniteClosure()); + pair1 = new MPair(x2, extY1, PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceExt(pair1).isPresent()); + } + + @Test + public void testReduceSup() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + /* + * Positive Tests + */ + + // X + SimpleType x1 = tf.getSimpleType("X", "T1", "T2", "T3", "T4"); + // Y + SimpleType y1 = tf.getSimpleType("Y", "T4", "T1", "T2", "T3"); + SimpleType buffer = tf.getSimpleType("Buffer"); + + //X + SimpleType x2 = tf.getSimpleType("X", tf.getSimpleType("Int"), tf.getExtendsType(tf.getSimpleType("Double")), tf.getPlaceholderType("M"), tf.getPlaceholderType("N")); + //? super Y, Number, Double, N> + SuperType supY1 = tf.getSuperType(tf.getSimpleType("Y", tf.getSuperType(tf.getSimpleType("HashSet", "Int")), tf.getSimpleType("Number"), tf.getSimpleType("Double"), tf.getPlaceholderType("N"))); + + // Y<...> < buffer < X<...> + fcb.add(y1, buffer); + fcb.add(buffer, x1); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + MPair pair1 = new MPair(x2, supY1, PairOperator.SMALLERDOTWC); + MPair pair2 = new MPair(tf.getSuperType(x2), supY1, PairOperator.SMALLERDOTWC); + MPair pair3 = new MPair(supY1, supY1, PairOperator.SMALLERDOTWC); + + System.out.println("------ ReduceSup ------"); + Optional> opt1 = rules.reduceSup(pair1); + System.out.println(opt1); + + Optional> opt2 = rules.reduceSup(pair2); + System.out.println(opt2); + + Optional> opt3 = rules.reduceSup(pair3); + System.out.println(opt3); + + /* + * Negative Tests + */ + + // Case 1: X <.? Y + pair1 = new MPair(x2, supY1.getSuperedType(), PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceSup(pair1).isPresent()); + + // Case 2: X =. ? super Y + pair2 = new MPair(x2, supY1, PairOperator.EQUALSDOT); + Assert.assertFalse(rules.reduceSup(pair2).isPresent()); + + // Case 3: ? super Y <.? ? super X + pair3 = new MPair(supY1, tf.getSuperType(x2), PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceSup(pair3).isPresent()); + + // Case 4: X <. ? super Y and ? super Y not in grArg(X) + fcb.clear(); + rules = new RuleSet(fcb.getFiniteClosure()); + pair1 = new MPair(x2, supY1, PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceSup(pair1).isPresent()); + } + + @Test + public void testReduceEq() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + + /* + * Positive Tests + */ + System.out.println("----- ReduceEq ------"); + + // C + SimpleType c1 = tf.getSimpleType("C", tf.getPlaceholderType("T1"), tf.getSimpleType("SType1"), tf.getExtendsType(tf.getSimpleType("SType1"))); + // C + SimpleType c2 = tf.getSimpleType("C", tf.getPlaceholderType("T2"), tf.getSimpleType("SType2"), tf.getExtendsType(tf.getSimpleType("SType2"))); + + MPair pair = new MPair(c1, c2, PairOperator.SMALLERDOTWC); + Optional> res = rules.reduceEq(pair); + System.out.println(res); + + /* + * Negative Tests + */ + + // Case 1: D <.? C + SimpleType d1 = tf.getSimpleType("D", tf.getPlaceholderType("T2"), tf.getSimpleType("SType2"), tf.getExtendsType(tf.getSimpleType("SType2"))); + pair = new MPair(d1, c1, PairOperator.SMALLERDOTWC); + Assert.assertFalse(rules.reduceEq(pair).isPresent()); + + // Case 2: C <. C + pair = new MPair(c1, c2, PairOperator.SMALLERDOT); + Assert.assertFalse(rules.reduceEq(pair).isPresent()); + } + + @Test + public void testErase1() { + TypeFactory tf = new TypeFactory(); + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getCollectionExample()); + + /* + * Positive Tests + */ + MPair erase1 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("Collection"), PairOperator.SMALLERDOT); + MPair erase2 = new MPair(tf.getSimpleType("HashSet", "T"), tf.getSimpleType("Collection"), PairOperator.SMALLERDOT); + MPair erase3 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOT); + + Assert.assertTrue(rules.erase1(erase1)); + Assert.assertTrue(rules.erase1(erase2)); + Assert.assertTrue(rules.erase1(erase3)); + + /* + * Negative Tests + */ + MPair noerase1 = new MPair(tf.getSimpleType("Collection"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOT); + MPair noerase2 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("Collection"), PairOperator.EQUALSDOT); + MPair noerase3 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("Collection"), PairOperator.SMALLERDOTWC); + + Assert.assertFalse(rules.erase1(noerase1)); + Assert.assertFalse(rules.erase1(noerase2)); + Assert.assertFalse(rules.erase1(noerase3)); + } + + @Test + public void testErase2() { + TypeFactory tf = new TypeFactory(); + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getCollectionExample()); + + /* + * Positive Tests + */ + MPair erase1 = new MPair(tf.getSimpleType("List", "T"), tf.getExtendsType(tf.getSimpleType("Collection")), PairOperator.SMALLERDOTWC); + MPair erase2 = new MPair(tf.getSimpleType("Collection"), tf.getSuperType(tf.getSimpleType("HashSet", "T")), PairOperator.SMALLERDOTWC); + MPair erase3 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOTWC); + MPair erase4 = new MPair(tf.getExtendsType(tf.getSimpleType("LinkedList", "T")), tf.getExtendsType(tf.getSimpleType("List", "T")), PairOperator.SMALLERDOTWC); + MPair erase5 = new MPair(tf.getSuperType(tf.getSimpleType("List", "T")), tf.getSuperType(tf.getSimpleType("Stack", "T")), PairOperator.SMALLERDOTWC); + + + Assert.assertTrue(rules.erase2(erase1)); + Assert.assertTrue(rules.erase2(erase2)); + Assert.assertTrue(rules.erase2(erase3)); + Assert.assertTrue(rules.erase2(erase4)); + Assert.assertTrue(rules.erase2(erase5)); + + /* + * Negative Tests + */ + MPair noerase1 = new MPair(tf.getSimpleType("Collection"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOTWC); + MPair noerase2 = new MPair(tf.getSuperType(tf.getSimpleType("List", "T")), tf.getSimpleType("ArrayList", "T"), PairOperator.SMALLERDOTWC); + MPair noerase3 = new MPair(tf.getExtendsType(tf.getSimpleType("List", "T")), tf.getSuperType(tf.getSimpleType("List", "T")), PairOperator.SMALLERDOTWC); + MPair noerase4 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOT); + + Assert.assertFalse(rules.erase2(noerase1)); + Assert.assertFalse(rules.erase2(noerase2)); + Assert.assertFalse(rules.erase2(noerase3)); + Assert.assertFalse(rules.erase2(noerase4)); + } + + @Test + public void testErase3() { + TypeFactory tf = new TypeFactory(); + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getFiniteClosure()); + + /* + * Positive Tests + */ + MPair erase1 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("List", "T"), PairOperator.EQUALSDOT); + MPair erase2 = new MPair(tf.getPlaceholderType("W"), tf.getPlaceholderType("W"), PairOperator.EQUALSDOT); + + Assert.assertTrue(rules.erase3(erase1)); + Assert.assertTrue(rules.erase3(erase2)); + + /* + * Negative Tests + */ + MPair noerase1 = new MPair(tf.getSimpleType("Collection"), tf.getSimpleType("List", "T"), PairOperator.EQUALSDOT); + MPair noerase2 = new MPair(tf.getSimpleType("List", "T"), tf.getSimpleType("List", "T"), PairOperator.SMALLERDOT); + + Assert.assertFalse(rules.erase3(noerase1)); + Assert.assertFalse(rules.erase3(noerase2)); + } + + @Test + public void testSwap() { + TypeFactory tf = new TypeFactory(); + IRuleSet rules = new RuleSet(new FiniteClosureBuilder().getFiniteClosure()); + + /* + * Positive Tests + */ + MPair swap1 = new MPair(tf.getExtendsType(tf.getSimpleType("MyClass")), tf.getPlaceholderType("P"), PairOperator.EQUALSDOT); + MPair swap2 = new MPair(tf.getSimpleType("MyClass"), tf.getPlaceholderType("X"), PairOperator.EQUALSDOT); + + MPair expected1 = new MPair(tf.getPlaceholderType("P"), tf.getExtendsType(tf.getSimpleType("MyClass")), PairOperator.EQUALSDOT); + MPair expected2 = new MPair(tf.getPlaceholderType("X"), tf.getSimpleType("MyClass"), PairOperator.EQUALSDOT); + + Optional opt1 = rules.swap(swap1); + Optional opt2 = rules.swap(swap2); + + // swap((? extends MyClass =. P)) = (P =. MyClass) + Assert.assertEquals(opt1.get(), expected1); + + // swap((MyClass =. X)) = (X =. MyClass) + Assert.assertEquals(opt2.get(), expected2); + + /* + * Negative Tests + */ + MPair noswap1 = new MPair(tf.getPlaceholderType("Z"), tf.getPlaceholderType("X"), PairOperator.EQUALSDOT); + MPair noswap2 = new MPair(tf.getSimpleType("MyClass"), tf.getExtendsType(tf.getPlaceholderType("X")), PairOperator.EQUALSDOT); + MPair noswap3 = new MPair( tf.getPlaceholderType("X"), tf.getSimpleType("MyClass"), PairOperator.EQUALSDOT); + MPair noswap4 = new MPair(tf.getSimpleType("MyClass"), tf.getPlaceholderType("X"), PairOperator.SMALLERDOT); + + opt1 = rules.swap(noswap1); + opt2 = rules.swap(noswap2); + Optional opt3 = rules.swap(noswap3); + Optional opt4 = rules.swap(noswap4); + + Assert.assertFalse(opt1.isPresent()); + Assert.assertFalse(opt2.isPresent()); + Assert.assertFalse(opt3.isPresent()); + Assert.assertFalse(opt4.isPresent()); + } + + @Test + public void testAdapt() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + SimpleType t1 = tf.getSimpleType("Type1", "T", "U"); + SimpleType t2 = tf.getSimpleType("Type2", "T"); + SimpleType t3 = tf.getSimpleType("Type3", tf.getPlaceholderType("T"), tf.getSimpleType("Integer")); + + fcb.add(t1, t2); + fcb.add(t2, t3); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + + /* + * Positive Tests + */ + + SimpleType c1 = tf.getSimpleType("Type1", "String", "Double"); + SimpleType c2 = tf.getSimpleType("Type2", "Object"); + SimpleType c3 = tf.getSimpleType("Type3", "Object", "Number"); + + MPair pair1 = new MPair(c1, c2, PairOperator.SMALLERDOT); + MPair pair2 = new MPair(c2, c3, PairOperator.SMALLERDOT); + MPair pair3 = new MPair(c1, c3, PairOperator.SMALLERDOT); + + System.out.println("------ Adapt ------"); + System.out.println(rules.adapt(pair1)); + System.out.println(rules.adapt(pair2)); + System.out.println(rules.adapt(pair3)); + + /* + * Negative Tests + */ + + MPair noAdapt1 = new MPair(c2, c1, PairOperator.SMALLERDOT); + MPair noAdapt2 = new MPair(c1, c1, PairOperator.SMALLERDOT); + MPair noAdapt3 = new MPair(c1, c2, PairOperator.SMALLERDOTWC); + + Assert.assertFalse(rules.adapt(noAdapt1).isPresent()); + Assert.assertFalse(rules.adapt(noAdapt2).isPresent()); + Assert.assertFalse(rules.adapt(noAdapt3).isPresent()); + } + + @Test + public void testAdaptExt() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + SimpleType t1 = tf.getSimpleType("Type1", "T", "U"); + SimpleType t2 = tf.getSimpleType("Type2", "T"); + SimpleType t3 = tf.getSimpleType("Type3", tf.getPlaceholderType("T"), tf.getSimpleType("Integer")); + SimpleType t32 = tf.getSimpleType("Type3", "T", "U"); + SimpleType t4 = tf.getSimpleType("Object"); + + fcb.add(t1, t2); + fcb.add(t2, t3); + fcb.add(t32, t4); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + + /* + * Positive Tests + */ + + SimpleType c1 = tf.getSimpleType("Type1", "String", "Double"); + SimpleType c2 = tf.getSimpleType("Type2", "Object"); + SimpleType c3 = tf.getSimpleType("Type3", "Object", "Number"); + ExtendsType extc1 = new ExtendsType(c1); + ExtendsType extc2 = new ExtendsType(c2); + ExtendsType extc3 = new ExtendsType(c3); + + MPair pair1 = new MPair(c1, extc2, PairOperator.SMALLERDOTWC); + MPair pair2 = new MPair(c2, extc3, PairOperator.SMALLERDOTWC); + MPair pair3 = new MPair(c1, extc3, PairOperator.SMALLERDOTWC); + MPair pair4 = new MPair(extc1, extc2, PairOperator.SMALLERDOTWC); + MPair pair5 = new MPair(extc2, extc3, PairOperator.SMALLERDOTWC); + MPair pair6 = new MPair(extc1, extc3, PairOperator.SMALLERDOTWC); + MPair pair7 = new MPair(extc1, extc1, PairOperator.SMALLERDOTWC); + + System.out.println("------ AdaptExt ------"); + System.out.println(rules.adaptExt(pair1)); + System.out.println(rules.adaptExt(pair2)); + System.out.println(rules.adaptExt(pair3)); + System.out.println(rules.adaptExt(pair4)); + System.out.println(rules.adaptExt(pair5)); + System.out.println(rules.adaptExt(pair6)); + System.out.println(rules.adaptExt(pair7)); + + /* + * Negative Tests + */ + + MPair noAdapt1 = new MPair(extc2, extc1, PairOperator.SMALLERDOTWC); + MPair noAdapt2 = new MPair(extc1, c2, PairOperator.SMALLERDOTWC); + MPair noAdapt3 = new MPair(tf.getSuperType(c1), extc2, PairOperator.SMALLERDOTWC); + MPair noAdapt4 = new MPair(extc3, extc1, PairOperator.SMALLERDOTWC); + MPair noAdapt5 = new MPair(c1, extc2, PairOperator.SMALLERDOT); + + Assert.assertFalse(rules.adaptExt(noAdapt1).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt2).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt3).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt4).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt5).isPresent()); + } + + @Test + public void testAdaptSup() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + + SimpleType t1 = tf.getSimpleType("Type1", "T", "U"); + SimpleType t2 = tf.getSimpleType("Type2", "T"); + SimpleType t3 = tf.getSimpleType("Type3", tf.getPlaceholderType("T"), tf.getSimpleType("Integer")); + SimpleType t32 = tf.getSimpleType("Type3", "T", "U"); + SimpleType t4 = tf.getSimpleType("Object"); + + fcb.add(t1, t2); + fcb.add(t2, t3); + fcb.add(t32, t4); + + IRuleSet rules = new RuleSet(fcb.getFiniteClosure()); + + /* + * Positive Tests + */ + + SimpleType c1 = tf.getSimpleType("Type1", "String", "Double"); + SimpleType c2 = tf.getSimpleType("Type2", "Object"); + SimpleType c3 = tf.getSimpleType("Type3", "Object", "Number"); + SuperType supc1 = new SuperType(c1); + SuperType supc2 = new SuperType(c2); + SuperType supc3 = new SuperType(c3); + + MPair pair1 = new MPair(c2, supc1, PairOperator.SMALLERDOTWC); + MPair pair2 = new MPair(c3, supc2, PairOperator.SMALLERDOTWC); + MPair pair3 = new MPair(c3, supc1, PairOperator.SMALLERDOTWC); + MPair pair4 = new MPair(supc2, supc1, PairOperator.SMALLERDOTWC); + MPair pair5 = new MPair(supc3, supc2, PairOperator.SMALLERDOTWC); + MPair pair6 = new MPair(supc3, supc1, PairOperator.SMALLERDOTWC); + MPair pair7 = new MPair(supc1, supc1, PairOperator.SMALLERDOTWC); + + System.out.println("------ AdaptSup ------"); + System.out.println(rules.adaptSup(pair1)); + System.out.println(rules.adaptSup(pair2)); + System.out.println(rules.adaptSup(pair3)); + System.out.println(rules.adaptSup(pair4)); + System.out.println(rules.adaptSup(pair5)); + System.out.println(rules.adaptSup(pair6)); + System.out.println(rules.adaptSup(pair7)); + + /* + * Negative Tests + */ + + MPair noAdapt1 = new MPair(supc2, supc1, PairOperator.SMALLERDOTWC); + MPair noAdapt2 = new MPair(supc1, c2, PairOperator.SMALLERDOTWC); + MPair noAdapt3 = new MPair(tf.getExtendsType(c1), supc2, PairOperator.SMALLERDOTWC); + MPair noAdapt4 = new MPair(supc3, supc1, PairOperator.SMALLERDOTWC); + MPair noAdapt5 = new MPair(c1, supc2, PairOperator.SMALLERDOT); + + Assert.assertFalse(rules.adaptExt(noAdapt1).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt2).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt3).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt4).isPresent()); + Assert.assertFalse(rules.adaptExt(noAdapt5).isPresent()); + } +} diff --git a/test/unify/TypeFactory.java b/test/unify/TypeFactory.java new file mode 100644 index 00000000..46b6f7bf --- /dev/null +++ b/test/unify/TypeFactory.java @@ -0,0 +1,37 @@ +package unify; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import de.dhbwstuttgart.typinference.unify.model.ExtendsType; +import de.dhbwstuttgart.typinference.unify.model.PlaceholderType; +import de.dhbwstuttgart.typinference.unify.model.SimpleType; +import de.dhbwstuttgart.typinference.unify.model.SuperType; +import de.dhbwstuttgart.typinference.unify.model.Type; + +public class TypeFactory { + + public ExtendsType getExtendsType(Type extendedType) { + return new ExtendsType(extendedType); + } + + public SuperType getSuperType(Type superedType) { + return new SuperType(superedType); + } + + public SimpleType getSimpleType(String name) { + return new SimpleType(name); + } + + public SimpleType getSimpleType(String name, Type... typeParams) { + return new SimpleType(name, typeParams); + } + + public SimpleType getSimpleType(String name, String... typeParams) { + return new SimpleType(name, Arrays.stream(typeParams).map(x -> getPlaceholderType(x)).collect(Collectors.toList()).toArray(new Type[0])); + } + + public PlaceholderType getPlaceholderType(String name) { + return new PlaceholderType(name); + } +} diff --git a/test/unify/UnifyOldTest.java b/test/unify/UnifyOldTest.java new file mode 100644 index 00000000..85f5ffd5 --- /dev/null +++ b/test/unify/UnifyOldTest.java @@ -0,0 +1,303 @@ +package unify; + +import junit.framework.Assert; + +import org.junit.Test; + +import de.dhbwstuttgart.syntaxtree.factory.UnifyPairMengenBuilder; +import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory; +import de.dhbwstuttgart.syntaxtree.factory.Unify_FC_TTO_Builder; +import de.dhbwstuttgart.syntaxtree.type.RefType; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.Menge; +import de.dhbwstuttgart.typeinference.Pair; +import de.dhbwstuttgart.typeinference.Pair.PairOperator; +import de.dhbwstuttgart.typeinference.unify.Unify; + +public class UnifyOldTest { + + @Test + public void unifyTestSimpleTypes() { + // Init Factories and Builders + UnifyTypeFactory typeFactory = new UnifyTypeFactory(); + Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); + UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); + UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); + + /* + * Test a <. Boolean + */ + + // Init Types + RefType boolT = typeFactory.GetSimpleType("java.lang.Boolean"); + TypePlaceholder aTph = typeFactory.GetTypePlaceholder("a"); + + // Expected Result + resultBuilder.clear(); + resultBuilder.addPair(aTph, boolT, PairOperator.Equal); + resultBuilder.addPair(aTph, typeFactory.GetExtendsType(boolT), + PairOperator.Equal); + Menge> expectedResult = resultBuilder.getNestedPairMenge(); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(aTph, boolT); + Menge> actualResult = Unify.unify( + assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); + + // System.out.println(expectedResult); + // System.out.println(actualResult); + + Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + /* + * Test b <. a, a <. Boolean + */ + + // Init Types + boolT = typeFactory.GetSimpleType("java.lang.Boolean"); + aTph = typeFactory.GetTypePlaceholder("a"); + TypePlaceholder bTph = typeFactory.GetTypePlaceholder("b"); + + // Expected Result + resultBuilder.clear(); + resultBuilder.addPair(aTph, boolT, PairOperator.Equal); + resultBuilder.addPair(aTph, typeFactory.GetExtendsType(boolT), + PairOperator.Equal); + resultBuilder.addPair(bTph, boolT, PairOperator.Equal); + resultBuilder.addPair(bTph, typeFactory.GetExtendsType(boolT), + PairOperator.Equal); + expectedResult = resultBuilder.getNestedPairMenge(); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(bTph, aTph); + assumptionBuilder.addPair(aTph, boolT); + actualResult = Unify.unify(assumptionBuilder.getPairMenge(), + fcBuilder.Get_FC_TTO()); + + // System.out.println(expectedResult); + // System.out.println(actualResult); + + // NOTE: Elemente im actualResult sind nicht unique + // Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + /* + * Test b <. a, a <. b + */ + + aTph = typeFactory.GetTypePlaceholder("a"); + bTph = typeFactory.GetTypePlaceholder("b"); + + // Expected Result + resultBuilder.clear(); + resultBuilder.addPair(bTph, aTph); + resultBuilder.addPair(aTph, bTph); + + Menge buffer = resultBuilder.getPairMenge(); + expectedResult = new Menge>(); + expectedResult.add(buffer); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(bTph, aTph); + assumptionBuilder.addPair(aTph, bTph); + actualResult = Unify.unify(assumptionBuilder.getPairMenge(), + fcBuilder.Get_FC_TTO()); + + // System.out.println(expectedResult); + // System.out.println(actualResult); + + Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + /* + * Test Integer <. a, a <. Boolean + */ + + RefType intT = typeFactory.GetSimpleType("java.lang.Integer"); + boolT = typeFactory.GetSimpleType("java.lang.Boolean"); + aTph = typeFactory.GetTypePlaceholder("a"); + bTph = typeFactory.GetTypePlaceholder("b"); + + // Expected Result + resultBuilder.clear(); + expectedResult = resultBuilder.getNestedPairMenge(); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(intT, aTph); + assumptionBuilder.addPair(aTph, boolT); + actualResult = Unify.unify(assumptionBuilder.getPairMenge(), + fcBuilder.Get_FC_TTO()); + + // System.out.println(expectedResult); + // System.out.println(actualResult); + + Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + } + + @Test + public void unifyTestGenerics() { + + // Init Factories and Builders + UnifyTypeFactory typeFactory = new UnifyTypeFactory(); + Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); + UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); + UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); + + /* + * Test a <. MyClass + */ + + TypePlaceholder aTph = typeFactory.GetTypePlaceholder("a"); + RefType myType = typeFactory.GetSimpleType("MyClass", + typeFactory.GetTypePlaceholder("T"), + typeFactory.GetTypePlaceholder("F")); + + // Expected Result + resultBuilder.clear(); + resultBuilder.addPair(aTph, myType, PairOperator.Equal); + resultBuilder.addPair(aTph, typeFactory.GetExtendsType(myType)); + Menge> expectedResult = resultBuilder.getNestedPairMenge(); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(aTph, myType); + Menge> actualResult = Unify.unify( + assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); + + // System.out.println(expectedResult); + // System.out.println(actualResult); + + Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + /* + * Test List> <. List + */ + + TypePlaceholder tTph = typeFactory.GetTypePlaceholder("T"); + RefType list = typeFactory.GetSimpleType("List", tTph); + RefType listlist = typeFactory.GetSimpleType("List", list); + + // Expected Result + resultBuilder.clear(); + resultBuilder.addPair(typeFactory.GetExtendsType(list), tTph, + PairOperator.Equal); + expectedResult = resultBuilder.getNestedPairMenge(); + + // Actual Result + assumptionBuilder.clear(); + assumptionBuilder.addPair(listlist, list); + actualResult = Unify.unify(assumptionBuilder.getPairMenge(), + fcBuilder.Get_FC_TTO()); + + System.out.println(expectedResult); + System.out.println(actualResult); + + Assert.assertTrue(mengeEquals(expectedResult, actualResult)); + + /* + * Test List <. List> + */ + } + + @Test + public void unifyTestInheritance() { + + // Init Factories and Builders + UnifyTypeFactory typeFactory = new UnifyTypeFactory(); + Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); + UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); + UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); + + // Init Types + RefType tBool = typeFactory.GetSimpleType("java.lang.Boolean"); + RefType tString = typeFactory.GetSimpleType("java.lang.String"); + RefType tInt = typeFactory.GetSimpleType("java.lang.Integer"); + TypePlaceholder tphA = typeFactory.GetTypePlaceholder("a"); + + // Build inheritance hierachy + // Bool <. String <. Int + fcBuilder.AddInheritance(tBool, tString); + fcBuilder.AddInheritance(tString, tInt); + + // Build Assumptions + assumptionBuilder.addPair(tphA, tString); + + // Build expected result + resultBuilder.addPair(tphA, tBool, PairOperator.Equal); + resultBuilder.addPair(tphA, typeFactory.GetExtendsType(tBool), + PairOperator.Equal); + resultBuilder.addPair(tphA, tString, PairOperator.Equal); + resultBuilder.addPair(tphA, typeFactory.GetExtendsType(tString), + PairOperator.Equal); + + // Assert + Menge> actualResult = Unify.unify( + assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); + + // System.out.println(actualResult); + // System.out.println("-------------------"); + // System.out.println(resultBuilder.getNestedPairMenge()); + + Assert.assertTrue(mengeEquals(resultBuilder.getNestedPairMenge(), + actualResult)); + } + + @Test + public void unifyTestWildcards() { + + } + + private static boolean mengeEquals(Menge> m1, + Menge> m2) { + if (m1.size() != m2.size()) + return false; + + return containsAll(m1, m2) && containsAll(m2, m1); + } + + private static boolean containsAll(Menge> m1, + Menge> m2) { + for (Menge elem : m2) + if (!contains(m1, elem)) + return false; + return true; + } + + private static boolean contains(Menge> m1, Menge m2) { + for (Menge elem : m1) + if (mengePairEquals(elem, m2)) + return true; + return false; + } + + private static boolean mengePairEquals(Menge m1, Menge m2) { + if (m1.size() != m2.size()) + return false; + + return containsAllPair(m1, m2) && containsAllPair(m2, m1); + } + + private static boolean containsAllPair(Menge m1, Menge m2) { + for (Pair elem : m1) + if (contains(m2, elem)) + return true; + return false; + } + + private static boolean contains(Menge m, Pair p) { + for (Pair elem : m) + if (pairEquals(elem, p)) + return true; + return false; + + } + + private static boolean pairEquals(Pair p1, Pair p2) { + return (p1.TA1.equals(p2.TA1) && p1.TA2.equals(p2.TA2)) + || (p1.TA1.equals(p2.TA2) && p1.TA2.equals(p2.TA1)); + } + +} diff --git a/test/unify/UnifyTest.java b/test/unify/UnifyTest.java index 59671c90..65f94d96 100644 --- a/test/unify/UnifyTest.java +++ b/test/unify/UnifyTest.java @@ -1,304 +1,51 @@ package unify; -import junit.framework.Assert; +import java.util.HashSet; +import java.util.Set; import org.junit.Test; -import de.dhbwstuttgart.syntaxtree.factory.UnifyPairMengenBuilder; -import de.dhbwstuttgart.syntaxtree.factory.UnifyTypeFactory; -import de.dhbwstuttgart.syntaxtree.factory.Unify_FC_TTO_Builder; -import de.dhbwstuttgart.syntaxtree.type.RefType; -import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; -import de.dhbwstuttgart.typeinference.Menge; -import de.dhbwstuttgart.typeinference.Pair; -import de.dhbwstuttgart.typeinference.Pair.PairOperator; -import de.dhbwstuttgart.typeinference.unify.Unify; - -public class UnifyTest { +import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; +import de.dhbwstuttgart.typeinference.unifynew.Unify; +import de.dhbwstuttgart.typinference.unify.model.MPair; +import de.dhbwstuttgart.typinference.unify.model.MPair.PairOperator; +public class UnifyTest extends Unify { + + @Test + public void unifyTest() { + TypeFactory tf = new TypeFactory(); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + Set eq = new HashSet(); + + fcb.add(tf.getSimpleType("Number"), tf.getSimpleType("Object")); + fcb.add(tf.getSimpleType("Integer"), tf.getSimpleType("Number")); + fcb.add(tf.getSimpleType("Double"), tf.getSimpleType("Number")); + + IFiniteClosure fc = fcb.getCollectionExample(); + + // Vector <. Vector + // A <. Number + // Double <. B + // B <. Object + eq.add(new MPair(tf.getSimpleType("Vector", tf.getSimpleType("Integer")), tf.getSimpleType("Vector", "A"), PairOperator.SMALLERDOT)); + eq.add(new MPair(tf.getPlaceholderType("A"), tf.getSimpleType("Number"), PairOperator.SMALLERDOT)); + eq.add(new MPair(tf.getPlaceholderType("A"), tf.getPlaceholderType("C"), PairOperator.SMALLERDOT)); + eq.add(new MPair(tf.getSimpleType("Double"), tf.getPlaceholderType("B"), PairOperator.SMALLERDOT)); + eq.add(new MPair(tf.getPlaceholderType("B"), tf.getSimpleType("Object"), PairOperator.EQUALSDOT)); + + this.unify(eq, fc); + + } + @Test - public void unifyTestSimpleTypes() { - - // Init Factories and Builders - UnifyTypeFactory typeFactory = new UnifyTypeFactory(); - Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); - UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); - UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); - - /* - * Test a <. Boolean - */ - - // Init Types - RefType boolT = typeFactory.GetSimpleType("java.lang.Boolean"); - TypePlaceholder aTph = typeFactory.GetTypePlaceholder("a"); - - // Expected Result - resultBuilder.clear(); - resultBuilder.addPair(aTph, boolT, PairOperator.Equal); - resultBuilder.addPair(aTph, typeFactory.GetExtendsType(boolT), - PairOperator.Equal); - Menge> expectedResult = resultBuilder.getNestedPairMenge(); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(aTph, boolT); - Menge> actualResult = Unify.unify( - assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); - - // System.out.println(expectedResult); - // System.out.println(actualResult); - - Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - - /* - * Test b <. a, a <. Boolean - */ - - // Init Types - boolT = typeFactory.GetSimpleType("java.lang.Boolean"); - aTph = typeFactory.GetTypePlaceholder("a"); - TypePlaceholder bTph = typeFactory.GetTypePlaceholder("b"); - - // Expected Result - resultBuilder.clear(); - resultBuilder.addPair(aTph, boolT, PairOperator.Equal); - resultBuilder.addPair(aTph, typeFactory.GetExtendsType(boolT), - PairOperator.Equal); - resultBuilder.addPair(bTph, boolT, PairOperator.Equal); - resultBuilder.addPair(bTph, typeFactory.GetExtendsType(boolT), - PairOperator.Equal); - expectedResult = resultBuilder.getNestedPairMenge(); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(bTph, aTph); - assumptionBuilder.addPair(aTph, boolT); - actualResult = Unify.unify(assumptionBuilder.getPairMenge(), - fcBuilder.Get_FC_TTO()); - - // System.out.println(expectedResult); - // System.out.println(actualResult); - - // NOTE: Elemente im actualResult sind nicht unique - // Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - - /* - * Test b <. a, a <. b - */ - - aTph = typeFactory.GetTypePlaceholder("a"); - bTph = typeFactory.GetTypePlaceholder("b"); - - // Expected Result - resultBuilder.clear(); - resultBuilder.addPair(bTph, aTph); - resultBuilder.addPair(aTph, bTph); - - Menge buffer = resultBuilder.getPairMenge(); - expectedResult = new Menge>(); - expectedResult.add(buffer); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(bTph, aTph); - assumptionBuilder.addPair(aTph, bTph); - actualResult = Unify.unify(assumptionBuilder.getPairMenge(), - fcBuilder.Get_FC_TTO()); - - // System.out.println(expectedResult); - // System.out.println(actualResult); - - Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - - /* - * Test Integer <. a, a <. Boolean - */ - - RefType intT = typeFactory.GetSimpleType("java.lang.Integer"); - boolT = typeFactory.GetSimpleType("java.lang.Boolean"); - aTph = typeFactory.GetTypePlaceholder("a"); - bTph = typeFactory.GetTypePlaceholder("b"); - - // Expected Result - resultBuilder.clear(); - expectedResult = resultBuilder.getNestedPairMenge(); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(intT, aTph); - assumptionBuilder.addPair(aTph, boolT); - actualResult = Unify.unify(assumptionBuilder.getPairMenge(), - fcBuilder.Get_FC_TTO()); - - // System.out.println(expectedResult); - // System.out.println(actualResult); - - Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - + public void applyTypeUnificationRulesTest() { + } - + @Test - public void unifyTestGenerics() { - - // Init Factories and Builders - UnifyTypeFactory typeFactory = new UnifyTypeFactory(); - Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); - UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); - UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); - - /* - * Test a <. MyClass - */ - - TypePlaceholder aTph = typeFactory.GetTypePlaceholder("a"); - RefType myType = typeFactory.GetSimpleType("MyClass", - typeFactory.GetTypePlaceholder("T"), - typeFactory.GetTypePlaceholder("F")); - - // Expected Result - resultBuilder.clear(); - resultBuilder.addPair(aTph, myType, PairOperator.Equal); - resultBuilder.addPair(aTph, typeFactory.GetExtendsType(myType)); - Menge> expectedResult = resultBuilder.getNestedPairMenge(); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(aTph, myType); - Menge> actualResult = Unify.unify( - assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); - - // System.out.println(expectedResult); - // System.out.println(actualResult); - - Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - - /* - * Test List> <. List - */ - - TypePlaceholder tTph = typeFactory.GetTypePlaceholder("T"); - RefType list = typeFactory.GetSimpleType("List", tTph); - RefType listlist = typeFactory.GetSimpleType("List", list); - - // Expected Result - resultBuilder.clear(); - resultBuilder.addPair(typeFactory.GetExtendsType(list), tTph, - PairOperator.Equal); - expectedResult = resultBuilder.getNestedPairMenge(); - - // Actual Result - assumptionBuilder.clear(); - assumptionBuilder.addPair(listlist, list); - actualResult = Unify.unify(assumptionBuilder.getPairMenge(), - fcBuilder.Get_FC_TTO()); - - System.out.println(expectedResult); - System.out.println(actualResult); - - Assert.assertTrue(mengeEquals(expectedResult, actualResult)); - - /* - * Test List <. List> - */ + public void calculatePairSetsTest() { + } - - @Test - public void unifyTestInheritance() { - - // Init Factories and Builders - UnifyTypeFactory typeFactory = new UnifyTypeFactory(); - Unify_FC_TTO_Builder fcBuilder = new Unify_FC_TTO_Builder(); - UnifyPairMengenBuilder assumptionBuilder = new UnifyPairMengenBuilder(); - UnifyPairMengenBuilder resultBuilder = new UnifyPairMengenBuilder(); - - // Init Types - RefType tBool = typeFactory.GetSimpleType("java.lang.Boolean"); - RefType tString = typeFactory.GetSimpleType("java.lang.String"); - RefType tInt = typeFactory.GetSimpleType("java.lang.Integer"); - TypePlaceholder tphA = typeFactory.GetTypePlaceholder("a"); - - // Build inheritance hierachy - // Bool <. String <. Int - fcBuilder.AddInheritance(tBool, tString); - fcBuilder.AddInheritance(tString, tInt); - - // Build Assumptions - assumptionBuilder.addPair(tphA, tString); - - // Build expected result - resultBuilder.addPair(tphA, tBool, PairOperator.Equal); - resultBuilder.addPair(tphA, typeFactory.GetExtendsType(tBool), - PairOperator.Equal); - resultBuilder.addPair(tphA, tString, PairOperator.Equal); - resultBuilder.addPair(tphA, typeFactory.GetExtendsType(tString), - PairOperator.Equal); - - // Assert - Menge> actualResult = Unify.unify( - assumptionBuilder.getPairMenge(), fcBuilder.Get_FC_TTO()); - - // System.out.println(actualResult); - // System.out.println("-------------------"); - // System.out.println(resultBuilder.getNestedPairMenge()); - - Assert.assertTrue(mengeEquals(resultBuilder.getNestedPairMenge(), - actualResult)); - } - - @Test - public void unifyTestWildcards() { - - } - - private static boolean mengeEquals(Menge> m1, - Menge> m2) { - if (m1.size() != m2.size()) - return false; - - return containsAll(m1, m2) && containsAll(m2, m1); - } - - private static boolean containsAll(Menge> m1, - Menge> m2) { - for (Menge elem : m2) - if (!contains(m1, elem)) - return false; - return true; - } - - private static boolean contains(Menge> m1, Menge m2) { - for (Menge elem : m1) - if (mengePairEquals(elem, m2)) - return true; - return false; - } - - private static boolean mengePairEquals(Menge m1, Menge m2) { - if (m1.size() != m2.size()) - return false; - - return containsAllPair(m1, m2) && containsAllPair(m2, m1); - } - - private static boolean containsAllPair(Menge m1, Menge m2) { - for (Pair elem : m1) - if (contains(m2, elem)) - return true; - return false; - } - - private static boolean contains(Menge m, Pair p) { - for (Pair elem : m) - if (pairEquals(elem, p)) - return true; - return false; - - } - - private static boolean pairEquals(Pair p1, Pair p2) { - return (p1.TA1.equals(p2.TA1) && p1.TA2.equals(p2.TA2)) - || (p1.TA1.equals(p2.TA2) && p1.TA2.equals(p2.TA1)); - } - + }