diff --git a/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java b/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java index a1b56472..427122bf 100644 --- a/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java +++ b/src/de/dhbwstuttgart/typeinference/unify/model/FiniteClosure.java @@ -19,10 +19,6 @@ public class FiniteClosure implements IFiniteClosure { private HashMap> inheritanceGraph; private HashMap>> strInheritanceGraph; - public FiniteClosure() { - - } - public FiniteClosure(Set pairs) { inheritanceGraph = new HashMap>(); @@ -76,32 +72,42 @@ public class FiniteClosure implements IFiniteClosure { // where foreach type var a in T2: // sigma1(T1) <=* sigma2(T2) //If a type of the same name is in the fc AND the type "type" is parameterized (some substitution sigma1 was applied) - if(strInheritanceGraph.containsKey(type.getName())) { - IUnify unify = new MartelliMontanariUnify(); - HashSet> candidateNodes = strInheritanceGraph.get(type.getName()); - for(Node candidateNode : candidateNodes) { - Type theta2 = candidateNode.getContent(); - Optional sigma2 = unify.unify(theta2, type); - if(!sigma2.isPresent()) - continue; - Set theta1s = inheritanceGraph.containsKey(type) ? inheritanceGraph.get(type).getContentOfDescendants() : smaller(theta2); - for(Type theta1 : theta1s) { - // Because only the most general type is calculated, sigma1 = sigma2 - Type sigma1Theta1 = sigma2.get().apply(theta1); + + IUnify unify = new MartelliMontanariUnify(); + HashSet candidates = new HashSet<>(); + if (strInheritanceGraph.containsKey(type.getName())) + strInheritanceGraph.get(type.getName()).forEach(x -> candidates.add(x.getContent())); + else + candidates.add(type); + + for (Type theta2 : candidates) { + Optional sigma2 = unify.unify(theta2, type); + if (!sigma2.isPresent()) + continue; + Set theta1s = new HashSet<>(); + if(inheritanceGraph.containsKey(type)) + theta1s = inheritanceGraph.get(type).getContentOfDescendants(); + else if(theta2.equals(type)) + theta1s.add(type); + else + theta1s = smaller(theta2); + for (Type theta1 : theta1s) { + // Because only the most general type is calculated, sigma1 = + // sigma2 + Type sigma1Theta1 = sigma2.get().apply(theta1); - ArrayList> paramCandidates = new ArrayList<>(); - for(Type param : sigma1Theta1.getTypeParams()) - paramCandidates.add(smArg(param)); - - Set permResult = new HashSet<>(); - permuteParams(paramCandidates, 0, permResult, new Type[paramCandidates.size()]); - - for(TypeParams newParams : permResult) - result.add(sigma1Theta1.setTypeParams(newParams)); - } + ArrayList> paramCandidates = new ArrayList<>(); + for (Type param : sigma1Theta1.getTypeParams()) + paramCandidates.add(smArg(param)); + + Set permResult = new HashSet<>(); + permuteParams(paramCandidates, 0, permResult, new Type[paramCandidates.size()]); + + for (TypeParams newParams : permResult) + result.add(sigma1Theta1.setTypeParams(newParams)); } } - + return result; } diff --git a/test/unify/FiniteClosureTest.java b/test/unify/FiniteClosureTest.java index 073b4a94..c35bfe66 100644 --- a/test/unify/FiniteClosureTest.java +++ b/test/unify/FiniteClosureTest.java @@ -1,49 +1,218 @@ package unify; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + import org.junit.Assert; import org.junit.Test; import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure; -import de.dhbwstuttgart.typeinference.unify.model.MPair; -import de.dhbwstuttgart.typeinference.unify.model.MPair.PairOperator; -import de.dhbwstuttgart.typeinference.unify.model.FiniteClosure; import de.dhbwstuttgart.typeinference.unify.model.Type; import de.dhbwstuttgart.typeinference.unifynew.TypeFactory; -public class FiniteClosureTest extends FiniteClosure { +public class FiniteClosureTest { @Test - public void testMatch() { + public void testSmaller() { TypeFactory tf = new TypeFactory(); - Type a = tf.getPlaceholderType("a"); - Type b = tf.getPlaceholderType("b"); - Type c = tf.getPlaceholderType("c"); + Type integer = tf.getSimpleType("Integer"); + Type number = tf.getSimpleType("Number"); - Type A = tf.getSimpleType("A"); - Type B = tf.getSimpleType("B"); - Type C1 = tf.getSimpleType("C", a, b, c); - Type C2 = tf.getSimpleType("C", a, A, b); - Type C3 = tf.getSimpleType("C", A, B, A); - Type D1 = tf.getSimpleType("D", C1, a, b, c); - Type D2 = tf.getSimpleType("D", C3, A, B, A); + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + fcb.add(integer, number); + fcb.add(tf.getSimpleType("MyMap", "T"), tf.getSimpleType("HashMap", tf.getSimpleType("Integer"))); + fcb.add(tf.getSimpleType("HashMap", "T"), tf.getSimpleType("Collection")); + IFiniteClosure fc = fcb.getCollectionExample(); + + /* + * Test Case 1: + * + * smaller(Set) = { HashSet, Set, LinkedHashSet } + */ - System.out.println(match(C2, C1)); - System.out.println(match(C3, C1)); - System.out.println(match(D2, D1)); - Assert.assertFalse(match(C3, C2).isPresent()); - Assert.assertFalse(match(C1, C2).isPresent()); + Type setInt = tf.getSimpleType("Set", integer); + Type hashSetInt = tf.getSimpleType("HashSet", integer); + Type treeSetInt = tf.getSimpleType("TreeSet", integer); + Type linkedHashSetInt = tf.getSimpleType("LinkedHashSet", integer); + + Set expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setInt, hashSetInt, linkedHashSetInt, treeSetInt, + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setInt)); + + /* + * Test Case 2: + * + * smaller(Set) = + * { HashSet, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet } + */ + + Type extInt = tf.getExtendsType(integer); + Type hashSetExtInt = tf.getSimpleType("HashSet", extInt); + Type treeSetExtInt = tf.getSimpleType("TreeSet", extInt); + Type linkedHashSetExtInt = tf.getSimpleType("LinkedHashSet", extInt); + Type setExtInt = tf.getSimpleType("Set", extInt); + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setInt, hashSetInt, linkedHashSetInt, treeSetInt, + hashSetExtInt, treeSetExtInt, linkedHashSetExtInt, setExtInt, + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setExtInt)); + + /* + * Test Case 3: + * + * smaller(Set) = + * { HashSet, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet + * HashSet } + */ + + Type hashSetNum = tf.getSimpleType("HashSet", number); + Type treeSetNum = tf.getSimpleType("TreeSet", number); + Type linkedHashSetNum = tf.getSimpleType("LinkedHashSet", number); + Type setNum = tf.getSimpleType("Set", number); + + Type extNum = tf.getExtendsType(number); + Type hashSetExtNum = tf.getSimpleType("HashSet", extNum); + Type treeSetExtNum = tf.getSimpleType("TreeSet", extNum); + Type linkedHashSetExtNum = tf.getSimpleType("LinkedHashSet", extNum); + Type setExtNum = tf.getSimpleType("Set", extNum); + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setInt, hashSetInt, linkedHashSetInt, treeSetInt, + setNum, hashSetNum, linkedHashSetNum, treeSetNum, + setExtInt, hashSetExtInt, linkedHashSetExtInt, treeSetExtInt, + setExtNum, hashSetExtNum, linkedHashSetExtNum, treeSetExtNum + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setExtNum)); + + /* + * Test Case 4: + * TODO ist das ergebnis korrekt oder müssen die ? ext Ts raus weil der allgemeienste Typ T ausreicht? + * smaller(Set) = + * { HashSet, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet } + */ + + Type t = tf.getPlaceholderType("T"); + Type setT = tf.getSimpleType("Set", t); + Type hashSetT = tf.getSimpleType("HashSet", t); + Type treeSetT = tf.getSimpleType("TreeSet", t); + Type linkedHashSetT = tf.getSimpleType("LinkedHashSet", t); + Type hashSetExtT = tf.getSimpleType("HashSet", t); + Type treeSetExtT = tf.getSimpleType("TreeSet", t); + Type linkedHashSetExtT = tf.getSimpleType("LinkedHashSet", t); + Type setExtT = tf.getSimpleType("Set", t); + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setT, hashSetT, treeSetT, linkedHashSetT, + setExtT, hashSetExtT, treeSetExtT, linkedHashSetExtT + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setT)); + + /* + * Test Case 5 + * + * smaller(Set = + * { Set, HashSet, TreeSet, LinkedHashSet, + * Set, HashSet, TreeSet, LinkedHashSet, + * Set, HashSet, TreeSet, LinkedHashSet } + */ + + Type superNum = tf.getSuperType(number); + Type superInt = tf.getSuperType(integer); + + Type setSupInt = tf.getSimpleType("Set", superInt); + Type hashSetSupInt = tf.getSimpleType("HashSet", superInt); + Type linkedHashSetSupInt = tf.getSimpleType("LinkedHashSet", superInt); + Type treeSetSupInt = tf.getSimpleType("TreeSet", superInt); + Type setSupNum = tf.getSimpleType("Set", superNum); + Type hashSetSupNum = tf.getSimpleType("HashSet", superNum); + Type linkedHashSetSupNum = tf.getSimpleType("LinkedHashSet", superNum); + Type treeSetSupNum = tf.getSimpleType("TreeSet", superNum); + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setSupInt, hashSetSupInt, linkedHashSetSupInt, treeSetSupInt, + setSupNum, hashSetSupNum, linkedHashSetSupNum, treeSetSupNum, + setInt, hashSetInt, linkedHashSetInt, treeSetInt, + setNum, hashSetNum, linkedHashSetNum, treeSetNum + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setSupInt)); + + /* + * Test Case 6: + * + * smaller(Set, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet } + * + */ + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setT, hashSetT, treeSetT, linkedHashSetT, + setExtT, hashSetExtT, treeSetExtT, linkedHashSetExtT + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setExtT)); + + /* + * Test Case 7: + * smaller(Set) = + * { HashSet, Set, TreeSet, LinkedHashSet, + * HashSet, Set, TreeSet, LinkedHashSet } + */ + + Type notInFc = tf.getSimpleType("notInFC"); + Type setNotInFc = tf.getSimpleType("Set", notInFc); + Type hashSetNotInFc = tf.getSimpleType("HashSet", notInFc); + Type treeSetNotInFc = tf.getSimpleType("TreeSet", notInFc); + Type linkedHashSetNotInFc = tf.getSimpleType("LinkedHashSet", notInFc); + Type hashSetExtNotInFc = tf.getSimpleType("HashSet", notInFc); + Type treeSetExtNotInFc = tf.getSimpleType("TreeSet", notInFc); + Type linkedHashSetExtNotInFc = tf.getSimpleType("LinkedHashSet", notInFc); + Type setExtNotInFc = tf.getSimpleType("Set", notInFc); + + expectedResult = new HashSet<>(Arrays.stream(new Type[] { + setNotInFc, hashSetNotInFc, treeSetNotInFc, linkedHashSetNotInFc, + setExtNotInFc, hashSetExtNotInFc, treeSetExtNotInFc, linkedHashSetExtNotInFc + }).collect(Collectors.toSet())); + + Assert.assertEquals(expectedResult, fc.smaller(setNotInFc)); + + /* + * Test Case 8: + * + */ } @Test public void testGreater() { - IFiniteClosure fc = new FiniteClosureBuilder().getCollectionExample(); TypeFactory tf = new TypeFactory(); - + FiniteClosureBuilder fcb = new FiniteClosureBuilder(); + fcb.add(tf.getSimpleType("Integer"), tf.getSimpleType("Number")); + fcb.add(tf.getSimpleType("MyMap", "T"), tf.getSimpleType("HashMap", tf.getSimpleType("Integer"))); + fcb.add(tf.getSimpleType("HashMap", "T"), tf.getSimpleType("Collection")); + IFiniteClosure fc = fcb.getCollectionExample(); + 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"))); + System.out.println(fc.greater(tf.getSimpleType("Deque", tf.getSimpleType("Integer")))); + System.out.println(fc.greater(tf.getSimpleType("Deque", tf.getSimpleType("Number")))); + System.out.println(fc.greater(tf.getSimpleType("Deque", tf.getExtendsType(tf.getSimpleType("Integer"))))); + System.out.println(fc.greater(tf.getSimpleType("Deque", tf.getSuperType(tf.getSimpleType("Integer"))))); } @Test @@ -57,20 +226,6 @@ public class FiniteClosureTest extends FiniteClosure { System.out.println("GrArg(? super List) = " + fc.grArg(tf.getSuperType(tf.getSimpleType("List", "T")))); } - @Test - public void testSmaller() { - FiniteClosureBuilder fcb = new FiniteClosureBuilder(); - TypeFactory tf = new TypeFactory(); - - fcb.add(tf.getSimpleType("Integer"), tf.getSimpleType("Number")); - IFiniteClosure fc = fcb.getCollectionExample(); - - System.out.println("\n\n----- Smaller Test -----"); - System.out.println("Smaller(List) = " + fc.smaller(tf.getSimpleType("List", tf.getExtendsType(tf.getSimpleType("Number"))))); - 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() {