facebook / facebook/pyrefly

`__new__` annotated as `Any` causes constructor call to be inferred as `Any`

Open
#4,463 2 comments 0 reactions 0 assignees View on GitHub
needs-discussion typechecking
Dominant language
Rust
Stars
7k
Forks
516
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

When a class defines `__new__` with return type `Any`, `pyrefly` infers the constructor call as `Any` rather than the class type. This causes `no-any-return-explicit` when the constructor result is returned from a function annotated to return that class.

```
from typing import Any, reveal_type

class MyClass:
def __new__(cls) -> Any:
return super().__new__(cls)

def my_func() -> MyClass:
x = MyClass()
reveal_type(x)
reveal_type(MyClass)
return x # ERROR: Returning Any from function declared to return "MyClass"
```

I understand why this happens, but it feels surprising that a function declared to return `MyClass` reports an error when returning `MyClass()`. Should `pyrefly` treat a constructor call as the class type in this case, even if `__new__` is annotated as returning `Any`?

I saw this pattern with `jinja2` using `Template.__new__` ([here](https://github.com/pallets/jinja/blob/main/src/jinja2/environment.py#L1164)), which returns `Any`.

For comparison, `mypy` treats `MyClass()` as `MyClass` despite the `Any` return annotation on `__new__`:
```
$ mypy --strict example.py
example.py:9: note: Revealed type is "example.MyClass"
example.py:10: note: Revealed type is "def () -> example.MyClass"
```

This seems like one of those cases were `pyrefly` is more technically correct, but `mypy` provides a better user experience. I don't know the ramifications of such a change though.

### Sandbox Link

https://pyrefly.org/sandbox/?project=v2.lZQxD4IwEIX_ykUWHaQ7u6PRdCYxBBskQdrQouXfe722hKIhcT16j971e-_fyFyFjXfUeaL8TBzVizcaqu40MYC932TpUYlhf8iXh6MJntPN-cATlOpbXESoOB684Hyrvf1RC8fnL_R7C5DBifMLL4BTyQ2LNwUaPtoQ58Ep8SnAyNha7oJi6Va9wiCDqy9A2CgGIPLTjBizqJeXfYYJK-BhjNIFY7FdDg0TPbvLWrOkg4EjvnpVLYV3KgeSsNUou8GfGoQWhkqIsat4IHNhVdfWrTlWOPcSw01qPg

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

_No response_

Contributor guide

Open the contributing guide

Research direction

Reproduce the example in the linked Pyrefly sandbox and inspect the revealed types and return error. Trace the constructor-call inference for a class whose __new__ returns Any, then compare the result with the stated mypy behavior. Done means the intended constructor type is established and covered by a regression test without breaking relevant __new__ semantics.

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.