Improve error reporting: Warn when pipe operators are incorrectly indented
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 131
Description
## What
Another one for the #1103 list. A recent [F# question on StackOverflow](http://stackoverflow.com/q/38965302/2314532) highlighted a place where the compiler's error messages are not helpful. The user wrote the following code:
``` fsharp
let process_args argv =
let (result, _) = ((default_settings, "-f"), argv)
||> Array.fold (fun (state, setting) elem ->
// (snip body of folder function as it's irrelevant here)
)
result
```
Note that the user's original code used the verbose-syntax usage of `let ... in` here, which I've replaced with light-syntax `let` (without `in`) since the syntax makes no difference in this case and the same unhelpful compiler errors appear.
This function produces two error messages: one on the `let` of `let (result, _) = ...`, and one on the `||>` operator. The error on `let` is:
> Incomplete value or function definition. If this is in an expression, the body of the expression must be indented to the same column as the 'let' keyword.
and the error on the `||>` is:
> Unexpected infix operator in binding. Expected incomplete structured construct at or before this point or other token.
## Why
The StackOverflow user asking this question appeared to understand F# pretty well, but he was not able to figure out from those two error messages that he had an indentation problem with his pipe operator. It should have been indented far enough to be under the `((default_settings, "-f"), argv)` tuple, but the error messages on `let` and `||>` give no clue to that fact.
## How
The code pattern of `let something = somethingElse |> someFunc` is extremely common. If the `|>` operator (or any other pipe operator like `||>`, `<|`, and so on) is found "alone" on a line when the previous line had a `let` statement, it's likely that the user meant to indent the `|>` to line up with `somethingElse`. So a nicer error message for the original user's code might have been:
```
Unexpected infix operator in binding.
The ||> operator should be indented so that it is aligned under the value it operates on.
Instead of this:
let (result, _) = ((default_settings, "-f"), argv)
||> Array.fold (fun (state, setting) elem ->
you probably meant to write this:
let (result, _) =
((default_settings, "-f"), argv)
||> Array.fold (fun (state, setting) elem ->
or possibly this:
let (result, _) = ((default_settings, "-f"), argv)
||> Array.fold (fun (state, setting) elem ->
```
With, of course, the actual operator in the sentence "The `||>` operator should be indented ...". This will usually be the `|>` operator, since `||>` has very few good use cases outside of piping into a `.fold` -- but the same error message should be applicable to all the piping operators.
Contributor guide
Assessment
This issue has not been assessed yet.