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 normalize_type(t, tcon): """ Return a normalized type that eliminates all free variables from 't'. Any type variables bound in the given context will be resolved, and all remaining variables will be quantified with a Polytype. """ return T.quantify_type(resolve_type(t, tcon))
def infer(P, verbose=False, globals=None, context=None, input_types=None): 'Run type inference on the given AST. Returns the inferred type.' tcon = context or TypingContext(globals=globals) # Label every AST node with a temporary type variable L = TypeLabeling(tcon) L.verbose = verbose L.visit(P) # Generate constraints from AST # And chain them to constraints from input_types C = chain( ConstrainInputTypes(input_types).visit(P), ConstraintGenerator(tcon).visit(P)) S = Solver1(C, tcon) S.verbose = verbose S.solve() if verbose: print "\nThe free occurrence set is:" print " ", tcon.free_occurrences print "\nThe assumption set is:" print " ", tcon.assumptions if len(tcon.free_occurrences) > 0: undef = set([x.id for x in tcon.free_occurrences]) raise InferenceError, 'undefined variables: %s' % list(undef) if len(tcon.assumptions) > 0: assumed = set(assumptions.values()) raise InferenceError, 'unexplored assumptions: %s' % list(assumed) # Resolve the AST type slots to their solved types TypeResolution(S.solution, S.quantified).visit(P) # Resolve any outstanding variables in the typing context # XXX it's inefficient to go through the whole typings # environment when we could just record which ones were # introduced by the program P for id in tcon.typings: t = tcon.typings[id] if t in S.solution: tcon.typings[id] = resolve_type(t, S.solution) if isinstance(P, list): result = getattr(P[-1], 'type', T.Void) else: result = getattr(P, 'type', T.Void) # We quantify here to normalize the result of this procedure. # For instance, running the solver on a polymorphic expression like # "op_plus" will instantiate the polytype for op_plus with fresh # type variables. While what we want internally, this is not what # external clients expect. return T.quantify_type(result)
def infer(P, verbose=False, globals=None, context=None, input_types=None): 'Run type inference on the given AST. Returns the inferred type.' tcon = context or TypingContext(globals=globals) # Label every AST node with a temporary type variable L = TypeLabeling(tcon) L.verbose = verbose L.visit(P) # Generate constraints from AST # And chain them to constraints from input_types C = chain(ConstrainInputTypes(input_types).visit(P), ConstraintGenerator(tcon).visit(P)) S = Solver1(C,tcon) S.verbose = verbose S.solve() if verbose: print "\nThe free occurrence set is:" print " ", tcon.free_occurrences print "\nThe assumption set is:" print " ", tcon.assumptions if len(tcon.free_occurrences) > 0: undef = set([x.id for x in tcon.free_occurrences]) raise InferenceError, 'undefined variables: %s' % list(undef) if len(tcon.assumptions) > 0: assumed = set(assumptions.values()) raise InferenceError, 'unexplored assumptions: %s' % list(assumed) # Resolve the AST type slots to their solved types TypeResolution(S.solution, S.quantified).visit(P) # Resolve any outstanding variables in the typing context # XXX it's inefficient to go through the whole typings # environment when we could just record which ones were # introduced by the program P for id in tcon.typings: t = tcon.typings[id] if t in S.solution: tcon.typings[id] = resolve_type(t, S.solution) if isinstance(P, list): result = getattr(P[-1], 'type', T.Void) else: result = getattr(P, 'type', T.Void) # We quantify here to normalize the result of this procedure. # For instance, running the solver on a polymorphic expression like # "op_plus" will instantiate the polytype for op_plus with fresh # type variables. While what we want internally, this is not what # external clients expect. return T.quantify_type(result)
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 type_from_text(text): past = pyast.ast.parse(_pythonify_type(text), "<type string>", mode='eval') return T.quantify_type(_convert_type(past))