aa
TestHM.java
Go to the documentation of this file.
1 package com.cliffc.aa.HM;
2 
3 import com.cliffc.aa.HM.HM.Root;
4 import com.cliffc.aa.type.*;
5 import org.junit.Before;
6 import org.junit.Test;
7 
8 import static org.junit.Assert.assertEquals;
9 
10 public class TestHM {
11 
12  @Before public void reset() { HM.reset(); }
13 
14  private void run( String prog, String rez_hm, Type rez_gcp ) {
15  Root syn = HM.hm(prog);
16  if( HM.DO_HM )
17  assertEquals(rez_hm,syn._hmt.p());
18  if( HM.DO_GCP )
19  assertEquals(rez_gcp,syn.flow_type());
20  }
21  // Simple no-arg signature returning the type
22  private static TypeFunSig tfs(Type ret) {
24  }
25 
26  private static TypeStruct make_tups(Type t0, Type t1 ) { return TypeStruct.make(TypeStruct.tups(t0,t1 )); }
27  private static TypeStruct make_tups(Type t0, Type t1, Type t2) { return TypeStruct.make(TypeStruct.tups(t0,t1,t2)); }
31  private static final TypeMemPtr tuple55 = TypeMemPtr.make(7,make_tups(TypeInt.con(5),TypeInt.con(5)));
32  private static final TypeFunSig ret_tuple2 = tfs(tuple2);
34 
35  @Test(expected = RuntimeException.class)
36  public void test00() { run( "fred",null,null); }
37 
38  @Test public void test01() { run( "3" ,
39  "3", TypeInt.con(3)); }
40 
41  @Test public void test02() { run( "(pair1 3)" ,
42  "{ A -> ( 3, A) }", tfs(TypeMemPtr.make(7,make_tups(TypeInt.con(3),Type.SCALAR)))); }
43 
44  @Test public void test03() { run( "{ z -> (pair (z 0) (z \"abc\")) }" ,
45  "{ { *[0,4]\"abc\"? -> A } -> ( A, A) }", tfs(tuple2)); }
46 
47  @Test public void test04() { run( "fact = { n -> (if (eq0 n) 1 (* n (fact (dec n))))}; fact",
48  "{ int64 -> int64 }", tfs(TypeInt.INT64) ); }
49 
50  // Because {y->y} is passed in, all 'y' types must agree.
51  // This unifies 3 and "abc" which results in 'all'
52  @Test public void test05() {
53  Root syn = HM.hm("({ x -> (pair (x 3) (x 5)) } {y->y})");
54  if( HM.DO_HM )
55  assertEquals("( nint8, nint8)",syn._hmt.p());
56  if( HM.DO_GCP )
57  if( HM.DO_HM )
58  assertEquals(tuple82,syn.flow_type());
59  else
60  assertEquals(tuple82,syn.flow_type());
61  }
62 
63  @Test public void test06() {
64  Root syn = HM.hm("id={x->x}; (pair (id 3) (id \"abc\"))");
65  if( HM.DO_HM ) // HM is sharper here than in test05, because id is generalized per each use site
66  assertEquals("( 3, *[4]\"abc\")",syn._hmt.p());
67  if( HM.DO_GCP )
68  if( HM.DO_HM )
69  assertEquals(TypeMemPtr.make(7,make_tups(TypeInt.con(3),TypeMemPtr.make(4,TypeStr.ABC))),syn.flow_type());
70  else
71  assertEquals(tuplen2,syn.flow_type());
72  }
73 
74  // recursive unification; normal H-M fails here.
75  @Test public void test07() { run( "{ f -> (f f) }",
76  // We can argue the pretty-print should print:
77  // " A:{ A -> B }"
78  "{ A:{ A -> B } -> B }", tfs(Type.SCALAR) ); }
79 
80  @Test public void test08() { run( "g = {f -> 5}; (g g)",
81  "5", TypeInt.con(5)); }
82 
83  // example that demonstrates generic and non-generic variables:
84  @Test public void test09() { run( "{ g -> f = { x -> g }; (pair (f 3) (f \"abc\"))}",
85  "{ A -> ( A, A) }", ret_tuple2); }
86 
87  @Test public void test10() { run( "{ f g -> (f g)}",
88  "{ { A -> B } A -> B }", tfs(Type.SCALAR) ); }
89 
90  // Function composition
91  @Test public void test11() { run( "{ f g -> { arg -> (g (f arg))} }",
92  "{ { A -> B } { B -> C } -> { A -> C } }", tfs(tfs(Type.SCALAR))); }
93 
94  // Stacked functions ignoring all function arguments
95  @Test public void test12() { run( "map = { fun -> { x -> 2 } }; ((map 3) 5)",
96  "2", TypeInt.con(2)); }
97 
98  // map takes a function and an element (collection?) and applies it (applies to collection?)
99  @Test public void test13() { run( "map = { fun -> { x -> (fun x)}}; { p -> 5 }",
100  "{ A -> 5 }", tfs(TypeInt.con(5))); }
101 
102  // Looking at when tvars are duplicated ("fresh" copies made).
103  // This is the "map" problem with a scalar instead of a collection.
104  // Takes a '{a->b}' and a 'a' for a couple of different prims.
105  @Test public void test14() {
106  Root syn = HM.hm("map = { fun -> { x -> (fun x)}};"+
107  "(pair ((map str) 5) ((map factor) 2.3))");
108  if( HM.DO_HM )
109  assertEquals("( *[4]str, flt64)",syn._hmt.p());
110  if( HM.DO_GCP )
111  if( HM.DO_HM )
113  else
114  assertEquals(tuple2,syn.flow_type());
115  }
116 
117  // map takes a function and an element (collection?) and applies it (applies to collection?)
118  @Test public void test15() { run("map = { fun x -> (fun x)}; (map {a->3} 5)",
119  "3", TypeInt.con(3)); }
120 
121  // map takes a function and an element (collection?) and applies it (applies to collection?)
122  @Test public void test16() { run("map = { fun x -> (fun x)}; (map { a-> (pair a a)} 5)",
123  "( 5, 5)", tuple55); }
124 
125  @Test public void test17() { run("fcn = { p -> { a -> (pair a a) }};"+
126  "map = { fun x -> (fun x)};"+
127  "{ q -> (map (fcn q) 5)}",
128  "{ A -> ( 5, 5) }", tfs(tuple55)); }
129 
130  // Checking behavior when using "if" to merge two functions with sufficiently
131  // different signatures, then attempting to pass them to a map & calling internally.
132  // fcn takes a predicate 'p' and returns one of two fcns.
133  // let fcn = { p -> (if p {a -> pair[a,a ]}
134  // {b -> pair[b,pair[3,b]]}) } in
135  // map takes a function and an element (collection?) and applies it (applies to collection?)
136  // let map = { fun x -> (fun x) }
137  // in { q -> ((map (fcn q)) 5) }
138  // Should return { q -> q ? [5,5] : [5,[3,5]] }
139  // Ultimately, unifies "a" with "pair[3,a]" which throws recursive unification.
140  @Test public void test18() {
141  Root syn = HM.hm("fcn = {p -> (if p {a -> (pair a a)} {b -> (pair b (pair 3 b))})};"+
142  "map = { fun x -> (fun x)};"+
143  "{ q -> (map (fcn q) 5)}");
144  if( HM.DO_HM )
145  assertEquals("{ A? -> ( B:Cannot unify A:( 3, A) and 5, B) }",syn._hmt.p());
146  if( HM.DO_GCP )
147  if( HM.DO_HM )
149  else
150  assertEquals(tfs(TypeMemPtr.make(7,make_tups(TypeInt.con(5),Type.NSCALR))),syn.flow_type());
151  }
152 
153  @Test public void test19() { run("cons ={x y-> {cadr -> (cadr x y)}};"+
154  "cdr ={mycons -> (mycons { p q -> q})};"+
155  "(cdr (cons 2 3))",
156  "3", TypeInt.con(3)); }
157 
158  // Take 2nd element of pair, and applies a function.
159  // let map = fn parg fun => (fun (cdr parg))
160  // Some pairs:
161  // let intz = (pair2 false 3)
162  // let strz = (pair2 false "abc")
163  // in pair(map(str,intz),map(isempty,strz))
164  // Expects: ("2",false)
165  @Test public void test20() {
166  Root syn = HM.hm("cons ={x y-> {cadr -> (cadr x y)}};"+
167  "cdr ={mycons -> (mycons { p q -> q})};"+
168  "map ={fun parg -> (fun (cdr parg))};"+
169  "(pair (map str (cons 0 5)) (map isempty (cons 0 \"abc\")))");
170  if( HM.DO_HM )
171  assertEquals("( *[4]str, int1)",syn._hmt.p());
172  if( HM.DO_GCP )
173  if( HM.DO_HM )
175  else
176  assertEquals(tuple2,syn.flow_type());
177  }
178 
179  // Obscure factorial-like
180  @Test public void test21() { run("f0 = { f x -> (if (eq0 x) 1 (f (f0 f (dec x)) 2))}; (f0 * 99)",
181  "int64", TypeInt.INT64); }
182 
183  // Obscure factorial-like
184  // let f0 = fn f x => (if (eq0 x) 1 (* (f0 f (dec x)) 2) ) in f0 f0 99
185  // let f0 = fn f x => (if (eq0 x) 1 (f (f0 f (dec x)) 2) ) in f0 * 99
186  @Test public void test22() { run("f0 = { f x -> (if (eq0 x) 1 (* (f0 f (dec x)) 2))}; (f0 f0 99)",
187  "int64", TypeInt.INT64); }
188 
189  // Mutual recursion
190  @Test public void test23() { run("is_even = "+
191  " is_odd = { n -> (if (eq0 n) 0 (is_even (dec n)))}; "+
192  " { n -> (if (eq0 n) 1 (is_odd (dec n)))};"+
193  "(is_even 3)" ,
194  "int1", TypeInt.BOOL); }
195 
196  // Toss a function into a pair & pull it back out
197  @Test public void test24() { run("{ g -> fgz = "+
198  " cons = {x y -> {cadr -> (cadr x y)}};"+
199  " cdr = {mycons -> (mycons { p q -> q})};"+
200  " (cdr (cons 2 { z -> (g z) }));"+
201  " (pair (fgz 3) (fgz 5))"+
202  "}"
203  ,
204  "{ { nint8 -> A } -> ( A, A) }", tfs(tuple2)); }
205 
206  // Basic structure test
207  @Test public void test25() { run("@{x=2, y=3}",
208  "@{ x = 2, y = 3}",
210  ); }
211 
212  // Basic field test
213  @Test public void test26() { run("@{x =2, y =3}.x",
214  "2", TypeInt.con(2)); }
215 
216  // Basic field test
217  @Test public void test27() { run("5.x",
218  "Missing field x in 5", Type.SCALAR); }
219 
220  // Basic field test.
221  @Test public void test28() { run("@{ y =3}.x",
222  "Missing field x in @{ y = 3}",
223  Type.SCALAR); }
224 
225  @Test public void test29() { run("{ g -> @{x=g, y=g}}",
226  "{ A -> @{ x = A, y = A} }", tfs(tuple9)); }
227 
228  // Load common field 'x', ignoring mismatched fields y and z
229  @Test public void test30() { run("{ pred -> (if pred @{x=2,y=3} @{x=3,z= \"abc\"}) .x }",
230  "{ A? -> nint8 }", tfs(TypeInt.NINT8)); }
231 
232  // Load some fields from an unknown struct: area of a rectangle.
233  // Since no nil-check, correctly types as needing a not-nil input.
234  @Test public void test31() { run("{ sq -> (* sq.x sq.y) }", // { sq -> sq.x * sq.y }
235  "{ @{ x = int64, y = int64} -> int64 }", tfs(TypeInt.INT64)); }
236 
237  private static TypeMemPtr build_cycle( int alias, boolean nil, Type fld ) {
238  // Build a cycle of length 2.
239  BitsAlias aliases = BitsAlias.make0(alias);
240  if( nil ) aliases = aliases.meet_nil();
241  TypeMemPtr cycle_ptr0 = TypeMemPtr.make(aliases,TypeObj.XOBJ);
242  TypeStruct cycle_str1 = TypeStruct.make(TypeFld.NO_DISP,TypeFld.make("n1",cycle_ptr0,1),TypeFld.make("v1",fld,2));
243  TypeMemPtr cycle_ptr1 = TypeMemPtr.make(aliases,cycle_str1);
244  TypeStruct cycle_str2 = TypeStruct.make(TypeFld.NO_DISP,TypeFld.make("n1",cycle_ptr1,1),TypeFld.make("v1",fld,2));
245  TypeStruct cycle_strn = cycle_str2.approx(1,alias);
246  TypeMemPtr cycle_ptrn = (TypeMemPtr)cycle_strn.at(1);
247  return cycle_ptrn;
248  }
249  private static TypeMemPtr build_cycle2( boolean nil, Type fld ) {
250  // Unrolled, known to only produce results where either other nested
251  // struct is from a different allocation site.
252  BitsAlias aliases0 = BitsAlias.make0(10);
253  BitsAlias aliases9 = BitsAlias.make0( 9);
254  if( nil ) aliases0 = aliases0.meet_nil();
255  if( nil ) aliases9 = aliases9.meet_nil();
256  TypeMemPtr cycle_ptr0 = TypeMemPtr.make(aliases0,TypeObj.XOBJ);
257  TypeStruct cycle_str1 = TypeStruct.make(TypeFld.NO_DISP,TypeFld.make("n1",cycle_ptr0,1),TypeFld.make("v1",fld,2));
258  TypeMemPtr cycle_ptr1 = TypeMemPtr.make(aliases9,cycle_str1);
259  TypeStruct cycle_str2 = TypeStruct.make(TypeFld.NO_DISP,TypeFld.make("n1",cycle_ptr1,1),TypeFld.make("v1",fld,2));
260  TypeMemPtr cycle_ptr2 = TypeMemPtr.make(aliases0,cycle_str2);
261  TypeStruct cycle_str3 = TypeStruct.make(TypeFld.NO_DISP,TypeFld.make("n1",cycle_ptr2,1),TypeFld.make("v1",fld,2));
262  TypeStruct cycle_strn = cycle_str3.approx(1,9);
263  TypeMemPtr cycle_ptrn = (TypeMemPtr)cycle_strn.at(1);
264  return cycle_ptrn;
265  }
266 
267 
268  // Recursive linked-list discovery, with no end clause. Since this code has
269  // no exit (its an infinite loop, endlessly reading from an infinite input
270  // and writing an infinite output), gcp gets a cyclic approximation.
271  @Test public void test32() {
272  Root syn = HM.hm("map = { fcn lst -> @{ n1 = (map fcn lst.n0), v1 = (fcn lst.v0) } }; map");
273  if( HM.DO_HM )
274  assertEquals("{ { A -> B } C:@{ n0 = C, v0 = A} -> D:@{ n1 = D, v1 = B} }",syn._hmt.p());
275  if( HM.DO_GCP )
276  // Build a cycle of length 2, without nil.
277  assertEquals(tfs(build_cycle(9,false,Type.SCALAR)),syn.flow_type());
278  }
279 
280  // Recursive linked-list discovery, with nil. Note that the output memory
281  // has the output memory alias, but not the input memory alias (which must be
282  // made before calling 'map').
283  @Test public void test33() {
284  Root syn = HM.hm("map = { fcn lst -> (if lst @{ n1=(map fcn lst.n0), v1=(fcn lst.v0) } 0) }; map");
285  if( HM.DO_HM )
286  assertEquals("{ { A -> B } C:@{ n0 = C, v0 = A}? -> D:@{ n1 = D, v1 = B}? }",syn._hmt.p());
287  if( HM.DO_GCP )
288  // Build a cycle of length 2, with nil.
289  assertEquals(tfs(build_cycle(9,true,Type.SCALAR)),syn.flow_type());
290  }
291 
292  // Recursive linked-list discovery, with no end clause
293  @Test public void test34() {
294  Root syn = HM.hm("map = { fcn lst -> (if lst @{ n1 = (map fcn lst.n0), v1 = (fcn lst.v0) } 0) }; (map dec @{n0 = 0, v0 = 5})");
295  if( HM.DO_HM )
296  assertEquals("A:@{ n1 = A, v1 = int64}?",syn._hmt.p());
297  if( HM.DO_GCP )
298  assertEquals(build_cycle(9,true,TypeInt.con(4)),syn.flow_type());
299  }
300 
301  // try the worse-case expo blow-up test case from SO
302  @Test public void test35() {
303  TypeFunPtr tfp = TypeFunPtr.make(16,3,Type.ANY);
304  TypeMemPtr tmp0 = TypeMemPtr.make(8,make_tups(tfp ,tfp ,tfp ));
305  TypeMemPtr tmp1 = TypeMemPtr.make(8,make_tups(tmp0,tmp0,tmp0));
306  TypeMemPtr tmp2 = TypeMemPtr.make(8,make_tups(tmp1,tmp1,tmp1));
307 
308  run("p0 = { x y z -> (triple x y z) };"+
309  "p1 = (triple p0 p0 p0);"+
310  "p2 = (triple p1 p1 p1);"+
311  "p3 = (triple p2 p2 p2);"+
312  "p3",
313  "( ( ( { A B C -> ( A, B, C) }, { D E F -> ( D, E, F) }, { G H I -> ( G, H, I) }), ( { J K L -> ( J, K, L) }, { M N O -> ( M, N, O) }, { P Q R -> ( P, Q, R) }), ( { S T U -> ( S, T, U) }, { V21 V22 V23 -> ( V21, V22, V23) }, { V24 V25 V26 -> ( V24, V25, V26) })), ( ( { V27 V28 V29 -> ( V27, V28, V29) }, { V30 V31 V32 -> ( V30, V31, V32) }, { V33 V34 V35 -> ( V33, V34, V35) }), ( { V36 V37 V38 -> ( V36, V37, V38) }, { V39 V40 V41 -> ( V39, V40, V41) }, { V42 V43 V44 -> ( V42, V43, V44) }), ( { V45 V46 V47 -> ( V45, V46, V47) }, { V48 V49 V50 -> ( V48, V49, V50) }, { V51 V52 V53 -> ( V51, V52, V53) })), ( ( { V54 V55 V56 -> ( V54, V55, V56) }, { V57 V58 V59 -> ( V57, V58, V59) }, { V60 V61 V62 -> ( V60, V61, V62) }), ( { V63 V64 V65 -> ( V63, V64, V65) }, { V66 V67 V68 -> ( V66, V67, V68) }, { V69 V70 V71 -> ( V69, V70, V71) }), ( { V72 V73 V74 -> ( V72, V73, V74) }, { V75 V76 V77 -> ( V75, V76, V77) }, { V78 V79 V80 -> ( V78, V79, V80) })))",
314  tmp2 );
315  }
316 
317  // Need to see if a map call, inlined a few times, 'rolls up'. Sometimes
318  // rolls up, sometimes not; depends on worklist visitation order.
319  @Test public void test36() {
320  Root syn = HM.hm("map = { lst -> (if lst @{ n1= arg= lst.n0; (if arg @{ n1=(map arg.n0), v1=(str arg.v0)} 0), v1=(str lst.v0) } 0) }; map");
321  if( HM.DO_HM )
322  assertEquals("{ A:@{ n0 = @{ n0 = A, v0 = int64}?, v0 = int64}? -> B:@{ n1 = @{ n1 = B, v1 = *[4]str}?, v1 = *[4]str}? }",syn._hmt.p());
323  if( HM.DO_GCP )
324  assertEquals(tfs(build_cycle2(true,TypeMemPtr.STRPTR)),syn.flow_type());
325  }
326 
327  @Test public void test37() { run("x = { y -> (x (y y))}; x",
328  "{ A:{ A -> A } -> B }", tfs(Type.XSCALAR)); }
329 
330  // Example from SimpleSub requiring 'x' to be both a struct with field
331  // 'v', and also a function type - specifically disallowed in 'aa'.
332  @Test public void test38() { run("{ x -> y = ( x x.v ); 0}",
333  "{ Cannot unify @{ v = A} and { A -> B } -> A? }", tfs(Type.XNIL)); }
334 
335  // Really bad flow-type: function can be called from the REPL with any
336  // argument type - and the worse case will be an error.
337  @Test public void test39() {
338  Root syn = HM.hm("x = { z -> z}; (x { y -> y.u})");
339  if( HM.DO_HM )
340  assertEquals("{ @{ u = A} -> A }",syn._hmt.p());
341  if( HM.DO_GCP )
342  assertEquals(tfs(Type.SCALAR), syn.flow_type());
343  }
344 
345  // Example from SimpleSub requiring 'x' to be both:
346  // - a recursive self-call function from "w = (x x)": $V66:{ $V66 -> V67 } AND
347  // - a function which takes a struct with field 'u'
348  // The first arg to x is two different kinds of functions, so fails unification.
349  @Test public void test40() {
350  Root syn = HM.hm("x = w = (x x); { z -> z}; (x { y -> y.u})");
351  if( HM.DO_HM )
352  assertEquals("Cannot unify A:{ A -> A } and @{ u = A}",syn._hmt.p());
353  if( HM.DO_GCP ) {
354  if( HM.DO_HM ) {
355  assertEquals(tfs(Type.SCALAR), syn.flow_type());
356  } else {
357  assertEquals(Type.SCALAR, syn.flow_type());
358  }
359  }
360  }
361 
362  // Example from TestParse.test15:
363  // map={lst fcn -> lst ? fcn lst.1};
364  // in_int=(0,2);"+ // List of ints
365  // in_str=(0,"abc");" + // List of strings
366  // out_str = map(in_int,str:{int->str});"+ // Map over ints with int->str conversion, returning a list of strings
367  // out_bool= map(in_str,{str -> str==\"abc\"});"+ // Map over strs with str->bool conversion, returning a list of bools
368  // (out_str,out_bool)",
369  @Test public void test41() {
370  Root syn = HM.hm("map={lst fcn -> (fcn lst.y) }; "+
371  "in_int=@{ x=0 y=2}; " +
372  "in_str=@{ x=0 y=\"abc\"}; " +
373  "out_str = (map in_int str); " +
374  "out_bool= (map in_str { xstr -> (eq xstr \"def\")}); "+
375  "(pair out_str out_bool)");
376  if( HM.DO_HM )
377  assertEquals("( *[4]str, int1)",syn._hmt.p());
378  if( HM.DO_GCP )
379  if( HM.DO_HM )
381  else
382  assertEquals(tuple2,syn.flow_type());
383  }
384 
385  // CCP Can help HM
386  @Test public void test42() {
387  Root syn = HM.hm("pred = 0; s1 = @{ x=\"abc\" }; s2 = @{ y=3.4 }; (if pred s1 s2).y");
388  if( HM.DO_HM ) {
389  if( HM.DO_GCP )
390  assertEquals("3.4000000953674316",syn._hmt.p());
391  else
392  assertEquals("Missing field y in @{ x = *[4]\"abc\"}",syn._hmt.p());
393  }
394  if( HM.DO_GCP )
395  assertEquals(TypeFlt.con(3.4f), syn.flow_type());
396  }
397 
398  // The z-merge is ignored; the last s2 is a fresh (unmerged) copy.
399  @Test public void test43() {
400  Root syn = HM.hm("pred = 0; s1 = @{ x=\"abc\" }; s2 = @{ y=3.4 }; z = (if pred s1 s2); s2.y");
401  if( HM.DO_HM )
402  assertEquals("3.4000000953674316",syn._hmt.p());
403  if( HM.DO_GCP )
404  assertEquals(TypeFlt.con(3.4f), syn.flow_type());
405  }
406 
407 
408  @Test public void test44() {
409  Root syn = HM.hm("fun = (if (isempty \"abc\") {x->x} {x->1.2}); (fun @{})");
410  if( HM.DO_HM ) {
411  if( HM.DO_GCP )
412  assertEquals("1.2000000476837158",syn._hmt.p());
413  else
414  assertEquals("Cannot unify 1.2000000476837158 and ()",syn._hmt.p());
415  }
416  if( HM.DO_GCP )
417  assertEquals(TypeFlt.con(1.2f), syn.flow_type());
418  }
419 
420 
421  // Requires a combo of HM and GCP to get the good answer
422  @Test public void test45() {
423  Root syn = HM.hm(
424 "id = {x -> x};" +
425 "loop = { name cnt ->" +
426 " (if cnt " +
427 " (loop" +
428 " fltfun = (if name id {x->3});" +
429 " (fltfun \"abc\")" +
430 " (dec cnt)" +
431 " )" +
432 " name" +
433 " )"+
434 "};" +
435 "(loop \"def\" (id 2))");
436  if( HM.DO_HM )
437  assertEquals(HM.DO_GCP
438  ? "*[0,4]str?" // Both HM and GCP
439  : "Cannot unify *[4]\"abc\" and 3", // HM alone cannot do this one
440  syn._hmt.p());
441  if( HM.DO_GCP )
442  assertEquals(HM.DO_HM
443  ? TypeMemPtr.STRPTR // Both HM and GCP
444  : Type.NSCALR, // GCP alone gets a very weak answer
445  syn.flow_type());
446  }
447 
448 
449  // Basic nil test
450  @Test public void test46() { run("0.x",
451  "May be nil when loading field x", Type.XSCALAR); }
452 
453  // Basic nil test
454  @Test public void test47() { run("{ pred -> (if pred @{x=3} 0).x}",
455  "{ A? -> May be nil when loading field x }", tfs(TypeInt.con(3))); }
456 
457  // Basic uplifting after check
458  @Test public void test48() { run("{ pred -> tmp=(if pred @{x=3} 0); (if tmp tmp.x 4) }",
459  "{ A? -> nint8 }", tfs(TypeInt.NINT8)); }
460 
461 
462  // map is parametric in nil-ness
463  @Test public void test49() {
464  Root syn = HM.hm("{ pred -> \n"+
465  " map = { fun x -> (fun x) };\n" +
466  " (pair (map {str0 -> str0.x } @{x = 3} )\n" +
467  " (map {str1 -> (if str1 str1.x 4)} (if pred @{x = 5} 0))\n" +
468  " )\n"+
469  "}");
470  if( HM.DO_HM )
471  assertEquals("{ A? -> ( 3, nint8) }",syn._hmt.p());
472  if( HM.DO_GCP )
473  if( HM.DO_HM ) assertEquals(tfs(TypeMemPtr.make(7,make_tups(TypeInt.con(3), TypeInt.NINT8 ))),syn.flow_type());
474  else assertEquals(tfs(TypeMemPtr.make(7,make_tups(TypeInt.NINT8 , TypeInt.NINT8 ))),syn.flow_type());
475  }
476 
477  // map is parametric in nil-ness. Verify still nil-checking.
478  @Test public void test50() {
479  Root syn = HM.hm("{ pred -> \n"+
480  " map = { fun x -> (fun x) };\n" +
481  " (pair (map {str0 -> str0.x } @{x = 3} )\n" +
482  " (map {str1 -> str1.x } (if pred @{x = 5} 0))\n" +
483  " )\n"+
484  "}");
485  if( HM.DO_HM )
486  assertEquals("{ A? -> May be nil when loading field x }",syn._hmt.p());
487  if( HM.DO_GCP )
488  if( HM.DO_HM ) assertEquals(tfs(TypeMemPtr.make(7,make_tups(TypeInt.NINT8, TypeInt.NINT8 ))),syn.flow_type());
489  else assertEquals(tfs(TypeMemPtr.make(7,make_tups(TypeInt.NINT8, TypeInt.NINT8 ))),syn.flow_type());
490  }
491 
492  @Test public void test51() {
493  Root syn = HM.hm("total_size = { a as ->" + // Total_size takes an 'a' and a list of 'as'
494  " (if as "+ // If list is not empty then
495  " (+ a.size "+ // Add the size of 'a' to
496  " (total_size as.val as.next))" + // the size of the rest of the list
497  " a.size"+ // Else the list is empty, just take the a.size
498  " )"+ // End of (if as...)
499  "};" + // End of total_size={...}
500  "total_size" // What is this type?
501  );
502  if( HM.DO_HM )
503  assertEquals("{ A:@{ size = int64} B:@{ next = B, val = A}? -> int64 }",syn._hmt.p());
504  if( HM.DO_GCP )
505  if( HM.DO_HM ) assertEquals(tfs(TypeInt.INT64),syn.flow_type());
506  else assertEquals(tfs(Type.SCALAR ),syn.flow_type());
507  }
508 
509  // Create a boolean-like structure, and unify.
510  @Test public void test52() {
511  Root syn = HM.hm("void = @{};"+ // Same as '()'; all empty structs are alike
512  "true = @{"+ // 'true' is a struct with and,or,thenElse
513  " and= {b -> b}"+
514  " or = {b -> true}"+
515  " thenElse = {then else->(then void) }"+
516  "};"+
517  "false = @{"+ // 'false' is a struct with and,or,thenElse
518  " and= {b -> false}"+
519  " or = {b -> b}"+
520  " thenElse = {then else->(else void) }"+
521  "};"+
522  "forceSubtyping ={b ->(if b true false)};"+ // A unified version
523  // Trying really hard here to unify 'true' and 'false'
524  "bool=@{true=(forceSubtyping 1), false=(forceSubtyping 0), force=forceSubtyping};"+
525  // Apply the unified 'false' to two different return contexts
526  "a=(bool.false.thenElse { x-> 3 } { y-> 4 });"+
527  "b=(bool.false.thenElse { z->@{}} { z->@{}});"+
528  // Look at the results
529  "@{a=a,b=b, bool=bool}"+
530  "");
531  if( HM.DO_HM ) {
532  /* An indented version of this answer
533  @{
534  a = nint8,
535  b = (),
536  bool = @{
537  false = A:@{ and = { A -> A }, or = { A -> A }, thenElse = { { () -> B } { () -> B } -> B } },
538  force = { C -> D:@{ and = { D -> D }, or = { D -> D }, thenElse = { { () -> E } { () -> E } -> E } } },
539  true = F:@{ and = { F -> F }, or = { F -> F }, thenElse = { { () -> G } { () -> G } -> G } }
540  }
541  }
542  */
543  assertEquals("@{ a = nint8, b = (), bool = @{ false = A:@{ and = { A -> A }, or = { A -> A }, thenElse = { { () -> B } { () -> B } -> B }}, force = { C? -> D:@{ and = { D -> D }, or = { D -> D }, thenElse = { { () -> E } { () -> E } -> E }} }, true = F:@{ and = { F -> F }, or = { F -> F }, thenElse = { { () -> G } { () -> G } -> G }}}}",syn._hmt.p());
544  }
545  if( HM.DO_GCP ) {
546  Type tf = TypeMemPtr.make(BitsAlias.FULL.make(10,11),
550  TypeFld.make("thenElse",TypeFunPtr.make(BitsFun.make0(17,20),2,TypeMemPtr.NO_DISP),3)));
552  TypeFld.make("true", tf,1),
553  TypeFld.make("false",tf,2),
554  TypeFld.make("force",TypeFunPtr.make(24,1,TypeMemPtr.NO_DISP),3)));
557  TypeFld.make("b",HM.DO_HM ? Type.SCALAR : Type.NSCALR,2),
558  TypeFld.make("bool",xbool,3));
559  assertEquals(TypeMemPtr.make(15,rez),syn.flow_type());
560  }
561  }
562 
563 
564  // Simple nil/default test; takes a nilable but does not return one.
565  @Test public void test53() { run( "{ x y -> (if x x y) }",
566  "{ A? A -> A }", tfs(Type.SCALAR)); }
567 
568  // Double nested. Currently fails to unify x and y.
569  @Test public void test54() { run( "{ x y -> (if x (if x x y) y) }",
570  "{ A? A -> A }", tfs(Type.SCALAR)); }
571 
572  // Regression test; was NPE. Was testMyBoolsNullPException from marco.servetto@gmail.com.
573  @Test public void test55() {
574  Root syn = HM.hm("void = @{}; "+
575  "true = @{ "+
576  " and = {b -> b} "+
577  " or = {b -> true} "+
578  " not = {unused ->true} "+
579  " thenElse = {then else->(then void) }"+
580  "}; "+
581  "false = @{ "+
582  " and = {b -> false} "+
583  " or = {b -> b} "+
584  " not = {unused ->true} "+
585  " thenElse = {then else->(else void) }"+
586  "}; "+
587  "boolSub ={b ->(if b true false)}; "+
588  "@{true=(boolSub 1) false=(boolSub 0)} "+
589  "");
590  if( HM.DO_HM )
591  assertEquals("@{ false = A:@{ and = { A -> A }, "+
592  "not = { B -> A }, "+
593  "or = { A -> A }, "+
594  "thenElse = { { () -> C } { () -> C } -> C }"+
595  "}, "+
596  "true = D:@{ and = { D -> D }, "+
597  "not = { E -> D }, "+
598  "or = { D -> D }, "+
599  "thenElse = { { () -> F } { () -> F } -> F }"+
600  "}"+
601  "}",syn._hmt.p());
602  if( HM.DO_GCP ) {
603  // true/false=*[10,11]@{$; and=[15,19]{any }; or=[16,20]{any }; not=[17,21]{any }; thenElse=[18,22]{any }}
604  Type tf = TypeMemPtr.make(BitsAlias.FULL.make(10,11),
609  TypeFld.make("thenElse",TypeFunPtr.make(BitsFun.make0(18,22),2,TypeMemPtr.NO_DISP),4)));
610  // *[12]@{^=any; true=$TF; false=$TF}
612  TypeFld.make("true" ,tf,1),
613  TypeFld.make("false",tf,2) );
614  assertEquals(TypeMemPtr.make(12,rez),syn.flow_type());
615  }
616 
617  }
618 
619  // Regression test. Was unexpectedly large type result. Cut down version of
620  // test from marco.servetto@gmail.com. Looks like it needs some kind of
621  // top-level unification with the true->false->true path, and instead the
622  // type has an unrolled instance of the 'true' type embedded in the 'false'
623  // type. Bug is actually a core HM algorithm change to handle cycles.
624  @Test public void test56() {
625  Root syn = HM.hm("left = "+
626  " rite = @{n1 = left v1 = 7 }; "+
627  " @{ n1 = rite v1 = 7 };"+
628  "left"+
629  "");
630  if( HM.DO_HM )
631  assertEquals("A:@{ n1 = @{ n1 = A, v1 = 7}, v1 = 7}",syn._hmt.p());
632  if( HM.DO_GCP )
633  assertEquals(build_cycle2(false,TypeInt.con(7)),syn.flow_type());
634  }
635 
636  @Test public void test57() {
637  Root syn = HM.hm(
638 "all = "+
639 "true = @{ "+
640 " not = {unused -> all.false}, "+
641 " thenElse = {then else->(then 7) } "+
642 "}; "+
643 "false = @{ "+
644 " not = {unused -> all.true}, "+
645 " thenElse = {then else->(else 7) } "+
646 "}; "+
647 "boolSub ={b ->(if b true false)}; "+
648 "@{true=true, false=false, boolSub=boolSub};"+
649 "all"+
650 "");
651  if( HM.DO_HM )
652  assertEquals("@{ boolSub = { A? -> @{ not = { B -> C:@{ not = { D -> C }, thenElse = { { 7 -> E } { 7 -> E } -> E }} }, thenElse = { { 7 -> F } { 7 -> F } -> F }} }, false = C, true = C}",syn._hmt.p());
653  if( HM.DO_GCP ) {
654 
658  TypeFld.make("thenElse",TypeFunPtr.make(BitsFun.make0(16),2,TypeMemPtr.NO_DISP),2)));
662  TypeFld.make("thenElse",TypeFunPtr.make(BitsFun.make0(18),2,TypeMemPtr.NO_DISP),2)));
664  TypeFld.make("true" ,tt,1),
665  TypeFld.make("false" ,ff,2),
666  TypeFld.make("boolSub",TypeFunPtr.make(BitsFun.make0(22),1,TypeMemPtr.NO_DISP),3));
667  assertEquals(TypeMemPtr.make(11,rez),syn.flow_type());
668  }
669  }
670 
671 }
com.cliffc.aa.type.BitsAlias.FULL
static BitsAlias FULL
Definition: BitsAlias.java:27
com.cliffc.aa.HM.TestHM.test54
void test54()
Definition: TestHM.java:569
com.cliffc.aa.type.Type.NSCALR
static final Type NSCALR
Definition: Type.java:330
com.cliffc.aa.type.TypeMemPtr.NO_DISP
static final Type NO_DISP
Definition: TypeMemPtr.java:80
com.cliffc.aa.HM.TestHM.build_cycle
static TypeMemPtr build_cycle(int alias, boolean nil, Type fld)
Definition: TestHM.java:237
com.cliffc.aa.HM.TestHM.tuple2
static final TypeMemPtr tuple2
Definition: TestHM.java:28
com.cliffc.aa.type.TypeFunPtr
Definition: TypeFunPtr.java:23
com.cliffc.aa.HM.HM.Root
Definition: HM.java:735
com.cliffc.aa.type.TypeTuple.make_args
static TypeTuple make_args(Type[] ts)
Definition: TypeTuple.java:106
com.cliffc.aa.type.BitsFun.make0
static BitsFun make0(int bit)
Definition: BitsFun.java:44
com.cliffc.aa.HM.TestHM.test39
void test39()
Definition: TestHM.java:337
com.cliffc.aa.type.TypeTuple.make_ret
static TypeTuple make_ret(Type trez)
Definition: TypeTuple.java:120
com.cliffc.aa.HM.TestHM.test10
void test10()
Definition: TestHM.java:87
com.cliffc.aa.type.Type.SCALAR
static final Type SCALAR
Definition: Type.java:328
com.cliffc
com.cliffc.aa.HM.TestHM.test06
void test06()
Definition: TestHM.java:63
com.cliffc.aa.HM.TestHM.tfs
static TypeFunSig tfs(Type ret)
Definition: TestHM.java:22
com.cliffc.aa.type.Bits.make
B make(boolean any, long[] bits)
Definition: Bits.java:154
com.cliffc.aa.type.TypeFld
Definition: TypeFld.java:12
com.cliffc.aa.type.Type.XSCALAR
static final Type XSCALAR
Definition: Type.java:329
com.cliffc.aa.type.TypeInt
Definition: TypeInt.java:9
com.cliffc.aa.HM.TestHM.test47
void test47()
Definition: TestHM.java:454
com.cliffc.aa.type.Type
an implementation of language AA
Definition: Type.java:94
com.cliffc.aa.HM.TestHM.test19
void test19()
Definition: TestHM.java:153
com.cliffc.aa.HM.HM.Root.flow_type
Type flow_type()
Definition: HM.java:775
com.cliffc.aa.type.TypeFunSig.make
static TypeFunSig make(String[] args, TypeTuple formals, TypeTuple ret)
Definition: TypeFunSig.java:71
com.cliffc.aa.type.TypeFlt
Definition: TypeFlt.java:9
com.cliffc.aa.HM.TestHM.test57
void test57()
Definition: TestHM.java:636
com.cliffc.aa.type.BitsAlias
Definition: BitsAlias.java:8
com.cliffc.aa.HM.TestHM.reset
void reset()
Definition: TestHM.java:12
com.cliffc.aa.type.TypeTuple
Definition: TypeTuple.java:11
com.cliffc.aa.HM.TestHM.test23
void test23()
Definition: TestHM.java:190
com.cliffc.aa.type.TypeFld.NO_DISP
static final TypeFld NO_DISP
Definition: TypeFld.java:170
com.cliffc.aa.HM.TestHM.test13
void test13()
Definition: TestHM.java:99
com.cliffc.aa.HM.TestHM.test26
void test26()
Definition: TestHM.java:213
com.cliffc.aa.HM.TestHM.test32
void test32()
Definition: TestHM.java:271
com.cliffc.aa.type.TypeInt.con
static TypeInt con(long con)
Definition: TypeInt.java:37
com.cliffc.aa.HM.HM
Definition: HM.java:84
com.cliffc.aa.HM.TestHM.test03
void test03()
Definition: TestHM.java:44
com.cliffc.aa.HM.TestHM.test45
void test45()
Definition: TestHM.java:422
com.cliffc.aa.HM.TestHM.test21
void test21()
Definition: TestHM.java:180
com.cliffc.aa.type.Type.ANY
static final Type ANY
Definition: Type.java:325
Test
com.cliffc.aa.HM.TestHM.test43
void test43()
Definition: TestHM.java:399
com.cliffc.aa.HM.TestHM.test15
void test15()
Definition: TestHM.java:118
com.cliffc.aa.HM.TestHM.test31
void test31()
Definition: TestHM.java:234
com.cliffc.aa.type.TypeStruct
A memory-based collection of optionally named fields.
Definition: TypeStruct.java:50
com.cliffc.aa.type.TypeFld.make
static TypeFld make(String fld, Type t, int order)
Definition: TypeFld.java:58
com.cliffc.aa.HM.TestHM.test52
void test52()
Definition: TestHM.java:510
com.cliffc.aa.HM.HM.DO_HM
static final boolean DO_HM
Definition: HM.java:91
com.cliffc.aa.HM.TestHM.test42
void test42()
Definition: TestHM.java:386
com.cliffc.aa.HM.TestHM.test46
void test46()
Definition: TestHM.java:450
com.cliffc.aa.type.TypeStruct.at
Type at(int idx)
Definition: TypeStruct.java:1013
com.cliffc.aa.HM.TestHM.test25
void test25()
Definition: TestHM.java:207
com.cliffc.aa.HM.TestHM.test51
void test51()
Definition: TestHM.java:492
com.cliffc.aa.HM.TestHM.tuple9
static final TypeMemPtr tuple9
Definition: TestHM.java:33
com.cliffc.aa.HM.TestHM.test12
void test12()
Definition: TestHM.java:95
com.cliffc.aa.HM.TestHM.test48
void test48()
Definition: TestHM.java:458
com.cliffc.aa.type.TypeInt.INT64
static final TypeInt INT64
Definition: TypeInt.java:39
com.cliffc.aa.HM.TestHM.test07
void test07()
Definition: TestHM.java:75
com.cliffc.aa.HM.TestHM.test37
void test37()
Definition: TestHM.java:327
com.cliffc.aa.HM.TestHM.test35
void test35()
Definition: TestHM.java:302
com.cliffc.aa.type.TypeObj
Definition: TypeObj.java:15
com.cliffc.aa.type.TypeFlt.con
static Type con(double con)
Definition: TypeFlt.java:36
com.cliffc.aa.HM.TestHM.test29
void test29()
Definition: TestHM.java:225
com.cliffc.aa.HM.TestHM.test40
void test40()
Definition: TestHM.java:349
com.cliffc.aa.HM.HM.T2.p
String p()
Definition: HM.java:2205
com.cliffc.aa.HM.TestHM.test11
void test11()
Definition: TestHM.java:91
com.cliffc.aa.type.Type.XNSCALR
static final Type XNSCALR
Definition: Type.java:331
com.cliffc.aa.type.TypeObj.XOBJ
static final TypeObj XOBJ
Definition: TypeObj.java:47
com.cliffc.aa.HM.HM.Syntax._hmt
T2 _hmt
Definition: HM.java:343
com.cliffc.aa.HM.TestHM.test04
void test04()
Definition: TestHM.java:47
com.cliffc.aa.type.TypeStr.ABC
static final TypeStr ABC
Definition: TypeStr.java:47
com.cliffc.aa.HM.TestHM.test28
void test28()
Definition: TestHM.java:221
com.cliffc.aa.type.TypeInt.NINT8
static final TypeInt NINT8
Definition: TypeInt.java:47
com.cliffc.aa.HM.TestHM.test14
void test14()
Definition: TestHM.java:105
com.cliffc.aa.HM.TestHM.test49
void test49()
Definition: TestHM.java:463
com.cliffc.aa.HM.TestHM.test53
void test53()
Definition: TestHM.java:565
com.cliffc.aa.type.Bits.meet_nil
B meet_nil()
Definition: Bits.java:212
com.cliffc.aa.HM.TestHM.test50
void test50()
Definition: TestHM.java:478
com.cliffc.aa.type.TypeFunPtr.make
static TypeFunPtr make(BitsFun fidxs, int nargs, Type disp)
Definition: TypeFunPtr.java:67
com.cliffc.aa.HM.TestHM.make_tups
static TypeStruct make_tups(Type t0, Type t1)
Definition: TestHM.java:26
com.cliffc.aa.HM.TestHM.tuplen2
static final TypeMemPtr tuplen2
Definition: TestHM.java:29
com.cliffc.aa.HM.TestHM.test16
void test16()
Definition: TestHM.java:122
com.cliffc.aa.type.TypeStruct.flds
static TypeFld[] flds(Type t1)
Definition: TypeStruct.java:184
com.cliffc.aa.type.TypeStr
Definition: TypeStr.java:14
com.cliffc.aa.HM.TestHM.test08
void test08()
Definition: TestHM.java:80
com.cliffc.aa.type.TypeStruct.tups
static TypeFld[] tups(Type t1, Type t2)
Definition: TypeStruct.java:186
com.cliffc.aa.type.BitsFun
Definition: BitsFun.java:7
com.cliffc.aa.HM.TestHM.tuple82
static final TypeMemPtr tuple82
Definition: TestHM.java:30
com.cliffc.aa.HM.TestHM.test38
void test38()
Definition: TestHM.java:332
com.cliffc.aa.HM.HM.hm
static Root hm(String sprog)
Definition: HM.java:94
com.cliffc.aa.type.TypeStruct.approx
TypeStruct approx(int cutoff, int alias)
Definition: TypeStruct.java:477
com.cliffc.aa.HM.TestHM.build_cycle2
static TypeMemPtr build_cycle2(boolean nil, Type fld)
Definition: TestHM.java:249
com.cliffc.aa.HM.TestHM.test55
void test55()
Definition: TestHM.java:573
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.type.BitsAlias.make0
static BitsAlias make0(int bit)
Definition: BitsAlias.java:72
com.cliffc.aa.HM.TestHM.test36
void test36()
Definition: TestHM.java:319
com.cliffc.aa.HM.TestHM.test20
void test20()
Definition: TestHM.java:165
com.cliffc.aa.HM.TestHM.test34
void test34()
Definition: TestHM.java:293
com.cliffc.aa.HM
Definition: HM.java:1
com.cliffc.aa.HM.TestHM.test33
void test33()
Definition: TestHM.java:283
com.cliffc.aa.type.TypeFunSig
Definition: TypeFunSig.java:10
com.cliffc.aa.HM.HM.DO_GCP
static final boolean DO_GCP
Definition: HM.java:92
com.cliffc.aa.HM.TestHM.test22
void test22()
Definition: TestHM.java:186
com.cliffc.aa.HM.TestHM.test09
void test09()
Definition: TestHM.java:84
com.cliffc.aa.type.TypeStruct.make
static TypeStruct make(String fld_name, Type t)
Definition: TypeStruct.java:190
com.cliffc.aa.HM.TestHM.test24
void test24()
Definition: TestHM.java:197
com.cliffc.aa.HM.TestHM.tuple55
static final TypeMemPtr tuple55
Definition: TestHM.java:31
com.cliffc.aa.HM.TestHM.test17
void test17()
Definition: TestHM.java:125
com.cliffc.aa.HM.TestHM.ret_tuple2
static final TypeFunSig ret_tuple2
Definition: TestHM.java:32
com.cliffc.aa.HM.TestHM.test01
void test01()
Definition: TestHM.java:38
com.cliffc.aa.type.Type.XNIL
static final Type XNIL
Definition: Type.java:333
com.cliffc.aa.HM.TestHM.test56
void test56()
Definition: TestHM.java:624
com.cliffc.aa.HM.TestHM.run
void run(String prog, String rez_hm, Type rez_gcp)
Definition: TestHM.java:14
com.cliffc.aa.type.TypeMemPtr.STRPTR
static final TypeMemPtr STRPTR
Definition: TypeMemPtr.java:97
com.cliffc.aa.HM.TestHM.test05
void test05()
Definition: TestHM.java:52
com.cliffc.aa.HM.TestHM
Definition: TestHM.java:10
com
com.cliffc.aa.HM.TestHM.test02
void test02()
Definition: TestHM.java:41
com.cliffc.aa.HM.HM.reset
static void reset()
Definition: HM.java:143
com.cliffc.aa.HM.TestHM.test41
void test41()
Definition: TestHM.java:369
com.cliffc.aa.HM.TestHM.test30
void test30()
Definition: TestHM.java:229
com.cliffc.aa.HM.TestHM.test44
void test44()
Definition: TestHM.java:408
com.cliffc.aa.HM.TestHM.test27
void test27()
Definition: TestHM.java:217
com.cliffc.aa.type.TypeInt.BOOL
static final TypeInt BOOL
Definition: TypeInt.java:43
com.cliffc.aa.HM.TestHM.test00
void test00()
Definition: TestHM.java:36
com.cliffc.aa.type
Definition: Bits.java:1
com.cliffc.aa.type.TypeMemPtr
Definition: TypeMemPtr.java:14
com.cliffc.aa.HM.TestHM.make_tups
static TypeStruct make_tups(Type t0, Type t1, Type t2)
Definition: TestHM.java:27
com.cliffc.aa.type.TypeFlt.FLT64
static final TypeFlt FLT64
Definition: TypeFlt.java:38
com.cliffc.aa.HM.TestHM.test18
void test18()
Definition: TestHM.java:140
com.cliffc.aa.type.TypeMemPtr.make
static TypeMemPtr make(BitsAlias aliases, TypeObj obj)
Definition: TypeMemPtr.java:66