Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c9cc000
[ty] [WIP] handle recursive type inference properly
mtshiba Sep 24, 2025
2cfdf1d
Merge branch 'main' into recursive-inference
mtshiba Oct 24, 2025
041bb24
use the last provisional value of `cycle_fn`
mtshiba Oct 27, 2025
074f18f
`Divergent` has `salsa::Id`
mtshiba Oct 27, 2025
c71fd0b
handle cycles in more query functions
mtshiba Oct 27, 2025
de28c13
Merge branch 'main' into recursive-inference
mtshiba Oct 27, 2025
a1e3d93
Update 1377_iteration_count_mismatch.md
mtshiba Oct 27, 2025
e63e3bd
Merge branch 'main' into recursive-inference
mtshiba Oct 30, 2025
b852be7
update salsa
mtshiba Oct 30, 2025
b45ebbd
refactor
mtshiba Oct 31, 2025
d8cab29
refactor
mtshiba Oct 31, 2025
9115e40
simplify type joining performed within `cycle_recovery`
mtshiba Oct 31, 2025
d68e5c0
revert unnecessary changes
mtshiba Oct 31, 2025
b0a7804
Add examples of self-referential types
mtshiba Oct 31, 2025
0caa4b1
Merge branch 'main' into recursive-inference
mtshiba Nov 3, 2025
36c5257
refactor
mtshiba Nov 3, 2025
6cc30e4
implement `ProtocolInstanceType::recursive_type_normalized_impl`
mtshiba Nov 3, 2025
1a9d899
Merge branch 'main' into recursive-inference
mtshiba Nov 3, 2025
eda8017
the code in `pr_20962_comprehension_panics.md` no longer panics
mtshiba Nov 3, 2025
fc63d5f
Update attributes.md
mtshiba Nov 5, 2025
8c06a05
follow the changes in salsa-rs/salsa#1021
mtshiba Nov 5, 2025
3653427
Merge branch 'main' into recursive-inference
mtshiba Nov 5, 2025
ab84bdf
Do not use `UnionBuilder` to union the last provisional type and the …
mtshiba Nov 6, 2025
fa88ca3
Merge branch 'main' into recursive-inference
mtshiba Nov 6, 2025
d0145c6
Revert "Do not use `UnionBuilder` to union the last provisional type …
mtshiba Nov 6, 2025
682a2e8
don't create a query cycle in the cycle recovery function
mtshiba Nov 6, 2025
d0b68f9
use `CycleHeads` to remove `Divergent` types
mtshiba Nov 6, 2025
55f9ae9
Merge branch 'main' into recursive-inference
mtshiba Nov 6, 2025
65bb223
Update builder.rs
mtshiba Nov 6, 2025
0cf4eaf
revert unnecessary changes
mtshiba Nov 6, 2025
91167f9
Merge branch 'main' into recursive-inference
mtshiba Nov 7, 2025
2393f6a
fix fuzzer hang
mtshiba Nov 7, 2025
02705c4
the second parameter `Id` of `cycle_fn` is not necessary
mtshiba Nov 10, 2025
664b8d8
Revert "fix fuzzer hang"
mtshiba Nov 10, 2025
4aad144
specify cycle_fn for `PEP695TypeAliasType::raw_value_type`
mtshiba Nov 10, 2025
74a3758
Merge branch 'main' into recursive-inference
mtshiba Nov 11, 2025
e7b0dc5
revert unnecessary changes
mtshiba Nov 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ regex-automata = { version = "0.4.9" }
rustc-hash = { version = "2.0.0" }
rustc-stable-hash = { version = "0.1.2" }
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "25b3ef146cfa2615f4ec82760bd0c22b454d0a12", default-features = false, features = [
salsa = { git = "https://github.com/mtshiba/salsa.git", rev = "9ea5289bc6a87943b8a8620df8ff429062c56af0", default-features = false, features = [
"compact_str",
"macros",
"salsa_unstable",
Expand Down
5 changes: 3 additions & 2 deletions crates/ruff_benchmark/benches/ty_walltime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ static PANDAS: Benchmark = Benchmark::new(
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY312,
},
3000,
3300,
);

static PYDANTIC: Benchmark = Benchmark::new(
Expand Down Expand Up @@ -197,7 +197,8 @@ static SYMPY: Benchmark = Benchmark::new(
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY312,
},
13000,
// TODO: With better decorator support, `__slots__` support, etc., it should be possible to reduce the number of errors considerably.
70000,
);

static TANJUN: Benchmark = Benchmark::new(
Expand Down
17 changes: 17 additions & 0 deletions crates/ty_python_semantic/resources/corpus/cycle_into_callable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Regression test for https://github.com/astral-sh/ruff/issues/17371
# panicked in commit d1088545a08aeb57b67ec1e3a7f5141159efefa5
# error message:
# dependency graph cycle when querying ClassType < 'db >::into_callable_(Id(1c00))

try:
class foo[T: bar](object):
pass
bar = foo
except Exception:
bar = lambda: 0
def bar():
pass

@bar()
class bar:
pass
69 changes: 69 additions & 0 deletions crates/ty_python_semantic/resources/corpus/divergent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
def f(cond: bool):
if cond:
result = ()
result += (f(cond),)
return result

return None

reveal_type(f(True))

def f(cond: bool):
if cond:
result = ()
result += (f(cond),)
return result

return None

def f(cond: bool):
result = None
if cond:
result = ()
result += (f(cond),)

return result

reveal_type(f(True))

def f(cond: bool):
result = None
if cond:
result = [f(cond) for _ in range(1)]

return result

reveal_type(f(True))

class Foo:
def value(self):
return 1

def unwrap(value):
if isinstance(value, Foo):
foo = value
return foo.value()
elif type(value) is tuple:
length = len(value)
if length == 0:
return ()
elif length == 1:
return (unwrap(value[0]),)
else:
result = []
for item in value:
result.append(unwrap(item))
return tuple(result)
else:
raise TypeError()

def descent(x: int, y: int):
if x > y:
y, x = descent(y, x)
return x, y
if x == 1:
return (1, 0)
if y == 1:
return (0, 1)
else:
return descent(x-1, y-1)
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ def outer_sync(): # `yield` from is only valid syntax inside a synchronous func
a: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in type expressions"
): ...

async def baz(): ...
async def baz():
yield

async def outer_async(): # avoid unrelated syntax errors on `yield` and `await`
def _(
a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
Expand Down
18 changes: 18 additions & 0 deletions crates/ty_python_semantic/resources/mdtest/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,24 @@

reveal_type(B().x) # revealed: Unknown | Literal[1]
reveal_type(A().x) # revealed: Unknown | Literal[1]

class Base:
def flip(self) -> "Sub":
return Sub()

class Sub(Base):
# TODO invalid override error
def flip(self) -> "Base":
return Base()

class C2:
def __init__(self, x: Sub):
self.x = x

def replace_with(self, other: "C2"):
self.x = other.x.flip()

reveal_type(C2(Sub()).x) # revealed: Unknown | Base
```

And cycles between many attributes:
Expand Down Expand Up @@ -2411,8 +2429,8 @@
self.x6 = self.x1 + self.x2 + self.x3 + self.x4 + self.x5 + self.x7
self.x7 = self.x1 + self.x2 + self.x3 + self.x4 + self.x5 + self.x6

reveal_type(self.x1) # revealed: Unknown | int

Check failure on line 2432 in crates/ty_python_semantic/resources/mdtest/attributes.md

View workflow job for this annotation

GitHub Actions / cargo test (linux)

unexpected error: 21 [revealed-type] "Revealed type: `Unknown | Divergent | Divergent | int`"

Check failure on line 2432 in crates/ty_python_semantic/resources/mdtest/attributes.md

View workflow job for this annotation

GitHub Actions / cargo test (linux)

unmatched assertion: revealed: Unknown | int
reveal_type(self.x2) # revealed: Unknown | int

Check failure on line 2433 in crates/ty_python_semantic/resources/mdtest/attributes.md

View workflow job for this annotation

GitHub Actions / cargo test (linux)

unexpected error: 21 [revealed-type] "Revealed type: `Unknown | Divergent | Divergent | int`"

Check failure on line 2433 in crates/ty_python_semantic/resources/mdtest/attributes.md

View workflow job for this annotation

GitHub Actions / cargo test (linux)

unmatched assertion: revealed: Unknown | int
reveal_type(self.x3) # revealed: Unknown | int
reveal_type(self.x4) # revealed: Unknown | int
reveal_type(self.x5) # revealed: Unknown | int
Expand Down
6 changes: 3 additions & 3 deletions crates/ty_python_semantic/resources/mdtest/call/union.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def _(flag: bool):

# error: [call-non-callable] "Object of type `Literal["This is a string literal"]` is not callable"
x = f(3)
reveal_type(x) # revealed: Unknown
reveal_type(x) # revealed: None | Unknown
```

## Union of binding errors
Expand All @@ -128,7 +128,7 @@ def _(flag: bool):
# error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1"
# error: [too-many-positional-arguments] "Too many positional arguments to function `f2`: expected 0, got 1"
x = f(3)
reveal_type(x) # revealed: Unknown
reveal_type(x) # revealed: None
```

## One not-callable, one wrong argument
Expand All @@ -146,7 +146,7 @@ def _(flag: bool):
# error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1"
# error: [call-non-callable] "Object of type `C` is not callable"
x = f(3)
reveal_type(x) # revealed: Unknown
reveal_type(x) # revealed: None | Unknown
```

## Union including a special-cased function
Expand Down
23 changes: 23 additions & 0 deletions crates/ty_python_semantic/resources/mdtest/cycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ reveal_type(p.x) # revealed: Unknown | int
reveal_type(p.y) # revealed: Unknown | int
```

## Self-referential bare type alias

```py
A = list["A" | None]

def f(x: A):
# TODO: should be `list[A | None]`?
reveal_type(x) # revealed: list[Divergent]
# TODO: should be `A | None`?
reveal_type(x[0]) # revealed: Divergent
```

## Self-referential type variables

```py
from typing import Generic, TypeVar

B = TypeVar("B", bound="Base")

class Base(Generic[B]):
pass
```

## Parameter default values

This is a regression test for <https://github.com/astral-sh/ty/issues/1402>. When a parameter has a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ match obj:

```py
class C:
def __await__(self): ...
def __await__(self):
yield

# error: [invalid-syntax] "`return` statement outside of a function"
return
Expand Down
Loading
Loading