def closing_over(self, t, closed, body): # NOTE: Like the Generalizing constraint, we're implicitly # assuming that due to constraint ordering the body # referenced here has already been solved. fntype = self.context.instantiate(resolve_type(body, self.solution)) if not isinstance(fntype, T.Fn): raise InferenceError, "closure must be over functional types" # Get the list of argument types from the Fn type innertypes = fntype.input_types() # Partition the inner argument types into the outer types # exported to the world and those corresponding to the closed # arguments outertypes, closedtypes = innertypes[:-len(closed)], \ innertypes[-len(closed):] for v, t2 in zip(closed, closedtypes): if self.verbose: print "\tt1 =", v.type print "\tt2 =", t2 t1 = resolve(v.type, self.solution) t1 = self.context.instantiate(t1) if self.verbose: print "\tresolve(t1) =", t1 print "\tresolve(t2) =", resolve_type(t2, self.solution) self.unify_monotypes(t1, t2) self.unify_monotypes(t, T.Fn(outertypes, fntype.result_type()))
def _Apply(self, ast): for c in self.visit_children(ast): yield c fntype = ast.function().type argtypes = [x.type for x in ast.arguments()] yield Equality(fntype, T.Fn(argtypes, ast.type), ast)
def _Procedure(self, ast): con = self.context # Create a new type variable for the return type of the procedure restype = con.fresh_typevar() restype.source = None # Get the names and type variables for the formal parameters argnames = [arg.id for arg in flatten(ast.formals())] argtypes = [arg.type for arg in flatten(ast.formals())] # Make the definition of this function visible within its body # to allow for recursive calls con.typings[ast.name().id] = ast.name().type con.begin_scope() # Make the formals visible con.typings.update(dict(zip(argnames, argtypes))) prior_monomorphs = con.monomorphs con.monomorphs = prior_monomorphs | set(argtypes) argtypeit = iter(argtypes) # Construct the formals types def make_type(formal): if hasattr(formal, '__iter__'): return T.Tuple(*[make_type(x) for x in iter(formal)]) else: return argtypeit.next() formals_types = make_type(ast.formals()) # XXX This makes the restriction that recursive invocations of F # in the body of F must have the same type signature. Probably # not strictly necessary, but allowing the more general case # might prove problematic, especially in tail recursive cases. # For now, we will forbid this. con.monomorphs.add(ast.name().type) # Produce all constraints for arguments # Tuple arguments, for example, will produce constraints for a in ast.formals(): for c in self.visit(a): yield c # Produce all the constraints for the body for c in self.visit_block(ast, restype, ast.body()): yield c con.monomorphs = prior_monomorphs M = set(self.context.monomorphs) yield Generalizing(ast.name().type, T.Fn(formals_types, restype), M, ast) con.end_scope()
def _Lambda(self, ast): restype = ast.parameters[0].type argnames = [arg.id for arg in ast.variables] argtypes = [arg.type for arg in ast.variables] con = self.context con.begin_scope() con.typings.update(dict(zip(argnames, argtypes))) con.monomorphs.update(argtypes) for c in self.visit_children(ast): yield c self.context.end_scope() yield Equality(ast.type, T.Fn(argtypes, restype), ast)
def _Map(self, ast): for c in self.visit_children(ast): yield c fn, args = ast.parameters[0], ast.parameters[1:] argtypes = [x.type for x in args] # Type variables that name the element types for each of the # argument sequences items = self.context.fresh_typelist(args) for itemtype, seqtype in zip(items, argtypes): itemtype.source = None yield Equality(seqtype, T.Seq(itemtype), ast) restype = self.context.fresh_typevar() restype.source = None yield Equality(fn.type, T.Fn(items, restype), ast) yield Equality(ast.type, T.Seq(restype), ast)
def _BinOp(self, tree): if type(tree.op) != pyast.ast.RShift: raise SyntaxError, "illegal type operator (%s)" % tree.op L = self.visit(tree.left) R = self.visit(tree.right) return T.Fn(L, R)