From 25bd2538fe95f9f67bea8e24204a5fdcb09277fb Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Tue, 5 Sep 2023 18:27:45 +0300 Subject: [PATCH] [mono][metadata] Fix overriding of methods from parent variant interfaces As an example from the now enabled test. ``` interface InterfaceScenario2 { static abstract int Method (); } class BaseScenario2 : InterfaceScenario2 { public static int Method() { // .override method int32 class InterfaceScenario2`1::Method() return 2; } public static int32 Method_Obj() { // .override method int32 class InterfaceScenario2`1::Method() return 3; } } class DerivedScenario2 : BaseScenario2 { public static int Method () { // .override method int32 class InterfaceScenario2`1::Method() return 6; } } public static string Test_Scenario2_1() where ImplType : InterfaceScenario2 { return ImplType.Method ().ToString (); } Test_Scenario2_1 ()); ``` This test calls InterfaceScenario2 on DerviedScenario2. This should call DerivedScenario2.Method (not BaseScenario2.Method) because this method overrides (in BaseScenario2) both the obvious slot for InterfaceScenario2 as well as the slot for variant compatible interface InterfaceScenario2. --- src/mono/mono/metadata/class-setup-vtable.c | 32 +++++++++++++++++++++ src/tests/issues.targets | 3 -- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index 9a235c1ec0cce..7304b0965f46c 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -1035,6 +1035,37 @@ apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable return TRUE; } +/* + * Interface method `decl` is overridden in `klass` with `override`. In addition to overriding the method slot + * for this interface method, if parent klass implements a different variant compatible interface, then we also + * need to override the correpsonding method slot in this other interface. + */ +static void +apply_override_variant_interface (MonoClass *klass, MonoMethod *decl, MonoMethod *override, MonoMethod **vtable) +{ + MonoClass *parent = klass->parent; + + // This handles variant overrides for static virtual methods only + if (!m_method_is_static (decl)) + return; + + if (mono_class_has_variant_generic_params (decl->klass) && parent) { + for (int k = 0; k < klass->parent->interface_offsets_count; k++) { + MonoClass *impl_itf = parent->interfaces_packed [k]; + if (decl->klass != impl_itf && + mono_class_has_variant_generic_params (impl_itf) && + mono_class_get_generic_type_definition (impl_itf) == mono_class_get_generic_type_definition (decl->klass)) { + if (mono_class_is_variant_compatible (impl_itf, decl->klass, FALSE)) { + int vt_slot = parent->interface_offsets_packed [k] + decl->slot; + vtable [vt_slot] = override; + TRACE_INTERFACE_VTABLE (printf ("\tvariance override slot %d with method %s\n", vt_slot, mono_method_full_name (override, TRUE))); + break; + } + } + } + } +} + static void handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map) { @@ -1788,6 +1819,7 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o g_assert (override->klass == klass); if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map)) goto fail; + apply_override_variant_interface (klass, decl, override, vtable); } } diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 5c148db7b67ce..516a9ec21ca89 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1294,9 +1294,6 @@ https://github.com/dotnet/runtime/issues/80350 - - Static virtual methods are not yet implemented in the Mono runtime. - Static virtual methods are not yet implemented in the Mono runtime.