Codegen Regression - `function` within recursive function results in null reference exception
See original GitHub issueUsing function
within a recursive function iterating over a list results in a null reference exception when matching against the empty list []
.
Repro steps
A sample repo has been made: https://github.com/StachuDotNet/function-rec-fsharp-dotnet7-bug-demo/blob/main/Program.fs
let list = [1; 2; 3]
let condition n = n < 3
let dropWhileWithMatch condition list =
let rec f (l : List<int>) : List<int> =
match l with
| [] -> []
| head :: tail ->
match condition head with
| true -> f tail
| false -> head :: tail
f list
let dropWhileWithFunction condition list =
let rec f : List<int> -> List<int> =
function
| [] -> []
| head :: tail ->
match condition head with
| true -> f tail
| false -> head :: tail
f list
// this runs fine:
let matchResult = dropWhileWithMatch condition list
printfn "Match: %A" matchResult
// and this results in a null reference exception
let functionResult = dropWhileWithFunction condition list
printfn "Function: %A" functionResult
(*
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
at Program.f@14-1.Invoke(FSharpList`1 _arg1) in /workspaces/function-rec-fsharp-dotnet7-bug-demo/Program.fs:line 18
at Program.dropWhileWithFunction(FSharpFunc`2 condition, FSharpList`1 list) in /workspaces/function-rec-fsharp-dotnet7-bug-demo/Program.fs:line 21
at <StartupCode$function-rec-fsharp-dotnet7-bug-demo>.$Program.main@() in /workspaces/function-rec-fsharp-dotnet7-bug-demo/Program.fs:line 29
*)
The sample repo includes a devcontainer set up for simple testing - just dotnet run
.
Related information
Provide any related information (optional):
- Ubuntu 21.10
- .NET SDK 7.0.100-preview.3.22179.4
I suspect this issue will be eventually closed in favor of a runtime
issue, but know too little to report there appropriately.
Issue Analytics
- State:
- Created a year ago
- Comments:9 (8 by maintainers)
Top Results From Across the Web
Null Reference Exception in Recursive Function
Use a function expression that references values that are defined recursively. Before we jump to examples, I suggest changing the definition ...
Read more >Changelog | Burst | 1.2.3 - Unity User Manual 2021.3 (LTS)
Fix possible NullReferenceException when an entry point function is calling another empty function. Fix an exception occurring while ...
Read more >Changelog | Burst | 1.3.9
Fixed a subtle codegen bug that could occur when the target is an Arm or AArch64 CPU ... Fix possible NullReferenceException when an...
Read more >Code Generation for Recursive Functions - MATLAB & ...
Use recursive functions in MATLAB code that is intended for code generation.
Read more >Recursion in Java
We'll explain the characteristics of a recursive function and show how to use recursion for solving various problems in Java.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@vzarytovskii , we probably need to evaluate the debugging experience more deeply, before we do that. This change, makes no difference in the debugging as far as I can tell.
I’m able to reproduce it on 6.0.300-preview.22154.4 too. There is an IL diff between stable and preview versions: stable (6.0.104) : both functions have effectively identical il https://www.diffchecker.com/Av9sdqwx
preview: IL of “function” is very different. It is on the left.
It seems that compiler is now trying to make “f” an object instead of function.
So it tries to get “f” from field which is somehow null and fails on “f tail” call. You can check that by printfn ReferenceEquals(f, null) before the call. Funnily, removing type annotation from “let rec f : List<int> -> List<int>” to just “let rec f” fixes an issue.
Side note: I wonder why compiler doesn’t emit a warning when rec function results in closure instead of a while loop. I would really like to see a warning. Some things are really better expressed as rec’s but it’s always a manual check that assures, not compiler.
https://www.diffchecker.com/eAcGUo5B
Oh, @vzarytovskii was faster than me 😃