This project is read-only.
1
Vote

Incorrect rejection of conversion to IDisposable involving generic type parameter constraint inheritance

description

Here's one for you nikov.

using System;
struct S : IDisposable
{
      public void Dispose() {}
}
class C<T> where T : IDisposable
{
    public virtual void M<U>(U u) where U : T
    {
        using(u) { } // This works just fine.
    }
}
class D : C<S>
{
    public override void M<U>(U u)
    {
        using(u) { } // This fails
    }
}
Desired result: should compile normally.
Acceptable result: should give an informative error message.
Observed result: fails with confusing convertibility error at indicated line.

For those of you reading this issue report who are unfamiliar with this pattern: you can get into all kinds of trouble by causing a method type parameter's constraint to become something specific via this sort of inheritance. The CLR type system has restrictions on what kinds of constraints can be propagated via this sort of inheritance; in particular, a specialization to int[] would be treated as a constraint of System.Array, a specialization to S here is treated a constraint to System.ValueType, and so on.

What is mysterious here though is why the constraint on T to IDisposable is lost when specializing T to S. Surely U in D.M<U> can still be known to be IDisposable.

This repros in every version of C# I've tried from 2.0 on, in Roslyn and in Mono. (Well, in some versions of Mono it crashes the semantic analyzer.) I therefore expect this to be WONT-FIXED, but thought it might be worth the effort.

comments