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, orig_types: Sequence[Optional[Type]], report_incompatible_typevar_value: Callable[[CallableType, Type, str, Context], None], 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 = get_proper_types(orig_types) # Create a map from type variable id to target type. id_to_type: Dict[TypeVarId, Type] = {} for tvar, type in zip(tvars, types): assert not isinstance(type, PartialType), "Internal error: must never apply partial type" if type is None: continue target_type = get_target_type( tvar, type, callable, report_incompatible_typevar_value, context, skip_unsatisfied ) if target_type is not None: id_to_type[tvar.id] = target_type param_spec = callable.param_spec() if param_spec is not None: nt = id_to_type.get(param_spec.id) if nt is not None: nt = get_proper_type(nt) if isinstance(nt, CallableType): callable = callable.expand_param_spec(nt) # 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 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 _create_partial_case( self, case_function: CallableType, intermediate: CallableType, constraints: _Constraints, ) -> CallableType: partial = cast( CallableType, expand_type( _Functions(case_function, intermediate).diff(), constraints, )) if case_function.is_generic(): # We can deal with really different `case_function` over here. # The first one is regular `generic` function # that has variables and typevars in its spec. # In this case, we process `partial` the same way. # It should be generic also. # # The second possible type of `case_function` is pseudo-generic. # These are functions that contain typevars in its spec, # but variables are empty. # Probably these functions are already used in a generic context. # So, we ignore them and do not add variables back. # # Regular functions are also untouched by this. return detach_callable(partial) return partial.copy_modified(variables=[])
def from_usage( self, applied_args: List[FuncArg], ) -> CallableType: """Infers function constrains from its usage: passed arguments.""" constraints = self._infer_constraints(applied_args) infered = expand_type(self._case_function, constraints) return cast(CallableType, infered)
def assert_expand(self, orig, map_items, result): lower_bounds = {} for id, t in map_items: lower_bounds[id] = t exp = expand_type(orig, lower_bounds) # Remove erased tags (asterisks). assert_equal(str(exp).replace('*', ''), str(result))
def map_instance_to_direct_supertype(instance, supertype): typ = instance.type for b in typ.bases: # The cast below cannot fail since we require that semantic analysis # was successful, so bases cannot contain unbound types. if b and (b).type == supertype: map = type_var_map(typ, instance.args) return expand_type(b, map) # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return Instance(typ.base, [Any()] * len(typ.base.type_vars))
def map_instance_to_direct_supertype(instance: Instance, supertype: TypeInfo) -> Instance: typ = instance.type for base in typ.bases: if base.type == supertype: map = type_var_map(typ, instance.args) return cast(Instance, expand_type(base, map)) # Relationship with the supertype not specified explicitly. Use AnyType # type arguments implicitly. # TODO Should this be an error instead? return Instance(supertype, [AnyType()] * len(supertype.type_vars))
def assert_expand(self, orig: Type, map_items: List[Tuple[TypeVarId, Type]], result: Type, ) -> None: lower_bounds = {} for id, t in map_items: lower_bounds[id] = t exp = expand_type(orig, lower_bounds) # Remove erased tags (asterisks). assert_equal(str(exp).replace('*', ''), str(result))
def map_instance_to_direct_supertypes(instance: Instance, supertype: TypeInfo) -> List[Instance]: # FIX: There should only be one supertypes, always. typ = instance.type result = [] # type: List[Instance] for b in typ.bases: if b.type == supertype: map = type_var_map(typ, instance.args) result.append(cast(Instance, expand_type(b, map))) if result: return result else: # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return [Instance(supertype, [AnyType()] * len(supertype.type_vars))]
def map_instance_to_direct_supertypes(instance: Instance, supertype: TypeInfo) -> List[Instance]: # FIX: There should only be one supertypes, always. typ = instance.type result = [] # type: List[Instance] for b in typ.bases: if b.type == supertype: env = instance_to_type_environment(instance) result.append(cast(Instance, expand_type(b, env))) if result: return result else: # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return [Instance(supertype, [AnyType()] * len(supertype.type_vars))]
def map_instance_to_direct_supertypes(instance, supertype): # FIX: There should only be one supertypes, always. typ = instance.type result = [] for b in typ.bases: # The cast below cannot fail since we require that semantic analysis # was successful, so bases cannot contain unbound types. if b and (b).type == supertype: map = type_var_map(typ, instance.args) result.append(expand_type(b, map)) if result: return result else: # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return [Instance(supertype, [Any()] * len(supertype.type_vars))]
def map_instance_to_direct_supertypes(instance: Instance, supertype: TypeInfo) -> List[Instance]: # FIX: There should only be one supertypes, always. typ = instance.type result = [] # type: List[Instance] for b in typ.bases: if b.type == supertype: env = instance_to_type_environment(instance) t = expand_type(b, env) assert isinstance(t, Instance) result.append(t) if result: return result else: # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return [Instance(supertype, [AnyType()] * len(supertype.type_vars))]
def map_instance_to_direct_supertypes(instance: Instance, supertype: TypeInfo) -> List[Instance]: # FIX: There should only be one supertypes, always. typ = instance.type result = [] # type: List[Instance] for b in typ.bases: if b.type == supertype: env = instance_to_type_environment(instance) t = expand_type(b, env) assert isinstance(t, ProperType) assert isinstance(t, Instance) result.append(t) if result: return result else: # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. any_type = AnyType(TypeOfAny.unannotated) return [Instance(supertype, [any_type] * len(supertype.type_vars))]
def expand(target: Type) -> Type: return expand_type(target, {id: to_apply[all_ids.index(id)] for id in ids})
def expand(target: Type) -> Type: return expand_type(target, {func.variables[0].id: typearg})
instance.type.base) if instance.type == supertype: break return instance Instance map_instance_to_direct_supertype(Instance instance, TypeInfo supertype): typ = instance.type for b in typ.bases: # The cast below cannot fail since we require that semantic analysis # was successful, so bases cannot contain unbound types. if b and ((Instance)b).type == supertype: map = type_var_map(typ, instance.args) return (Instance)expand_type(b, map) # Relationship with the supertype not specified explicitly. Use dynamic # type arguments implicitly. return Instance(typ.base, <Type> [Any()] * len(typ.base.type_vars)) dict<int, Type> type_var_map(TypeInfo typ, Type[] args): if not args: return None else: tvars = <int, Type> {} for i in range(len(args)): tvars[i + 1] = args[i] return tvars
def expand(target: Type) -> Type: assert typearg is not None return expand_type(target, {func.variables[0].id: typearg})
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, )