diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 9181c5902b7..1a91f439a7e 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -3732,22 +3732,22 @@ declExpr: $3 $2 mIf false } | IF declExpr recover %prec expr_if - { reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsIncompleteIf()) - // Produce an approximate expression during error recovery. - // Include expressions to make sure they get type checked in case that generates useful results for intellisense. - // Generate a throwAway for the expression so it isn't forced to have a type 'bool' - // from the context it is used in. - exprFromParseError $2 } + { errorR (Error(FSComp.SR.parsIncompleteIf (), rhs parseState 1)) + let ifExpr = $2 + let mIf = rhs parseState 1 + let mThen = ifExpr.Range.EndRange + let m = unionRanges mIf mThen + let spIfToThen = DebugPointAtBinding.Yes m + let trivia = { IfKeyword = mIf; IsElif = false; ThenKeyword = mThen; ElseKeyword = None; IfToThenRange = m } + SynExpr.IfThenElse($2, arbExpr ("if1", mThen), None, spIfToThen, true, m, trivia) } | IF recover %prec expr_if - { reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsIncompleteIf()) - // Produce an approximate expression during error recovery. There can still be value in doing this even - // for this pathological case. + { errorR (Error(FSComp.SR.parsIncompleteIf (), rhs parseState 1)) let m = rhs parseState 1 let mEnd = m.EndRange let spIfToThen = DebugPointAtBinding.Yes mEnd let trivia = { IfKeyword = m; IsElif = false; ThenKeyword = m; ElseKeyword = None; IfToThenRange = m } - exprFromParseError (SynExpr.IfThenElse(arbExpr ("ifGuard1", mEnd), arbExpr ("thenBody1", mEnd), None, spIfToThen, true, m, trivia)) } + SynExpr.IfThenElse(arbExpr ("if2", mEnd), arbExpr ("if3", mEnd), None, spIfToThen, true, m, trivia) } | LAZY declExpr %prec expr_lazy { SynExpr.Lazy($2, unionRanges (rhs parseState 1) $2.Range) } @@ -4318,6 +4318,10 @@ ifExprThen: | THEN declExpr %prec prec_then_if { $2, rhs parseState 1 } + | THEN recover %prec prec_then_if + { let mThen = rhs parseState 1 + arbExpr ("ifThen1", mThen.EndRange), mThen } + | OTHEN OBLOCKBEGIN typedSequentialExpr oblockend %prec prec_then_if { $3, rhs parseState 1 } @@ -4325,6 +4329,14 @@ ifExprThen: { if not $4 then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedEndOfFileThen()) exprFromParseError $3, rhs parseState 1 } + | OTHEN recover %prec prec_then_if + { let mThen = rhs parseState 1 + arbExpr ("ifThen2", mThen.EndRange), mThen } + + | OTHEN OBLOCKBEGIN recover %prec prec_then_if + { let mThen = rhs parseState 1 + arbExpr ("ifThen3", mThen.EndRange), mThen } + ifExprElifs: | /* EMPTY */ { None, None } diff --git a/src/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj b/src/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj index 32843bd4b13..890d9970bda 100644 --- a/src/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj +++ b/src/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj @@ -34,8 +34,12 @@ - - + + + + + + diff --git a/tests/service/data/SyntaxTree/Expression/If 01.fs b/tests/service/data/SyntaxTree/Expression/If 01.fs new file mode 100644 index 00000000000..86b77fcba53 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 01.fs @@ -0,0 +1,3 @@ +module Module + +if true then () diff --git a/tests/service/data/SyntaxTree/Expression/If 01.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 01.fs.bsl new file mode 100644 index 00000000000..775d6d7764d --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 01.fs.bsl @@ -0,0 +1,18 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 01.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (Const (Bool true, (3,3--3,7)), Const (Unit, (3,13--3,15)), None, + Yes (3,0--3,12), false, (3,0--3,15), + { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,8--3,12) + ElseKeyword = None + IfToThenRange = (3,0--3,12) }), (3,0--3,15))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,15), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/If 02.fs b/tests/service/data/SyntaxTree/Expression/If 02.fs new file mode 100644 index 00000000000..b3469780ecf --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 02.fs @@ -0,0 +1,3 @@ +module Module + +if true then () else () diff --git a/tests/service/data/SyntaxTree/Expression/If 02.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 02.fs.bsl new file mode 100644 index 00000000000..8f026aa409e --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 02.fs.bsl @@ -0,0 +1,18 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 02.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (Const (Bool true, (3,3--3,7)), Const (Unit, (3,13--3,15)), + Some (Const (Unit, (3,21--3,23))), Yes (3,0--3,12), false, + (3,0--3,23), { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,8--3,12) + ElseKeyword = Some (3,16--3,20) + IfToThenRange = (3,0--3,12) }), (3,0--3,23))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,23), { LeadingKeyword = Module (1,0--1,6) })], (true, true), + { ConditionalDirectives = [] + CodeComments = [] }, set [])) diff --git a/tests/service/data/SyntaxTree/Expression/If 03.fs b/tests/service/data/SyntaxTree/Expression/If 03.fs new file mode 100644 index 00000000000..c4e674eb652 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 03.fs @@ -0,0 +1,5 @@ +module Module + +if true + +() diff --git a/tests/service/data/SyntaxTree/Expression/If 03.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 03.fs.bsl new file mode 100644 index 00000000000..c68682f6f59 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 03.fs.bsl @@ -0,0 +1,22 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 03.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (Const (Bool true, (3,3--3,7)), + ArbitraryAfterError ("if1", (3,7--3,7)), None, Yes (3,0--3,7), + true, (3,0--3,7), { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,7--3,7) + ElseKeyword = None + IfToThenRange = (3,0--3,7) }), (3,0--3,7)); + 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,8)-(5,0) parse error Incomplete structured construct at or before this point in expression +(3,0)-(3,2) parse error Incomplete conditional. Expected 'if then ' or 'if then else '. diff --git a/tests/service/data/SyntaxTree/Expression/If 04.fs b/tests/service/data/SyntaxTree/Expression/If 04.fs new file mode 100644 index 00000000000..c6b2c4efb97 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 04.fs @@ -0,0 +1,5 @@ +module Module + +if + +() diff --git a/tests/service/data/SyntaxTree/Expression/If 04.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 04.fs.bsl new file mode 100644 index 00000000000..99ffbe73e73 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 04.fs.bsl @@ -0,0 +1,22 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 04.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (ArbitraryAfterError ("if2", (3,2--3,2)), + ArbitraryAfterError ("if3", (3,2--3,2)), None, Yes (3,2--3,2), + true, (3,0--3,2), { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,0--3,2) + ElseKeyword = None + IfToThenRange = (3,0--3,2) }), (3,0--3,2)); + 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,3)-(5,0) parse error Incomplete structured construct at or before this point in expression +(3,0)-(3,2) parse error Incomplete conditional. Expected 'if then ' or 'if then else '. diff --git a/tests/service/data/SyntaxTree/Expression/If 05.fs b/tests/service/data/SyntaxTree/Expression/If 05.fs new file mode 100644 index 00000000000..0b88a06a265 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 05.fs @@ -0,0 +1,5 @@ +module Module + +if true then + +() diff --git a/tests/service/data/SyntaxTree/Expression/If 05.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 05.fs.bsl new file mode 100644 index 00000000000..b04b2f73abb --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 05.fs.bsl @@ -0,0 +1,21 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 05.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (Const (Bool true, (3,3--3,7)), Const (Unit, (5,0--5,2)), None, + Yes (3,0--3,12), false, (3,0--5,2), + { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,8--3,12) + ElseKeyword = None + IfToThenRange = (3,0--3,12) }), (3,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 [])) + +(5,0)-(5,1) parse warning Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions. +(5,0)-(5,1) parse warning Possible incorrect indentation: this token is offside of context started at position (3:1). Try indenting this token further or using standard formatting conventions. diff --git a/tests/service/data/SyntaxTree/Expression/If 06.fs b/tests/service/data/SyntaxTree/Expression/If 06.fs new file mode 100644 index 00000000000..f64f0dbb72b --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 06.fs @@ -0,0 +1,6 @@ +module Module + +do + if true then + +open global diff --git a/tests/service/data/SyntaxTree/Expression/If 06.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 06.fs.bsl new file mode 100644 index 00000000000..9eb34c95351 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 06.fs.bsl @@ -0,0 +1,26 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 06.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (Do + (IfThenElse + (Const (Bool true, (4,7--4,11)), + ArbitraryAfterError ("ifThen3", (4,16--4,16)), None, + Yes (4,4--4,16), false, (4,4--4,16), + { IfKeyword = (4,4--4,6) + IsElif = false + ThenKeyword = (4,12--4,16) + ElseKeyword = None + IfToThenRange = (4,4--4,16) }), (3,0--4,16)), (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 [])) + +(6,0)-(6,4) parse warning 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,0)-(6,4) parse warning 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,0)-(6,4) parse error Unexpected keyword 'open' in if/then/else expression +(7,0)-(7,0) parse error Incomplete structured construct at or before this point in definition. Expected incomplete structured construct at or before this point or other token. +(7,0)-(7,0) parse error Incomplete structured construct at or before this point in implementation file diff --git a/tests/service/data/SyntaxTree/Expression/If 07.fs b/tests/service/data/SyntaxTree/Expression/If 07.fs new file mode 100644 index 00000000000..24fef65f330 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 07.fs @@ -0,0 +1,3 @@ +module Module + +if diff --git a/tests/service/data/SyntaxTree/Expression/If 07.fs.bsl b/tests/service/data/SyntaxTree/Expression/If 07.fs.bsl new file mode 100644 index 00000000000..d4d53023ff8 --- /dev/null +++ b/tests/service/data/SyntaxTree/Expression/If 07.fs.bsl @@ -0,0 +1,21 @@ +ImplFile + (ParsedImplFileInput + ("/root/Expression/If 07.fs", false, QualifiedNameOfFile Module, [], [], + [SynModuleOrNamespace + ([Module], false, NamedModule, + [Expr + (IfThenElse + (ArbitraryAfterError ("if2", (3,2--3,2)), + ArbitraryAfterError ("if3", (3,2--3,2)), None, Yes (3,2--3,2), + true, (3,0--3,2), { IfKeyword = (3,0--3,2) + IsElif = false + ThenKeyword = (3,0--3,2) + ElseKeyword = None + IfToThenRange = (3,0--3,2) }), (3,0--3,2))], + PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None, + (1,0--3,2), { 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 expression +(3,0)-(3,2) parse error Incomplete conditional. Expected 'if then ' or 'if then else '.