Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser: recover on unfinished nested modules #15402

Merged
merged 3 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/Compiler/SyntaxTree/LexFilter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Context =
| CtxtTypeDefns of Position // 'type <here> =', not removed when we find the "="

| CtxtNamespaceHead of Position * token
| CtxtModuleHead of Position * token * LexingModuleAttributes
| CtxtModuleHead of Position * token * LexingModuleAttributes * isNested: bool
| CtxtMemberHead of Position
| CtxtMemberBody of Position
// If bool is true then this is "whole file"
Expand All @@ -68,7 +68,7 @@ type Context =

member c.StartPos =
match c with
| CtxtNamespaceHead (p, _) | CtxtModuleHead (p, _, _) | CtxtException p | CtxtModuleBody (p, _) | CtxtNamespaceBody p
| CtxtNamespaceHead (p, _) | CtxtModuleHead (p, _, _, _) | CtxtException p | CtxtModuleBody (p, _) | CtxtNamespaceBody p
| CtxtLetDecl (_, p) | CtxtDo p | CtxtInterfaceHead p | CtxtTypeDefns p | CtxtParen (_, p) | CtxtMemberHead p | CtxtMemberBody p
| CtxtWithAsLet p
| CtxtWithAsAugment p
Expand Down Expand Up @@ -1393,6 +1393,9 @@ type LexFilterImpl (
| CtxtSeqBlock(_, _, AddOneSidedBlockEnd) ->
Some (ORIGHT_BLOCK_END(getLastTokenEndRange ()))

| CtxtModuleHead(isNested = true) ->
Some OBLOCKSEP

| _ ->
None

Expand Down Expand Up @@ -1598,11 +1601,11 @@ type LexFilterImpl (
// Otherwise it's a 'head' module declaration, so ignore it

// Here prevToken is either 'module', 'rec', 'global' (invalid), '.', or ident, because we skip attribute tokens and access modifier tokens
| _, CtxtModuleHead (moduleTokenPos, prevToken, lexingModuleAttributes) :: rest ->
| _, CtxtModuleHead (moduleTokenPos, prevToken, lexingModuleAttributes, isNested) :: rest ->
match prevToken, token with
| _, GREATER_RBRACK when lexingModuleAttributes = LexingModuleAttributes
&& moduleTokenPos.Column < tokenStartPos.Column ->
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, NotLexingModuleAttributes))
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, NotLexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| _ when lexingModuleAttributes = LexingModuleAttributes
&& moduleTokenPos.Column < tokenStartPos.Column ->
Expand All @@ -1612,10 +1615,10 @@ type LexFilterImpl (
| MODULE, GLOBAL
| (MODULE | REC | DOT), (REC | IDENT _)
| IDENT _, DOT when moduleTokenPos.Column < tokenStartPos.Column ->
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, token, NotLexingModuleAttributes))
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, token, NotLexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| MODULE, LBRACK_LESS when moduleTokenPos.Column < tokenStartPos.Column ->
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, LexingModuleAttributes))
replaceCtxt tokenTup (CtxtModuleHead (moduleTokenPos, prevToken, LexingModuleAttributes, isNested))
returnToken tokenLexbufState token
| _, (EQUALS | COLON) ->
if debug then dprintf "CtxtModuleHead: COLON/EQUALS, pushing CtxtModuleBody and CtxtSeqBlock\n"
Expand Down Expand Up @@ -1643,7 +1646,7 @@ type LexFilterImpl (
// and we've encountered declarations below
if debug then dprintf "CtxtModuleHead: not start of file, popping CtxtModuleHead\n"
popCtxt()
reprocessWithoutBlockRule()
insertTokenFromPrevPosToCurrentPos OBLOCKSEP

// Offside rule for SeqBlock.
// f x
Expand Down Expand Up @@ -1972,7 +1975,8 @@ type LexFilterImpl (
| MODULE, _ :: _ ->
insertComingSoonTokens("MODULE", MODULE_COMING_SOON, MODULE_IS_HERE)
if debug then dprintf "MODULE: entering CtxtModuleHead, awaiting EQUALS to go to CtxtSeqBlock (%a)\n" outputPos tokenStartPos
pushCtxt tokenTup (CtxtModuleHead (tokenStartPos, token, NotLexingModuleAttributes))
let isNested = match offsideStack with | [ CtxtSeqBlock _ ] -> false | _ -> true
auduchinok marked this conversation as resolved.
Show resolved Hide resolved
pushCtxt tokenTup (CtxtModuleHead (tokenStartPos, token, NotLexingModuleAttributes, isNested))
pool.Return tokenTup
hwTokenFetch useBlockRule

Expand Down
6 changes: 6 additions & 0 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,12 @@ moduleIntro:
let mModule = rhs parseState 1
mModule, $4, $5.LongIdent, $3, $2 }

| moduleKeyword opt_attributes opt_access opt_rec OBLOCKSEP
{ if not (isNil $2) then
parseState.LexBuffer.CheckLanguageFeatureAndRecover LanguageFeature.AttributesToRightOfModuleKeyword (rhs parseState 4)
auduchinok marked this conversation as resolved.
Show resolved Hide resolved
let mModule = rhs parseState 1
mModule, $4, [], $3, $2 }


/* The start of a namespace declaration */
namespaceIntro:
Expand Down
2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg41.bsl
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

neg41.fs(3,1,3,5): parse error FS0010: Unexpected keyword 'type' in definition. Expected '=' or other token.
neg41.fs(2,20,3,1): parse error FS0010: Incomplete structured construct at or before this point in definition. Expected '=' or other token.
2 changes: 1 addition & 1 deletion tests/fsharp/typecheck/sigs/neg42.bsl
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

neg42.fsi(3,1,3,5): parse error FS0010: Unexpected keyword 'type' in signature file. Expected ':', '=' or other token.
neg42.fsi(2,20,3,1): parse error FS0010: Incomplete structured construct at or before this point in signature file. Expected ':', '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

module A

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 03.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,8)), false, [], false, (3,0--3,8),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None });
Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(3,9)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

module

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 04.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--5,0)), false, [], false, (3,0--5,0),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None });
Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(3,7)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

module rec

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 05.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--5,0)), true, [], false, (3,0--5,0),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None });
Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(3,11)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

module rec A

()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 06.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,12)), true, [], false, (3,0--3,12),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None });
Expr (Const (Unit, (5,0--5,2)), (5,0--5,2))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,2), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(3,13)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

module A =
module

2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 07.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,8)), false,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (4,4--6,0)), false, [], false, (4,4--6,0),
{ ModuleKeyword = Some (4,4--4,10)
EqualsRange = None })], false, (3,0--6,0),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = Some (3,9--3,10) });
Expr (Const (Int32 2, (6,0--6,1)), (6,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 []))

(6,0)-(6,1) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

module A =
module B

2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 08.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,8)), false,
[NestedModule
(SynComponentInfo
([], None, [], [B],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (4,4--4,12)), false, [], false, (4,4--4,12),
{ ModuleKeyword = Some (4,4--4,10)
EqualsRange = None });
Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
(3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
EqualsRange = Some (3,9--3,10) })],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,13)-(6,4) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

module A =
module B =

2
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 09.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,8)), false,
[NestedModule
(SynComponentInfo
([], None, [], [B],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (4,4--4,12)), false, [], false, (4,4--4,14),
{ ModuleKeyword = Some (4,4--4,10)
EqualsRange = Some (4,13--4,14) });
Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
(3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
EqualsRange = Some (3,9--3,10) })],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(6,4)-(6,5) parse error Possible incorrect indentation: this token is offside of context started at position (4:5). Try indenting this token further or using standard formatting conventions.
(6,4)-(6,5) parse error Incomplete structured construct at or before this point in definition
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Module

module A =
module

2
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 10.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [A],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--3,8)), false,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((4,4), FSharp.Compiler.Xml.XmlDocCollector),
false, None, (4,4--6,4)), false, [], false, (4,4--6,4),
{ ModuleKeyword = Some (4,4--4,10)
EqualsRange = None });
Expr (Const (Int32 2, (6,4--6,5)), (6,4--6,5))], false,
(3,0--6,5), { ModuleKeyword = Some (3,0--3,6)
EqualsRange = Some (3,9--3,10) })],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--6,5), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,11)-(6,4) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

module

A
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 11.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--5,0)), false, [], false, (3,0--5,0),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None }); Expr (Ident A, (5,0--5,1))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,1), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(3,7)-(5,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Module

module
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
ImplFile
(ParsedImplFileInput
("/root/ModuleOrNamespace/Nested module 12.fs", false,
QualifiedNameOfFile Module, [], [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[NestedModule
(SynComponentInfo
([], None, [], [],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector), false,
None, (3,0--4,0)), false, [], false, (3,0--4,0),
{ ModuleKeyword = Some (3,0--3,6)
EqualsRange = None })],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--4,0), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
CodeComments = [] }, set []))

(4,0)-(4,0) parse error Incomplete structured construct at or before this point in definition. Expected '=' or other token.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Module

module A
Loading