Skip to content

Commit

Permalink
Disallow calling type on Protocol
Browse files Browse the repository at this point in the history
Fixes #16919, fixes #16890
  • Loading branch information
hauntsaninja committed Nov 3, 2024
1 parent 1f200dd commit afa72b9
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
9 changes: 7 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1802,10 +1802,15 @@ def check_callable_call(

if (
callee.is_type_obj()
and (len(arg_types) == 1)
and len(arg_types) == 1
and is_equivalent(callee.ret_type, self.named_type("builtins.type"))
):
callee = callee.copy_modified(ret_type=TypeType.make_normalized(arg_types[0]))
proper_arg = get_proper_type(arg_types[0])
if isinstance(proper_arg, Instance) and proper_arg.type.is_protocol:
self.msg.fail("Calling type() on a protocol class is unsound", context)
callee = callee.copy_modified(ret_type=self.named_type("builtins.object"))
else:
callee = callee.copy_modified(ret_type=TypeType.make_normalized(arg_types[0]))

if callable_node:
# Store the inferred callable type.
Expand Down
19 changes: 19 additions & 0 deletions test-data/unit/check-protocols.test
Original file line number Diff line number Diff line change
Expand Up @@ -4215,3 +4215,22 @@ def g4(a: Input[bytes], b: Output[str]) -> None:
f(a, b) # E: Cannot infer type argument 1 of "f"

[builtins fixtures/tuple.pyi]

[case testTypeCallOnProtocol]
from typing import Protocol

import mod

class P(Protocol):
def foo(self) -> None: ...

a: P = mod
value = type(a) # E: Calling type() on a protocol class is unsound
reveal_type(value) # N: Revealed type is "builtins.object"
reveal_type(value.foo) # E: "object" has no attribute "foo" \
# N: Revealed type is "Any"

[file mod.py]
def foo() -> None: ...

[builtins fixtures/tuple.pyi]

0 comments on commit afa72b9

Please sign in to comment.