dotnet/roslyn

Consider improving diagnostics when all equally specific implementation candidates are re-abstractions

Open

#35,915 opened on May 23, 2019

View on GitHub
 (0 comments) (0 reactions) (0 assignees)C# (4,257 forks)batch import
Area-CompilersBugConcept-Diagnostic ClarityFeature - Default Interface Implhelp wanted

Repository metrics

Stars
 (20,414 stars)
PR merge metrics
 (Avg merge 6d 17h) (256 merged PRs in 30d)

Description

        [Fact]
        public void MethodReAbstraction_09()
        {
            var source1 =
@"
public interface I1
{
    void M1() {} 
}

public interface I2 : I1
{
    abstract void I1.M1();
}

public interface I3 : I1
{
    abstract void I1.M1();
}
";

            var source2 =
@"
class Test1 : I2, I3
{
}
";
            ValidateMethodReAbstraction_09(source1, source2);
        }

        private void ValidateMethodReAbstraction_09(string source1, string source2)
        {
            var compilation1 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll,
                                                 parseOptions: TestOptions.Regular,
                                                 targetFramework: TargetFramework.NetStandardLatest);
            validate(compilation1.SourceModule);

            var expected = new DiagnosticDescription[]
                {
                    // (2,15): error CS8705: Interface member 'I1.M1()' does not have a most specific implementation. Neither 'I2.I1.M1()', nor 'I3.I1.M1()' are most specific.
                    // class Test1 : I2, I3
                    Diagnostic(ErrorCode.ERR_MostSpecificImplementationIsNotFound, "I2").WithArguments("I1.M1()", "I2.I1.M1()", "I3.I1.M1()").WithLocation(2, 15)
                };

            compilation1.VerifyDiagnostics(expected);

            var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll,
                                                 parseOptions: TestOptions.Regular,
                                                 targetFramework: TargetFramework.NetStandardLatest);
            compilation2.VerifyDiagnostics();

            foreach (var reference in new[] { compilation2.ToMetadataReference(), compilation2.EmitToImageReference() })
            {
                var compilation3 = CreateCompilation(source2, options: TestOptions.DebugDll, references: new[] { reference },
                                                     parseOptions: TestOptions.Regular,
                                                     targetFramework: TargetFramework.NetStandardLatest);
                validate(compilation3.SourceModule);
                compilation3.VerifyDiagnostics(expected);
            }

            static void validate(ModuleSymbol m)
            {
                var test1 = m.GlobalNamespace.GetTypeMember("Test1");
                var i1m1 = test1.InterfacesNoUseSiteDiagnostics().First().ContainingNamespace.GetTypeMember("I1").GetMember<MethodSymbol>("M1");
                Assert.Equal("void I1.M1()", i1m1.ToTestDisplayString());

                Assert.Null(test1.FindImplementationForInterfaceMember(i1m1));
            }
        }

Observed:

                    // (2,15): error CS8705: Interface member 'I1.M1()' does not have a most specific implementation. Neither 'I2.I1.M1()', nor 'I3.I1.M1()' are most specific.
                    // class Test1 : I2, I3
                    Diagnostic(ErrorCode.ERR_MostSpecificImplementationIsNotFound, "I2").WithArguments("I1.M1()", "I2.I1.M1()", "I3.I1.M1()").WithLocation(2, 15)

Suggested: Perhaps we should simply say that I1.M1() is not implemented as long as all conflicting candidates are re-abstractions.

Contributor guide