Repository navigation
Add a refactoring between fun x -> x.Prop and _.Prop - #20535
xperiandri wants to merge 11 commits into
Conversation
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev Caution No release notes found for the changed paths (see table below). Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format. The following format is recommended for this repository: `* . (PR #XXXXX)`
If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.
|
ee5d78c to
119ccbf
Compare
fun x -> x.Prop and the _.Prop shorthand
f1fdbc0 to
0bc4d75
Compare
This comment has been minimized.
This comment has been minimized.
T-Gro
left a comment
There was a problem hiding this comment.
Maybe in general, could you run e.g. 2-3 rounds of the "code compaction" skill from this repo which will check any shared patterns between added code and code which already exists in the compiler (like various Ops, helpers or other pieces of logic) - the skill covers some common patterns of logic reuse.
fun x -> x.Prop and the _.Prop shorthandfun x -> x.Prop and _.Prop
Covered casesConverts
Not offered
|
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.
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.
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.
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.
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.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
🔍 Tooling Safety Check — Affects-Design-Time
|
abonie
left a comment
There was a problem hiding this comment.
🤖🕵️ AI review — verify independently.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The refactoring can generate invalid SRTP code, discard comments, and appear in explicitly excluded contexts.
Review effort: Balanced
Findings: 2
Open (3)
What changed in this PR
Adds bidirectional Visual Studio refactoring between explicit lambdas and F# _. shorthand, backed by shared compiler syntax-tree logic.
Changes:
- Adds the refactoring, telemetry, resources, and localization.
- Extracts reusable syntax-chain conversion operations.
- Adds compiler-service and editor tests plus release notes.
| File | Description |
|---|---|
vsintegration/tests/FSharp.Editor.Tests/Refactors/ConvertDotLambdaTests.fs |
Tests refactoring behavior. |
vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj |
Includes new editor tests. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf |
Adds localized resources. |
vsintegration/src/FSharp.Editor/Telemetry/TelemetryReporter.fs |
Defines refactoring telemetry event. |
vsintegration/src/FSharp.Editor/Refactor/ConvertDotLambda.fs |
Implements bidirectional conversion. |
vsintegration/src/FSharp.Editor/FSharp.Editor.resx |
Adds action titles. |
vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj |
Includes the provider. |
tests/FSharp.Compiler.Service.Tests/SyntaxTreeOpsTests.fs |
Tests syntax-chain operations. |
tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.Tests.fsproj |
Includes syntax tests. |
src/Compiler/SyntaxTree/SyntaxTreeOps.fsi |
Declares chain conversion helper. |
src/Compiler/SyntaxTree/SyntaxTreeOps.fs |
Implements shared chain traversal. |
docs/release-notes/.VisualStudio/18.vNext.md |
Documents the refactoring. |
docs/release-notes/.FSharp.Compiler.Service/11.0.200.md |
Documents syntax-operation changes. |
3d2645a to
7d64d6e
Compare
abonie
left a comment
There was a problem hiding this comment.
🤖🕵️ AI review — verify independently.
abonie
left a comment
There was a problem hiding this comment.
🤖🕵️ AI review — verify independently.
7d64d6e to
7b928dc
Compare
7b928dc to
92978a6
Compare
T-Gro
left a comment
There was a problem hiding this comment.
The diff is still way too big - apply the NoBloat instructions and CodeCompaction skill.
Especially the massive code comments would benefit not just with drastic reduction, but ideally with well named functions/arguments/bindings/types making the intention clear.
If a well named piece of code just tells what the comment says - delete the comment.
- Delete the 9 non-license implementation comment lines. Rename the internal helpers so
dot-lambda, generated-argument, offside-line, and sole-parenthesis intent is in code rather than XML prose. - Delete the FCS release note: the shared internal syntax walker and its inverse are not user-visible FCS behavior. Keep a compact Visual Studio note for the refactoring action.
- Fold the standalone success Facts and multiline cases into the existing parameterized conversion tables.
A lambda whose only use of its parameter is the head of a member, method, indexer or type-application chain converts to the F# 8 shorthand, and a shorthand converts back to a 'fun' lambda with a parameter name the body does not use. The accepted chains mirror SyntaxTreeOps.pushUnaryArg, so the shorthand produced always type checks like the lambda it replaces. A lambda spanning multiple lines still converts as long as its body is such a chain; the result collapses onto the line the '_.' replaces 'fun' on. Fixes dotnet#16234 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e of its section Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pushUnaryArg now finds the head of the atomic chain (atomic applications, member and index lookups, type applications) through a zipper that also rebuilds the chain, and tryPopUnaryArg uses the same zipper to split the root identifier off a lambda body. The editor refactoring between `fun x -> x.P` and `_.P` can then accept exactly the bodies the compiler accepts instead of keeping its own copy of the rule. pushUnaryArg keeps its recovery branches and reports FS3584 on the same node as before. Both functions stay internal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ment targets as uses The refactoring drops its own chain walker for SyntaxTreeOps.tryPopUnaryArg, the inverse of what the compiler does to a `_.` body, so the two cannot drift. The check that the dot follows the root without a space goes with it: `x .P` is the same chain and `_ .P` is a valid shorthand. `fun x -> x.M(x.P <- 1)` was offered as `_.M(x.P <- 1)`, where `x` then names an outer value: an assignment to `x`, `x.P` or `x.Xs[0]` keeps its target as a long identifier rather than an expression, so the use was not counted. The condition for dropping the parentheses around the lambda argument is now the ParenthesizedLambdaArgument active pattern, both folds over the body share one identifier collector, and spans come from RoslynHelpers directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reak the layout Lambda to shorthand is no longer offered when - a comment stands in the `fun x -> x` text that `_` replaces; - the body uses a name such as `_arg1`: the compiler names the parameter of `_.` that way, so the use would bind to it instead of the outer value; - the lambda is applied through more than one pair of parentheses, `((fun x -> x.P)) y`, like the single pair that was already excluded. Shorthand to lambda is no longer offered - inside a quotation, where the name of the lambda variable is observable; - when the chain itself continues on a later line: `_.Trim()` followed by `.Length` on the next line is valid after `_` but offside as the body of a lambda that starts further right. Arguments may still span lines. It replaces only the `_` token, so what stands between `_` and the dot, a space or a comment, stays. The tests now parse every converted document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bullet was listed twice, once without the pull request link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4be0d7d to
e18b128
Compare
Delete the nine implementation comment lines and let the helper names say what the comments said: - splitDotLambdaChain: the head of a dot-lambda body and the function that rebuilds the chain around another head (was atomicChainHead) - canBeCapturedByGeneratedArgument: a name the generated parameter of _. would capture (was isGeneratedArgumentName) - lastOffsideSensitiveLine: the last line of a chain outside its argument brackets (was lastLineOutsideArguments) - SoleParenthesizedLambdaArgument: the parentheses that hold only the lambda (was ParenthesizedLambdaArgument) SyntaxTreeOps is an internal module, so pushUnaryArg and tryPopUnaryArg lose their doc comments as well. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The four success Facts and the multi-line cases become rows of the two conversion tables; the rows that were Facts keep their names as display names. The shorthand-to-lambda table takes the caret marker as its first argument, which also absorbs the table that needed another marker, and a binding that starts with "let " spells out its own definition. Test methods go from 8 to 3 and the cases stay at 61. SyntaxTreeOpsTests interpolates instead of calling sprintf. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…oring The shared internal syntax walker and its inverse are not user-visible FCS behavior, so the FCS note is deleted. The Visual Studio note names the refactoring action and nothing else. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Pushed e47c07c (names instead of the nine implementation comments), 12d14fd (the tests folded into the tables) and b5496e8 (release notes): the PR now adds one comment line, the license header, down from 10 lines and 1037 characters, and the added lines in total go from 604 to 548. The helpers carry the intent in their names ( |


Fixes #16234
Offers
Ctrl+.to turn a lambda that only reads a member chain of its parameter (fun x -> x.Name,fun x -> x.M(y),fun x -> x.Items[0]) into the_.shorthand, and a shorthand back into afunlambda. It is a refactoring rather than a code fix because both forms are correct.Not offered for lambdas with several or annotated parameters, bodies that do more than read the chain, lambdas applied directly, or inside quotations.
🤖 Generated with Claude Code