Skip to content

Incorrent "Missing return statement" in presence of bad combination of decorated function call, definition order and NoReturn #8129

Closed

Description

@jstasiak

Code to reproduce:

from typing import Callable, NoReturn, TypeVar


def no_return() -> NoReturn:
    pass


def use_decorated_before_defined() -> int:
    decorated()
    if bool():
        return 0
    else:
        no_return()


T = TypeVar('T')


def wrapper(function: T) -> T:
    return function


def decorator() -> Callable[[T], T]:
    return wrapper


@decorator()
def decorated() -> None: pass


def use_decorated_after_defined() -> int:
    decorated()
    if bool():
        return 0
    else:
        no_return()


def use_wrapped_before_defined() -> int:
    wrapped()
    if bool():
        return 0
    else:
        no_return()


@wrapper
def wrapped() -> None: pass

I tested this both with mypy 0.750 and one from the current master branch (526a218), running on CPython 3.7.5. The command line and the output:

% python -m mypy repro.py
repro.py:8: error: Missing return statement
Found 1 error in 1 file (checked 1 source file)

I'd expect no errors here. After some digging in mypy source code I believe use_decorated_before_defined can't be fully processed when it's type-checked (at least the first time it's entered) because of a) the call to decorated being looked at before decorated is defined and b) decorated being decorated (pardon my repetition) with a result of another function call which I suspect creates a difficult environment for mypy to deduce things and it defers further processing of use_decorated_before_defined (or at least part of it).

Then, when the call to no_return is encountered its type is detected as Any because of the processing being deferred per above, hence the error.

I left two similar variants of the function (use_decorated_after_defined and use_wrapped_before_defined) to help narrow things down as those don't trigger the error.

Activity

  1. msullivan commented on Dec 12, 2019

    @msullivan
    Collaborator

    Yeah, this seems legit and somewhat hairy. I suspect you are right and the issue is that the node is being deferred.

    I think that this can be fixed by adding a check for if the node is deferred, though that feels ugly.

  2. self-assigned this
    on Dec 14, 2019
  3. removed their assignment
    on Jun 18, 2020
  4. LEdoian commented on Aug 12, 2022

    @LEdoian

    Shouldn't the title of this issue be made more generic, since issue #8401 is a duplicate of this, but does match the title?

    I have an issue similar to #8401 (NoReturn being confused by code being run before definition) but am not sure whether to post here or create separate issue.

  5. added 2 commits that reference this issue on Sep 1, 2022
    19c3869
    3eb30a8
  6. added a commit that references this issue on Sep 2, 2022
    0a8d425
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions