Files
ruff/crates/red_knot_python_semantic/resources/mdtest/unary/custom.md
Douglas Creager 2802cbde29 Don't special-case class instances in unary expression inference (#15045)
We have a handy `to_meta_type` that does the right thing for class
instances, and also works for all of the other types that are “instances
of” something. Unless I'm missing something, this should let us get rid
of the catch-all clause in one fell swoop.

cf #14548
2024-12-18 14:37:17 -05:00

5.0 KiB

Custom unary operations

Class instances

class Yes:
    def __pos__(self) -> bool:
        return False

    def __neg__(self) -> str:
        return "negative"

    def __invert__(self) -> int:
        return 17

class Sub(Yes): ...
class No: ...

reveal_type(+Yes())  # revealed: bool
reveal_type(-Yes())  # revealed: str
reveal_type(~Yes())  # revealed: int

reveal_type(+Sub())  # revealed: bool
reveal_type(-Sub())  # revealed: str
reveal_type(~Sub())  # revealed: int

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `No`"
reveal_type(+No())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `No`"
reveal_type(-No())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `No`"
reveal_type(~No())  # revealed: Unknown

Classes

class Yes:
    def __pos__(self) -> bool:
        return False

    def __neg__(self) -> str:
        return "negative"

    def __invert__(self) -> int:
        return 17

class Sub(Yes): ...
class No: ...

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Yes]`"
reveal_type(+Yes)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Yes]`"
reveal_type(-Yes)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Yes]`"
reveal_type(~Yes)  # revealed: Unknown

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Sub]`"
reveal_type(+Sub)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Sub]`"
reveal_type(-Sub)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Sub]`"
reveal_type(~Sub)  # revealed: Unknown

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
reveal_type(+No)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
reveal_type(-No)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
reveal_type(~No)  # revealed: Unknown

Function literals

def f():
    pass

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[f]`"
reveal_type(+f)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[f]`"
reveal_type(-f)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[f]`"
reveal_type(~f)  # revealed: Unknown

Subclass

class Yes:
    def __pos__(self) -> bool:
        return False

    def __neg__(self) -> str:
        return "negative"

    def __invert__(self) -> int:
        return 17

class Sub(Yes): ...
class No: ...

def yes() -> type[Yes]:
    return Yes

def sub() -> type[Sub]:
    return Sub

def no() -> type[No]:
    return No

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[Yes]`"
reveal_type(+yes())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[Yes]`"
reveal_type(-yes())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[Yes]`"
reveal_type(~yes())  # revealed: Unknown

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[Sub]`"
reveal_type(+sub())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[Sub]`"
reveal_type(-sub())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[Sub]`"
reveal_type(~sub())  # revealed: Unknown

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[No]`"
reveal_type(+no())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[No]`"
reveal_type(-no())  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[No]`"
reveal_type(~no())  # revealed: Unknown

Metaclass

class Meta(type):
    def __pos__(self) -> bool:
        return False

    def __neg__(self) -> str:
        return "negative"

    def __invert__(self) -> int:
        return 17

class Yes(metaclass=Meta): ...
class Sub(Yes): ...
class No: ...

reveal_type(+Yes)  # revealed: bool
reveal_type(-Yes)  # revealed: str
reveal_type(~Yes)  # revealed: int

reveal_type(+Sub)  # revealed: bool
reveal_type(-Sub)  # revealed: str
reveal_type(~Sub)  # revealed: int

# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
reveal_type(+No)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
reveal_type(-No)  # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
reveal_type(~No)  # revealed: Unknown