Skip to content

Commit

Permalink
Fix bug in referencing nested type in IL (#102933)
Browse files Browse the repository at this point in the history
* Fix bug in referencing nested type in IL

* Move GetResolutionScope method inline

* Change args order
  • Loading branch information
buyaa-n authored and pull[bot] committed Jul 20, 2024
1 parent 964383a commit 2239705
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,14 @@ private EntityHandle GetTypeReferenceOrSpecificationHandle(Type type)
}
else
{
typeHandle = AddTypeReference(type, GetResolutionScopeHandle(type));
if (type.IsNested)
{
typeHandle = AddTypeReference(GetTypeReferenceOrSpecificationHandle(type.DeclaringType!), null, type.Name);
}
else
{
typeHandle = AddTypeReference(GetAssemblyReference(type.Assembly), type.Namespace, type.Name);
}
}

_typeReferences.Add(type, typeHandle);
Expand All @@ -704,16 +711,6 @@ private EntityHandle GetTypeReferenceOrSpecificationHandle(Type type)
return typeHandle;
}

private EntityHandle GetResolutionScopeHandle(Type type)
{
if (type.IsNested)
{
return GetTypeReferenceOrSpecificationHandle(type.DeclaringType!);
}

return GetAssemblyReference(type.Assembly);
}

private TypeSpecificationHandle AddTypeSpecification(Type type) =>
_metadataBuilder.AddTypeSpecification(
signature: _metadataBuilder.GetOrAddBlob(MetadataSignatureHelper.GetTypeSpecificationSignature(type, this)));
Expand Down Expand Up @@ -944,11 +941,11 @@ private MethodDefinitionHandle AddMethodDefinition(MethodBuilderImpl method, Blo
bodyOffset: offset,
parameterList: MetadataTokens.ParameterHandle(parameterToken));

private TypeReferenceHandle AddTypeReference(Type type, EntityHandle resolutionScope) =>
private TypeReferenceHandle AddTypeReference(EntityHandle resolutionScope, string? ns, string name) =>
_metadataBuilder.AddTypeReference(
resolutionScope: resolutionScope,
@namespace: (type.Namespace == null) ? default : _metadataBuilder.GetOrAddString(type.Namespace),
name: _metadataBuilder.GetOrAddString(type.Name));
@namespace: (ns == null) ? default : _metadataBuilder.GetOrAddString(ns),
name: _metadataBuilder.GetOrAddString(name));

private MemberReferenceHandle AddMemberReference(string memberName, EntityHandle parent, BlobBuilder signature) =>
_metadataBuilder.AddMemberReference(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2673,5 +2673,30 @@ public void TypeBuilderByRefReferencedInIL()
tlc.Unload();
}
}

[Fact]
public void NestedTypeTokenReferencedCorrectlyInIL()
{
using (TempFile file = TempFile.Create())
{
PersistedAssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder typeBuilder);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
MethodBuilder writeMethod = typeBuilder.DefineMethod("Test", MethodAttributes.Public | MethodAttributes.Static);
ILGenerator il = writeMethod.GetILGenerator();
il.DeclareLocal(typeof(HashSet<int>.Enumerator));
il.Emit(OpCodes.Newobj, typeof(HashSet<int>).GetConstructors().First(c => c.GetParameters().Length == 0));
il.Emit(OpCodes.Callvirt, typeof(HashSet<int>).GetMethod("GetEnumerator")!);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ret);
typeBuilder.CreateType();
ab.Save(file.Path);

TestAssemblyLoadContext tlc = new TestAssemblyLoadContext();
Type typeFromDisk = tlc.LoadFromAssemblyPath(file.Path).GetType("MyType");
MethodInfo method = typeFromDisk.GetMethod("Test")!;
method.Invoke(null, null); // just make sure token works
tlc.Unload();
}
}
}
}

0 comments on commit 2239705

Please sign in to comment.