facebookincubator / cinder

Cinder is Meta's internal performance-oriented production version of CPython.
https://trycinder.com
Other
3.49k stars 121 forks source link

PyDict is not equivalent to dict #41

Closed LuKuangChen closed 3 years ago

LuKuangChen commented 3 years ago

What version of Static Python are you using?

9965302 2021-07-15

The Problem

We believe that PyDict is supposed to be the same as the dict type. However, the following pair of programs reveals that these two type constructors are not equivalent. Is this a bug? Or are there some subtle differences between PyDict and dict?

$ diff ./CheckedDict_is_dict.py ./CheckedDict_is_not_PyDict.py 
...
7c7
< def consumer(d: dict[int, int]) -> int:
---
> def consumer(d: PyDict[int, int]) -> int:
...
# CheckedDict_is_dict.py
from __static__ import CheckedDict

def producer() -> CheckedDict[int, int]:
    return CheckedDict[int, int]({2: 3})

def consumer(d: dict[int, int]) -> int:
    return d[2]

d = producer()
print(consumer(d))  # 3
# CheckedDict_is_not_PyDict.py
from __static__ import CheckedDict, PyDict

def producer() -> CheckedDict[int, int]:
    return CheckedDict[int, int]({2: 3})

def consumer(d: PyDict[int, int]) -> int:
    return d[2]

d = producer()
print(consumer(d))

# We expected the value `3`, but saw
#
#    compiler.static.TypedSyntaxError: type mismatch: chkdict[int, int]
#    received for positional arg 'd', expected dict
LuKuangChen commented 3 years ago

We just realized that dict[int, int] is read as dynamic because dict from the typing module is not handled. This file lists types that are defined by the typing module and are understood by Static Python. The list includes Dict, but no dict. Our two programs raise the same error after replacing dict with Dict.

The corrected program:

# CheckedDict_is_not_Dict.py
from __static__ import CheckedDict
from typing import Dict

def producer() -> CheckedDict[int, int]:
    return CheckedDict[int, int]({2: 3})

def consumer(d: Dict[int, int]) -> int:
    return d[2]

d = producer()
print(consumer(d))
# compiler.static.TypedSyntaxError: type mismatch: chkdict[int, int]
# received for positional arg 'd', expected dict