diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md index e187f285d4b..34cd87ffba9 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.300.md @@ -27,6 +27,7 @@ * Fix missing `null` highlighting in tooltips ([PR #18457](https://github.com/dotnet/fsharp/pull/18457)) * Fix range of SynPat.Named doesn't include accessibility ([PR #18526](https://github.com/dotnet/fsharp/pull/18526)) * Allow `_` in `use!` bindings values (lift FS1228 restriction) ([PR #18487](https://github.com/dotnet/fsharp/pull/18487)) +* Allow `let!` and `use!` binding with type annotation without parentheses. ([PR #18508](https://github.com/dotnet/fsharp/pull/18508)) * Make `[]` combination work([PR #18444](https://github.com/dotnet/fsharp/pull/18444/)) * Fix code completion considers types from own namespace non-imported ([PR #18518](https://github.com/dotnet/fsharp/issues/18518)) * Code completion: fix getting qualifier expression in do statements in type decls ([PR #18524](https://github.com/dotnet/fsharp/pull/18524)) diff --git a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs index f861665a5fc..5569b9d3328 100644 --- a/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs @@ -1802,6 +1802,7 @@ let rec TryTranslateComputationExpression match pat with | SynPat.Named(ident = SynIdent(id, _); isThisVal = false) -> id, pat | SynPat.LongIdent(longDotId = SynLongIdent(id = [ id ])) -> id, pat + | SynPat.Typed(pat = pat) -> extractIdentifierFromPattern pat | SynPat.Wild(m) when supportsUseBangBindingValueDiscard -> // To properly call the Using(disposable) CE member, we need to convert the wildcard to a SynPat.Named let tmpIdent = mkSynId m "_" diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index e5e0bca6a29..227d2a88520 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4466,6 +4466,37 @@ declExpr: let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals } SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, $2, $4, $7, $8, m, trivia) } + | BINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock IN opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let + { // Handle type annotations on patterns in let!/use! bindings + // Examples: let! x: int = async { return 1 } + // use! _: IDisposable = async { return new MemoryStream() } + let spBind = DebugPointAtBinding.Yes(rhs2 parseState 1 7) + let pat = + match $3 with + | None -> $2 + | Some (_, SynReturnInfo((ty, _), _)) -> + SynPat.Typed($2, ty, unionRanges $2.Range ty.Range) + let mEquals = rhs parseState 4 + let m = unionRanges (rhs parseState 1) $9.Range + let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals } + SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) } + + | OBINDER headBindingPattern opt_topReturnTypeWithTypeConstraints EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders typedSequentialExprBlock %prec expr_let + { // Handle type annotations on patterns in let!/use! bindings (offside-sensitive version) + // This rule maintains consistent handling of binding constructs across different syntactic contexts + let report, mIn, _ = $6 + report (if $1 = "use" then "use!" else "let!") (rhs parseState 1) // report unterminated error + let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $5.Range) + let pat = + match $3 with + | None -> $2 + | Some (_, SynReturnInfo((ty, _), _)) -> + SynPat.Typed($2, ty, unionRanges $2.Range ty.Range) + let mEquals = rhs parseState 4 + let m = unionRanges (rhs parseState 1) $9.Range + let trivia: SynExprLetOrUseBangTrivia = { LetOrUseBangKeyword = rhs parseState 1 ; EqualsRange = Some mEquals } + SynExpr.LetOrUseBang(spBind, ($1 = "use"), true, pat, $5, $8, $9, m, trivia) } + | OBINDER headBindingPattern EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let { // error recovery that allows intellisense when writing incomplete computation expressions let spBind = DebugPointAtBinding.Yes(unionRanges (rhs parseState 1) $4.Range) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs new file mode 100644 index 00000000000..7bd2b4cd827 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBang05.fs @@ -0,0 +1,58 @@ +open System + +open System + +type Disposable(id: int) = + static let mutable disposedIds = Set.empty + static let mutable constructedIds = Set.empty + + do constructedIds <- constructedIds.Add(id) + + member _.Id = id + + static member GetDisposed() = disposedIds + static member GetConstructed() = constructedIds + static member Reset() = + disposedIds <- Set.empty + constructedIds <- Set.empty + + interface IDisposable with + member this.Dispose() = disposedIds <- disposedIds.Add(this.Id) + +type DisposableBuilder() = + member _.Using(resource: #IDisposable, f) = + async { + use res = resource + return! f res + } + + member _.Bind(disposable: Disposable, f) = async.Bind(async.Return(disposable), f) + member _.Return(x) = async.Return x + member _.ReturnFrom(x) = x + member _.Bind(task, f) = async.Bind(task, f) + +let counterDisposable = DisposableBuilder() + +let testBindingPatterns() = + Disposable.Reset() + + counterDisposable { + use! res:IDisposable = new Disposable(1) + use! __:IDisposable = new Disposable(2) + use! (res1: IDisposable) = new Disposable(3) + use! _: IDisposable = new Disposable(4) + use! (_: IDisposable) = new Disposable(5) + return () + } |> Async.RunSynchronously + + let constructed = Disposable.GetConstructed() + let disposed = Disposable.GetDisposed() + let undisposed = constructed - disposed + + if not undisposed.IsEmpty then + printfn $"Undisposed instances: %A{undisposed}" + failwithf "Not all disposables were properly disposed" + else + printfn $"Success! All %d{constructed.Count} disposables were properly disposed" + +testBindingPatterns() \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs index ba0f31bd885..0028acc8a90 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBangBindings.fs @@ -50,6 +50,17 @@ module UseBangBindingsVersion9 = |> withDiagnostics [ (Error 1228, Line 47, Col 14, Line 47, Col 15, "'use!' bindings must be of the form 'use! = '") ] + + [] + let ``UseBangBindings - UseBang05_fs - Current LangVersion`` compilation = + compilation + |> asFsx + |> withLangVersion90 + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 1228, Line 43, Col 14, Line 43, Col 15, "'use!' bindings must be of the form 'use! = '") + ] module UseBangBindingsPreview = [] @@ -83,4 +94,13 @@ module UseBangBindingsPreview = |> withLangVersionPreview |> compileAndRun |> shouldSucceed + + [] + let ``UseBangBindings - UseBang05_fs - Preview LangVersion`` compilation = + compilation + |> asExe + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs new file mode 100644 index 00000000000..4fbe7575b3a --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding01.fs @@ -0,0 +1,7 @@ +// #DeclarationElements #LetBindings +// +open System + +let answer = + use x:IDisposable = new System.IO.MemoryStream() + 42 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs new file mode 100644 index 00000000000..be6cf7b8399 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBinding02.fs @@ -0,0 +1,26 @@ +open System + +type private Disposable() = + [] static val mutable private disposedTimes: int + [] static val mutable private constructedTimes: int + + do Disposable.constructedTimes <- Disposable.constructedTimes + 1 + + static member DisposeCallCount() = Disposable.disposedTimes + static member ConstructorCallCount() = Disposable.constructedTimes + + interface System.IDisposable with + member _.Dispose() = + Disposable.disposedTimes <- Disposable.disposedTimes + 1 + +let _scope = + use x: IDisposable = new Disposable() + () + +let disposeCalls = Disposable.DisposeCallCount() +if disposeCalls <> 1 then + failwith "was not disposed or disposed too many times" + +let ctorCalls = Disposable.ConstructorCallCount() +if ctorCalls <> 1 then + failwithf "unexpected constructor call count: %i" ctorCalls diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs new file mode 100644 index 00000000000..840870377fe --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindingDiscard03.fs @@ -0,0 +1,26 @@ +open System + +type private Disposable() = + [] static val mutable private disposedTimes: int + [] static val mutable private constructedTimes: int + + do Disposable.constructedTimes <- Disposable.constructedTimes + 1 + + static member DisposeCallCount() = Disposable.disposedTimes + static member ConstructorCallCount() = Disposable.constructedTimes + + interface System.IDisposable with + member _.Dispose() = + Disposable.disposedTimes <- Disposable.disposedTimes + 1 + +let _scope = + use _:IDisposable = new Disposable() + () + +let disposeCalls = Disposable.DisposeCallCount() +if disposeCalls <> 1 then + failwith "was not disposed or disposed too many times" + +let ctorCalls = Disposable.ConstructorCallCount() +if ctorCalls <> 1 then + failwithf "unexpected constructor call count: %i" ctorCalls diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs index 74137286a8a..b1e08869312 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/UseBindings/UseBindings.fs @@ -33,4 +33,25 @@ module UseBindings = |> asExe |> withLangVersion60 |> compileAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``UseBindings - UseBindingDiscard03_fs - Current LangVersion`` compilation = + compilation + |> asExe + |> compileAndRun + |> shouldSucceed + + [] + let ``UseBindings - UseBinding01_fs - Current LangVersion`` compilation = + compilation + |> asFsx + |> compile + |> shouldSucceed + + [] + let ``UseBindings - UseBinding02_fs - Current LangVersion`` compilation = + compilation + |> asFsx + |> compile + |> shouldSucceed diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs new file mode 100644 index 00000000000..f191f7aee2b --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs @@ -0,0 +1,6 @@ +module Module + +async { + let! res: int = async { return 1 } + return res +} diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs.bsl new file mode 100644 index 00000000000..25dcb64b68f --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 01.fs.bsl @@ -0,0 +1,36 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 01.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + LetOrUseBang + (Yes (4,4--4,38), false, true, + Typed + (Named (SynIdent (res, None), false, None, (4,9--4,12)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,9--4,17)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (4,35--4,36)), + (4,28--4,36), + { YieldOrReturnKeyword = (4,28--4,34) }), + (4,26--4,38)), (4,20--4,38)), [], + YieldOrReturn + ((false, true), Ident res, (5,4--5,14), + { YieldOrReturnKeyword = (5,4--5,10) }), (4,4--5,14), + { LetOrUseBangKeyword = (4,4--4,8) + EqualsRange = Some (4,18--4,19) }), (3,6--6,1)), + (3,0--6,1)), (3,0--6,1))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs new file mode 100644 index 00000000000..4d58841b1d6 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs @@ -0,0 +1,6 @@ +module Module + +async { + let! (res: int) = async { return 1 } + return res +} diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs.bsl new file mode 100644 index 00000000000..189efbc20c6 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 02.fs.bsl @@ -0,0 +1,38 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 02.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + LetOrUseBang + (Yes (4,4--4,40), false, true, + Paren + (Typed + (Named + (SynIdent (res, None), false, None, (4,10--4,13)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,10--4,18)), (4,9--4,19)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (4,37--4,38)), + (4,30--4,38), + { YieldOrReturnKeyword = (4,30--4,36) }), + (4,28--4,40)), (4,22--4,40)), [], + YieldOrReturn + ((false, true), Ident res, (5,4--5,14), + { YieldOrReturnKeyword = (5,4--5,10) }), (4,4--5,14), + { LetOrUseBangKeyword = (4,4--4,8) + EqualsRange = Some (4,20--4,21) }), (3,6--6,1)), + (3,0--6,1)), (3,0--6,1))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs new file mode 100644 index 00000000000..5c5e72047cc --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs @@ -0,0 +1,7 @@ +module Module + +async { + let (a: int, b: int) = 1, 3 + let! (c: int, d: int) = async { return 1, 3 } + return a + b + c + d +} diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs.bsl new file mode 100644 index 00000000000..ae8313afb7a --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 03.fs.bsl @@ -0,0 +1,125 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 03.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + LetOrUse + (false, false, + [SynBinding + (None, Normal, false, false, [], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + SynValData + (None, + SynValInfo ([], SynArgInfo ([], false, None)), + None), + Paren + (Tuple + (false, + [Typed + (Named + (SynIdent (a, None), false, None, + (4,9--4,10)), + LongIdent + (SynLongIdent ([int], [], [None])), + (4,9--4,15)); + Typed + (Named + (SynIdent (b, None), false, None, + (4,17--4,18)), + LongIdent + (SynLongIdent ([int], [], [None])), + (4,17--4,23))], [(4,15--4,16)], (4,9--4,23)), + (4,8--4,24)), None, + Tuple + (false, + [Const (Int32 1, (4,27--4,28)); + Const (Int32 3, (4,30--4,31))], [(4,28--4,29)], + (4,27--4,31)), (4,8--4,24), Yes (4,4--4,31), + { LeadingKeyword = Let (4,4--4,7) + InlineKeyword = None + EqualsRange = Some (4,25--4,26) })], + LetOrUseBang + (Yes (5,4--5,49), false, true, + Paren + (Tuple + (false, + [Typed + (Named + (SynIdent (c, None), false, None, + (5,10--5,11)), + LongIdent (SynLongIdent ([int], [], [None])), + (5,10--5,16)); + Typed + (Named + (SynIdent (d, None), false, None, + (5,18--5,19)), + LongIdent (SynLongIdent ([int], [], [None])), + (5,18--5,24))], [(5,16--5,17)], (5,10--5,24)), + (5,9--5,25)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), + Tuple + (false, + [Const (Int32 1, (5,43--5,44)); + Const (Int32 3, (5,46--5,47))], + [(5,44--5,45)], (5,43--5,47)), + (5,36--5,47), + { YieldOrReturnKeyword = (5,36--5,42) }), + (5,34--5,49)), (5,28--5,49)), [], + YieldOrReturn + ((false, true), + App + (NonAtomic, false, + App + (NonAtomic, true, + LongIdent + (false, + SynLongIdent + ([op_Addition], [], + [Some (OriginalNotation "+")]), None, + (6,21--6,22)), + App + (NonAtomic, false, + App + (NonAtomic, true, + LongIdent + (false, + SynLongIdent + ([op_Addition], [], + [Some (OriginalNotation "+")]), + None, (6,17--6,18)), + App + (NonAtomic, false, + App + (NonAtomic, true, + LongIdent + (false, + SynLongIdent + ([op_Addition], [], + [Some + (OriginalNotation "+")]), + None, (6,13--6,14)), Ident a, + (6,11--6,14)), Ident b, + (6,11--6,16)), (6,11--6,18)), + Ident c, (6,11--6,20)), (6,11--6,22)), + Ident d, (6,11--6,24)), (6,4--6,24), + { YieldOrReturnKeyword = (6,4--6,10) }), + (5,4--6,24), { LetOrUseBangKeyword = (5,4--5,8) + EqualsRange = Some (5,26--5,27) }), + (4,4--6,24), { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }), (3,6--7,1)), + (3,0--7,1)), (3,0--7,1))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--7,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs new file mode 100644 index 00000000000..2a1e0319849 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs @@ -0,0 +1,7 @@ +module Module + +async { + let a: int, b: int = 1, 3 + let! c: int, d: int = async { return 1, 3 } + return a + b + c + d +} \ No newline at end of file diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs.bsl new file mode 100644 index 00000000000..2c81842ee99 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 04.fs.bsl @@ -0,0 +1,51 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 04.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + Tuple + (false, + [LetOrUse + (false, false, + [SynBinding + (None, Normal, false, false, [], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + SynValData + (None, + SynValInfo ([], SynArgInfo ([], false, None)), + None), + Named + (SynIdent (a, None), false, None, (4,8--4,9)), + Some + (SynBindingReturnInfo + (LongIdent + (SynLongIdent ([int], [], [None])), + (4,11--4,14), [], + { ColonRange = Some (4,9--4,10) })), + Typed + (ArbitraryAfterError + ("localBinding2", (4,14--4,14)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,14--4,14)), (4,8--4,9), Yes (4,4--4,14), + { LeadingKeyword = Let (4,4--4,7) + InlineKeyword = None + EqualsRange = None })], + ArbitraryAfterError ("declExpr3", (5,15--5,16)), + (4,4--5,16), { LetOrUseKeyword = (4,4--4,7) + InKeyword = None }); Ident d], + [(5,15--5,16)], (4,4--5,18)), (3,6--5,47)), (3,0--5,47)), + (3,0--5,47))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--5,47), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(4,14)-(4,15) parse error Unexpected symbol ',' in binding. Expected '=' or other token. +(5,15)-(5,16) parse error Unexpected symbol ',' in expression. Expected '=' or other token. +(6,4)-(6,10) parse error Incomplete structured construct at or before this point in implementation file diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs new file mode 100644 index 00000000000..be48e42bb81 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs @@ -0,0 +1,3 @@ +module Module +let! x:int = async { return 1 } +let! (y:int) = async { return 2 } \ No newline at end of file diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl new file mode 100644 index 00000000000..e158175c57f --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl @@ -0,0 +1,47 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 05.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (LetOrUseBang + (Yes (2,0--2,31), false, true, + Typed + (Named (SynIdent (x, None), false, None, (2,5--2,6)), + LongIdent (SynLongIdent ([int], [], [None])), (2,5--2,10)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (2,28--2,29)), + (2,21--2,29), { YieldOrReturnKeyword = (2,21--2,27) }), + (2,19--2,31)), (2,13--2,31)), [], + LetOrUseBang + (Yes (3,0--3,33), false, true, + Paren + (Typed + (Named (SynIdent (y, None), false, None, (3,6--3,7)), + LongIdent (SynLongIdent ([int], [], [None])), + (3,6--3,11)), (3,5--3,12)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 2, (3,30--3,31)), + (3,23--3,31), + { YieldOrReturnKeyword = (3,23--3,29) }), + (3,21--3,33)), (3,15--3,33)), [], + ImplicitZero (3,33--3,33), (3,0--3,33), + { LetOrUseBangKeyword = (3,0--3,4) + EqualsRange = Some (3,13--3,14) }), (2,0--3,33), + { LetOrUseBangKeyword = (2,0--2,4) + EqualsRange = Some (2,11--2,12) }), (2,0--3,33))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,33), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(3,0)-(3,33) parse error Incomplete structured construct at or before this point in expression diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs new file mode 100644 index 00000000000..4dfb5dcf98a --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs @@ -0,0 +1,3 @@ +module Module +let! _:int = async { return 1 } +let! (_:int) = async { return 2 } \ No newline at end of file diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl new file mode 100644 index 00000000000..0bfa21aa1cd --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl @@ -0,0 +1,47 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed LetBang 06.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (LetOrUseBang + (Yes (2,0--2,31), false, true, + Typed + (Wild (2,5--2,6), + LongIdent (SynLongIdent ([int], [], [None])), (2,5--2,10)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (2,28--2,29)), + (2,21--2,29), { YieldOrReturnKeyword = (2,21--2,27) }), + (2,19--2,31)), (2,13--2,31)), [], + LetOrUseBang + (Yes (3,0--3,33), false, true, + Paren + (Typed + (Wild (3,6--3,7), + LongIdent (SynLongIdent ([int], [], [None])), + (3,6--3,11)), (3,5--3,12)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 2, (3,30--3,31)), + (3,23--3,31), + { YieldOrReturnKeyword = (3,23--3,29) }), + (3,21--3,33)), (3,15--3,33)), [], + ImplicitZero (3,33--3,33), (3,0--3,33), + { LetOrUseBangKeyword = (3,0--3,4) + EqualsRange = Some (3,13--3,14) }), (2,0--3,33), + { LetOrUseBangKeyword = (2,0--2,4) + EqualsRange = Some (2,11--2,12) }), (2,0--3,33))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,33), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(3,0)-(3,33) parse error Incomplete structured construct at or before this point in expression diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs b/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs new file mode 100644 index 00000000000..840c1678319 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs @@ -0,0 +1,6 @@ +module Module + +async { + use! res: int = async { return 1 } + return res +} diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs.bsl new file mode 100644 index 00000000000..c85105e4884 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 01.fs.bsl @@ -0,0 +1,36 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed UseBang 01.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + LetOrUseBang + (Yes (4,4--4,38), true, true, + Typed + (Named (SynIdent (res, None), false, None, (4,9--4,12)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,9--4,17)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (4,35--4,36)), + (4,28--4,36), + { YieldOrReturnKeyword = (4,28--4,34) }), + (4,26--4,38)), (4,20--4,38)), [], + YieldOrReturn + ((false, true), Ident res, (5,4--5,14), + { YieldOrReturnKeyword = (5,4--5,10) }), (4,4--5,14), + { LetOrUseBangKeyword = (4,4--4,8) + EqualsRange = Some (4,18--4,19) }), (3,6--6,1)), + (3,0--6,1)), (3,0--6,1))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs b/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs new file mode 100644 index 00000000000..cf1f75dc46c --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs @@ -0,0 +1,6 @@ +module Module + +async { + use! (res: int) = async { return 1 } + return res +} diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs.bsl new file mode 100644 index 00000000000..a28de2ddb58 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 02.fs.bsl @@ -0,0 +1,38 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed UseBang 02.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + LetOrUseBang + (Yes (4,4--4,40), true, true, + Paren + (Typed + (Named + (SynIdent (res, None), false, None, (4,10--4,13)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,10--4,18)), (4,9--4,19)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (4,37--4,38)), + (4,30--4,38), + { YieldOrReturnKeyword = (4,30--4,36) }), + (4,28--4,40)), (4,22--4,40)), [], + YieldOrReturn + ((false, true), Ident res, (5,4--5,14), + { YieldOrReturnKeyword = (5,4--5,10) }), (4,4--5,14), + { LetOrUseBangKeyword = (4,4--4,8) + EqualsRange = Some (4,20--4,21) }), (3,6--6,1)), + (3,0--6,1)), (3,0--6,1))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--6,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs new file mode 100644 index 00000000000..c0f2a3eb394 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs @@ -0,0 +1,4 @@ +module Module + +use! x:int = async { return 1 } +use! (y:int) = async { return 2 } \ No newline at end of file diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl new file mode 100644 index 00000000000..618f22920c4 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl @@ -0,0 +1,47 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed UseBang 03.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (LetOrUseBang + (Yes (3,0--3,31), true, true, + Typed + (Named (SynIdent (x, None), false, None, (3,5--3,6)), + LongIdent (SynLongIdent ([int], [], [None])), (3,5--3,10)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (3,28--3,29)), + (3,21--3,29), { YieldOrReturnKeyword = (3,21--3,27) }), + (3,19--3,31)), (3,13--3,31)), [], + LetOrUseBang + (Yes (4,0--4,33), true, true, + Paren + (Typed + (Named (SynIdent (y, None), false, None, (4,6--4,7)), + LongIdent (SynLongIdent ([int], [], [None])), + (4,6--4,11)), (4,5--4,12)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 2, (4,30--4,31)), + (4,23--4,31), + { YieldOrReturnKeyword = (4,23--4,29) }), + (4,21--4,33)), (4,15--4,33)), [], + ImplicitZero (4,33--4,33), (4,0--4,33), + { LetOrUseBangKeyword = (4,0--4,4) + EqualsRange = Some (4,13--4,14) }), (3,0--4,33), + { LetOrUseBangKeyword = (3,0--3,4) + EqualsRange = Some (3,11--3,12) }), (3,0--4,33))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,33), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(4,0)-(4,33) parse error Incomplete structured construct at or before this point in expression diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs new file mode 100644 index 00000000000..9ef3a6a3665 --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs @@ -0,0 +1,4 @@ +module Module + +use! _:int = async { return 1 } +use! (_:int) = async { return 2 } \ No newline at end of file diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl new file mode 100644 index 00000000000..6e406fbf91d --- /dev/null +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl @@ -0,0 +1,47 @@ +ImplFile + (ParsedImplFileInput + ("/root/SynType/Typed UseBang 04.fs", false, QualifiedNameOfFile Module, [], + [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (LetOrUseBang + (Yes (3,0--3,31), true, true, + Typed + (Wild (3,5--3,6), + LongIdent (SynLongIdent ([int], [], [None])), (3,5--3,10)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 1, (3,28--3,29)), + (3,21--3,29), { YieldOrReturnKeyword = (3,21--3,27) }), + (3,19--3,31)), (3,13--3,31)), [], + LetOrUseBang + (Yes (4,0--4,33), true, true, + Paren + (Typed + (Wild (4,6--4,7), + LongIdent (SynLongIdent ([int], [], [None])), + (4,6--4,11)), (4,5--4,12)), + App + (NonAtomic, false, Ident async, + ComputationExpr + (false, + YieldOrReturn + ((false, true), Const (Int32 2, (4,30--4,31)), + (4,23--4,31), + { YieldOrReturnKeyword = (4,23--4,29) }), + (4,21--4,33)), (4,15--4,33)), [], + ImplicitZero (4,33--4,33), (4,0--4,33), + { LetOrUseBangKeyword = (4,0--4,4) + EqualsRange = Some (4,13--4,14) }), (3,0--4,33), + { LetOrUseBangKeyword = (3,0--3,4) + EqualsRange = Some (3,11--3,12) }), (3,0--4,33))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,33), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(4,0)-(4,33) parse error Incomplete structured construct at or before this point in expression