def infer_function_type_arguments_pass2( self, callee_type, args, arg_kinds, formal_to_actual, inferred_args, context): """Perform second pass of generic function type argument inference. The second pass is needed for arguments with types such as func<s(t)>, where both s and t are type variables, when the actual argument is a lambda with inferred types. The idea is to infer the type variable t in the first pass (based on the types of other arguments). This lets us infer the argument and return type of the lambda expression and thus also the type variable s in this second pass. Return (the callee with type vars applied, inferred actual arg types). """ # None or erased types in inferred types mean that there was not enough # information to infer the argument. Replace them with None values so # that they are not applied yet below. for i, arg in enumerate(inferred_args): if isinstance(arg, NoneTyp) or isinstance(arg, ErasedType): inferred_args[i] = None callee_type = self.apply_generic_arguments( callee_type, inferred_args, context) arg_types = self.infer_arg_types_in_context2( callee_type, args, arg_kinds, formal_to_actual) inferred_args = infer_function_type_arguments( callee_type, arg_types, arg_kinds, formal_to_actual, self.chk.basic_types()) return callee_type, inferred_args
def infer_function_type_arguments(self, callee_type, args, arg_kinds, formal_to_actual, context): """Infer the type arguments for a generic callee type. Infer based on the types of arguments. Return a derived callable type that has the arguments applied (and stored as implicit type arguments). """ if not self.chk.is_dynamic_function(): # Disable type errors during type inference. There may be errors # due to partial available context information at this time, but # these errors can be safely ignored as the arguments will be # inferred again later. self.msg.disable_errors() arg_types = self.infer_arg_types_in_context2( callee_type, args, arg_kinds, formal_to_actual) self.msg.enable_errors() arg_pass_nums = self.get_arg_infer_passes( callee_type.arg_types, formal_to_actual, len(args)) pass1_args = [] for i, arg in enumerate(arg_types): if arg_pass_nums[i] > 1: pass1_args.append(None) else: pass1_args.append(arg) inferred_args = infer_function_type_arguments( callee_type, pass1_args, arg_kinds, formal_to_actual, self.chk.basic_types()) if 2 in arg_pass_nums: # Second pass of type inference. (callee_type, inferred_args) = self.infer_function_type_arguments_pass2( callee_type, args, arg_kinds, formal_to_actual, inferred_args, context) else: # In dynamically typed functions use implicit 'any' types for # type variables. inferred_args = [Any()] * len(callee_type.variables.items) return self.apply_inferred_arguments(callee_type, inferred_args, context)
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) Callable infer_function_type_arguments(self, Callable callee_type, Typ[] arg_types, int[] arg_kinds, int[][] formal_to_actual, Context context): """Infer the type arguments for a generic callee type. Return a derived callable type that has the arguments applied (and stored as implicit type arguments). If is_var_arg is True, the callee uses varargs. """ Typ[] inferred_args = infer_function_type_arguments( callee_type, arg_types, arg_kinds, formal_to_actual, self.chk.basic_types()) return self.apply_inferred_arguments(callee_type, inferred_args, [], context)