Skip to content
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

[mono][metadata] Fixes for static virtual methods with interface variance #91664

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

BrzVlad
Copy link
Member

@BrzVlad BrzVlad commented Sep 6, 2023

Fixes #88689
Contributes to #49904

…rent class first

When we lookup the vtable slot for a generic interface method, we first go through the set of implemented interfaces in the klass and look for an exact match. If the klass is not implementing this exact interface, we then look for any interface implementation that is variant compatible. Before this change we were iterating starting from the base implementations which is incorrect. We now iterate starting from the interfaces explicitly implemented by the most derived type (matching first interface in declaration order) and then continuing with the base types.

Scenario covered in ComplexHierarchyPositive.cs
…aces

As an example from the now enabled test.

```
interface InterfaceScenario2<in T> {
	static abstract int Method ();
}

class BaseScenario2 : InterfaceScenario2<string, InterfaceScenario2<object> {
	public static int Method() {
//		.override method int32 class InterfaceScenario2`1<string>::Method()
		return 2;
	}

	public static int32 Method_Obj() {
//		.override method int32 class InterfaceScenario2`1<object>::Method()
		return 3;
	}
}

class DerivedScenario2 : BaseScenario2 {
	public static int Method () {
//		.override method int32 class InterfaceScenario2`1<object>::Method()
		return 6;
	}
}

public static string Test_Scenario2_1<T, ImplType>() where ImplType : InterfaceScenario2<T> {
	return ImplType.Method ().ToString ();
}

Test_Scenario2_1<string, DerivedScenario2> ());
```

This test calls InterfaceScenario2<string> on DerviedScenario2. This should call DerivedScenario2.Method (not BaseScenario2.Method) because this method overrides (in BaseScenario2) both the obvious slot for InterfaceScenario2<object> as well as the slot for variant compatible interface InterfaceScenario2<string>.
@SamMonoRT
Copy link
Member

/azp run runtime-extra-platforms

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@BrzVlad
Copy link
Member Author

BrzVlad commented Oct 5, 2023

@lambdageek Could you take a look at this ?

@kg
Copy link
Member

kg commented Jul 9, 2024

The actual algorithm and everything look right here, but I'm concerned that applying the variance at the vtable level is wrong as a general approach, since the spec seems to require the check to be done at call sites. Or does every specific generic instantiation of a given interface have its own slot in every class's vtable? I was under the impression that wasn't true, and that was part of the motivation for the IMT in minijit.

On the other hand, for the specific scenario of static virtual methods, the vtable approach seems like it's probably safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Variant static interface dispatch behaves incorrectly on Mono
3 participants