def apply_generic_arguments(callable: CallableType, types: List[Type], msg: MessageBuilder, context: Context) -> CallableType: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def (int) -> int'. Note that each type can be None; in this case, it will not be applied. """ tvars = callable.variables assert len(tvars) == len(types) # Check that inferred type variable values are compatible with allowed # values and bounds. Also, promote subtype values to allowed values. types = types[:] for i, type in enumerate(types): values = callable.variables[i].values if values and type: if isinstance(type, AnyType): continue if isinstance(type, TypeVarType) and type.values: # Allow substituting T1 for T if every allowed value of T1 # is also a legal value of T. if all( any(is_same_type(v, v1) for v in values) for v1 in type.values): continue for value in values: if isinstance(type, PartialType) or mypy.subtypes.is_subtype( type, value): types[i] = value break else: msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context) upper_bound = callable.variables[i].upper_bound if (type and not isinstance(type, PartialType) and not mypy.subtypes.is_subtype(type, upper_bound)): msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[TypeVarId, Type] for i, tv in enumerate(tvars): if types[i]: id_to_type[tv.id] = types[i] # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return callable.copy_modified( arg_types=arg_types, ret_type=expand_type(callable.ret_type, id_to_type), variables=remaining_tvars, )
def apply_generic_arguments(callable: CallableType, types: List[Type], msg: MessageBuilder, context: Context) -> Type: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def (int) -> int'. Note that each type can be None; in this case, it will not be applied. """ tvars = callable.variables if len(tvars) != len(types): msg.incompatible_type_application(len(tvars), len(types), context) return AnyType() # Check that inferred type variable values are compatible with allowed # values and bounds. Also, promote subtype values to allowed values. types = types[:] for i, type in enumerate(types): values = callable.variables[i].values if values and type: if isinstance(type, AnyType): continue if isinstance(type, TypeVarType) and type.values: # Allow substituting T1 for T if every allowed value of T1 # is also a legal value of T. if all(any(is_same_type(v, v1) for v in values) for v1 in type.values): continue for value in values: if mypy.subtypes.is_subtype(type, value): types[i] = value break else: msg.incompatible_typevar_value(callable, i + 1, type, context) upper_bound = callable.variables[i].upper_bound if type and not mypy.subtypes.satisfies_upper_bound(type, upper_bound): msg.incompatible_typevar_value(callable, i + 1, type, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[TypeVarId, Type] for i, tv in enumerate(tvars): if types[i]: id_to_type[tv.id] = types[i] # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return callable.copy_modified( arg_types=arg_types, ret_type=expand_type(callable.ret_type, id_to_type), variables=remaining_tvars, )
def apply_generic_arguments(callable: CallableType, types: List[Type], msg: MessageBuilder, context: Context) -> Type: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def [-1:int] (int) -> int'. Here '[-1:int]' is an implicit bound type variable. Note that each type can be None; in this case, it will not be applied. """ tvars = callable.variables if len(tvars) != len(types): msg.incompatible_type_application(len(tvars), len(types), context) return AnyType() # Check that inferred type variable values are compatible with allowed # values. Also, promote subtype values to allowed values. types = types[:] for i, type in enumerate(types): values = callable.variables[i].values if values and type: if isinstance(type, AnyType): continue for value in values: if mypy.subtypes.is_subtype(type, value): types[i] = value break else: msg.incompatible_typevar_value(callable, i + 1, type, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[int, Type] for i, tv in enumerate(tvars): if types[i]: id_to_type[tv.id] = types[i] # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] bound_vars = [(tv.id, id_to_type[tv.id]) for tv in tvars if tv.id in id_to_type] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return CallableType(arg_types, callable.arg_kinds, callable.arg_names, expand_type(callable.ret_type, id_to_type), callable.fallback, callable.name, remaining_tvars, callable.bound_vars + bound_vars, callable.line, callable.repr)
def apply_generic_arguments(callable: CallableType, types: List[Type], msg: MessageBuilder, context: Context) -> Type: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def [-1:int] (int) -> int'. Here '[-1:int]' is an implicit bound type variable. Note that each type can be None; in this case, it will not be applied. """ tvars = callable.variables if len(tvars) != len(types): msg.incompatible_type_application(len(tvars), len(types), context) return AnyType() # Check that inferred type variable values are compatible with allowed # values. Also, promote subtype values to allowed values. types = types[:] for i, type in enumerate(types): values = callable.variables[i].values if values and type: if isinstance(type, AnyType): continue for value in values: if mypy.subtypes.is_subtype(type, value): types[i] = value break else: msg.incompatible_typevar_value(callable, i + 1, type, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[int, Type] for i, tv in enumerate(tvars): if types[i]: id_to_type[tv.id] = types[i] # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] bound_vars = [(tv.id, id_to_type[tv.id]) for tv in tvars if tv.id in id_to_type] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return callable.copy_modified( arg_types=arg_types, ret_type=expand_type(callable.ret_type, id_to_type), variables=remaining_tvars, bound_vars=callable.bound_vars + bound_vars, )
def apply_generic_arguments(callable: CallableType, orig_types: Sequence[Optional[Type]], msg: MessageBuilder, context: Context, skip_unsatisfied: bool = False) -> CallableType: """Apply generic type arguments to a callable type. For example, applying [int] to 'def [T] (T) -> T' results in 'def (int) -> int'. Note that each type can be None; in this case, it will not be applied. If `skip_unsatisfied` is True, then just skip the types that don't satisfy type variable bound or constraints, instead of giving an error. """ tvars = callable.variables assert len(tvars) == len(orig_types) # Check that inferred type variable values are compatible with allowed # values and bounds. Also, promote subtype values to allowed values. types = list(orig_types) for i, type in enumerate(types): assert not isinstance(type, PartialType), "Internal error: must never apply partial type" values = callable.variables[i].values if type is None: continue if values: if isinstance(type, AnyType): continue if isinstance(type, TypeVarType) and type.values: # Allow substituting T1 for T if every allowed value of T1 # is also a legal value of T. if all(any(is_same_type(v, v1) for v in values) for v1 in type.values): continue matching = [] for value in values: if mypy.subtypes.is_subtype(type, value): matching.append(value) if matching: best = matching[0] # If there are more than one matching value, we select the narrowest for match in matching[1:]: if mypy.subtypes.is_subtype(match, best): best = match types[i] = best else: if skip_unsatisfied: types[i] = None else: msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context) else: upper_bound = callable.variables[i].upper_bound if not mypy.subtypes.is_subtype(type, upper_bound): if skip_unsatisfied: types[i] = None else: msg.incompatible_typevar_value(callable, type, callable.variables[i].name, context) # Create a map from type variable id to target type. id_to_type = {} # type: Dict[TypeVarId, Type] for i, tv in enumerate(tvars): typ = types[i] if typ: id_to_type[tv.id] = typ # Apply arguments to argument types. arg_types = [expand_type(at, id_to_type) for at in callable.arg_types] # The callable may retain some type vars if only some were applied. remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type] return callable.copy_modified( arg_types=arg_types, ret_type=expand_type(callable.ret_type, id_to_type), variables=remaining_tvars, )