Skip to content

Dispose extension methods should not even be considered in pattern-based disposal #32767

@jcouv

Description

@jcouv

Currently, we bind x.Dispose() and reject the result if it is an extension. But we should not even consider extensions, to avoid diagnostics about ambiguities.

There is the same issue with binding GetAsyncEnumerator.

        [Fact]
        public void UsingPatternScopedExtensionMethodTest()
        {
            var source = @"
ref struct S1
{
}

namespace N1
{
    static class C2 
    {
        public static void Dispose(this S1 s1) { }
    }
}

namespace N2
{
    static class C3 
    {
        public static void Dispose(this S1 s1) { }
    }
}

namespace N3
{
    static class C4 
    {
        public static int Dispose(this S1 s1) { return 0; }
    }
}


namespace N4
{
    partial class C5
    {
        static void M()
        {
            using (S1 s = new S1()) // error 1
            {
            }
        }
    }
}
namespace N4
{
    using N1;
    partial class C5
    {
        static void M2()
        {
            using (S1 s = new S1()) // error 2
            {
            }
        }
    }
}
namespace N4
{
    using N3;
    partial class C5
    {
        static void M3()
        {
            using (S1 s = new S1()) // error 3
            {
            }
        }
    }
}
namespace N4
{
    using N1;
    using N3;
    partial class C5
    {
        static void M4()
        {
            using (S1 s = new S1())  // error 4
            {
            }
        }
    }
}
namespace N4
{
    using N3;
    namespace N5
    {
        partial class C5
        {
            static void M5()
            {
                using (S1 s = new S1())  // error 5 
                {
                }
            }
        }

        namespace N6
        {
            using N1;
            partial class C5
            {
                static void M6()
                {
                    using (S1 s = new S1())  // error 6 
                    { 
                    }
                }
            }
        }
    }
}";
            // Extension methods should just be ignored, rather than rejected after-the-fact. So there should be no error about ambiguities

            CreateCompilation(source).VerifyDiagnostics(
                // (37,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 1
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(37, 20),
                // (50,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 2
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(50, 20),
                // (63,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 3
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(63, 20),
                // (77,20): error CS0121: The call is ambiguous between the following methods or properties: 'N1.C2.Dispose(S1)' and 'N3.C4.Dispose(S1)'
                //             using (S1 s = new S1())  // error 4
                Diagnostic(ErrorCode.ERR_AmbigCall, "S1 s = new S1()").WithArguments("N1.C2.Dispose(S1)", "N3.C4.Dispose(S1)").WithLocation(77, 20),
                // (77,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1())  // error 4
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(77, 20),
                // (92,24): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //                 using (S1 s = new S1())  // error 5 
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(92, 24),
                // (105,28): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //                     using (S1 s = new S1())  // error 6 
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(105, 28)
                );
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions