Warning 20 range: also walk through let/use bindings (follow-up to #19504)#19896
Warning 20 range: also walk through let/use bindings (follow-up to #19504)#19896T-Gro wants to merge 10 commits into
Conversation
- Walk through let/use bindings in addition to Sequential when locating
the offending expression for warning 20. Fixes the case Eugene flagged:
for _ in [] do
let x = 1
x
- Fix wrong issue link (#5735 -> #5418) in code comment, release notes,
and test annotations.
- Add regression tests for the let/use case (single + nested bindings).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
abonie
left a comment
There was a problem hiding this comment.
🤖 AI-generated review — verify before acting on findings.
| |> typecheck | ||
| |> shouldFail | ||
| |> withSingleDiagnostic (Warning 20, Line 5, Col 5, Line 5, Col 10, | ||
| "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") |
There was a problem hiding this comment.
[Test Coverage / LOW] The PR title and release note both say "let/use", but the two new tests only cover let bindings. The use path goes through the identical code (SynExpr.LetOrUse is one union case for both), so it works — but there is no regression guard for it.
Suggested addition:
// https://github.com/dotnet/fsharp/issues/5418
[<Fact>]
let ``Warn On Last Expression In For Loop - non-unit after use binding``() =
FSharp """
type D() =
interface System.IDisposable with
member _.Dispose() = ()
member _.Value = 1
for _ in [] do
use d = new D()
d.Value
"""
|> typecheck
|> shouldFail
|> withSingleDiagnostic (Warning 20, Line 8, Col 5, Line 8, Col 12,
"The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.")There was a problem hiding this comment.
If adding more cases, a case with a computation expression could be useful.
| // Use the range of the last expression in a sequential chain (also walking through | ||
| // 'let'/'use' bindings) for warnings, so that "expression is ignored" diagnostics point | ||
| // at the offending expression rather than the entire sequential body. | ||
| // See https://github.com/dotnet/fsharp/issues/5418 |
There was a problem hiding this comment.
@T-Gro Could you cherry-pick the comments rules from the other PR?
| "The result of this expression has type 'bool' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") | ||
|
|
||
| // https://github.com/dotnet/fsharp/issues/5735 | ||
| // https://github.com/dotnet/fsharp/issues/5418 |
There was a problem hiding this comment.
These comments are also redundant: the resulting commit is going to have the link to the PR with all the needed context.
| |> typecheck | ||
| |> shouldFail | ||
| |> withSingleDiagnostic (Warning 20, Line 5, Col 5, Line 5, Col 10, | ||
| "The result of this expression has type 'int' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") |
There was a problem hiding this comment.
If adding more cases, a case with a computation expression could be useful.
… add PR link - Remove issue URL references from code comments and test methods (per auduchinok: redundant, commit links to PR with full context) - Add test for 'use' binding (non-unit after use) - Add test for computation expression after let binding - Add PR #19896 link to release notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…0-let-binding-range
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dy covers the user-facing fix Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| let x = async { return 1 } | ||
| x | ||
| let x = 1 | ||
| seq { yield x } |
There was a problem hiding this comment.
What specific about computation expressions does it test? It doesn't seem to cover its keywords or inner CE-specific syntax constructs.
There was a problem hiding this comment.
You're right — it didn't test CE-specific syntax at all. Replaced it with a while-loop + let binding test that genuinely exercises the lastExprRange fix in a different loop context (while loops also go through TcStmt). A real CE-specific test wouldn't hit this code path since CE for-bodies are handled by the CE translation, not TcStmt.
There was a problem hiding this comment.
A real CE-specific test wouldn't hit this code path since CE for-bodies are handled by the CE translation, not TcStmt.
So, what range would be highlighted in the case of CE?
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous 'computation expression after let binding' test only used
async { return x } as a non-unit value - it didn't exercise CE-specific
syntax constructs. Replace with a while-loop test that genuinely exercises
the TcStmt lastExprRange fix in a different loop context.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…0-let-binding-range
Follow-up to #19504 addressing review feedback from @auduchinok.
#19504 fixed warning 20 ("expression is implicitly ignored") to point at the last expression of a sequential body inside
for/while. The walk only descended throughSynExpr.Sequential, so when the last expression was the body of alet/usebinding, the squiggle covered the wholeletexpression instead of just the offending tail:This PR also descends through
SynExpr.LetOrUse, so the squiggle lands onxalone in cases like the one above.It also corrects the issue reference cited by the original PR (#5418 — "Wrong expression is ignored warning range"; the previously cited #5735 is unrelated to this diagnostic).
Tracking: #5418