Skip to content

Commit 5aa06dc

Browse files
committed
Wrap _BoolExpr for immediate execution.
1 parent 14379e6 commit 5aa06dc

3 files changed

Lines changed: 36 additions & 11 deletions

File tree

typemap/type_eval/_eval_typing.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
if typing.TYPE_CHECKING:
2222
from typing import Any
2323

24-
from . import _apply_generic, _typing_inspect
24+
from . import _apply_generic, _typing_inspect, _wrapped_value
2525

2626

2727
__all__ = ("eval_typing",)
@@ -437,11 +437,12 @@ class _GlobalsWrapper(dict):
437437
438438
For example, suppose we have:
439439
440-
type IsIntBool[T] = Bool[IsSub[T, int]]
440+
type IsIntBool[T] = IsSub[T, int]
441441
type IsIntLiteral[T] = Literal[True] if IsIntBool[T] else Literal[False]
442442
443-
Though Bool is a special form, IsIntBool is not, and so when used in a
444-
boolean context, it will always evaluate to true.
443+
Though `IsSub` results in a `_LiteralGeneric`, `IsIntBool` is not itself
444+
a `_LiteralGeneric`. So when used in `IsIntLiteral`, it will always evaluate
445+
to true.
445446
"""
446447

447448
def __init__(self, base_dict, ctx):
@@ -452,6 +453,10 @@ def __getitem__(self, key):
452453
value = super().__getitem__(key)
453454
if isinstance(value, typing.TypeAliasType):
454455
return _TypeAliasWrapper(value, self._ctx)
456+
elif isinstance(value, type) and issubclass(
457+
value, _wrapped_value._BoolExpr
458+
):
459+
return _GenericClassWrapper(value, self._ctx)
455460
return value
456461

457462

@@ -472,6 +477,22 @@ def __getattr__(self, name):
472477
return getattr(self._type_alias, name)
473478

474479

480+
class _GenericClassWrapper:
481+
def __init__(self, generic_class, ctx):
482+
self._generic_class = generic_class
483+
self._ctx = ctx
484+
485+
def __getitem__(self, item):
486+
result = self._generic_class[item]
487+
# Immediately evaluate the generic alias
488+
if isinstance(result, (types.GenericAlias, typing._GenericAlias)):
489+
return _eval_types(result, self._ctx)
490+
return result
491+
492+
def __getattr__(self, name):
493+
return getattr(self._generic_class, name)
494+
495+
475496
@_eval_types_impl.register
476497
def _eval_applied_class(obj: typing_GenericAlias, ctx: EvalContext):
477498
"""Eval a typing._GenericAlias -- an applied user-defined class"""

typemap/type_eval/_wrapped_value.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
class _BoolExpr:
2+
pass
3+
4+
15
class _BoolValue:
26
class _WrappedInstance:
37
def __init__(self, value: bool, type_name: str):

typemap/typing.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import _GenericAlias # type: ignore
55

66

7-
from .type_eval._wrapped_value import _BoolValue
7+
from .type_eval._wrapped_value import _BoolExpr, _BoolValue
88

99

1010
_SpecialForm: typing.Any = typing._SpecialForm
@@ -210,30 +210,30 @@ def __bool__(self):
210210
return False
211211

212212

213-
class IsSubtype[Lhs, Rhs]:
213+
class IsSubtype[Lhs, Rhs](_BoolExpr):
214214
pass
215215

216216

217-
class IsSubSimilar[Lhs, Rhs]:
217+
class IsSubSimilar[Lhs, Rhs](_BoolExpr):
218218
pass
219219

220220

221-
class Matches[Lhs, Rhs]:
221+
class Matches[Lhs, Rhs](_BoolExpr):
222222
pass
223223

224224

225225
IsSub = IsSubSimilar
226226

227227

228-
class AllOf[*Ts]:
228+
class AllOf[*Ts](_BoolExpr):
229229
pass
230230

231231

232-
class AnyOf[*Ts]:
232+
class AnyOf[*Ts](_BoolExpr):
233233
pass
234234

235235

236-
class Bool[T: typing.Literal[True, False]]:
236+
class Bool[T: typing.Literal[True, False]](_BoolExpr):
237237
pass
238238

239239

0 commit comments

Comments
 (0)