def unify_monotypes(self, t1, t2): "Unify the given types, which must be either Monotypes or Variables" assert isinstance(t1, (T.Monotype, T.Typevar)) assert isinstance(t2, (T.Monotype, T.Typevar)) con = self.context # Resolve w.r.t. the current solution before proceeding t1 = resolve(t1, self.solution) t2 = resolve(t2, self.solution) if self.verbose: print "\tunifying", t1, "and", t2 if t1 == t2: pass elif con.is_variable(t1): self.unify_variable(t1, t2) elif con.is_variable(t2): self.unify_variable(t2, t1) else: t1 = self.context.instantiate(t1) t2 = self.context.instantiate(t2) if t1.name != t2.name or len(t1.parameters) != len(t2.parameters): con.error('type mismatch %s and %s' % (t1, t2)) for (u, v) in zip(t1.parameters, t2.parameters): self.unify_monotypes(u, v)
def unify_monotypes(self, t1, t2): "Unify the given types, which must be either Monotypes or Variables" assert isinstance(t1, (T.Monotype, T.Typevar)) assert isinstance(t2, (T.Monotype, T.Typevar)) con = self.context # Resolve w.r.t. the current solution before proceeding t1 = resolve(t1, self.solution) t2 = resolve(t2, self.solution) if self.verbose: print "\tunifying", t1, "and", t2 if t1==t2: pass elif con.is_variable(t1): self.unify_variable(t1, t2) elif con.is_variable(t2): self.unify_variable(t2, t1) else: t1 = self.context.instantiate(t1) t2 = self.context.instantiate(t2) if t1.name != t2.name or len(t1.parameters) != len(t2.parameters): con.error('type mismatch %s and %s' % (t1,t2)) for (u,v) in zip(t1.parameters, t2.parameters): self.unify_monotypes(u, v)
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 _Bind(self, ast): type = self.expression_type(ast.value()) # Convert functional types to polytypes as necessary if isinstance(type, T.Fn): free = [v for v in AST.free_variables(ast.value(), {})] bound = [self.tcon.typings[id] for id in free] bound = [resolve(t, self.tcon.environment) for t in bound] type = T.quantify_type(type, bound) ##This code allows us to unpack tuples returned from functions def match(binder, type): if isinstance(binder, AST.Name): self.tcon.typings[binder.id] = type elif isinstance(binder, AST.Tuple): if len(binder.parameters)!=len(type.parameters): raise InferenceError, \ "binder and value don't match (%s)" % ast for b, t in zip(binder.parameters, type.parameters): match(b, t) else: raise InferenceError, "illegal binder (%s)" % ast match(ast.binder(), type) return None
def generalize_binding(self, t1, t2, M): assert isinstance(t1, T.Typevar) assert isinstance(t2, (T.Typevar, T.Monotype)) # Generalization occurs for identifiers introduced in # declaration statements. This may, for instance, occur as the # result of a declaration: # x = E # or a procedure definition # def f(...): S # # The type variable t1 associated with the binder (e.g., 'x') is # allowed to become a Polytype. We generate this polytype by # quantifying over the free variables of t2 that do not occur in # M. # NOTE: In general, we must be careful about when we can solve # Generalizing constraints. In the current solver, where # constraints are generated in post-order, they can be solved # immediately. In other orderings, they may need to be deferred # if they contain "active" type variables. r1 = resolve(t1, self.solution) r2 = resolve_type(t2, self.solution) if self.verbose: print "\tt1 =", t1 print "\tt2 =", t2 print "\tresolve(t1) =", r1 print "\tresolve(t2) =", r2 if r1 != t1 and isinstance(r2, T.Monotype): self.unify_monotypes(r1, r2) r2 = resolve_type(t2, self.solution) # The set of type variables associated with assumptions should # also be treated as monomorphs. While we may have made # assumptions about a polymorphic function, we will have # generated a fresh type variable for each occurrence. These # type variables are thus properly monomorphic. # R = set() for x in chain(M, self.context.assumptions.keys()): R |= set(T.names_in_type(resolve_type(x, self.solution))) if self.verbose: print "\tR =", R assert self.context.is_variable(t1) self.solution[t1] = T.quantify_type(r2, R, self.quantified) if self.verbose: print "\t--> Quantifying", t2, "to", self.solution[t1]
def _Map(self, ast): fn, args = ast.parameters[0], ast.parameters[1:] # Type the function we're applying fntype = self.visit(fn) argtypes = self.visit(args) items = [self.tcon.fresh_typevar() for x in argtypes] for t, seq in zip(items, argtypes): unify(T.Seq(t), seq, self.tcon) # Unify function type with element types restype = self.tcon.fresh_typevar() unify(fntype, T.Fn(T.Tuple(*items), restype), self.tcon) return T.Seq(resolve(restype, self.tcon.environment))
def resolve_variable(tcon, t): 'Resolve current mapping (if any) of typevars' if isinstance(t, T.Typevar): return resolve(t, tcon.typings) else: return t