pyre-check icon indicating copy to clipboard operation
pyre-check copied to clipboard

Explicit TypeVars (e.g. `TypeVar("T", int, str)`) can't be satisfied from refinement + new construction

Open fliepeltje opened this issue 4 years ago • 2 comments

When returning a value that fits within the typevar constraint, the checker returns an Incompatible return type [7] error. To reproduce:

T = TypeVar("T", int, str)

def fn(value: T) -> T:
    if isinstance(value, int):
        return int(5)
    else:
        return str("five")

This raises Incompatible return type [7]: Expected Variable[T <: [int, str]] but got int and Incompatible return type [7]: Expected Variable[T <: [int, str]] but got str

This works correctly:

def fn(value: T) -> T:
    return value

fliepeltje avatar Feb 26 '20 15:02 fliepeltje

We don't currently support this use of explicit type variables. We already enforce the exterior behavior necessary to make this sound (e.g fn(my_int_subclass) -> int, not my_int_subclass), but have not yet implemented the internal logic to accept these cases as demanded by PEP 484.

Doing so would require some fairly significant extensions to our type variable system, and would be something we'd potentially be interested in doing, and would be possible, but I'd imagine it would unfortunately be a while before we'd get around to it.

mrkmndz avatar Feb 26 '20 18:02 mrkmndz

The current behavior appears to be correct according to PEP 484. The code in the first sample should generate errors.

The problem is that the signature of fn indicates that it accepts an object that must be a subtype of either int or str and return the same type. The body of the function is returning either int or str, which are not guaranteed to be the same as the type of the input parameter value.

The second example is fine because value is know to be of type T, so it's fine for it to be used as a return value.

erictraut avatar Feb 20 '21 01:02 erictraut