Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1486,17 +1486,15 @@ def check_func_def(
):
show_error = False

if show_error:
if show_error and not self.current_node_deferred:
may_be_abstract = (
body_is_trivial
and defn.info is not FUNC_NO_INFO
and defn.info.metaclass_type is not None
and defn.info.metaclass_type.type.has_base("abc.ABCMeta")
)
if self.options.warn_no_return:
if not self.current_node_deferred and not isinstance(
return_type, (NoneType, AnyType)
):
if not isinstance(return_type, (NoneType, AnyType)):
# Control flow fell off the end of a function that was
# declared to return a non-None type.
if isinstance(return_type, UninhabitedType):
Expand Down Expand Up @@ -3154,6 +3152,13 @@ def visit_block(self, b: Block) -> None:
self.binder.unreachable()
return
for s in b.body:
# If we export types, we need to continue checking to make sure all
# expressions are present in type map (even if most have type Any).
if self.current_node_deferred and not self.options.export_types:
# With current deferral logic there is no point continuing to
# type-check current function, as we will not infer more types,
# will not show errors, and each expression is inferred as Any.
return
if self.binder.is_unreachable():
if not self.should_report_unreachable_issues():
break
Expand Down Expand Up @@ -4713,6 +4718,7 @@ def check_simple_assignment(
and inferred is not None
and inferred.type is not None
and not inferred.is_final
and not self.current_node_deferred
):
new_inferred = remove_instance_last_known_values(rvalue_type)
if not is_same_type(inferred.type, new_inferred):
Expand Down
17 changes: 17 additions & 0 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -3750,3 +3750,20 @@ foo(*args) # E: Argument 1 to "foo" has incompatible type "*list[object]"; expe
kwargs: dict[str, object]
foo(**kwargs) # E: Argument 1 to "foo" has incompatible type "**dict[str, object]"; expected "P"
[builtins fixtures/dict.pyi]

[case testNoImplicitReturnErrorOnDeferral_no_empty]
# flags: --no-warn-no-return
def deferred() -> int:
c: C
x = 1
if int():
x = c.x
reveal_type(x) # N: Revealed type is "builtins.int"
return x

class C:
def __init__(self) -> None:
self.x = defer()

def defer() -> int:
return 1
15 changes: 15 additions & 0 deletions test-data/unit/check-redefine2.test
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,21 @@ def f2() -> None:
reveal_type(x) # N: Revealed type is "builtins.str"
reveal_type(x) # N: Revealed type is "builtins.int | builtins.str"

[case testNewRedefineNoWideningDeferred]
# flags: --allow-redefinition-new --local-partial-types
def deferred() -> None:
c: C
x = 1
if int():
x = c.x
reveal_type(x) # N: Revealed type is "builtins.int"

class C:
def __init__(self) -> None:
self.x = defer()

def defer() -> int: ...

[case testNewRedefineTryStatement]
# flags: --allow-redefinition-new --local-partial-types
class E(Exception): pass
Expand Down