From 3a58db9063ce16e826fd8262e84d839c8aa47aa0 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Fri, 26 Jul 2024 19:11:42 +0200 Subject: [PATCH 1/5] Parser: recover on missing union case fields --- src/Compiler/pars.fsy | 77 ++++++++++++++----- .../service/data/SyntaxTree/Type/Union 01.fs | 4 + .../data/SyntaxTree/Type/Union 01.fs.bsl | 26 +++++++ .../service/data/SyntaxTree/Type/Union 02.fs | 4 + .../data/SyntaxTree/Type/Union 02.fs.bsl | 41 ++++++++++ .../service/data/SyntaxTree/Type/Union 03.fs | 4 + .../data/SyntaxTree/Type/Union 03.fs.bsl | 43 +++++++++++ .../service/data/SyntaxTree/Type/Union 04.fs | 4 + .../data/SyntaxTree/Type/Union 04.fs.bsl | 50 ++++++++++++ .../service/data/SyntaxTree/Type/Union 05.fs | 4 + .../data/SyntaxTree/Type/Union 05.fs.bsl | 46 +++++++++++ .../service/data/SyntaxTree/Type/Union 06.fs | 4 + .../data/SyntaxTree/Type/Union 06.fs.bsl | 46 +++++++++++ 13 files changed, 333 insertions(+), 20 deletions(-) create mode 100644 tests/service/data/SyntaxTree/Type/Union 01.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 01.fs.bsl create mode 100644 tests/service/data/SyntaxTree/Type/Union 02.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 02.fs.bsl create mode 100644 tests/service/data/SyntaxTree/Type/Union 03.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 03.fs.bsl create mode 100644 tests/service/data/SyntaxTree/Type/Union 04.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 04.fs.bsl create mode 100644 tests/service/data/SyntaxTree/Type/Union 05.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 05.fs.bsl create mode 100644 tests/service/data/SyntaxTree/Type/Union 06.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 06.fs.bsl diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 9e19fec1c20..32fff353e99 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2711,17 +2711,26 @@ attrUnionCaseDecl: { fun (xmlDoc, mBar) -> mkSynUnionCase $1 $2 (SynIdent(mkSynId mBar.EndRange "", None)) (SynUnionCaseKind.Fields []) mBar (xmlDoc, mBar) |> Choice2Of2 } | opt_attributes opt_access unionCaseName OF unionCaseRepr - { mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.Fields $5) (rhs2 parseState 1 5) >> Choice2Of2 } + { let mId = rhs parseState 3 + let fields, mFields = $5 + let mWhole = unionRanges mId mFields + mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.Fields fields) mWhole >> Choice2Of2 } | opt_attributes opt_access unionCaseName unionCaseRepr { errorR (Error(FSComp.SR.parsMissingKeyword("of"), rhs2 parseState 3 4)) - mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.Fields $4) (rhs2 parseState 1 4) >> Choice2Of2 } + let mAttributes = rhs parseState 1 + let fields, mFields = $4 + let mWhole = unionRanges mAttributes mFields + mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.Fields fields) mWhole >> Choice2Of2 } | opt_attributes opt_access OF unionCaseRepr - { let mOf = rhs parseState 3 + { let mAttributes = rhs parseState 1 + let mOf = rhs parseState 3 let mId = mOf.StartRange + let fields, mFields = $4 + let mWhole = unionRanges mAttributes mFields errorR (Error(FSComp.SR.parsMissingUnionCaseName(), mOf)) - mkSynUnionCase $1 $2 (SynIdent(mkSynId mId "", None)) (SynUnionCaseKind.Fields $4) (rhs2 parseState 1 4) >> Choice2Of2 } + mkSynUnionCase $1 $2 (SynIdent(mkSynId mId "", None)) (SynUnionCaseKind.Fields fields) mWhole >> Choice2Of2 } | opt_attributes opt_access OF recover { let mOf = rhs parseState 3 @@ -2733,13 +2742,18 @@ attrUnionCaseDecl: { mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.Fields []) (rhs2 parseState 1 4) >> Choice2Of2 } | opt_attributes opt_access unionCaseName COLON topType - { if parseState.LexBuffer.ReportLibraryOnlyFeatures then libraryOnlyWarning(lhs parseState) - mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.FullType $5) (rhs2 parseState 1 5) >> Choice2Of2 } + { let mAttributes = rhs parseState 1 + let fullType, _ = $5 + let mWhole = unionRanges mAttributes fullType.Range + if parseState.LexBuffer.ReportLibraryOnlyFeatures then libraryOnlyWarning(lhs parseState) + mkSynUnionCase $1 $2 $3 (SynUnionCaseKind.FullType $5) mWhole >> Choice2Of2 } | opt_attributes opt_access unionCaseName EQUALS atomicExpr { if Option.isSome $2 then errorR(Error(FSComp.SR.parsEnumFieldsCannotHaveVisibilityDeclarations(), rhs parseState 2)) let mEquals = rhs parseState 4 - let mDecl = rhs2 parseState 1 5 + let mAttributes = rhs parseState 1 + let expr, _ = $5 + let mDecl = unionRanges mAttributes expr.Range (fun (xmlDoc, mBar) -> let trivia: SynEnumCaseTrivia = { BarRange = Some mBar; EqualsRange = mEquals } let mDecl = unionRangeWithXmlDoc xmlDoc mDecl @@ -2797,16 +2811,20 @@ firstUnionCaseDeclOfMany: firstUnionCaseDecl: | ident OF unionCaseRepr - { let trivia: SynUnionCaseTrivia = { BarRange = None } + { let fields, mFields = $3 + let trivia: SynUnionCaseTrivia = { BarRange = None } let xmlDoc = grabXmlDoc (parseState, [], 1) - let mDecl = rhs2 parseState 1 3 |> unionRangeWithXmlDoc xmlDoc - Choice2Of2(SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields $3, xmlDoc, None, mDecl, trivia)) } + let mId = rhs parseState 1 + let mDecl = unionRanges mId mFields |> unionRangeWithXmlDoc xmlDoc + Choice2Of2(SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields fields, xmlDoc, None, mDecl, trivia)) } - | unionCaseName COLON topType + | unionCaseName COLON topType { if parseState.LexBuffer.ReportLibraryOnlyFeatures then libraryOnlyWarning(lhs parseState) let trivia: SynUnionCaseTrivia = { BarRange = None } let xmlDoc = grabXmlDoc (parseState, [], 1) - let mDecl = rhs2 parseState 1 3 |> unionRangeWithXmlDoc xmlDoc + let mId = rhs parseState 1 + let fullType, _ = $3 + let mDecl = unionRanges mId fullType.Range |> unionRangeWithXmlDoc xmlDoc Choice2Of2(SynUnionCase([], $1, SynUnionCaseKind.FullType $3, xmlDoc, None, mDecl, trivia)) } | ident OF recover @@ -2818,18 +2836,21 @@ firstUnionCaseDecl: | OF unionCaseRepr { let mOf = rhs parseState 1 let mId = mOf.StartRange + let fields, mFields = $2 errorR (Error(FSComp.SR.parsMissingUnionCaseName(), mOf)) let id = SynIdent(mkSynId mId "", None) let trivia: SynUnionCaseTrivia = { BarRange = None } let xmlDoc = grabXmlDoc (parseState, [], 1) - let mDecl = rhs2 parseState 1 2 |> unionRangeWithXmlDoc xmlDoc - Choice2Of2(SynUnionCase([], id, SynUnionCaseKind.Fields $2, xmlDoc, None, mDecl, trivia)) } + let mDecl = unionRanges mOf mFields |> unionRangeWithXmlDoc xmlDoc + Choice2Of2(SynUnionCase([], id, SynUnionCaseKind.Fields fields, xmlDoc, None, mDecl, trivia)) } | ident EQUALS atomicExpr opt_OBLOCKSEP - { let mEquals = rhs parseState 2 + { let mId = rhs parseState 1 + let mEquals = rhs parseState 2 let trivia: SynEnumCaseTrivia = { BarRange = None; EqualsRange = mEquals } let xmlDoc = grabXmlDoc (parseState, [], 1) - let mDecl = rhs2 parseState 1 3 |> unionRangeWithXmlDoc xmlDoc + let expr, _ = $3 + let mDecl = unionRanges mId expr.Range |> unionRangeWithXmlDoc xmlDoc Choice1Of2(SynEnumCase([], SynIdent($1, None), fst $3, xmlDoc, mDecl, trivia)) } | ident EQUALS recover opt_OBLOCKSEP @@ -2843,10 +2864,25 @@ firstUnionCaseDecl: unionCaseReprElements: | unionCaseReprElement STAR unionCaseReprElements - { $1 :: $3 } + { let mField = rhs parseState 1 + let fields, mFields = $3 + $1 :: fields, unionRanges mField mFields } + + | unionCaseReprElement STAR recover + { let mStar = rhs parseState 2 + let ty = SynType.FromParseError mStar.EndRange + let field = mkSynAnonField (ty, PreXmlDoc.Empty) + [$1; field], rhs2 parseState 1 2 } + + | STAR unionCaseReprElements + { let mStar = rhs parseState 1 + let fields, mFields = $2 + let ty = SynType.FromParseError mStar.StartRange + let field = mkSynAnonField (ty, PreXmlDoc.Empty) + field :: fields, unionRanges mStar mFields } | unionCaseReprElement %prec prec_toptuptyptail_prefix - { [$1] } + { [$1], rhs parseState 1 } unionCaseReprElement: | ident COLON appTypeNullableInParens @@ -2872,7 +2908,7 @@ unionCaseReprElement: unionCaseRepr: | braceFieldDeclList { errorR(Deprecated(FSComp.SR.parsConsiderUsingSeparateRecordType(), lhs parseState)) - $1 } + $1, rhs parseState 1 } | unionCaseReprElements { $1 } @@ -2948,7 +2984,8 @@ exconIntro: { SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields [], PreXmlDoc.Empty, None, lhs parseState, { BarRange = None }) } | ident OF unionCaseRepr - { SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields $3, PreXmlDoc.Empty, None, lhs parseState, { BarRange = None }) } + { let fields, _ = $3 + SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields fields, PreXmlDoc.Empty, None, lhs parseState, { BarRange = None }) } | ident OF recover { SynUnionCase([], SynIdent($1, None), SynUnionCaseKind.Fields [], PreXmlDoc.Empty, None, lhs parseState, { BarRange = None }) } diff --git a/tests/service/data/SyntaxTree/Type/Union 01.fs b/tests/service/data/SyntaxTree/Type/Union 01.fs new file mode 100644 index 00000000000..ded50da8c59 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 01.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A diff --git a/tests/service/data/SyntaxTree/Type/Union 01.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 01.fs.bsl new file mode 100644 index 00000000000..d652bfba1e6 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 01.fs.bsl @@ -0,0 +1,26 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 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 [], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,7), { BarRange = Some (4,4--4,5) })], + (4,4--4,7)), (4,4--4,7)), [], None, (3,5--4,7), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,7))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,7), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Type/Union 02.fs b/tests/service/data/SyntaxTree/Type/Union 02.fs new file mode 100644 index 00000000000..2642c3aa9f7 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 02.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A of int * int diff --git a/tests/service/data/SyntaxTree/Type/Union 02.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 02.fs.bsl new file mode 100644 index 00000000000..55d2c0c07e6 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 02.fs.bsl @@ -0,0 +1,41 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 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, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,11--4,14), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,17), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,17--4,20), { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,20), { BarRange = Some (4,4--4,5) })], + (4,4--4,20)), (4,4--4,20)), [], None, (3,5--4,20), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,20))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,20), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Type/Union 03.fs b/tests/service/data/SyntaxTree/Type/Union 03.fs new file mode 100644 index 00000000000..65f7681501c --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 03.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A of int * diff --git a/tests/service/data/SyntaxTree/Type/Union 03.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 03.fs.bsl new file mode 100644 index 00000000000..2906039ff99 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 03.fs.bsl @@ -0,0 +1,43 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 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, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,11--4,14), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, FromParseError (4,16--4,16), + false, PreXmlDocEmpty, None, (4,16--4,16), + { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,16), { BarRange = Some (4,4--4,5) })], + (4,4--4,16)), (4,4--4,16)), [], None, (3,5--4,16), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,16))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,16), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(5,0)-(5,0) parse error Unexpected syntax or possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this further. +To continue using non-conforming indentation, pass the '--strict-indentation-' flag to the compiler, or set the language version to F# 7. +(5,0)-(5,0) parse error Incomplete structured construct at or before this point in union case diff --git a/tests/service/data/SyntaxTree/Type/Union 04.fs b/tests/service/data/SyntaxTree/Type/Union 04.fs new file mode 100644 index 00000000000..84494f97bef --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 04.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A of int * int * diff --git a/tests/service/data/SyntaxTree/Type/Union 04.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 04.fs.bsl new file mode 100644 index 00000000000..65be844f376 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 04.fs.bsl @@ -0,0 +1,50 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 04.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, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,11--4,14), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,17), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,17--4,20), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, FromParseError (4,22--4,22), + false, PreXmlDocEmpty, None, (4,22--4,22), + { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,22), { BarRange = Some (4,4--4,5) })], + (4,4--4,22)), (4,4--4,22)), [], None, (3,5--4,22), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,22))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,22), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(5,0)-(5,0) parse error Unexpected syntax or possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this further. +To continue using non-conforming indentation, pass the '--strict-indentation-' flag to the compiler, or set the language version to F# 7. +(5,0)-(5,0) parse error Incomplete structured construct at or before this point in union case diff --git a/tests/service/data/SyntaxTree/Type/Union 05.fs b/tests/service/data/SyntaxTree/Type/Union 05.fs new file mode 100644 index 00000000000..4cdd073d671 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 05.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A of int * * int diff --git a/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl new file mode 100644 index 00000000000..b0436900936 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl @@ -0,0 +1,46 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 05.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, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,11--4,14), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, FromParseError (4,17--4,17), + false, PreXmlDocEmpty, None, (4,17--4,17), + { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,19), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,19--4,22), { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,22), { BarRange = Some (4,4--4,5) })], + (4,4--4,22)), (4,4--4,22)), [], None, (3,5--4,22), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,22))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,22), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Type/Union 06.fs b/tests/service/data/SyntaxTree/Type/Union 06.fs new file mode 100644 index 00000000000..66bba9135ab --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 06.fs @@ -0,0 +1,4 @@ +module Module + +type U = + | A of * int * int diff --git a/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl new file mode 100644 index 00000000000..91e9590d638 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl @@ -0,0 +1,46 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 06.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, None, FromParseError (4,11--4,11), + false, PreXmlDocEmpty, None, (4,11--4,11), + { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,13), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,13--4,16), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,19), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,19--4,22), { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,22), { BarRange = Some (4,4--4,5) })], + (4,4--4,22)), (4,4--4,22)), [], None, (3,5--4,22), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--4,22))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--4,22), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) From 3a59ee0ce01c065cd6a1737960e99b22b9c50f40 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 30 Jul 2024 15:22:21 +0200 Subject: [PATCH 2/5] Add missing error --- src/Compiler/FSComp.txt | 3 ++- src/Compiler/pars.fsy | 3 ++- tests/service/data/SyntaxTree/Type/Union 05.fs.bsl | 2 ++ tests/service/data/SyntaxTree/Type/Union 06.fs.bsl | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index d98cfb61b97..62412a7698a 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1762,7 +1762,7 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [] di 3860,chkStaticMembersOnObjectExpressions,"Object expressions cannot implement interfaces with static abstract members or declare static members." 3861,chkTailCallAttrOnNonRec,"The TailCall attribute should only be applied to recursive functions." 3862,parsStaticMemberImcompleteSyntax,"Incomplete declaration of a static construct. Use 'static let','static do','static member' or 'static val' for declaration." -3863,parsExpectingField,"Expecting record field" +3863,parsExpectingRecordField,"Expecting record field" 3864,tooManyMethodsInDotNetTypeWritingAssembly,"The type '%s' has too many methods. Found: '%d', maximum: '%d'" 3865,parsOnlySimplePatternsAreAllowedInConstructors,"Only simple patterns are allowed in primary constructors" 3866,chkStaticAbstractInterfaceMembers,"A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.%s)." @@ -1775,3 +1775,4 @@ featureParsedHashDirectiveArgumentNonString,"# directives with non-quoted string 3869,featureParsedHashDirectiveUnexpectedInteger,"Unexpected integer literal '%d'." 3869,featureParsedHashDirectiveUnexpectedIdentifier,"Unexpected identifier '%s'." featureEmptyBodiedComputationExpressions,"Support for computation expressions with empty bodies: builder {{ }}" +3870,parsExpectingUnionCaseField,"Expecting union case field" diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 32fff353e99..24e876bd6a2 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2471,7 +2471,7 @@ braceFieldDeclList: { [] } | LBRACE rbrace - { errorR (Error(FSComp.SR.parsExpectingField(), rhs parseState 2)) + { errorR (Error(FSComp.SR.parsExpectingRecordField (), rhs parseState 2)) [] } anonRecdType: @@ -2876,6 +2876,7 @@ unionCaseReprElements: | STAR unionCaseReprElements { let mStar = rhs parseState 1 + errorR (Error(FSComp.SR.parsExpectingUnionCaseField (), rhs parseState 1)) let fields, mFields = $2 let ty = SynType.FromParseError mStar.StartRange let field = mkSynAnonField (ty, PreXmlDoc.Empty) diff --git a/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl index b0436900936..36eb5dae412 100644 --- a/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl +++ b/tests/service/data/SyntaxTree/Type/Union 05.fs.bsl @@ -44,3 +44,5 @@ ImplFile (1,0--4,22), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] CodeComments = [] }, set [])) + +(4,17)-(4,18) parse error Expecting union case field diff --git a/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl index 91e9590d638..90b09522783 100644 --- a/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl +++ b/tests/service/data/SyntaxTree/Type/Union 06.fs.bsl @@ -44,3 +44,5 @@ ImplFile (1,0--4,22), { LeadingKeyword = Module (1,0--1,6) })], (true, true), { ConditionalDirectives = [] CodeComments = [] }, set [])) + +(4,11)-(4,12) parse error Expecting union case field From 686a8073d4e051eb3f41fc7fc3c63661f3680a9f Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 30 Jul 2024 15:22:32 +0200 Subject: [PATCH 3/5] Add another test --- .../service/data/SyntaxTree/Type/Union 07.fs | 5 +++ .../data/SyntaxTree/Type/Union 07.fs.bsl | 45 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/service/data/SyntaxTree/Type/Union 07.fs create mode 100644 tests/service/data/SyntaxTree/Type/Union 07.fs.bsl diff --git a/tests/service/data/SyntaxTree/Type/Union 07.fs b/tests/service/data/SyntaxTree/Type/Union 07.fs new file mode 100644 index 00000000000..096dc43834c --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 07.fs @@ -0,0 +1,5 @@ +module Module + +type U = + | A of int * + | B diff --git a/tests/service/data/SyntaxTree/Type/Union 07.fs.bsl b/tests/service/data/SyntaxTree/Type/Union 07.fs.bsl new file mode 100644 index 00000000000..2f0f76e6131 --- /dev/null +++ b/tests/service/data/SyntaxTree/Type/Union 07.fs.bsl @@ -0,0 +1,45 @@ +ImplFile + (ParsedImplFileInput + ("/root/Type/Union 07.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, None, + LongIdent (SynLongIdent ([int], [], [None])), + false, + PreXmlDoc ((4,11), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,11--4,14), { LeadingKeyword = None + MutableKeyword = None }); + SynField + ([], false, None, FromParseError (4,16--4,16), + false, PreXmlDocEmpty, None, (4,16--4,16), + { LeadingKeyword = None + MutableKeyword = None })], + PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (4,6--4,16), { BarRange = Some (4,4--4,5) }); + SynUnionCase + ([], SynIdent (B, None), Fields [], + PreXmlDoc ((5,4), FSharp.Compiler.Xml.XmlDocCollector), + None, (5,6--5,7), { BarRange = Some (5,4--5,5) })], + (4,4--5,7)), (4,4--5,7)), [], None, (3,5--5,7), + { LeadingKeyword = Type (3,0--3,4) + EqualsRange = Some (3,7--3,8) + WithKeyword = None })], (3,0--5,7))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--5,7), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) + +(5,4)-(5,5) parse error Unexpected symbol '|' in union case From 2c93f9e2793671c4495f31d9fd4aebbd0f28f65a Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Fri, 26 Jul 2024 21:43:31 +0200 Subject: [PATCH 4/5] Release notes --- docs/release-notes/.FSharp.Compiler.Service/9.0.100.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index 172d864ed76..c4496adae3c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -9,6 +9,7 @@ ### 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)) * Sink: report function domain type ([PR #17470](https://github.com/dotnet/fsharp/pull/17470)) ### Changed From 4ea778e890b897a1728b9738aa1022c351186899 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 30 Jul 2024 15:39:52 +0200 Subject: [PATCH 5/5] Update xlf --- src/Compiler/xlf/FSComp.txt.cs.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.de.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.es.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.fr.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.it.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.ja.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.ko.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.pl.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.ru.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.tr.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 15 ++++++++++----- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 15 ++++++++++----- 13 files changed, 130 insertions(+), 65 deletions(-) diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 2d6569495fb..dc578af9a99 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1007,21 +1007,26 @@ Byl očekáván výraz. - - Expecting record field - Očekává se pole záznamu. - - Expecting pattern Očekává se vzorek. + + Expecting record field + Expecting record field + + Expecting type Očekává se typ + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Neúplný znakový literál (příklad: Q) nebo volání kvalifikovaného typu (příklad: T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 05412ee34ff..0d5007fed66 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1007,21 +1007,26 @@ Ausdruck wird erwartet - - Expecting record field - Datensatzfeld wird erwartet - - Expecting pattern Muster wird erwartet + + Expecting record field + Expecting record field + + Expecting type Typ wird erwartet + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Unvollständiges Zeichenliteral (Beispiel: „Q“) oder qualifizierter Typaufruf (Beispiel: „T.Name“) diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index fc01995a3e7..eee3b33c5c9 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1007,21 +1007,26 @@ Se espera una expresión - - Expecting record field - Se espera un campo de registro - - Expecting pattern Se espera un patrón + + Expecting record field + Expecting record field + + Expecting type Tipo esperado + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Literal de carácter incompleto (ejemplo: 'Q') o invocación de tipo completo (ejemplo: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 0210d676034..37b8637fac1 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1007,21 +1007,26 @@ Expression attendue - - Expecting record field - Champ d’enregistrement attendu - - Expecting pattern Modèle attendu + + Expecting record field + Expecting record field + + Expecting type Type attendu + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Littéral de caractère incomplet (exemple : 'Q') ou appel de type qualifié (exemple : 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 09fc8de5a9a..45f773a03e8 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1007,21 +1007,26 @@ Prevista espressione. - - Expecting record field - Previsto campo record - - Expecting pattern Criterio previsto + + Expecting record field + Expecting record field + + Expecting type Previsto tipo + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Valore letterale carattere incompleto (ad esempio: 'Q') o chiamata di tipo qualificato (ad esempio: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index e9a86b84566..c4b21520176 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1007,21 +1007,26 @@ 式を指定してください - - Expecting record field - レコード フィールドが必要です - - Expecting pattern 必要なパターン + + Expecting record field + Expecting record field + + Expecting type 型が必要です + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) 不完全な文字リテラル (例: 'Q') または修飾型の呼び出し (例: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 8133d0bd01e..00d19be0919 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1007,21 +1007,26 @@ 식이 필요함 - - Expecting record field - 레코드 필드 필요 - - Expecting pattern 예상되는 패턴 + + Expecting record field + Expecting record field + + Expecting type 예상 형식 + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) 불완전한 문자 리터럴(예: 'Q') 또는 정규화된 형식 호출(예: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 626ead02352..f9f8d75e2c0 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1007,21 +1007,26 @@ Oczekiwanie na wyrażenie - - Expecting record field - Oczekiwanie pola rekordu - - Expecting pattern Oczekiwano wzorca + + Expecting record field + Expecting record field + + Expecting type Oczekiwano typu + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Niekompletny literał znaku (przykład: „Q”) lub wywołanie typu kwalifikowanego (przykład: „T.Name”) diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 06620eb856c..b6ecb582a3d 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1007,21 +1007,26 @@ Esperando uma expressão - - Expecting record field - Esperando campo de registro - - Expecting pattern Padrão esperado + + Expecting record field + Expecting record field + + Expecting type Esperando tipo + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Literal de caractere incompleto (exemplo: 'Q') ou invocação de tipo qualificado (exemplo: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 722b02ce15f..a55d1afade8 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1007,21 +1007,26 @@ Ожидается выражение - - Expecting record field - Ожидается поле записи - - Expecting pattern Ожидается шаблон + + Expecting record field + Expecting record field + + Expecting type Требуется тип + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Неполный символьный литерал (например: "Q") или вызов квалифицированного типа (например: "T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 12f8cfeeb77..da224bfc0ee 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1007,21 +1007,26 @@ İfade bekleniyor - - Expecting record field - Kayıt alanı bekleniyor - - Expecting pattern Desen bekleniyor + + Expecting record field + Expecting record field + + Expecting type Tür bekleniyor + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) Eksik karakter değişmez değeri (örnek: 'Q') veya tam tür çağrısı (örnek: 'T.Name) diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index caca4c82014..26b945a8541 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1007,21 +1007,26 @@ 应为表达式 - - Expecting record field - 应为记录字段 - - Expecting pattern 预期模式 + + Expecting record field + Expecting record field + + Expecting type 预期类型 + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) 字符文本不完整(示例: "Q")或限定类型调用(示例: "T.Name") diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index fe208053fc5..16d8255e6aa 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1007,21 +1007,26 @@ 必須是運算式 - - Expecting record field - 必須是記錄欄位 - - Expecting pattern 必須是模式 + + Expecting record field + Expecting record field + + Expecting type 必須是類型 + + Expecting union case field + Expecting union case field + + Incomplete character literal (example: 'Q') or qualified type invocation (example: 'T.Name) 不完整的字元文字 (範例: 'Q') 或限定類型調用 (範例: 'T.Name)