Skip to content

Commit

Permalink
fix min(Enum) (#474)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored Feb 10, 2022
1 parent f63da81 commit ffdb0ff
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Fix bug affecting type compatibility between
generics and literals (#474)
- Add support for `typing.Never` and `typing_extensions.Never` (#472)
- Add `inferred_any`, an extremely noisy error code
that triggers whenever the type checker infers something as `Any` (#471)
Expand Down
12 changes: 12 additions & 0 deletions pyanalyze/test_typevar.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,15 @@ def test_call_with_value_restriction(self):
def capybara(c: CallableT, u: UnionT) -> None:
c(3)
u(3)

@assert_passes()
def test_min_enum(self):
import enum

class E(enum.IntEnum):
a = 1
b = 2

def capybara():
m = min(E)
assert_is_value(m, TypedValue(E))
13 changes: 8 additions & 5 deletions pyanalyze/value.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,11 @@ def can_assign(self, other: Value, ctx: CanAssignContext) -> CanAssign:
# enums, but they are ints at runtime.
return self.can_assign_thrift_enum(other, ctx)
elif isinstance(other, KnownValue):
if self_tobj.is_instance(other.val):
return {}
return self_tobj.can_assign(self, other, ctx)
can_assign = self_tobj.can_assign(self, other, ctx)
if isinstance(can_assign, CanAssignError):
if self_tobj.is_instance(other.val):
return {}
return can_assign
elif isinstance(other, TypedValue):
return self_tobj.can_assign(self, other, ctx)
elif isinstance(other, SubclassValue):
Expand Down Expand Up @@ -782,6 +784,7 @@ def __str__(self) -> str:
return f"{stringify_object(self.typ)}[{args_str}]"

def can_assign(self, other: Value, ctx: CanAssignContext) -> CanAssign:
original_other = other
other = replace_known_sequence_value(other)
if isinstance(other, KnownValue):
other = TypedValue(type(other.val))
Expand All @@ -790,7 +793,7 @@ def can_assign(self, other: Value, ctx: CanAssignContext) -> CanAssign:
# If we don't think it's a generic base, try super;
# runtime isinstance() may disagree.
if generic_args is None or len(self.args) != len(generic_args):
return super().can_assign(other, ctx)
return super().can_assign(original_other, ctx)
bounds_maps = []
for i, (my_arg, their_arg) in enumerate(zip(self.args, generic_args)):
can_assign = my_arg.can_assign(their_arg, ctx)
Expand All @@ -801,7 +804,7 @@ def can_assign(self, other: Value, ctx: CanAssignContext) -> CanAssign:
return CanAssignError(f"Cannot assign {other} to {self}")
return unify_bounds_maps(bounds_maps)

return super().can_assign(other, ctx)
return super().can_assign(original_other, ctx)

def maybe_specify_error(
self, i: int, other: Value, error: CanAssignError, ctx: CanAssignContext
Expand Down

0 comments on commit ffdb0ff

Please sign in to comment.