mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
[red-knot] resolve int/list/dict/set/tuple to builtin type (#12521)
Now that we have builtins available, resolve some simple cases to the right builtin type. We should also adjust the display for types to include their module name; that's not done yet here.
This commit is contained in:
parent
bf23d38a21
commit
4b69271809
2 changed files with 102 additions and 23 deletions
|
@ -43,14 +43,14 @@ pub(crate) fn symbol_ty_by_name<'db>(
|
||||||
.unwrap_or(Type::Unbound)
|
.unwrap_or(Type::Unbound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shorthand for `symbol_ty` that looks up a module-global symbol in a file.
|
/// Shorthand for `symbol_ty` that looks up a module-global symbol by name in a file.
|
||||||
pub(crate) fn global_symbol_ty_by_name<'db>(db: &'db dyn Db, file: File, name: &str) -> Type<'db> {
|
pub(crate) fn global_symbol_ty_by_name<'db>(db: &'db dyn Db, file: File, name: &str) -> Type<'db> {
|
||||||
symbol_ty_by_name(db, global_scope(db, file), name)
|
symbol_ty_by_name(db, global_scope(db, file), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shorthand for `symbol_ty` that looks up a symbol in the builtins.
|
/// Shorthand for `symbol_ty` that looks up a symbol in the builtins.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the builtins module isn't available for some reason.
|
/// Returns `Unbound` if the builtins module isn't available for some reason.
|
||||||
pub(crate) fn builtins_symbol_ty_by_name<'db>(db: &'db dyn Db, name: &str) -> Type<'db> {
|
pub(crate) fn builtins_symbol_ty_by_name<'db>(db: &'db dyn Db, name: &str) -> Type<'db> {
|
||||||
builtins_scope(db)
|
builtins_scope(db)
|
||||||
.map(|builtins| symbol_ty_by_name(db, builtins, name))
|
.map(|builtins| symbol_ty_by_name(db, builtins, name))
|
||||||
|
|
|
@ -553,7 +553,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
pattern,
|
pattern,
|
||||||
guard,
|
guard,
|
||||||
} = case;
|
} = case;
|
||||||
// TODO infer case patterns; they aren't normal expressions
|
|
||||||
self.infer_match_pattern(pattern);
|
self.infer_match_pattern(pattern);
|
||||||
self.infer_optional_expression(guard.as_deref());
|
self.infer_optional_expression(guard.as_deref());
|
||||||
self.infer_body(body);
|
self.infer_body(body);
|
||||||
|
@ -920,10 +919,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
let ast::ExprNumberLiteral { range: _, value } = literal;
|
let ast::ExprNumberLiteral { range: _, value } = literal;
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
ast::Number::Int(n) => {
|
ast::Number::Int(n) => n
|
||||||
// TODO support big int literals
|
.as_i64()
|
||||||
n.as_i64().map(Type::IntLiteral).unwrap_or(Type::Unknown)
|
.map(Type::IntLiteral)
|
||||||
}
|
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int")),
|
||||||
// TODO builtins.float or builtins.complex
|
// TODO builtins.float or builtins.complex
|
||||||
_ => Type::Unknown,
|
_ => Type::Unknown,
|
||||||
}
|
}
|
||||||
|
@ -1004,8 +1003,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
self.infer_expression(elt);
|
self.infer_expression(elt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO tuple type
|
// TODO generic
|
||||||
Type::Unknown
|
builtins_symbol_ty_by_name(self.db, "tuple")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
|
fn infer_list_expression(&mut self, list: &ast::ExprList) -> Type<'db> {
|
||||||
|
@ -1019,8 +1018,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
self.infer_expression(elt);
|
self.infer_expression(elt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO list type
|
// TODO generic
|
||||||
Type::Unknown
|
builtins_symbol_ty_by_name(self.db, "list")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_set_expression(&mut self, set: &ast::ExprSet) -> Type<'db> {
|
fn infer_set_expression(&mut self, set: &ast::ExprSet) -> Type<'db> {
|
||||||
|
@ -1030,8 +1029,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
self.infer_expression(elt);
|
self.infer_expression(elt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO set type
|
// TODO generic
|
||||||
Type::Unknown
|
builtins_symbol_ty_by_name(self.db, "set")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_dict_expression(&mut self, dict: &ast::ExprDict) -> Type<'db> {
|
fn infer_dict_expression(&mut self, dict: &ast::ExprDict) -> Type<'db> {
|
||||||
|
@ -1042,8 +1041,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
self.infer_expression(&item.value);
|
self.infer_expression(&item.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO dict type
|
// TODO generic
|
||||||
Type::Unknown
|
builtins_symbol_ty_by_name(self.db, "dict")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_generator_expression(&mut self, generator: &ast::ExprGenerator) -> Type<'db> {
|
fn infer_generator_expression(&mut self, generator: &ast::ExprGenerator) -> Type<'db> {
|
||||||
|
@ -1346,23 +1345,19 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
ast::Operator::Add => n
|
ast::Operator::Add => n
|
||||||
.checked_add(m)
|
.checked_add(m)
|
||||||
.map(Type::IntLiteral)
|
.map(Type::IntLiteral)
|
||||||
// TODO builtins.int
|
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int")),
|
||||||
.unwrap_or(Type::Unknown),
|
|
||||||
ast::Operator::Sub => n
|
ast::Operator::Sub => n
|
||||||
.checked_sub(m)
|
.checked_sub(m)
|
||||||
.map(Type::IntLiteral)
|
.map(Type::IntLiteral)
|
||||||
// TODO builtins.int
|
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int")),
|
||||||
.unwrap_or(Type::Unknown),
|
|
||||||
ast::Operator::Mult => n
|
ast::Operator::Mult => n
|
||||||
.checked_mul(m)
|
.checked_mul(m)
|
||||||
.map(Type::IntLiteral)
|
.map(Type::IntLiteral)
|
||||||
// TODO builtins.int
|
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int")),
|
||||||
.unwrap_or(Type::Unknown),
|
|
||||||
ast::Operator::Div => n
|
ast::Operator::Div => n
|
||||||
.checked_div(m)
|
.checked_div(m)
|
||||||
.map(Type::IntLiteral)
|
.map(Type::IntLiteral)
|
||||||
// TODO builtins.int
|
.unwrap_or_else(|| builtins_symbol_ty_by_name(self.db, "int")),
|
||||||
.unwrap_or(Type::Unknown),
|
|
||||||
ast::Operator::Mod => n
|
ast::Operator::Mod => n
|
||||||
.checked_rem(m)
|
.checked_rem(m)
|
||||||
.map(Type::IntLiteral)
|
.map(Type::IntLiteral)
|
||||||
|
@ -2236,6 +2231,90 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn big_int() -> anyhow::Result<()> {
|
||||||
|
let mut db = setup_db();
|
||||||
|
|
||||||
|
db.write_dedented(
|
||||||
|
"/src/a.py",
|
||||||
|
"
|
||||||
|
x = 10_000_000_000_000_000_000
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_public_ty(&db, "/src/a.py", "x", "Literal[int]");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_literal() -> anyhow::Result<()> {
|
||||||
|
let mut db = setup_db();
|
||||||
|
|
||||||
|
db.write_dedented(
|
||||||
|
"/src/a.py",
|
||||||
|
"
|
||||||
|
x = ()
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// TODO should be a generic type
|
||||||
|
assert_public_ty(&db, "/src/a.py", "x", "Literal[tuple]");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_literal() -> anyhow::Result<()> {
|
||||||
|
let mut db = setup_db();
|
||||||
|
|
||||||
|
db.write_dedented(
|
||||||
|
"/src/a.py",
|
||||||
|
"
|
||||||
|
x = []
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// TODO should be a generic type
|
||||||
|
assert_public_ty(&db, "/src/a.py", "x", "Literal[list]");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_literal() -> anyhow::Result<()> {
|
||||||
|
let mut db = setup_db();
|
||||||
|
|
||||||
|
db.write_dedented(
|
||||||
|
"/src/a.py",
|
||||||
|
"
|
||||||
|
x = {1, 2}
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// TODO should be a generic type
|
||||||
|
assert_public_ty(&db, "/src/a.py", "x", "Literal[set]");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dict_literal() -> anyhow::Result<()> {
|
||||||
|
let mut db = setup_db();
|
||||||
|
|
||||||
|
db.write_dedented(
|
||||||
|
"/src/a.py",
|
||||||
|
"
|
||||||
|
x = {}
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// TODO should be a generic type
|
||||||
|
assert_public_ty(&db, "/src/a.py", "x", "Literal[dict]");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn first_public_def<'db>(db: &'db TestDb, file: File, name: &str) -> Definition<'db> {
|
fn first_public_def<'db>(db: &'db TestDb, file: File, name: &str) -> Definition<'db> {
|
||||||
let scope = global_scope(db, file);
|
let scope = global_scope(db, file);
|
||||||
*use_def_map(db, scope)
|
*use_def_map(db, scope)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue