Skip to content

Commit 8b7bf60

Browse files
authored
Allow let! and use! binding with type annotation without parentheses. (#18508)
1 parent 5db953f commit 8b7bf60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+836
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Fixed
2+
3+
* Allow `let!` and `use!` type annotations without requiring parentheses ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))

docs/release-notes/.Language/preview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487))
88
* Warn when `unit` is passed to an `obj`-typed argument ([PR #18330](https://github.com/dotnet/fsharp/pull/18330))
99
* 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))
10+
* Allow `let!` and `use!` type annotations without requiring parentheses. ([PR #18508](https://github.com/dotnet/fsharp/pull/18508))
1011

1112
### Fixed
1213

src/Compiler/Checking/Expressions/CheckComputationExpressions.fs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,9 @@ let rec TryTranslateComputationExpression
17931793
let supportsUseBangBindingValueDiscard =
17941794
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.UseBangBindingValueDiscard
17951795

1796+
let supportsTypedLetOrUseBang =
1797+
ceenv.cenv.g.langVersion.SupportsFeature LanguageFeature.AllowTypedLetOrUseBang
1798+
17961799
// use! x = ...
17971800
// use! (x) = ...
17981801
// use! (__) = ...
@@ -1802,6 +1805,7 @@ let rec TryTranslateComputationExpression
18021805
match pat with
18031806
| SynPat.Named(ident = SynIdent(id, _); isThisVal = false) -> id, pat
18041807
| SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) -> id, pat
1808+
| SynPat.Typed(pat = pat) when supportsTypedLetOrUseBang -> extractIdentifierFromPattern pat
18051809
| SynPat.Wild(m) when supportsUseBangBindingValueDiscard ->
18061810
// To properly call the Using(disposable) CE member, we need to convert the wildcard to a SynPat.Named
18071811
let tmpIdent = mkSynId m "_"

src/Compiler/FSComp.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ featureSupportValueOptionsAsOptionalParameters,"Support ValueOption as valid typ
18001800
featureSupportWarnWhenUnitPassedToObjArg,"Warn when unit is passed to a member accepting `obj` argument, e.g. `Method(o:obj)` will warn if called via `Method()`."
18011801
featureUseBangBindingValueDiscard,"Allows use! _ = ... in computation expressions"
18021802
featureScopedNowarn,"Support for scoped enabling / disabling of warnings by #warn and #nowarn directives, also inside modules"
1803+
featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type annotations without requiring parentheses"
18031804
3874,lexWarnDirectiveMustBeFirst,"#nowarn/#warnon directives must appear as the first non-whitespace characters on a line"
18041805
3875,lexWarnDirectiveMustHaveArgs,"Warn directives must have warning number(s) as argument(s)"
18051806
3876,lexWarnDirectivesMustMatch,"There is another %s for this warning already in line %d."

src/Compiler/Facilities/LanguageFeatures.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ type LanguageFeature =
101101
| WarnWhenUnitPassedToObjArg
102102
| UseBangBindingValueDiscard
103103
| ScopedNowarn
104+
| AllowTypedLetOrUseBang
104105

105106
/// LanguageVersion management
106107
type LanguageVersion(versionText) =
@@ -233,6 +234,7 @@ type LanguageVersion(versionText) =
233234
LanguageFeature.WarnWhenUnitPassedToObjArg, previewVersion
234235
LanguageFeature.UseBangBindingValueDiscard, previewVersion
235236
LanguageFeature.ScopedNowarn, previewVersion
237+
LanguageFeature.AllowTypedLetOrUseBang, previewVersion
236238
]
237239

238240
static let defaultLanguageVersion = LanguageVersion("default")
@@ -397,6 +399,7 @@ type LanguageVersion(versionText) =
397399
| LanguageFeature.WarnWhenUnitPassedToObjArg -> FSComp.SR.featureSupportWarnWhenUnitPassedToObjArg ()
398400
| LanguageFeature.UseBangBindingValueDiscard -> FSComp.SR.featureUseBangBindingValueDiscard ()
399401
| LanguageFeature.ScopedNowarn -> FSComp.SR.featureScopedNowarn ()
402+
| LanguageFeature.AllowTypedLetOrUseBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens ()
400403

401404
/// Get a version string associated with the given feature.
402405
static member GetFeatureVersionString feature =

src/Compiler/Facilities/LanguageFeatures.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ type LanguageFeature =
9292
| WarnWhenUnitPassedToObjArg
9393
| UseBangBindingValueDiscard
9494
| ScopedNowarn
95+
| AllowTypedLetOrUseBang
9596

9697
/// LanguageVersion management
9798
type LanguageVersion =

src/Compiler/pars.fsy

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4466,6 +4466,39 @@ declExpr:
44664466
let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
44674467
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m, trivia) }
44684468

4469+
| BINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock IN opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
4470+
{ // Handle type annotations on patterns in let!/use! bindings
4471+
// Examples: let! x: int = async { return 1 }
4472+
// use! _: IDisposable = async { return new MemoryStream() }
4473+
let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 7)
4474+
let pat =
4475+
match $3 with
4476+
| None -> $2
4477+
| Some (_, SynReturnInfo((ty, _), _)) ->
4478+
SynPat.Typed($2, ty, unionRanges $2.Range ty.Range)
4479+
parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang pat.Range
4480+
let mEquals = rhs parseState 4
4481+
let m = unionRanges (rhs parseState 1) $9.Range
4482+
let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
4483+
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) }
4484+
4485+
| OBINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let
4486+
{ // Handle type annotations on patterns in let!/use! bindings (offside-sensitive version)
4487+
// This rule maintains consistent handling of binding constructs across different syntactic contexts
4488+
let report, mIn, _ = $6
4489+
report (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error
4490+
let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $5.Range)
4491+
let pat =
4492+
match $3 with
4493+
| None -> $2
4494+
| Some (_, SynReturnInfo((ty, _), _)) ->
4495+
SynPat.Typed($2, ty, unionRanges $2.Range ty.Range)
4496+
parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AllowTypedLetOrUseBang pat.Range
4497+
let mEquals = rhs parseState 4
4498+
let m = unionRanges (rhs parseState 1) $9.Range
4499+
let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals }
4500+
SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) }
4501+
44694502
| OBINDER headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let
44704503
{ // error recovery that allows intellisense when writing incomplete computation expressions
44714504
let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $4.Range)

src/Compiler/xlf/FSComp.txt.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compiler/xlf/FSComp.txt.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Compiler/xlf/FSComp.txt.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)