Open AlexeyRaga opened 2 years ago
Thanks for reporting.
OK this is really complicated. I looked into the IL and saw that the compiler is generating a second function for inline
functions with the exact same sequence point but with $W
suffixed. This is described here https://github.com/fsharp/fslang-design/blob/main/FSharp-5.0/FS-1071-witness-passing-quotations.md#compiled-form-of-srtp-constrained-generic-code.
Coverlet is properly injecting the tracker in both functions but nevertheless they both never get called. Or at least for me it seems like this.
When I look into the IL without inline
there is only one function without the $W
. The function is also properly instrumented and the function is beeing call and thus hit.
Now when I look into the same IL with inline
none of the two instrumented functions is called. Seems like the compiler optimized it in a way that the corresponding IL operation is used instead of a function call.
Maybe this is just because of the simple code example I'm using but I try to analyze this a bit more. Any information on this is highly welcome.
Coverlet is properly injecting the tracker in both functions but nevertheless they both never get called.
I think that this is what inline
means: the compiler inlines (copies) the function body instead of the function call.
From F# documentation:
Inline functions are functions that are integrated directly into the calling code.
I also see that inline
in F# works across compilation units:
F# can also inline between compiled assemblies because inline is conveyed via .NET metadata.
So based on that I would expect that there'd be no calls to the inline
functions and that they are only compiled into assemblies as functions (with the flag mentioned above) to be inlined later in assemblies that use them...
But I don't know what happens at the edge cases, like:
inline
and not just a function? I would guess that it'd be inlined too (otherwise why enabling the keyword there), but I haven't written much OOP in F# myself...Thanks for the explanation. I currently don't have any idea how we could work around this. I can't find a way to map the inline
function body to the executed IL.
The only thing that comes to my mind is excluding inline
functions from the instrumentation to at least get rid of the false not covered
report of inline functions
.
@MarcoRossignoli @petli what do you think? Any other ideas?
OK I just got a response from the fsharp
team that they currently don't emit this information (https://github.com/dotnet/fsharp/issues/12263). Now I really don't have any other idea how to deal with this except for excluding inline
functions.
It looks like
Coverlet
misses theinline
directive on F# functions and reports zero coverage for such functions and methods:In this example above, many of the functions that I test use
unwrapHandler
but, zero coverage is returned.Another example:![image](https://user-images.githubusercontent.com/1394391/133923747-5619ff17-df4f-40f1-9798-e4f6e2adf6ef.png)
Here we see that
valueCurry
is used within the same method, but it is still reported as untested.If I remove
inline
then it looks like:So, even in my simple case,
Coverlet
misses 6K+ passes and reports the code as untested.