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

[<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