def clos(state, node): """closure nodes""" # we extend given env type, so that subsequent unifications will # be reflected to us (when unifying different branches, then # sealing) with state.current(node.env): env_type = expr(state, node.env) assert type(env_type) in row.types gen_type = closure.env_gen(env_type, state.depth) tool.debug("gen_type:", gen_type.show()) state.pure(gen_type) def constraint(args_type): state.unify(gen_type, args_type[0]) # we need to preconstrain env type, because it may contain # functions and we need to know whether they are regular functions # or closures before calling them with state.current(node.code): assert type(node.code) is ast.Abs code_type = abs(state, node.code, constraint) state.pure(code_type) return closure.clos(code_type, gen_type)
def find_instance(self, mono): '''find typeclass instance matching mono''' tool.debug('finding instance of:', self.name, mono.show()) # print('finding instance of:', self.name, 'for:', mono.show()) t = type(mono) matches = [] for scheme, instance in self.instances.items(): # TODO what about depth ? fresh = hm.instantiate( scheme ) try: # note: we unify in a fresh union_find hm.unify(tool.UnionFind(), fresh, mono) matches.append( (scheme, instance) ) except error.Type: pass if not matches: raise error.Type('typeclass {0} has no instance for type {1}' .format( self.name, mono.show() )) if len(matches) > 1: raise error.Type('ambiguous {0} instances for {1}'.format(self.name, mono.show())) return matches[0]
def row_gen(state, node): # this will row-generalize type for node node_type = expr(state, node.expr) assert type(node_type) in row.types, "closure env should be a record: {0}".format(node_type.show()) # copy tuple, then add a fresh row type variable var = row.Var(state.depth) if type(node_type) is row.Empty: gen_type = var else: gen_type = row.record(*tuple(iter(node_type))) gen_type.set_terminator(var) tool.debug("gen_type:", gen_type.show()) return gen_type
def find_overload(self, identifier, mono): tool.debug('finding overload for:', identifier, ':', mono.show()) proto = self.definition[identifier] uf = tool.UnionFind() fresh = hm.instantiate(hm.generalize(proto)) vars = fresh.variables() assert len(vars) == 1 hm.unify(uf, fresh, mono) a = next(iter(vars)) t = uf.find( a ) scheme, instance = self.find_instance(t) return instance[identifier]
def coercion(state, node): """function/closure coercion""" node_type = expr(state, node.expr).nice(state.uf) assert type(node_type) is App, "cannot coerce to function type: {0}".format(node_type.show()) if node_type.func is func: return node_type if node_type.func is closure.clos: # seal env types env_type = node_type.args[1] # print('env_type:', env_type.show()) # print('variables:', env_type.variables()) if env_type.variables(): state.unify(env_type.var(), row.empty) code_type = node_type.args[0] tool.debug("after sealing:") tool.debug("env:", env_type.nice(state.uf).show()) tool.debug("code:", code_type.nice(state.uf).show()) # return partial application of the closure code to env res = code_type.args[1] # nullary closures: if not res.is_func_type(): return unit >> res return res assert False, "cannot coerce to function type: {0}".format(node_type.show())
def unify(uf, a, b): """unify types ta and tb""" a = uf.find(a) b = uf.find(b) # TODO introduce kinds ? ta = type(a) tb = type(b) with tool.indentation(): if tool.DEBUG: na, nb = a.nice(uf), b.nice(uf) sa, sb = show(na, nb) if na.variables() or nb.variables(): tool.debug("unify:", sa) tool.debug("with:", sb) if ta is App and tb is App and a.func == b.func: for ai, bi in zip(a.args, b.args): unify(uf, ai, bi) elif ta in row.types and tb in row.types: row.unify(uf, a, b) elif ta is typeclass.Var or tb is typeclass.Var: typeclass.unify(uf, a, b) elif ta is Var or tb is Var: var = a if ta is Var else b other = b if ta is Var else a # print('unifying:', ta, tb) # TODO what if we auto-unify ? is this legal ? # assert var is not other if type(other) is App: # TODO delay occurs_check? occurs_check(var, other) if type(other) is Var and var.depth < other.depth: var, other = other, var # TODO should we nice before linking ? uf.link(var, other) if tool.DEBUG and type(other) is Var: with tool.indentation(): tool.debug("repr:", sa if a is other else sb) elif a != b: sa, sb = show(a, b, 0, True) raise error.Type("""can not unify types {0} and {1}""".format(sa, sb))
out += ' : ' + str(poly) ts.cleanup() if not args.codegen: print(out) continue with tool.debug_scope('closure conversion'): # closure conversion node = closure.toplevel( closure.State(), node) # typecheck closure conversion with tool.debug_scope('typecheck closure conversion'): poly = hm.toplevel(cc, node ) tool.debug('closure conversion type:', poly) with tool.debug_scope("codegen"): code = codegen.toplevel(cs, node) if code and type(node) in ast.expression_types: code = codegen.print_expr(cs, poly.body, code, out) cc.cleanup() if code: with open('debug', 'w') as file: print('file', 'lli', file = file) print('run',
def unify(uf, a, b): """unify row types ra and rb""" a = uf.find(a) b = uf.find(b) ta = type(a) tb = type(b) assert ta in types and tb in types # print( ra, rb) if ta is Extension and tb is Extension: if a.label == b.label: # unify heads hm.unify(uf, a.mono, b.mono) # unify tails unify(uf, a.tail, b.tail) else: try: # try pulling b's head in a tool.debug("pulling", b.label) pa = a.pull(b.label) unify(uf, pa, b) # it worked: remember pa is originially a uf.link(pa, a) except PullError: try: # try pulling a's head in b tool.debug("pulling", a.label) pb = b.pull(a.label) unify(uf, a, pb) # it worked: remember pa is originially b uf.link(pb, b) except PullError: tool.debug("union") # none of it worked: neither heads is present in # other type. try to unify both to record union # unify a's tail var with a fresh copy of b try: unify(uf, a.var(), b.fresh()) unify(uf, b.var(), a.fresh()) except FreshError: sa, sb = hm.show(a, b) raise error.Type("can not unify row type {0} with {1}".format(sa, sb)) elif ta is Var or tb is Var: var = a if ta is Var else b other = a if tb is Var else b uf.link(var, other) # tool.debug('repr:', other.show()) elif a != b: raise error.Type("can not unify row type {0} with {1}".format(a.show(), b.show())) else: assert ta is Empty and tb is Empty