mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 14:52:01 +00:00
[red-knot] Reduce some repetitiveness in tests (#13135)
This commit is contained in:
parent
facf6febf0
commit
9d517061f2
4 changed files with 136 additions and 97 deletions
|
@ -152,9 +152,9 @@ pub(crate) fn definitions_ty<'db>(
|
|||
);
|
||||
let mut all_types = unbound_ty.into_iter().chain(def_types);
|
||||
|
||||
let Some(first) = all_types.next() else {
|
||||
panic!("definitions_ty should never be called with zero definitions and no unbound_ty.")
|
||||
};
|
||||
let first = all_types
|
||||
.next()
|
||||
.expect("definitions_ty should never be called with zero definitions and no unbound_ty.");
|
||||
|
||||
if let Some(second) = all_types.next() {
|
||||
let mut builder = UnionBuilder::new(db);
|
||||
|
@ -171,7 +171,7 @@ pub(crate) fn definitions_ty<'db>(
|
|||
}
|
||||
|
||||
/// Unique ID for a type.
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Type<'db> {
|
||||
/// the dynamic type: a statically-unknown set of values
|
||||
Any,
|
||||
|
@ -216,10 +216,6 @@ impl<'db> Type<'db> {
|
|||
matches!(self, Type::Unbound)
|
||||
}
|
||||
|
||||
pub const fn is_unknown(&self) -> bool {
|
||||
matches!(self, Type::Unknown)
|
||||
}
|
||||
|
||||
pub const fn is_never(&self) -> bool {
|
||||
matches!(self, Type::Never)
|
||||
}
|
||||
|
@ -237,6 +233,78 @@ impl<'db> Type<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
pub const fn into_class_type(self) -> Option<ClassType<'db>> {
|
||||
match self {
|
||||
Type::Class(class_type) => Some(class_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_class(self) -> ClassType<'db> {
|
||||
self.into_class_type()
|
||||
.expect("Expected a Type::Class variant")
|
||||
}
|
||||
|
||||
pub const fn into_module_type(self) -> Option<File> {
|
||||
match self {
|
||||
Type::Module(file) => Some(file),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_module(self) -> File {
|
||||
self.into_module_type()
|
||||
.expect("Expected a Type::Module variant")
|
||||
}
|
||||
|
||||
pub const fn into_union_type(self) -> Option<UnionType<'db>> {
|
||||
match self {
|
||||
Type::Union(union_type) => Some(union_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_union(self) -> UnionType<'db> {
|
||||
self.into_union_type()
|
||||
.expect("Expected a Type::Union variant")
|
||||
}
|
||||
|
||||
pub const fn into_intersection_type(self) -> Option<IntersectionType<'db>> {
|
||||
match self {
|
||||
Type::Intersection(intersection_type) => Some(intersection_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_intersection(self) -> IntersectionType<'db> {
|
||||
self.into_intersection_type()
|
||||
.expect("Expected a Type::Intersection variant")
|
||||
}
|
||||
|
||||
pub const fn into_function_type(self) -> Option<FunctionType<'db>> {
|
||||
match self {
|
||||
Type::Function(function_type) => Some(function_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_function(self) -> FunctionType<'db> {
|
||||
self.into_function_type()
|
||||
.expect("Expected a Type::Function variant")
|
||||
}
|
||||
|
||||
pub const fn into_int_literal_type(self) -> Option<i64> {
|
||||
match self {
|
||||
Type::IntLiteral(value) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_int_literal(self) -> i64 {
|
||||
self.into_int_literal_type()
|
||||
.expect("Expected a Type::IntLiteral variant")
|
||||
}
|
||||
|
||||
pub fn may_be_unbound(&self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
Type::Unbound => true,
|
||||
|
@ -361,7 +429,7 @@ impl<'db> Type<'db> {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn instance(&self) -> Type<'db> {
|
||||
pub fn to_instance(&self) -> Type<'db> {
|
||||
match self {
|
||||
Type::Any => Type::Any,
|
||||
Type::Unknown => Type::Unknown,
|
||||
|
|
|
@ -313,9 +313,11 @@ mod tests {
|
|||
let db = setup_db();
|
||||
let t0 = Type::IntLiteral(0);
|
||||
let t1 = Type::IntLiteral(1);
|
||||
let Type::Union(union) = UnionBuilder::new(&db).add(t0).add(t1).build() else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
let union = UnionBuilder::new(&db)
|
||||
.add(t0)
|
||||
.add(t1)
|
||||
.build()
|
||||
.expect_union();
|
||||
|
||||
assert_eq!(union.elements_vec(&db), &[t0, t1]);
|
||||
}
|
||||
|
@ -356,19 +358,20 @@ mod tests {
|
|||
let t2 = Type::BooleanLiteral(false);
|
||||
let t3 = Type::IntLiteral(17);
|
||||
|
||||
let Type::Union(union) = UnionBuilder::new(&db).add(t0).add(t1).add(t3).build() else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
let union = UnionBuilder::new(&db)
|
||||
.add(t0)
|
||||
.add(t1)
|
||||
.add(t3)
|
||||
.build()
|
||||
.expect_union();
|
||||
assert_eq!(union.elements_vec(&db), &[t0, t3]);
|
||||
let Type::Union(union) = UnionBuilder::new(&db)
|
||||
let union = UnionBuilder::new(&db)
|
||||
.add(t0)
|
||||
.add(t1)
|
||||
.add(t2)
|
||||
.add(t3)
|
||||
.build()
|
||||
else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
.expect_union();
|
||||
|
||||
assert_eq!(union.elements_vec(&db), &[bool_ty, t3]);
|
||||
}
|
||||
|
@ -380,9 +383,11 @@ mod tests {
|
|||
let t1 = Type::IntLiteral(1);
|
||||
let t2 = Type::IntLiteral(2);
|
||||
let u1 = UnionBuilder::new(&db).add(t0).add(t1).build();
|
||||
let Type::Union(union) = UnionBuilder::new(&db).add(u1).add(t2).build() else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
let union = UnionBuilder::new(&db)
|
||||
.add(u1)
|
||||
.add(t2)
|
||||
.build()
|
||||
.expect_union();
|
||||
|
||||
assert_eq!(union.elements_vec(&db), &[t0, t1, t2]);
|
||||
}
|
||||
|
@ -402,16 +407,14 @@ mod tests {
|
|||
let db = setup_db();
|
||||
let t0 = Type::IntLiteral(0);
|
||||
let ta = Type::Any;
|
||||
let Type::Intersection(inter) = IntersectionBuilder::new(&db)
|
||||
let intersection = IntersectionBuilder::new(&db)
|
||||
.add_positive(ta)
|
||||
.add_negative(t0)
|
||||
.build()
|
||||
else {
|
||||
panic!("expected to be an intersection");
|
||||
};
|
||||
.expect_intersection();
|
||||
|
||||
assert_eq!(inter.pos_vec(&db), &[ta]);
|
||||
assert_eq!(inter.neg_vec(&db), &[t0]);
|
||||
assert_eq!(intersection.pos_vec(&db), &[ta]);
|
||||
assert_eq!(intersection.neg_vec(&db), &[t0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -424,16 +427,14 @@ mod tests {
|
|||
.add_positive(ta)
|
||||
.add_negative(t1)
|
||||
.build();
|
||||
let Type::Intersection(inter) = IntersectionBuilder::new(&db)
|
||||
let intersection = IntersectionBuilder::new(&db)
|
||||
.add_positive(t2)
|
||||
.add_positive(i0)
|
||||
.build()
|
||||
else {
|
||||
panic!("expected to be an intersection");
|
||||
};
|
||||
.expect_intersection();
|
||||
|
||||
assert_eq!(inter.pos_vec(&db), &[t2, ta]);
|
||||
assert_eq!(inter.neg_vec(&db), &[t1]);
|
||||
assert_eq!(intersection.pos_vec(&db), &[t2, ta]);
|
||||
assert_eq!(intersection.neg_vec(&db), &[t1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -446,16 +447,14 @@ mod tests {
|
|||
.add_positive(ta)
|
||||
.add_negative(t1)
|
||||
.build();
|
||||
let Type::Intersection(inter) = IntersectionBuilder::new(&db)
|
||||
let intersection = IntersectionBuilder::new(&db)
|
||||
.add_positive(t2)
|
||||
.add_negative(i0)
|
||||
.build()
|
||||
else {
|
||||
panic!("expected to be an intersection");
|
||||
};
|
||||
.expect_intersection();
|
||||
|
||||
assert_eq!(inter.pos_vec(&db), &[t2, t1]);
|
||||
assert_eq!(inter.neg_vec(&db), &[ta]);
|
||||
assert_eq!(intersection.pos_vec(&db), &[t2, t1]);
|
||||
assert_eq!(intersection.neg_vec(&db), &[ta]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -466,13 +465,11 @@ mod tests {
|
|||
let ta = Type::Any;
|
||||
let u0 = UnionBuilder::new(&db).add(t0).add(t1).build();
|
||||
|
||||
let Type::Union(union) = IntersectionBuilder::new(&db)
|
||||
let union = IntersectionBuilder::new(&db)
|
||||
.add_positive(ta)
|
||||
.add_positive(u0)
|
||||
.build()
|
||||
else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
.expect_union();
|
||||
let [Type::Intersection(i0), Type::Intersection(i1)] = union.elements_vec(&db)[..] else {
|
||||
panic!("expected a union of two intersections");
|
||||
};
|
||||
|
|
|
@ -125,10 +125,7 @@ impl Display for DisplayUnionType<'_> {
|
|||
f.write_str("Literal[")?;
|
||||
|
||||
if literal_kind == LiteralTypeKind::IntLiteral {
|
||||
literals.sort_unstable_by_key(|ty| match ty {
|
||||
Type::IntLiteral(n) => *n,
|
||||
_ => panic!("Expected only int literals when kind is IntLiteral"),
|
||||
});
|
||||
literals.sort_unstable_by_key(|ty| ty.expect_int_literal());
|
||||
}
|
||||
|
||||
for (i, literal_ty) in literals.iter().enumerate() {
|
||||
|
@ -294,9 +291,7 @@ mod tests {
|
|||
let builder = vec.iter().fold(UnionBuilder::new(&db), |builder, literal| {
|
||||
builder.add(*literal)
|
||||
});
|
||||
let Type::Union(union) = builder.build() else {
|
||||
panic!("expected a union");
|
||||
};
|
||||
let union = builder.build().expect_union();
|
||||
let display = format!("{}", union.display(&db));
|
||||
assert_eq!(
|
||||
display,
|
||||
|
|
|
@ -463,9 +463,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
fn infer_function_type_params(&mut self, function: &ast::StmtFunctionDef) {
|
||||
let Some(type_params) = function.type_params.as_deref() else {
|
||||
panic!("function type params scope without type params");
|
||||
};
|
||||
let type_params = function
|
||||
.type_params
|
||||
.as_deref()
|
||||
.expect("function type params scope without type params");
|
||||
|
||||
// TODO: this should also be applied to parameter annotations.
|
||||
if !self.is_stub() {
|
||||
|
@ -1398,10 +1399,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
ast::Number::Int(n) => n
|
||||
.as_i64()
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").instance()),
|
||||
ast::Number::Float(_) => builtins_symbol_ty_by_name(self.db, "float").instance(),
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").to_instance()),
|
||||
ast::Number::Float(_) => builtins_symbol_ty_by_name(self.db, "float").to_instance(),
|
||||
ast::Number::Complex { .. } => {
|
||||
builtins_symbol_ty_by_name(self.db, "complex").instance()
|
||||
builtins_symbol_ty_by_name(self.db, "complex").to_instance()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1501,7 +1502,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
// TODO generic
|
||||
builtins_symbol_ty_by_name(self.db, "tuple").instance()
|
||||
builtins_symbol_ty_by_name(self.db, "tuple").to_instance()
|
||||
}
|
||||
|
||||
fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
|
||||
|
@ -1516,7 +1517,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
// TODO generic
|
||||
builtins_symbol_ty_by_name(self.db, "list").instance()
|
||||
builtins_symbol_ty_by_name(self.db, "list").to_instance()
|
||||
}
|
||||
|
||||
fn infer_set_expression(&mut self, set: &ast::ExprSet) -> Type<'db> {
|
||||
|
@ -1527,7 +1528,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
// TODO generic
|
||||
builtins_symbol_ty_by_name(self.db, "set").instance()
|
||||
builtins_symbol_ty_by_name(self.db, "set").to_instance()
|
||||
}
|
||||
|
||||
fn infer_dict_expression(&mut self, dict: &ast::ExprDict) -> Type<'db> {
|
||||
|
@ -1539,7 +1540,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
|
||||
// TODO generic
|
||||
builtins_symbol_ty_by_name(self.db, "dict").instance()
|
||||
builtins_symbol_ty_by_name(self.db, "dict").to_instance()
|
||||
}
|
||||
|
||||
/// Infer the type of the `iter` expression of the first comprehension.
|
||||
|
@ -1927,22 +1928,22 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Add) => n
|
||||
.checked_add(m)
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").instance()),
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").to_instance()),
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Sub) => n
|
||||
.checked_sub(m)
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").instance()),
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").to_instance()),
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Mult) => n
|
||||
.checked_mul(m)
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").instance()),
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").to_instance()),
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Div) => n
|
||||
.checked_div(m)
|
||||
.map(Type::IntLiteral)
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").instance()),
|
||||
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int").to_instance()),
|
||||
|
||||
(Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Mod) => n
|
||||
.checked_rem(m)
|
||||
|
@ -2152,7 +2153,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
name.ctx
|
||||
);
|
||||
|
||||
self.infer_name_expression(name).instance()
|
||||
self.infer_name_expression(name).to_instance()
|
||||
}
|
||||
|
||||
ast::Expr::NoneLiteral(_literal) => Type::None,
|
||||
|
@ -2328,7 +2329,7 @@ mod tests {
|
|||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::symbol::FileScopeId;
|
||||
use crate::semantic_index::{global_scope, semantic_index, symbol_table, use_def_map};
|
||||
use crate::types::{global_symbol_ty_by_name, infer_definition_types, symbol_ty_by_name, Type};
|
||||
use crate::types::{global_symbol_ty_by_name, infer_definition_types, symbol_ty_by_name};
|
||||
use crate::{HasTy, ProgramSettings, SemanticModel};
|
||||
|
||||
use super::TypeInferenceBuilder;
|
||||
|
@ -2587,9 +2588,7 @@ mod tests {
|
|||
let mod_file = system_path_to_file(&db, "src/mod.py").expect("Expected file to exist.");
|
||||
let ty = global_symbol_ty_by_name(&db, mod_file, "Sub");
|
||||
|
||||
let Type::Class(class) = ty else {
|
||||
panic!("Sub is not a Class")
|
||||
};
|
||||
let class = ty.expect_class();
|
||||
|
||||
let base_names: Vec<_> = class
|
||||
.bases(&db)
|
||||
|
@ -2615,19 +2614,11 @@ mod tests {
|
|||
|
||||
let mod_file = system_path_to_file(&db, "src/mod.py").unwrap();
|
||||
let ty = global_symbol_ty_by_name(&db, mod_file, "C");
|
||||
|
||||
let Type::Class(class_id) = ty else {
|
||||
panic!("C is not a Class");
|
||||
};
|
||||
|
||||
let class_id = ty.expect_class();
|
||||
let member_ty = class_id.class_member(&db, &Name::new_static("f"));
|
||||
|
||||
let Type::Function(func) = member_ty else {
|
||||
panic!("C.f is not a Function");
|
||||
};
|
||||
let func = member_ty.expect_function();
|
||||
|
||||
assert_eq!(func.name(&db), "f");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -2826,11 +2817,7 @@ mod tests {
|
|||
db.write_file("src/a.py", "def example() -> int: return 42")?;
|
||||
|
||||
let mod_file = system_path_to_file(&db, "src/a.py").unwrap();
|
||||
let ty = global_symbol_ty_by_name(&db, mod_file, "example");
|
||||
let Type::Function(function) = ty else {
|
||||
panic!("example is not a function");
|
||||
};
|
||||
|
||||
let function = global_symbol_ty_by_name(&db, mod_file, "example").expect_function();
|
||||
let returns = function.return_type(&db);
|
||||
assert_eq!(returns.display(&db).to_string(), "int");
|
||||
|
||||
|
@ -3248,20 +3235,14 @@ mod tests {
|
|||
|
||||
let a = system_path_to_file(&db, "src/a.py").expect("Expected file to exist.");
|
||||
let c_ty = global_symbol_ty_by_name(&db, a, "C");
|
||||
let Type::Class(c_class) = c_ty else {
|
||||
panic!("C is not a Class")
|
||||
};
|
||||
let c_class = c_ty.expect_class();
|
||||
let mut c_bases = c_class.bases(&db);
|
||||
let b_ty = c_bases.next().unwrap();
|
||||
let Type::Class(b_class) = b_ty else {
|
||||
panic!("B is not a Class")
|
||||
};
|
||||
let b_class = b_ty.expect_class();
|
||||
assert_eq!(b_class.name(&db), "B");
|
||||
let mut b_bases = b_class.bases(&db);
|
||||
let a_ty = b_bases.next().unwrap();
|
||||
let Type::Class(a_class) = a_ty else {
|
||||
panic!("A is not a Class")
|
||||
};
|
||||
let a_class = a_ty.expect_class();
|
||||
assert_eq!(a_class.name(&db), "A");
|
||||
|
||||
Ok(())
|
||||
|
@ -3481,9 +3462,7 @@ mod tests {
|
|||
// imported builtins module is the same file as the implicit builtins
|
||||
let file = system_path_to_file(&db, "/src/a.py").expect("Expected file to exist.");
|
||||
let builtins_ty = global_symbol_ty_by_name(&db, file, "builtins");
|
||||
let Type::Module(builtins_file) = builtins_ty else {
|
||||
panic!("Builtins are not a module?");
|
||||
};
|
||||
let builtins_file = builtins_ty.expect_module();
|
||||
let implicit_builtins_file = builtins_scope(&db).expect("builtins to exist").file(&db);
|
||||
assert_eq!(builtins_file, implicit_builtins_file);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue