aa
HM8.java
Go to the documentation of this file.
1 package com.cliffc.aa.HM;
2 
3 import com.cliffc.aa.type.*;
4 import com.cliffc.aa.util.*;
5 import org.jetbrains.annotations.NotNull;
6 
7 import java.util.*;
8 
9 import static com.cliffc.aa.AA.unimpl;
10 
11 // Hindley-Milner typing. Complete stand-alone, for research. MEETs base
12 // types, instead of declaring type error. Requires SSA renumbering; looks
13 // 'up' the Syntax tree for variables instead of building a 'nongen' set.
14 //
15 // T2 types form a Lattice, with 'unify' same as 'meet'. T2's form a DAG
16 // (cycles if i allow recursive unification) with sharing. Each Syntax has a
17 // T2, and the forest of T2s can share. Leaves of a T2 can be either a simple
18 // concrete base type, or a sharable leaf. Unify is structural, and where not
19 // unifyable the union is replaced with an Error.
20 
21 // Extend to records with nil.
22 // Extend to aliases.
23 
24 public class HM8 {
25  static final HashMap<String,T2> PRIMS = new HashMap<>();
26  static boolean DEBUG_LEAKS=false;
27  static { BitsAlias.init0(); }
28 
29  public static Syntax hm( String sprog ) {
30  Worklist work = new Worklist();
31 
32  // Simple types
33  T2 bool = T2.make_base(TypeInt.BOOL);
34  T2 int64 = T2.make_base(TypeInt.INT64);
35  T2 flt64 = T2.make_base(TypeFlt.FLT64);
37 
38  // Primitives
39  PRIMS.put("nil",T2.make_nil());
40 
41  T2 var1 = T2.make_leaf();
42  T2 var2 = T2.make_leaf();
43  T2 var3 = T2.make_leaf();
44 
45  PRIMS.put("pair1",T2.make_fun(var1, T2.make_fun(var2, T2.prim("pair",var1,var2) ))); // curried
46  PRIMS.put("pair",T2.make_fun(var1, var2, T2.prim("pair",var1,var2) ));
47  PRIMS.put("triple",T2.make_fun(var1, var2, var3, T2.prim("triple",var1,var2,var3) ));
48 
49  PRIMS.put("if",T2.make_fun(var2,var1,var1,var1));
50 
51  PRIMS.put("dec",T2.make_fun(int64,int64));
52  PRIMS.put("*" ,T2.make_fun(int64,int64,int64));
53  PRIMS.put("?0",T2.make_fun(T2.make_leaf(),bool));
54  PRIMS.put("isempty",T2.make_fun(strp,bool));
55 
56  // Print a string; int->str
57  PRIMS.put("str",T2.make_fun(int64,strp));
58  // Factor; FP div/mod-like operation
59  PRIMS.put("factor",T2.make_fun(flt64,T2.prim("divmod",flt64,flt64)));
60 
61  // Parse
62  Syntax prog = parse( sprog );
63 
64  // Prep for SSA: pre-gather all the (unique) ids
65  int cnt_syns = prog.prep_tree(null,null,work);
66  int init_T2s = T2.CNT;
67 
68  while( work.len()>0 ) { // While work
69  int oldcnt = T2.CNT; // Used for cost-check when no-progress
70  Syntax syn = work.pop(); // Get work
71  T2 old = syn._t; // Old value for progress assert
72  if( syn.hm(work) ) { // Compute a new HM type and check for progress
73  assert !syn.debug_find().unify(old.find(),null);// monotonic: unifying with the result is no-progress
74  syn.add_work(work); // Push affected neighors on worklist
75  } else {
76  assert !DEBUG_LEAKS || oldcnt==T2.CNT; // No-progress consumes no-new-T2s
77  }
78  // VERY EXPENSIVE ASSERT: O(n^2). Every Syntax that makes progress is on the worklist
79  assert prog.more_work(work);
80  }
81  assert prog.more_work(work);
82 
83  //System.out.println("Initial T2s: "+init_T2s+", Prog size: "+cnt_syns+", worklist iters: "+work._cnt+", T2s: "+T2.CNT);
84  return prog;
85  }
86  static void reset() { PRIMS.clear(); T2.reset(); BitsAlias.reset_to_init0(); }
87 
88  // ---------------------------------------------------------------------
89  // Program text for parsing
90  private static int X;
91  private static byte[] BUF;
92  @Override public String toString() { return new String(BUF,X,BUF.length-X); }
93  static Syntax parse( String s ) {
94  X = 0;
95  BUF = s.getBytes();
96  Syntax prog = term();
97  if( skipWS() != -1 ) throw unimpl("Junk at end of program: "+new String(BUF,X,BUF.length-X));
98  return prog;
99  }
100  static Syntax term() {
101  if( skipWS()==-1 ) return null;
102  if( isDigit(BUF[X]) ) return number();
103  if( BUF[X]=='"' ) return string();
104  if( BUF[X]=='(' ) { // Parse an Apply
105  X++; // Skip paren
106  Syntax fun = term();
107  Ary<Syntax> ARGS = new Ary<>(new Syntax[1],0);
108  while( skipWS()!= ')' && X<BUF.length ) ARGS.push(term());
109  return new Apply(fun,require(')',ARGS.asAry()));
110  }
111  if( BUF[X]=='{' ) { // Lambda of 1 or 2 args
112  X++; // Skip paren
113  Ary<String> args = new Ary<>(new String[1],0);
114  while( skipWS()!='-' ) args.push(id());
115  require("->");
116  Syntax body = require('}',term());
117  return new Lambda(body,args.asAry());
118  }
119  // Let or Id
120  if( isAlpha0(BUF[X]) ) {
121  String id = id();
122  if( skipWS()!='=' ) return new Ident(id);
123  // Let expression; "id = term(); term..."
124  X++; // Skip '='
125  Syntax def = require(';',term());
126  return new Let(id,def,term());
127  }
128 
129  // Structure
130  if( BUF[X]=='@' ) {
131  X++;
132  require('{',null);
133  Ary<String> ids = new Ary<>(String.class);
134  Ary<Syntax> flds = new Ary<>(Syntax.class);
135  while( skipWS()!='}' && X < BUF.length ) {
136  String id = require('=',id());
137  Syntax fld = term();
138  if( fld==null ) throw unimpl("Missing term for field "+id);
139  ids .push( id);
140  flds.push(fld);
141  if( skipWS()==',' ) X++;
142  }
143  return require('}',new Struct(ids.asAry(),flds.asAry()));
144  }
145 
146  // Field lookup is prefix or backwards: ".x term"
147  if( BUF[X]=='.' ) {
148  X++;
149  return new Field(id(),term());
150  }
151 
152  throw unimpl("Unknown syntax");
153  }
154  private static final SB ID = new SB();
155  private static String id() {
156  ID.clear();
157  while( X<BUF.length && isAlpha1(BUF[X]) )
158  ID.p((char)BUF[X++]);
159  String s = ID.toString().intern();
160  if( s.length()==0 ) throw unimpl("Missing id");
161  return s;
162  }
163  private static Syntax number() {
164  int sum=0;
165  while( X<BUF.length && isDigit(BUF[X]) )
166  sum = sum*10+BUF[X++]-'0';
167  if( X>= BUF.length || BUF[X]!='.' ) return new Con(TypeInt.con(sum));
168  X++;
169  float f = (float)sum;
170  f = f + (BUF[X++]-'0')/10.0f;
171  return new Con(TypeFlt.con(f));
172  }
173  private static Syntax string() {
174  int start = ++X;
175  while( X<BUF.length && BUF[X]!='"' ) X++;
176  return require('"', new Con(TypeStr.con(new String(BUF,start,X-start).intern())));
177  }
178  private static byte skipWS() {
179  while( X<BUF.length && isWS(BUF[X]) ) X++;
180  return X==BUF.length ? -1 : BUF[X];
181  }
182  private static boolean isWS (byte c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; }
183  private static boolean isDigit (byte c) { return '0' <= c && c <= '9'; }
184  private static boolean isAlpha0(byte c) { return ('a'<=c && c <= 'z') || ('A'<=c && c <= 'Z') || (c=='_') || (c=='*') || (c=='?'); }
185  private static boolean isAlpha1(byte c) { return isAlpha0(c) || ('0'<=c && c <= '9') || (c=='/'); }
186  private static <T> T require(char c, T t) { if( skipWS()!=c ) throw unimpl("Missing '"+c+"'"); X++; return t; }
187  private static void require(String s) {
188  skipWS();
189  for( int i=0; i<s.length(); i++ )
190  if( X+i >= BUF.length || BUF[X+i]!=s.charAt(i) )
191  throw unimpl("Missing '"+s+"'");
192  X+=s.length();
193  }
194 
195  // ---------------------------------------------------------------------
196  // Worklist of Syntax nodes
197  private static class Worklist {
198  public int _cnt;
199  private final Ary<Syntax> _ary = new Ary<>(Syntax.class); // For picking random element
200  private final HashSet<Syntax> _work = new HashSet<>(); // For preventing dups
201  public int len() { return _ary.len(); }
202  public void push(Syntax s) { if( s!=null && !_work.contains(s) ) _work.add(_ary.push(s)); }
203  public Syntax pop() { Syntax s = _ary.pop();_cnt++; _work.remove(s); return s; }
204  //public Syntax pop() { Syntax s = _ary.del( _cnt++%_ary._len); _work.remove(s); return s; }
205  public boolean has(Syntax s) { return _work.contains(s); }
206  public void addAll(Ary<? extends Syntax> ss) { if( ss != null ) for( Syntax s : ss ) push(s); }
207  @Override public String toString() { return _ary.toString(); }
208  }
209 
210  // ---------------------------------------------------------------------
211  // Small classic tree of T2s, immutable, with sharing at the root parts.
212  static class VStack implements Iterable<T2> {
213  final VStack _par;
214  final T2 _nongen;
215  VStack( VStack par, T2 nongen ) { _par=par; _nongen=nongen; }
216  @Override public String toString() {
217  // Collect dups across the forest of types
218  VBitSet dups = new VBitSet();
219  for( VStack vs = this; vs!=null; vs = vs._par )
220  vs._nongen.get_dups(dups);
221  // Now recursively print
222  return str(new SB(),dups).toString();
223  }
224  SB str(SB sb, VBitSet dups) {
225  _nongen.str(sb,new VBitSet(),dups);
226  if( _par!=null ) _par.str(sb.p(" , "),dups);
227  return sb;
228  }
229  @NotNull @Override public Iterator<T2> iterator() { return new Iter(); }
230  private class Iter implements Iterator<T2> {
231  private VStack _vstk;
232  Iter() { _vstk=VStack.this; }
233  @Override public boolean hasNext() { return _vstk!=null; }
234  @Override public T2 next() { T2 v = _vstk._nongen; _vstk = _vstk._par; return v; }
235  }
236  }
237 
238  // ---------------------------------------------------------------------
239  static abstract class Syntax {
242  T2 _pre; // Pre-memory
243  T2 _t; // Current HM type
244  T2 _post; // Post-memory
245  T2 find() { // U-F find
246  T2 t = _t.find();
247  return t==_t ? t : (_t=t);
248  }
249  T2 debug_find() { return _t.debug_find(); } // Find, without the roll-up
250  T2 pre() {
251  T2 t = _pre.find();
252  return t==_pre ? t : (_pre=t);
253  }
254  T2 post() {
255  T2 t = _post.find();
256  return t==_post ? t : (_post=t);
257  }
258 
259  // Compute and set a new HM type.
260  // If no change, return false.
261  // If a change, return always true, however:
262  // - If 'work' is null do not change/set anything.
263  // - If 'work' is available, set a new HM in '_t' and update the worklist.
264  abstract boolean hm(Worklist work);
265 
266  abstract int prep_tree(Syntax par, VStack nongen, Worklist work);
267  final void prep_tree_impl( Syntax par, VStack nongen, Worklist work, T2 t ) {
268  _par=par;
269  _pre = T2.make_mem();
270  _t=t;
271  _post = T2.make_mem();
272  _nongen = nongen;
273  work.push(this);
274  }
275  abstract void prep_lookup_deps(Ident id);
276 
277  abstract T2 lookup(String name); // Lookup name in scope & return type; TODO: pre-cache this.
278 
279  abstract void add_work(Worklist work); // Add affected neighbors to worklist
280 
281  // Giant Assert: True if OK; all Syntaxs off worklist do not make progress
282  abstract boolean more_work(Worklist work);
283  final boolean more_work_impl(Worklist work) {
284  boolean no_more_work = work.has(this) || !hm(null); // Either on worklist, or no-progress
285  return no_more_work;
286  }
287  // Print for debugger
288  @Override final public String toString() { return str(new SB()).toString(); }
289  abstract SB str(SB sb);
290  // Line-by-line print with more detail
291  public String p() { return p0(new SB(), new VBitSet()).toString(); }
292  final SB p0(SB sb, VBitSet dups) {
293  _t.get_dups(dups);
294  _t.str(p1(sb.i()).p(" "), new VBitSet(),dups).nl();
295  return p2(sb.ii(1),dups).di(1);
296  }
297  abstract SB p1(SB sb); // Self short print
298  abstract SB p2(SB sb, VBitSet dups); // Recursion print
299  }
300 
301  static class Con extends Syntax {
302  final Type _con;
303  Con(Type con) { super(); _con=con; }
304  @Override SB str(SB sb) { return p1(sb); }
305  @Override SB p1(SB sb) { return sb.p(_con instanceof TypeMemPtr ? "str" : _con.toString()); }
306  @Override SB p2(SB sb, VBitSet dups) { return sb; }
307  @Override boolean hm(Worklist work) { return false; }
308  @Override T2 lookup(String name) { throw unimpl("should not reach here"); }
309  @Override void add_work(Worklist work) { work.push(_par); }
310  @Override int prep_tree( Syntax par, VStack nongen, Worklist work ) {
311  prep_tree_impl(par, nongen, work, _con==Type.NIL ? T2.make_nil() : T2.make_base(_con));
312  _pre=_post; // Unify at prep-time
313  return 1;
314  }
315  @Override void prep_lookup_deps(Ident id) { throw unimpl("should not reach here"); }
316  @Override boolean more_work(Worklist work) { return more_work_impl(work); }
317  }
318 
319  static class Ident extends Syntax {
320  final String _name;
321  Ident(String name) { _name=name; }
322  @Override SB str(SB sb) { return p1(sb); }
323  @Override SB p1(SB sb) { return sb.p(_name); }
324  @Override SB p2(SB sb, VBitSet dups) { return sb; }
325  @Override boolean hm(Worklist work) {
326  // A boolean if name is from a Let._body (or PRIM) vs Let._def (or
327  // Lambda). Not helpful, as its only useful at the top-layer.
328  // Structural unification requires the 'occurs check' at each internal
329  // layer, which can differ from the top-layer.
330  //boolean occurs_fresh = _par==null /*from prims*/ || _par.is_fresh(_name,this);
331  T2 t = _par==null ? null : _par.lookup(_name); // Lookup in current env
332  if( t==null ) t = PRIMS.get(_name); // Lookup in prims
333  if( t==null )
334  throw new RuntimeException("Parse error, "+_name+" is undefined");
335  return t.find().fresh_unify(find(),_nongen,work);
336  }
337  @Override T2 lookup(String name) { throw unimpl("should not reach here"); }
338  @Override void add_work(Worklist work) {
339  work.push(_par);
340  T2 t = _par==null ? null : _par.lookup(_name); // Lookup in current env
341  if( t==null ) t = PRIMS.get(_name); // Lookup in prims
342  t = t.find();
343  if( t.occurs_in(_par) ) // Got captured in some parent?
344  t.add_deps_work(work); // Need to revisit dependent ids
345  }
346  @Override int prep_tree( Syntax par, VStack nongen, Worklist work ) {
347  prep_tree_impl(par,nongen,work,T2.make_leaf());
348  _pre=_post; // Unify at prep-time
349  for( Syntax syn = _par; syn!=null; syn = syn._par )
350  syn.prep_lookup_deps(this);
351  return 1;
352  }
353  @Override void prep_lookup_deps(Ident id) { throw unimpl("should not reach here"); }
354  @Override boolean more_work(Worklist work) { return more_work_impl(work); }
355  }
356 
357  static class Lambda extends Syntax {
358  final String[] _args;
359  final Syntax _body;
361  Lambda(Syntax body, String... args) {
362  _args=args;
363  _body=body;
364  _targs = new T2[args.length];
365  for( int i=0; i<args.length; i++ ) _targs[i] = T2.make_leaf();
366  }
367  @Override SB str(SB sb) {
368  sb.p("{ ");
369  for( String arg : _args ) sb.p(arg).p(' ');
370  return _body.str(sb.p("-> ")).p(" }");
371  }
372  @Override SB p1(SB sb) {
373  sb.p("{ ");
374  for( String arg : _args ) sb.p(arg).p(' ');
375  return sb.p(" -> ... } ");
376  }
377  @Override SB p2(SB sb, VBitSet dups) { return _body.p0(sb,dups); }
378  T2 targ(int i) { T2 targ = _targs[i].find(); return targ==_targs[i] ? targ : (_targs[i]=targ); }
379  @Override boolean hm(Worklist work) {
380  boolean progress = false;
381  // Lambda memory: pre-memory unifies with body-pre, post-memory unifies with post-body.
382  progress |= pre ().unify(_body.pre (),work);
383  progress |= post().unify(_body.post(),work);
384  if( work==null && progress ) return true;
385 
386  // The normal lambda work
387  T2 old = find();
388  if( old.is_err() ) return false;
389  if( old.is_fun() ) { // Already a function? Compare-by-parts
390  for( int i=0; i<_targs.length; i++ )
391  if( old.args(i).unify(targ(i),work) )
392  { progress=true; break; }
393  if( !progress && !old.args(_targs.length).unify(_body.find(),work) )
394  return false; // Shortcut: no progress, no allocation
395  }
396  // Make a new T2 for progress
397  T2[] targs = Arrays.copyOf(_targs,_targs.length+1);
398  targs[_targs.length] = _body.find();
399  T2 fun = T2.make_fun(targs);
400  return old.unify(fun,work);
401  }
402  @Override T2 lookup(String name) {
403  for( int i=0; i<_args.length; i++ )
404  if( Util.eq(_args[i],name) ) return targ(i);
405  return _par==null ? null : _par.lookup(name);
406  }
407  @Override void add_work(Worklist work) {
408  work.push(_par );
409  work.push(_body);
410  for( int i=0; i<_targs.length; i++ )
411  if( targ(i).occurs_in_type(find()) ) work.addAll(_targs[i]._deps);
412  }
413  @Override int prep_tree( Syntax par, VStack nongen, Worklist work ) {
414  prep_tree_impl(par,nongen,work,T2.make_leaf());
415  VStack vs = nongen;
416  for( int i=0; i<_targs.length; i++ )
417  vs = new VStack(vs,_targs[i]);
418  return _body.prep_tree(this,vs,work) + 1;
419  }
420  @Override void prep_lookup_deps(Ident id) {
421  for( int i=0; i<_args.length; i++ )
422  if( Util.eq(_args[i],id._name) ) _targs[i].push_update(id);
423  }
424  @Override boolean more_work(Worklist work) {
425  if( !more_work_impl(work) ) return false;
426  return _body.more_work(work);
427  }
428  }
429 
430  static class Let extends Syntax {
431  final String _arg0;
432  final Syntax _def, _body;
434  Let(String arg0, Syntax def, Syntax body) { _arg0=arg0; _body=body; _def=def; _targ=T2.make_leaf(); }
435  @Override SB str(SB sb) { return _body.str(_def.str(sb.p(_arg0).p(" = ")).p("; ")); }
436  @Override SB p1(SB sb) { return sb.p(_arg0).p(" = ... ; ..."); }
437  @Override SB p2(SB sb, VBitSet dups) { _body.p0(sb,dups); return _def.p0(sb,dups); }
438  T2 targ() { T2 targ = _targ.find(); return targ==_targ ? targ : (_targ=targ); }
439  @Override boolean hm(Worklist work) {
440  boolean progress = false;
441  // Let memory: pre-memory unifies with body-pre, post-memory unifies with post-body.
442  progress |= pre ().unify(_def .pre (),work);
443  progress |= _def .post().unify(_body.pre (),work);
444  progress |= _body.post().unify( post(),work);
445  if( work==null && progress ) return true;
446 
447  return targ().unify(_def.find(),work);
448  }
449  @Override T2 lookup(String name) {
450  if( Util.eq(_arg0,name) ) return targ();
451  return _par==null ? null : _par.lookup(name);
452  }
453  @Override void add_work(Worklist work) {
454  work.push(_par);
455  work.push(_body);
456  work.push(_def);
457  if( targ().occurs_in_type(_def.find()) ) work.addAll(_targ._deps);
458  }
459  @Override int prep_tree( Syntax par, VStack nongen, Worklist work ) {
460  prep_tree_impl(par,nongen,work,_body._t);
461  int cnt = _body.prep_tree(this, nongen ,work) +
462  _def .prep_tree(this,new VStack(nongen,_targ),work);
463  _t = _body._t; // Unify 'Let._t' with the '_body'
464  return cnt+1;
465  }
466  @Override void prep_lookup_deps(Ident id) {
467  if( Util.eq(id._name,_arg0) ) _targ.push_update(id);
468  }
469  @Override boolean more_work(Worklist work) {
470  if( !more_work_impl(work) ) return false;
471  return _body.more_work(work) && _def.more_work(work);
472  }
473  }
474 
475  static class Apply extends Syntax {
476  final Syntax _fun;
477  final Syntax[] _args;
478  Apply(Syntax fun, Syntax... args) { _fun = fun; _args = args; }
479  @Override SB str(SB sb) {
480  _fun.str(sb.p("(")).p(" ");
481  for( Syntax arg : _args )
482  arg.str(sb).p(" ");
483  return sb.unchar().p(")");
484  }
485  @Override SB p1(SB sb) { return sb.p("(...)"); }
486  @Override SB p2(SB sb, VBitSet dups) {
487  _fun.p0(sb,dups);
488  for( Syntax arg : _args ) arg.p0(sb,dups);
489  return sb;
490  }
491 
492  // Unifiying these: make_fun(this.arg0 this.arg1 -> new )
493  // _fun{_fun.arg0 _fun.arg1 -> _fun.rez}
494  @Override boolean hm(Worklist work) {
495  // U/F link pre/post memory with argument memories
496  boolean progress = false;
497  progress |= pre().unify(_fun.pre(),work);
498  if( work==null && progress ) return true;
499  progress |= _fun.post().unify(_args[0].pre(),work);
500  if( work==null && progress ) return true;
501  for( int i=1; i<_args.length; i++ ) {
502  progress |= _args[i-1].post().unify(_args[i].pre(),work);
503  if( work==null && progress ) return true;
504  }
505  progress |= _args[_args.length-1].post().unify(post(),work);
506  if( work==null && progress ) return true;
507 
508  // Discover not-nil in the trivial case of directly using the 'if'
509  // primitive against a T2.is_struct(). Will not work if 'if' is some
510  // more hidden or complex function (e.q. '&&' or '||') or the predicate
511  // implies not-null on some other struct.
512  T2 str = is_if_nil();
513  if( str!=null && str.is_struct() && str._con==null ) {
514  if( work==null ) return true;
515  progress = true;
516  str._con = Type.NIL; // Add nil to a struct
517  work.addAll(str._deps);
518  }
519 
520  // Progress if:
521  // _fun is not a function
522  // any arg-pair-unifies make progress
523  // this-unify-_fun.return makes progress
524  T2 tfun = _fun.find();
525  if( !tfun.is_fun() ) {
526  if( tfun.is_err() ) return find().unify(tfun,work);
527  if( work==null ) return true; // Will-progress & just-testing
528  T2[] targs = new T2[_args.length+1];
529  for( int i=0; i<_args.length; i++ )
530  targs[i] = _args[i].find();
531  targs[_args.length] = find(); // Return
532  T2 nfun = T2.make_fun(targs);
533  progress = tfun.unify(nfun,work);
534  return tfun.find().is_err() ? find().unify(tfun.find(),work) : progress;
535  }
536 
537  if( tfun._args.length != _args.length+1 )
538  progress |= T2.make_err("Mismatched argument lengths").unify(find(),work);
539  // Check for progress amongst arg pairs
540  for( int i=0; i<_args.length; i++ ) {
541  progress |= tfun.args(i).unify(_args[i].find(),work);
542  if( progress && work==null )
543  return true; // Will-progress & just-testing early exit
544  }
545  progress |= tfun.args(_args.length).unify(find(),work);
546  if( tfun.find().is_err() ) return find().unify(tfun.find(),work);
547  return progress;
548  }
549  @Override T2 lookup(String name) { return _par==null ? null : _par.lookup(name); }
550  @Override void add_work(Worklist work) {
551  work.push(_par);
552  for( Syntax arg : _args ) work.push(arg);
553  }
554  @Override int prep_tree(Syntax par, VStack nongen, Worklist work) {
555  prep_tree_impl(par,nongen,work,T2.make_leaf());
556  int cnt = 1+_fun.prep_tree(this,nongen,work);
557  for( Syntax arg : _args ) cnt += arg.prep_tree(this,nongen,work);
558  T2 str = is_if_nil();
559  if( str!=null ) str.push_update(this);
560  return cnt;
561  }
562  @Override void prep_lookup_deps(Ident id) { }
563  @Override boolean more_work(Worklist work) {
564  if( !more_work_impl(work) ) return false;
565  if( !_fun.more_work(work) ) return false;
566  for( Syntax arg : _args ) if( !arg.more_work(work) ) return false;
567  return true;
568  }
569  // True if we can refine an if-not-nil
570  private T2 is_if_nil() {
571  return _fun instanceof Ident && Util.eq(((Ident)_fun)._name,"if") && _args[0] instanceof Ident ? _args[0].find() : null;
572  }
573  }
574 
575  // Structure or Records.
576  static class Struct extends Syntax {
578  final String[] _ids;
579  final Syntax[] _flds;
580  Struct( String[] ids, Syntax[] flds ) { _ids=ids; _flds=flds; _alias = BitsAlias.make0(BitsAlias.new_alias(BitsAlias.REC)); }
581  @Override SB str(SB sb) {
582  _alias.str(sb.p('*')).p("@{");
583  for( int i=0; i<_ids.length; i++ ) {
584  sb.p(' ').p(_ids[i]).p(" = ");
585  _flds[i].str(sb);
586  if( i < _ids.length-1 ) sb.p(',');
587  }
588  return sb.p("}");
589  }
590  @Override SB p1(SB sb) { return _alias.str(sb.p('*')).p("@{ ... } "); }
591  @Override SB p2(SB sb, VBitSet dups) {
592  for( int i=0; i<_ids.length; i++ )
593  _flds[i].p0(sb.p(_ids[i]).p(" = "),dups);
594  return sb;
595  }
596  @Override boolean hm(Worklist work) {
597  // U/F link pre/post memory with fields' memories
598  boolean progress = false, must_alloc=false;
599  progress |= pre().unify(_flds[0].pre(),work);
600  if( work==null && progress ) return true;
601  for( int i=1; i<_flds.length; i++ ) {
602  progress |= _flds[i-1].post().unify(_flds[i].pre(),work);
603  if( work==null && progress ) return true;
604  }
605  progress |= _flds[_flds.length-1].post().unify(post(),work);
606  if( work==null && progress ) return true;
607 
608  // Force result to be a struct with at least these fields.
609  // Do not allocate a T2 unless we need to pick up fields.
610  T2 rec = find();
611  for( String id : _ids )
612  if( Util.find(rec._ids, id) == -1 )
613  { must_alloc = true; break; }
614  if( must_alloc ) { // Must allocate.
615  if( work==null ) return true; // Will progress
616  T2[] t2s = new T2[_ids.length];
617  for( int i=0; i<_ids.length; i++ )
618  t2s[i] = _flds[i].find();
619  T2.make_struct(_ids,_alias,t2s).unify(rec,work);
620  rec=find();
621  progress = true;
622  }
623 
624  // Extra fields are unified with ALL since they are not created here.
625  for( int i=0; i<rec._ids.length; i++ ) {
626  if( Util.find(_ids,rec._ids[i])== -1 && rec.args(i)._con!=Type.ALL && !rec.args(i).is_err() ) {
627  if( work==null ) return true;
628  progress |= T2.make_base(Type.ALL).unify(rec.args(i),work);
629  }
630  }
631 
632  // Unify existing fields. Ignore extras on either side.
633  for( int i=0; i<_ids.length; i++ ) {
634  int idx = Util.find(rec._ids,_ids[i]);
635  if( idx!= -1 ) progress |= rec.args(idx).unify(_flds[i].find(),work);
636  if( work==null && progress ) return true;
637  }
638 
639  // Unify struct at alias into post-memory
640  progress |= _post.unify_rec(_alias.getbit(),rec,work);
641  return progress;
642  }
643  @Override T2 lookup(String name) { return _par==null ? null : _par.lookup(name); }
644  @Override void add_work(Worklist work) {
645  work.push(_par);
646  for( Syntax fld : _flds ) work.push(fld);
647  }
648  @Override int prep_tree(Syntax par, VStack nongen, Worklist work) {
649  T2[] t2s = new T2[_ids.length];
650  prep_tree_impl(par, nongen, work, T2.make_struct(_ids,_alias,t2s));
651  prep_tree_impl(par, nongen, work, T2.make_struct(new String[0],_alias,new T2[0]));
652  int cnt = 1; // One for self
653  for( int i=0; i<_flds.length; i++ ) { // Prep all sub-fields
654  cnt += _flds[i].prep_tree(this,nongen,work);
655  t2s[i] = _flds[i].find();
656  }
657  return cnt;
658  }
659  @Override void prep_lookup_deps(Ident id) { }
660  @Override boolean more_work(Worklist work) {
661  if( !more_work_impl(work) ) return false;
662  for( Syntax fld : _flds )
663  if( !fld.more_work(work) )
664  return false;
665  return true;
666  }
667  }
668 
669  // Field lookup in a Struct
670  static class Field extends Syntax {
671  final String _id;
672  final Syntax _rec;
673  Field( String id, Syntax str ) { _id=id; _rec =str; }
674  @Override SB str(SB sb) { return _rec.str(sb.p(".").p(_id).p(' ')); }
675  @Override SB p1 (SB sb) { return sb.p(".").p(_id); }
676  @Override SB p2(SB sb, VBitSet dups) { return _rec.p0(sb,dups); }
677  @Override boolean hm(Worklist work) {
678  boolean progress = false;
679  progress |= pre ().unify(_rec.pre (),work); // Pre -memory unifies with child pre
680  progress |= post().unify(_rec.post(),work); // Post-memory unifies with child post
681  if( work==null && progress ) return true;
682 
683  T2 rec = _rec.find();
684  int idx = rec._ids==null ? -1 : Util.find(rec._ids,_id);
685  if( idx==-1 ) { // Not a struct or no field, force it to be one
686  if( find().is_err() ) return false;
687  if( work==null ) return true;
688  if( rec.is_err() ) return find().unify(rec,work);
689  progress |= T2.make_struct(new String[]{_id}, BitsAlias.RECORD_BITS.dual(),new T2[]{find().push_update(rec._deps)}).unify(rec, work);
690  } else {
691  // Unify the field
692  progress |= rec.args(idx).unify(find(), work);
693  if( find()._con==Type.ALL )
694  progress |= T2.make_err("Missing field "+_id+" in "+rec.find()).unify(find(),work);
695  }
696  return progress;
697  }
698  @Override T2 lookup(String name) { return _par==null ? null : _par.lookup(name); }
699  @Override void add_work(Worklist work) {
700  work.push(_par);
701  work.push(_rec);
702  _rec.add_work(work);
703  }
704  @Override int prep_tree(Syntax par, VStack nongen, Worklist work) {
705  prep_tree_impl(par, nongen, work, T2.make_leaf());
706  return _rec.prep_tree(this,nongen,work)+1;
707  }
708  @Override void prep_lookup_deps(Ident id) { }
709  @Override boolean more_work(Worklist work) {
710  if( !more_work_impl(work) ) return false;
711  return _rec.more_work(work);
712  }
713  }
714 
715  // ---------------------------------------------------------------------
716  // T2 types form a Lattice, with 'unify' same as 'meet'. T2's form a DAG
717  // (cycles if i allow recursive unification) with sharing. Each Syntax has a
718  // T2, and the forest of T2s can share. Leaves of a T2 can be either a
719  // simple concrete base type, or a sharable leaf. Unify is structural, and
720  // where not unifyable the union is replaced with an Error.
721  static class T2 {
722  private static int CNT=0;
723  final int _uid;
724 
725  // A plain type variable starts with a 'V', and can unify directly.
726  // Everything else is structural - during unification they must match names
727  // and arguments and Type constants.
728  @NotNull String _name; // name, e.g. "->" or "pair" or "V123" or "base"
729 
730  // Structural parts to unify with, or slot 0 is used during normal U-F
731  T2 @NotNull [] _args;
732 
733  // Base types carry a concrete Type
735 
736  // Structs have field names
737  @NotNull String[] _ids;
738 
739  // Alias bits, for pointers and structs only.
741 
742  // Dependent (non-local) tvars to revisit
744 
745  // Constructor factories.
746  static T2 make_fun(T2... args) { return new T2("->",null,null,null,args); }
747  static T2 make_leaf() { return new T2("V"+CNT,null,null,null,new T2[1]); }
748  static T2 make_base(Type con) { return new T2("Base",con,null,null); }
749  static T2 make_nil() { return new T2("Nil",null,null,null); }
750  static T2 make_struct( String[] ids, BitsAlias aliases, T2[] flds ) { return new T2("@{}", null,ids,aliases,flds); }
751  static T2 make_mem() { return new T2("[]" ,null,null,null,new T2[1]); }
752  static T2 make_err(String s) { return new T2("Err",TypeStr.con(s.intern()),null,null); }
753  static T2 prim(String name, T2... args) { return new T2(name,null,null,null,args); }
754  T2 copy() { return new T2(_name,_con,_ids,_aliases,new T2[_args.length]); }
755 
756  private T2(@NotNull String name, Type con, String[] ids, BitsAlias aliases, T2 @NotNull ... args) {
757  _uid = CNT++;
758  _name= name;
759  _con = con;
760  _ids = ids;
761  _aliases = aliases;
762  _args= args;
763  _deps = null;
764  }
765 
766  // A type var, not a concrete leaf. Might be U-Fd or not.
767  boolean is_leaf() { return _name.charAt(0)=='V' || (isa("Base") && _con==null); }
768  boolean no_uf() { return !is_leaf() || _args[0]==null; }
769  boolean isa(String name) { return Util.eq(_name,name); }
770  boolean is_base() { return isa("Base") && _con!=null; }
771  boolean is_nil () { return isa("Nil"); }
772  boolean is_fun () { return isa("->"); }
773  boolean is_struct() { return isa("@{}"); }
774  boolean is_mem() { return isa("[]"); }
775  boolean is_err() { return isa("Err"); }
776 
777  T2 debug_find() {// Find, without the roll-up
778  if( !is_leaf() ) return this; // Shortcut
779  T2 u = _args[0];
780  if( u==null ) return this; // Shortcut
781  if( u.no_uf() ) return u; // Shortcut
782  // U-F fixup
783  while( u.is_leaf() && u._args[0]!=null ) u = u._args[0];
784  return u;
785  }
786 
787  // U-F find
788  T2 find() {
789  T2 u = debug_find();
790  if( u==this || u==_args[0] ) return u;
791  T2 v = this, v2;
792  while( v.is_leaf() && (v2=v._args[0])!=u ) { v._args[0]=u; v = v2; }
793  return u;
794  }
795  // U-F find on the args array
796  T2 args(int i) {
797  T2 u = _args[i];
798  T2 uu = u.find();
799  return u==uu ? uu : (_args[i]=uu);
800  }
801 
802  // U-F union; this becomes that; returns 'that'.
803  // No change if only testing, and reports progress.
804  boolean union(T2 that, Worklist work) {
805  assert no_uf(); // Cannot union twice
806  if( this==that ) return false;
807  if( work==null ) return true; // Report progress without changing
808  // Worklist: put updates on the worklist for revisiting
809  if( _deps != null ) {
810  work.addAll(_deps); // Re-Apply
811  // Merge update lists, for future unions
812  if( that._deps==null && that.is_leaf() ) that._deps = _deps;
813  else
814  for( Syntax dep : _deps ) that.push_update(dep);
815  _deps = null;
816  }
817  if( _args.length==0 ) _args = new T2[1];
818  _args[0] = that; // U-F update
819  if( _name.charAt(0)!='V' ) _name = "V"+_uid; // Flag as a leaf & unified
820  assert !no_uf();
821  return true;
822  }
823 
824  // Unify a struct with nil
825  boolean or0(T2 that, Worklist work) {
826  assert is_nil() && that.is_struct();
827  if( work==null ) return that._con==null; // Progress if moving from not-nil to nilable
828  if( that._con == Type.NIL ) return false;// Already nilable
829  _args = new T2[1]; // Room for U-F
830  that._con=Type.NIL;
831  return union(that,work);
832  }
833 
834  // -----------------
835  // Structural unification.
836  // Returns false if no-change, true for change.
837  // If work is null, does not actually change anything, just reports progress.
838  // If work and change, unifies 'this' into 'that' (changing both), and
839  // updates the worklist.
840  static private final HashMap<Long,T2> DUPS = new HashMap<>();
841  boolean unify( T2 that, Worklist work ) {
842  if( this==that ) return false;
843  assert DUPS.isEmpty();
844  boolean progress = _unify(that,work);
845  DUPS.clear();
846  return progress;
847  }
848 
849  // Structural unification, 'this' into 'that'. No change if just testing
850  // (work is null) and returns 'that' if progress. If updating, both 'this'
851  // and 'that' are the same afterwards.
852  private boolean _unify(T2 that, Worklist work) {
853  assert no_uf() && that.no_uf();
854  if( this==that ) return false;
855 
856  // two errs union in either order, so keep lower uid (actually should merge error strings)
857  if( is_err() && that.is_err() && _uid<that._uid ) return that.union(this,work);
858  if( is_err() ) return that.union(this,work);
859  if( that.is_err() ) return union(that,work);
860 
861  // two leafs union in either order, so keep lower uid
862  if( is_leaf() && that.is_leaf() && _uid<that._uid ) return that.union(this,work);
863  if( is_leaf() ) return union(that,work);
864  if( that.is_leaf() ) return that.union(this,work);
865  if( is_base() && that.is_base() ) return unify_base(that,work);
866  // Unify struct with nil
867  if( is_nil() && that.is_struct() ) return or0(that,work);
868  if( that.is_nil() && is_struct() ) return that.or0(this,work);
869 
870  // Cycle check
871  long luid = dbl_uid(that); // long-unique-id formed from this and that
872  T2 rez = DUPS.get(luid);
873  assert rez==null || rez==that;
874  if( rez!=null ) return false; // Been there, done that
875  DUPS.put(luid,that); // Close cycles
876 
877  if( work==null ) return true; // Here we definitely make progress; bail out early if just testing
878 
879  if( !Util.eq(_name,that._name) )
880  return union_err(that,work,"Cannot unify "+this+" and "+that);
881  assert _args!=that._args; // Not expecting to share _args and not 'this'
882  if( !is_struct() && !is_mem() && _args.length != that._args.length )
883  return union_err(that,work,"Cannot unify "+this+" and "+that);
884 
885  // Structural recursion unification.
886 
887  // Structs unify only on matching fields, and add missing fields.
888  if( is_struct() ) {
889  // Unification for structs is more complicated; args are aligned via
890  // field names and not by position.
891  for( int i=0; i<_ids.length; i++ ) { // For all fields in LHS
892  int idx = Util.find(that._ids,_ids[i]);
893  if( idx==-1 ) that.add_fld(_ids[i],args(i), work); // Extend 'that' with matching field from 'this'
894  else args(i)._unify(that.args(idx),work); // Unify matching field
895  that = that.find(); // Recursively, might have already rolled this up
896  }
897  if( _con!=null && that._con==null ) that._con=Type.NIL;
898  that._aliases = that._aliases.meet(this._aliases);
899  if( this==that ) return true; // Might have unioned this-into-that recursively, exit now with progress
900 
901  // Memory add missing fields
902  } else if( is_mem() ) {
903  for( int i=0; i<_args.length; i++ ) // For all fields in LHS
904  if( _args[i]!=null )
905  that.unify_rec(i,args(i),work);
906 
907  // Normal structural unification
908  } else {
909  for( int i=0; i<_args.length; i++ ) // For all fields in LHS
910  args(i)._unify(that.args(i),work);
911  }
912  if( find().is_err() && !that.find().is_err() ) return that.find().union(find(),work); // Preserve errors
913  return find().union(that,work);
914  }
915 
916  private void add_fld(String id, T2 fld, Worklist work) {
917  assert is_struct();
918  int len = _ids.length;
919  _ids = Arrays.copyOf( _ids,len+1);
920  _args = Arrays.copyOf(_args,len+1);
921  _ids [len] = id ;
922  _args[len] = fld;
923  work.addAll(_deps); //
924  }
925 
926  private long dbl_uid(T2 t) { return ((long)_uid<<32)|t._uid; }
927 
928  private boolean unify_base(T2 that, Worklist work) {
929  Type con = _con.meet(that._con);
930  if( con==that._con ) return false; // No progress
931  if( work==null ) return true;
932  that._con = con; // Yes progress, but no update if null work
933  _args = new T2[1]; // Room for a forwarding pointer
934  _con=null; // Flip from 'Base' to 'Leaf'
935  return union(that,work);
936  }
937  private boolean fresh_base(T2 that, Worklist work) {
938  Type con = _con.meet(that._con);
939  if( con==that._con ) return false; // No progress
940  if( work==null ) return true;
941  that._con = con; // Yes progress, but no update if null work
942  return true;
943  }
944  private boolean union_err(T2 that, Worklist work, String msg) {
945  union(that,work);
946  return that.union(make_err(msg),work);
947  }
948 
949  // -----------------
950  // Make a (lazy) fresh copy of 'this' and unify it with 'that'. This is
951  // the same as calling 'fresh' then 'unify', without the clone of 'this'.
952  // The Syntax is used when making the 'fresh' copy for the occurs_check;
953  // it is another version of the 'nongen' set.
954  // Returns progress.
955  // If work is null, we are testing only and make no changes.
956  static private final HashMap<T2,T2> VARS = new HashMap<>();
957  boolean fresh_unify(T2 that, VStack nongen, Worklist work) {
958  assert VARS.isEmpty() && DUPS.isEmpty();
959  int old = CNT;
960  boolean progress = _fresh_unify(that,nongen,work);
961  VARS.clear(); DUPS.clear();
962  if( work==null && old!=CNT && DEBUG_LEAKS )
963  throw unimpl("busted, made T2s but just testing");
964  return progress;
965  }
966 
967  // Outer recursive version, wraps a VARS check around other work
968  private boolean _fresh_unify(T2 that, VStack nongen, Worklist work) {
969  assert no_uf() && that.no_uf();
970  T2 prior = VARS.get(this);
971  if( prior!=null ) // Been there, done that
972  return prior.find()._unify(that,work); // Also 'prior' needs unification with 'that'
973  if( cycle_equals(that) ) return vput(that,false);
974 
975  if( that.is_err() ) return vput(that,false); // That is an error, ignore 'this' and no progress
976  if( this.is_err() ) return vput(that,_unify(that,work));
977 
978  // Attempting to pre-compute occurs_in, by computing 'is_fresh' in the
979  // Ident.hm() call does NOT work. The 'is_fresh' is for the top-layer
980  // only, not the internal layers. As soon as we structural recurse down
981  // a layer, 'is_fresh' does not correlate with an occurs_in check.
982  if( nongen_in(nongen) ) return vput(that,_unify(that,work)); // Famous 'occurs-check', switch to normal unify
983  if( this.is_leaf() ) return vput(that,false); // Lazy map LHS tvar to RHS
984  if( that.is_leaf() ) // RHS is a tvar; union with a deep copy of LHS
985  return work==null || vput(that,that.union(_fresh(nongen),work));
986  // Bases MEET cons in RHS
987  if( is_base() && that.is_base() ) return vput(that,fresh_base(that,work));
988  // Unify struct with nil
989  if( is_nil() && that.is_struct() ) return vput(that,or0(that,work));
990  if( that.is_nil() && is_struct() )
991  return work==null || vput(that,that.or0(_fresh(nongen),work));
992 
993  if( !Util.eq(_name,that._name) ||
994  (!is_struct() && _args.length != that._args.length) )
995  return work == null || vput(that,that._unify(make_err("Cannot unify "+this+" and "+that),work));
996 
997  // Structural recursion unification, lazy on LHS
998  vput(that,false); // Early set, to stop cycles
999  boolean progress = false;
1000  if( is_struct() )
1001  progress = _fresh_unify_struct(that,nongen,work);
1002  else {
1003  for( int i=0; i<_args.length; i++ ) {
1004  progress |= args(i)._fresh_unify(that.args(i),nongen,work);
1005  if( progress && work==null ) return true;
1006  }
1007  }
1008  return progress;
1009  }
1010 
1011  // Unification with structs must honor field names.
1012  private boolean _fresh_unify_struct(T2 that, VStack nongen, Worklist work) {
1013  assert is_struct() && that.is_struct();
1014  if( _con!=null && that._con==null ) {
1015  if( work==null ) return true; // Will progress
1016  that._con = Type.NIL; // Allow nil
1017  }
1018  boolean progress = false;
1019  for( int i=0; i<_args.length; i++ ) {
1020  int idx = Util.find(that._ids,_ids[i]);
1021  if( idx == -1 ) { // Missing field on RHS
1022  if( work==null ) return true; // Will definitely make progress
1023  progress = true;
1024  that.add_fld(_ids[i],args(i)._fresh(nongen), work);
1025  } else
1026  progress |= args(i)._fresh_unify(that.args(idx),nongen,work);
1027  if( progress && work==null ) return true;
1028  }
1029  return progress;
1030  }
1031 
1032  private boolean vput(T2 that, boolean progress) { VARS.put(this,that); return progress; }
1033 
1034  // Return a fresh copy of 'this'
1035  private T2 _fresh(VStack nongen) {
1036  assert no_uf();
1037  T2 rez = VARS.get(this);
1038  if( rez!=null ) return rez; // Been there, done that
1039 
1040  if( is_leaf() ) {
1041  // If occurs_in lexical scope, keep same variable, else make a new leaf
1042  T2 t = nongen_in(nongen) ? this : T2.make_leaf();
1043  VARS.put(this,t);
1044  return t;
1045  } else { // Structure is deep-replicated
1046  T2 t = copy();
1047  VARS.put(this,t); // Stop cyclic structure looping
1048  for( int i=0; i<_args.length; i++ )
1049  t._args[i] = args(i)._fresh(nongen);
1050  return t;
1051  }
1052  }
1053 
1054  // -----------------
1055  private static final VBitSet ODUPS = new VBitSet();
1056  boolean occurs_in(Syntax syn) {
1057  if( syn==null ) return false;
1058  if( is_base() ) return false;
1059  assert ODUPS.isEmpty();
1060  boolean found = _occurs_in(syn);
1061  ODUPS.clear();
1062  return found;
1063  }
1064  boolean occurs_in_type(T2 x) {
1065  assert ODUPS.isEmpty();
1066  boolean found = _occurs_in_type(x);
1067  ODUPS.clear();
1068  return found;
1069  }
1070  boolean _occurs_in(Syntax syn) {
1071  for( ; syn!=null; syn=syn._par )
1072  if( _occurs_in_type(syn.find()) )
1073  return true;
1074  return false;
1075  }
1076 
1077  boolean _occurs_in_type(T2 x) {
1078  assert no_uf() && x.no_uf();
1079  if( x==this ) return true;
1080  if( ODUPS.tset(x._uid) ) return false; // Been there, done that
1081  if( !x.is_leaf() )
1082  for( int i=0; i<x._args.length; i++ )
1083  if( _occurs_in_type(x.args(i)) )
1084  return true;
1085  return false;
1086  }
1087 
1088  boolean nongen_in(VStack syn) {
1089  if( syn==null ) return false;
1090  assert ODUPS.isEmpty();
1091  boolean found = _nongen_in(syn);
1092  ODUPS.clear();
1093  return found;
1094  }
1095  boolean _nongen_in(VStack nongen) {
1096  for( T2 t2 : nongen )
1097  if( _occurs_in_type(t2.find()) )
1098  return true;
1099  return false;
1100  }
1101 
1102  // -----------------
1103  // Test for structural equivalence, including cycles
1104  static private final HashMap<T2,T2> CDUPS = new HashMap<>();
1105  boolean cycle_equals(T2 t) {
1106  assert CDUPS.isEmpty();
1107  boolean rez = _cycle_equals(t);
1108  CDUPS.clear();
1109  return rez;
1110  }
1111  boolean _cycle_equals(T2 t) {
1112  assert no_uf() && t.no_uf();
1113  if( this==t ) return true;
1114  if( is_base() && t.is_base() )
1115  return _con==t._con; // Base-cases have to be completely identical
1116  if( !Util.eq(_name,t._name) || // Wrong type-var names
1117  _args.length != t._args.length ) // Mismatched sizes
1118  return false;
1119  if( _args==t._args ) return true;
1120  // Cycles stall the equal/unequal decision until we see a difference.
1121  T2 tc = CDUPS.get(this);
1122  if( tc!=null )
1123  return tc==t; // Cycle check; true if both cycling the same
1124  CDUPS.put(this,t);
1125  if( is_struct() ) // Struct equality honors field names without regard to order
1126  return _cycle_equals_struct(t);
1127  for( int i=0; i<_args.length; i++ )
1128  if( !args(i)._cycle_equals(t.args(i)) )
1129  return false;
1130  return true;
1131  }
1132 
1133  private boolean _cycle_equals_struct(T2 t) {
1134  assert is_struct() && t.is_struct();
1135  if( _con != t._con ) return false;
1136  for( int i=0; i<_args.length; i++ ) {
1137  int idx = Util.find(t._ids,_ids[i]);
1138  if( idx==-1 || !args(i)._cycle_equals(t.args(idx)) )
1139  return false;
1140  }
1141  return true;
1142  }
1143 
1144  // -----------------
1145  T2 getrec(int alias) {
1146  assert is_mem();
1147  if( alias >= _args.length ) return null;
1148  T2 str = args(alias);
1149  assert str==null || str.is_struct();
1150  return str;
1151  }
1152 
1153  // Unify 'str' at alias 'alias' in 'this' memory.
1154  boolean unify_rec(int alias, T2 str, Worklist work) {
1155  assert is_mem() && str.is_struct();
1156  while( alias >= _args.length )
1157  _args = Arrays.copyOf(_args,_args.length<<1);
1158  if( _args[alias] != null ) return args(alias).unify(str,work);
1159  if( work!=null ) _args[alias] = str;
1160  return true;
1161  }
1162 
1163  // -----------------
1164  // This is a T2 function that is the target of 'fresh', i.e., this function
1165  // might be fresh-unified with some other function. Push the application
1166  // down the function parts; if any changes the fresh-application may make
1167  // progress.
1168  static final VBitSet UPDATE_VISIT = new VBitSet();
1169  T2 push_update( Ary<Syntax> as ) { if( as != null ) for( Syntax a : as ) push_update(a); return this; }
1170  void push_update( Syntax a) { assert UPDATE_VISIT.isEmpty(); push_update_impl(a); UPDATE_VISIT.clear(); }
1171  private void push_update_impl(Syntax a) {
1172  assert no_uf();
1173  if( UPDATE_VISIT.tset(_uid) ) return;
1174  if( _deps==null ) _deps = new Ary<>(Syntax.class);
1175  if( _deps.find(a)==-1 ) _deps.push(a);
1176  for( int i=0; i<_args.length; i++ )
1177  if( _args[i]!=null )
1178  args(i).push_update_impl(a);
1179  }
1180 
1181  void add_deps_work( Worklist work ) { assert UPDATE_VISIT.isEmpty(); add_deps_work_impl(work); UPDATE_VISIT.clear(); }
1182  private void add_deps_work_impl( Worklist work ) {
1183  if( is_leaf() || _args.length==0 ) {
1184  work.addAll(_deps);
1185  } else {
1186  if( UPDATE_VISIT.tset(_uid) ) return;
1187  for( int i=0; i<_args.length; i++ )
1188  args(i).add_deps_work_impl(work);
1189  }
1190  }
1191 
1192  // -----------------
1193  // Glorious Printing
1194 
1195  // Look for dups, in a tree or even a forest (which Syntax.p() does)
1196  VBitSet get_dups(VBitSet dups) { return _get_dups(new VBitSet(),dups); }
1198  if( visit.tset(_uid) && no_uf() ) dups.set(_uid);
1199  else
1200  for( T2 t : _args )
1201  if( t!=null )
1202  t._get_dups(visit,dups);
1203  return dups;
1204  }
1205 
1206  // Fancy print for Debuggers - includes explicit U-F re-direction.
1207  // Does NOT roll-up U-F, has no side-effects.
1208  @Override public String toString() { return str(new SB(), new VBitSet(), get_dups(new VBitSet()) ).toString(); }
1209  SB str(SB sb, VBitSet visit, VBitSet dups) {
1210  if( is_err() ) return sb.p(_con.getstr());
1211  if( is_leaf() || is_base() ) {
1212  if( is_base() ) sb.p(_con instanceof TypeMemPtr ? "str" : _con.toString()); else sb.p(_name);
1213  return _args.length==0 || _args[0]==null ? sb : _args[0].str(sb.p(">>"), visit, dups);
1214  }
1215  boolean dup = dups.get(_uid);
1216  if( dup ) sb.p("$V").p(_uid);
1217  if( visit.tset(_uid) && dup ) return sb;
1218  if( dup ) sb.p(':');
1219 
1220  // Special printing for functions
1221  if( is_fun() ) {
1222  sb.p("{ ");
1223  for( int i=0; i<_args.length-1; i++ )
1224  str(sb,visit,_args[i],dups).p(" ");
1225  return str(sb.p("-> "),visit,_args[_args.length-1],dups).p(" }");
1226  }
1227 
1228  // Special printing for structures
1229  if( is_struct() ) {
1230  _aliases.str(sb.p('*')).p("@{");
1231  for( int i=0; i<_ids.length; i++ )
1232  str(sb.p(' ').p(_ids[i]).p(" = "),visit,_args[i],dups).p(',');
1233  sb.unchar().p("}");
1234  if( _con==Type.NIL ) sb.p('?');
1235  return sb;
1236  }
1237 
1238  // Special printing for memory
1239  if( is_mem() ) {
1240  sb.p("[ ");
1241  for( int i=0; i<_args.length; i++ )
1242  if( _args[i] != null )
1243  _args[i].str(sb.p(i).p(':'),visit,dups).p(", ");
1244  return sb.unchar(2).p("]");
1245  }
1246 
1247  // Generic structural T2
1248  sb.p("(").p(_name).p(" ");
1249  for( T2 t : _args ) str(sb,visit,t,dups).p(" ");
1250  return sb.unchar().p(")");
1251  }
1252  static private SB str(SB sb, VBitSet visit, T2 t, VBitSet dups) { return t==null ? sb.p("_") : t.str(sb,visit,dups); }
1253 
1254  // Same as toString but calls find(). Can thus side-effect & roll-up U-Fs, so not a toString
1255  public String p() { return p(get_dups(new VBitSet())); }
1256  private static int VCNT;
1257  private static final HashMap<T2,Integer> VNAMES = new HashMap<>();
1258  String p(VBitSet dups) { VCNT=0; VNAMES.clear(); return find()._p(new SB(), new VBitSet(), dups).toString(); }
1259  private SB _p(SB sb, VBitSet visit, VBitSet dups) {
1260  assert no_uf();
1261  if( is_err () ) return sb.p( _con.getstr() );
1262  if( is_base() ) return sb.p(_con instanceof TypeMemPtr ? "str" : _con.toString() );
1263  if( is_leaf() || dups.get(_uid) ) { // Leafs or Duplicates? Take some effort to pretty-print cycles
1264  Integer ii = VNAMES.get(this);
1265  if( ii==null ) VNAMES.put(this,ii=VCNT++);
1266  // 2nd and later visits use the short form
1267  boolean later = !is_leaf() && visit.tset(_uid);
1268  if( later ) sb.p('$');
1269  char c = (char)('A'+ii);
1270  if( c<'V' ) sb.p(c); else sb.p("V"+ii);
1271  if( is_leaf() || later ) return sb;
1272  // First visit prints the V._uid and the type
1273  sb.p(':');
1274  }
1275 
1276  // Special printing for functions: { arg -> body }
1277  if( is_fun() ) {
1278  sb.p("{ ");
1279  for( int i=0; i<_args.length-1; i++ )
1280  args(i)._p(sb,visit,dups).p(" ");
1281  return args(_args.length-1)._p(sb.p("-> "),visit,dups).p(" }");
1282  }
1283 
1284  // Special printing for structures: @{ fld0 = body, fld1 = body, ... }
1285  if( is_struct() ) {
1286  _aliases.str(sb.p('*')).p("@{");
1287  for( int i=0; i<_ids.length; i++ )
1288  args(i)._p(sb.p(' ').p(_ids[i]).p(" = "),visit,dups).p(',');
1289  sb.unchar().p("}");
1290  if( _con==Type.NIL ) sb.p('?');
1291  return sb;
1292  }
1293 
1294  // Special printing for memory
1295  if( is_mem() ) {
1296  sb.p("[ ");
1297  for( int i=0; i<_args.length; i++ )
1298  if( _args[i] != null )
1299  args(i)._p(sb.p(i).p(':'),visit,dups).p(", ");
1300  return sb.unchar(2).p("]");
1301  }
1302 
1303  // Generic structural T2: (fun arg0 arg1...)
1304  sb.p("(").p(_name).p(" ");
1305  for( int i=0; i<_args.length; i++ ) args(i)._p(sb,visit,dups).p(" ");
1306  return sb.unchar().p(")");
1307  }
1308 
1309  static void reset() { CNT=0; DUPS.clear(); VARS.clear(); ODUPS.clear(); CDUPS.clear(); UPDATE_VISIT.clear(); }
1310  }
1311 
1312 }
com.cliffc.aa.type.Bits.dual
B dual()
Definition: Bits.java:368
com.cliffc.aa.HM.HM8.Con._con
final Type _con
Definition: HM8.java:302
com.cliffc.aa.HM.HM8.skipWS
static byte skipWS()
Definition: HM8.java:178
com.cliffc.aa.HM.HM8.require
static< T > T require(char c, T t)
Definition: HM8.java:186
com.cliffc.aa.HM.HM8.T2.add_fld
void add_fld(String id, T2 fld, Worklist work)
Definition: HM8.java:916
com.cliffc.aa.HM.HM8.T2.union_err
boolean union_err(T2 that, Worklist work, String msg)
Definition: HM8.java:944
com.cliffc.aa.HM.HM8.id
static String id()
Definition: HM8.java:155
com.cliffc.aa.HM.HM8.VStack.Iter.next
T2 next()
Definition: HM8.java:234
com.cliffc.aa.HM.HM8.Con
Definition: HM8.java:301
com.cliffc.aa.HM.HM8.Struct.Struct
Struct(String[] ids, Syntax[] flds)
Definition: HM8.java:580
com.cliffc.aa.HM.HM8.T2.add_deps_work_impl
void add_deps_work_impl(Worklist work)
Definition: HM8.java:1182
com.cliffc.aa.HM.HM8.Field.lookup
T2 lookup(String name)
Definition: HM8.java:698
com.cliffc.aa.HM.HM8.Lambda._body
final Syntax _body
Definition: HM8.java:359
com.cliffc.aa.type.Bits.str
SB str(SB sb)
Definition: Bits.java:134
com.cliffc.aa.HM.HM8.T2
Definition: HM8.java:721
com.cliffc.aa.HM.HM8.Let._targ
T2 _targ
Definition: HM8.java:433
com.cliffc.aa.HM.HM8.Let.add_work
void add_work(Worklist work)
Definition: HM8.java:453
com.cliffc.aa.HM.HM8.T2._cycle_equals_struct
boolean _cycle_equals_struct(T2 t)
Definition: HM8.java:1133
com.cliffc.aa.HM.HM8.Syntax.hm
abstract boolean hm(Worklist work)
com.cliffc.aa.HM.HM8.Worklist
Definition: HM8.java:197
com.cliffc.aa.util.Ary.push
E push(E e)
Add element in amortized constant time.
Definition: Ary.java:58
com.cliffc.aa.HM.HM8.T2.CNT
static int CNT
Definition: HM8.java:722
com.cliffc.aa.HM.HM8.T2.add_deps_work
void add_deps_work(Worklist work)
Definition: HM8.java:1181
com.cliffc.aa.HM.HM8.Ident.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:324
com.cliffc.aa.HM.HM8.Apply
Definition: HM8.java:475
com.cliffc.aa.HM.HM8.Struct.p1
SB p1(SB sb)
Definition: HM8.java:590
com.cliffc.aa.util.Util.find
static int find(int[] es, int e)
Definition: Util.java:6
com.cliffc.aa.HM.HM8.T2.toString
String toString()
Definition: HM8.java:1208
com.cliffc.aa.HM.HM8.VStack.Iter._vstk
VStack _vstk
Definition: HM8.java:231
com.cliffc.aa.util.Util.eq
static boolean eq(String s0, String s1)
Definition: Util.java:16
com.cliffc.aa.HM.HM8.Lambda.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:420
com.cliffc.aa.HM.HM8.Let._arg0
final String _arg0
Definition: HM8.java:431
com.cliffc.aa.HM.HM8.T2.is_nil
boolean is_nil()
Definition: HM8.java:771
com.cliffc.aa.util.SB.ii
SB ii(int i)
Definition: SB.java:44
com.cliffc.aa.HM.HM8.T2.make_struct
static T2 make_struct(String[] ids, BitsAlias aliases, T2[] flds)
Definition: HM8.java:750
com.cliffc
com.cliffc.aa.HM.HM8.T2.is_fun
boolean is_fun()
Definition: HM8.java:772
com.cliffc.aa.HM.HM8.Field.hm
boolean hm(Worklist work)
Definition: HM8.java:677
com.cliffc.aa.type.Type.toString
final String toString()
Definition: Type.java:127
com.cliffc.aa.util.SB.di
SB di(int i)
Definition: SB.java:46
com.cliffc.aa.HM.HM8.parse
static Syntax parse(String s)
Definition: HM8.java:93
com.cliffc.aa.HM.HM8.Ident.Ident
Ident(String name)
Definition: HM8.java:321
com.cliffc.aa.HM.HM8.T2.is_mem
boolean is_mem()
Definition: HM8.java:774
com.cliffc.aa.HM.HM8.isAlpha0
static boolean isAlpha0(byte c)
Definition: HM8.java:184
com.cliffc.aa.HM.HM8.Lambda.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:377
com.cliffc.aa.HM.HM8.Field.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:704
com.cliffc.aa.HM.HM8.T2.prim
static T2 prim(String name, T2... args)
Definition: HM8.java:753
com.cliffc.aa.HM.HM8.Struct.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:648
com.cliffc.aa.HM.HM8.T2.args
T2 args(int i)
Definition: HM8.java:796
com.cliffc.aa.HM.HM8.Lambda
Definition: HM8.java:357
com.cliffc.aa.HM.HM8.T2.DUPS
static final HashMap< Long, T2 > DUPS
Definition: HM8.java:840
com.cliffc.aa.HM.HM8.T2._cycle_equals
boolean _cycle_equals(T2 t)
Definition: HM8.java:1111
com.cliffc.aa.util
Definition: AbstractEntry.java:1
com.cliffc.aa.HM.HM8.T2.push_update
T2 push_update(Ary< Syntax > as)
Definition: HM8.java:1169
com.cliffc.aa.HM.HM8.Syntax._par
Syntax _par
Definition: HM8.java:240
com.cliffc.aa.HM.HM8.Syntax
Definition: HM8.java:239
com.cliffc.aa.HM.HM8.T2.union
boolean union(T2 that, Worklist work)
Definition: HM8.java:804
com.cliffc.aa.type.TypeInt
Definition: TypeInt.java:9
com.cliffc.aa.HM.HM8.Syntax.toString
final String toString()
Definition: HM8.java:288
com.cliffc.aa.HM.HM8.VStack._par
final VStack _par
Definition: HM8.java:213
com.cliffc.aa.HM.HM8.T2.get_dups
VBitSet get_dups(VBitSet dups)
Definition: HM8.java:1196
com.cliffc.aa.HM.HM8.T2.VNAMES
static final HashMap< T2, Integer > VNAMES
Definition: HM8.java:1257
com.cliffc.aa.type.Type
an implementation of language AA
Definition: Type.java:94
com.cliffc.aa.HM.HM8.T2.T2
T2(@NotNull String name, Type con, String[] ids, BitsAlias aliases, T2 @NotNull ... args)
Definition: HM8.java:756
com.cliffc.aa.util.SB.clear
SB clear()
Definition: SB.java:61
com.cliffc.aa.type.TypeFlt
Definition: TypeFlt.java:9
com.cliffc.aa.HM.HM8.Con.str
SB str(SB sb)
Definition: HM8.java:304
com.cliffc.aa.util.Ary
Definition: Ary.java:11
com.cliffc.aa.HM.HM8.Struct._alias
final BitsAlias _alias
Definition: HM8.java:577
com.cliffc.aa.HM.HM8.Worklist._ary
final Ary< Syntax > _ary
Definition: HM8.java:199
com.cliffc.aa.HM.HM8.Con.Con
Con(Type con)
Definition: HM8.java:303
com.cliffc.aa.type.BitsAlias
Definition: BitsAlias.java:8
com.cliffc.aa.HM.HM8.reset
static void reset()
Definition: HM8.java:86
com.cliffc.aa.HM.HM8.Field._rec
final Syntax _rec
Definition: HM8.java:672
com.cliffc.aa.HM.HM8.X
static int X
Definition: HM8.java:90
com.cliffc.aa.HM.HM8.Ident.str
SB str(SB sb)
Definition: HM8.java:322
com.cliffc.aa.HM.HM8.Worklist.pop
Syntax pop()
Definition: HM8.java:203
com.cliffc.aa.HM.HM8.Ident.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:346
com.cliffc.aa.HM.HM8.toString
String toString()
Definition: HM8.java:92
com.cliffc.aa.HM.HM8.Struct._ids
final String[] _ids
Definition: HM8.java:578
com.cliffc.aa.type.TypeInt.con
static TypeInt con(long con)
Definition: TypeInt.java:37
com.cliffc.aa.HM.HM8.Con.hm
boolean hm(Worklist work)
Definition: HM8.java:307
com.cliffc.aa.HM.HM8.number
static Syntax number()
Definition: HM8.java:163
com.cliffc.aa.HM.HM8.T2._fresh_unify_struct
boolean _fresh_unify_struct(T2 that, VStack nongen, Worklist work)
Definition: HM8.java:1012
com.cliffc.aa.HM.HM8.T2.unify
boolean unify(T2 that, Worklist work)
Definition: HM8.java:841
com.cliffc.aa.HM.HM8.Struct.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:591
com.cliffc.aa.HM.HM8.Struct._flds
final Syntax[] _flds
Definition: HM8.java:579
com.cliffc.aa.HM.HM8.T2.nongen_in
boolean nongen_in(VStack syn)
Definition: HM8.java:1088
com.cliffc.aa.HM.HM8.T2.fresh_unify
boolean fresh_unify(T2 that, VStack nongen, Worklist work)
Definition: HM8.java:957
com.cliffc.aa.HM.HM8.Lambda.targ
T2 targ(int i)
Definition: HM8.java:378
com.cliffc.aa.type.BitsAlias.new_alias
static int new_alias(int par)
Definition: BitsAlias.java:75
com.cliffc.aa.type.Type.meet
final Type meet(Type t)
Definition: Type.java:412
com.cliffc.aa.AA.unimpl
static RuntimeException unimpl()
Definition: AA.java:10
com.cliffc.aa.HM.HM8.T2._args
T2[] _args
Definition: HM8.java:731
com.cliffc.aa.HM.HM8.Struct.hm
boolean hm(Worklist work)
Definition: HM8.java:596
com.cliffc.aa.HM.HM8.T2._occurs_in_type
boolean _occurs_in_type(T2 x)
Definition: HM8.java:1077
com.cliffc.aa.HM.HM8.T2._occurs_in
boolean _occurs_in(Syntax syn)
Definition: HM8.java:1070
com.cliffc.aa.HM.HM8.Worklist.addAll
void addAll(Ary<? extends Syntax > ss)
Definition: HM8.java:206
com.cliffc.aa.HM.HM8.Let.lookup
T2 lookup(String name)
Definition: HM8.java:449
com.cliffc.aa.HM.HM8.Struct.lookup
T2 lookup(String name)
Definition: HM8.java:643
com.cliffc.aa.util.SB.unchar
SB unchar()
Definition: SB.java:58
Iterable
com.cliffc.aa.type.Type.ALL
static final Type ALL
Definition: Type.java:324
com.cliffc.aa.HM.HM8.VStack.Iter.hasNext
boolean hasNext()
Definition: HM8.java:233
com.cliffc.aa.HM.HM8.T2.make_mem
static T2 make_mem()
Definition: HM8.java:751
com.cliffc.aa.HM.HM8.Lambda._targs
T2[] _targs
Definition: HM8.java:360
com.cliffc.aa.type.BitsAlias.REC
static final int REC
Definition: BitsAlias.java:25
com.cliffc.aa.HM.HM8.Apply.add_work
void add_work(Worklist work)
Definition: HM8.java:550
com.cliffc.aa.HM.HM8.Apply._args
final Syntax[] _args
Definition: HM8.java:477
com.cliffc.aa.util.Ary.asAry
E[] asAry()
Definition: Ary.java:172
com.cliffc.aa.HM.HM8
Definition: HM8.java:24
com.cliffc.aa.util.VBitSet.tset
boolean tset(int idx)
Definition: VBitSet.java:7
com.cliffc.aa.type.TypeInt.INT64
static final TypeInt INT64
Definition: TypeInt.java:39
com.cliffc.aa.HM.HM8.Let.targ
T2 targ()
Definition: HM8.java:438
com.cliffc.aa.type.TypeFlt.con
static Type con(double con)
Definition: TypeFlt.java:36
com.cliffc.aa.HM.HM8.Syntax._nongen
VStack _nongen
Definition: HM8.java:241
com.cliffc.aa.HM.HM8.VStack.toString
String toString()
Definition: HM8.java:216
com.cliffc.aa.HM.HM8.term
static Syntax term()
Definition: HM8.java:100
com.cliffc.aa.HM.HM8.T2.debug_find
T2 debug_find()
Definition: HM8.java:777
com.cliffc.aa.HM.HM8.T2.reset
static void reset()
Definition: HM8.java:1309
com.cliffc.aa.HM.HM8.Let.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:459
com.cliffc.aa.HM.HM8.Apply.more_work
boolean more_work(Worklist work)
Definition: HM8.java:563
com.cliffc.aa.HM.HM8.T2.UPDATE_VISIT
static final VBitSet UPDATE_VISIT
Definition: HM8.java:1168
com.cliffc.aa.HM.HM8.VStack.iterator
Iterator< T2 > iterator()
Definition: HM8.java:229
com.cliffc.aa.HM.HM8.T2._fresh
T2 _fresh(VStack nongen)
Definition: HM8.java:1035
com.cliffc.aa.HM.HM8.T2.make_nil
static T2 make_nil()
Definition: HM8.java:749
com.cliffc.aa.HM.HM8.T2.is_leaf
boolean is_leaf()
Definition: HM8.java:767
com.cliffc.aa.HM.HM8.Syntax._pre
T2 _pre
Definition: HM8.java:242
com.cliffc.aa.HM.HM8.Lambda._args
final String[] _args
Definition: HM8.java:358
com.cliffc.aa.type.BitsAlias.RECORD_BITS
static BitsAlias RECORD_BITS
Definition: BitsAlias.java:26
com.cliffc.aa.HM.HM8.Syntax.lookup
abstract T2 lookup(String name)
com.cliffc.aa.HM.HM8.Worklist._work
final HashSet< Syntax > _work
Definition: HM8.java:200
com.cliffc.aa.HM.HM8.T2._aliases
BitsAlias _aliases
Definition: HM8.java:740
com.cliffc.aa.HM.HM8.VStack
Definition: HM8.java:212
com.cliffc.aa.HM.HM8.Apply.p1
SB p1(SB sb)
Definition: HM8.java:485
com.cliffc.aa.HM.HM8.T2.getrec
T2 getrec(int alias)
Definition: HM8.java:1145
com.cliffc.aa.HM.HM8.Field.p1
SB p1(SB sb)
Definition: HM8.java:675
com.cliffc.aa.HM.HM8.Syntax._post
T2 _post
Definition: HM8.java:244
com.cliffc.aa.HM.HM8.DEBUG_LEAKS
static boolean DEBUG_LEAKS
Definition: HM8.java:26
com.cliffc.aa.HM.HM8.T2.CDUPS
static final HashMap< T2, T2 > CDUPS
Definition: HM8.java:1104
com.cliffc.aa.util.Util
Definition: Util.java:5
com.cliffc.aa.HM.HM8.T2.vput
boolean vput(T2 that, boolean progress)
Definition: HM8.java:1032
com.cliffc.aa.HM.HM8.Let.Let
Let(String arg0, Syntax def, Syntax body)
Definition: HM8.java:434
com.cliffc.aa.HM.HM8.T2.VARS
static final HashMap< T2, T2 > VARS
Definition: HM8.java:956
com.cliffc.aa.HM.HM8.Let._body
final Syntax _body
Definition: HM8.java:432
com.cliffc.aa.HM.HM8.Apply._fun
final Syntax _fun
Definition: HM8.java:476
com.cliffc.aa.HM.HM8.isAlpha1
static boolean isAlpha1(byte c)
Definition: HM8.java:185
com.cliffc.aa.HM.HM8.Syntax.post
T2 post()
Definition: HM8.java:254
com.cliffc.aa.HM.HM8.require
static void require(String s)
Definition: HM8.java:187
com.cliffc.aa.HM.HM8.T2.str
SB str(SB sb, VBitSet visit, VBitSet dups)
Definition: HM8.java:1209
com.cliffc.aa.HM.HM8.Con.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:306
com.cliffc.aa.HM.HM8.Apply.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:486
com.cliffc.aa.HM.HM8.T2.make_leaf
static T2 make_leaf()
Definition: HM8.java:747
com.cliffc.aa.HM.HM8.T2.dbl_uid
long dbl_uid(T2 t)
Definition: HM8.java:926
com.cliffc.aa.HM.HM8.Syntax.debug_find
T2 debug_find()
Definition: HM8.java:249
com.cliffc.aa.type.TypeStr.con
static TypeStr con(String con)
Definition: TypeStr.java:42
com.cliffc.aa.HM.HM8.Apply.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:562
com.cliffc.aa.HM.HM8.T2.str
static SB str(SB sb, VBitSet visit, T2 t, VBitSet dups)
Definition: HM8.java:1252
com.cliffc.aa.HM.HM8.Syntax.pre
T2 pre()
Definition: HM8.java:250
com.cliffc.aa.HM.HM8.Let.str
SB str(SB sb)
Definition: HM8.java:435
com.cliffc.aa.HM.HM8.T2.copy
T2 copy()
Definition: HM8.java:754
com.cliffc.aa.HM.HM8.T2.unify_base
boolean unify_base(T2 that, Worklist work)
Definition: HM8.java:928
com.cliffc.aa.HM.HM8.T2.no_uf
boolean no_uf()
Definition: HM8.java:768
com.cliffc.aa.HM.HM8.Lambda.p1
SB p1(SB sb)
Definition: HM8.java:372
com.cliffc.aa.HM.HM8.T2.push_update
void push_update(Syntax a)
Definition: HM8.java:1170
com.cliffc.aa.HM.HM8.T2._con
Type _con
Definition: HM8.java:734
com.cliffc.aa.HM.HM8.Syntax.more_work
abstract boolean more_work(Worklist work)
com.cliffc.aa.HM.HM8.Worklist.toString
String toString()
Definition: HM8.java:207
com.cliffc.aa.HM.HM8.T2.make_err
static T2 make_err(String s)
Definition: HM8.java:752
com.cliffc.aa.type.TypeStr
Definition: TypeStr.java:14
com.cliffc.aa.HM.HM8.Ident.more_work
boolean more_work(Worklist work)
Definition: HM8.java:354
com.cliffc.aa.HM.HM8.Field._id
final String _id
Definition: HM8.java:671
com.cliffc.aa.HM.HM8.T2.p
String p()
Definition: HM8.java:1255
com.cliffc.aa.type.Bits.getbit
int getbit()
Definition: Bits.java:202
com.cliffc.aa.HM.HM8.Worklist.len
int len()
Definition: HM8.java:201
com.cliffc.aa.HM.HM8.T2._p
SB _p(SB sb, VBitSet visit, VBitSet dups)
Definition: HM8.java:1259
com.cliffc.aa.HM.HM8.Ident.hm
boolean hm(Worklist work)
Definition: HM8.java:325
com.cliffc.aa.HM.HM8.Ident.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:353
com.cliffc.aa.HM.HM8.VStack.Iter.Iter
Iter()
Definition: HM8.java:232
com.cliffc.aa.HM.HM8.Let.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:437
com.cliffc.aa.util.VBitSet
Definition: VBitSet.java:5
com.cliffc.aa.HM.HM8.Struct.more_work
boolean more_work(Worklist work)
Definition: HM8.java:660
com.cliffc.aa.HM.HM8.Lambda.str
SB str(SB sb)
Definition: HM8.java:367
com.cliffc.aa.type.BitsAlias.init0
static void init0()
Definition: BitsAlias.java:63
NotNull
com.cliffc.aa.util.SB
Tight/tiny StringBuilder wrapper.
Definition: SB.java:8
com.cliffc.aa.type.Type.NIL
static final Type NIL
Definition: Type.java:332
com.cliffc.aa.HM.HM8.VStack.VStack
VStack(VStack par, T2 nongen)
Definition: HM8.java:215
com.cliffc.aa.HM.HM8.Field
Definition: HM8.java:670
com.cliffc.aa.HM.HM8.Syntax.p2
abstract SB p2(SB sb, VBitSet dups)
com.cliffc.aa.HM.HM8.T2.p
String p(VBitSet dups)
Definition: HM8.java:1258
com.cliffc.aa.HM.HM8.T2.is_err
boolean is_err()
Definition: HM8.java:775
com.cliffc.aa.HM.HM8.Field.more_work
boolean more_work(Worklist work)
Definition: HM8.java:709
com.cliffc.aa.AA
an implementation of language AA
Definition: AA.java:9
com.cliffc.aa.HM.HM8.Worklist._cnt
int _cnt
Definition: HM8.java:198
com.cliffc.aa.HM.HM8.Syntax.p1
abstract SB p1(SB sb)
com.cliffc.aa.HM.HM8.T2.is_struct
boolean is_struct()
Definition: HM8.java:773
com.cliffc.aa.HM.HM8.Let
Definition: HM8.java:430
com.cliffc.aa.HM.HM8.Syntax.add_work
abstract void add_work(Worklist work)
com.cliffc.aa.HM.HM8.isWS
static boolean isWS(byte c)
Definition: HM8.java:182
com.cliffc.aa.HM.HM8.Syntax.prep_tree_impl
final void prep_tree_impl(Syntax par, VStack nongen, Worklist work, T2 t)
Definition: HM8.java:267
com.cliffc.aa.HM.HM8.Struct.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:659
com.cliffc.aa.HM.HM8.T2.isa
boolean isa(String name)
Definition: HM8.java:769
com.cliffc.aa.HM.HM8.T2.unify_rec
boolean unify_rec(int alias, T2 str, Worklist work)
Definition: HM8.java:1154
com.cliffc.aa.HM.HM8.T2.VCNT
static int VCNT
Definition: HM8.java:1256
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.util.SB.nl
SB nl()
Definition: SB.java:48
com.cliffc.aa.HM.HM8.Syntax._t
T2 _t
Definition: HM8.java:243
com.cliffc.aa.type.BitsAlias.make0
static BitsAlias make0(int bit)
Definition: BitsAlias.java:72
com.cliffc.aa.HM.HM8.Con.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:315
com.cliffc.aa.HM.HM8.Con.add_work
void add_work(Worklist work)
Definition: HM8.java:309
com.cliffc.aa.HM.HM8.T2.fresh_base
boolean fresh_base(T2 that, Worklist work)
Definition: HM8.java:937
com.cliffc.aa.HM.HM8.T2.make_fun
static T2 make_fun(T2... args)
Definition: HM8.java:746
com.cliffc.aa.HM.HM8.T2.push_update_impl
void push_update_impl(Syntax a)
Definition: HM8.java:1171
com.cliffc.aa.HM.HM8.Let._def
final Syntax _def
Definition: HM8.java:432
com.cliffc.aa.HM.HM8.Apply.hm
boolean hm(Worklist work)
Definition: HM8.java:494
com.cliffc.aa.HM.HM8.hm
static Syntax hm(String sprog)
Definition: HM8.java:29
com.cliffc.aa.HM.HM8.Ident
Definition: HM8.java:319
com.cliffc.aa.util.SB.p
SB p(String s)
Definition: SB.java:13
com.cliffc.aa.HM.HM8.Apply.is_if_nil
T2 is_if_nil()
Definition: HM8.java:570
com.cliffc.aa.HM.HM8.ID
static final SB ID
Definition: HM8.java:154
com.cliffc.aa.HM.HM8.Syntax.p0
final SB p0(SB sb, VBitSet dups)
Definition: HM8.java:292
com.cliffc.aa.HM.HM8.isDigit
static boolean isDigit(byte c)
Definition: HM8.java:183
com.cliffc.aa.HM.HM8.Field.p2
SB p2(SB sb, VBitSet dups)
Definition: HM8.java:676
com.cliffc.aa.HM.HM8.VStack.Iter
Definition: HM8.java:230
com.cliffc.aa.HM.HM8.Syntax.prep_tree
abstract int prep_tree(Syntax par, VStack nongen, Worklist work)
com.cliffc.aa.HM.HM8.Field.add_work
void add_work(Worklist work)
Definition: HM8.java:699
com.cliffc.aa.HM.HM8.T2._get_dups
VBitSet _get_dups(VBitSet visit, VBitSet dups)
Definition: HM8.java:1197
com.cliffc.aa.HM.HM8.T2._unify
boolean _unify(T2 that, Worklist work)
Definition: HM8.java:852
com.cliffc.aa.HM.HM8.Con.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:310
com.cliffc.aa.HM.HM8.Con.p1
SB p1(SB sb)
Definition: HM8.java:305
com.cliffc.aa.HM.HM8.Ident.add_work
void add_work(Worklist work)
Definition: HM8.java:338
com.cliffc.aa.HM.HM8.T2.make_base
static T2 make_base(Type con)
Definition: HM8.java:748
com.cliffc.aa.HM.HM8.Let.hm
boolean hm(Worklist work)
Definition: HM8.java:439
com.cliffc.aa.HM.HM8.Syntax.str
abstract SB str(SB sb)
com.cliffc.aa.HM.HM8.T2._deps
Ary< Syntax > _deps
Definition: HM8.java:743
com.cliffc.aa.HM.HM8.Lambda.more_work
boolean more_work(Worklist work)
Definition: HM8.java:424
com.cliffc.aa.HM.HM8.T2._name
String _name
Definition: HM8.java:728
com.cliffc.aa.HM.HM8.VStack._nongen
final T2 _nongen
Definition: HM8.java:214
com.cliffc.aa.HM.HM8.Syntax.find
T2 find()
Definition: HM8.java:245
com.cliffc.aa.HM.HM8.Worklist.push
void push(Syntax s)
Definition: HM8.java:202
com.cliffc.aa.HM.HM8.Syntax.prep_lookup_deps
abstract void prep_lookup_deps(Ident id)
com.cliffc.aa.HM.HM8.T2.ODUPS
static final VBitSet ODUPS
Definition: HM8.java:1055
com.cliffc.aa.HM.HM8.Ident._name
final String _name
Definition: HM8.java:320
com.cliffc.aa.HM.HM8.Ident.p1
SB p1(SB sb)
Definition: HM8.java:323
com.cliffc.aa.util.SB.i
SB i(int d)
Definition: SB.java:38
com.cliffc.aa.HM.HM8.Lambda.Lambda
Lambda(Syntax body, String... args)
Definition: HM8.java:361
com.cliffc.aa.HM.HM8.T2.find
T2 find()
Definition: HM8.java:788
com.cliffc.aa.HM.HM8.T2._ids
String[] _ids
Definition: HM8.java:737
com.cliffc.aa.HM.HM8.string
static Syntax string()
Definition: HM8.java:173
com.cliffc.aa.HM.HM8.Lambda.hm
boolean hm(Worklist work)
Definition: HM8.java:379
com.cliffc.aa.type.TypeMemPtr.STRPTR
static final TypeMemPtr STRPTR
Definition: TypeMemPtr.java:97
com.cliffc.aa.HM.HM8.Field.str
SB str(SB sb)
Definition: HM8.java:674
com.cliffc.aa.HM.HM8.PRIMS
static final HashMap< String, T2 > PRIMS
Definition: HM8.java:25
com.cliffc.aa.HM.HM8.T2.is_base
boolean is_base()
Definition: HM8.java:770
com.cliffc.aa.type.Bits.meet
B meet(final B bs)
Definition: Bits.java:298
com.cliffc.aa.HM.HM8.Worklist.has
boolean has(Syntax s)
Definition: HM8.java:205
com.cliffc.aa.HM.HM8.Let.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:466
com.cliffc.aa.HM.HM8.Field.Field
Field(String id, Syntax str)
Definition: HM8.java:673
com.cliffc.aa.HM.HM8.Lambda.lookup
T2 lookup(String name)
Definition: HM8.java:402
com.cliffc.aa.HM.HM8.T2.or0
boolean or0(T2 that, Worklist work)
Definition: HM8.java:825
com.cliffc.aa.HM.HM8.Con.more_work
boolean more_work(Worklist work)
Definition: HM8.java:316
com.cliffc.aa.HM.HM8.Syntax.p
String p()
Definition: HM8.java:291
com.cliffc.aa.HM.HM8.T2.occurs_in
boolean occurs_in(Syntax syn)
Definition: HM8.java:1056
com.cliffc.aa.HM.HM8.Con.lookup
T2 lookup(String name)
Definition: HM8.java:308
com
com.cliffc.aa.HM.HM8.Lambda.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:413
com.cliffc.aa.HM.HM8.Let.more_work
boolean more_work(Worklist work)
Definition: HM8.java:469
com.cliffc.aa.HM.HM8.Struct.str
SB str(SB sb)
Definition: HM8.java:581
com.cliffc.aa.HM.HM8.Ident.lookup
T2 lookup(String name)
Definition: HM8.java:337
com.cliffc.aa.HM.HM8.T2._fresh_unify
boolean _fresh_unify(T2 that, VStack nongen, Worklist work)
Definition: HM8.java:968
com.cliffc.aa.HM.HM8.Syntax.more_work_impl
final boolean more_work_impl(Worklist work)
Definition: HM8.java:283
com.cliffc.aa.HM.HM8.Apply.str
SB str(SB sb)
Definition: HM8.java:479
com.cliffc.aa.HM.HM8.Field.prep_lookup_deps
void prep_lookup_deps(Ident id)
Definition: HM8.java:708
com.cliffc.aa.HM.HM8.T2.occurs_in_type
boolean occurs_in_type(T2 x)
Definition: HM8.java:1064
com.cliffc.aa.HM.HM8.Struct
Definition: HM8.java:576
com.cliffc.aa.type.Type.getstr
String getstr()
Definition: Type.java:806
com.cliffc.aa.type.TypeInt.BOOL
static final TypeInt BOOL
Definition: TypeInt.java:43
com.cliffc.aa.HM.HM8.Lambda.add_work
void add_work(Worklist work)
Definition: HM8.java:407
com.cliffc.aa.util.SB.toString
String toString()
Definition: SB.java:62
com.cliffc.aa.HM.HM8.T2._nongen_in
boolean _nongen_in(VStack nongen)
Definition: HM8.java:1095
com.cliffc.aa.HM.HM8.Apply.Apply
Apply(Syntax fun, Syntax... args)
Definition: HM8.java:478
com.cliffc.aa.type
Definition: Bits.java:1
com.cliffc.aa.HM.HM8.VStack.str
SB str(SB sb, VBitSet dups)
Definition: HM8.java:224
com.cliffc.aa.type.TypeMemPtr
Definition: TypeMemPtr.java:14
com.cliffc.aa.type.TypeFlt.FLT64
static final TypeFlt FLT64
Definition: TypeFlt.java:38
com.cliffc.aa.HM.HM8.Apply.prep_tree
int prep_tree(Syntax par, VStack nongen, Worklist work)
Definition: HM8.java:554
com.cliffc.aa.HM.HM8.Apply.lookup
T2 lookup(String name)
Definition: HM8.java:549
com.cliffc.aa.type.BitsAlias.reset_to_init0
static void reset_to_init0()
Definition: BitsAlias.java:64
com.cliffc.aa.HM.HM8.BUF
static byte[] BUF
Definition: HM8.java:91
com.cliffc.aa.HM.HM8.Let.p1
SB p1(SB sb)
Definition: HM8.java:436
com.cliffc.aa.HM.HM8.T2._uid
final int _uid
Definition: HM8.java:723
com.cliffc.aa.HM.HM8.Struct.add_work
void add_work(Worklist work)
Definition: HM8.java:644
com.cliffc.aa.HM.HM8.T2.cycle_equals
boolean cycle_equals(T2 t)
Definition: HM8.java:1105