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 CE error reporting when using use! with and! #17671

Merged
merged 13 commits into from
Sep 10, 2024
Merged
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* Applied nullable reference types to FSharp.Compiler.Service itself ([PR #15310](https://github.com/dotnet/fsharp/pull/15310))
* Ensure that isinteractive multi-emit backing fields are not public. ([Issue #17439](https://github.com/dotnet/fsharp/issues/17438)), ([PR #17439](https://github.com/dotnet/fsharp/pull/17439))
* Better error reporting for unions with duplicated fields. ([PR #17521](https://github.com/dotnet/fsharp/pull/17521))
* Better CE error reporting when using `use!` with `and!` ([PR #17671](https://github.com/dotnet/fsharp/pull/17671))
* Better error reporting for let bindings. ([PR #17601](https://github.com/dotnet/fsharp/pull/17601))
* Optimize ILTypeDef interface impls reading from metadata. ([PR #17382](https://github.com/dotnet/fsharp/pull/17382))
* Better error reporting for active patterns. ([PR #17666](https://github.com/dotnet/fsharp/pull/17666))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1987,12 +1987,17 @@ let rec TryTranslateComputationExpression

Some(translatedCtxt bindExpr)

// 'use! pat = e1 ... in e2' where 'pat' is not a simple name --> error
// 'use! pat = e1 ... in e2' where 'pat' is not a simple name -> error
| SynExpr.LetOrUseBang(isUse = true; pat = pat; andBangs = andBangs) ->
if isNil andBangs then
error (Error(FSComp.SR.tcInvalidUseBangBinding (), pat.Range))
else
error (Error(FSComp.SR.tcInvalidUseBangBindingNoAndBangs (), comp.Range))
let m =
match andBangs with
| [] -> comp.Range
| h :: _ -> h.Trivia.AndBangKeyword

error (Error(FSComp.SR.tcInvalidUseBangBindingNoAndBangs (), m))

// 'let! pat1 = expr1 and! pat2 = expr2 in ...' -->
// build.BindN(expr1, expr2, ...)
Expand Down
8 changes: 8 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,14 @@ type SynExprAndBang =
range: range *
trivia: SynExprAndBangTrivia

member x.Range =
match x with
| SynExprAndBang(range = range) -> range

member this.Trivia =
match this with
| SynExprAndBang(trivia = trivia) -> trivia

[<NoEquality; NoComparison>]
type SynExprRecordField =
| SynExprRecordField of
Expand Down
6 changes: 6 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,12 @@ type SynExprAndBang =
range: range *
trivia: SynExprAndBangTrivia

/// Gets the syntax range of this construct
member Range: range

/// Gets the trivia associated with this construct
member Trivia: SynExprAndBangTrivia
edgarfgp marked this conversation as resolved.
Show resolved Hide resolved

[<NoEquality; NoComparison>]
type SynExprRecordField =
| SynExprRecordField of
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ type SynBindingTrivia =
[<NoEquality; NoComparison>]
type SynExprAndBangTrivia =
{
AndBangKeyword: range
EqualsRange: range
InKeyword: range option
}
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/SyntaxTree/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,10 @@ type SynBindingTrivia =
[<NoEquality; NoComparison>]
type SynExprAndBangTrivia =
{
/// The syntax range of the `and!` keyword
AndBangKeyword: range
/// The syntax range of the `=` token.
EqualsRange: range

/// The syntax range of the `in` keyword.
InKeyword: range option
}
Expand Down
6 changes: 4 additions & 2 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -4078,15 +4078,17 @@ moreBinders:
let mEquals = rhs parseState 3
let m = unionRanges (rhs parseState 1) $4.Range
let mIn = rhs parseState 5
SynExprAndBang(spBind, $1, true, $2, $4, m, { EqualsRange = mEquals; InKeyword = Some mIn }) :: $6 }
let trivia = { AndBangKeyword = rhs parseState 1; EqualsRange = mEquals; InKeyword = Some mIn }
SynExprAndBang(spBind, $1, true, $2, $4, m, trivia) :: $6 }

| OAND_BANG headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders %prec expr_let
{ let report, mIn, _ = $5
report "and!" (rhs parseState 1) // report unterminated error
let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 5) (* TODO Pretty sure this is wrong *)
let mEquals = rhs parseState 3
let m = unionRanges (rhs parseState 1) $4.Range
SynExprAndBang(spBind, $1, true, $2, $4, m, { EqualsRange = mEquals; InKeyword = mIn }) :: $7 }
let trivia = { AndBangKeyword = rhs parseState 1; EqualsRange = mEquals; InKeyword = mIn }
SynExprAndBang(spBind, $1, true, $2, $4, m, trivia) :: $7 }

| %prec prec_no_more_attr_bindings
{ [] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,98 @@ let x = A.Prop { return 0 }
|> compile
|> shouldSucceed
|> ignore

[<Fact>]
let ``use! may not be combined with and!`` () =
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

let result = ResultBuilder()

let run r2 r3 =
result {
use! b = r2
and! c = r3
return b - c
}
"""
|> ignoreWarnings
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 3345, Line 18, Col 9, Line 18, Col 13, "use! may not be combined with and!")
]

[<Fact>]
let ``multiple use! may not be combined with and!`` () =
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

let result = ResultBuilder()

let run r2 r3 =
result {
use! b = r2
and! c = r3
use! d = r2
return b - c
}
"""
|> ignoreWarnings
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 3345, Line 18, Col 9, Line 18, Col 13, "use! may not be combined with and!")
]

[<Fact>]
let ``multiple use! may not be combined with multiple and!`` () =
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 _.BindReturn(x: Result<'T,'U>, f) = Result.map f x
member _.Bind(x: Result<'T,'U>, f) = Result.bind f x

let result = ResultBuilder()

let run r2 r3 =
result {
let! c = r3
and! c = r3
use! b = r2
and! c = r3
return b - c
}
"""
|> ignoreWarnings
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 3345, Line 22, Col 9, Line 22, Col 13, "use! may not be combined with and!")
]
Original file line number Diff line number Diff line change
Expand Up @@ -7740,8 +7740,12 @@ FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynExpr get_body()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynExprAndBang NewSynExprAndBang(FSharp.Compiler.Syntax.DebugPointAtBinding, Boolean, Boolean, FSharp.Compiler.Syntax.SynPat, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia)
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynPat get_pat()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynPat pat
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia Trivia
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia get_Trivia()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia get_trivia()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia trivia
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range Range
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range get_Range()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range get_range()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range range
FSharp.Compiler.Syntax.SynExprAndBang: Int32 Tag
Expand Down Expand Up @@ -10139,12 +10143,14 @@ FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Microsoft.FSharp.Core.FSharpOpti
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_BarRange()
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], FSharp.Compiler.Text.Range)
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range AndBangKeyword
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range EqualsRange
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range get_AndBangKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range get_EqualsRange()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Void .ctor(FSharp.Compiler.Text.Range, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: FSharp.Compiler.Text.Range OpeningBraceRange
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: FSharp.Compiler.Text.Range get_OpeningBraceRange()
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: System.String ToString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7740,8 +7740,12 @@ FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynExpr get_body()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynExprAndBang NewSynExprAndBang(FSharp.Compiler.Syntax.DebugPointAtBinding, Boolean, Boolean, FSharp.Compiler.Syntax.SynPat, FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range, FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia)
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynPat get_pat()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Syntax.SynPat pat
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia Trivia
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia get_Trivia()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia get_trivia()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia trivia
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range Range
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range get_Range()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range get_range()
FSharp.Compiler.Syntax.SynExprAndBang: FSharp.Compiler.Text.Range range
FSharp.Compiler.Syntax.SynExprAndBang: Int32 Tag
Expand Down Expand Up @@ -10139,12 +10143,14 @@ FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Microsoft.FSharp.Core.FSharpOpti
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_BarRange()
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynEnumCaseTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range], FSharp.Compiler.Text.Range)
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range AndBangKeyword
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range EqualsRange
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range get_AndBangKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: FSharp.Compiler.Text.Range get_EqualsRange()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] InKeyword
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_InKeyword()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: System.String ToString()
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Void .ctor(FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprAndBangTrivia: Void .ctor(FSharp.Compiler.Text.Range, FSharp.Compiler.Text.Range, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range])
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: FSharp.Compiler.Text.Range OpeningBraceRange
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: FSharp.Compiler.Text.Range get_OpeningBraceRange()
FSharp.Compiler.SyntaxTrivia.SynExprAnonRecdTrivia: System.String ToString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ ImplFile
App
(NonAtomic, false, Ident getFoo,
Const (Unit, (4,22--4,24)), (4,15--4,24)),
(4,4--4,24), { EqualsRange = (4,13--4,14)
(4,4--4,24), { AndBangKeyword = (4,4--4,8)
EqualsRange = (4,13--4,14)
InKeyword = Some (4,25--4,27) });
SynExprAndBang
(Yes (5,4--6,10), false, true,
Expand All @@ -35,7 +36,8 @@ ImplFile
App
(NonAtomic, false, Ident getMeh,
Const (Unit, (5,22--5,24)), (5,15--5,24)),
(5,4--5,24), { EqualsRange = (5,13--5,14)
(5,4--5,24), { AndBangKeyword = (5,4--5,8)
EqualsRange = (5,13--5,14)
InKeyword = None })],
YieldOrReturn ((false, true), Ident bar, (6,4--6,14)),
(3,4--6,14), { EqualsRange = Some (3,13--3,14) }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ ImplFile
App
(NonAtomic, false, Ident getFoo,
Const (Unit, (5,22--5,24)), (5,15--5,24)),
(5,4--5,24), { EqualsRange = (5,13--5,14)
(5,4--5,24), { AndBangKeyword = (5,4--5,8)
EqualsRange = (5,13--5,14)
InKeyword = None })],
YieldOrReturn ((false, true), Ident bar, (7,4--7,14)),
(3,4--7,14), { EqualsRange = Some (3,13--3,14) }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ ImplFile
App
(NonAtomic, false, Ident someFunction,
Const (Unit, (4,26--4,28)), (4,13--4,28)),
(4,4--4,28), { EqualsRange = (4,11--4,12)
(4,4--4,28), { AndBangKeyword = (4,4--4,8)
EqualsRange = (4,11--4,12)
InKeyword = None })],
YieldOrReturn
((false, true), Const (Unit, (5,11--5,13)), (5,4--5,13)),
Expand Down
Loading