diff --git a/plum/promotion.py b/plum/promotion.py index 62091e2..1df4a26 100644 --- a/plum/promotion.py +++ b/plum/promotion.py @@ -139,8 +139,9 @@ def add_promotion_rule(type1, type2, type_to): def rule(t1: type1, t2: type2): return type_to - # If the types are the same, we don't need to add the reverse rule. - if type1 is type2: + # If the types are the same, we don't need to add the reverse rule. Resolve the + # types to handle the case where types are equal, but not identical. + if TypeHint(resolve_type_hint(type1)) == TypeHint(resolve_type_hint(type2)): return # Escape early. @_promotion_rule.dispatch diff --git a/tests/test_promotion.py b/tests/test_promotion.py index 12417a2..375e134 100644 --- a/tests/test_promotion.py +++ b/tests/test_promotion.py @@ -1,3 +1,5 @@ +import typing +import warnings from numbers import Number from typing import Union @@ -159,7 +161,24 @@ def test_inheritance(convert, promote): assert promote(Re(), n) == ("Num from Re", n) assert promote(Re(), Rat()) == ("Num from Re", "Num from Rat") - # Test that explicit self-promotion works. - # This should also trigger the "escape hatch" in `add_promotion_rule`. - add_promotion_rule(Num, Num, Num) - assert promote(n, n) == (n, n) + +def test_self_promotion(convert, promote): + # This should trigger the "escape hatch" in `add_promotion_rule`. It also should not + # trigger a redefinition warning. Explicitly test for that. + with warnings.catch_warnings(): + warnings.simplefilter("error") + + # Simple case where types are identical: + add_promotion_rule(Num, Num, Num) + n = Num() + assert promote(n, n) == (n, n) + + # Also test a more complicated scenario where the types are equal, but not + # identical. + t1 = typing.Union[int, float] + t2 = typing.Union[float, int] + assert t1 is not t2 + add_promotion_rule(t1, t2, str) + add_conversion_method(int, str, str) + add_conversion_method(float, str, str) + assert promote(1, 1.0) == ("1", "1.0")