Skip to content

Allow typed bindings(and!) in CE without parentheses #18682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1799aaf
make attribute targets mismatches a warning and not an error.
edgarfgp Apr 23, 2025
55507e9
release notes
edgarfgp Apr 23, 2025
1738018
update tests
edgarfgp Apr 23, 2025
65f5bb6
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 24, 2025
0c97b9d
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 27, 2025
6f2b706
update baselines
edgarfgp Apr 29, 2025
e8f1bb0
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 29, 2025
75d8f5e
Update baselines
edgarfgp Apr 29, 2025
4f2e97e
Merge branch 'fix-attr-targets' of github.com:edgarfgp/fsharp into fi…
edgarfgp Apr 29, 2025
63be5d5
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 30, 2025
4248f2a
Move attribute form logic to an AP
edgarfgp Apr 30, 2025
cc96217
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e270b88
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e0cc65a
Merge branch 'main' into fix-attr-targets
edgarfgp May 2, 2025
1e29d58
Merge branch 'main' into fix-attr-targets
edgarfgp May 5, 2025
1470bf9
Merge branch 'main' into fix-attr-targets
edgarfgp May 6, 2025
8988215
Merge branch 'main' into fix-attr-targets
edgarfgp May 7, 2025
74712e8
Merge branch 'main' into fix-attr-targets
edgarfgp May 12, 2025
967c4a9
Merge branch 'main' of github.com:edgarfgp/fsharp
edgarfgp May 13, 2025
a30cef4
Merge branch 'dotnet:main' into main
edgarfgp May 22, 2025
5fa0480
Merge branch 'dotnet:main' into main
edgarfgp May 24, 2025
15e3d34
Merge branch 'dotnet:main' into main
edgarfgp May 29, 2025
b7ffcf8
Merge branch 'dotnet:main' into main
edgarfgp Jun 6, 2025
549f961
Add new parser rule and syntax tree tests
edgarfgp Jun 10, 2025
b3f4baa
Add CE test that uses let! and and!
edgarfgp Jun 10, 2025
98937bc
more syntax tree tests
edgarfgp Jun 10, 2025
a020505
more syntax tree tests
edgarfgp Jun 10, 2025
1ba22bf
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jun 11, 2025
dce81de
more syntax tree tests
edgarfgp Jun 10, 2025
c921606
Merge branch 'allow-and-bang-typed-bindings' of github.com:edgarfgp/f…
edgarfgp Jun 11, 2025
86fedfd
Update LanguageFeature and release notes
edgarfgp Jun 11, 2025
aee26ec
update baselines
edgarfgp Jun 11, 2025
4712569
more tests
edgarfgp Jun 18, 2025
43a4c21
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jun 18, 2025
3a346de
update tests
edgarfgp Jun 18, 2025
c03a338
Unifying let, let! and! parser rules
edgarfgp Jun 19, 2025
03805f5
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jun 19, 2025
81c0aba
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jul 5, 2025
b5a9e9f
Unify mkLetExpression
edgarfgp Jul 5, 2025
9e2e694
Merge branch 'allow-and-bang-typed-bindings' of github.com:edgarfgp/f…
edgarfgp Jul 5, 2025
7aeb9b7
format code
edgarfgp Jul 5, 2025
9e50380
update tests
edgarfgp Jul 6, 2025
4cecf5e
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jul 7, 2025
63ba102
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jul 10, 2025
cc89f66
Merge branch 'main' into allow-and-bang-typed-bindings
edgarfgp Jul 12, 2025
02fecdf
cover error cases in the grammar
edgarfgp Jul 12, 2025
fd7e890
Use parsExpectingType
edgarfgp Jul 12, 2025
58667ff
more tests
edgarfgp Jul 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Fix parsing errors using anonymous records and code quotations ([PR #18603](https://github.com/dotnet/fsharp/pull/18603))
* Better error message for attribute targets. ([PR #18641](https://github.com/dotnet/fsharp/pull/18641))
* Fixed: Allow `return`, `return!`, `yield`, `yield!` type annotations without parentheses ([PR #18533](https://github.com/dotnet/fsharp/pull/18533))
* Allow `let!` and `use!` type annotations without requiring parentheses ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))
* Allow `let!`, `use!`, `and!` type annotations without requiring parentheses (([PR #18508](https://github.com/dotnet/fsharp/pull/18508) and [PR #18682](https://github.com/dotnet/fsharp/pull/18682)))
* Fix find all references for F# exceptions ([PR #18565](https://github.com/dotnet/fsharp/pull/18565))
* Shorthand lambda: fix completion for chained calls and analysis for unfinished expression ([PR #18560](https://github.com/dotnet/fsharp/pull/18560))
* Completion: fix previous namespace considered opened [PR #18609](https://github.com/dotnet/fsharp/pull/18609)
Expand Down
2 changes: 1 addition & 1 deletion docs/release-notes/.Language/preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330))
* Fix parsing errors using anonymous records and units of measures ([PR #18543](https://github.com/dotnet/fsharp/pull/18543))
* Scoped Nowarn: added the #warnon compiler directive ([Language suggestion #278](https://github.com/fsharp/fslang-suggestions/issues/278), [RFC FS-1146 PR](https://github.com/fsharp/fslang-design/pull/782), [PR #18049](https://github.com/dotnet/fsharp/pull/18049))
* Allow `let!` and `use!` type annotations without requiring parentheses. ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))
* Allow `let!`, `use!`, `and!` type annotations without requiring parentheses (([PR #18508](https://github.com/dotnet/fsharp/pull/18508) and [PR #18682](https://github.com/dotnet/fsharp/pull/18682)))

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,7 @@ let rec TryTranslateComputationExpression
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.UseBangBindingValueDiscard

let supportsTypedLetOrUseBang =
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowTypedLetOrUseBang
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowTypedLetUseAndBang

// use! x = ...
// use! (x) = ...
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Facilities/LanguageFeatures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ type LanguageFeature =
| UseBangBindingValueDiscard
| BetterAnonymousRecordParsing
| ScopedNowarn
| AllowTypedLetOrUseBang
| AllowTypedLetUseAndBang

/// LanguageVersion management
type LanguageVersion(versionText) =
Expand Down Expand Up @@ -235,7 +235,7 @@ type LanguageVersion(versionText) =
LanguageFeature.UseBangBindingValueDiscard, languageVersion100
LanguageFeature.BetterAnonymousRecordParsing, languageVersion100
LanguageFeature.ScopedNowarn, languageVersion100
LanguageFeature.AllowTypedLetOrUseBang, languageVersion100
LanguageFeature.AllowTypedLetUseAndBang, languageVersion100
LanguageFeature.UnmanagedConstraintCsharpInterop, languageVersion100
LanguageFeature.AllowAccessModifiersToAutoPropertiesGettersAndSetters, languageVersion100

Expand Down Expand Up @@ -408,7 +408,7 @@ type LanguageVersion(versionText) =
| LanguageFeature.UseBangBindingValueDiscard -> FSComp.SR.featureUseBangBindingValueDiscard ()
| LanguageFeature.BetterAnonymousRecordParsing -> FSComp.SR.featureBetterAnonymousRecordParsing ()
| LanguageFeature.ScopedNowarn -> FSComp.SR.featureScopedNowarn ()
| LanguageFeature.AllowTypedLetOrUseBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens ()
| LanguageFeature.AllowTypedLetUseAndBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens ()

/// Get a version string associated with the given feature.
static member GetFeatureVersionString feature =
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Facilities/LanguageFeatures.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ type LanguageFeature =
| UseBangBindingValueDiscard
| BetterAnonymousRecordParsing
| ScopedNowarn
| AllowTypedLetOrUseBang
| AllowTypedLetUseAndBang

/// LanguageVersion management
type LanguageVersion =
Expand Down
107 changes: 76 additions & 31 deletions src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -867,41 +867,19 @@ let mkClassMemberLocalBindings

SynMemberDefn.LetBindings(decls, isStatic, isRec, mWhole)

let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _), mIn, body: SynExpr) =
let ignoredFreeAttrs, decls = declsPreAttrs [] None
/// Creates a SynExprAndBang node for and! bindings in computation expressions
let mkAndBang (mKeyword: range, pat: SynPat, rhs: SynExpr, mWhole: range, mEquals: range, mIn: range option) =
let spBind = DebugPointAtBinding.Yes(unionRanges mKeyword rhs.Range)

let mWhole =
match decls with
| SynBinding(xmlDoc = xmlDoc) :: _ -> unionRangeWithXmlDoc xmlDoc mWhole
| _ -> mWhole

if not (isNil ignoredFreeAttrs) then
warning (Error(FSComp.SR.parsAttributesIgnored (), mWhole))

let mIn =
mIn
|> Option.bind (fun (mIn: range) ->
if Position.posEq mIn.Start body.Range.Start then
None
else
Some mIn)

let mLetOrUse =
match decls with
| SynBinding(trivia = trivia) :: _ -> trivia.LeadingKeyword.Range
| _ -> range0

SynExpr.LetOrUse(
isRec,
isUse,
decls,
body,
mWhole,
let trivia: SynExprAndBangTrivia =
{
LetOrUseKeyword = mLetOrUse
AndBangKeyword = mKeyword
EqualsRange = mEquals
InKeyword = mIn
}
)

// For and!, isUse is always true, isFromSource is always true
SynExprAndBang(spBind, false, true, pat, rhs, mWhole, trivia)

let mkDefnBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _bindingSetRange), attrs, vis, attrsm) =
if isUse then
Expand Down Expand Up @@ -1073,3 +1051,70 @@ let leadingKeywordIsAbstract =
| SynLeadingKeyword.StaticAbstract _
| SynLeadingKeyword.StaticAbstractMember _ -> true
| _ -> false

/// Unified helper for creating let/let!/use/use! expressions
/// Creates either SynExpr.LetOrUse or SynExpr.LetOrUseBang based on isBang parameter
/// Handles all four cases: 'let', 'let!', 'use', and 'use!'
let mkLetExpression
(
isBang: bool,
mKeyword: range,
mIn: Option<range>,
mWhole: range,
body: SynExpr,
bindingInfo: (bool * BindingSet) option,
bangInfo: (SynPat * SynExpr * SynExprAndBang list * range option * bool) option
) =
if isBang then
match bangInfo with
| Some(pat, rhs, andBangs, mEquals, isUse) ->
// Create let! or use! expression
let spBind = DebugPointAtBinding.Yes(unionRanges mKeyword rhs.Range)

let trivia: SynExprLetOrUseBangTrivia =
{
LetOrUseBangKeyword = mKeyword
EqualsRange = mEquals
}
// isFromSource is true for user-written code
SynExpr.LetOrUseBang(spBind, isUse, true, pat, rhs, andBangs, body, mWhole, trivia)
| None -> SynExpr.FromParseError(body, mWhole)
else
match bindingInfo with
| Some(isRec, BindingSetPreAttrs(_, _, isUse, declsPreAttrs, _)) ->
// Create regular let or use expression
let ignoredFreeAttrs, decls = declsPreAttrs [] None

let mWhole' =
match decls with
| SynBinding(xmlDoc = xmlDoc) :: _ -> unionRangeWithXmlDoc xmlDoc mWhole
| _ -> mWhole

if not (isNil ignoredFreeAttrs) then
warning (Error(FSComp.SR.parsAttributesIgnored (), mWhole'))

let mIn' =
mIn
|> Option.bind (fun (mIn: range) ->
if Position.posEq mIn.Start body.Range.Start then
None
else
Some mIn)

let mLetOrUse =
match decls with
| SynBinding(trivia = trivia) :: _ -> trivia.LeadingKeyword.Range
| _ -> range0

SynExpr.LetOrUse(
isRec,
isUse, // Pass through the isUse flag from binding info
decls,
body,
mWhole',
{
LetOrUseKeyword = mLetOrUse
InKeyword = mIn'
}
)
| None -> SynExpr.FromParseError(body, mWhole)
15 changes: 14 additions & 1 deletion src/Compiler/SyntaxTree/ParseHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,20 @@ val mkClassMemberLocalBindings:
isStatic: bool * initialRangeOpt: range option * attrs: SynAttributes * vis: SynAccess option * BindingSet ->
SynMemberDefn

val mkLocalBindings: mWhole: range * BindingSet * mIn: range option * body: SynExpr -> SynExpr
/// Creates either SynExpr.LetOrUse or SynExpr.LetOrUseBang based on isBang parameter
/// Handles all four cases: 'let', 'let!', 'use', and 'use!'
val mkLetExpression:
isBang: bool *
mKeyword: range *
mIn: range option *
mWhole: range *
body: SynExpr *
bindingInfo: (bool * BindingSet) option *
bangInfo: (SynPat * SynExpr * SynExprAndBang list * range option * bool) option ->
SynExpr

val mkAndBang:
mKeyword: range * pat: SynPat * rhs: SynExpr * mWhole: range * mEquals: range * mIn: range option -> SynExprAndBang

val mkDefnBindings:
mWhole: range * BindingSet * attrs: SynAttributes * vis: SynAccess option * attrsm: range -> SynModuleDecl list
Expand Down
Loading
Loading