[ty] Fix panic when attempting to validate the members of a protocol that inherits from a protocol in another module (#20956)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (macos) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / ty completion evaluation (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks walltime (medium|multithreaded) (push) Blocked by required conditions
CI / benchmarks walltime (small|large) (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run

This commit is contained in:
Alex Waygood 2025-10-18 15:01:46 +01:00 committed by GitHub
parent 16efe53a72
commit 68c1fa86c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 63 additions and 17 deletions

View file

@ -1114,6 +1114,8 @@ it's a large section).
<!-- snapshot-diagnostics -->
`a.py`:
```py
from typing import Protocol
@ -1140,6 +1142,31 @@ class A(Protocol):
pass
```
Validation of protocols that had cross-module inheritance used to break, so we test that explicitly
here too:
`b.py`:
```py
from typing import Protocol
# Ensure the number of scopes in `b.py` is greater than the number of scopes in `c.py`:
class SomethingUnrelated: ...
class A(Protocol):
x: int
```
`c.py`:
```py
from b import A
from typing import Protocol
class C(A, Protocol):
x = 42 # fine, due to declaration in the base class
```
## Equivalence of protocols
```toml

View file

@ -9,7 +9,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/protocols.md
# Python source files
## mdtest_snippet.py
## a.py
```
1 | from typing import Protocol
@ -37,11 +37,33 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/protocols.md
23 | pass
```
## b.py
```
1 | from typing import Protocol
2 |
3 | # Ensure the number of scopes in `b.py` is greater than the number of scopes in `c.py`:
4 | class SomethingUnrelated: ...
5 |
6 | class A(Protocol):
7 | x: int
```
## c.py
```
1 | from b import A
2 | from typing import Protocol
3 |
4 | class C(A, Protocol):
5 | x = 42 # fine, due to declaration in the base class
```
# Diagnostics
```
warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the body of a protocol class
--> src/mdtest_snippet.py:12:5
--> src/a.py:12:5
|
11 | # error: [ambiguous-protocol-member]
12 | a = None # type: int
@ -50,7 +72,7 @@ warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the
14 | b = ... # type: str
|
info: Assigning to an undeclared variable in a protocol class leads to an ambiguous interface
--> src/mdtest_snippet.py:6:7
--> src/a.py:6:7
|
4 | return True
5 |
@ -66,7 +88,7 @@ info: rule `ambiguous-protocol-member` is enabled by default
```
warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the body of a protocol class
--> src/mdtest_snippet.py:14:5
--> src/a.py:14:5
|
12 | a = None # type: int
13 | # error: [ambiguous-protocol-member]
@ -76,7 +98,7 @@ warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the
16 | if coinflip():
|
info: Assigning to an undeclared variable in a protocol class leads to an ambiguous interface
--> src/mdtest_snippet.py:6:7
--> src/a.py:6:7
|
4 | return True
5 |
@ -92,7 +114,7 @@ info: rule `ambiguous-protocol-member` is enabled by default
```
warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the body of a protocol class
--> src/mdtest_snippet.py:17:9
--> src/a.py:17:9
|
16 | if coinflip():
17 | c = 1 # error: [ambiguous-protocol-member]
@ -101,7 +123,7 @@ warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the
19 | c = 2
|
info: Assigning to an undeclared variable in a protocol class leads to an ambiguous interface
--> src/mdtest_snippet.py:6:7
--> src/a.py:6:7
|
4 | return True
5 |
@ -117,7 +139,7 @@ info: rule `ambiguous-protocol-member` is enabled by default
```
warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the body of a protocol class
--> src/mdtest_snippet.py:22:9
--> src/a.py:22:9
|
21 | # error: [ambiguous-protocol-member]
22 | for d in range(42):
@ -125,7 +147,7 @@ warning[ambiguous-protocol-member]: Cannot assign to undeclared variable in the
23 | pass
|
info: Assigning to an undeclared variable in a protocol class leads to an ambiguous interface
--> src/mdtest_snippet.py:6:7
--> src/a.py:6:7
|
4 | return True
5 |