[dim][regression] Explicit interface override (mono/mono#17583)
authorThays Grazia <thaystg@gmail.com>
Wed, 30 Oct 2019 17:47:15 +0000 (14:47 -0300)
committerGitHub <noreply@github.com>
Wed, 30 Oct 2019 17:47:15 +0000 (14:47 -0300)
* Precedence order:
-> Override interface method in class
-> Method in class
-> DIM

Commit migrated from https://github.com/mono/mono/commit/fffb1201bdd14e18e19a3c61d0afe25a91a2d501

src/mono/mono/metadata/class-init.c
src/mono/mono/tests/Makefile.am
src/mono/mono/tests/interface-2.cs [new file with mode: 0644]

index 0cebac9..1d13536 100644 (file)
@@ -3100,7 +3100,6 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                // Loop on all interface methods...
                int mcount = mono_class_get_method_count (ic);
                for (im_index = 0; im_index < mcount; im_index++) {
-                       gboolean foundOverrideInClassOrParent = FALSE;
                        MonoMethod *im = ic->methods [im_index];
                        int im_slot = ic_offset + im->slot;
                        MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
@@ -3110,41 +3109,17 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
 
                        TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
 
-                       int cm_index;
-                       MonoMethod *cm;
-
-                       // First look for a suitable method among the class methods
-                       for (l = virt_methods; l; l = l->next) {
-                               cm = (MonoMethod *)l->data;
-                               TRACE_INTERFACE_VTABLE (printf ("    For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
-                               if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
-                                       TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
-                                       vtable [im_slot] = cm;
-                                       foundOverrideInClassOrParent = TRUE;
-                                       /* Why do we need this? */
-                                       if (cm->slot < 0) {
-                                               cm->slot = im_slot;
-                                       }
-                                       if (conflict_map)
-                                               g_hash_table_remove(conflict_map, im);
-                               }
-                               TRACE_INTERFACE_VTABLE (printf ("\n"));
-                               if (mono_class_has_failure (klass))  /*Might be set by check_interface_method_override*/
-                                       goto fail;
-                       }
-                       
-                       // If the slot is still empty, look in all the inherited virtual methods...
-                       if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
-                               MonoClass *parent = klass->parent;
-                               // Reverse order, so that last added methods are preferred
-                               for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
-                                       cm = parent->vtable [cm_index];
-                                       
-                                       TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("    For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
-                                       if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
-                                               TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
+                       if (override_im == NULL || (override_im && MONO_CLASS_IS_INTERFACE_INTERNAL(override_im->klass))) {
+                               int cm_index;
+                               MonoMethod *cm;
+
+                               // First look for a suitable method among the class methods
+                               for (l = virt_methods; l; l = l->next) {
+                                       cm = (MonoMethod *)l->data;
+                                       TRACE_INTERFACE_VTABLE (printf ("    For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
+                                       if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
+                                               TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
                                                vtable [im_slot] = cm;
-                                               foundOverrideInClassOrParent = TRUE;
                                                /* Why do we need this? */
                                                if (cm->slot < 0) {
                                                        cm->slot = im_slot;
@@ -3157,17 +3132,39 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
                                        if (mono_class_has_failure (klass))  /*Might be set by check_interface_method_override*/
                                                goto fail;
                                }
-                       }
+                               
+                               // If the slot is still empty, look in all the inherited virtual methods...
+                               if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
+                                       MonoClass *parent = klass->parent;
+                                       // Reverse order, so that last added methods are preferred
+                                       for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
+                                               MonoMethod *cm = parent->vtable [cm_index];
+                                               
+                                               TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("    For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
+                                               if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
+                                                       TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
+                                                       vtable [im_slot] = cm;
+                                                       /* Why do we need this? */
+                                                       if (cm->slot < 0) {
+                                                               cm->slot = im_slot;
+                                                       }
+                                                       break;
+                                               }
+                                               if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
+                                                       goto fail;
+                                               TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
+                                       }
+                               }
 
-                       if (vtable [im_slot] == NULL) {
-                               if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
-                                       TRACE_INTERFACE_VTABLE (printf ("    Using default iface method %s.\n", mono_method_full_name (im, 1)));
-                                       vtable [im_slot] = im;
+                               if (vtable [im_slot] == NULL) {
+                                       if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
+                                               TRACE_INTERFACE_VTABLE (printf ("    Using default iface method %s.\n", mono_method_full_name (im, 1)));
+                                               vtable [im_slot] = im;
+                                       }
                                }
-                       }
-                       
-                       if (override_im != NULL && !foundOverrideInClassOrParent)
+                       } else {
                                g_assert (vtable [im_slot] == override_im);
+                       }
                }
        }
        
index 6330eff..45871d6 100755 (executable)
@@ -383,6 +383,7 @@ TESTS_CS_SRC=               \
        params.cs               \
        reflection.cs           \
        interface.cs            \
+       interface-2.cs          \
        iface.cs                \
        iface2.cs               \
        iface3.cs               \
diff --git a/src/mono/mono/tests/interface-2.cs b/src/mono/mono/tests/interface-2.cs
new file mode 100644 (file)
index 0000000..185d2a7
--- /dev/null
@@ -0,0 +1,97 @@
+using System;
+
+public interface I1
+{
+    int M1()
+    {
+        return 100;
+    }
+}
+
+public interface I2 : I1 { int I1.M1() { return 200; } }
+
+public interface I3 : I1 { int I1.M1() { return 300; } }
+
+public interface I4 : I1 { int I1.M1() { return 400; } }
+
+class Test10 : I1, I2, I3, I4 {
+    //void I1.M1() { System.Console.WriteLine("I1.I1.M1"); }
+    public int M1() { return 0; }
+}
+
+public interface I1t
+{
+    int M1t()
+    {
+        return 100;
+    }
+}
+
+public interface I2t : I1t { int I1t.M1t() { return 200; } }
+
+public interface I3t : I1t { int I1t.M1t() { return 300; } }
+
+public interface I4t : I1t { int I1t.M1t() { return 400; } }
+
+class Test10t : I1t, I2t, I3t, I4t
+{
+    int I1t.M1t() { return 0; }
+    public int M1t() { return 10; }
+}
+
+
+public interface IName
+{
+       string Name { get; }
+}
+public interface IOther<T>
+{
+       T other { get; }
+       string Name { get; }
+}
+public class Name1 : IName
+{
+       public string Name { get { return "ClassName"; } }
+       string IName.Name { get { return "InterfaceName"; } }
+}
+public class Name2 : IName, IOther<int>
+{
+       public string Name { get { return "ClassName"; } }
+       string IName.Name { get { return "InterfaceName"; } }
+       public int other { get { return 43; } }
+}
+
+public class Test
+{
+       public static int test_0_override()
+       {
+               var name1 = new Name1();
+               var name2 = new Name2();
+               IName iName1 = name1;
+               IName iName2 = name2;
+               if (!iName1.Name.Equals("InterfaceName"))
+                       return 10;
+               if (!iName2.Name.Equals("InterfaceName"))
+                       return 20;
+               if (!name1.Name.Equals("ClassName"))
+                       return 30;
+               if (!name2.Name.Equals("ClassName"))
+                       return 40;
+        return 0;
+       }
+
+       public static int test_0_dim_override()
+       {
+               I1 var = new Test10();
+               if (var.M1() != 0)
+                       return var.M1();
+
+               I1t var2 = new Test10t();
+               return var2.M1t();
+    }
+
+    public static int Main (string[] args) {
+               return TestDriver.RunTests (typeof (Test), args);
+       }
+
+}