-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Emit redundant-expr
warnings for if statements that are always true or always false.
#20068
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Oh, 57 errors for Mypy itself, e.g. |
We already kind of have a distinction between things that are true at compile time and run time for unreachability reporting, maybe that has a nice way to do that here? Probably not though. (It's been too long for me to remember any special cases...) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
A few looks into the primer results (from bottom to top; without obvious repetitions): noxMypy issues (in this case already under discussion in #11764). x: str | None,
if callable(x): # error: If condition is always false
... # type: ignore[unreachable] boostedblobAdditional runtime type checking. def f(x: str | int) -> None:
if not isinstance(x, str | int): # error: If condition is always false
raise ValueError
def g(x: str | int) -> None:
if isinstance(x, str):
return
if isinstance(x, int): # error: If condition is always true
return
raise AssertionError scikit-build-coreReally redundant code (or at least one that needs explanations): def f(env: dict[str, str] | None):
if env:
for key, value in env.items():
if isinstance(value, bool): # error: If condition is always false
... import dataclasses
@dataclasses.dataclass
class Settings1:
cmake: bool = False
@dataclasses.dataclass
class Settings2:
cmake: bool = False
def f(s1: Settings1, s2: Settings2) -> None:
if not s1.cmake or s2.cmake:
...
if s2.cmake: # error: If condition is always false
... Based on these few examples, this PR seems correct. However, it somehow collides with exhaustiveness checking. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I tried to filter out warnings for redundant if statements that obviously serve for dynamic type or exhaustiveness checking. The logic is very similar to the one implemented in Assertion or raise statement not in else body: def f(x: int | str) -> None:
if isinstance(x, int):
...
elif isinstance(x, str):
...
assert False Custom error handling method: def f(x: int) -> None:
if not isinstance(x, int):
print("type error!")
return None
.... Assertion or raise statement not in the first line of the if or else body: def f(x: int) -> None:
if not isinstance(x, int):
msg = "type error!"
raise TypeError(msg)
.... Missing assertion or raise statement: def f(x: Literal[1, 2]) -> None:
if x == 1:
...
elif x == 2:
...
return None Return def __add__(self, x: float) -> float:
if not isinstance(name, float):
return NotImplemented # type: ignore[unreachable]
... The current state of this PR also causes two unreachable warnings for reasons I have not yet investigated. |
mypy/checker.py
Outdated
|
||
if codes.REDUNDANT_EXPR not in self.options.enabled_error_codes: | ||
return | ||
if refers_to_fullname(expr, ("typing.TYPE_CHECKING", "typing_extensions.TYPE_CHECKING")): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this can check infer_condition_value
(see unreachability.py
) and see if it's MYPY_TRUE
or MYPY_FALSE
. I think that would be more resilient. It's a bit funny that that relies on a name, but I think it's better to match it anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are probably right. At least, now things like if TYPE_CHECKING and TYPE_CHECKING:
(and maybe more useful patterns) are possible.
The comparison with name
appears less ideal than the original one with fullname
to me, but I think this difference does not really matter. At least, it allowed me to add the test testNoRedundantExpressionWarningsForUsagesOfTYPECHECKING
easily.
mypy/checker.py
Outdated
) | ||
if isinstance(get_proper_type(typ), UninhabitedType): | ||
return True | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah as you point out this seems to duplicate is_noop_for_reachability
. Why not just call that? I think probably pass
and ...
as bodies are alright. (and any reasoning against them IMO also stands for disabling reachability warnings on them :^) )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I often saw that someone used pass
temporarily as the only statement of a if or else block and later added real code but forgot to remove the pass
statement. For reachability analysis, this causes no problem:
from typing import Literal
x: Literal[1]
if x == 1:
y = 1
else:
pass
y = 2 # error: Statement is unreachable
However, this PR only evaluates the block's first statement, which is maybe okay for raise
but not for pass
.
Maybe it is better to go through all lines and only silence the redundant-expr
error if all of them are ignorable. In this case, yes, calling is_noop_for_reachability
would be the right thing to do. I avoided this so far because of performance concerns. However, after rethinking, it seems unlikely that finding the first line that is not ignorable takes many tries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did it so.
mypy/checker.py
Outdated
elif not _filter(body): | ||
self.msg.redundant_condition_in_if(False, expr) | ||
|
||
if else_map is None and not stmt.while_stmt: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. I would prefer if we could only exempt truthy while
blocks if they are very trivial. Have you looked at only exempting int and bool literals? (or I guess, maybe all literals if we don't want to be too lintery...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I haven't, but your idea sounds reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
… the first one (which allows to call `is_noop_for_reachability`).
This comment has been minimized.
This comment has been minimized.
@A5rocks: Thanks for the remarks! I adjusted everything as suggested. I think the only big open case left (for this PR) is: def f(x: int | str) -> None:
if isinstance(x, int):
...
elif isinstance(x, str):
...
assert False I tend to make the block after the last def f(x: int | str) -> None:
if isinstance(x, int):
...
elif isinstance(x, str):
...
else:
assert False |
Diff from mypy_primer, showing the effect of this PR on open source code: CPython (Argument Clinic) (https://github.com/python/cpython)
+ Tools/clinic/libclinic/clanguage.py:82: error: Statement is unreachable [unreachable]
aiohttp (https://github.com/aio-libs/aiohttp)
+ aiohttp/client_exceptions.py:323:4: error: If condition is always true [redundant-expr]
+ aiohttp/client_exceptions.py:323:4: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-redundant-expr for more info
+ aiohttp/helpers.py:267:8: error: If condition is always false [redundant-expr]
+ aiohttp/helpers.py:877:14: error: If condition is always true [redundant-expr]
+ aiohttp/cookiejar.py:297:12: error: If condition is always false [redundant-expr]
+ aiohttp/cookiejar.py:485:15: error: While condition is always false [redundant-expr]
+ aiohttp/multipart.py:306:15: error: While condition is always true [redundant-expr]
+ aiohttp/multipart.py:447:15: error: While condition is always true [redundant-expr]
+ aiohttp/multipart.py:660:12: error: If condition is always false [redundant-expr]
+ aiohttp/connector.py:159:12: error: If condition is always true [redundant-expr]
+ aiohttp/connector.py:812:8: error: If condition is always false [redundant-expr]
+ aiohttp/client_reqrep.py:169:4: error: If condition is always true [redundant-expr]
+ aiohttp/client_reqrep.py:275:12: error: If condition is always true [redundant-expr]
+ aiohttp/client.py:948:16: error: If condition is always true [redundant-expr]
+ aiohttp/web_response.py:267:14: error: If condition is always true [redundant-expr]
+ aiohttp/web_fileresponse.py:328:16: error: If condition is always true [redundant-expr]
+ aiohttp/web_protocol.py:715:16: error: If condition is always false [redundant-expr]
+ aiohttp/web_runner.py:263:20: error: If condition is always true [redundant-expr]
mypy (https://github.com/python/mypy)
+ mypy/nodes.py:4533: error: If condition is always true [redundant-expr]
+ mypy/nodes.py:4533: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-redundant-expr for more info
+ mypy/nodes.py:4582: error: If condition is always true [redundant-expr]
+ mypy/nodes.py:4626: error: If condition is always true [redundant-expr]
+ mypy/nodes.py:4831: error: If condition is always true [redundant-expr]
+ mypy/traverser.py:126: error: If condition is always true [redundant-expr]
+ mypy/traverser.py:195: error: If condition is always true [redundant-expr]
+ mypy/traverser.py:201: error: If condition is always true [redundant-expr]
+ mypy/server/astmerge.py:448: error: If condition is always true [redundant-expr]
+ mypy/server/astmerge.py:460: error: If condition is always true [redundant-expr]
+ mypy/server/astmerge.py:477: error: If condition is always true [redundant-expr]
+ mypy/fixup.py:280: error: If condition is always true [redundant-expr]
+ mypy/fixup.py:282: error: If condition is always true [redundant-expr]
+ mypy/fixup.py:315: error: If condition is always true [redundant-expr]
+ mypy/fixup.py:322: error: If condition is always true [redundant-expr]
+ mypy/fixup.py:362: error: If condition is always true [redundant-expr]
+ mypy/constraints.py:133: error: If condition is always false [redundant-expr]
+ mypy/constraints.py:133: note: Error code "redundant-expr" not covered by "type: ignore" comment
+ mypy/messages.py:1254: error: If condition is always true [redundant-expr]
+ mypy/fastparse.py:2077: error: If condition is always true [redundant-expr]
+ mypyc/analysis/ircheck.py:307: error: If condition is always true [redundant-expr]
+ mypy/server/astdiff.py:259: error: If condition is always true [redundant-expr]
+ mypy/plugins/dataclasses.py:140: error: If condition is always true [redundant-expr]
+ mypy/semanal.py:1003: error: If condition is always true [redundant-expr]
+ mypy/semanal.py:1403: error: If condition is always true [redundant-expr]
+ mypy/semanal.py:3872: error: If condition is always true [redundant-expr]
+ mypy/semanal.py:5817: error: If condition is always true [redundant-expr]
+ mypy/checkexpr.py:3546: error: Statement is unreachable [unreachable]
+ mypy/checkexpr.py:3546: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-unreachable for more info
+ mypy/checker.py:2508: error: If condition is always true [redundant-expr]
+ mypy/checker.py:8671: error: If condition is always true [redundant-expr]
+ mypy/checker.py:8672: error: If condition is always true [redundant-expr]
+ mypy/build.py:1138: error: If condition is always false [redundant-expr]
+ mypy/build.py:1381: error: If condition is always false [redundant-expr]
+ mypyc/irbuild/prepare.py:263: error: If condition is always true [redundant-expr]
+ mypy/stubtest.py:349: error: If condition is always false [redundant-expr]
+ mypy/stubtest.py:632: error: If condition is always false [redundant-expr]
+ mypyc/irbuild/expression.py:919: error: If condition is always true [redundant-expr]
pyproject-metadata (https://github.com/pypa/pyproject-metadata)
+ pyproject_metadata/pyproject.py:86: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:100: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:105: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:168: error: If condition is always true [redundant-expr]
+ pyproject_metadata/pyproject.py:249: error: If condition is always true [redundant-expr]
+ pyproject_metadata/pyproject.py:333: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:341: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:351: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:383: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:396: error: If condition is always false [redundant-expr]
+ pyproject_metadata/pyproject.py:408: error: If condition is always false [redundant-expr]
+ pyproject_metadata/__init__.py:369: error: If condition is always false [redundant-expr]
rich (https://github.com/Textualize/rich)
+ rich/text.py:990: error: If condition is always true [redundant-expr]
+ rich/text.py:1241: error: If condition is always true [redundant-expr]
+ rich/rule.py:96: error: If condition is always true [redundant-expr]
+ rich/padding.py:71: error: If condition is always true [redundant-expr]
+ rich/align.py:178: error: If condition is always true [redundant-expr]
pyodide (https://github.com/pyodide/pyodide)
+ pyodide-build/pyodide_build/vendor/loky.py:166: error: If condition is always false [redundant-expr]
+ pyodide-build/pyodide_build/common.py:268: error: If condition is always true [redundant-expr]
+ pyodide-build/pyodide_build/recipe/skeleton.py:126: error: If condition is always true [redundant-expr]
+ src/py/pyodide/http/pyxhr.py:188: error: If condition is always true [redundant-expr]
packaging (https://github.com/pypa/packaging)
+ src/packaging/_manylinux.py:142: error: If condition is always false [redundant-expr]
+ src/packaging/markers.py:344: error: If condition is always false [redundant-expr]
+ src/packaging/metadata.py:386: error: If condition is always false [redundant-expr]
poetry (https://github.com/python-poetry/poetry)
+ src/poetry/utils/_compat.py:39: error: If condition is always false [redundant-expr]
+ src/poetry/pyproject/toml.py:48: error: If condition is always false [redundant-expr]
+ src/poetry/utils/authenticator.py:164: error: If condition is always true [redundant-expr]
+ src/poetry/utils/authenticator.py:263: error: If condition is always true [redundant-expr]
+ src/poetry/config/source.py:23: error: If condition is always false [redundant-expr]
+ src/poetry/utils/env/env_manager.py:196: error: If condition is always false [redundant-expr]
+ src/poetry/utils/env/env_manager.py:377: error: If condition is always false [redundant-expr]
+ src/poetry/installation/executor.py:819: error: If condition is always false [redundant-expr]
+ src/poetry/console/commands/remove.py:70: error: If condition is always false [redundant-expr]
+ tests/console/commands/test_install.py:155: error: If condition is always false [redundant-expr]
+ tests/console/commands/test_build.py:184: error: If condition is always false [redundant-expr]
+ src/poetry/console/commands/add.py:329: error: If condition is always true [redundant-expr]
archinstall (https://github.com/archlinux/archinstall)
+ archinstall/lib/models/authentication.py:47: error: If condition is always false [redundant-expr]
+ archinstall/lib/models/mirrors.py:100: error: If condition is always true [redundant-expr]
+ archinstall/lib/installer.py:840: error: If condition is always true [redundant-expr]
+ archinstall/lib/installer.py:946: error: If condition is always true [redundant-expr]
+ archinstall/lib/authentication/authentication_menu.py:120: error: If condition is always true [redundant-expr]
+ archinstall/lib/profile/profile_menu.py:142: error: If condition is always true [redundant-expr]
build (https://github.com/pypa/build)
+ src/build/__main__.py:187: error: If condition is always true [redundant-expr]
xarray (https://github.com/pydata/xarray)
+ xarray/compat/npcompat.py: note: In function "isdtype":
+ xarray/compat/npcompat.py:72: error: If condition is always false [redundant-expr]
+ xarray/core/utils.py: note: In function "equivalent":
+ xarray/core/utils.py:266: error: If condition is always false [redundant-expr]
+ xarray/backends/locks.py: note: In function "combine_locks":
+ xarray/backends/locks.py:267: error: If condition is always true [redundant-expr]
+ xarray/core/indexing.py: note: In function "group_indexers_by_index":
+ xarray/core/indexing.py:147: error: If condition is always true [redundant-expr]
+ xarray/core/indexing.py: note: In function "map_index_queries":
+ xarray/core/indexing.py:197: error: If condition is always false [redundant-expr]
+ xarray/core/indexing.py: note: In function "_decompose_outer_indexer":
+ xarray/core/indexing.py:1398: error: If condition is always false [redundant-expr]
+ xarray/core/indexing.py: note: At top level:
+ xarray/core/indexes.py: note: In member "from_variables" of class "PandasIndex":
+ xarray/core/indexes.py:722: error: If condition is always false [redundant-expr]
+ xarray/core/indexes.py: note: In member "to_pandas_indexes" of class "Indexes":
+ xarray/core/indexes.py:1853: error: If condition is always false [redundant-expr]
+ xarray/core/indexes.py:1853: error: If condition is always true [redundant-expr]
+ xarray/core/indexes.py:1855: error: If condition is always true [redundant-expr]
+ xarray/core/indexes.py: note: In member "copy_indexes" of class "Indexes":
+ xarray/core/indexes.py:1881: error: If condition is always false [redundant-expr]
+ xarray/core/indexes.py:1881: error: If condition is always true [redundant-expr]
+ xarray/plot/facetgrid.py: note: In member "set_axis_labels" of class "FacetGrid":
+ xarray/plot/facetgrid.py:852: error: If condition is always false [redundant-expr]
+ xarray/plot/facetgrid.py: note: At top level:
+ xarray/core/variable.py: note: In member "_pad_options_dim_to_index" of class "Variable":
+ xarray/core/variable.py:1225: error: If condition is always false [redundant-expr]
+ xarray/core/variable.py: note: At top level:
+ xarray/structure/merge.py: note: In function "coerce_pandas_values":
+ xarray/structure/merge.py:530: error: If condition is always false [redundant-expr]
+ xarray/core/coordinates.py: note: In member "equals" of class "Coordinates":
+ xarray/core/coordinates.py:477: error: If condition is always false [redundant-expr]
+ xarray/core/coordinates.py: note: In member "identical" of class "Coordinates":
+ xarray/core/coordinates.py:488: error: If condition is always false [redundant-expr]
+ xarray/coding/cftimeindex.py: note: In member "shift" of class "CFTimeIndex":
+ xarray/coding/cftimeindex.py:508: error: If condition is always true [redundant-expr]
+ xarray/conventions.py: note: In function "ensure_not_multiindex":
+ xarray/conventions.py:56: error: If condition is always false [redundant-expr]
+ xarray/plot/dataarray_plot.py: note: In function "line":
+ xarray/plot/dataarray_plot.py:521: error: If condition is always true [redundant-expr]
+ xarray/plot/dataarray_plot.py:524: error: If condition is always true [redundant-expr]
+ xarray/plot/dataarray_plot.py: note: At top level:
+ xarray/plot/dataarray_plot.py: note: In function "_add_labels":
+ xarray/plot/dataarray_plot.py:1110: error: If condition is always true [redundant-expr]
+ xarray/core/dataset.py: note: In member "expand_dims" of class "Dataset":
+ xarray/core/dataset.py:4576: error: If condition is always true [redundant-expr]
+ xarray/core/dataset.py: note: In member "transpose" of class "Dataset":
+ xarray/core/dataset.py:6237: error: If condition is always false [redundant-expr]
+ xarray/core/dataset.py: note: In member "dropna" of class "Dataset":
+ xarray/core/dataset.py:6378: error: If condition is always true [redundant-expr]
+ xarray/core/dataset.py: note: In member "sortby" of class "Dataset":
+ xarray/core/dataset.py:8102: error: If condition is always true [redundant-expr]
+ xarray/core/dataarray.py: note: In member "dot" of class "DataArray":
+ xarray/core/dataarray.py:5184: error: If condition is always true [redundant-expr]
+ xarray/indexes/nd_point_index.py: note: In member "from_variables" of class "NDPointIndex":
+ xarray/indexes/nd_point_index.py:270: error: If condition is always false [redundant-expr]
+ xarray/core/parallel.py: note: In function "check_result_variables":
+ xarray/core/parallel.py:50: error: If condition is always true [redundant-expr]
+ xarray/core/parallel.py: note: At top level:
+ xarray/core/datatree.py: note: In member "__getitem__" of class "DataTree":
+ xarray/core/datatree.py:967: error: If condition is always true [redundant-expr]
+ xarray/testing/assertions.py: note: In function "_assert_dataarray_invariants":
+ xarray/testing/assertions.py:431: error: If condition is always true [redundant-expr]
+ xarray/testing/assertions.py: note: In function "_assert_dataset_invariants":
+ xarray/testing/assertions.py:466: error: If condition is always true [redundant-expr]
+ xarray/testing/assertions.py: note: In function "_assert_internal_invariants":
+ xarray/testing/assertions.py:490: error: If condition is always true [redundant-expr]
+ xarray/backends/common.py: note: In function "ensure_dtype_not_object":
+ xarray/backends/common.py:682: error: If condition is always false [redundant-expr]
+ xarray/backends/common.py:682: error: If condition is always true [redundant-expr]
+ xarray/computation/rolling.py: note: In member "construct" of class "Coarsen":
+ xarray/computation/rolling.py:1191: error: If condition is always true [redundant-expr]
+ xarray/computation/rolling.py:1191: error: If condition is always false [redundant-expr]
+ xarray/computation/rolling.py:1215: error: If condition is always false [redundant-expr]
+ xarray/computation/fit.py: note: In function "polyfit":
+ xarray/computation/fit.py:186: error: If condition is always true [redundant-expr]
+ xarray/tests/test_indexing.py: note: In member "test_group_indexers_by_index" of class "TestIndexers":
+ xarray/tests/test_indexing.py:104: error: If condition is always false [redundant-expr]
+ xarray/tests/test_indexing.py: note: At top level:
+ xarray/tests/test_backends.py: note: In member "check_dtypes_roundtripped" of class "DatasetIOBase":
+ xarray/tests/test_backends.py:521: error: If condition is always false [redundant-expr]
+ xarray/tests/test_backends.py: note: At top level:
+ xarray/tests/test_backends_datatree.py: note: In function "test_to_zarr_compute_false":
+ xarray/tests/test_backends_datatree.py:787: error: If condition is always true [redundant-expr]
scikit-build-core (https://github.com/scikit-build/scikit-build-core)
+ src/scikit_build_core/settings/skbuild_overrides.py:219: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:86: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:100: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:105: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:168: error: If condition is always true [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:249: error: If condition is always true [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:333: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:341: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:351: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:383: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:396: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/pyproject.py:408: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/_vendor/pyproject_metadata/__init__.py:369: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/setuptools/build_cmake.py:250: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/hatch/plugin.py:73: error: If condition is always false [redundant-expr]
+ src/scikit_build_core/build/__main__.py:45: error: If condition is always true [redundant-expr]
boostedblob (https://github.com/hauntsaninja/boostedblob)
+ boostedblob/boost.py:578: error: If condition is always true [redundant-expr]
+ boostedblob/boost.py:590: error: If condition is always true [redundant-expr]
nox (https://github.com/wntrblm/nox)
+ nox/sessions.py:617: error: If condition is always false [redundant-expr]
|
Fixes #19728
And thereby implements the two XXX comments of
TypeChecker.visit_if_stmt
.The only surprise I encountered is that we must take care of while statements here, too, because while statements are transformed to if statements during type checking. It seems right to me to only emit warnings for
while False
but not forwhile True
.@A5rocks: Are you aware of other, uncovered special cases?