Skip to content

Commit

Permalink
Better error reporting for use
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarfgp committed Sep 27, 2024
1 parent 6cdcc3c commit 7432bc0
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1801,11 +1801,8 @@ let rec TryTranslateComputationExpression
| SynExpr.LetOrUse(
isUse = true
bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr; debugPoint = spBind) ]
body = innerComp) ->
let mBind =
match spBind with
| DebugPointAtBinding.Yes m -> m
| _ -> rhsExpr.Range
body = innerComp
trivia = { LetOrUseKeyword = mBind }) ->

if ceenv.isQuery then
error (Error(FSComp.SR.tcUseMayNotBeUsedInQueries (), mBind))
Expand Down
10 changes: 3 additions & 7 deletions src/Compiler/Checking/Expressions/CheckSequenceExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,10 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT
// 'use x = expr in expr'
| SynExpr.LetOrUse(
isUse = true
bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr; debugPoint = spBind) ]
bindings = [ SynBinding(kind = SynBindingKind.Normal; headPat = pat; expr = rhsExpr) ]
body = innerComp
range = wholeExprMark) ->
range = wholeExprMark
trivia = { LetOrUseKeyword = mBind }) ->

let bindPatTy = NewInferenceType g
let inputExprTy = NewInferenceType g
Expand All @@ -252,11 +253,6 @@ let TcSequenceExpression (cenv: TcFileState) env tpenv comp (overallTy: OverallT
let envinner = { envinner with eIsControlFlow = true }
tcSequenceExprBody envinner genOuterTy tpenv innerComp

let mBind =
match spBind with
| DebugPointAtBinding.Yes m -> m.NoteSourceConstruct(NotedSourceConstruct.Binding)
| _ -> inputExpr.Range

let inputExprMark = inputExpr.Range

let matchv, matchExpr =
Expand Down
7 changes: 6 additions & 1 deletion src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,8 +1048,13 @@ let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs,
None
else
Some mIn)

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

SynExpr.LetOrUse(isRec, isUse, decls, body, mWhole, { InKeyword = mIn })
SynExpr.LetOrUse(isRec, isUse, decls, body, mWhole, { LetOrUseKeyword = mLetOrUse ; InKeyword = mIn })

let mkDefnBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs, _bindingSetRange), attrs, vis, attrsm) =
if isUse then
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,11 @@ type SynExprDotLambdaTrivia =
[<NoEquality; NoComparison>]
type SynExprLetOrUseTrivia =
{
LetOrUseKeyword: range
InKeyword: range option
}

static member Zero: SynExprLetOrUseTrivia = { InKeyword = None }
static member Zero: SynExprLetOrUseTrivia = { InKeyword = None; LetOrUseKeyword = Range.Zero }

[<NoEquality; NoComparison>]
type SynExprLetOrUseBangTrivia =
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ type SynExprDotLambdaTrivia =
[<NoEquality; NoComparison>]
type SynExprLetOrUseTrivia =
{
/// The syntax range of the `let` or `use` keyword.
LetOrUseKeyword: range
/// The syntax range of the `in` keyword.
InKeyword: range option
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,4 +442,52 @@ query {
|> shouldFail
|> withDiagnostics [
(Error 3143, Line 4, Col 5, Line 4, Col 9, "'let!', 'use!' and 'do!' expressions may not be used in queries")
]
]

[<Fact>]
let ``use expressions may not be used in queries(SynExpr.Sequential)`` () =
Fsx """
let x11 =
query { for c in [1..10] do
use x = { new System.IDisposable with __.Dispose() = () }
yield 1 }
"""
|> ignoreWarnings
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 3142, Line 4, Col 13, Line 4, Col 16, "'use' expressions may not be used in queries")
]

[<Fact>]
let ``use, This control construct may only be used if the computation expression builder defines a 'Using' method`` () =
Fsx """
module Result =
let zip x1 x2 =
match x1,x2 with
| Ok x1res, Ok x2res -> Ok (x1res, x2res)
| Error e, _ -> Error e
| _, Error e -> Error e
type ResultBuilder() =
member _.MergeSources(t1: Result<'T,'U>, t2: Result<'T1,'U>) = Result.zip t1 t2
member _.BindReturn(x: Result<'T,'U>, f) = Result.map f x
member _.YieldReturn(x: Result<'T,'U>) = x
member _.Return(x: 'T) = Ok x
let result = ResultBuilder()
let run r2 r3 =
result {
use b = r2
return Ok 0
}
"""
|> ignoreWarnings
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 708, Line 20, Col 9, Line 20, Col 12, "This control construct may only be used if the computation expression builder defines a 'Using' method")
]

2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg61.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ neg61.fs(79,13,79,16): typecheck error FS3146: 'try/with' expressions may not be

neg61.fs(86,13,86,16): typecheck error FS3141: 'try/finally' expressions may not be used in queries

neg61.fs(92,13,92,70): typecheck error FS3142: 'use' expressions may not be used in queries
neg61.fs(92,13,92,15): typecheck error FS3142: 'use' expressions may not be used in queries

neg61.fs(97,13,97,17): typecheck error FS3143: 'let!', 'use!' and 'do!' expressions may not be used in queries

Expand Down

0 comments on commit 7432bc0

Please sign in to comment.