-
Notifications
You must be signed in to change notification settings - Fork 5.1k
[mono] Skip exact interface matches when an interface has variance #103757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a8ba321
5c1716e
d2ab21f
45c88da
67ec69e
59e7b6b
0290301
88a8440
adcf3b3
c65f1e0
9504318
5264714
f7324cd
c7dfe4b
8bd5929
235ed52
2292aff
e5fdca9
ff1138c
90b90e5
c01da2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1946,21 +1946,25 @@ mono_class_interface_offset (MonoClass *klass, MonoClass *itf) | |
int | ||
mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) | ||
{ | ||
int i = mono_class_interface_offset (klass, itf); | ||
gboolean has_variance = mono_class_has_variant_generic_params (itf); | ||
int exact_match = mono_class_interface_offset (klass, itf), i = -1; | ||
*non_exact_match = FALSE; | ||
if (i >= 0) | ||
return i; | ||
|
||
if (exact_match >= 0) { | ||
if (!has_variance) | ||
return exact_match; | ||
} | ||
|
||
int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass); | ||
|
||
if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) { | ||
if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) { | ||
MonoClass *gtd = mono_class_get_generic_type_definition (itf); | ||
int found = -1; | ||
|
||
for (i = 0; i < klass_interface_offsets_count; i++) { | ||
if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) { | ||
found = i; | ||
*non_exact_match = TRUE; | ||
*non_exact_match = (i != exact_match); | ||
break; | ||
} | ||
|
||
|
@@ -1971,7 +1975,7 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo | |
for (i = 0; i < klass_interface_offsets_count; i++) { | ||
if (mono_class_get_generic_type_definition (m_class_get_interfaces_packed (klass) [i]) == gtd) { | ||
found = i; | ||
*non_exact_match = TRUE; | ||
*non_exact_match = (i != exact_match); | ||
break; | ||
} | ||
} | ||
|
@@ -1980,16 +1984,45 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo | |
return -1; | ||
|
||
return m_class_get_interface_offsets_packed (klass) [found]; | ||
} | ||
} else if (has_variance) { | ||
MonoClass **vst; | ||
int vst_count; | ||
MonoClass *current = klass; | ||
|
||
// Perform two passes per class, then check the base class | ||
while (current) { | ||
mono_class_get_variance_search_table (current, &vst, &vst_count); | ||
|
||
// Exact match pass: Is there an exact match at this level of the type hierarchy? | ||
// If so, we can use the interface_offset we computed earlier, since we're walking from most derived to least. | ||
for (i = 0; i < vst_count; i++) { | ||
if (itf != vst [i]) | ||
continue; | ||
|
||
*non_exact_match = FALSE; | ||
return exact_match; | ||
} | ||
|
||
if (!mono_class_has_variant_generic_params (itf)) | ||
return -1; | ||
// Inexact match (variance) pass: | ||
// Is any interface at this level of the type hierarchy variantly compatible with the desired interface? | ||
// If so, select the first compatible one we find. | ||
for (i = 0; i < vst_count; i++) { | ||
if (!mono_class_is_variant_compatible (itf, vst [i], FALSE)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: how is this variance search table different from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The variance search table should be smaller. I can try to figure out whether we can get rid of interfaces_packed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two examples of what I was thinking in action:
|
||
continue; | ||
|
||
for (i = 0; i < klass_interface_offsets_count; i++) { | ||
if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) { | ||
*non_exact_match = TRUE; | ||
return m_class_get_interface_offsets_packed (klass) [i]; | ||
int inexact_match = mono_class_interface_offset (klass, vst[i]); | ||
g_assert (inexact_match != exact_match); | ||
*non_exact_match = TRUE; | ||
return inexact_match; | ||
} | ||
|
||
// Now check base class if present | ||
current = m_class_get_parent (current); | ||
} | ||
|
||
// If the variance search failed to find a match, return the exact match search result (probably -1). | ||
*non_exact_match = (exact_match < 0); | ||
return exact_match; | ||
} | ||
|
||
return -1; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
/* | ||
https://github.com/dotnet/runtime/issues/103365 | ||
When using an interface with a generic out type, an explicit implementation, and a derived class, the base classes implementation is called instead of the derived class when running on Mono; CoreCLR has the expected behavior. | ||
*/ | ||
|
||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Runtime.CompilerServices; | ||
using Xunit; | ||
|
||
public interface IBaseInterface<out T> | ||
{ | ||
string explicitDeclaration(); | ||
} | ||
|
||
public class BasicBaseClass : IBaseInterface<BasicBaseClass> | ||
{ | ||
string className = "BasicBaseClass"; | ||
string IBaseInterface<BasicBaseClass>.explicitDeclaration() | ||
{ | ||
return className; | ||
} | ||
} | ||
|
||
public class BasicDerivedClass : BasicBaseClass, IBaseInterface<BasicDerivedClass> | ||
{ | ||
string className = "BasicDerivedClass"; | ||
|
||
string IBaseInterface<BasicDerivedClass>.explicitDeclaration() | ||
{ | ||
return className; | ||
} | ||
} | ||
|
||
public static class Test_Issue103365 | ||
{ | ||
[Fact] | ||
public static void Main () | ||
{ | ||
var instances = new IBaseInterface<BasicBaseClass>[2]; | ||
instances[0] = new BasicBaseClass(); | ||
instances[1] = new BasicDerivedClass(); | ||
Assert.Equal("BasicBaseClass", instances[0].explicitDeclaration()); | ||
Assert.Equal("BasicDerivedClass", instances[1].explicitDeclaration()); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<ItemGroup> | ||
<Compile Include="103365.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" /> | ||
</ItemGroup> | ||
</Project> |
Uh oh!
There was an error while loading. Please reload this page.