Skip to content

Commit

Permalink
Merge pull request #1235 from taylorwood/result-ignored
Browse files Browse the repository at this point in the history
Expand warning when expression result is ignored
  • Loading branch information
KevinRansom authored Jun 24, 2016
2 parents deea6a5 + 3600557 commit 760a50b
Show file tree
Hide file tree
Showing 21 changed files with 28 additions and 22 deletions.
4 changes: 2 additions & 2 deletions src/fsharp/CompileOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ let UseOfAddressOfOperatorE() = DeclareResourceString("UseOfAddressOfOperator","
let DefensiveCopyWarningE() = DeclareResourceString("DefensiveCopyWarning","%s")
let DeprecatedThreadStaticBindingWarningE() = DeclareResourceString("DeprecatedThreadStaticBindingWarning","")
let FunctionValueUnexpectedE() = DeclareResourceString("FunctionValueUnexpected","%s")
let UnitTypeExpected1E() = DeclareResourceString("UnitTypeExpected1","%s")
let UnitTypeExpected1E() = DeclareResourceString("UnitTypeExpected1","")
let UnitTypeExpected2E() = DeclareResourceString("UnitTypeExpected2","%s")
let RecursiveUseCheckedAtRuntimeE() = DeclareResourceString("RecursiveUseCheckedAtRuntime","")
let LetRecUnsound1E() = DeclareResourceString("LetRecUnsound1","%s")
Expand Down Expand Up @@ -1185,7 +1185,7 @@ let OutputPhasedErrorR (os:System.Text.StringBuilder) (err:PhasedError) =
if perhapsProp then
os.Append(UnitTypeExpected2E().Format (NicePrint.stringOfTy denv ty)) |> ignore
else
os.Append(UnitTypeExpected1E().Format (NicePrint.stringOfTy denv ty)) |> ignore
os.Append(UnitTypeExpected1E().Format) |> ignore
| RecursiveUseCheckedAtRuntime _ ->
os.Append(RecursiveUseCheckedAtRuntimeE().Format) |> ignore
| LetRecUnsound (_,[v],_) ->
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/FSStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,7 @@
<value>This expression is a function value, i.e. is missing arguments. Its type is {0}.</value>
</data>
<data name="UnitTypeExpected1" xml:space="preserve">
<value>This expression should have type 'unit', but has type '{0}'. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name.</value>
<value>The result of this expression is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.</value>
</data>
<data name="UnitTypeExpected2" xml:space="preserve">
<value>This expression should have type 'unit', but has type '{0}'. If assigning to a property use the syntax 'obj.Prop &lt;- expr'.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#light

// Verify warning when 'do-bindings' do not return unit.
//<Expects id="FS0020" status="warning">This expression should have type 'unit', but has type 'int'</Expects>
//<Expects id="FS0020" status="warning">The result of this expression is implicitly ignored</Expects>

let square x = x * x

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Eventually, we will deprecated them - and the specs will be updated.
//
//<Expects status="error" span="(11,5-11,6)" id="FS0039">The value or constructor 'a' is not defined$</Expects>
//<Expects status="error" span="(11,5-11,10)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(11,5-11,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
module A =
let a = 3 in a + 1 |> ignore;;
a > 4;;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// I'm adding these cases to make sure we do not accidentally change the behavior from version to version
// Eventually, we will deprecated them - and the specs will be updated.
//
//<Expects status="error" span="(11,5-12,10)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(11,5-12,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//

module B =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// I'm adding these cases to make sure we do not accidentally change the behavior from version to version
// Eventually, we will deprecated them - and the specs will be updated.
//
//<Expects status="error" span="(12,5-12,10)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(12,5-12,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//
module C =
let a = 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// I'm adding these cases to make sure we do not accidentally change the behavior from version to version
// Eventually, we will deprecated them - and the specs will be updated.
//
//<Expects status="error" span="(11,5-13,10)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(11,5-13,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//

module D =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Eventually, we will deprecated them - and the specs will be updated.
//<Expects status="error" span="(12,13-12,14)" id="FS0001">The type 'int' does not match the type 'unit'$</Expects>
//<Expects status="error" span="(12,18-12,24)" id="FS0001">Type mismatch\. Expecting a. ''a -> 'b' .but given a. ''a -> unit' .The type 'int' does not match the type 'unit'$</Expects>
//<Expects status="error" span="(10,5-13,10)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(10,5-13,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
module E =
let a = 3 in
a + 1 |> ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#light

// Verify warning if a finally block does not return 'unit'
//<Expects id="FS0020" status="warning">This expression should have type 'unit', but has type 'bool'</Expects>
//<Expects id="FS0020" status="warning">The result of this expression is implicitly ignored</Expects>

let x : int =
try
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// #Conformance #DataExpressions #Query
// Where expressions require parenthesis
//<Expects status="error" span="(8,9-8,14)" id="FS3095">'where' is not used correctly\. This is a custom operation in this query or computation expression\.$</Expects>
//<Expects status="error" span="(8,9-8,24)" id="FS0020">This expression should have type 'unit', but has type 'bool'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(8,9-8,24)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
let query =
query {
for i in [1..10] do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Regression test for FSHARP1.0:5590
// This code used to compile, but fail peverification
// Now, it just does not compile anymore telling the user to annotated it a bit.
//<Expects status="warning" span="(14,1-14,5)" id="FS0020">This expression should have type 'unit', but has type 'int'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="warning" span="(14,1-14,5)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//<Expects status="error" span="(7,6-7,16)" id="FS1210">Active pattern '\|A1\|A2\|A3\|' has a result type containing type variables that are not determined by the input\. The common cause is a when a result case is not mentioned, e\.g\. 'let \(\|A\|B\|\) \(x:int\) = A x'\. This can be fixed with a type constraint, e\.g\. 'let \(\|A\|B\|\) \(x:int\) : Choice<int,unit> = A x'$</Expects>
let (|A1|A2|A3|) (inp:int) : Choice<unit,'T,'U> =
printfn "hello"
Expand Down
2 changes: 1 addition & 1 deletion tests/fsharpqa/Source/Diagnostics/General/W_Multiline02.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// #Regression #Diagnostics
// Regression test for FSHARP1.0:3596
// Make sure that error spans correctly across multiple lines
//<Expects status="warning" id="FS0020" span="(8,1-10,18)">This expression should have type 'unit'</Expects>
//<Expects status="warning" id="FS0020" span="(8,1-10,18)">The result of this expression is implicitly ignored</Expects>
#nowarn "988"
let f g x = g x

Expand Down
2 changes: 1 addition & 1 deletion tests/fsharpqa/Source/Diagnostics/NONTERM/quoteExpr01.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// #Regression #Diagnostics
// Regression test for FSHARP1.0:2391, FSHARP1.0:1479
//<Expects id="FS0020" span="(5,1-5,24)" status="warning">This expression should have type 'unit', but has type 'seq.Quotations.Var.'</Expects>
//<Expects id="FS0020" span="(5,1-5,24)" status="warning">The result of this expression is implicitly ignored</Expects>
#light "off"
<@@ 1 @@>.GetFreeVars()
2 changes: 1 addition & 1 deletion tests/fsharpqa/Source/Diagnostics/async/MissingIgnore.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// #Regression #Diagnostics #Async
// Regression tests for FSHARP1.0:4394
//<Expects status="error" span="(4,9-4,10)" id="FS0020">This expression should have type 'unit', but has type 'int'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(4,9-4,10)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
async { 1;
return 2 } |> ignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// #Regression #Diagnostics #Async
// Regression tests for FSHARP1.0:4394
// common mistake: forgetting the return! For a loop
//<Expects status="error" span="(5,39-5,45)" id="FS0020">This expression should have type 'unit', but has type 'Async<'a>'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(5,39-5,45)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
let rec loop() = async { let x = 1 in loop() }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// #Regression #Diagnostics #Async
// Regression tests for FSHARP1.0:4394
// common mistake: forgetting the return! For a loop
//<Expects status="error" span="(5,26-5,32)" id="FS0020">This expression should have type 'unit', but has type 'Async<'a>'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(5,26-5,32)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
let rec loop() = async { loop() }
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// #Regression #Diagnostics #Async
// Regression tests for FSHARP1.0:4394
// common mistake: forgetting the return! For a loop
//<Expects status="error" span="(6,41-6,48)" id="FS0020">This expression should have type 'unit', but has type 'Async<'a>'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(6,41-6,48)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//<Expects status="error" span="(6,50-6,52)" id="FS0001">This expression was expected to have type. 'Async<'a>' .but here has type. 'unit'</Expects>
let rec loop2() = async.Delay(fun () -> loop2(); ());
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// #Regression #Diagnostics #Async
// Regression tests for FSHARP1.0:4394
// common mistake: forgetting the return! For a loop
//<Expects status="error" span="(8,35-8,42)" id="FS0020">This expression should have type 'unit', but has type 'Async<'a>'\. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name\.$</Expects>
//<Expects status="error" span="(8,35-8,42)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>
//<Expects status="error" span="(8,44-8,46)" id="FS0001">This expression was expected to have type. 'Async<'a>' .but here has type. 'unit'</Expects>
// Note: interestingly, this looks much better if a method call is not used
let delay x = async.Delay x
Expand Down
6 changes: 3 additions & 3 deletions tests/fsharpqa/Source/Misc/Parsing02.fs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// #Regression #Misc
// Verify warnings associated with top level expressions getting discarded

//<Expects id="FS0020" status="warning">This expression should have type 'unit', but has type '\( \^a -> unit\) \* int'</Expects>
//<Expects id="FS0020" status="warning">This expression should have type 'unit', but has type '\('a \[\] -> unit \[\]\) \* string \[\]'</Expects>
//<Expects id="FS0020" status="warning" span="(9,1)">The result of this expression is implicitly ignored</Expects>
//<Expects id="FS0020" status="warning" span="(12,1)">The result of this expression is implicitly ignored</Expects>

// Note the comma between printf "%A", this results in a tuple expr which probabaly wasn't intended.
// Note the comma between printf "%A", this results in a tuple expr which probably wasn't intended.
let arr = [|"Foo"; "Bar"|]
printf "%d", arr.Length

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// #Warnings
//<Expects status="warning" span="(4,1)" id="FS0020">The result of this expression is implicitly ignored\. Consider using 'ignore' to discard this value explicitly, e\.g\. 'expr \|> ignore', or 'let' to bind the result to a name, e\.g\. 'let result = expr'.$</Expects>

1 + 2
printfn "%d" 3
1 change: 1 addition & 0 deletions tests/fsharpqa/Source/Warnings/env.lst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
SOURCE=DowncastInsteadOfUpcast.fs # DowncastInsteadOfUpcast.fs
SOURCE=RuntimeTypeTestInPattern.fs # RuntimeTypeTestInPattern.fs
SOURCE=RuntimeTypeTestInPattern2.fs # RuntimeTypeTestInPattern2.fs
SOURCE=WarnIfExpressionResultUnused.fs # WarnIfExpressionResultUnused.fs

0 comments on commit 760a50b

Please sign in to comment.