facebook / facebook/pyrefly

Invariant code expecting to combine seperate types into union stops working wih indirection

Open
#4,446 0 comments 0 reactions 0 assignees View on GitHub
typechecking
Dominant language
Rust
Stars
7k
Forks
519
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

When pyrefly is solving a generic function with an invariant type parameter, I expect that it always behaves the same (the same generic over different parameters is solved to a union if available).

Instead, the behavior is inconsistent between one with no indirection, and one level of call indirection, where if the arguments are put behind a level of call indirection, pyrefly stops inferring the union solution and instead gives an error.

```py
from collections.abc import Callable
from typing import Literal

class Container[T]:
def get(self) -> T: ...

def combine[T](*args: Container[T]) -> Container[T]: ...

# Code works fine with no indirection (no errors)
x: Container[int | str] = combine(
Container[int](),
Container[str](),
)

def indirection[T](c: Container[T]) -> Container[T]:
return c

# With an added level of indirection, the code stops working
# ERROR sandbox.py:24:5-42: Argument `Container[str]` is not assignable to parameter `*args` with type `Container[int]` in function `combine` [bad-argument-type]
y: Container[int | str] = combine(
indirection(Container[int]()),
indirection(Container[str]()),
)

```

### Sandbox Link

https://pyrefly.org/sandbox/?project=v2.jVVda4MwFP0rF_qgG1WhuBffxtjzhhT2UApaDVrWmqLpuv37nZvENemK7aMx5yb3no9MRuaNFLHh4AerzUbmaTTci-wU7ir61XLtuK4RSptEi2SZURzHBsU_K7nfAAJE-AhvwMluFQ3xyp7RM_yoBZ1k_zkgmmCZ01a11EnIxU4c5IT4NpxAK99udWgIXuPIwMDtNUJza2_TOnyYXy4zSi9rnZpOnFO5m-pWJ1Z2xnzV2NMH91BCnXUtatoh8nckveJzUq3AhdH7oORh0BMAMYx-zfO3nM4EZ4s0e4rSRUbPfXPcC7Rc-F0UnCMQIj89UCbTTUpC-D08Coap0LQUZrj89rgVeDyo0P1lGRV2kgWtNmUdAauPjRgJV_zcyYDTb3jJxkjH9T2GGsvNf-_O6N0sjFPCwTB9c8TbiELQ1gzPoqBWqcOQJckIl32TiC6pZTUkHiIhjqnyq9xqr_jlSOqsGVD2emikd4VGYDIjmIqMgBMDOyZT4Bc

### (Only applicable for extension issues) IDE Information

_No response_

Contributor guide

Open the contributing guide

Research direction

Reproduce the two combine examples from the linked Pyrefly sandbox, comparing direct Container arguments with the indirection function. Trace the invariant generic inference path for these calls; done means both forms infer Container[int | str] without the reported bad-argument-type error.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.