Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/10.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* Fix FS3356 false positive for instance extension members with same name on different types, introduced by [#18821](https://github.com/dotnet/fsharp/pull/18821). ([PR #19260](https://github.com/dotnet/fsharp/pull/19260))
* Fix graph-based type checking incorrectly resolving dependencies when the same module name is defined across multiple files in the same namespace. ([PR #19280](https://github.com/dotnet/fsharp/pull/19280))
* F# Scripts: Fix default reference paths resolving when an SDK directory is specified. ([PR #19270](https://github.com/dotnet/fsharp/pull/19270))
* Fix a bug where `let!` and `use!` were incorrectly allowed outside computation expressions. [PR #19347](https://github.com/dotnet/fsharp/pull/19347)

### Added
* FSharpType: add ImportILType ([PR #19300](https://github.com/dotnet/fsharp/pull/19300))
Expand Down
11 changes: 7 additions & 4 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6002,7 +6002,13 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights)
cenv.TcArrayOrListComputedExpression cenv env overallTy tpenv (isArray, comp) m

| SynExpr.LetOrUse _ ->
| SynExpr.LetOrUse letOrUse ->
match letOrUse with
| { Bindings = SynBinding(trivia = { LeadingKeyword = leadingKeyword }) :: _ }
when letOrUse.IsBang ->
errorR(Error(FSComp.SR.tcConstructRequiresComputationExpression(), leadingKeyword.Range))
| _ -> ()

TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr id

| SynExpr.TryWith (synBodyExpr, synWithClauses, mTryToLast, spTry, spWith, trivia) ->
Expand Down Expand Up @@ -6110,9 +6116,6 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
| SynExpr.MatchBang (trivia = { MatchBangKeyword = m })
| SynExpr.WhileBang (range = m) ->
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m))
| LetOrUse({ Bindings = [ SynBinding(trivia = { LeadingKeyword = leadingKeyword }) ]}, true, _) ->
error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), leadingKeyword.Range))

| SynExpr.IndexFromEnd (rightExpr, m) ->
errorR(Error(FSComp.SR.tcTraitInvocationShouldUseTick(), m))
let adjustedExpr = ParseHelpers.adjustHatPrefixToTyparLookup m rightExpr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,63 @@ module EmptyBodied =
|> shouldFail
|> withErrorCode 789
|> withErrorMessage "'{ }' is not a valid expression. Records must include at least one field. Empty sequences are specified by using Seq.empty or an empty list '[]'."

module LetUseBangTests =

[<Fact>]
let ``let! isn't allowed outside of Computation Expression`` () =
FSharp """
let test =
let! a = 1 + 1
()
"""
|> asExe
|> compile
|> withErrorCode 750
|> withErrorMessage "This construct may only be used within computation expressions"

[<Fact>]
let ``use! isn't allowed outside of Computation Expression`` () =
FSharp """
open System

let test =
use! a =
{ new IDisposable with
member this.Dispose() = ()
}
()
"""
|> asExe
|> compile
|> withErrorCode 750
|> withErrorMessage "This construct may only be used within computation expressions"

[<Fact>]
let ``let! with and! aren't allowed outside of Computation Expression`` () =
FSharp """
let test =
let! a = 1 + 1
and! b = 1 + 1
()
"""
|> asExe
|> compile
|> withErrorCode 750
|> withErrorMessage "This construct may only be used within computation expressions"

[<Fact>]
let ``When let! is outside of Computation Expression, the analysis lasts`` () =
FSharp """
let test =
let! a = 1 + 1
return! 0
"""
|> asExe
|> compile
|> withDiagnostics [
(Error 750, Line 3, Col 13, Line 3, Col 17,
"This construct may only be used within computation expressions");
(Error 748, Line 4, Col 13, Line 4, Col 20,
"This construct may only be used within computation expressions. To return a value from an ordinary function simply write the expression without 'return'.")
]
Loading