Merge pull request #100 from Horusiath/fsharp-async-task-support
Demystify F# async/task stack traces
This commit is contained in:
commit
1f10ebc836
@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier.Benchmarks", "test\Ben.Demystifier.Benchmarks\Ben.Demystifier.Benchmarks.csproj", "{EF5557DF-C48E-4999-846C-D99A92E86373}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpStackTrace", "sample\FSharpStackTrace\FSharpStackTrace.fsproj", "{D6B779D2-A678-47CC-A2F9-A312292EA7A2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -48,6 +50,10 @@ Global
|
||||
{EF5557DF-C48E-4999-846C-D99A92E86373}.Debug|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF5557DF-C48E-4999-846C-D99A92E86373}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF5557DF-C48E-4999-846C-D99A92E86373}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -57,6 +63,7 @@ Global
|
||||
{B9E150B0-AEEB-4D98-8BE1-92C1296699A2} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
|
||||
{E161FC12-53C2-47CD-A5FC-3684B86723A9} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
|
||||
{EF5557DF-C48E-4999-846C-D99A92E86373} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
|
||||
{D6B779D2-A678-47CC-A2F9-A312292EA7A2} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {841B7D5F-E810-4F94-A529-002C7E075216}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>7.2</LangVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
20
sample/FSharpStackTrace/FSharpStackTrace.fsproj
Normal file
20
sample/FSharpStackTrace/FSharpStackTrace.fsproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ply" Version="0.1.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
35
sample/FSharpStackTrace/Program.fs
Normal file
35
sample/FSharpStackTrace/Program.fs
Normal file
@ -0,0 +1,35 @@
|
||||
// Learn more about F# at http://fsharp.org
|
||||
|
||||
open System
|
||||
open System.Diagnostics
|
||||
open System.Threading.Tasks
|
||||
open FSharp.Control.Tasks.Builders
|
||||
|
||||
let call i = async {
|
||||
do! Async.Sleep 1
|
||||
if i = 10 then
|
||||
failwith "BOOM!"
|
||||
return i
|
||||
}
|
||||
|
||||
let run count = async {
|
||||
let calls = Array.init count call
|
||||
for call in calls do
|
||||
let! _ = call
|
||||
()
|
||||
return 0
|
||||
}
|
||||
|
||||
let makeTheCall () = task {
|
||||
let! x = run 20
|
||||
return x
|
||||
}
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
try
|
||||
let results = makeTheCall().GetAwaiter().GetResult()
|
||||
printfn "%A" results
|
||||
with e ->
|
||||
printfn "%s" <| string (e.Demystify())
|
||||
0 // return an integer exit code
|
||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
class Program
|
||||
|
||||
@ -114,6 +114,13 @@ namespace System.Diagnostics
|
||||
|
||||
methodName = method.Name;
|
||||
}
|
||||
else if (IsFSharpAsync(method))
|
||||
{
|
||||
methodDisplayInfo.IsAsync = true;
|
||||
methodDisplayInfo.SubMethodBase = null;
|
||||
subMethodName = null;
|
||||
methodName = null;
|
||||
}
|
||||
|
||||
// Method name
|
||||
methodDisplayInfo.MethodBase = method;
|
||||
@ -241,6 +248,20 @@ namespace System.Diagnostics
|
||||
return methodDisplayInfo;
|
||||
}
|
||||
|
||||
private static bool IsFSharpAsync(MethodBase method)
|
||||
{
|
||||
if (method is MethodInfo minfo)
|
||||
{
|
||||
var returnType = minfo.ReturnType;
|
||||
if (returnType.Namespace == "Microsoft.FSharp.Control" && returnType.Name == "FSharpAsync`1")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryResolveGeneratedName(ref MethodBase method, out Type type, out string methodName, out string subMethodName, out GeneratedNameKind kind, out int? ordinal)
|
||||
{
|
||||
kind = GeneratedNameKind.None;
|
||||
@ -699,6 +720,29 @@ namespace System.Diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
if (type.Namespace == "Microsoft.FSharp.Control")
|
||||
{
|
||||
switch (type.Name)
|
||||
{
|
||||
case "AsyncPrimitives":
|
||||
case "Trampoline":
|
||||
return false;
|
||||
case var typeName when type.IsGenericType:
|
||||
{
|
||||
if (typeName == "AsyncResult`1") return false;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type.Namespace == "Ply")
|
||||
{
|
||||
if (type.DeclaringType.Name == "TplPrimitives")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallbacks for runtime pre-StackTraceHiddenAttribute
|
||||
if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw")
|
||||
{
|
||||
|
||||
@ -18,6 +18,9 @@ namespace System.Diagnostics
|
||||
|
||||
internal StringBuilder Append(StringBuilder sb)
|
||||
{
|
||||
if (ResolvedType.Assembly.ManifestModule.Name == "FSharp.Core.dll" && ResolvedType.Name == "Unit")
|
||||
return sb;
|
||||
|
||||
if (!string.IsNullOrEmpty(Prefix))
|
||||
{
|
||||
sb.Append(Prefix)
|
||||
|
||||
@ -29,6 +29,15 @@ namespace System.Diagnostics
|
||||
{ typeof(ushort), "ushort" }
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, string> FSharpTypeNames = new Dictionary<string, string>
|
||||
{
|
||||
{ "Unit", "void" },
|
||||
{ "FSharpOption", "Option" },
|
||||
{ "FSharpAsync", "Async" },
|
||||
{ "FSharpOption`1", "Option" },
|
||||
{ "FSharpAsync`1", "Async" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Pretty print a type name.
|
||||
/// </summary>
|
||||
@ -92,6 +101,11 @@ namespace System.Diagnostics
|
||||
{
|
||||
builder.Append(type.Name);
|
||||
}
|
||||
else if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
|
||||
&& FSharpTypeNames.TryGetValue(type.Name, out builtInName))
|
||||
{
|
||||
builder.Append(builtInName);
|
||||
}
|
||||
else if (type.IsGenericParameter)
|
||||
{
|
||||
if (options.IncludeGenericParameterNames)
|
||||
@ -153,7 +167,15 @@ namespace System.Diagnostics
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
|
||||
&& FSharpTypeNames.TryGetValue(type.Name, out var builtInName))
|
||||
{
|
||||
builder.Append(builtInName);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(type.Name, 0, genericPartIndex);
|
||||
}
|
||||
|
||||
builder.Append('<');
|
||||
for (var i = offset; i < length; i++)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user