Skip to content

Commit

Permalink
[mypyc] Add LoadAddress op for PySet_Type & PyFrozenSet_Type
Browse files Browse the repository at this point in the history
This also fixes mypyc/mypyc#917

RE above, the root issue is that mypyc didn't know builtins.set was a
built-in name, so it guessed it comes from the module globals. This
didn't blow up anything up somehow... until the dataclasses
commit[^1] which made the `__annotations__` logic for dataclasses try to
better preserve the type annotations (previously they would be erased
to builtins.type). This new logic would use `load_type` to load
`builtins.set` (so it can be put in `__annotations__`) which went poorly
as only types registered with `load_address_op` are considered
built-ins.

[^1]: python@1bcfc04
  • Loading branch information
ichard26 committed Jul 3, 2022
1 parent 914297e commit e6882c3
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 5 deletions.
16 changes: 15 additions & 1 deletion mypyc/primitives/set_ops.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
"""Primitive set (and frozenset) ops."""

from mypyc.primitives.registry import function_op, method_op, binary_op, ERR_NEG_INT
from mypyc.primitives.registry import (
load_address_op, function_op, method_op, binary_op, ERR_NEG_INT
)
from mypyc.ir.ops import ERR_MAGIC, ERR_FALSE
from mypyc.ir.rtypes import (
object_rprimitive, bool_rprimitive, set_rprimitive, c_int_rprimitive, pointer_rprimitive,
bit_rprimitive
)


# Get the 'builtins.set' type object.
load_address_op(
name='builtins.set',
type=object_rprimitive,
src='PySet_Type')

# Get the 'builtins.frozenset' tyoe object.
load_address_op(
name='builtins.frozenset',
type=object_rprimitive,
src='PyFrozenSet_Type')

# Construct an empty set.
new_set_op = function_op(
name='builtins.set',
Expand Down
10 changes: 8 additions & 2 deletions mypyc/test-data/fixtures/ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from typing import (
TypeVar, Generic, List, Iterator, Iterable, Dict, Optional, Tuple, Any, Set,
overload, Mapping, Union, Callable, Sequence,
overload, Mapping, Union, Callable, Sequence, FrozenSet, AbstractSet
)

T = TypeVar('T')
Expand Down Expand Up @@ -211,7 +211,13 @@ def discard(self, x: T) -> None: pass
def clear(self) -> None: pass
def pop(self) -> T: pass
def update(self, x: Iterable[S]) -> None: pass
def __or__(self, s: Set[S]) -> Set[Union[T, S]]: ...
def __or__(self, s: AbstractSet[S]) -> Set[Union[T, S]]: ...

class frozenset(Generic[T]):
def __init__(self, i: Optional[Iterable[T]] = None) -> None: pass
def __iter__(self) -> Iterator[T]: pass
def __len__(self) -> int: pass
def __or__(self, s: AbstractSet[S]) -> FrozenSet[Union[T, S]]: ...

class slice: pass

Expand Down
23 changes: 23 additions & 0 deletions mypyc/test-data/fixtures/typing-full.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ TypeVar = 0
Generic = 0
Protocol = 0
Tuple = 0
Set = 0
FrozenSet = 0
Callable = 0
_promote = 0
NamedTuple = 0
Expand Down Expand Up @@ -138,6 +140,27 @@ class Mapping(Iterable[T], Generic[T, T_co], metaclass=ABCMeta):
class MutableMapping(Mapping[T, U], metaclass=ABCMeta):
def __setitem__(self, k: T, v: U) -> None: pass

@runtime_checkable
class Collection(Iterable[T_co], Container[T_co], Protocol[T_co]):
# Implement Sized (but don't have it as a base class).
@abstractmethod
def __len__(self) -> int: ...

class AbstractSet(Collection[T_co], Generic[T_co]):
@abstractmethod
def __contains__(self, x: object) -> bool: ...
def _hash(self) -> int: ...
# Mixin methods
def __le__(self, other: AbstractSet[Any]) -> bool: ...
def __lt__(self, other: AbstractSet[Any]) -> bool: ...
def __gt__(self, other: AbstractSet[Any]) -> bool: ...
def __ge__(self, other: AbstractSet[Any]) -> bool: ...
def __and__(self, other: AbstractSet[Any]) -> AbstractSet[T_co]: ...
def __or__(self, other: AbstractSet[T]) -> AbstractSet[T_co | T]: ...
def __sub__(self, other: AbstractSet[Any]) -> AbstractSet[T_co]: ...
def __xor__(self, other: AbstractSet[T]) -> AbstractSet[T_co | T]: ...
def isdisjoint(self, other: Iterable[Any]) -> bool: ...

class SupportsInt(Protocol):
def __int__(self) -> int: pass

Expand Down
12 changes: 10 additions & 2 deletions mypyc/test-data/run-python37.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[case testRunDataclass]
import dataclasses
from dataclasses import dataclass, field
from typing import Set, List, Callable, Any
from typing import Set, FrozenSet, List, Callable, Any

@dataclass
class Person1:
Expand Down Expand Up @@ -68,8 +68,15 @@ class Person4:
def name(self) -> str:
return self._name

@dataclass
class Person5:
friends: Set[str] = field(default_factory=set)
parents: FrozenSet[str] = frozenset()

[typing fixtures/typing-full.pyi]

[file other.py]
from native import Person1, Person1b, Person2, Person3, Person4, testBool
from native import Person1, Person1b, Person2, Person3, Person4, Person5, testBool
i1 = Person1(age = 5, name = 'robot')
assert i1.age == 5
assert i1.name == 'robot'
Expand Down Expand Up @@ -117,6 +124,7 @@ assert i8 > i9

assert Person1.__annotations__ == {'age': int, 'name': str}
assert Person2.__annotations__ == {'age': int, 'name': str}
assert Person5.__annotations__ == {'friends': set, 'parents': frozenset}

[file driver.py]
import sys
Expand Down

0 comments on commit e6882c3

Please sign in to comment.