[ty] Rename Type unwrapping methods (#20857)

## Summary

Rename "unwrapping" methods on `Type` from e.g.
`Type::into_class_literal` to `Type::as_class_literal`. I personally
find that name more intuitive, since no transformation of any kind is
happening. We are just unwrapping from certain enum variants. An
alternative would be `try_as_class_literal`, which would follow the
[`strum` naming
scheme](https://docs.rs/strum/latest/strum/derive.EnumTryAs.html), but
is slightly longer.

Also rename `Type::into_callable` to `Type::try_upcast_to_callable`.
Note that I intentionally kept names like
`FunctionType::into_callable_type`, because those return `CallableType`,
not `Option<Type<…>>`.

## Test Plan

Pure refactoring
This commit is contained in:
David Peter 2025-10-14 09:53:29 +02:00 committed by GitHub
parent e338d2095e
commit f73bb45be6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 81 additions and 87 deletions

View file

@ -1447,7 +1447,7 @@ mod implicit_globals {
fn module_type_symbols<'db>(db: &'db dyn Db) -> smallvec::SmallVec<[ast::name::Name; 8]> { fn module_type_symbols<'db>(db: &'db dyn Db) -> smallvec::SmallVec<[ast::name::Name; 8]> {
let Some(module_type) = KnownClass::ModuleType let Some(module_type) = KnownClass::ModuleType
.to_class_literal(db) .to_class_literal(db)
.into_class_literal() .as_class_literal()
else { else {
// The most likely way we get here is if a user specified a `--custom-typeshed-dir` // The most likely way we get here is if a user specified a `--custom-typeshed-dir`
// without a `types.pyi` stub in the `stdlib/` directory // without a `types.pyi` stub in the `stdlib/` directory

View file

@ -854,7 +854,7 @@ impl ReachabilityConstraints {
} }
let overloads_iterator = let overloads_iterator =
if let Some(Type::Callable(callable)) = ty.into_callable(db) { if let Some(Type::Callable(callable)) = ty.try_upcast_to_callable(db) {
callable.signatures(db).overloads.iter() callable.signatures(db).overloads.iter()
} else { } else {
return Truthiness::AlwaysFalse.negate_if(!predicate.is_positive); return Truthiness::AlwaysFalse.negate_if(!predicate.is_positive);

View file

@ -982,39 +982,39 @@ impl<'db> Type<'db> {
matches!(self, Type::TypeVar(_)) matches!(self, Type::TypeVar(_))
} }
pub(crate) const fn into_type_var(self) -> Option<BoundTypeVarInstance<'db>> { pub(crate) const fn as_typevar(self) -> Option<BoundTypeVarInstance<'db>> {
match self { match self {
Type::TypeVar(bound_typevar) => Some(bound_typevar), Type::TypeVar(bound_typevar) => Some(bound_typevar),
_ => None, _ => None,
} }
} }
pub(crate) fn has_type_var(self, db: &'db dyn Db) -> bool { pub(crate) fn has_typevar(self, db: &'db dyn Db) -> bool {
any_over_type(db, self, &|ty| matches!(ty, Type::TypeVar(_)), false) any_over_type(db, self, &|ty| matches!(ty, Type::TypeVar(_)), false)
} }
pub(crate) const fn into_class_literal(self) -> Option<ClassLiteral<'db>> { pub(crate) const fn as_class_literal(self) -> Option<ClassLiteral<'db>> {
match self { match self {
Type::ClassLiteral(class_type) => Some(class_type), Type::ClassLiteral(class_type) => Some(class_type),
_ => None, _ => None,
} }
} }
pub(crate) const fn into_type_alias(self) -> Option<TypeAliasType<'db>> { pub(crate) const fn as_type_alias(self) -> Option<TypeAliasType<'db>> {
match self { match self {
Type::KnownInstance(KnownInstanceType::TypeAliasType(type_alias)) => Some(type_alias), Type::KnownInstance(KnownInstanceType::TypeAliasType(type_alias)) => Some(type_alias),
_ => None, _ => None,
} }
} }
pub(crate) const fn into_dynamic(self) -> Option<DynamicType<'db>> { pub(crate) const fn as_dynamic(self) -> Option<DynamicType<'db>> {
match self { match self {
Type::Dynamic(dynamic_type) => Some(dynamic_type), Type::Dynamic(dynamic_type) => Some(dynamic_type),
_ => None, _ => None,
} }
} }
pub(crate) const fn unwrap_as_callable_type(self) -> Option<CallableType<'db>> { pub(crate) const fn as_callable(self) -> Option<CallableType<'db>> {
match self { match self {
Type::Callable(callable_type) => Some(callable_type), Type::Callable(callable_type) => Some(callable_type),
_ => None, _ => None,
@ -1022,11 +1022,10 @@ impl<'db> Type<'db> {
} }
pub(crate) const fn expect_dynamic(self) -> DynamicType<'db> { pub(crate) const fn expect_dynamic(self) -> DynamicType<'db> {
self.into_dynamic() self.as_dynamic().expect("Expected a Type::Dynamic variant")
.expect("Expected a Type::Dynamic variant")
} }
pub(crate) const fn into_protocol_instance(self) -> Option<ProtocolInstanceType<'db>> { pub(crate) const fn as_protocol_instance(self) -> Option<ProtocolInstanceType<'db>> {
match self { match self {
Type::ProtocolInstance(instance) => Some(instance), Type::ProtocolInstance(instance) => Some(instance),
_ => None, _ => None,
@ -1035,7 +1034,7 @@ impl<'db> Type<'db> {
#[track_caller] #[track_caller]
pub(crate) fn expect_class_literal(self) -> ClassLiteral<'db> { pub(crate) fn expect_class_literal(self) -> ClassLiteral<'db> {
self.into_class_literal() self.as_class_literal()
.expect("Expected a Type::ClassLiteral variant") .expect("Expected a Type::ClassLiteral variant")
} }
@ -1048,7 +1047,7 @@ impl<'db> Type<'db> {
matches!(self, Type::ClassLiteral(..)) matches!(self, Type::ClassLiteral(..))
} }
pub(crate) fn into_enum_literal(self) -> Option<EnumLiteralType<'db>> { pub(crate) fn as_enum_literal(self) -> Option<EnumLiteralType<'db>> {
match self { match self {
Type::EnumLiteral(enum_literal) => Some(enum_literal), Type::EnumLiteral(enum_literal) => Some(enum_literal),
_ => None, _ => None,
@ -1058,7 +1057,7 @@ impl<'db> Type<'db> {
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
pub(crate) fn expect_enum_literal(self) -> EnumLiteralType<'db> { pub(crate) fn expect_enum_literal(self) -> EnumLiteralType<'db> {
self.into_enum_literal() self.as_enum_literal()
.expect("Expected a Type::EnumLiteral variant") .expect("Expected a Type::EnumLiteral variant")
} }
@ -1066,7 +1065,7 @@ impl<'db> Type<'db> {
matches!(self, Type::TypedDict(..)) matches!(self, Type::TypedDict(..))
} }
pub(crate) fn into_typed_dict(self) -> Option<TypedDictType<'db>> { pub(crate) fn as_typed_dict(self) -> Option<TypedDictType<'db>> {
match self { match self {
Type::TypedDict(typed_dict) => Some(typed_dict), Type::TypedDict(typed_dict) => Some(typed_dict),
_ => None, _ => None,
@ -1100,14 +1099,14 @@ impl<'db> Type<'db> {
)) ))
} }
pub(crate) const fn into_module_literal(self) -> Option<ModuleLiteralType<'db>> { pub(crate) const fn as_module_literal(self) -> Option<ModuleLiteralType<'db>> {
match self { match self {
Type::ModuleLiteral(module) => Some(module), Type::ModuleLiteral(module) => Some(module),
_ => None, _ => None,
} }
} }
pub(crate) const fn into_union(self) -> Option<UnionType<'db>> { pub(crate) const fn as_union(self) -> Option<UnionType<'db>> {
match self { match self {
Type::Union(union_type) => Some(union_type), Type::Union(union_type) => Some(union_type),
_ => None, _ => None,
@ -1117,10 +1116,10 @@ impl<'db> Type<'db> {
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
pub(crate) fn expect_union(self) -> UnionType<'db> { pub(crate) fn expect_union(self) -> UnionType<'db> {
self.into_union().expect("Expected a Type::Union variant") self.as_union().expect("Expected a Type::Union variant")
} }
pub(crate) const fn into_function_literal(self) -> Option<FunctionType<'db>> { pub(crate) const fn as_function_literal(self) -> Option<FunctionType<'db>> {
match self { match self {
Type::FunctionLiteral(function_type) => Some(function_type), Type::FunctionLiteral(function_type) => Some(function_type),
_ => None, _ => None,
@ -1130,7 +1129,7 @@ impl<'db> Type<'db> {
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
pub(crate) fn expect_function_literal(self) -> FunctionType<'db> { pub(crate) fn expect_function_literal(self) -> FunctionType<'db> {
self.into_function_literal() self.as_function_literal()
.expect("Expected a Type::FunctionLiteral variant") .expect("Expected a Type::FunctionLiteral variant")
} }
@ -1139,7 +1138,7 @@ impl<'db> Type<'db> {
} }
pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool { pub(crate) fn is_union_of_single_valued(&self, db: &'db dyn Db) -> bool {
self.into_union().is_some_and(|union| { self.as_union().is_some_and(|union| {
union.elements(db).iter().all(|ty| { union.elements(db).iter().all(|ty| {
ty.is_single_valued(db) ty.is_single_valued(db)
|| ty.is_bool(db) || ty.is_bool(db)
@ -1152,7 +1151,7 @@ impl<'db> Type<'db> {
} }
pub(crate) fn is_union_with_single_valued(&self, db: &'db dyn Db) -> bool { pub(crate) fn is_union_with_single_valued(&self, db: &'db dyn Db) -> bool {
self.into_union().is_some_and(|union| { self.as_union().is_some_and(|union| {
union.elements(db).iter().any(|ty| { union.elements(db).iter().any(|ty| {
ty.is_single_valued(db) ty.is_single_valued(db)
|| ty.is_bool(db) || ty.is_bool(db)
@ -1164,7 +1163,7 @@ impl<'db> Type<'db> {
|| (self.is_enum(db) && !self.overrides_equality(db)) || (self.is_enum(db) && !self.overrides_equality(db))
} }
pub(crate) fn into_string_literal(self) -> Option<StringLiteralType<'db>> { pub(crate) fn as_string_literal(self) -> Option<StringLiteralType<'db>> {
match self { match self {
Type::StringLiteral(string_literal) => Some(string_literal), Type::StringLiteral(string_literal) => Some(string_literal),
_ => None, _ => None,
@ -1404,7 +1403,7 @@ impl<'db> Type<'db> {
} }
} }
pub(crate) fn into_callable(self, db: &'db dyn Db) -> Option<Type<'db>> { pub(crate) fn try_upcast_to_callable(self, db: &'db dyn Db) -> Option<Type<'db>> {
match self { match self {
Type::Callable(_) => Some(self), Type::Callable(_) => Some(self),
@ -1427,7 +1426,7 @@ impl<'db> Type<'db> {
.place; .place;
if let Place::Type(ty, Boundness::Bound) = call_symbol { if let Place::Type(ty, Boundness::Bound) = call_symbol {
ty.into_callable(db) ty.try_upcast_to_callable(db)
} else { } else {
None None
} }
@ -1447,13 +1446,13 @@ impl<'db> Type<'db> {
)), )),
}, },
Type::Union(union) => union.try_map(db, |element| element.into_callable(db)), Type::Union(union) => union.try_map(db, |element| element.try_upcast_to_callable(db)),
Type::EnumLiteral(enum_literal) => { Type::EnumLiteral(enum_literal) => enum_literal
enum_literal.enum_class_instance(db).into_callable(db) .enum_class_instance(db)
} .try_upcast_to_callable(db),
Type::TypeAlias(alias) => alias.value_type(db).into_callable(db), Type::TypeAlias(alias) => alias.value_type(db).try_upcast_to_callable(db),
Type::KnownBoundMethod(method) => Some(Type::Callable(CallableType::new( Type::KnownBoundMethod(method) => Some(Type::Callable(CallableType::new(
db, db,
@ -1943,7 +1942,7 @@ impl<'db> Type<'db> {
}), }),
(_, Type::Callable(_)) => relation_visitor.visit((self, target, relation), || { (_, Type::Callable(_)) => relation_visitor.visit((self, target, relation), || {
self.into_callable(db).when_some_and(|callable| { self.try_upcast_to_callable(db).when_some_and(|callable| {
callable.has_relation_to_impl( callable.has_relation_to_impl(
db, db,
target, target,
@ -8083,7 +8082,7 @@ impl<'db> TypeVarInstance<'db> {
TypeVarBoundOrConstraints::UpperBound(upper_bound.to_instance(db)?) TypeVarBoundOrConstraints::UpperBound(upper_bound.to_instance(db)?)
} }
TypeVarBoundOrConstraints::Constraints(constraints) => { TypeVarBoundOrConstraints::Constraints(constraints) => {
TypeVarBoundOrConstraints::Constraints(constraints.to_instance(db)?.into_union()?) TypeVarBoundOrConstraints::Constraints(constraints.to_instance(db)?.as_union()?)
} }
}; };
let identity = TypeVarIdentity::new( let identity = TypeVarIdentity::new(
@ -8131,7 +8130,7 @@ impl<'db> TypeVarInstance<'db> {
DefinitionKind::TypeVar(typevar) => { DefinitionKind::TypeVar(typevar) => {
let typevar_node = typevar.node(&module); let typevar_node = typevar.node(&module);
definition_expression_type(db, definition, typevar_node.bound.as_ref()?) definition_expression_type(db, definition, typevar_node.bound.as_ref()?)
.into_union()? .as_union()?
} }
// legacy typevar // legacy typevar
DefinitionKind::Assignment(assignment) => { DefinitionKind::Assignment(assignment) => {
@ -10713,7 +10712,7 @@ impl<'db> TypeAliasType<'db> {
} }
} }
pub(crate) fn into_pep_695_type_alias(self) -> Option<PEP695TypeAliasType<'db>> { pub(crate) fn as_pep_695_type_alias(self) -> Option<PEP695TypeAliasType<'db>> {
match self { match self {
TypeAliasType::PEP695(type_alias) => Some(type_alias), TypeAliasType::PEP695(type_alias) => Some(type_alias),
TypeAliasType::ManualPEP695(_) => None, TypeAliasType::ManualPEP695(_) => None,

View file

@ -421,7 +421,7 @@ impl<'db> UnionBuilder<'db> {
.elements .elements
.iter() .iter()
.filter_map(UnionElement::to_type_element) .filter_map(UnionElement::to_type_element)
.filter_map(Type::into_enum_literal) .filter_map(Type::as_enum_literal)
.map(|literal| literal.name(self.db).clone()) .map(|literal| literal.name(self.db).clone())
.chain(std::iter::once(enum_member_to_add.name(self.db).clone())) .chain(std::iter::once(enum_member_to_add.name(self.db).clone()))
.collect::<FxOrderSet<_>>(); .collect::<FxOrderSet<_>>();
@ -650,7 +650,7 @@ impl<'db> IntersectionBuilder<'db> {
for intersection in &self.intersections { for intersection in &self.intersections {
if intersection.negative.iter().any(|negative| { if intersection.negative.iter().any(|negative| {
negative negative
.into_enum_literal() .as_enum_literal()
.is_some_and(|lit| lit.enum_class_instance(self.db) == ty) .is_some_and(|lit| lit.enum_class_instance(self.db) == ty)
}) { }) {
contains_enum_literal_as_negative_element = true; contains_enum_literal_as_negative_element = true;

View file

@ -378,7 +378,7 @@ impl<'db> Bindings<'db> {
.., ..,
] if property.getter(db).is_some_and(|getter| { ] if property.getter(db).is_some_and(|getter| {
getter getter
.into_function_literal() .as_function_literal()
.is_some_and(|f| f.name(db) == "__name__") .is_some_and(|f| f.name(db) == "__name__")
}) => }) =>
{ {
@ -392,7 +392,7 @@ impl<'db> Bindings<'db> {
] => { ] => {
match property match property
.getter(db) .getter(db)
.and_then(Type::into_function_literal) .and_then(Type::as_function_literal)
.map(|f| f.name(db).as_str()) .map(|f| f.name(db).as_str())
{ {
Some("__name__") => { Some("__name__") => {
@ -785,7 +785,7 @@ impl<'db> Bindings<'db> {
// be a "(specialised) protocol class", but `typing.is_protocol(SupportsAbs[int])` returns // be a "(specialised) protocol class", but `typing.is_protocol(SupportsAbs[int])` returns
// `False` at runtime, so we do not set the return type to `Literal[True]` in this case. // `False` at runtime, so we do not set the return type to `Literal[True]` in this case.
overload.set_return_type(Type::BooleanLiteral( overload.set_return_type(Type::BooleanLiteral(
ty.into_class_literal() ty.as_class_literal()
.is_some_and(|class| class.is_protocol(db)), .is_some_and(|class| class.is_protocol(db)),
)); ));
} }
@ -817,7 +817,7 @@ impl<'db> Bindings<'db> {
continue; continue;
}; };
let Some(attr_name) = attr_name.into_string_literal() else { let Some(attr_name) = attr_name.as_string_literal() else {
continue; continue;
}; };

View file

@ -1724,7 +1724,7 @@ impl<'db> ClassLiteral<'db> {
/// Determine if this is an abstract class. /// Determine if this is an abstract class.
pub(super) fn is_abstract(self, db: &'db dyn Db) -> bool { pub(super) fn is_abstract(self, db: &'db dyn Db) -> bool {
self.metaclass(db) self.metaclass(db)
.into_class_literal() .as_class_literal()
.is_some_and(|metaclass| metaclass.is_known(db, KnownClass::ABCMeta)) .is_some_and(|metaclass| metaclass.is_known(db, KnownClass::ABCMeta))
} }
@ -1758,7 +1758,7 @@ impl<'db> ClassLiteral<'db> {
) -> impl Iterator<Item = KnownFunction> + 'db { ) -> impl Iterator<Item = KnownFunction> + 'db {
self.decorators(db) self.decorators(db)
.iter() .iter()
.filter_map(|deco| deco.into_function_literal()) .filter_map(|deco| deco.as_function_literal())
.filter_map(|decorator| decorator.known(db)) .filter_map(|decorator| decorator.known(db))
} }
@ -2398,7 +2398,7 @@ impl<'db> ClassLiteral<'db> {
(CodeGeneratorKind::NamedTuple, name) if name != "__init__" => { (CodeGeneratorKind::NamedTuple, name) if name != "__init__" => {
KnownClass::NamedTupleFallback KnownClass::NamedTupleFallback
.to_class_literal(db) .to_class_literal(db)
.into_class_literal()? .as_class_literal()?
.own_class_member(db, self.inherited_generic_context(db), None, name) .own_class_member(db, self.inherited_generic_context(db), None, name)
.ignore_possibly_unbound() .ignore_possibly_unbound()
.map(|ty| { .map(|ty| {
@ -5250,7 +5250,7 @@ impl KnownClass {
}; };
overload.set_return_type(Type::KnownInstance(KnownInstanceType::Deprecated( overload.set_return_type(Type::KnownInstance(KnownInstanceType::Deprecated(
DeprecatedInstance::new(db, message.into_string_literal()), DeprecatedInstance::new(db, message.as_string_literal()),
))); )));
} }
@ -5270,7 +5270,7 @@ impl KnownClass {
return; return;
}; };
let Some(name) = name.into_string_literal() else { let Some(name) = name.as_string_literal() else {
if let Some(builder) = if let Some(builder) =
context.report_lint(&INVALID_TYPE_ALIAS_TYPE, call_expression) context.report_lint(&INVALID_TYPE_ALIAS_TYPE, call_expression)
{ {

View file

@ -192,7 +192,7 @@ impl<'db, 'ast> InferContext<'db, 'ast> {
.ancestor_scopes(scope_id) .ancestor_scopes(scope_id)
.filter_map(|(_, scope)| scope.node().as_function()) .filter_map(|(_, scope)| scope.node().as_function())
.map(|node| binding_type(self.db, index.expect_single_definition(node))) .map(|node| binding_type(self.db, index.expect_single_definition(node)))
.filter_map(Type::into_function_literal); .filter_map(Type::as_function_literal);
// Iterate over all functions and test if any is decorated with `@no_type_check`. // Iterate over all functions and test if any is decorated with `@no_type_check`.
function_scope_tys.any(|function_ty| { function_scope_tys.any(|function_ty| {

View file

@ -1145,7 +1145,7 @@ fn is_instance_truthiness<'db>(
fn is_mode_with_nontrivial_return_type<'db>(db: &'db dyn Db, mode: Type<'db>) -> bool { fn is_mode_with_nontrivial_return_type<'db>(db: &'db dyn Db, mode: Type<'db>) -> bool {
// Return true for any mode that doesn't match typeshed's // Return true for any mode that doesn't match typeshed's
// `OpenTextMode` type alias (<https://github.com/python/typeshed/blob/6937a9b193bfc2f0696452d58aad96d7627aa29a/stdlib/_typeshed/__init__.pyi#L220>). // `OpenTextMode` type alias (<https://github.com/python/typeshed/blob/6937a9b193bfc2f0696452d58aad96d7627aa29a/stdlib/_typeshed/__init__.pyi#L220>).
mode.into_string_literal().is_none_or(|mode| { mode.as_string_literal().is_none_or(|mode| {
!matches!( !matches!(
mode.value(db), mode.value(db),
"r+" | "+r" "r+" | "+r"
@ -1557,7 +1557,7 @@ impl KnownFunction {
return; return;
} }
let mut diagnostic = if let Some(message) = message let mut diagnostic = if let Some(message) = message
.and_then(Type::into_string_literal) .and_then(Type::as_string_literal)
.map(|s| s.value(db)) .map(|s| s.value(db))
{ {
builder.into_diagnostic(format_args!("Static assertion error: {message}")) builder.into_diagnostic(format_args!("Static assertion error: {message}"))

View file

@ -35,7 +35,7 @@ pub(crate) fn enclosing_generic_contexts<'db>(
NodeWithScopeKind::Class(class) => { NodeWithScopeKind::Class(class) => {
let definition = index.expect_single_definition(class); let definition = index.expect_single_definition(class);
binding_type(db, definition) binding_type(db, definition)
.into_class_literal()? .as_class_literal()?
.generic_context(db) .generic_context(db)
} }
NodeWithScopeKind::Function(function) => { NodeWithScopeKind::Function(function) => {
@ -43,15 +43,15 @@ pub(crate) fn enclosing_generic_contexts<'db>(
infer_definition_types(db, definition) infer_definition_types(db, definition)
.undecorated_type() .undecorated_type()
.expect("function should have undecorated type") .expect("function should have undecorated type")
.into_function_literal()? .as_function_literal()?
.last_definition_signature(db) .last_definition_signature(db)
.generic_context .generic_context
} }
NodeWithScopeKind::TypeAlias(type_alias) => { NodeWithScopeKind::TypeAlias(type_alias) => {
let definition = index.expect_single_definition(type_alias); let definition = index.expect_single_definition(type_alias);
binding_type(db, definition) binding_type(db, definition)
.into_type_alias()? .as_type_alias()?
.into_pep_695_type_alias()? .as_pep_695_type_alias()?
.generic_context(db) .generic_context(db)
} }
_ => None, _ => None,
@ -1284,7 +1284,7 @@ impl<'db> SpecializationBuilder<'db> {
let types_have_typevars = formal_union let types_have_typevars = formal_union
.elements(self.db) .elements(self.db)
.iter() .iter()
.filter(|ty| ty.has_type_var(self.db)); .filter(|ty| ty.has_typevar(self.db));
let Ok(Type::TypeVar(formal_bound_typevar)) = types_have_typevars.exactly_one() let Ok(Type::TypeVar(formal_bound_typevar)) = types_have_typevars.exactly_one()
else { else {
return Ok(()); return Ok(());
@ -1305,7 +1305,7 @@ impl<'db> SpecializationBuilder<'db> {
// type. (Note that we've already handled above the case where the actual is // type. (Note that we've already handled above the case where the actual is
// assignable to any _non-typevar_ union element.) // assignable to any _non-typevar_ union element.)
let bound_typevars = let bound_typevars =
(formal.elements(self.db).iter()).filter_map(|ty| ty.into_type_var()); (formal.elements(self.db).iter()).filter_map(|ty| ty.as_typevar());
if let Ok(bound_typevar) = bound_typevars.exactly_one() { if let Ok(bound_typevar) = bound_typevars.exactly_one() {
self.add_type_mapping(bound_typevar, actual); self.add_type_mapping(bound_typevar, actual);
} }

View file

@ -777,7 +777,7 @@ pub fn definitions_for_keyword_argument<'db>(
let mut resolved_definitions = Vec::new(); let mut resolved_definitions = Vec::new();
if let Some(Type::Callable(callable_type)) = func_type.into_callable(db) { if let Some(Type::Callable(callable_type)) = func_type.try_upcast_to_callable(db) {
let signatures = callable_type.signatures(db); let signatures = callable_type.signatures(db);
// For each signature, find the parameter with the matching name // For each signature, find the parameter with the matching name
@ -872,7 +872,7 @@ pub fn call_signature_details<'db>(
let func_type = call_expr.func.inferred_type(model); let func_type = call_expr.func.inferred_type(model);
// Use into_callable to handle all the complex type conversions // Use into_callable to handle all the complex type conversions
if let Some(callable_type) = func_type.into_callable(db) { if let Some(callable_type) = func_type.try_upcast_to_callable(db) {
let call_arguments = let call_arguments =
CallArguments::from_arguments(&call_expr.arguments, |_, splatted_value| { CallArguments::from_arguments(&call_expr.arguments, |_, splatted_value| {
splatted_value.inferred_type(model) splatted_value.inferred_type(model)

View file

@ -490,7 +490,7 @@ pub(crate) fn nearest_enclosing_class<'db>(
infer_definition_types(db, definition) infer_definition_types(db, definition)
.declaration_type(definition) .declaration_type(definition)
.inner_type() .inner_type()
.into_class_literal() .as_class_literal()
}) })
} }
@ -514,7 +514,7 @@ pub(crate) fn nearest_enclosing_function<'db>(
inference inference
.undecorated_type() .undecorated_type()
.unwrap_or_else(|| inference.declaration_type(definition).inner_type()) .unwrap_or_else(|| inference.declaration_type(definition).inner_type())
.into_function_literal() .as_function_literal()
}) })
} }

View file

@ -531,7 +531,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// Filter out class literals that result from imports // Filter out class literals that result from imports
if let DefinitionKind::Class(class) = definition.kind(self.db()) { if let DefinitionKind::Class(class) = definition.kind(self.db()) {
ty.inner_type() ty.inner_type()
.into_class_literal() .as_class_literal()
.map(|class_literal| (class_literal, class.node(self.module()))) .map(|class_literal| (class_literal, class.node(self.module())))
} else { } else {
None None
@ -939,7 +939,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
if !matches!(definition.kind(self.db()), DefinitionKind::Function(_)) { if !matches!(definition.kind(self.db()), DefinitionKind::Function(_)) {
return None; return None;
} }
let function = ty.inner_type().into_function_literal()?; let function = ty.inner_type().as_function_literal()?;
if function.has_known_decorator(self.db(), FunctionDecorators::OVERLOAD) { if function.has_known_decorator(self.db(), FunctionDecorators::OVERLOAD) {
Some(definition.place(self.db())) Some(definition.place(self.db()))
} else { } else {
@ -2200,12 +2200,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
{ {
Ok(return_ty) => { Ok(return_ty) => {
let is_input_function_like = inferred_ty let is_input_function_like = inferred_ty
.into_callable(self.db()) .try_upcast_to_callable(self.db())
.and_then(Type::unwrap_as_callable_type) .and_then(Type::as_callable)
.is_some_and(|callable| callable.is_function_like(self.db())); .is_some_and(|callable| callable.is_function_like(self.db()));
if is_input_function_like if is_input_function_like && let Some(callable_type) = return_ty.as_callable() {
&& let Some(callable_type) = return_ty.unwrap_as_callable_type()
{
// When a method on a class is decorated with a function that returns a `Callable`, assume that // When a method on a class is decorated with a function that returns a `Callable`, assume that
// the returned callable is also function-like. See "Decorating a method with a `Callable`-typed // the returned callable is also function-like. See "Decorating a method with a `Callable`-typed
// decorator" in `callables_as_descriptors.md` for the extended explanation. // decorator" in `callables_as_descriptors.md` for the extended explanation.
@ -2546,7 +2544,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
for decorator in decorator_list { for decorator in decorator_list {
let decorator_ty = self.infer_decorator(decorator); let decorator_ty = self.infer_decorator(decorator);
if decorator_ty if decorator_ty
.into_function_literal() .as_function_literal()
.is_some_and(|function| function.is_known(self.db(), KnownFunction::Dataclass)) .is_some_and(|function| function.is_known(self.db(), KnownFunction::Dataclass))
{ {
dataclass_params = Some(DataclassParams::default()); dataclass_params = Some(DataclassParams::default());
@ -3342,8 +3340,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let assigned_d = assigned_ty.display(db); let assigned_d = assigned_ty.display(db);
let value_d = value_ty.display(db); let value_d = value_ty.display(db);
if let Some(typed_dict) = value_ty.into_typed_dict() { if let Some(typed_dict) = value_ty.as_typed_dict() {
if let Some(key) = slice_ty.into_string_literal() { if let Some(key) = slice_ty.as_string_literal() {
let key = key.value(self.db()); let key = key.value(self.db());
validate_typed_dict_key_assignment( validate_typed_dict_key_assignment(
&self.context, &self.context,
@ -4056,7 +4054,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
); );
let typevar_class = callable_type let typevar_class = callable_type
.into_class_literal() .as_class_literal()
.and_then(|cls| cls.known(self.db())) .and_then(|cls| cls.known(self.db()))
.filter(|cls| { .filter(|cls| {
matches!(cls, KnownClass::TypeVar | KnownClass::ExtensionsTypeVar) matches!(cls, KnownClass::TypeVar | KnownClass::ExtensionsTypeVar)
@ -4278,10 +4276,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
); );
}; };
let Some(name_param) = name_param_ty let Some(name_param) = name_param_ty.as_string_literal().map(|name| name.value(db)) else {
.into_string_literal()
.map(|name| name.value(db))
else {
return error( return error(
&self.context, &self.context,
"The first argument to `TypeVar` must be a string literal.", "The first argument to `TypeVar` must be a string literal.",
@ -5036,7 +5031,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// Avoid looking up attributes on a module if a module imports from itself // Avoid looking up attributes on a module if a module imports from itself
// (e.g. `from parent import submodule` inside the `parent` module). // (e.g. `from parent import submodule` inside the `parent` module).
let import_is_self_referential = module_ty let import_is_self_referential = module_ty
.into_module_literal() .as_module_literal()
.is_some_and(|module| Some(self.file()) == module.module(self.db()).file(self.db())); .is_some_and(|module| Some(self.file()) == module.module(self.db()).file(self.db()));
// First try loading the requested attribute from the module. // First try loading the requested attribute from the module.
@ -5871,7 +5866,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
} = dict; } = dict;
// Validate `TypedDict` dictionary literal assignments. // Validate `TypedDict` dictionary literal assignments.
if let Some(typed_dict) = tcx.annotation.and_then(Type::into_typed_dict) if let Some(typed_dict) = tcx.annotation.and_then(Type::as_typed_dict)
&& let Some(ty) = self.infer_typed_dict_expression(dict, typed_dict) && let Some(ty) = self.infer_typed_dict_expression(dict, typed_dict)
{ {
return ty; return ty;
@ -6595,10 +6590,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
self.infer_all_argument_types(arguments, &mut call_arguments, &bindings); self.infer_all_argument_types(arguments, &mut call_arguments, &bindings);
// Validate `TypedDict` constructor calls after argument type inference // Validate `TypedDict` constructor calls after argument type inference
if let Some(class_literal) = callable_type.into_class_literal() { if let Some(class_literal) = callable_type.as_class_literal() {
if class_literal.is_typed_dict(self.db()) { if class_literal.is_typed_dict(self.db()) {
let typed_dict_type = Type::typed_dict(ClassType::NonGeneric(class_literal)); let typed_dict_type = Type::typed_dict(ClassType::NonGeneric(class_literal));
if let Some(typed_dict) = typed_dict_type.into_typed_dict() { if let Some(typed_dict) = typed_dict_type.as_typed_dict() {
validate_typed_dict_constructor( validate_typed_dict_constructor(
&self.context, &self.context,
typed_dict, typed_dict,
@ -9459,7 +9454,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
} }
} }
CallErrorKind::BindingError => { CallErrorKind::BindingError => {
if let Some(typed_dict) = value_ty.into_typed_dict() { if let Some(typed_dict) = value_ty.as_typed_dict() {
let slice_node = subscript.slice.as_ref(); let slice_node = subscript.slice.as_ref();
report_invalid_key_on_typed_dict( report_invalid_key_on_typed_dict(
@ -9566,7 +9561,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// TODO: properly handle old-style generics; get rid of this temporary hack // TODO: properly handle old-style generics; get rid of this temporary hack
if !value_ty if !value_ty
.into_class_literal() .as_class_literal()
.is_some_and(|class| class.iter_mro(db, None).contains(&ClassBase::Generic)) .is_some_and(|class| class.iter_mro(db, None).contains(&ClassBase::Generic))
{ {
report_non_subscriptable(context, value_node.into(), value_ty, "__class_getitem__"); report_non_subscriptable(context, value_node.into(), value_ty, "__class_getitem__");

View file

@ -1157,7 +1157,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
let argument_type = self.infer_expression(&arguments[0], TypeContext::default()); let argument_type = self.infer_expression(&arguments[0], TypeContext::default());
let Some(callable_type) = argument_type.into_callable(db) else { let Some(callable_type) = argument_type.try_upcast_to_callable(db) else {
if let Some(builder) = self if let Some(builder) = self
.context .context
.report_lint(&INVALID_TYPE_FORM, arguments_slice) .report_lint(&INVALID_TYPE_FORM, arguments_slice)

View file

@ -165,7 +165,7 @@ impl<'db> Type<'db> {
// from a protocol `Q` to be a subtype of `Q` to be a subtype of `Q` if it overrides // from a protocol `Q` to be a subtype of `Q` to be a subtype of `Q` if it overrides
// `Q`'s members in a Liskov-incompatible way. // `Q`'s members in a Liskov-incompatible way.
let type_to_test = self let type_to_test = self
.into_protocol_instance() .as_protocol_instance()
.and_then(ProtocolInstanceType::as_nominal_type) .and_then(ProtocolInstanceType::as_nominal_type)
.map(Type::NominalInstance) .map(Type::NominalInstance)
.unwrap_or(self); .unwrap_or(self);

View file

@ -634,7 +634,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
// Add the narrowed values from the RHS first, to keep literals before broader types. // Add the narrowed values from the RHS first, to keep literals before broader types.
builder = builder.add(rhs_values); builder = builder.add(rhs_values);
if let Some(lhs_union) = lhs_ty.into_union() { if let Some(lhs_union) = lhs_ty.as_union() {
for element in lhs_union.elements(self.db) { for element in lhs_union.elements(self.db) {
// Keep only the non-single-valued portion of the original type. // Keep only the non-single-valued portion of the original type.
if !element.is_single_valued(self.db) if !element.is_single_valued(self.db)
@ -671,7 +671,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
let mut single_builder = UnionBuilder::new(self.db); let mut single_builder = UnionBuilder::new(self.db);
let mut rest_builder = UnionBuilder::new(self.db); let mut rest_builder = UnionBuilder::new(self.db);
if let Some(lhs_union) = lhs_ty.into_union() { if let Some(lhs_union) = lhs_ty.as_union() {
for element in lhs_union.elements(self.db) { for element in lhs_union.elements(self.db) {
if element.is_single_valued(self.db) if element.is_single_valued(self.db)
|| element.is_literal_string() || element.is_literal_string()
@ -840,7 +840,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
let callable_type = inference.expression_type(&**callable); let callable_type = inference.expression_type(&**callable);
if callable_type if callable_type
.into_class_literal() .as_class_literal()
.is_some_and(|c| c.is_known(self.db, KnownClass::Type)) .is_some_and(|c| c.is_known(self.db, KnownClass::Type))
{ {
let place = self.expect_place(&target); let place = self.expect_place(&target);
@ -903,7 +903,7 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
if function == KnownFunction::HasAttr { if function == KnownFunction::HasAttr {
let attr = inference let attr = inference
.expression_type(second_arg) .expression_type(second_arg)
.into_string_literal()? .as_string_literal()?
.value(self.db); .value(self.db);
if !is_identifier(attr) { if !is_identifier(attr) {

View file

@ -641,7 +641,7 @@ impl<'a, 'db> ProtocolMember<'a, 'db> {
// unfortunately not sufficient to obtain the `Callable` supertypes of these types, due to the // unfortunately not sufficient to obtain the `Callable` supertypes of these types, due to the
// complex interaction between `__new__`, `__init__` and metaclass `__call__`. // complex interaction between `__new__`, `__init__` and metaclass `__call__`.
let attribute_type = if self.name == "__call__" { let attribute_type = if self.name == "__call__" {
let Some(attribute_type) = other.into_callable(db) else { let Some(attribute_type) = other.try_upcast_to_callable(db) else {
return ConstraintSet::from(false); return ConstraintSet::from(false);
}; };
attribute_type attribute_type

View file

@ -55,7 +55,7 @@ fn infer_method_information<'db>(
let method = infer_definition_types(db, definition) let method = infer_definition_types(db, definition)
.declaration_type(definition) .declaration_type(definition)
.inner_type() .inner_type()
.into_function_literal()?; .as_function_literal()?;
let class_def = index.expect_single_definition(class_node); let class_def = index.expect_single_definition(class_node);
let (class_literal, class_is_generic) = match infer_definition_types(db, class_def) let (class_literal, class_is_generic) = match infer_definition_types(db, class_def)