Skip to content

Commit 561a5eb

Browse files
authored
Fix false negative [<TailCall>] warning (#18399)
1 parent 8359ec6 commit 561a5eb

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.300.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
### Fixed
2+
* Fix missing TailCall warning in TOp.IntegerForLoop ([PR #18399](https://github.com/dotnet/fsharp/pull/18399))
23
* Fix classification of `nameof` in `nameof<'T>`, `match … with nameof ident -> …`. ([Issue #10026](https://github.com/dotnet/fsharp/issues/10026), [PR #18300](https://github.com/dotnet/fsharp/pull/18300))
34
* Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877))
45
* Fix optimizer internal error for records with static fields ([Issue #18165](https://github.com/dotnet/fsharp/issues/18165), [PR #18280](https://github.com/dotnet/fsharp/pull/18280))

src/Compiler/Checking/TailCallChecks.fs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,12 @@ let CheckModuleBinding cenv (isRec: bool) (TBind _ as bind) =
792792
// warn for recursive calls in TryWith/TryFinally operations
793793
exprs |> Seq.iter (checkTailCall true)
794794
| Expr.Op(args = exprs) -> exprs |> Seq.iter (checkTailCall insideSubBindingOrTry)
795-
| Expr.Sequential(expr2 = expr2) -> checkTailCall insideSubBindingOrTry expr2
795+
| Expr.Sequential(expr1 = expr1; expr2 = expr2) ->
796+
match expr1 with
797+
| Expr.Op(args = exprs; op = TOp.IntegerForLoop _) -> checkTailCall insideSubBindingOrTry expr1
798+
| _ -> ()
799+
800+
checkTailCall insideSubBindingOrTry expr2
796801
| _ -> ()
797802

798803
checkTailCall false bodyExpr

tests/FSharp.Compiler.ComponentTests/ErrorMessages/TailCallAttribute.fs

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -773,20 +773,20 @@ namespace N
773773
|> compile
774774
|> shouldFail
775775
|> withResults [
776-
{ Error = Warning 3569
777-
Range = { StartLine = 21
778-
StartColumn = 27
779-
EndLine = 21
780-
EndColumn = 35 }
781-
Message =
782-
"The member or function 'instType' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." }
783776
{ Error = Warning 3569
784777
Range = { StartLine = 17
785778
StartColumn = 32
786779
EndLine = 17
787780
EndColumn = 77 }
788781
Message =
789782
"The member or function 'instType' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." }
783+
{ Error = Warning 3569
784+
Range = { StartLine = 21
785+
StartColumn = 27
786+
EndLine = 21
787+
EndColumn = 35 }
788+
Message =
789+
"The member or function 'instType' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." }
790790
]
791791

792792
[<FSharp.Test.FactForNETCOREAPP>]
@@ -1769,3 +1769,72 @@ module M =
17691769
|> withLangVersion80
17701770
|> compile
17711771
|> shouldSucceed
1772+
1773+
[<FSharp.Test.FactForNETCOREAPP>]
1774+
let ``Warn successfully in Array-mapped recursive call`` () =
1775+
"""
1776+
namespace N
1777+
1778+
module M =
1779+
1780+
type Value =
1781+
{ Code: string }
1782+
1783+
[<TailCall>]
1784+
let rec fooArray (values: Value[], code: string) =
1785+
match values with
1786+
| [||] -> seq { code }
1787+
| values ->
1788+
let replicatedValues =
1789+
values
1790+
|> Array.map (fun value -> fooArray (values, value.Code))
1791+
replicatedValues |> Seq.concat
1792+
"""
1793+
|> FSharp
1794+
|> withLangVersion80
1795+
|> compile
1796+
|> shouldFail
1797+
|> withResults [
1798+
{ Error = Warning 3569
1799+
Range = { StartLine = 16
1800+
StartColumn = 20
1801+
EndLine = 16
1802+
EndColumn = 74 }
1803+
Message =
1804+
"The member or function 'fooArray' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." }
1805+
]
1806+
1807+
[<FSharp.Test.FactForNETCOREAPP>]
1808+
let ``Warn successfully in Seq-mapped recursive call`` () =
1809+
"""
1810+
namespace N
1811+
1812+
module M =
1813+
1814+
type Value =
1815+
{ Code: string }
1816+
1817+
[<TailCall>]
1818+
let rec fooSeq (values: Value[], code: string) =
1819+
match values with
1820+
| [||] -> seq { code }
1821+
| values ->
1822+
let replicatedValues =
1823+
values
1824+
|> Seq.map (fun value -> fooSeq (values, value.Code))
1825+
|> Seq.toArray
1826+
replicatedValues |> Seq.concat
1827+
"""
1828+
|> FSharp
1829+
|> withLangVersion80
1830+
|> compile
1831+
|> shouldFail
1832+
|> withResults [
1833+
{ Error = Warning 3569
1834+
Range = { StartLine = 16
1835+
StartColumn = 42
1836+
EndLine = 16
1837+
EndColumn = 48 }
1838+
Message =
1839+
"The member or function 'fooSeq' has the 'TailCallAttribute' attribute, but is not being used in a tail recursive way." }
1840+
]

0 commit comments

Comments
 (0)