def _check_excluded_types(self, tree, type, excluded_types): for excluded_type in excluded_types: try: gbs_type.unify(type, excluded_type) area = position.ProgramAreaNear(tree) msg = i18n.i18n('Expression can\'t have type: %s') % (excluded_type,) self.error(GbsTypeInferenceException(msg, area)) except gbs_type.UnificationFailedException as exception: pass
def _set_routine_definition_type(self, tree, prfn, name, params, body): """Given a context with types for the parameters and local variables in a routine, build the type for this routine and unify it with its type in the global context. For instance if the function "f" has a parameter "x", and returns an expression, take the type "s" for "x" from the local context, the type "t" for the returned expression. Build the type "s -> t" for the function and unify that with any type information previously known for "f". This requires that the body of the routine has already been typechecked.""" param_types = [] for p in params.children: param_types.append(self.context[p.value]) param_types = gbs_type.GbsTupleType(param_types) if prfn == 'procedure': def_type = gbs_type.GbsProcedureType(param_types) elif prfn == 'function': return_types = self._return_type(prfn, name, params, body) def_type = gbs_type.GbsFunctionType(param_types, return_types) elif prfn == 'entrypoint' and (name.value == 'program' or name.value == 'interactive'): def_type = gbs_type.GbsEntryPointType() else: assert False expected = self.global_context[name.value].instantiate() try: gbs_type.unify(expected, def_type) if prfn == 'function': #[TODO] Check freevars = def_type.freevars() if len(freevars) > 0: def_type = gbs_type.GbsForallType(freevars, def_type) self.global_context[name.value] = def_type tree.type_annot = def_type except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) if prfn == 'procedure': msg = i18n.i18n( 'procedure "%s" should take: %s\n' + 'But takes: %s' ) % ( name.value, expected.paramtype(), def_type.paramtype() ) else: msg = i18n.i18n( 'function "%s" should take: %s and return: %s\n' + 'But takes: %s and returns: %s' ) % ( name.value, expected.paramtype(), expected.restype(), def_type.paramtype(), def_type.restype() ) self.error(GbsTypeInferenceException(msg, area))
def _add_var(self, token, new_type=None): """Add a variable to the context with the given type, checking that it is consistent with the types it might already have.""" if new_type is None: # fresh new_type = gbs_type.GbsTypeVar() varname = token.value if varname in self.ribs[-1]: old_type = self.context[varname] gbs_type.unify(new_type, old_type) else: self.context[varname] = new_type set_add(self.ribs[-1], varname) return new_type
def check_type(self, tree, real_type, expected_type, excluded_types=[]): try: gbs_type.unify(real_type, expected_type) self._check_excluded_types(tree, real_type, excluded_types) return real_type except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) msg = i18n.i18n( 'Expression should have type: %s\n' + 'But has type: %s' ) % ( expected_type, real_type ) self.error(GbsTypeInferenceException(msg, area))
def _check_literals(self, lits, expected_type): """Check the types for the list of literals in a case statement.""" for lit in lits.children: lit_type = self.infer_tok_literal(lit) try: gbs_type.unify(lit_type, expected_type) except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(lit) msg = i18n.i18n( 'Literal should have type: %s\n' + 'But has type: %s' ) % ( expected_type, lit_type ) self.error(GbsTypeInferenceException(msg, area))
def infer_proc_call(self, tree): "Infer types for a procedure call." proc_name = tree.children[1].value proc_type = self.global_context[proc_name].instantiate() arg_type = self.infer_tuple(tree.children[2]) expected = gbs_type.GbsProcedureType(arg_type) try: gbs_type.unify(proc_type, expected) except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) msg = i18n.i18n( 'procedure "%s" is receiving: %s\n' + 'But should receive: %s' ) % ( proc_name, expected.paramtype(), proc_type.paramtype() ) self.error(GbsTypeInferenceException(msg, area)) tree.type_annotation = proc_type.parameters()
def _infer_func_call(self, tree, nretvals): "Infer types for a function call." fun_name = tree.children[1].value fun_type = self.global_context[fun_name].instantiate() arg_type = self.infer_tuple(tree.children[2]) subtypes = [gbs_type.GbsTypeVar() for i in range(nretvals)] res_type = gbs_type.GbsTupleType(subtypes) expected = gbs_type.GbsFunctionType(arg_type, res_type) # check parameters try: gbs_type.unify(expected.paramtype(), fun_type.paramtype()) except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) msg = i18n.i18n( 'function "%s" is receiving: %s\n' + 'But should receive: %s' ) % ( fun_name, print_type(expected.paramtype()), print_type(fun_type.paramtype()) ) self.error(GbsTypeInferenceException(msg, area)) # check return value try: gbs_type.unify(fun_type._res, expected._res) except gbs_type.UnificationFailedException as e: area = position.ProgramAreaNear(tree) msg = i18n.i18n( 'function "%s" is called as if it returned: %s\n' + 'But returns: %s' ) % ( fun_name, expected._res, fun_type._res ) self.error(GbsTypeInferenceException(msg, area)) tree.type_annotation = fun_type.parameters() return res_type