Skip to content

Commit e6b6def

Browse files
authored
Fix parser recovery, name resolution, and code completion for unfinished enum patterns (#19708)
* Code completion/patterns: fix enum member completion * Release notes
1 parent 1874c88 commit e6b6def

30 files changed

Lines changed: 413 additions & 5 deletions

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
* Fix signature generation: type params with special characters missing backtick escaping. ([Issue #19595](https://github.com/dotnet/fsharp/issues/19595), [PR #19609](https://github.com/dotnet/fsharp/pull/19609))
5252
* Fix internal error when using custom attribute with `[<Optional>]` value type parameter and no `[<DefaultParameterValue>]`. ([Issue #8353](https://github.com/dotnet/fsharp/issues/8353), [PR #19484](https://github.com/dotnet/fsharp/pull/19484))
5353
* Fix parallel compilation of scripts ([PR #19649](https://github.com/dotnet/fsharp/pull/19649))
54+
* Fix parser recovery, name resolution, and code completion for unfinished enum patterns ([PR #19708](https://github.com/dotnet/fsharp/pull/19708))
5455
* Parser: fix unexpected diagnostics in debug builds, improve error messages ([PR #19730](https://github.com/dotnet/fsharp/pull/19730))
5556

5657
### Added

src/Compiler/Checking/NameResolution.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3531,7 +3531,7 @@ let rec ResolvePatternLongIdentPrim sink (ncenv: NameResolver) fullyQualified wa
35313531
match extraDotAtTheEnd with
35323532
| ExtraDotAfterIdentifier.Yes ->
35333533
match LookupTypeNameInEnvNoArity fullyQualified id.idText nenv with
3534-
| tcref :: _ when tcref.IsUnionTycon ->
3534+
| tcref :: _ when tcref.IsUnionTycon || tcref.IsEnumTycon ->
35353535
let res = ResolutionInfo.Empty.AddEntity (id.idRange, tcref)
35363536
ResolutionInfo.SendEntityPathToSink (sink, ncenv, nenv, ItemOccurrence.Pattern, ad, res, ResultTyparChecker(fun () -> true))
35373537
Item.Types (id.idText, [ mkWoNullAppTy tcref [] ])

src/Compiler/Service/FSharpCheckerResults.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ type internal TypeCheckInfo
904904
/// Is the item suitable for completion in a pattern
905905
let IsPatternCandidate (item: CompletionItem) =
906906
match item.Item with
907+
| Item.RecdField f -> f.Tycon.IsEnumTycon
907908
| Item.Value v -> v.LiteralValue.IsSome
908909
| Item.ILField field -> field.LiteralValue.IsSome
909910
| Item.ActivePatternCase _

src/Compiler/pars.fsy

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
241241

242242
/* start with lowest */
243243

244+
%nonassoc prec_atompat_pathop_error
244245
%nonassoc prec_args_error /* less than RPAREN */
245246
%nonassoc prec_atomexpr_lparen_error /* less than RPAREN */
246247

@@ -6934,6 +6935,11 @@ pathOp:
69346935
{ let ident, trivia = $1
69356936
SynLongIdent([ident], [], [Some trivia]) }
69366937

6938+
| ident DOT %prec prec_atompat_pathop_error
6939+
{ let mDot = rhs parseState 2
6940+
reportParseErrorAt mDot.EndRange (FSComp.SR.parsIdentifierExpected())
6941+
SynLongIdent([$1], [mDot], [None]) }
6942+
69376943
| ident DOT pathOp
69386944
{ prependIdentInLongIdentWithTrivia (SynIdent($1, None)) (rhs parseState 2) $3 }
69396945

tests/FSharp.Compiler.Service.Tests/CompletionTests.fs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,45 @@ module Module =
369369
"""
370370
assertHasNoItemsWithNames ["E"] info
371371

372+
[<Fact>]
373+
let ``Pattern - Enum 01`` () =
374+
let info =
375+
Checker.getCompletionInfo """
376+
namespace Ns1
377+
type E =
378+
| A = 1
379+
| B = 2
380+
381+
namespace Ns2
382+
383+
open Ns1
384+
385+
module M =
386+
match E.A with
387+
| E.{caret}
388+
"""
389+
assertHasItemWithNames ["A"] info
390+
391+
[<Fact>]
392+
let ``Pattern - Enum 02`` () =
393+
let info =
394+
Checker.getCompletionInfo """
395+
namespace Ns1
396+
type E =
397+
| A = 1
398+
| B = 2
399+
400+
namespace Ns2
401+
402+
open Ns1
403+
404+
module M =
405+
match E.A with
406+
| E.{caret}
407+
| E.B -> ()
408+
"""
409+
assertHasItemWithNames ["A"] info
410+
372411
#if NETCOREAPP
373412
[<Fact>]
374413
let ``Span appears in completion and is not marked obsolete`` () =

tests/FSharp.Compiler.Service.Tests/SyntaxTreeTests.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ let private sanitizeAST (sourceDirectoryValue: string) (ast: ParsedInput) : Pars
124124

125125
let parseSourceCode (name: string, code: string) =
126126
let location = Path.Combine(RootDirectory, name).Replace("\\", "/")
127+
Range.setTestSource location code
127128

128129
let parseResults =
129130
checker.ParseFile(
@@ -188,7 +189,10 @@ let ParseFile fileName =
188189
let equals = expected = actual
189190
let testUpdateBSLEnv = System.Environment.GetEnvironmentVariable("TEST_UPDATE_BSL")
190191

191-
if not (isNull testUpdateBSLEnv) && testUpdateBSLEnv.Trim() = "1" && not equals then
192+
let shouldUpdateBaseline =
193+
(not (isNull testUpdateBSLEnv) && testUpdateBSLEnv.Trim() = "1" && not equals)
194+
195+
if shouldUpdateBaseline then
192196
File.WriteAllText(bslPath, actual)
193197
elif not equals then
194198
File.WriteAllText(actualPath, actual)

tests/FSharp.Compiler.Service.Tests/TypeChecker/TypeCheckerRecoveryTests.fs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,76 @@ let o: obj = null
119119
if true then
120120
o.GetHashCode{caret}
121121
"""
122+
123+
module Patterns =
124+
[<Fact>]
125+
let ``Enum - Type 01`` () =
126+
assertHasSymbolUsageAtCaret "E" """
127+
type E =
128+
| A = 1
129+
130+
match E.A with
131+
| E{caret}.A -> ()
132+
"""
133+
134+
[<Fact>]
135+
let ``Enum - Type 02`` () =
136+
assertHasSymbolUsageAtCaret "E" """
137+
type E =
138+
| A = 1
139+
140+
match E.A with
141+
| E{caret} -> ()
142+
"""
143+
144+
[<Fact>]
145+
let ``Enum - Type 03`` () =
146+
assertHasSymbolUsageAtCaret "E" """
147+
type E =
148+
| A = 1
149+
150+
match E.A with
151+
| E{caret}
152+
"""
153+
154+
[<Fact>]
155+
let ``Enum - Type 04`` () =
156+
assertHasSymbolUsageAtCaret "E" """
157+
type E =
158+
| A = 1
159+
160+
match E.A with
161+
| E{caret}.
162+
"""
163+
164+
[<Fact>]
165+
let ``Enum - Type 05`` () =
166+
assertHasSymbolUsageAtCaret "E" """
167+
type E =
168+
| A = 1
169+
170+
match E.A with
171+
| E{caret}. -> ()
172+
"""
173+
174+
[<Fact(Skip = "Improve name resolution recovery")>]
175+
let ``Enum - Type 06`` () =
176+
assertHasSymbolUsageAtCaret "E" """
177+
type E =
178+
| A = 1
179+
180+
match E.A with
181+
| E{caret}.B
182+
"""
183+
184+
[<Fact>]
185+
let ``Enum - Type 07`` () =
186+
assertHasSymbolUsageAtCaret "E" """
187+
type E =
188+
| A = 1
189+
190+
match E.A with
191+
| E{caret}.
192+
193+
()
194+
"""

tests/service/data/SyntaxTree/Expression/Object - Class 13.fs.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ ImplFile
5858
WarnDirectives = []
5959
CodeComments = [] }, set []))
6060

61-
(4,18)-(5,5) parse error Incomplete structured construct at or before this point in object expression
61+
(4,17)-(4,17) parse error Identifier expected
6262
(4,18)-(5,5) parse error Expecting member body

tests/service/data/SyntaxTree/Member/Member 03.fs.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,5 +110,5 @@ ImplFile
110110
WarnDirectives = []
111111
CodeComments = [] }, set []))
112112

113-
(5,23)-(6,4) parse error Incomplete structured construct at or before this point in member definition
113+
(5,22)-(5,22) parse error Identifier expected
114114
(5,23)-(6,4) parse error Expecting member body

tests/service/data/SyntaxTree/Member/Member 07.fs.bsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,4 @@ ImplFile
109109
WarnDirectives = []
110110
CodeComments = [] }, set []))
111111

112-
(5,23)-(5,24) parse error Unexpected symbol '=' in member definition
112+
(5,22)-(5,22) parse error Identifier expected

0 commit comments

Comments
 (0)