python / python/mypy

Covariant type variable error in nested function

Open
#8,191 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug false-positive priority-1-normal topic-type-variables
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

I believe the below code should be allowed:

from typing import *

T_co = TypeVar('T_co', covariant=True)

class Col(Generic[T_co]):
  def __init__(self, items: Iterable[T_co]) -> None:
    self.items = items

  def any(self, pred: Callable[[T_co], bool]) -> bool:
    return any(map(pred, self.items))

  def any_zero(self, fn: Callable[[T_co], int]) -> bool:
    def pred(x: T_co) -> bool: # error: Cannot use type variable as a parameter
      return fn(x) == 0
    return self.any(pred)

I believe the purpose of this error is to disallow breaking variance, e.g.:

  def unsafe(self) -> Callable[[T_co], int]:
    def fn(t: T_co) -> int:
      return id(t)
    return fn

However, restricting variance on nested functions has both false positives (first example), and false negatives:

class Unsafe(Generic[T_co]):
  def __init__(self, fn: Callable[[T_co], int]) -> None:
    self.fn = fn

  def get_fn(self) -> Callable[[T_co], int]:
    return self.fn

The above code has no error, but is not type safe. I believe the proper way to check for this is to look at the signatures of each exposed method and verify that the type parameter is not used with the wrong parity.

mypy 0.740, python 3.7.5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the nested-function examples with mypy 0.740 and compare the reported variance error with the unsafe exposed-method example. Trace the variance checks for nested functions and exposed method signatures. Done means the safe example is accepted while the unsafe cases are rejected without introducing false negatives.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.