Skip to content

[ty] Add support for the LSP protocol's "type hierarchy" feature#23566

Merged
BurntSushi merged 7 commits intomainfrom
ag/claude-type-hierarchy
Feb 27, 2026
Merged

[ty] Add support for the LSP protocol's "type hierarchy" feature#23566
BurntSushi merged 7 commits intomainfrom
ag/claude-type-hierarchy

Conversation

@BurntSushi
Copy link
Member

@BurntSushi BurntSushi commented Feb 25, 2026

The LSP protocol's "type hierarchy" support comes in the form of three
distinct requests:

The idea is that textDocument/prepareTypeHierarchy is called with
a particular document offset and that the server returns a non-empty
response if it's valid to ask for super- or sub-types for that
location. The client can then use that information as input to one
of either typeHierarchy/supertypes or typeHierarchy/subtypes to
request supertypes or subtypes, respectively. Note that these requests
are only for direct supertypes or subtypes.

The main implementation challenge here was discovering subtypes. In
particular, this requires a full scan of the environment and so can
take quite a bit of time on large projects. pylance in particular seems
to take a similar approach, although it is quite a bit slower than
ty. This PR does come with a basic optimization where we won't load a
module for parsing/checking unless it literally contains the class name
we're interested in.

One thing I did attempt was to account for re-exports of classes and also
for subtypes to find dynamic classes. For example:

class Base: pass
Dynamic = type("Dynamic", (Base,), {})

If one puts the cursor on Base and asks for its subtypes, ty will
not include Dynamic. It's possible to implement this, but 1) perf
suffered quite a bit on bigger projects and 2) I ended up with a lot of
false positives. Probably (2) is resolvable, but I think that's best
served for future work. (I think there are other higher priority things
to work on. And pylance doesn't handle this case either.)

Closes astral-sh/ty#534

@BurntSushi
Copy link
Member Author

Demo with a small project:

2026-02-25T14.43.10-05.00.mp4

Demo on Home Assistant (notice that asking for all subtypes for str takes a fair bit of time):

2026-02-25T14.44.53-05.00.mp4

@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch from f054016 to 8f4c478 Compare February 25, 2026 19:56
@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

Typing conformance results

No changes detected ✅

@BurntSushi
Copy link
Member Author

I assigned @dhruvmanila to this PR for review since it's involved with LSP. But I also assigned @AlexWaygood because of the stuff in ty_python_semantic for extracting subtypes. (Claude helped me a fair bit with it.)

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

mypy_primer results

Changes were detected when running on open source projects
spack (https://github.com/spack/spack)
- lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Unknown | Sized`
+ lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Sized | Unknown`
- lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Unknown | Sized`
+ lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Sized | Unknown`

pylint (https://github.com/pycqa/pylint)
- pylint/checkers/refactoring/implicit_booleaness_checker.py:219:24: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `str | Unknown`
+ pylint/checkers/refactoring/implicit_booleaness_checker.py:219:24: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `Unknown | str`
- pylint/checkers/refactoring/implicit_booleaness_checker.py:219:62: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `str | Unknown`
+ pylint/checkers/refactoring/implicit_booleaness_checker.py:219:62: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `Unknown | str`
- pylint/checkers/refactoring/implicit_booleaness_checker.py:222:27: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `str | (Unknown & ~None)`
+ pylint/checkers/refactoring/implicit_booleaness_checker.py:222:27: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `(Unknown & ~None) | str`
- pylint/checkers/refactoring/implicit_booleaness_checker.py:236:29: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `str | Unknown`
+ pylint/checkers/refactoring/implicit_booleaness_checker.py:236:29: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `Unknown | str`
- pylint/checkers/refactoring/implicit_booleaness_checker.py:239:29: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `str | Unknown`
+ pylint/checkers/refactoring/implicit_booleaness_checker.py:239:29: error[unresolved-attribute] Attribute `as_string` is not defined on `str` in union `Unknown | str`

vision (https://github.com/pytorch/vision)
- test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1551:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1605:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1692:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1747:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`

artigraph (https://github.com/artigraph/artigraph)
- tests/arti/types/test_types.py:100:51: error[invalid-argument-type] Argument is incorrect: Expected `frozenset[Any]`, found `frozenset[float | Unknown | int] | list[Unknown | int | float] | tuple[float | Unknown | int, ...]`
+ tests/arti/types/test_types.py:100:51: error[invalid-argument-type] Argument is incorrect: Expected `frozenset[Any]`, found `frozenset[float | Unknown | int] | list[int | Unknown | float] | tuple[float | Unknown | int, ...]`

cloud-init (https://github.com/canonical/cloud-init)
- tests/unittests/distros/test_user_data_normalize.py:24:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | bool | list[Unknown] | ... omitted 3 union elements`
+ tests/unittests/distros/test_user_data_normalize.py:24:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | dict[Unknown | str, Unknown | str] | str | ... omitted 3 union elements`
- tests/unittests/sources/test_gce.py:71:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | bool | list[Unknown] | ... omitted 3 union elements`
+ tests/unittests/sources/test_gce.py:71:31: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `dict[Unknown, Unknown]`, found `Unknown | dict[Unknown | str, Unknown | str] | str | ... omitted 3 union elements`

openlibrary (https://github.com/internetarchive/openlibrary)
- openlibrary/catalog/utils/__init__.py:132:17: error[unresolved-attribute] Attribute `search` is not defined on `str` in union `str | Unknown`
+ openlibrary/catalog/utils/__init__.py:132:17: error[unresolved-attribute] Attribute `search` is not defined on `str` in union `Unknown | str`

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/deployments/runner.py:1017:70: error[unresolved-attribute] Attribute `__name__` is not defined on `(...) -> Any` in union `Unknown | ((...) -> Any)`
+ src/prefect/deployments/runner.py:1017:70: error[unresolved-attribute] Attribute `__name__` is not defined on `((...) -> Any) & ((*args: object, **kwargs: object) -> object)` in union `Unknown | (((...) -> Any) & ((*args: object, **kwargs: object) -> object))`
- src/prefect/flow_engine.py:1004:32: error[invalid-await] `Unknown | R@FlowRunEngine | Coroutine[Any, Any, R@FlowRunEngine]` is not awaitable
- src/prefect/flow_engine.py:1610:24: error[invalid-await] `Unknown | R@AsyncFlowRunEngine | Coroutine[Any, Any, R@AsyncFlowRunEngine]` is not awaitable
- src/prefect/flows.py:286:34: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
+ src/prefect/flows.py:286:34: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
- src/prefect/flows.py:404:68: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
+ src/prefect/flows.py:404:68: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
- Found 5781 diagnostics
+ Found 5779 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ddtrace/debugging/_redaction.py:16:5: error[unsupported-operator] Operator `|` is not supported between objects of type `frozenset[Unknown | str]` and `Unknown | EnvVariable[set[Unknown]]`
+ ddtrace/debugging/_redaction.py:16:5: error[unsupported-operator] Operator `|` is not supported between objects of type `frozenset[str | Unknown]` and `Unknown | EnvVariable[set[Unknown]]`
- scripts/freshvenvs.py:343:69: error[invalid-argument-type] Argument to function `_versions_fully_cover_bounds` is incorrect: Expected `list[str]`, found `list[Version | Unknown] & ~AlwaysFalsy`
+ scripts/freshvenvs.py:343:69: error[invalid-argument-type] Argument to function `_versions_fully_cover_bounds` is incorrect: Expected `list[str]`, found `list[Unknown | Version] & ~AlwaysFalsy`
- tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `Span | Unknown | None | ... omitted 6 union elements`
+ tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `int | float | complex | ... omitted 6 union elements`

ibis (https://github.com/ibis-project/ibis)
- ibis/selectors.py:333:16: error[invalid-return-type] Return type does not match returned value: expected `frozenset[str]`, found `frozenset[Buffer | Unknown | str]`
+ ibis/selectors.py:333:16: error[invalid-return-type] Return type does not match returned value: expected `frozenset[str]`, found `frozenset[str | Buffer | Unknown]`
- ibis/selectors.py:428:13: error[invalid-assignment] Object of type `frozenset[Unknown | str]` is not assignable to `tuple[str | Column, ...]`
+ ibis/selectors.py:428:13: error[invalid-assignment] Object of type `frozenset[str | Unknown]` is not assignable to `tuple[str | Column, ...]`

sympy (https://github.com/sympy/sympy)
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
- sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:968:29: error[unresolved-attribute] Attribute `is_nonnegative` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:968:47: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:969:12: error[unresolved-attribute] Attribute `is_zero` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:975:12: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:976:16: error[unresolved-attribute] Attribute `is_negative` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:978:18: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:984:14: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/geometry/polygon.py:1501:12: error[unresolved-attribute] Attribute `is_Number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/geometry/polygon.py:1502:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/geometry/polygon.py:1502:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic | int | float | complex | Any`
- sympy/geometry/polygon.py:1503:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic` and `Literal[3]`
+ sympy/geometry/polygon.py:1503:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[3]`
+ sympy/geometry/polygon.py:1510:40: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/matrices/expressions/hadamard.py:82:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Basic`
+ sympy/matrices/expressions/hadamard.py:82:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Any | Basic | int | float | complex`
- sympy/matrices/expressions/kronecker.py:110:16: error[unresolved-attribute] Object of type `Basic` has no attribute `is_Identity`
- sympy/matrices/expressions/kronecker.py:111:33: error[unresolved-attribute] Object of type `Basic` has no attribute `rows`
+ sympy/matrices/expressions/kronecker.py:110:16: error[unresolved-attribute] Attribute `is_Identity` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/matrices/expressions/kronecker.py:111:33: error[unresolved-attribute] Attribute `rows` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/matrices/expressions/matadd.py:61:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Unknown | Basic`
+ sympy/matrices/expressions/matadd.py:61:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Unknown | Basic | int | float | complex`
+ sympy/parsing/mathematica.py:692:38: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Never]`, found `Unknown | list[Unknown | str]`
- sympy/physics/optics/gaussopt.py:264:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:264:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:299:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:299:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:299:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:299:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:708:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:708:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:757:8: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:757:25: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:758:21: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:760:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:760:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:760:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:760:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:791:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic`
+ sympy/physics/optics/gaussopt.py:791:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:838:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:838:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
- sympy/physics/optics/gaussopt.py:838:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:838:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:838:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic`
+ sympy/physics/optics/gaussopt.py:838:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:839:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:839:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:839:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:839:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:840:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:840:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:840:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:840:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:888:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/physics/optics/gaussopt.py:888:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:84:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:259:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/physics/quantum/cg.py:348:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/polys/fields.py:101:24: error[unresolved-attribute] Object of type `Basic` has no attribute `as_numer_denom`
+ sympy/polys/fields.py:101:24: error[unresolved-attribute] Attribute `as_numer_denom` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:472:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:472:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:474:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:474:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:476:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:476:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:478:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:478:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:480:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:480:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:482:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:482:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:492:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:492:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
- sympy/polys/polyoptions.py:494:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Basic`
+ sympy/polys/polyoptions.py:494:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polytools.py:6008:12: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6008:31: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6008:51: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6008:70: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6009:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/polys/polytools.py:6009:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6138:12: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6138:31: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6138:51: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6138:70: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6139:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/polys/polytools.py:6139:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/series/formal.py:988:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/series/fourier.py:147:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
+ sympy/series/order.py:154:20: error[unresolved-attribute] Attribute `is_symbol` is not defined on `int`, `float`, `complex` in union `Unknown | Basic | int | float | complex`
- sympy/series/order.py:189:28: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Unknown | Basic`
+ sympy/series/order.py:189:28: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Unknown | Basic | int | float | complex`
- sympy/series/order.py:193:29: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[-1]` and `Unknown | Basic`
+ sympy/series/order.py:193:29: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[-1]` and `Unknown | Basic | int | float | complex`
+ sympy/series/order.py:270:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
+ sympy/series/order.py:270:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
+ sympy/series/order.py:270:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
- sympy/series/order.py:288:45: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
+ sympy/series/order.py:288:45: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
- sympy/series/order.py:289:48: error[unsupported-operator] Operator `**` is not supported between objects of type `Unknown | Basic` and `Basic`
+ sympy/series/order.py:289:48: error[unsupported-operator] Operator `**` is not supported between objects of type `Any | Basic | int | float | complex` and `Basic`
- sympy/series/order.py:292:49: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
+ sympy/series/order.py:292:49: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
- sympy/series/order.py:298:53: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
+ sympy/series/order.py:298:53: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
- sympy/simplify/cse_main.py:300:23: error[not-iterable] Object of type `Sized | Unknown` may not be iterable
+ sympy/simplify/cse_main.py:300:23: error[not-iterable] Object of type `Unknown | Sized` may not be iterable
- sympy/simplify/cse_main.py:306:16: error[unsupported-operator] Operator `in` is not supported between objects of type `Unknown` and `Sized | Unknown`
+ sympy/simplify/cse_main.py:306:16: error[unsupported-operator] Operator `in` is not supported between objects of type `Unknown` and `Unknown | Sized`
- sympy/simplify/hyperexpand.py:1047:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1047:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1048:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1048:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1049:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1049:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1088:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1088:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1089:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1089:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1090:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1090:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1176:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1176:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1177:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1177:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1178:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1178:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1179:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1179:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1180:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1180:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1214:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1214:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1215:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1215:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1216:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1216:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1217:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1217:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1218:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1218:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1266:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1266:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1267:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1267:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1268:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1268:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1269:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1269:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1270:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1270:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1314:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1314:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1315:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1315:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1316:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1316:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1317:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
+ sympy/simplify/hyperexpand.py:1317:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
- sympy/simplify/hyperexpand.py:1318:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
+ sympy/simplify/hyperexpand.py:1318:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
- sympy/simplify/simplify.py:357:10: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/simplify/simplify.py:357:10: error[unsupported-operator] Operator `/` is not supported between two objects of type `Any | Basic | int | float | complex`
+ sympy/simplify/sqrtdenest.py:431:25: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
+ sympy/solvers/recurr.py:418:9: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/solvers/recurr.py:418:9: error[unresolved-attribute] Object of type `Basic` has no attribute `expand`
+ sympy/solvers/recurr.py:418:9: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Any | Basic`
+ sympy/solvers/recurr.py:422:24: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/solvers/recurr.py:437:24: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/solvers/recurr.py:590:23: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/solvers/tests/test_pde.py:109:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:109:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/solvers/tests/test_pde.py:130:22: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:130:22: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/solvers/tests/test_pde.py:138:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:138:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/solvers/tests/test_pde.py:164:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:164:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/solvers/tests/test_pde.py:202:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:202:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/solvers/tests/test_pde.py:216:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(Unknown | str, /) -> Unknown`, found `<class 'Function'>`
+ sympy/solvers/tests/test_pde.py:216:16: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | Unknown, /) -> Unknown`, found `<class 'Function'>`
- sympy/stats/symbolic_probability.py:532:55: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Basic | Unknown`
+ sympy/stats/symbolic_probability.py:532:55: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Unknown | Basic`
- sympy/stats/symbolic_probability.py:533:55: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Basic | Unknown`
+ sympy/stats/symbolic_probability.py:533:55: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Unknown | Basic`
- sympy/stats/tests/test_finite_rv.py:358:31: error[unsupported-operator] Operator `+` is not supported between objects of type `int | Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:358:31: error[unsupported-operator] Operator `+` is not supported between objects of type `int | Basic | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:362:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:362:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:363:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:363:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:364:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:364:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:364:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:364:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:364:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:364:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:364:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:364:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:366:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/stats/tests/test_finite_rv.py:366:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
- sympy/stats/tests/test_finite_rv.py:366:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:366:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:366:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:366:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:366:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:366:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:367:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:367:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:367:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:367:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
+ sympy/stats/tests/test_finite_rv.py:367:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:368:33: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:368:33: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:368:38: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:368:38: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:368:46: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
+ sympy/stats/tests/test_finite_rv.py:368:46: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
- sympy/stats/tests/test_finite_rv.py:368:55: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[2]`
+ sympy/stats/tests/test_finite_rv.py:368:55: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/tensor/indexed.py:162:79: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/tensor/indexed.py:170:39: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Any | Basic | int | float | complex`
+ sympy/tensor/indexed.py:651:12: error[unresolved-attribute] Attribute `is_Number` is not defined on `int`, `float`, `complex`, `None` in union `Any | Basic | int | ... omitted 3 union elements`
+ sympy/tensor/indexed.py:652:20: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex`, `None` in union `Any | Basic | int | ... omitted 3 union elements`
+ sympy/tensor/indexed.py:656:16: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex`, `None` in union `Any | Basic | int | ... omitted 3 union elements`
+ sympy/tensor/indexed.py:679:33: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Any | Basic | int | ... omitted 3 union elements`
- Found 16108 diagnostics
+ Found 16149 diagnostics

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `str | Unknown`
+ sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `Unknown | str`

static-frame (https://github.com/static-frame/static-frame)
- static_frame/test/unit/test_frame_iter.py:1389:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1389:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1397:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1397:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1408:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1408:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1411:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1411:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1431:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1431:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1439:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1439:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1481:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1481:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1489:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1489:13: error[unresolved-attribute] Attribute `to_pairs` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1549:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1549:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1550:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1550:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1553:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1553:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1554:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1554:26: error[unresolved-attribute] Attribute `tolist` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`
- static_frame/test/unit/test_frame_iter.py:1684:29: error[unresolved-attribute] Attribute `shape` is not defined on `tuple[Any, Any]` in union `tuple[Any, Any] | Any`
+ static_frame/test/unit/test_frame_iter.py:1684:29: error[unresolved-attribute] Attribute `shape` is not defined on `tuple[Any, Any]` in union `Any | tuple[Any, Any]`

rotki (https://github.com/rotki/rotki)
- rotkehlchen/tests/unit/test_makerdao.py:170:9: error[invalid-argument-type] Argum

... (truncated 27 lines) ...

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

Memory usage report

Memory usage unchanged ✅

@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch 2 times, most recently from d455f07 to cbf3b4d Compare February 25, 2026 20:02
@carljm carljm removed their request for review February 25, 2026 20:04
@ntBre ntBre added the ty Multi-file analysis & type inference label Feb 25, 2026
@astral-sh-bot

This comment was marked as off-topic.

@AlexWaygood AlexWaygood added the server Related to the LSP server label Feb 25, 2026
@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch from cbf3b4d to 0dd2212 Compare February 25, 2026 23:21
Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

I did glance through the semantic changes but it would still be great to have @AlexWaygood take a look as well.

Comment on lines +1576 to +1582
/// The file containing the class definition.
pub file: ruff_db::files::File,
/// The range covering the full class definition header.
pub full_range: ruff_db::files::FileRange,
/// The range of the class name (for selection/focus).
pub selection_range: ruff_db::files::FileRange,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just use TextRange for full_range and selection_range because the file is already present on the struct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice catch. Yeah that's much simpler.

db: &dyn Db,
class_literal: ClassLiteral<'_>,
) -> TypeHierarchyClass {
let name = class_literal.name(db).to_string();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the Name struct here instead of .to_string()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. I don't think it ends up reducing allocs though. By the time we build this, all of our filtering has already been done. And we eventually need to convert this to a String at the LSP boundary anyway. We'd probably need to define our own LSP wire types to truly eliminate the extra alloc.

I did make this change though for consistency reasons. I agree it's still nice to use Name when we can.

Comment on lines +1728 to +1731
Type::Union(union) => union
.elements(db)
.iter()
.find_map(|elem| extract_class_literal(db, *elem)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we return a list of TypeHierarchyItems here instead of picking the first one in reponse to textDocument/prepareTypeHierarchy? Or, is that not the correct way to think about this from an editor perspective?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it might get a bit complicated to handle Option<impl Iterator<Item = ClassLiteral>> where extract_class_literal is being used so we can leave this for a follow-up improvement.

Comment on lines +1763 to +1777
// For the dynamic cases, we special case a variable definition
// like this:
//
// Dynamic = type("Dynamic", (object,), {})
//
// In this case, the range for the element we return will correspond to
// the left hand side of the variable assignment. This works better as
// an "anchor" point because it avoids ambiguity with asking for the
// type hierarchy of `type` itself.
//
// If there is not a variable definition, then we fall back to the
// class definition's "header" range, which will be the `type` (or
// `namedtuple`) call. Subsequent type hierarchy requests will then
// (likely incorrectly) return the type hierarchy for `type` itself.
ClassLiteral::Dynamic(dynamic_class) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the current implementation is perfectly fine but just a random thought where we could possibly use the string value to represent this type hierarchy symbol if there's no assignment and that wouldn't have any subtypes (haven't looked whether it's feasible in terms of follow-up requests). I think this might be a more work for little gains so would avoid until user feedback.

Comment on lines +1662 to +1667
// Skip files that don't contain the class name. This avoids expensive
// semantic analysis for files that can't possibly contain a subclass
// of the target. We can't do this when looking for subtypes of
// `object` since `object` can be implicit.
if !target_is_object && !source_text(db, file).contains(target_name.as_str()) {
continue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's neat!

Comment on lines +412 to +416
// through" it. But what if the user actually wants the type
// hierarchy for `type`? Maybe we should only recognize the
// idiom when the cursor is on the `"Dynamic"` string literal.
// ---AG
let test = cursor_test(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this seems reasonable, we can check whether the cursor is on type vs on the "Dynamic" string literal.

Comment on lines +661 to +664
/// This tests that we don't currently respect `__all__` when returning
/// subtypes.
#[test]
fn subtypes_all_not_respected() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if __all__ should be respected in this case, I'd consider this request to return all subtypes irrespective of whether it's a public symbol or not but then we're not considering private modules so an argument can be made to consider __all__ as well. I guess we can defer it based on user feedback.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think waiting on user feedback is wise here. The current "ignore private/test modules but also don't respect __all__" seems to be what pylance does.

");
}

fn snapshot(db: &dyn Db, items: &[TypeHierarchyItem]) -> String {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: might be useful to use diagnostic to highlight the class which would allow us to snapshot the range values as well, not urgent and can be pushed as follow-up and could even be a "help wanted" issue

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can file an issue about this.

/// Note that this implements the `BackgroundRequestHandler` because the
/// request might be for a symbol in a document that is not open in the current
/// session.
pub(crate) struct TypeHierarchySupertypesRequestHandler;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have separate files (to follow the current convention e.g., prepare_rename and rename) for each of these request handler, so all in all 3 files each for prepare, subtype and supertype request. The common hierarchy_handler can be moved outside the requests directory similar to server/api/semantic_tokens.rs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting. I actually originally had 3 separate files to follow the convention, but I found it a lot nicer to put all three in the same file since they are so closely related (and share helpers). Do you feel strongly about this? If not, I'd like to keep it this way. The helpers are highly specific to these request handlers and it feels weird to me to move them somewhere else away from the trait impls.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel too strongly, it's mainly for consistency. It should also be easier to go directly to the file for a specific request using a fuzzing finder but that can easily be done by searching for the symbol as well. In addition to the rename traits, the diagnostics are also split this way and uses the server/api/diagnostics.rs as the common file containing shared code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blech, okay. I went back and looked and yeah, this pattern is indeed quite strong. I don't want to be the one to break it, so I've split them back out into separate modules. I've also added a module comment to ty_server::server::api::requests documenting the pattern.

I'm still not really a fan of this though. I would argue that the semantic tokens request handlers should also probably be merged. But nothing else really sticks out to me. The shared code for diagnostics, for example, is used in more request handlers than just the diagnostic ones. And the request handlers for diagnostics vs workspace diagnostics are quite different. So them getting their own modules seems fine.

Comment on lines +149 to +152
// We don't actually know which project the request
// came from, so just look for results across all
// projects.
let mut items = vec![];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can avoid resolving the item location by using the data field in the prepareTypeHierarchy response to store the file URI:

/**
 * A data entry field that is preserved between a type hierarchy prepare and
 * supertypes or subtypes requests. It could also be used to identify the
 * type hierarchy in the server, helping improve the performance on
 * resolving supertypes and subtypes.
 */
data?: [LSPAny](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#lspAny);

We do this in ruff-lsp between code action and the code action resolve request. You can basically pass in any information you want between the prepare and the actual request.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I saw the arbitrary data blob, but it wasn't obvious to me that it would be helpful here? In particular, TypeHierarchyItem already has the file URI (and an offset), so we don't need to additionally store it in a data blob. The resolve_item_location routine is basically just mapping that file URI back into our internal types (either a system path or a vendored path).

Copy link
Member Author

@BurntSushi BurntSushi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holding off on pushing my changes based on your feedback because I rebased and don't want to mess up Alex's review if he's in the middle of one. :)

Comment on lines +661 to +664
/// This tests that we don't currently respect `__all__` when returning
/// subtypes.
#[test]
fn subtypes_all_not_respected() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think waiting on user feedback is wise here. The current "ignore private/test modules but also don't respect __all__" seems to be what pylance does.

/// Note that this implements the `BackgroundRequestHandler` because the
/// request might be for a symbol in a document that is not open in the current
/// session.
pub(crate) struct TypeHierarchySupertypesRequestHandler;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting. I actually originally had 3 separate files to follow the convention, but I found it a lot nicer to put all three in the same file since they are so closely related (and share helpers). Do you feel strongly about this? If not, I'd like to keep it this way. The helpers are highly specific to these request handlers and it feels weird to me to move them somewhere else away from the trait impls.

Comment on lines +149 to +152
// We don't actually know which project the request
// came from, so just look for results across all
// projects.
let mut items = vec![];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I saw the arbitrary data blob, but it wasn't obvious to me that it would be helpful here? In particular, TypeHierarchyItem already has the file URI (and an offset), so we don't need to additionally store it in a data blob. The resolve_item_location routine is basically just mapping that file URI back into our internal types (either a system path or a vendored path).

");
}

fn snapshot(db: &dyn Db, items: &[TypeHierarchyItem]) -> String {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can file an issue about this.

Comment on lines +1576 to +1582
/// The file containing the class definition.
pub file: ruff_db::files::File,
/// The range covering the full class definition header.
pub full_range: ruff_db::files::FileRange,
/// The range of the class name (for selection/focus).
pub selection_range: ruff_db::files::FileRange,
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice catch. Yeah that's much simpler.

db: &dyn Db,
class_literal: ClassLiteral<'_>,
) -> TypeHierarchyClass {
let name = class_literal.name(db).to_string();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. I don't think it ends up reducing allocs though. By the time we build this, all of our filtering has already been done. And we eventually need to convert this to a String at the LSP boundary anyway. We'd probably need to define our own LSP wire types to truly eliminate the extra alloc.

I did make this change though for consistency reasons. I agree it's still nice to use Name when we can.

Comment on lines +19 to +22
/// The range covering the full class definition.
pub full_range: FileRange,
/// The range of the class name (for selection/focus).
pub selection_range: FileRange,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, nice catch!

@AlexWaygood
Copy link
Member

I haven't started a review yet but it is on my list for today! One question about this:

This PR does come with a basic optimization where we won't load a
module for parsing/checking unless it literally contains the class name
we're interested in.

Does this account for the possibility that classes might be aliased? E.g.

a.py:

class Foo: ...

b.py:

from a import Foo as Bar

__all__ = ["Bar"]

c.py:

from b import Bar

class Baz(Bar): ...

The string "Foo" appears nowhere in the source for c.py, but it contains a class that inherits from Foo nonetheless.

For real-world examples of where this could cause issues: certain builtin "exception classes" in Python are actually just aliases to OSError under the hood these days (retained only for backwards compatibility):

EnvironmentError = OSError
IOError = OSError
if sys.platform == "win32":
WindowsError = OSError

@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch from 0dd2212 to 88046e8 Compare February 26, 2026 13:40
@BurntSushi
Copy link
Member Author

Ah okay, just pushed then. :)

@AlexWaygood It indeed does not account for that. There are tests documenting that limitation. I noted in the OP that I tried to fix this, but there are challenges. Perf being one of them. The other being that my approach ended up with a lot of false positives. I felt like there were higher priority things to work on, and as far as I can tell, pylance has the same limitation. (This manifests in other ways too. e.g., It means we don't discover subtypes that are created through type.) I'm sure fixing the false positives is possible, but fixing the perf problem seems non-trivial.

@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch from 88046e8 to ca7cc1a Compare February 26, 2026 13:48
This brings in astral-sh/lsp-types#2,
which is necessary to advertise an LSP server's capability to
provide type hierarchy information.
These were previously only used in auto-import, but we'll
want to use them for filtering subtypes too. So put them
in a more central location.

I think these codify pretty solid ecosystem conventions,
but I've added some cautionary language to the docs for
these methods.
…y" feature

Most of the interesting logic is inside of `ty_python_semantic`.
We include a light wrapper API along with tests in `ty_ide`,
which I think follows our existing convention for this sort of
thing.

Some of the tests demonstrate limitations in the current approach.
I believe all such limitations are present in pylance as well.
So this should bring us to parity at minimum.
In some cases, the LSP client will send us file paths corresponding
to a vendored file in typeshed. We really want to treat this as a
`VendoredPath` and not a `SystemPath`. In particular, if we treat it
as the latter, we can end up with two different interned `File`
values for the same file. And this leads to disastrous things (like
definitions no longer being equivalent).
I think the main interesting piece here is mapping file URLs
back to their appropriate vendored or system file path type.
Otherwise, this mostly just wraps the API exposed in `ty_ide`.

We also add a few "sanity check" end-to-end tests, but leave
the bulk of the testing responsibility to `ty_ide`.
@BurntSushi BurntSushi force-pushed the ag/claude-type-hierarchy branch from ca7cc1a to 112240c Compare February 27, 2026 12:44
@BurntSushi
Copy link
Member Author

@AlexWaygood I'm going to bring this in, but I'm more than happy to do follow-ups. :-)

@BurntSushi BurntSushi merged commit e45f226 into main Feb 27, 2026
50 checks passed
@BurntSushi BurntSushi deleted the ag/claude-type-hierarchy branch February 27, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

server Related to the LSP server ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Type hierarchy

5 participants