Skip to content

Commit d51f619

Browse files
[release/10.0] UnsafeAccessor - ambiguous name and signature match (#119974)
* UnsafeAccessor - ambiguous name and signature match Handle the case where there is an ambiguous name and signature match, but one is generic and the other isn't. * Feedback --------- Co-authored-by: Aaron R Robinson <[email protected]>
1 parent a890075 commit d51f619

File tree

3 files changed

+98
-25
lines changed

3 files changed

+98
-25
lines changed

src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationConte
329329
return false;
330330
}
331331

332+
// Validate generic parameter.
333+
if (declSig.GenericParameterCount != maybeSig.GenericParameterCount)
334+
{
335+
return false;
336+
}
337+
332338
// Validate argument count and return type
333339
if (context.Kind == UnsafeAccessorKind.Constructor)
334340
{

src/coreclr/vm/unsafeaccessors.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,14 +424,26 @@ namespace
424424
return false;
425425
}
426426

427-
// Handle generic param count
428-
DWORD declGenericCount = 0;
429-
DWORD methodGenericCount = 0;
427+
// Handle generic signature
430428
if (callConvDecl & IMAGE_CEE_CS_CALLCONV_GENERIC)
429+
{
430+
if (!(callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC))
431+
return false;
432+
433+
DWORD declGenericCount = 0;
434+
DWORD methodGenericCount = 0;
431435
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declGenericCount));
432-
if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
433436
IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &methodGenericCount));
434437

438+
if (declGenericCount != methodGenericCount)
439+
return false;
440+
}
441+
else if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)
442+
{
443+
// Method is generic but declaration is not
444+
return false;
445+
}
446+
435447
DWORD declArgCount;
436448
DWORD methodArgCount;
437449
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declArgCount));

src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -181,21 +181,76 @@ public static void Verify_Generic_AccessFieldClass()
181181
}
182182
}
183183

184+
class AmbiguousMethodName
185+
{
186+
private void M() { }
187+
private void M<T>() { }
188+
private void N() { }
189+
190+
private static void SM() { }
191+
private static void SM<U>() { }
192+
private static void SN() { }
193+
}
194+
195+
static class AccessorsAmbiguousMethodName
196+
{
197+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
198+
public extern static void CallM(AmbiguousMethodName a);
199+
200+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
201+
public extern static void CallM<T>(AmbiguousMethodName a);
202+
203+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "N")]
204+
public extern static void CallN_MissingMethod<T>(AmbiguousMethodName a);
205+
206+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
207+
public extern static void CallSM(AmbiguousMethodName a);
208+
209+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")]
210+
public extern static void CallSM<U>(AmbiguousMethodName a);
211+
212+
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SN")]
213+
public extern static void CallSN_MissingMethod<T>(AmbiguousMethodName a);
214+
}
215+
216+
[Fact]
217+
public static void Verify_Generic_AmbiguousMethodName()
218+
{
219+
Console.WriteLine($"Running {nameof(Verify_Generic_AmbiguousMethodName)}");
220+
221+
{
222+
AmbiguousMethodName a = new();
223+
AccessorsAmbiguousMethodName.CallM(a);
224+
AccessorsAmbiguousMethodName.CallM<int>(a);
225+
AccessorsAmbiguousMethodName.CallM<string>(a);
226+
AccessorsAmbiguousMethodName.CallM<Guid>(a);
227+
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallN_MissingMethod<int>(a));
228+
}
229+
230+
{
231+
AccessorsAmbiguousMethodName.CallSM(null);
232+
AccessorsAmbiguousMethodName.CallSM<int>(null);
233+
AccessorsAmbiguousMethodName.CallSM<string>(null);
234+
AccessorsAmbiguousMethodName.CallSM<Guid>(null);
235+
Assert.Throws<MissingMethodException>(() => AccessorsAmbiguousMethodName.CallSN_MissingMethod<int>(null));
236+
}
237+
}
238+
184239
class Base
185240
{
186-
protected virtual string CreateMessageGeneric<T>(T t) => $"{nameof(Base)}:{t}";
241+
protected virtual string CreateMessage<T>(T t) => $"{nameof(Base)}<>:{t}";
187242
}
188243

189-
class GenericBase<T> : Base
244+
class GenericBase<U> : Base
190245
{
191-
protected virtual string CreateMessage(T t) => $"{nameof(GenericBase<T>)}:{t}";
192-
protected override string CreateMessageGeneric<U>(U u) => $"{nameof(GenericBase<T>)}:{u}";
246+
protected virtual string CreateMessage(U u) => $"{nameof(GenericBase<U>)}:{u}";
247+
protected override string CreateMessage<V>(V v) => $"{nameof(GenericBase<U>)}<>:{v}";
193248
}
194249

195250
sealed class Derived1 : GenericBase<string>
196251
{
197252
protected override string CreateMessage(string u) => $"{nameof(Derived1)}:{u}";
198-
protected override string CreateMessageGeneric<U>(U t) => $"{nameof(Derived1)}:{t}";
253+
protected override string CreateMessage<W>(W w) => $"{nameof(Derived1)}<>:{w}";
199254
}
200255

201256
sealed class Derived2 : GenericBase<string>
@@ -209,33 +264,33 @@ public static void Verify_Generic_InheritanceMethodResolution()
209264
Console.WriteLine($"Running {nameof(Verify_Generic_InheritanceMethodResolution)}");
210265
{
211266
Base a = new();
212-
Assert.Equal($"{nameof(Base)}:1", CreateMessage<int>(a, 1));
213-
Assert.Equal($"{nameof(Base)}:{expect}", CreateMessage<string>(a, expect));
214-
Assert.Equal($"{nameof(Base)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
267+
Assert.Equal($"{nameof(Base)}<>:1", CreateMessage<int>(a, 1));
268+
Assert.Equal($"{nameof(Base)}<>:{expect}", CreateMessage<string>(a, expect));
269+
Assert.Equal($"{nameof(Base)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
215270
}
216271
{
217272
GenericBase<int> a = new();
218-
Assert.Equal($"{nameof(GenericBase<int>)}:1", CreateMessage<int>(a, 1));
219-
Assert.Equal($"{nameof(GenericBase<int>)}:{expect}", CreateMessage<string>(a, expect));
220-
Assert.Equal($"{nameof(GenericBase<int>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
273+
Assert.Equal($"{nameof(GenericBase<int>)}<>:1", CreateMessage<int>(a, 1));
274+
Assert.Equal($"{nameof(GenericBase<int>)}<>:{expect}", CreateMessage<string>(a, expect));
275+
Assert.Equal($"{nameof(GenericBase<int>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
221276
}
222277
{
223278
GenericBase<string> a = new();
224-
Assert.Equal($"{nameof(GenericBase<string>)}:1", CreateMessage<int>(a, 1));
225-
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", CreateMessage<string>(a, expect));
226-
Assert.Equal($"{nameof(GenericBase<string>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
279+
Assert.Equal($"{nameof(GenericBase<string>)}<>:1", CreateMessage<int>(a, 1));
280+
Assert.Equal($"{nameof(GenericBase<string>)}<>:{expect}", CreateMessage<string>(a, expect));
281+
Assert.Equal($"{nameof(GenericBase<string>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
227282
}
228283
{
229284
GenericBase<Struct> a = new();
230-
Assert.Equal($"{nameof(GenericBase<Struct>)}:1", CreateMessage<int>(a, 1));
231-
Assert.Equal($"{nameof(GenericBase<Struct>)}:{expect}", CreateMessage<string>(a, expect));
232-
Assert.Equal($"{nameof(GenericBase<Struct>)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
285+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:1", CreateMessage<int>(a, 1));
286+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{expect}", CreateMessage<string>(a, expect));
287+
Assert.Equal($"{nameof(GenericBase<Struct>)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
233288
}
234289
{
235290
Derived1 a = new();
236-
Assert.Equal($"{nameof(Derived1)}:1", CreateMessage<int>(a, 1));
237-
Assert.Equal($"{nameof(Derived1)}:{expect}", CreateMessage<string>(a, expect));
238-
Assert.Equal($"{nameof(Derived1)}:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
291+
Assert.Equal($"{nameof(Derived1)}<>:1", CreateMessage<int>(a, 1));
292+
Assert.Equal($"{nameof(Derived1)}<>:{expect}", CreateMessage<string>(a, expect));
293+
Assert.Equal($"{nameof(Derived1)}<>:{nameof(Struct)}", CreateMessage<Struct>(a, new Struct()));
239294
}
240295
{
241296
// Verify resolution of generic override logic.
@@ -245,7 +300,7 @@ public static void Verify_Generic_InheritanceMethodResolution()
245300
Assert.Equal($"{nameof(GenericBase<string>)}:{expect}", Accessors<string>.CreateMessage(a2, expect));
246301
}
247302

248-
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessageGeneric")]
303+
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessage")]
249304
extern static string CreateMessage<W>(Base b, W w);
250305
}
251306

0 commit comments

Comments
 (0)