Demystify truncating internals of F# async/task expressions

This commit is contained in:
Bartosz Sypytkowski 2020-01-05 17:02:03 +01:00
parent 1ca8f79a36
commit af40cc3bfa
8 changed files with 134 additions and 3 deletions

View File

@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier.Benchmarks", "test\Ben.Demystifier.Benchmarks\Ben.Demystifier.Benchmarks.csproj", "{EF5557DF-C48E-4999-846C-D99A92E86373}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier.Benchmarks", "test\Ben.Demystifier.Benchmarks\Ben.Demystifier.Benchmarks.csproj", "{EF5557DF-C48E-4999-846C-D99A92E86373}"
EndProject EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpStackTrace", "sample\FSharpStackTrace\FSharpStackTrace.fsproj", "{D6B779D2-A678-47CC-A2F9-A312292EA7A2}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{EF5557DF-C48E-4999-846C-D99A92E86373}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -57,6 +63,7 @@ Global
{B9E150B0-AEEB-4D98-8BE1-92C1296699A2} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4} {B9E150B0-AEEB-4D98-8BE1-92C1296699A2} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
{E161FC12-53C2-47CD-A5FC-3684B86723A9} = {455921D3-DD54-4355-85CF-F4009DF2AB70} {E161FC12-53C2-47CD-A5FC-3684B86723A9} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
{EF5557DF-C48E-4999-846C-D99A92E86373} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4} {EF5557DF-C48E-4999-846C-D99A92E86373} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
{D6B779D2-A678-47CC-A2F9-A312292EA7A2} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {841B7D5F-E810-4F94-A529-002C7E075216} SolutionGuid = {841B7D5F-E810-4F94-A529-002C7E075216}

View File

@ -1,5 +1,4 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>7.2</LangVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View 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>

View 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

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
class Program class Program

View File

@ -114,6 +114,13 @@ namespace System.Diagnostics
methodName = method.Name; methodName = method.Name;
} }
else if (IsFSharpAsync(method))
{
methodDisplayInfo.IsAsync = true;
methodDisplayInfo.SubMethodBase = null;
subMethodName = null;
methodName = null;
}
// Method name // Method name
methodDisplayInfo.MethodBase = method; methodDisplayInfo.MethodBase = method;
@ -241,6 +248,20 @@ namespace System.Diagnostics
return methodDisplayInfo; 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) 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; kind = GeneratedNameKind.None;
@ -662,6 +683,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;
}
}
if (StackTraceHiddenAttributeType != null) if (StackTraceHiddenAttributeType != null)
{ {
// Don't show any types marked with the StackTraceHiddenAttribute // Don't show any types marked with the StackTraceHiddenAttribute

View File

@ -18,6 +18,9 @@ namespace System.Diagnostics
internal StringBuilder Append(StringBuilder sb) internal StringBuilder Append(StringBuilder sb)
{ {
if (ResolvedType.Assembly.ManifestModule.Name == "FSharp.Core.dll" && ResolvedType.Name == "Unit")
return sb;
if (!string.IsNullOrEmpty(Prefix)) if (!string.IsNullOrEmpty(Prefix))
{ {
sb.Append(Prefix) sb.Append(Prefix)

View File

@ -29,6 +29,15 @@ namespace System.Diagnostics
{ typeof(ushort), "ushort" } { 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> /// <summary>
/// Pretty print a type name. /// Pretty print a type name.
/// </summary> /// </summary>
@ -93,6 +102,11 @@ namespace System.Diagnostics
{ {
builder.Append(type.Name); 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) else if (type.IsGenericParameter)
{ {
if (options.IncludeGenericParameterNames) if (options.IncludeGenericParameterNames)
@ -154,7 +168,15 @@ namespace System.Diagnostics
return; 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(type.Name, 0, genericPartIndex);
}
builder.Append('<'); builder.Append('<');
for (var i = offset; i < length; i++) for (var i = offset; i < length; i++)