mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
[red-knot] Fix panic on cyclic *
imports (#16958)
Some checks are pending
CI / cargo fmt (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / cargo fmt (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
[Knot Playground] Release / publish (push) Waiting to run
## Summary Further work towards https://github.com/astral-sh/ruff/issues/14169. We currently panic on encountering cyclic `*` imports. This is easily fixed using fixpoint iteration. ## Test Plan Added a test that panics on `main`, but passes with this PR
This commit is contained in:
parent
dd5b02aaa2
commit
4975c2f027
2 changed files with 47 additions and 1 deletions
|
@ -834,6 +834,35 @@ reveal_type(g) # revealed: Unknown
|
||||||
reveal_type(h) # revealed: Unknown
|
reveal_type(h) # revealed: Unknown
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Cyclic star imports
|
||||||
|
|
||||||
|
Believe it or not, this code does _not_ raise an exception at runtime!
|
||||||
|
|
||||||
|
`a.py`:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from b import *
|
||||||
|
|
||||||
|
A: bool = True
|
||||||
|
```
|
||||||
|
|
||||||
|
`b.py`:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from a import *
|
||||||
|
|
||||||
|
B: bool = True
|
||||||
|
```
|
||||||
|
|
||||||
|
`c.py`:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from a import *
|
||||||
|
|
||||||
|
reveal_type(A) # revealed: bool
|
||||||
|
reveal_type(B) # revealed: bool
|
||||||
|
```
|
||||||
|
|
||||||
## Integration test: `collections.abc`
|
## Integration test: `collections.abc`
|
||||||
|
|
||||||
The `collections.abc` standard-library module provides a good integration test, as all its symbols
|
The `collections.abc` standard-library module provides a good integration test, as all its symbols
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
//! separate query, we would need to complete semantic indexing on `bar` in order to
|
//! separate query, we would need to complete semantic indexing on `bar` in order to
|
||||||
//! complete analysis of the global namespace of `foo`. Since semantic indexing is somewhat
|
//! complete analysis of the global namespace of `foo`. Since semantic indexing is somewhat
|
||||||
//! expensive, this would be undesirable. A separate query allows us to avoid this issue.
|
//! expensive, this would be undesirable. A separate query allows us to avoid this issue.
|
||||||
|
//!
|
||||||
|
//! An additional concern is that the recursive nature of this query means that it must be able
|
||||||
|
//! to handle cycles. We do this using fixpoint iteration; adding fixpoint iteration to the
|
||||||
|
//! whole [`super::semantic_index()`] query would probably be prohibitively expensive.
|
||||||
|
|
||||||
use ruff_db::{files::File, parsed::parsed_module};
|
use ruff_db::{files::File, parsed::parsed_module};
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
|
@ -26,7 +30,20 @@ use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{module_name::ModuleName, resolve_module, Db};
|
use crate::{module_name::ModuleName, resolve_module, Db};
|
||||||
|
|
||||||
#[salsa::tracked(return_ref)]
|
fn exports_cycle_recover(
|
||||||
|
_db: &dyn Db,
|
||||||
|
_value: &FxHashSet<Name>,
|
||||||
|
_count: u32,
|
||||||
|
_file: File,
|
||||||
|
) -> salsa::CycleRecoveryAction<FxHashSet<Name>> {
|
||||||
|
salsa::CycleRecoveryAction::Iterate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exports_cycle_initial(_db: &dyn Db, _file: File) -> FxHashSet<Name> {
|
||||||
|
FxHashSet::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[salsa::tracked(return_ref, cycle_fn=exports_cycle_recover, cycle_initial=exports_cycle_initial)]
|
||||||
pub(super) fn exported_names(db: &dyn Db, file: File) -> FxHashSet<Name> {
|
pub(super) fn exported_names(db: &dyn Db, file: File) -> FxHashSet<Name> {
|
||||||
let module = parsed_module(db.upcast(), file);
|
let module = parsed_module(db.upcast(), file);
|
||||||
let mut finder = ExportFinder::new(db, file);
|
let mut finder = ExportFinder::new(db, file);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue