[red-knot] Resolve symbols from builtins.pyi
in the stdlib if they … · astral-sh/ruff@d8cf8ac (original) (raw)
`@@ -29,15 +29,16 @@ use ruff_db::parsed::parsed_module;
`
29
29
`use ruff_python_ast as ast;
`
30
30
`use ruff_python_ast::{ExprContext, TypeParams};
`
31
31
``
``
32
`+
use crate::builtins::builtins_scope;
`
32
33
`use crate::semantic_index::ast_ids::{HasScopedAstId, HasScopedUseId, ScopedExpressionId};
`
33
34
`use crate::semantic_index::definition::{Definition, DefinitionKind, DefinitionNodeKey};
`
34
35
`use crate::semantic_index::expression::Expression;
`
35
36
`use crate::semantic_index::semantic_index;
`
36
``
`-
use crate::semantic_index::symbol::NodeWithScopeKind;
`
37
``
`-
use crate::semantic_index::symbol::{NodeWithScopeRef, ScopeId};
`
``
37
`+
use crate::semantic_index::symbol::{FileScopeId, NodeWithScopeKind, NodeWithScopeRef, ScopeId};
`
38
38
`use crate::semantic_index::SemanticIndex;
`
39
39
`use crate::types::{
`
40
``
`-
definitions_ty, global_symbol_ty_by_name, ClassType, FunctionType, Name, Type, UnionTypeBuilder,
`
``
40
`+
builtins_symbol_ty_by_name, definitions_ty, global_symbol_ty_by_name, ClassType, FunctionType,
`
``
41
`+
Name, Type, UnionTypeBuilder,
`
41
42
`};
`
42
43
`use crate::Db;
`
43
44
``
`@@ -686,7 +687,18 @@ impl<'db> TypeInferenceBuilder<'db> {
`
686
687
`let symbol = symbols.symbol_by_name(id).unwrap();
`
687
688
`if !symbol.is_defined() || !self.scope.is_function_like(self.db) {
`
688
689
`// implicit global
`
689
``
`-
Some(global_symbol_ty_by_name(self.db, self.file, id))
`
``
690
`+
let mut unbound_ty = if file_scope_id == FileScopeId::global() {
`
``
691
`+
Type::Unbound
`
``
692
`+
} else {
`
``
693
`+
global_symbol_ty_by_name(self.db, self.file, id)
`
``
694
`+
};
`
``
695
`+
// fallback to builtins
`
``
696
`+
if matches!(unbound_ty, Type::Unbound)
`
``
697
`+
&& Some(self.scope) != builtins_scope(self.db)
`
``
698
`+
{
`
``
699
`+
unbound_ty = builtins_symbol_ty_by_name(self.db, id);
`
``
700
`+
}
`
``
701
`+
Some(unbound_ty)
`
690
702
`} else {
`
691
703
`Some(Type::Unbound)
`
692
704
`}
`
`@@ -792,6 +804,7 @@ mod tests {
`
792
804
`use ruff_db::testing::assert_function_query_was_not_run;
`
793
805
`use ruff_python_ast:📛:Name;
`
794
806
``
``
807
`+
use crate::builtins::builtins_scope;
`
795
808
`use crate::db::tests::TestDb;
`
796
809
`use crate::semantic_index::definition::Definition;
`
797
810
`use crate::semantic_index::semantic_index;
`
`@@ -819,6 +832,23 @@ mod tests {
`
819
832
` db
`
820
833
`}
`
821
834
``
``
835
`+
fn setup_db_with_custom_typeshed(typeshed: &str) -> TestDb {
`
``
836
`+
let db = TestDb::new();
`
``
837
+
``
838
`+
Program::new(
`
``
839
`+
&db,
`
``
840
`+
TargetVersion::Py38,
`
``
841
`+
SearchPathSettings {
`
``
842
`+
extra_paths: Vec::new(),
`
``
843
`+
workspace_root: SystemPathBuf::from("/src"),
`
``
844
`+
site_packages: None,
`
``
845
`+
custom_typeshed: Some(SystemPathBuf::from(typeshed)),
`
``
846
`+
},
`
``
847
`+
);
`
``
848
+
``
849
`+
db
`
``
850
`+
}
`
``
851
+
822
852
`fn assert_public_ty(db: &TestDb, file_name: &str, symbol_name: &str, expected: &str) {
`
823
853
`let file = system_path_to_file(db, file_name).expect("Expected file to exist.");
`
824
854
``
`@@ -1370,6 +1400,80 @@ mod tests {
`
1370
1400
`Ok(())
`
1371
1401
`}
`
1372
1402
``
``
1403
`+
#[test]
`
``
1404
`+
fn builtin_symbol_vendored_stdlib() -> anyhow::Result<()> {
`
``
1405
`+
let mut db = setup_db();
`
``
1406
+
``
1407
`+
db.write_file("/src/a.py", "c = copyright")?;
`
``
1408
+
``
1409
`+
assert_public_ty(&db, "/src/a.py", "c", "Literal[copyright]");
`
``
1410
+
``
1411
`+
Ok(())
`
``
1412
`+
}
`
``
1413
+
``
1414
`+
#[test]
`
``
1415
`+
fn builtin_symbol_custom_stdlib() -> anyhow::Result<()> {
`
``
1416
`+
let mut db = setup_db_with_custom_typeshed("/typeshed");
`
``
1417
+
``
1418
`+
db.write_files([
`
``
1419
`+
("/src/a.py", "c = copyright"),
`
``
1420
`+
(
`
``
1421
`+
"/typeshed/stdlib/builtins.pyi",
`
``
1422
`+
"def copyright() -> None: ...",
`
``
1423
`+
),
`
``
1424
`+
("/typeshed/stdlib/VERSIONS", "builtins: 3.8-"),
`
``
1425
`+
])?;
`
``
1426
+
``
1427
`+
assert_public_ty(&db, "/src/a.py", "c", "Literal[copyright]");
`
``
1428
+
``
1429
`+
Ok(())
`
``
1430
`+
}
`
``
1431
+
``
1432
`+
#[test]
`
``
1433
`+
fn unknown_global_later_defined() -> anyhow::Result<()> {
`
``
1434
`+
let mut db = setup_db();
`
``
1435
+
``
1436
`+
db.write_file("/src/a.py", "x = foo; foo = 1")?;
`
``
1437
+
``
1438
`+
assert_public_ty(&db, "/src/a.py", "x", "Unbound");
`
``
1439
+
``
1440
`+
Ok(())
`
``
1441
`+
}
`
``
1442
+
``
1443
`+
#[test]
`
``
1444
`+
fn unknown_builtin_later_defined() -> anyhow::Result<()> {
`
``
1445
`+
let mut db = setup_db_with_custom_typeshed("/typeshed");
`
``
1446
+
``
1447
`+
db.write_files([
`
``
1448
`+
("/src/a.py", "x = foo"),
`
``
1449
`+
("/typeshed/stdlib/builtins.pyi", "foo = bar; bar = 1"),
`
``
1450
`+
("/typeshed/stdlib/VERSIONS", "builtins: 3.8-"),
`
``
1451
`+
])?;
`
``
1452
+
``
1453
`+
assert_public_ty(&db, "/src/a.py", "x", "Unbound");
`
``
1454
+
``
1455
`+
Ok(())
`
``
1456
`+
}
`
``
1457
+
``
1458
`+
#[test]
`
``
1459
`+
fn import_builtins() -> anyhow::Result<()> {
`
``
1460
`+
let mut db = setup_db();
`
``
1461
+
``
1462
`+
db.write_file("/src/a.py", "import builtins; x = builtins.copyright")?;
`
``
1463
+
``
1464
`+
assert_public_ty(&db, "/src/a.py", "x", "Literal[copyright]");
`
``
1465
`+
// imported builtins module is the same file as the implicit builtins
`
``
1466
`+
let file = system_path_to_file(&db, "/src/a.py").expect("Expected file to exist.");
`
``
1467
`+
let builtins_ty = global_symbol_ty_by_name(&db, file, "builtins");
`
``
1468
`+
let Type::Module(builtins_file) = builtins_ty else {
`
``
1469
`+
panic!("Builtins are not a module?");
`
``
1470
`+
};
`
``
1471
`+
let implicit_builtins_file = builtins_scope(&db).expect("builtins to exist").file(&db);
`
``
1472
`+
assert_eq!(builtins_file, implicit_builtins_file);
`
``
1473
+
``
1474
`+
Ok(())
`
``
1475
`+
}
`
``
1476
+
1373
1477
`fn first_public_def<'db>(db: &'db TestDb, file: File, name: &str) -> Definition<'db> {
`
1374
1478
`let scope = global_scope(db, file);
`
1375
1479
`*use_def_map(db, scope)
`