From 3bf77a963554fcae06c10524b82ddf17a27af41e Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Sun, 4 May 2025 07:54:43 -0700 Subject: [PATCH] [red-knot] add cycle handling for FunctionType::signature query move some ecosystem projects from bad to good add mdtest --- .../resources/mdtest/cycle.md | 15 ++++++++++++ .../resources/primer/bad.txt | 6 ----- .../resources/primer/good.txt | 6 +++++ crates/ty_python_semantic/src/types.rs | 23 ++++++++++++++++++- .../src/types/signatures.rs | 11 ++++++++- 5 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 crates/ty_python_semantic/resources/mdtest/cycle.md diff --git a/crates/ty_python_semantic/resources/mdtest/cycle.md b/crates/ty_python_semantic/resources/mdtest/cycle.md new file mode 100644 index 0000000000..dea0a124e5 --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/cycle.md @@ -0,0 +1,15 @@ +# Cycles + +## Function signature + +Deferred annotations can result in cycles in resolving a function signature: + +```py +from __future__ import annotations + +# error: [invalid-type-form] +def f(x: f): + pass + +reveal_type(f) # revealed: def f(x: Unknown) -> Unknown +``` diff --git a/crates/ty_python_semantic/resources/primer/bad.txt b/crates/ty_python_semantic/resources/primer/bad.txt index 4d2f648ab2..7001dd9391 100644 --- a/crates/ty_python_semantic/resources/primer/bad.txt +++ b/crates/ty_python_semantic/resources/primer/bad.txt @@ -1,4 +1,3 @@ -Expression # cycle panic (signature_) Tanjun # cycle panic (signature_) altair # cycle panics (try_metaclass_) antidote # hangs / slow @@ -12,21 +11,16 @@ hydpy # cycle panics (try_metaclass_) ibis # cycle panics (try_metaclass_) manticore # stack overflow materialize # stack overflow -mypy # cycle panic (signature_) pandas # slow pandas-stubs # cycle panics (try_metaclass_) pandera # cycle panics (try_metaclass_) prefect # slow pylint # cycle panics (self-recursive type alias) -pytest # cycle panics (signature_) pywin32 # bad use-def map (binding with definitely-visible unbound) -schemathesis # cycle panics (signature_) scikit-learn # success, but mypy-primer hangs processing the output scipy # missing expression type ("expression should belong to this TypeInference region") spack # success, but mypy-primer hangs processing the output spark # cycle panics (try_metaclass_) steam.py # cycle panics (try_metaclass_), often hangs when multi-threaded -streamlit # cycle panic (signature_) sympy # stack overflow -trio # cycle panics (deferred annotatation resolving in wrong scope) xarray # cycle panics (try_metaclass_) diff --git a/crates/ty_python_semantic/resources/primer/good.txt b/crates/ty_python_semantic/resources/primer/good.txt index 219abfbf11..b17c24aa21 100644 --- a/crates/ty_python_semantic/resources/primer/good.txt +++ b/crates/ty_python_semantic/resources/primer/good.txt @@ -1,4 +1,5 @@ AutoSplit +Expression PyGithub PyWinCtl SinbadCogs @@ -55,6 +56,7 @@ mkdocs mkosi mongo-python-driver more-itertools +mypy mypy-protobuf mypy_primer nionutils @@ -82,6 +84,7 @@ pylox pyodide pyp pyppeteer +pytest pytest-robotframework python-chess python-htmlgen @@ -90,6 +93,7 @@ rclip rich rotki schema_salad +schemathesis scrapy setuptools sockeye @@ -99,7 +103,9 @@ starlette static-frame stone strawberry +streamlit tornado +trio twine typeshed-stats urllib3 diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 1e4ca637d9..6f368e5319 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -6495,6 +6495,11 @@ impl<'db> FunctionSignature<'db> { pub(crate) fn iter(&self) -> Iter> { self.as_slice().iter() } + + /// Returns the "bottom" signature (subtype of all fully-static signatures.) + pub(crate) fn bottom(db: &'db dyn Db) -> Self { + Self::Single(Signature::bottom(db)) + } } impl<'db> IntoIterator for &'db FunctionSignature<'db> { @@ -6639,7 +6644,7 @@ impl<'db> FunctionType<'db> { /// /// Were this not a salsa query, then the calling query /// would depend on the function's AST and rerun for every change in that file. - #[salsa::tracked(return_ref)] + #[salsa::tracked(return_ref, cycle_fn=signature_cycle_recover, cycle_initial=signature_cycle_initial)] pub(crate) fn signature(self, db: &'db dyn Db) -> FunctionSignature<'db> { if let Some(overloaded) = self.to_overloaded(db) { FunctionSignature::Overloaded( @@ -6849,6 +6854,22 @@ impl<'db> FunctionType<'db> { } } +fn signature_cycle_recover<'db>( + _db: &'db dyn Db, + _value: &FunctionSignature<'db>, + _count: u32, + _function: FunctionType<'db>, +) -> salsa::CycleRecoveryAction> { + salsa::CycleRecoveryAction::Iterate +} + +fn signature_cycle_initial<'db>( + db: &'db dyn Db, + _function: FunctionType<'db>, +) -> FunctionSignature<'db> { + FunctionSignature::bottom(db) +} + /// Non-exhaustive enumeration of known functions (e.g. `builtins.reveal_type`, ...) that might /// have special behavior. #[derive( diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index a44720d38c..3f08e69cdb 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -291,6 +291,16 @@ impl<'db> Signature<'db> { } } + /// Return the "bottom" signature, subtype of all other fully-static signatures. + pub(crate) fn bottom(db: &'db dyn Db) -> Self { + Self { + generic_context: None, + inherited_generic_context: None, + parameters: Parameters::object(db), + return_ty: Some(Type::Never), + } + } + pub(crate) fn normalized(&self, db: &'db dyn Db) -> Self { Self { generic_context: self.generic_context, @@ -957,7 +967,6 @@ impl<'db> Parameters<'db> { } /// Return parameters that represents `(*args: object, **kwargs: object)`. - #[cfg(test)] pub(crate) fn object(db: &'db dyn Db) -> Self { Self { value: vec![