Skip to content

Commit 35d9aef

Browse files
vlaciLászló Vaskó
and
László Vaskó
authored
is_singleton_type: move business logic to type definitions (#13165)
This greatly reduces complexity as each type can determine for themselves if they are representing a singleton. `get_enum_values` has to be moved as well, as it is used by `get_singleton_type`. Relates-to: #13117 Co-authored-by: László Vaskó <[email protected]>
1 parent 6635b47 commit 35d9aef

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

mypy/typeops.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -719,11 +719,6 @@ def is_literal_type_like(t: Optional[Type]) -> bool:
719719
return False
720720

721721

722-
def get_enum_values(typ: Instance) -> List[str]:
723-
"""Return the list of values for an Enum."""
724-
return [name for name, sym in typ.type.names.items() if isinstance(sym.node, Var)]
725-
726-
727722
def is_singleton_type(typ: Type) -> bool:
728723
"""Returns 'true' if this type is a "singleton type" -- if there exists
729724
exactly only one runtime value associated with this type.
@@ -741,16 +736,7 @@ def is_singleton_type(typ: Type) -> bool:
741736
constructing two distinct instances of 100001.
742737
"""
743738
typ = get_proper_type(typ)
744-
# TODO:
745-
# Also make this return True if the type corresponds to NotImplemented?
746-
return (
747-
isinstance(typ, NoneType)
748-
or (isinstance(typ, LiteralType)
749-
and (typ.is_enum_literal() or isinstance(typ.value, bool)))
750-
or (isinstance(typ, Instance) and (
751-
typ.type.is_enum and len(get_enum_values(typ)) == 1
752-
or typ.type.fullname == 'builtins.ellipsis'))
753-
)
739+
return typ.is_singleton_type()
754740

755741

756742
def try_expanding_sum_type_to_union(typ: Type, target_fullname: str) -> ProperType:
@@ -827,7 +813,7 @@ def try_contracting_literals_in_union(types: Sequence[Type]) -> List[ProperType]
827813
fullname = typ.fallback.type.fullname
828814
if typ.fallback.type.is_enum or isinstance(typ.value, bool):
829815
if fullname not in sum_types:
830-
sum_types[fullname] = (set(get_enum_values(typ.fallback))
816+
sum_types[fullname] = (set(typ.fallback.get_enum_values())
831817
if typ.fallback.type.is_enum
832818
else {True, False},
833819
[])
@@ -855,7 +841,7 @@ def coerce_to_literal(typ: Type) -> Type:
855841
if typ.last_known_value:
856842
return typ.last_known_value
857843
elif typ.type.is_enum:
858-
enum_values = get_enum_values(typ)
844+
enum_values = typ.get_enum_values()
859845
if len(enum_values) == 1:
860846
return LiteralType(value=enum_values[0], fallback=typ)
861847
return original_type

mypy/types.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ def serialize(self) -> Union[JsonDict, str]:
240240
def deserialize(cls, data: JsonDict) -> 'Type':
241241
raise NotImplementedError(f'Cannot deserialize {cls.__name__} instance')
242242

243+
def is_singleton_type(self) -> bool:
244+
return False
245+
243246

244247
class TypeAliasType(Type):
245248
"""A type alias to another type.
@@ -1027,6 +1030,9 @@ def deserialize(cls, data: JsonDict) -> 'NoneType':
10271030
assert data['.class'] == 'NoneType'
10281031
return NoneType()
10291032

1033+
def is_singleton_type(self) -> bool:
1034+
return True
1035+
10301036

10311037
# NoneType used to be called NoneTyp so to avoid needlessly breaking
10321038
# external plugins we keep that alias here.
@@ -1231,6 +1237,21 @@ def copy_modified(self, *,
12311237
def has_readable_member(self, name: str) -> bool:
12321238
return self.type.has_readable_member(name)
12331239

1240+
def is_singleton_type(self) -> bool:
1241+
# TODO:
1242+
# Also make this return True if the type corresponds to NotImplemented?
1243+
return (
1244+
self.type.is_enum and len(self.get_enum_values()) == 1
1245+
or self.type.fullname == 'builtins.ellipsis'
1246+
)
1247+
1248+
def get_enum_values(self) -> List[str]:
1249+
"""Return the list of values for an Enum."""
1250+
return [
1251+
name for name, sym in self.type.names.items()
1252+
if isinstance(sym.node, mypy.nodes.Var)
1253+
]
1254+
12341255

12351256
class FunctionLike(ProperType):
12361257
"""Abstract base class for function types."""
@@ -2268,6 +2289,9 @@ def deserialize(cls, data: JsonDict) -> 'LiteralType':
22682289
fallback=Instance.deserialize(data['fallback']),
22692290
)
22702291

2292+
def is_singleton_type(self) -> bool:
2293+
return self.is_enum_literal() or isinstance(self.value, bool)
2294+
22712295

22722296
class StarType(ProperType):
22732297
"""The star type *type_parameter.

0 commit comments

Comments
 (0)