Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
544dafa
add more sequents
dcreager Nov 26, 2025
998b20f
add for_each_path
dcreager Nov 26, 2025
3b509e9
it's a start
dcreager Nov 20, 2025
20ecb56
add ConstraintSetAssignability relation
dcreager Nov 26, 2025
fc2f175
use constraint set assignable
dcreager Nov 26, 2025
b7fb679
it works!
dcreager Nov 26, 2025
9950c12
these need to be positional only to be assignable
dcreager Nov 26, 2025
fedc754
this gets recursively expanded now
dcreager Nov 26, 2025
2c62674
clean up the diff
dcreager Nov 26, 2025
2b949b3
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 2, 2025
d88120b
mark these as TODO
dcreager Dec 2, 2025
957304e
mdlint
dcreager Dec 2, 2025
7bbf839
hackity hack
dcreager Dec 2, 2025
3045258
clippity bippity
dcreager Dec 2, 2025
a303b7a
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 2, 2025
58c67fd
don't create T ≤ T constraints
dcreager Nov 25, 2025
beb2956
carry over failing test from conformance suite
dcreager Dec 3, 2025
a0f64bd
even more hack
dcreager Dec 3, 2025
d3fd988
fix tests
dcreager Dec 3, 2025
2e46c8d
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 3, 2025
db5834d
add failing tests
dcreager Dec 3, 2025
77ce24a
allow multiple overloads/callables when inferring
dcreager Dec 3, 2025
85e6143
use self annotation in synthesized __init__ callable
dcreager Dec 3, 2025
3bcca62
doc
dcreager Dec 3, 2025
75e9d66
self
dcreager Dec 3, 2025
94aca37
skip non-inferable
dcreager Dec 3, 2025
b90cdfc
generic
dcreager Dec 3, 2025
1e33d25
fix test
dcreager Dec 3, 2025
b314119
catch self-referential typevars
dcreager Dec 4, 2025
54a4f2e
use ConstraintSetAssignability for constraint bounds
dcreager Dec 4, 2025
3384392
treat each overload separately
dcreager Dec 4, 2025
8c7e20a
format, really?!?!
dcreager Dec 4, 2025
c0dc6cf
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 5, 2025
c74eb12
pull this out into a helper method
dcreager Dec 5, 2025
db488e3
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 5, 2025
056258c
cs assignability for paramspecs
dcreager Dec 5, 2025
657685f
don't throw away return type
dcreager Dec 5, 2025
b84a35f
oh hey that's a real bug
dcreager Dec 5, 2025
a372e63
different TODO explanation for overload example
dcreager Dec 5, 2025
d47e9a6
callable invariance rears its head again
dcreager Dec 5, 2025
6138152
Revert "skip non-inferable"
dcreager Dec 5, 2025
c60560f
do this at the overloads level
dcreager Dec 5, 2025
ecb9c13
gotta get those return types too
dcreager Dec 7, 2025
22c7fc4
don't pivot on never or object
dcreager Dec 7, 2025
c56d5cc
not failing anymore
dcreager Dec 7, 2025
b3e4855
any here
dcreager Dec 7, 2025
81fc51e
update test TODOs
dcreager Dec 7, 2025
72e0c32
clippy
dcreager Dec 7, 2025
f29200c
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 7, 2025
f23ae75
group typevars by binding context
dcreager Dec 9, 2025
f82b3f1
abstract over any mention of a typevar
dcreager Dec 9, 2025
9a37861
skip current type when specializing
dcreager Dec 9, 2025
4f7ad7b
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 10, 2025
b1ede88
add more comments
dcreager Dec 10, 2025
a892be3
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 11, 2025
bfde3e4
update tests
dcreager Dec 11, 2025
f624bfd
clean up the diff
dcreager Dec 11, 2025
c6a4e1c
bump expected diagnostics for static-frame
carljm Dec 11, 2025
4bcca58
add mapping for lower bound too
dcreager Dec 10, 2025
c85f102
no really
dcreager Dec 12, 2025
73acf0a
whelp those are backwards
dcreager Dec 12, 2025
2950af4
calculate variance from parameter type
dcreager Dec 11, 2025
2fd7a7d
limit to valid specializations
dcreager Dec 11, 2025
e476624
never?
dcreager Dec 12, 2025
690310c
not needed anymore
dcreager Dec 12, 2025
c94fbe2
Merge remote-tracking branch 'origin/main' into gggg
dcreager Dec 13, 2025
99ec0be
fix test
dcreager Dec 13, 2025
25a6690
add materialization test
dcreager Dec 13, 2025
e906526
only when function defs are same
dcreager Dec 13, 2025
068eb1f
add sig todo
dcreager Dec 13, 2025
8069064
Merge remote-tracking branch 'origin/dcreager/callable-return' into d…
dcreager Dec 13, 2025
8871fdd
bump expected sympy diagnostics in benchmark
AlexWaygood Dec 13, 2025
ddcd76c
add canonically_ordered
dcreager Dec 14, 2025
3c811c1
canonical ordering for constraint set mappings
dcreager Dec 14, 2025
b9ecab1
fix py-fuzzer test failure
dcreager Dec 14, 2025
8655598
codex attempt 1
dcreager Dec 14, 2025
86271d6
codex 2
dcreager Dec 14, 2025
e583cb7
restore TODOs
dcreager Dec 14, 2025
bdaf8e5
doc
dcreager Dec 14, 2025
a4a3aff
simpler source_order_for
dcreager Dec 14, 2025
d223f64
remove source_order_for
dcreager Dec 14, 2025
49ca97a
lots of renaming
dcreager Dec 15, 2025
5a8a950
sort specialize_constrained by source_order
dcreager Dec 15, 2025
92894d3
reuse self source_order
dcreager Dec 15, 2025
649c7bc
more comment
dcreager Dec 15, 2025
1f34f43
document overall approach
dcreager Dec 15, 2025
7e2ea8b
use source order in specialize_constrained too
dcreager Dec 15, 2025
da31e13
fix test expectation
dcreager Dec 15, 2025
ccb03d3
remove now-unused items
dcreager Dec 15, 2025
019db2a
more comments
dcreager Dec 15, 2025
358185b
document display source_order
dcreager Dec 15, 2025
63c75d8
only fold once
dcreager Dec 15, 2025
88eb5eb
don't always bump
dcreager Dec 15, 2025
7f4893d
place bounds/constraints first
dcreager Dec 15, 2025
d942975
include source_order in display_graph output
dcreager Dec 15, 2025
1dd3cf0
fix test expectations (again)
dcreager Dec 15, 2025
cba45ac
clippy
dcreager Dec 15, 2025
f8a5d04
Merge branch 'dcreager/source-order-constraints' into dcreager/callab…
dcreager Dec 15, 2025
dfcdbcf
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 15, 2025
94b4dd8
track source_order in PathAssignments
dcreager Dec 15, 2025
42185b6
Revert "canonical ordering for constraint set mappings"
dcreager Dec 15, 2025
483f342
Revert "add canonically_ordered"
dcreager Dec 15, 2025
a914071
return a slice!
dcreager Dec 15, 2025
2614be3
add note about paramspec overloads
dcreager Dec 15, 2025
26c847c
add a bunch of callable reveals
dcreager Dec 15, 2025
4e3dd58
fix Class3 example
dcreager Dec 15, 2025
2897d49
add TODO
dcreager Dec 15, 2025
06a02fc
Revert "fix py-fuzzer test failure"
dcreager Dec 15, 2025
44256de
Merge remote-tracking branch 'origin/main' into dcreager/callable-return
dcreager Dec 15, 2025
75b8516
Merge branch 'main' into dcreager/callable-return
dcreager Dec 16, 2025
e79986a
sort those paths
dcreager Dec 15, 2025
18ac8e6
build multiple constraints on a path into union/intersection
dcreager Dec 16, 2025
5b01dba
use vecs
dcreager Dec 16, 2025
0cc5e03
test non-paramspec callables individually
dcreager Dec 16, 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
4 changes: 2 additions & 2 deletions crates/ruff_benchmark/benches/ty_walltime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ static SYMPY: Benchmark = Benchmark::new(
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY312,
},
13030,
13100,
);

static TANJUN: Benchmark = Benchmark::new(
Expand Down Expand Up @@ -223,7 +223,7 @@ static STATIC_FRAME: Benchmark = Benchmark::new(
max_dep_date: "2025-08-09",
python_version: PythonVersion::PY311,
},
950,
1100,
);

#[track_caller]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ reveal_type(B().name_does_not_matter()) # revealed: B
reveal_type(B().positional_only(1)) # revealed: B
reveal_type(B().keyword_only(x=1)) # revealed: B
# TODO: This should deally be `B`
reveal_type(B().decorated_method()) # revealed: Unknown
reveal_type(B().decorated_method()) # revealed: Self@decorated_method

reveal_type(B().a_property) # revealed: B

Expand Down
4 changes: 1 addition & 3 deletions crates/ty_python_semantic/resources/mdtest/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ async def main():
loop = asyncio.get_event_loop()
with concurrent.futures.ThreadPoolExecutor() as pool:
result = await loop.run_in_executor(pool, blocking_function)

# TODO: should be `int`
reveal_type(result) # revealed: Unknown
reveal_type(result) # revealed: int
```

### `asyncio.Task`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ def get_default() -> str:

reveal_type(field(default=1)) # revealed: dataclasses.Field[Literal[1]]
reveal_type(field(default=None)) # revealed: dataclasses.Field[None]
# TODO: this could ideally be `dataclasses.Field[str]` with a better generics solver
reveal_type(field(default_factory=get_default)) # revealed: dataclasses.Field[Unknown]
reveal_type(field(default_factory=get_default)) # revealed: dataclasses.Field[str]
```

## dataclass_transform field_specifiers
Expand Down
9 changes: 4 additions & 5 deletions crates/ty_python_semantic/resources/mdtest/decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,10 @@ from functools import cache
def f(x: int) -> int:
return x**2

# TODO: Should be `_lru_cache_wrapper[int]`
reveal_type(f) # revealed: _lru_cache_wrapper[Unknown]

# TODO: Should be `int`
reveal_type(f(1)) # revealed: Unknown
# revealed: _lru_cache_wrapper[int]
reveal_type(f)
# revealed: int
reveal_type(f(1))
```

## Lambdas as decorators
Expand Down
4 changes: 2 additions & 2 deletions crates/ty_python_semantic/resources/mdtest/deprecated.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ classes. Uses of these items should subsequently produce a warning.
from typing_extensions import deprecated

@deprecated("use OtherClass")
def myfunc(): ...
def myfunc(x: int): ...

myfunc() # error: [deprecated] "use OtherClass"
myfunc(1) # error: [deprecated] "use OtherClass"
```

```py
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,7 @@ def identity(x: T) -> T:
def head(xs: list[T]) -> T:
return xs[0]

# TODO: this should be `Literal[1]`
reveal_type(invoke(identity, 1)) # revealed: Unknown
reveal_type(invoke(identity, 1)) # revealed: Literal[1]

# TODO: this should be `Unknown | int`
reveal_type(invoke(head, [1, 2, 3])) # revealed: Unknown
Comment on lines 560 to 561
Copy link
Member Author

Choose a reason for hiding this comment

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

This TODO is not also removed because we end up inferring this constraint set when comparing head to Callable[[A], B]:

(B@invoke ≤ T@head) ∧ (list[T@head] ≤ A@invoke)

We then try to remove T@head from the constraint set by calculating

∃T@head ⋅ (B@invoke ≤ T@head) ∧ (list[T@head] ≤ A@invoke)

We should be able to pick T@head = B@invoke and simplify that to

(B@invoke = *) ∧ (list[B@invoke] ≤ A@invoke)

which I think would then be enough to propagate through the return type to discharge this TODO. I think this would require adding more derived facts to the sequent map.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,7 @@ V = TypeVar("V", default="V")
class D(Generic[V]):
x: V

# TODO: we shouldn't leak a typevar like this in type inference
reveal_type(D().x) # revealed: V@D
reveal_type(D().x) # revealed: Unknown
```

## Regression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,7 @@ def identity[T](x: T) -> T:
def head[T](xs: list[T]) -> T:
return xs[0]

# TODO: this should be `Literal[1]`
reveal_type(invoke(identity, 1)) # revealed: Unknown
reveal_type(invoke(identity, 1)) # revealed: Literal[1]

# TODO: this should be `Unknown | int`
reveal_type(invoke(head, [1, 2, 3])) # revealed: Unknown
Expand Down Expand Up @@ -736,3 +735,159 @@ def f[T](x: T, y: Not[T]) -> T:
y = x # error: [invalid-assignment]
return x
```

## `Callable` parameters

We can recurse into the parameters and return values of `Callable` parameters to infer
specializations of a generic function.

```py
from typing import Any, Callable, NoReturn, overload, Self
from ty_extensions import generic_context, into_callable

def accepts_callable[**P, R](callable: Callable[P, R]) -> Callable[P, R]:
return callable

def returns_int() -> int:
raise NotImplementedError

# revealed: () -> int
reveal_type(into_callable(returns_int))
# revealed: () -> int
reveal_type(accepts_callable(returns_int))
# revealed: int
reveal_type(accepts_callable(returns_int)())

class ClassWithoutConstructor: ...

# revealed: () -> ClassWithoutConstructor
reveal_type(into_callable(ClassWithoutConstructor))
# revealed: () -> ClassWithoutConstructor
reveal_type(accepts_callable(ClassWithoutConstructor))
# revealed: ClassWithoutConstructor
reveal_type(accepts_callable(ClassWithoutConstructor)())

class ClassWithNew:
def __new__(cls, *args, **kwargs) -> Self:
raise NotImplementedError

# revealed: (...) -> ClassWithNew
reveal_type(into_callable(ClassWithNew))
# revealed: (...) -> ClassWithNew
reveal_type(accepts_callable(ClassWithNew))
# revealed: ClassWithNew
reveal_type(accepts_callable(ClassWithNew)())

class ClassWithInit:
def __init__(self) -> None: ...

# revealed: () -> ClassWithInit
reveal_type(into_callable(ClassWithInit))
# revealed: () -> ClassWithInit
reveal_type(accepts_callable(ClassWithInit))
# revealed: ClassWithInit
reveal_type(accepts_callable(ClassWithInit)())

class ClassWithNewAndInit:
def __new__(cls, *args, **kwargs) -> Self:
raise NotImplementedError

def __init__(self, x: int) -> None: ...

# TODO: We do not currently solve a common behavioral supertype for the two solutions of P.
# revealed: ((...) -> ClassWithNewAndInit) | ((x: int) -> ClassWithNewAndInit)
reveal_type(into_callable(ClassWithNewAndInit))
# TODO: revealed: ((...) -> ClassWithNewAndInit) | ((x: int) -> ClassWithNewAndInit)
# revealed: (...) -> ClassWithNewAndInit
reveal_type(accepts_callable(ClassWithNewAndInit))
# revealed: ClassWithNewAndInit
reveal_type(accepts_callable(ClassWithNewAndInit)())

class Meta(type):
def __call__(cls, *args: Any, **kwargs: Any) -> NoReturn:
raise NotImplementedError

class ClassWithNoReturnMetatype(metaclass=Meta):
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
raise NotImplementedError

# TODO: The return types here are wrong, because we end up creating a constraint (Never ≤ R), which
# we confuse with "R has no lower bound".
# revealed: (...) -> Never
reveal_type(into_callable(ClassWithNoReturnMetatype))
# TODO: revealed: (...) -> Never
# revealed: (...) -> Unknown
reveal_type(accepts_callable(ClassWithNoReturnMetatype))
# TODO: revealed: Never
# revealed: Unknown
reveal_type(accepts_callable(ClassWithNoReturnMetatype)())

class Proxy: ...

class ClassWithIgnoredInit:
def __new__(cls) -> Proxy:
return Proxy()

def __init__(self, x: int) -> None: ...

# revealed: () -> Proxy
reveal_type(into_callable(ClassWithIgnoredInit))
# revealed: () -> Proxy
reveal_type(accepts_callable(ClassWithIgnoredInit))
# revealed: Proxy
reveal_type(accepts_callable(ClassWithIgnoredInit)())

class ClassWithOverloadedInit[T]:
t: T # invariant

@overload
def __init__(self: "ClassWithOverloadedInit[int]", x: int) -> None: ...
@overload
def __init__(self: "ClassWithOverloadedInit[str]", x: str) -> None: ...
def __init__(self, x: int | str) -> None: ...

# TODO: The old solver cannot handle this overloaded constructor. The ideal solution is that we
# would solve **P once, and map it to the entire overloaded signature of the constructor. This
# mapping would have to include the return types, since there are different return types for each
# overload. We would then also have to determine that R must be equal to the return type of **P's
# solution.

# revealed: Overload[(x: int) -> ClassWithOverloadedInit[int], (x: str) -> ClassWithOverloadedInit[str]]
reveal_type(into_callable(ClassWithOverloadedInit))
# TODO: revealed: Overload[(x: int) -> ClassWithOverloadedInit[int], (x: str) -> ClassWithOverloadedInit[str]]
# revealed: Overload[(x: int) -> ClassWithOverloadedInit[int] | ClassWithOverloadedInit[str], (x: str) -> ClassWithOverloadedInit[int] | ClassWithOverloadedInit[str]]
reveal_type(accepts_callable(ClassWithOverloadedInit))
# TODO: revealed: ClassWithOverloadedInit[int]
# revealed: ClassWithOverloadedInit[int] | ClassWithOverloadedInit[str]
reveal_type(accepts_callable(ClassWithOverloadedInit)(0))
# TODO: revealed: ClassWithOverloadedInit[str]
# revealed: ClassWithOverloadedInit[int] | ClassWithOverloadedInit[str]
reveal_type(accepts_callable(ClassWithOverloadedInit)(""))

class GenericClass[T]:
t: T # invariant

def __new__(cls, x: list[T], y: list[T]) -> Self:
raise NotImplementedError

def _(x: list[str]):
# TODO: This fails because we are not propagating GenericClass's generic context into the
# Callable that we create for it.
# revealed: (x: list[T@GenericClass], y: list[T@GenericClass]) -> GenericClass[T@GenericClass]
reveal_type(into_callable(GenericClass))
# revealed: ty_extensions.GenericContext[T@GenericClass]
reveal_type(generic_context(into_callable(GenericClass)))

# revealed: (x: list[T@GenericClass], y: list[T@GenericClass]) -> GenericClass[T@GenericClass]
reveal_type(accepts_callable(GenericClass))
# TODO: revealed: ty_extensions.GenericContext[T@GenericClass]
# revealed: None
reveal_type(generic_context(accepts_callable(GenericClass)))

# TODO: revealed: GenericClass[str]
# TODO: no errors
# revealed: GenericClass[T@GenericClass]
# error: [invalid-argument-type]
# error: [invalid-argument-type]
reveal_type(accepts_callable(GenericClass)(x, x))
```
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,8 @@ class C[**P]:
def __init__(self, f: Callable[P, int]) -> None:
self.f = f

def f(x: int, y: str) -> bool:
# Note that the return type must match exactly, since C is invariant on the return type of C.f.
def f(x: int, y: str) -> int:
return True

c = C(f)
Expand Down Expand Up @@ -618,6 +619,22 @@ reveal_type(foo.method) # revealed: bound method Foo[(int, str, /)].method(int,
reveal_type(foo.method(1, "a")) # revealed: str
```

### Gradual types propagate through `ParamSpec` inference

```py
from typing import Callable

def callable_identity[**P, R](func: Callable[P, R]) -> Callable[P, R]:
return func

@callable_identity
def f(env: dict) -> None:
pass

# revealed: (env: dict[Unknown, Unknown]) -> None
reveal_type(f)
```

### Overloads

`overloaded.pyi`:
Expand Down Expand Up @@ -662,7 +679,7 @@ reveal_type(change_return_type(int_int)) # revealed: Overload[(x: int) -> str,
reveal_type(change_return_type(int_str)) # revealed: Overload[(x: int) -> str, (x: str) -> str]

# error: [invalid-argument-type]
reveal_type(change_return_type(str_str)) # revealed: Overload[(x: int) -> str, (x: str) -> str]
reveal_type(change_return_type(str_str)) # revealed: (...) -> str
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, why do we lose the parameters here?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is an example where we're now collectively taking into account all of the constraints across the entire call site. In this case, we're correctly flagging invalid-argument-type, because change_return_type expects a callable that returns an int, which neither overload of str_str does. Before we went ahead and inferred a specialization of P from the callable parameter, even though it was invalid. But now, since the argument is invalid, we don't infer anything for P, and fall back on its Unknown equivalent (...)


# TODO: Both of these shouldn't raise an error
# error: [invalid-argument-type]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ reveal_type(C[int]().y) # revealed: int
class D[T = T]:
x: T

reveal_type(D().x) # revealed: T@D
reveal_type(D().x) # revealed: Unknown
Copy link
Member Author

Choose a reason for hiding this comment

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

This is an error condition anyway, and I find it better to infer Unknown here than to let the typevar leak through when we were supposed to have solved it.

```

[pep 695]: https://peps.python.org/pep-0695/
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ from ty_extensions import ConstraintSet, generic_context
def mentions[T, U]():
# (T@mentions ≤ int) ∧ (U@mentions = list[T@mentions])
constraints = ConstraintSet.range(Never, T, int) & ConstraintSet.range(list[T], U, list[T])
# revealed: ty_extensions.Specialization[T@mentions = int, U@mentions = list[int]]
# TODO: revealed: ty_extensions.Specialization[T@mentions = int, U@mentions = list[int]]
# revealed: ty_extensions.Specialization[T@mentions = int, U@mentions = Unknown]
reveal_type(generic_context(mentions).specialize_constrained(constraints))
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ x11: list[Literal[1] | Literal[2] | Literal[3]] = [1, 2, 3]
reveal_type(x11) # revealed: list[Literal[1, 2, 3]]

x12: Y[Y[Literal[1]]] = [[1]]
reveal_type(x12) # revealed: list[Y[Literal[1]]]
reveal_type(x12) # revealed: list[list[Literal[1]]]
Copy link
Member Author

Choose a reason for hiding this comment

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

This is because we're now using specialize_recursive instead of specialize_partial.


x13: list[tuple[Literal[1], Literal[2], Literal[3]]] = [(1, 2, 3)]
reveal_type(x13) # revealed: list[tuple[Literal[1], Literal[2], Literal[3]]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/deprecated.md
1 | from typing_extensions import deprecated
2 |
3 | @deprecated("use OtherClass")
4 | def myfunc(): ...
4 | def myfunc(x: int): ...
5 |
6 | myfunc() # error: [deprecated] "use OtherClass"
6 | myfunc(1) # error: [deprecated] "use OtherClass"
7 | from typing_extensions import deprecated
8 |
9 | @deprecated("use BetterClass")
Expand All @@ -42,9 +42,9 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/deprecated.md
warning[deprecated]: The function `myfunc` is deprecated
--> src/mdtest_snippet.py:6:1
|
4 | def myfunc(): ...
4 | def myfunc(x: int): ...
5 |
6 | myfunc() # error: [deprecated] "use OtherClass"
6 | myfunc(1) # error: [deprecated] "use OtherClass"
| ^^^^^^ use OtherClass
7 | from typing_extensions import deprecated
|
Expand Down
Loading