build: a declared return type is checked rather than trusted, so an unchecked Any cannot reach a caller - #330
Merged
Conversation
Documentation build overview
8 files changed ·
|
stack merge was automatically disabled
September 1, 2026 15:52
Pull Request is not mergeable
FBumann
force-pushed
the
fix/checked-returns
branch
from
September 1, 2026 16:00
cd0c876 to
64a0ecb
Compare
stack merge was automatically disabled
September 1, 2026 16:32
Pull Request is not mergeable
…nchecked Any cannot reach a caller Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FBumann
force-pushed
the
fix/checked-returns
branch
from
September 1, 2026 16:36
64a0ecb to
87929f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
The following content was generated by AI.
Forcing all ~120 of pyrefly's error kinds on the #325 tree leaves exactly seven ungated, and only three carry signal rather than noise. Those three land here —
no-any-return-explicit,no-any-return-implicit,unknown-variable-type— with the eight sites they name, plusstrict-callable-subtyping = true.The rule that matters is
no-any-return-*: it catches a function whose declared return type the checker never actually verified, which is a wrong value reaching a caller under a type that promised otherwise.model.py:712_expansion: Anyerrors.py:91schema_error(exc: Any)exc: ValidationError— what the docstring already said it takeserrors.py:104str(error.get('msg', ''))excmade this redundant, and #325's own rule caught itmodel.py:562return handler(v)cast('PiecewiseMethod', …)— pydantic's wrap handler returnsAny; the cast is where that stopsmodel.py:777return _without_absence(handler(self))cast('dict[str, Any]', …)_yaml.py:73node.valuepairs: list[tuple[yaml.Node, yaml.Node]]_where_parser.py:179result = items[0]result: WhereNode | UnresolvedWhereNode = items[0], and onecast('WhereNode', …)where the fold hands a parsed leaf toAndNode/OrNode— since #341 those fields are resolved nodes onlyexclusivity.py:367Typing
excleftAnyunused inerrors.py, andruffremoved the import.Verified
pixi run ciexit 0: lint clean, 1003 passed,mkdocs build --strictbuilds, 27 TeX documents compile.pyrefly checkis 0 errors, 9 suppressed — one of the nine being the one added here.Mutation table — each fix reverted on the committed tree, restored with
git checkout --pyrefly check_expansionback toAnyschema_error'sexcback toAnyPiecewiseMethodcast droppedWhereNodeannotation droppedstrict-callable-subtypingoffstrict-callable-subtypingchanges nothing on this tree in either direction, so the mutation proves nothing about it. A positive control does — a narrow function assigned where a*args: Any, **kwargs: Anyprotocol is expected, appended todegree.pyand then reverted:That is the shape
set_parse_actiontakes, which is why the knob is here rather than deferred.The one suppression
exclusivity.py:367returns an implicitAnyfrom_between(...) -> Any | None. Every fix available is worse than the line: declaring-> Anysilences it by deleting the signature's statement that the discrete branch may have nothing to return, and a precise signature needs overloads acrossfloat/int/datefor one private helper with one caller. Suppressed per line with that reason, which is what[tool.pyrefly]'s own comment asks for.Declined, and why
implicit-bool(103 sites). Banningif some_list:forif len(some_list) > 0:fights Python idiom for no defect. But 27 of the 103 are| Nonetypes, whereif x:conflatesNonewith empty — sometimes intended, sometimes a bug. That is worth one manual sweep, not a rule; it is not in this PR and is not filed as an issue yet.explicit-any(73),unknown-argument-type(44),unused-call-result(18). The pydantic doors and the pyparsing seam — the same diagnostics #325 argued against under basedpyright's names.spec-compliant-overloadsis not a strictness knob: its own help says it falls back toAnymore often.strict-partial-subtypingis free at 0 errors but nothing insrc/importsfunctools.partial, so it gates nothing — left out under YAGNI.Stack: on #325 (
fix/pyrefly-gate), which this needs for the severity spelling to mean anything.