def infer_lambda_type(self, e): """Try to infer lambda expression type using context. Return None if could not infer type. """ ctx = self.chk.type_context[-1] if not ctx or not isinstance(ctx, Callable): return None # The context may have function type variables in it. We replace them # since these are the type variables we are ultimately trying to infer; # they must be considered as indeterminate. We use ErasedType since it # does not affect type inference results (it is for purposes like this # only). ctx = replace_func_type_vars(ctx, ErasedType()) callable_ctx = ctx if callable_ctx.arg_kinds != e.arg_kinds: # Incompatible context; cannot use it to infer types. self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e) return None if not e.typ: return callable_ctx else: # The lambda already has a type; only infer the return type. return replace_callable_return_type(e.typ.typ, callable_ctx.ret_type)
def infer_function_type_arguments_using_context(self, callable): """Unify callable return type to type context to infer type vars. For example, if the return type is set<t> where 't' is a type variable of callable, and if the context is set<int>, return callable modified by substituting 't' with 'int'. """ ctx = self.chk.type_context[-1] if not ctx: return callable # The return type may have references to function type variables that # we are inferring right now. We must consider them as indeterminate # and they are not potential results; thus we replace them with the # None type. On the other hand, class type variables are valid results. erased_ctx = replace_func_type_vars(ctx, ErasedType()) args = infer_type_arguments(callable.type_var_ids(), callable.ret_type, erased_ctx, self.chk.basic_types()) # Only substite non-None and non-erased types. new_args = [] for arg in args: if isinstance(arg, NoneTyp) or has_erased_component(arg): new_args.append(None) else: new_args.append(arg) return self.apply_generic_arguments(callable, new_args, None)
Callable infer_function_type_arguments_using_context(self, Callable callable): """Unify callable return type to type context to infer type vars. For example, if the return type is set<t> where 't' is a type variable of callable, and if the context is set<int>, return callable modified by substituting 't' with 'int'. """ ctx = self.chk.type_context[-1] if not ctx: return callable # The return type may have references to function type variables that # we are inferring right now. We must consider them as indeterminate # and they are not potential results; thus we replace them with the # None type. On the other hand, class type variables are valid results. erased_ctx = replace_func_type_vars(ctx) args = infer_type_arguments(callable.type_var_ids(), callable.ret_type, erased_ctx, self.chk.basic_types()) # If all the inferred types are None types, do no type variable # substition. # TODO This is not nearly general enough. If a type has a None type # component we should not use it. Also if some types are not-None # we should only substitute them. Finally, using None types for # this might not be optimal. some_not_none = False for i in range(len(args)): if not isinstance(args[i], NoneTyp): some_not_none = True if not some_not_none: return callable return (Callable)self.apply_generic_arguments(callable, args, [], None)