Skip to content

Commit

Permalink
Parser: recover on missing union case field types (#17455)
Browse files Browse the repository at this point in the history
* Parser: recover on missing union case field types

* Release notes
  • Loading branch information
auduchinok authored Aug 2, 2024
1 parent d2d38e3 commit d8e2f21
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 9 deletions.
3 changes: 2 additions & 1 deletion docs/release-notes/.FSharp.Compiler.Service/9.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
### Added

* Support for nullable reference types ([PR #15181](https://github.com/dotnet/fsharp/pull/15181))
* Parser: recover on missing union case fields ([#17452](https://github.com/dotnet/fsharp/pull/17452))
* Parser: recover on missing union case fields (PR [#17452](https://github.com/dotnet/fsharp/pull/17452))
* Parser: recover on missing union case field types (PR [#17455](https://github.com/dotnet/fsharp/pull/17455))
* Sink: report function domain type ([PR #17470](https://github.com/dotnet/fsharp/pull/17470))

### Changed
Expand Down
28 changes: 20 additions & 8 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ let parse_error_rich = Some(fun (ctxt: ParseErrorContext<_>) ->
%type <SynExpr> argExpr
%type <SynExpr> declExprBlock
%type <SynPat> headBindingPattern
%type <SynType> appTypeNullableInParens
%type <SynType> atomTypeNonAtomicDeprecated
%type <SynExpr> atomicExprAfterType
%type <SynExpr> typedSequentialExprBlock
Expand Down Expand Up @@ -2883,27 +2884,35 @@ unionCaseReprElements:
field :: fields, unionRanges mStar mFields }

| unionCaseReprElement %prec prec_toptuptyptail_prefix
{ [$1], rhs parseState 1 }
{ [$1], $1.Range }

unionCaseReprElement:
| ident COLON appTypeNullableInParens
{ let xmlDoc = grabXmlDoc(parseState, [], 1)
let mWhole = rhs2 parseState 1 3 |> unionRangeWithXmlDoc xmlDoc
{ let xmlDoc = grabXmlDoc (parseState, [], 1)
let mId = rhs parseState 1
let mWhole = unionRanges mId $3.Range |> unionRangeWithXmlDoc xmlDoc
mkSynNamedField ($1, $3, xmlDoc, mWhole) }

| ident COLON recover
{ let xmlDoc = grabXmlDoc (parseState, [], 1)
let mColon = rhs parseState 2
let ty = SynType.FromParseError mColon.EndRange
let mWhole = rhs2 parseState 1 2 |> unionRangeWithXmlDoc xmlDoc
mkSynNamedField ($1, ty, xmlDoc, mWhole) }

| appTypeNullableInParens
{ let xmlDoc = grabXmlDoc(parseState, [], 1)
{ let xmlDoc = grabXmlDoc (parseState, [], 1)
mkSynAnonField ($1, xmlDoc) }

| ident COLON invalidUseOfAppTypeFunction
{ let xmlDoc = grabXmlDoc(parseState, [], 1)
{ let xmlDoc = grabXmlDoc (parseState, [], 1)
let mWhole = rhs2 parseState 1 3 |> unionRangeWithXmlDoc xmlDoc
reportParseErrorAt ($3 : SynType).Range (FSComp.SR.tcUnexpectedFunTypeInUnionCaseField())
reportParseErrorAt ($3: SynType).Range (FSComp.SR.tcUnexpectedFunTypeInUnionCaseField ())
mkSynNamedField ($1, $3, xmlDoc, mWhole) }

| invalidUseOfAppTypeFunction
{ let xmlDoc = grabXmlDoc(parseState, [], 1)
reportParseErrorAt ($1 : SynType).Range (FSComp.SR.tcUnexpectedFunTypeInUnionCaseField())
{ let xmlDoc = grabXmlDoc (parseState, [], 1)
reportParseErrorAt ($1: SynType).Range (FSComp.SR.tcUnexpectedFunTypeInUnionCaseField ())
mkSynAnonField ($1, xmlDoc) }

unionCaseRepr:
Expand Down Expand Up @@ -5981,11 +5990,13 @@ invalidUseOfAppTypeFunction:
{ let mArrow = rhs parseState 2
let m = unionRanges (rhs2 parseState 1 2) $3.Range
SynType.Fun($1, $3, m, { ArrowRange = mArrow }) }

| appTypeWithoutNull RARROW recover
{ let mArrow = rhs parseState 2
let ty = SynType.FromParseError(mArrow.EndRange)
let m = rhs2 parseState 1 2
SynType.Fun($1, ty, m, { ArrowRange = mArrow }) }

| appTypeWithoutNull RARROW RARROW invalidUseOfAppTypeFunction
{ let mArrow1 = rhs parseState 2
let mArrow2 = rhs parseState 3
Expand All @@ -5994,6 +6005,7 @@ invalidUseOfAppTypeFunction:
let m1 = unionRanges $1.Range $4.Range
let m2 = unionRanges mArrow2 $4.Range
SynType.Fun($1, SynType.Fun(ty, $4, m2, { ArrowRange = mArrow2 }), m1, { ArrowRange = mArrow1 }) }

| appTypeWithoutNull RARROW appTypeWithoutNull
{ let mArrow = rhs parseState 2
let m = rhs2 parseState 1 3
Expand Down
4 changes: 4 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 01.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Module

type U =
| A of i: int
35 changes: 35 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 01.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ImplFile
(ParsedImplFileInput
("/root/Type/Union - Field 01.fs", false, QualifiedNameOfFile Module, [],
[],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [U],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
Simple
(Union
(None,
[SynUnionCase
([], SynIdent (A, None),
Fields
[SynField
([], false, Some i,
LongIdent (SynLongIdent ([int], [], [None])),
false,
PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,11--4,17), { LeadingKeyword = None
MutableKeyword = None })],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,6--4,17), { BarRange = Some (4,4--4,5) })],
(4,4--4,17)), (4,4--4,17)), [], None, (3,5--4,17),
{ LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,17))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--4,17), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))
4 changes: 4 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 02.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Module

type U =
| A of i:
36 changes: 36 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 02.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ImplFile
(ParsedImplFileInput
("/root/Type/Union - Field 02.fs", false, QualifiedNameOfFile Module, [],
[],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [U],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
Simple
(Union
(None,
[SynUnionCase
([], SynIdent (A, None),
Fields
[SynField
([], false, Some i, FromParseError (4,13--4,13),
false,
PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,11--4,13), { LeadingKeyword = None
MutableKeyword = None })],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,6--4,13), { BarRange = Some (4,4--4,5) })],
(4,4--4,13)), (4,4--4,13)), [], None, (3,5--4,13),
{ LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,13))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--4,13), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(5,0)-(5,0) parse error Incomplete structured construct at or before this point in union case
4 changes: 4 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 03.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Module

type U =
| A of i: * int
43 changes: 43 additions & 0 deletions tests/service/data/SyntaxTree/Type/Union - Field 03.fs.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
ImplFile
(ParsedImplFileInput
("/root/Type/Union - Field 03.fs", false, QualifiedNameOfFile Module, [],
[],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Types
([SynTypeDefn
(SynComponentInfo
([], None, [], [U],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (3,5--3,6)),
Simple
(Union
(None,
[SynUnionCase
([], SynIdent (A, None),
Fields
[SynField
([], false, Some i, FromParseError (4,13--4,13),
false,
PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,11--4,13), { LeadingKeyword = None
MutableKeyword = None });
SynField
([], false, None,
LongIdent (SynLongIdent ([int], [], [None])),
false,
PreXmlDoc ((4,16), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,16--4,19), { LeadingKeyword = None
MutableKeyword = None })],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
None, (4,6--4,19), { BarRange = Some (4,4--4,5) })],
(4,4--4,19)), (4,4--4,19)), [], None, (3,5--4,19),
{ LeadingKeyword = Type (3,0--3,4)
EqualsRange = Some (3,7--3,8)
WithKeyword = None })], (3,0--4,19))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--4,19), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,14)-(4,15) parse error Unexpected symbol '*' in union case

0 comments on commit d8e2f21

Please sign in to comment.