dotnet / dotnet/fsharp

Inconsistent parenthesization requirements for single-argument additional constructors (with `new`)

Open
#16,257 2 comments 0 reactions 1 assignee Claimed by @edgarfgp View on GitHub
Area-Compiler-Syntax Feature Improvement
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 22h
Merged PRs (30d)
144

Description

A single-argument additional constructor (i.e., a non-primary constructor declared with `new`) must have parentheses around its argument only if it is followed by another additional constructor.

**Repro steps**

1. Define a type with multiple additional constructors, one of which takes a single atomic argument pattern.
2. If the single-argument additional constructor is the last (or only) additional constructor, the argument does not need to be parenthesized; if any additional constructors follow it, the argument _does_ need to be parenthesized.

This:

```fsharp
type T (x, y) =
new (x) = T (x, 3)
```

can be simplified to

```fsharp
type T (x, y) =
new x = T (x, 3)
```

Likewise:

```fsharp
type T (x, y) =
new (x, y, z) = T (x, y)
new (x) = T (x, 3)
```

can become

```fsharp
type T (x, y) =
new (x, y, z) = T (x, y)
new x = T (x, 3)
```

But if there's another constructor and it comes _after_ the single-argument one:

```fsharp
type T (x, y) =
new (x) = T (x, 3)
new (x, y, _z) = T (x, y)
```

the parentheses must stay

```fsi
> type T (x, y) =
- new x = T (x, 3)
- new (x, y, _z) = T (x, y);;

new (x, y, _z) = T (x, y);;
-------------------^

stdin(3,20): error FS0010: Unexpected symbol '=' in expression
```

The removal of the parentheses has a significant effect on the way the following additional constructors are parsed:

- [AST with parens](https://fsprojects.github.io/fantomas-tools/#/ast?data=N4KABGBEAmCmBmBLAdrAzpAXFSAacUiaAYmolmPAIYA2as%2BEkAxgPZwWQAuAngA6wwAFTAAKAB64wPAJRgAvAB0ATouQQIqAO5jxc%2BcN1SAzDJVqNYbUelSA%2BgC99hiVNl4CkWOL5Vk0Ci5lAFdYEABfIA)
- [AST without parens](https://fsprojects.github.io/fantomas-tools/#/ast?data=N4KABGBEAmCmBmBLAdrAzpAXFSAacUiaAYmolmPAIYA2as%2BEkAxgPZwWQAuAngA6wwAFTAAKAB64wPAJRgAvAB0ATouQQIqAO5hxC4WMlgAzDJVqNYbYak8pAfQBec%2BQYm2ZeApFji%2BVZGgKLmUAV1gQAF8gA)
- [AST diff](https://gist.github.com/brianrourkeboll/cd8564c2a6ec7631ccc88afc7c06a645/revisions)

**Expected behavior**

Parentheses should either always be required for a single-argument additional constructor, or they should never be required.

**Actual behavior**

Parentheses are required for a single-argument additional constructor only if it is not the last additional constructor.

**Known workarounds**

N/A.

**Related information**

Provide any related information (optional):

.NET SDK 8.0.100-rc.2.23502.2 (and probably long before).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.