Fody / ConfigureAwait

Configure async code's ConfigureAwait at a global level

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

awaiting Func<XmlReader, Task<TValue>> throws "NullReferenceException"

chrfin opened this issue · comments

I have the following code (simplified):

Func<XmlReader, Task<TKey>> readKey = parameterValue;
var key = await readKey(reader).ConfigureAwait(false);

and if I remove the ConfigureAwait(false) from these I get the following during build:

Error   1   Fody: An unhandled exception occurred:
Exception:
Object reference not set to an instance of an object. 
StackTrace:
   at Mono.Cecil.ImportGenericContext.TypeParameter(String type, Int32 position)
   at Mono.Cecil.MetadataImporter.ImportTypeSpecification(TypeReference type, ImportGenericContext context)
   at Mono.Cecil.MetadataImporter.ImportType(TypeReference type, ImportGenericContext context)
   at Mono.Cecil.MetadataImporter.ImportTypeSpecification(TypeReference type, ImportGenericContext context)
   at Mono.Cecil.MetadataImporter.ImportType(TypeReference type, ImportGenericContext context)
   at Mono.Cecil.ModuleDefinition.Import(TypeReference type)
   at ConfigureAwait.ModuleWeaver.AddAwaitConfigToAsyncMethod(TypeDefinition type, Boolean value) in C:\projects\configureawait\src\ConfigureAwait\ModuleWeaver.cs:line 95
   at ConfigureAwait.ModuleWeaver.ProcessType(Nullable`1 assemblyConfigureAwaitValue, TypeDefinition type) in C:\projects\configureawait\src\ConfigureAwait\ModuleWeaver.cs:line 69
   at ConfigureAwait.ModuleWeaver.Execute() in C:\projects\configureawait\src\ConfigureAwait\ModuleWeaver.cs:line 41
   at lambda_method(Closure , Object )
   at InnerWeaver.ExecuteWeavers() in c:\ConsoleBuildAgent\work\ed448661dbb30d2e\FodyIsolated\InnerWeaver.cs:line 144
   at InnerWeaver.Execute() in c:\ConsoleBuildAgent\work\ed448661dbb30d2e\FodyIsolated\InnerWeaver.cs:line 62
Source:
Mono.Cecil
TargetSite:
Mono.Cecil.TypeReference TypeParameter(System.String, Int32)

I seems this is a generic problem with all methods returning generic tasks not know at build time of the library...

The problem is this code in ModuleWeavers.cs, AddAwaitConfigToAsyncMethod method:

                if (v.VariableType.IsGenericInstance)
                {
                    var genericVariableType = (GenericInstanceType)v.VariableType;
                    var variableType = v.VariableType.Resolve();
                    if (variableType.FullName == "System.Runtime.CompilerServices.TaskAwaiter`1")
                        v.VariableType = ModuleDefinition.ImportReference(gConfiguredTaskAwaiterTypeDef.MakeGenericInstanceType(genericVariableType.GenericArguments));
                    awaitableVar = new VariableDefinition(ModuleDefinition.ImportReference(gConfiguredTaskAwaitableTypeDef.MakeGenericInstanceType(genericVariableType.GenericArguments)));
                    method.Body.Variables.Insert(i + 1, awaitableVar);

                    var configureAwaitMethodDef = typeFinder.GetMSCorLibTypeDefinition("System.Threading.Tasks.Task`1").Methods.First(m => m.Name == "ConfigureAwait");
                    configureAwaitMethod = ModuleDefinition.ImportReference(configureAwaitMethodDef);
                    configureAwaitMethod.DeclaringType = ModuleDefinition.ImportReference(typeFinder.GetMSCorLibTypeDefinition("System.Threading.Tasks.Task`1").MakeGenericInstanceType(genericVariableType.GenericArguments));
                }

It should be:

                if (v.VariableType.IsGenericInstance)
                {
                    var genericVariableType = (GenericInstanceType)v.VariableType;
                    var variableType = v.VariableType.Resolve();
                    if (variableType.FullName == "System.Runtime.CompilerServices.TaskAwaiter`1")
                    {
                      v.VariableType = ModuleDefinition.ImportReference(gConfiguredTaskAwaiterTypeDef.MakeGenericInstanceType(genericVariableType.GenericArguments));
                      awaitableVar = new VariableDefinition(ModuleDefinition.ImportReference(gConfiguredTaskAwaitableTypeDef.MakeGenericInstanceType(genericVariableType.GenericArguments)));
                      method.Body.Variables.Insert(i + 1, awaitableVar);

                      var configureAwaitMethodDef = typeFinder.GetMSCorLibTypeDefinition("System.Threading.Tasks.Task`1")
                                                              .Methods.First(m => m.Name == "ConfigureAwait");
                      configureAwaitMethod = ModuleDefinition.ImportReference(configureAwaitMethodDef);
                      configureAwaitMethod.DeclaringType = ModuleDefinition.ImportReference(typeFinder.GetMSCorLibTypeDefinition("System.Threading.Tasks.Task`1")
                                                                                                      .MakeGenericInstanceType(genericVariableType.GenericArguments));
                    }
                }

caesay has done a pull request that fixes this but the fix is entangled in a lot of other changes that distantcam may not be willing to take on board.

When I get a chance I will do a pull request with this fixed (and a unit test!)

Should be fixed in 0.3.0