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] Check for additional implemented variant interfaces #57086

Merged
merged 4 commits into from
Aug 17, 2021

Conversation

lambdageek
Copy link
Member

If a class implements a variant interface, consider whether it is explicitly implementing (as opposed to obtaining by being a subclass of some base class) some variant interfaces.

Two examples:

public interface IFactory<out T> { T Get(); }
public class Foo {}
public class Bar : Foo {}
public class FooFactory : IFactory<Foo> { public Foo Get() => new Foo(); }
public class BarFactory : FooFactory, IFactory<Bar> { public new Bar Get() => new Bar(); }

In this case, BarFactory explicitly implements IFactory<Bar> and also IFactory<Foo>.

Conversely for contravariant gparams:

interface ITaker<in T> { string Consume (T x); }
class Foo {}
class Bar : Foo {}
class BarTaker : ITaker<Bar> { public string Consume (Bar x) => "consumed Bar"; }
class FooTaker : BarTaker, ITaker<Foo> { public string Consume (Foo x) => "consumed Foo"; }

In this case FooTaker implements ITaker<Foo> but alsoITaker<Bar>.

When this happens, the signature of the implementing method 'Bar BarFactory:Get()' doesn't match the signature of the implemented interface method 'Foo IFactory<Foo>:Get()'.

We should check the signature parameters of the candidate method and the implemented method, but I think the interface setup code already checks this for us.

Fixes #48512

@ghost
Copy link

ghost commented Aug 9, 2021

Tagging subscribers to this area:
See info in area-owners.md if you want to be subscribed.

Issue Details

If a class implements a variant interface, consider whether it is explicitly implementing (as opposed to obtaining by being a subclass of some base class) some variant interfaces.

Two examples:

public interface IFactory<out T> { T Get(); }
public class Foo {}
public class Bar : Foo {}
public class FooFactory : IFactory<Foo> { public Foo Get() => new Foo(); }
public class BarFactory : FooFactory, IFactory<Bar> { public new Bar Get() => new Bar(); }

In this case, BarFactory explicitly implements IFactory<Bar> and also IFactory<Foo>.

Conversely for contravariant gparams:

interface ITaker<in T> { string Consume (T x); }
class Foo {}
class Bar : Foo {}
class BarTaker : ITaker<Bar> { public string Consume (Bar x) => "consumed Bar"; }
class FooTaker : BarTaker, ITaker<Foo> { public string Consume (Foo x) => "consumed Foo"; }

In this case FooTaker implements ITaker<Foo> but alsoITaker<Bar>.

When this happens, the signature of the implementing method 'Bar BarFactory:Get()' doesn't match the signature of the implemented interface method 'Foo IFactory<Foo>:Get()'.

We should check the signature parameters of the candidate method and the implemented method, but I think the interface setup code already checks this for us.

Fixes #48512

Author: lambdageek
Assignees: -
Labels:

area-VM-meta-mono

Milestone: -

@lambdageek
Copy link
Member Author

Test failures are related. I think I'm trashing some unrelated vtable entries. May need a signature check after all.

@lambdageek lambdageek marked this pull request as draft August 10, 2021 18:10
…ing variant interfaces

If a class implements a variant interface, consider whether it is explicitly
implementing (as opposed to obtaining by being a subclass of some base class)
some variant interfaces.

Two examples:
public interface IFactory<out T> { T Get(); }
public class Foo {}
public class Bar : Foo {}
public class FooFactory : IFactory<Foo> { public Foo Get() => new Foo(); }
public class BarFactory : FooFactory, IFactory<Bar> { public new Bar Get() => new Bar(); }

In this case, BarFactory explicitly implements IFactory<Bar> and also
IFactory<Foo>.

Conversely for contravariant gparams:
interface ITaker<in T> { string Consume (T x); }
class Foo {}
class Bar : Foo {}
class BarTaker : ITaker<Bar> { public string Consume (Bar x) => "consumed Bar"; }
class FooTaker : BarTaker, ITaker<Foo> { public string Consume (Foo x) =>
"consumed Foo"; }

In this case FooTaker implements ITaker<Foo> but also ITaker<Bar>.

When this happens, the signature of the implementing method 'Bar
BarFactory:Get()' doesn't match the signature of the implemented interface
method 'Foo IFactory<Foo>:Get()'.

We should check the signature parameters of the candidate method and the
implemented method, but I think the interface setup code already checks this
for us.

Fixes dotnet#48512
@lambdageek lambdageek marked this pull request as ready for review August 17, 2021 02:17
@lambdageek
Copy link
Member Author

@vargaz @thaystg could you review? In particular, I'm not sure if this is too risky of a hack - I'm not sure if this is close to what the ECMA spec says to do for variant generics.

@lambdageek lambdageek merged commit eeee548 into dotnet:main Aug 17, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Sep 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Mono] Invalid covariant interface calls
2 participants