pylint-dev / pylint

It's not just a linter that annoys you!
https://pylint.readthedocs.io/en/latest/
GNU General Public License v2.0
5.26k stars 1.12k forks source link

With Pylint 3.2.4 and Python 3.8 getting incorrect error W0101: Unreachable code (unreachable) #9751

Closed nanonano closed 3 months ago

nanonano commented 3 months ago

Bug description

When using pylint 3.2.4 I'm getting "W0101: Unreachable code (unreachable" errors but only for Python 3.8. They do not happen for Python 3.9 to 3.12.

See https://github.com/BittyTax/BittyTax/actions/runs/9677156397/job/26698206145.

Worked fine for pylint 3.2.3, see https://github.com/BittyTax/BittyTax/actions/runs/9667255227/job/26668643763.

Command used

pylint $(git ls-files '*.py')

Pylint output

src/bittytax/price/datasource.py:245:8: W0101: Unreachable code (unreachable)
43
src/bittytax/price/datasource.py:253:8: W0101: Unreachable code (unreachable)
44
src/bittytax/price/datasource.py:268:8: W0101: Unreachable code (unreachable)
45
src/bittytax/price/datasource.py:342:8: W0101: Unreachable code (unreachable)
46
src/bittytax/price/datasource.py:357:8: W0101: Unreachable code (unreachable)
47
src/bittytax/price/datasource.py:384:8: W0101: Unreachable code (unreachable)
48
src/bittytax/price/datasource.py:402:8: W0101: Unreachable code (unreachable)
49
src/bittytax/price/datasource.py:423:8: W0101: Unreachable code (unreachable)
50
src/bittytax/price/datasource.py:438:8: W0101: Unreachable code (unreachable)
51
src/bittytax/price/datasource.py:455:8: W0101: Unreachable code (unreachable)
52
src/bittytax/price/datasource.py:475:8: W0101: Unreachable code (unreachable)
53
src/bittytax/price/datasource.py:495:8: W0101: Unreachable code (unreachable)
54
src/bittytax/price/datasource.py:518:8: W0101: Unreachable code (unreachable)
55
src/bittytax/price/datasource.py:539:8: W0101: Unreachable code (unreachable)
56
src/bittytax/price/datasource.py:558:8: W0101: Unreachable code (unreachable)
57
src/bittytax/price/datasource.py:584:8: W0101: Unreachable code (unreachable)

Expected behavior

No errors and per pylint 3.2.3.

Pylint version

astroid-3.2.2 pylint-3.2.4

OS / Environment

Ubuntu 22.04.4 LTS

DanielNoord commented 3 months ago

I don't have access to laptop right now, but can somebody bisect if this is due to https://github.com/pylint-dev/pylint/pull/9714?

jnsnow commented 3 months ago

Seeing the same in QEMU's tests: under Python 3.9 through 3.12 inclusive, there's no issue. Python 3.8 with 3.1.1, 3.2.0, 3.2.1, 3.2.2, 3.2.3 all work correctly. This only seems to surface directly under pylint 3.2.4 and python 3.8. Python 3.7 and earlier untested.

Bisecting confirms commit c41c35a8e0dd71ba96944613e6a2ced830407670

here's a somewhat minimized reproducer: I tried testing it one function at a time, but could only trigger it in the caller to qemu_img_json().

import json
import subprocess
from typing import Any

def qemu_tool(
    *args: str,
    check: bool = True,
    combine_stdio: bool = True
) -> 'subprocess.CompletedProcess[str]':
    subp = subprocess.run(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT if combine_stdio else subprocess.PIPE,
        universal_newlines=True,
        check=False
    )

    if check and subp.returncode or (subp.returncode < 0):
        raise subprocess.CalledProcessError(
            subp.returncode, args,
            output=subp.stdout,
            stderr=subp.stderr,
        )

    return subp

def qemu_img(
    *args: str,
    check: bool = True,
    combine_stdio: bool = True
) -> 'subprocess.CompletedProcess[str]':
    full_args = ['qemu-img'] + list(args)
    return qemu_tool(*full_args, check=check, combine_stdio=combine_stdio)

def qemu_img_json(*args: str) -> Any:
    try:
        res = qemu_img(*args, combine_stdio=False)
    except subprocess.CalledProcessError as exc:
        if exc.returncode < 0:
            raise
        try:
            return json.loads(exc.stdout)
        except json.JSONDecodeError:
            pass
        raise
    return json.loads(res.stdout)

def qemu_img_info(*args: str) -> Any:
    ret = qemu_img_json('info', "--output", "json", *args)
    print("hello?")  # repro.py:50:4: W0101: Unreachable code (unreachable)
    return ret

... If I had to guess, it's because _SpecialForm is being checked in 3.8, but I believe that typing.Any also inherits _SpecialForm, so I think that might be what's going on here.

jnsnow commented 3 months ago

Yup. Here's a much shorter reproducer:

from typing import Any

def repro() -> Any:
    return 5

def main():
    x = repro() + 5
    print(x)
Pierre-Sassoulas commented 3 months ago

Thank you for the reproducer @jnsnow ! I don't have python 3.8 locally, but I've opened #9753 to reproduce in the continuous integration.

nanonano commented 3 months ago

Big thankyou to everyone for getting this resolved so quickly.