Skip to content
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

Better error reporting for use #17811

Merged
merged 16 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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/9.0.200.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
* Better ranges for CE `let!` and `use!` error reporting. ([PR #17712](https://github.com/dotnet/fsharp/pull/17712))
* Better ranges for CE `do!` error reporting. ([PR #17779](https://github.com/dotnet/fsharp/pull/17779))
* Better ranges for CE `match!`. ([PR #17789](https://github.com/dotnet/fsharp/pull/17789))
* Better ranges for CE `use` error reporting. ([PR #17811](https://github.com/dotnet/fsharp/pull/17811))

### Breaking Changes
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
17 changes: 16 additions & 1 deletion src/Compiler/SyntaxTree/ParseHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,22 @@ let mkLocalBindings (mWhole, BindingSetPreAttrs(_, isRec, isUse, declsPreAttrs,
else
Some mIn)

SynExpr.LetOrUse(isRec, isUse, decls, body, mWhole, { InKeyword = mIn })
let mLetOrUse =
match decls with
| SynBinding(trivia = trivia) :: _ -> trivia.LeadingKeyword.Range
| _ -> Range.Zero

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
7 changes: 6 additions & 1 deletion src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,15 @@ 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 @@ -493,4 +493,85 @@ let run r2 r3 =
|> shouldFail
|> withDiagnostics [
(Error 750, Line 3, Col 5, Line 3, Col 11, "This construct may only be used within computation expressions")
]
]

[<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")
]

[<Fact>]
let ``This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.`` () =
Fsx """
let x18rec2 =
query {
for d in [1..10] do
let rec f x = x + 1 // error expected here - no recursive functions
and g x = f x + 2
select (f d)
}

let x18inline =
query {
for d in [1..10] do
let inline f x = x + 1 // error expected here - no inline functions
select (f d)
}

let x18mutable =
query {
for d in [1..10] do
let mutable v = 1 // error expected here - no mutable values
select (f d)
}

"""
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 3147, Line 5, Col 17, Line 5, Col 20, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.")
(Error 3147, Line 13, Col 20, Line 13, Col 23, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.")
(Error 3147, Line 20, Col 21, Line 20, Col 22, "This 'let' definition may not be used in a query. Only simple value definitions may be used in queries.")
]
Original file line number Diff line number Diff line change
Expand Up @@ -10217,7 +10217,9 @@ FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.SyntaxTrivia
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range LetOrUseKeyword
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range get_LetOrUseKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range MatchBangKeyword
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range WithKeyword
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range get_MatchBangKeyword()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10217,7 +10217,9 @@ FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.SyntaxTrivia
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range LetOrUseKeyword
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: FSharp.Compiler.Text.Range get_LetOrUseKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprLetOrUseTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range MatchBangKeyword
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range WithKeyword
FSharp.Compiler.SyntaxTrivia.SynExprMatchBangTrivia: FSharp.Compiler.Text.Range get_MatchBangKeyword()
Expand Down
4 changes: 2 additions & 2 deletions tests/fsharp/typecheck/sigs/neg59.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ neg59.fs(89,15,89,18): typecheck error FS3141: 'try/finally' expressions may not

neg59.fs(95,15,95,18): typecheck error FS3141: 'try/finally' expressions may not be used in queries

neg59.fs(102,15,102,64): typecheck error FS3142: 'use' expressions may not be used in queries
neg59.fs(102,15,102,18): typecheck error FS3142: 'use' expressions may not be used in queries

neg59.fs(108,15,108,64): typecheck error FS3142: 'use' expressions may not be used in queries
neg59.fs(108,15,108,18): typecheck error FS3142: 'use' expressions may not be used in queries

neg59.fs(113,15,113,25): typecheck error FS3140: 'while' expressions may not be used in queries

Expand Down
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,16): 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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// #Regression #Conformance #DataExpressions #ComputationExpressions
// Regression test for FSHARP1.0:6149
//<Expects status="error" span="(17,3-17,18)" id="FS0708">This control construct may only be used if the computation expression builder defines a 'Using' method$</Expects>
//<Expects status="error" span="(17,3-17,6)" id="FS0708">This control construct may only be used if the computation expression builder defines a 'Using' method$</Expects>

type R = S of string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ ImplFile
{ LeadingKeyword = Let (3,4--3,7)
InlineKeyword = Some (3,8--3,14)
EqualsRange = Some (3,21--3,22) })],
Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }),
(2,11--2,16), NoneAtLet, { LeadingKeyword = Let (2,0--2,3)
InlineKeyword = Some (2,4--2,10)
EqualsRange = Some (2,17--2,18) })],
(2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,4--4,6)), (3,4--4,6),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = None }), (2,11--2,16), NoneAtLet,
{ LeadingKeyword = Let (2,0--2,3)
InlineKeyword = Some (2,4--2,10)
EqualsRange = Some (2,17--2,18) })], (2,0--4,6))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ ImplFile
Yes (3,4--3,13), { LeadingKeyword = Let (3,4--3,7)
InlineKeyword = None
EqualsRange = Some (3,10--3,11) })],
Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }),
(2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,4--4,6)), (3,4--4,6),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = None }), (2,0--4,6)), (2,0--4,6))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ ImplFile
{ LeadingKeyword = Let (3,4--3,7)
InlineKeyword = None
EqualsRange = Some (3,15--3,16) })],
Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }),
(2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,4--4,6)), (3,4--4,6),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = None }), (2,0--4,6)), (2,0--4,6))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ ImplFile
NoneAtLet, { LeadingKeyword = Let (3,4--3,7)
InlineKeyword = None
EqualsRange = Some (3,12--3,13) })],
Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }),
(2,4--2,5), NoneAtLet, { LeadingKeyword = Let (2,0--2,3)
InlineKeyword = None
EqualsRange = Some (2,6--2,7) })],
(2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,4--4,6)), (3,4--4,6),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = None }), (2,4--2,5), NoneAtLet,
{ LeadingKeyword = Let (2,0--2,3)
InlineKeyword = None
EqualsRange = Some (2,6--2,7) })], (2,0--4,6))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ ImplFile
[Some (OriginalNotation "+")]), None,
(5,6--5,7)), Ident x, (5,4--5,7)), Ident y,
(5,4--5,9)), (4,4--5,9),
{ InKeyword = Some (4,14--4,16) }), (3,4--5,9),
{ InKeyword = Some (3,14--3,16) }), (2,4--2,8), NoneAtLet,
{ LetOrUseKeyword = (4,4--4,7)
InKeyword = Some (4,14--4,16) }), (3,4--5,9),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = Some (3,14--3,16) }), (2,4--2,8), NoneAtLet,
{ LeadingKeyword = Let (2,0--2,3)
InlineKeyword = None
EqualsRange = Some (2,9--2,10) })], (2,0--5,9))],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ ImplFile
InlineKeyword = None
EqualsRange = Some (2,6--2,7) })],
Const (Unit, (2,13--2,15)), (2,0--2,15),
{ InKeyword = Some (2,10--2,12) }), (2,0--2,15))],
{ LetOrUseKeyword = (2,0--2,3)
InKeyword = Some (2,10--2,12) }), (2,0--2,15))],
PreXmlDocEmpty, [], None, (2,0--2,15), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ ImplFile
Yes (3,0--3,9), { LeadingKeyword = Let (3,0--3,3)
InlineKeyword = None
EqualsRange = Some (3,6--3,7) })],
Const (Unit, (4,0--4,2)), (3,0--4,2), { InKeyword = None }),
(2,0--4,2)), (2,0--4,2))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,0--4,2)), (3,0--4,2),
{ LetOrUseKeyword = (3,0--3,3)
InKeyword = None }), (2,0--4,2)), (2,0--4,2))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ ImplFile
SynLongIdent
([e1; Value], [(4,10--4,11)], [None; None]), None,
(4,8--4,16))], [(4,6--4,7)], (4,0--4,16)),
(3,0--4,16), { InKeyword = None }), (2,0--4,16)),
(3,0--4,16), { LetOrUseKeyword = (3,0--3,3)
InKeyword = None }), (2,0--4,16)),
(2,0--4,16))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ ImplFile
InlineKeyword = None
EqualsRange = Some (4,10--4,11) })],
Const (Unit, (5,4--5,6)), (3,4--5,6),
{ InKeyword = Some (4,15--4,17) }), (2,0--5,6)), (2,0--5,6))],
{ LetOrUseKeyword = (3,4--3,11)
InKeyword = Some (4,15--4,17) }), (2,0--5,6)), (2,0--5,6))],
PreXmlDocEmpty, [], None, (2,0--6,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ ImplFile
InlineKeyword = None
EqualsRange = Some (5,6--5,7) })],
ArbitraryAfterError ("seqExpr", (5,10--5,10)), (5,0--5,10),
{ InKeyword = None }), [], (3,0--5,10), Yes (3,0--3,3),
{ LetOrUseKeyword = (5,0--5,3)
InKeyword = None }), [], (3,0--5,10), Yes (3,0--3,3),
Yes (5,10--5,10), { TryKeyword = (3,0--3,3)
TryToWithRange = (3,0--5,10)
WithKeyword = (5,10--5,10)
Expand Down
11 changes: 6 additions & 5 deletions tests/service/data/SyntaxTree/LeadingKeyword/UseKeyword.fs.bsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ ImplFile
{ LeadingKeyword = Use (3,4--3,7)
InlineKeyword = None
EqualsRange = Some (3,10--3,11) })],
Const (Unit, (4,4--4,6)), (3,4--4,6), { InKeyword = None }),
(2,0--4,6)), (2,0--4,6))], PreXmlDocEmpty, [], None, (2,0--5,0),
{ LeadingKeyword = None })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
Const (Unit, (4,4--4,6)), (3,4--4,6),
{ LetOrUseKeyword = (3,4--3,7)
InKeyword = None }), (2,0--4,6)), (2,0--4,6))],
PreXmlDocEmpty, [], None, (2,0--5,0), { LeadingKeyword = None })],
(true, true), { ConditionalDirectives = []
CodeComments = [] }, set []))
Loading
Loading