Skip to content

Commit

Permalink
bpo-44636: Collapse union of equal types (GH-27178)
Browse files Browse the repository at this point in the history
The result of `int | int` is now `int`.

Fix comparison of the union type with non-hashable objects.
`int | str == {}` no longer raises a TypeError.
  • Loading branch information
serhiy-storchaka committed Jul 16, 2021
1 parent aeaa553 commit d9f9232
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
7 changes: 6 additions & 1 deletion Lib/test/test_types.py
Expand Up @@ -623,7 +623,7 @@ def test_or_types_operator(self):
self.assertEqual(None | typing.List[int], typing.Union[None, typing.List[int]])
self.assertEqual(str | float | int | complex | int, (int | str) | (float | complex))
self.assertEqual(typing.Union[str, int, typing.List[int]], str | int | typing.List[int])
self.assertEqual(int | int, int)
self.assertIs(int | int, int)
self.assertEqual(
BaseException |
bool |
Expand Down Expand Up @@ -651,6 +651,8 @@ def test_or_types_operator(self):
3 | int
with self.assertRaises(TypeError):
Example() | int
x = int | str
self.assertNotEqual(x, {})
with self.assertRaises(TypeError):
(int | str) < typing.Union[str, int]
with self.assertRaises(TypeError):
Expand Down Expand Up @@ -704,6 +706,8 @@ def test_or_type_operator_with_TypeVar(self):
TV = typing.TypeVar('T')
assert TV | str == typing.Union[TV, str]
assert str | TV == typing.Union[str, TV]
self.assertIs((int | TV)[int], int)
self.assertIs((TV | int)[int], int)

def test_union_args(self):
self.assertEqual((int | str).__args__, (int, str))
Expand All @@ -721,6 +725,7 @@ def test_union_parameter_chaining(self):
self.assertEqual(list[int | list[T]][str], list[int | list[str]])
self.assertEqual((list[T] | list[S]).__parameters__, (T, S))
self.assertEqual((list[T] | list[S])[int, T], list[int] | list[T])
self.assertEqual((list[T] | list[S])[int, int], list[int])

def test_or_type_operator_with_forward(self):
T = typing.TypeVar('T')
Expand Down
@@ -0,0 +1 @@
Collapse union of equal types. E.g. the result of ``int | int`` is now ``int``. Fix comparison of the union type with non-hashable objects. E.g. ``int | str == {}`` no longer raises a TypeError.
24 changes: 16 additions & 8 deletions Objects/unionobject.c
Expand Up @@ -187,9 +187,9 @@ union_richcompare(PyObject *a, PyObject *b, int op)
}
}
} else {
if (PySet_Add(b_set, b) == -1) {
goto exit;
}
Py_DECREF(a_set);
Py_DECREF(b_set);
Py_RETURN_NOTIMPLEMENTED;
}
result = PyObject_RichCompare(a_set, b_set, op);
exit:
Expand Down Expand Up @@ -551,17 +551,25 @@ _Py_Union(PyObject *args)
}
}

args = dedup_and_flatten_args(args);
if (args == NULL) {
return NULL;
}
if (PyTuple_GET_SIZE(args) == 1) {
PyObject *result1 = PyTuple_GET_ITEM(args, 0);
Py_INCREF(result1);
Py_DECREF(args);
return result1;
}

result = PyObject_GC_New(unionobject, &_Py_UnionType);
if (result == NULL) {
Py_DECREF(args);
return NULL;
}

result->parameters = NULL;
result->args = dedup_and_flatten_args(args);
result->args = args;
_PyObject_GC_TRACK(result);
if (result->args == NULL) {
Py_DECREF(result);
return NULL;
}
return (PyObject*)result;
}

0 comments on commit d9f9232

Please sign in to comment.