microsoft / microsoft/pyright

Regression: crtp type bounds lost

Open
#10,420 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
15.6k
Forks
1.8k
Avg merge
12h 13m
Merged PRs (30d)
52

Description

**Describe the bug**

In the example below, I have two ways of turning a function that takes a recursive visitor as a second argument into a simple-recursive one.

In the `make_rec_protocol` case, I expect that the revealed type of the return value is `Recursive[T@_protocol, T@_protocol]` and in the `make_rec_callable` that it is `Callable[[T@_callable], T@_callable]`.

In 1.1.375 this is the case.

In 1.1.376 and later, `make_rec_callable` has a type of `Callable[[Node[Any]], Node[Any]`

In 1.1.388 and later, `make_rec_protocol` has a type of `Recursive[Node[Any], Node[Any]]`.

So it appears like the actual generics are being lost and only the bound on the generic is being inferred.

Is this correct due to a tightening of the rules, or a regression?

**Code or Screenshots**

```python
from typing import Any, Protocol, Callable

class Node[T: "Node[Any]"]:
...

class Recursive[U_contra, V_co](Protocol):
def __call__(self, value: U_contra) -> V_co:
...

def _protocol[T: "Node[Any]"](node: T, fn: Recursive[T, T]) -> T:
...

def _callable[T: "Node[Any]"](node: T, fn: Callable[[T], T]) -> T:
...

def make_rec_protocol[U_contra, V_co](
fn: Callable[[U_contra, Recursive[U_contra, V_co]], V_co]
) -> Recursive[U_contra, V_co]:
...

def make_rec_callable[U_contra, V_co](
fn: Callable[[U_contra, Callable[[U_contra], V_co]], V_co]
) -> Callable[[U_contra], V_co]:
...

reveal_type(make_rec_protocol(_protocol)) # Expect Recursive[T@_protocol, T@_protocol]

reveal_type(make_rec_callable(_callable)) # Expect Callable[[T@_callable], T@_callable]
```

Contributor guide

Open the contributing guide

Research direction

No repository file or test is named. Start by reproducing the supplied Python snippet with Pyright 1.1.375, 1.1.376, and 1.1.388 or later, then trace the generic inference path for make_rec_protocol and make_rec_callable. Done means determining whether the revealed types preserve the type variables or incorrectly widen them to their bounds, with a regression test covering the result.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.