Skip to content

Commit b3a7e29

Browse files
authored
Don't crash graph checking on invalid syntax (#16588)
* Don't crash graph checking on invalid syntax * release note * Avoid crash due to cts disposal * f * Might as well fix this here * rename
1 parent dcf28e8 commit b3a7e29

File tree

5 files changed

+44
-22
lines changed

5 files changed

+44
-22
lines changed

docs/release-notes/.FSharp.Compiler.Service/8.0.300.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
* Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514))
44
* `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550))
5-
* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575))
5+
* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588))
66
* Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578))
77

88
### Added
99

10-
* The stackguard depth for ILPdbWriter.unshadowScopes can be modified via the environment variable `FSHARP_ILPdb_UnshadowScopes_StackGuardDepth`([PR #16583](https://github.com/dotnet/fsharp/pull/16583))
10+
* The stackguard depth for ILPdbWriter.unshadowScopes can be modified via the environment variable `FSHARP_ILPdb_UnshadowScopes_StackGuardDepth`([PR #16583](https://github.com/dotnet/fsharp/pull/16583))
1111
* Parser recovers on complex primary constructor patterns, better tree representation for primary constructor patterns. ([PR #16425](https://github.com/dotnet/fsharp/pull/16425))
1212
* Name resolution: keep type vars in subsequent checks ([PR #16456](https://github.com/dotnet/fsharp/pull/16456))
1313
* Higher-order-function-based API for working with the untyped abstract syntax tree. ([PR #16462](https://github.com/dotnet/fsharp/pull/16462))

src/Compiler/Driver/GraphChecking/FileContentMapping.fs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ type Continuations = ((FileContentEntry list -> FileContentEntry list) -> FileCo
99
let collectFromOption (mapping: 'T -> 'U list) (t: 'T option) : 'U list = List.collect mapping (Option.toList t)
1010

1111
let longIdentToPath (skipLast: bool) (longId: LongIdent) : LongIdentifier =
12-
if skipLast then
13-
List.take (longId.Length - 1) longId
14-
else
15-
longId
12+
match skipLast, longId with
13+
| true, _ :: _ -> List.take (longId.Length - 1) longId
14+
| _ -> longId
1615
|> List.map (fun ident -> ident.idText)
1716

1817
let synLongIdentToPath (skipLast: bool) (synLongIdent: SynLongIdent) =

src/Compiler/Driver/GraphChecking/GraphProcessing.fs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,12 @@ let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison>
230230

231231
let processedCount = IncrementableInt(0)
232232

233-
let raiseExn (item, ex: exn) =
234-
localCts.Cancel()
233+
let handleExn (item, ex: exn) =
234+
try
235+
localCts.Cancel()
236+
with :? ObjectDisposedException ->
237+
// If it's disposed already, it means that the processing has already finished, most likely due to cancellation or failure in another node.
238+
()
235239

236240
match ex with
237241
| :? OperationCanceledException -> completionSignal.TrySetCanceled()
@@ -252,7 +256,7 @@ let processGraphAsync<'Item, 'Result when 'Item: equality and 'Item: comparison>
252256

253257
match res with
254258
| Choice1Of2() -> ()
255-
| Choice2Of2 ex -> raiseExn (node.Info.Item, ex)
259+
| Choice2Of2 ex -> handleExn (node.Info.Item, ex)
256260
},
257261
cts.Token
258262
)

tests/FSharp.Compiler.ComponentTests/TypeChecks/Graph/FileContentMappingTests.fs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,36 @@ module B = C
122122
| [ TopLevelNamespace "" [ PrefixedIdentifier "C" ] ] -> Assert.Pass()
123123
| content -> Assert.Fail($"Unexpected content: {content}")
124124

125-
[<Test>]
126-
let ``Invalid nested module should just be ignored`` () =
127-
let content =
128-
getContent
129-
false
130-
"""
131-
module A
132125

133-
module B.C
134-
"""
126+
module InvalidSyntax =
135127

136-
match content with
137-
| [ TopLevelNamespace "" [] ] -> Assert.Pass()
138-
| content -> Assert.Fail($"Unexpected content: {content}")
128+
[<Test>]
129+
let ``Nested module`` () =
130+
let content =
131+
getContent
132+
false
133+
"""
134+
module A
135+
136+
module B.C
137+
"""
138+
139+
match content with
140+
| [ TopLevelNamespace "" [] ] -> Assert.Pass()
141+
| content -> Assert.Fail($"Unexpected content: {content}")
142+
143+
144+
[<Test>]
145+
let ``Module above namespace`` () =
146+
let content =
147+
getContent
148+
false
149+
"""
150+
module
151+
152+
namespace A.B.C
153+
"""
154+
155+
match content with
156+
| [ TopLevelNamespace "" [] ] -> Assert.Pass()
157+
| content -> Assert.Fail($"Unexpected content: {content}")

vsintegration/src/FSharp.Editor/LanguageService/WorkspaceExtensions.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ module private CheckerExtensions =
447447
) =
448448
cancellableTask {
449449

450-
if document.Project.UseTransparentCompiler then
450+
if checker.UsesTransparentCompiler then
451451
return! checker.ParseAndCheckDocumentUsingTransparentCompiler(document, options, userOpName)
452452
else
453453
let allowStaleResults =

0 commit comments

Comments
 (0)