mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Remove special casing for string-literal-in-tuple __contains__
(#19642)
This commit is contained in:
parent
32c454bb56
commit
27b03a9d7b
6 changed files with 156 additions and 243 deletions
|
@ -78,7 +78,7 @@ use crate::types::visitor::any_over_type;
|
|||
use crate::types::{
|
||||
BoundMethodType, CallableType, ClassLiteral, ClassType, DeprecatedInstance, DynamicType,
|
||||
KnownClass, Truthiness, Type, TypeMapping, TypeRelation, TypeTransformer, TypeVarInstance,
|
||||
UnionBuilder, walk_type_mapping,
|
||||
UnionBuilder, all_members, walk_type_mapping,
|
||||
};
|
||||
use crate::{Db, FxOrderSet, ModuleName, resolve_module};
|
||||
|
||||
|
@ -1082,6 +1082,8 @@ pub enum KnownFunction {
|
|||
EnumMembers,
|
||||
/// `ty_extensions.all_members`
|
||||
AllMembers,
|
||||
/// `ty_extensions.has_member`
|
||||
HasMember,
|
||||
/// `ty_extensions.top_materialization`
|
||||
TopMaterialization,
|
||||
/// `ty_extensions.bottom_materialization`
|
||||
|
@ -1150,6 +1152,7 @@ impl KnownFunction {
|
|||
| Self::DunderAllNames
|
||||
| Self::EnumMembers
|
||||
| Self::StaticAssert
|
||||
| Self::HasMember
|
||||
| Self::AllMembers => module.is_ty_extensions(),
|
||||
Self::ImportModule => module.is_importlib(),
|
||||
}
|
||||
|
@ -1186,6 +1189,16 @@ impl KnownFunction {
|
|||
}
|
||||
}
|
||||
|
||||
KnownFunction::HasMember => {
|
||||
let [Some(ty), Some(Type::StringLiteral(member))] = parameter_types else {
|
||||
return;
|
||||
};
|
||||
let ty_members = all_members(db, *ty);
|
||||
overload.set_return_type(Type::BooleanLiteral(
|
||||
ty_members.iter().any(|m| m.name == member.value(db)),
|
||||
));
|
||||
}
|
||||
|
||||
KnownFunction::AssertType => {
|
||||
let [Some(actual_ty), Some(asserted_ty)] = parameter_types else {
|
||||
return;
|
||||
|
@ -1444,6 +1457,7 @@ pub(crate) mod tests {
|
|||
| KnownFunction::IsEquivalentTo
|
||||
| KnownFunction::TopMaterialization
|
||||
| KnownFunction::BottomMaterialization
|
||||
| KnownFunction::HasMember
|
||||
| KnownFunction::AllMembers => KnownModule::TyExtensions,
|
||||
|
||||
KnownFunction::ImportModule => KnownModule::ImportLib,
|
||||
|
|
|
@ -7691,38 +7691,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
right: Type<'db>,
|
||||
range: TextRange,
|
||||
) -> Result<Type<'db>, CompareUnsupportedError<'db>> {
|
||||
let is_str_literal_in_tuple = |literal: Type<'db>, tuple: TupleType<'db>| {
|
||||
// Protect against doing a lot of work for pathologically large
|
||||
// tuples.
|
||||
//
|
||||
// Ref: https://github.com/astral-sh/ruff/pull/18251#discussion_r2115909311
|
||||
let (minimum_length, _) = tuple.tuple(self.db()).len().size_hint();
|
||||
if minimum_length > 1 << 12 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut definitely_true = false;
|
||||
let mut definitely_false = true;
|
||||
for element in tuple.tuple(self.db()).all_elements().copied() {
|
||||
if element.is_string_literal() {
|
||||
if literal == element {
|
||||
definitely_true = true;
|
||||
definitely_false = false;
|
||||
}
|
||||
} else if !literal.is_disjoint_from(self.db(), element) {
|
||||
definitely_false = false;
|
||||
}
|
||||
}
|
||||
|
||||
if definitely_true {
|
||||
Some(true)
|
||||
} else if definitely_false {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Note: identity (is, is not) for equal builtin types is unreliable and not part of the
|
||||
// language spec.
|
||||
// - `[ast::CompOp::Is]`: return `false` if unequal, `bool` if equal
|
||||
|
@ -7854,30 +7822,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
}
|
||||
}
|
||||
(Type::StringLiteral(_), Type::Tuple(tuple)) if op == ast::CmpOp::In => {
|
||||
if let Some(answer) = is_str_literal_in_tuple(left, tuple) {
|
||||
return Ok(Type::BooleanLiteral(answer));
|
||||
}
|
||||
|
||||
self.infer_binary_type_comparison(
|
||||
KnownClass::Str.to_instance(self.db()),
|
||||
op,
|
||||
right,
|
||||
range,
|
||||
)
|
||||
}
|
||||
(Type::StringLiteral(_), Type::Tuple(tuple)) if op == ast::CmpOp::NotIn => {
|
||||
if let Some(answer) = is_str_literal_in_tuple(left, tuple) {
|
||||
return Ok(Type::BooleanLiteral(!answer));
|
||||
}
|
||||
|
||||
self.infer_binary_type_comparison(
|
||||
KnownClass::Str.to_instance(self.db()),
|
||||
op,
|
||||
right,
|
||||
range,
|
||||
)
|
||||
}
|
||||
(Type::StringLiteral(_), _) => self.infer_binary_type_comparison(
|
||||
KnownClass::Str.to_instance(self.db()),
|
||||
op,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue