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 '.