/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/AmbiguousOverrideTests.cs
1 406 строк
56 KB
Jan Jones
Disambiguate extension methods in "ambiguous call" error message when they have the same name but are from different assemblies (#80453)
01 окт 2025, 17:26
Не верифицирован
01 окт 2025, 17:26
9eb62b6
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class AmbiguousOverrideTests : CompilingTestBase { [Fact] public void TestAmbiguousNoErrors() { string source = @" using System; public class Base<TLong, TInt> { public virtual void Method(TLong l, int i) { Console.Write(1); } public virtual void Method(long l, TInt i) { Console.Write(2);} } public class Derived<TInt> : Base<long, TInt> { public override void Method(long l, TInt i) { Console.Write(3); } // overrides 2 } public class Derived2 : Derived<int> { public override void Method(long l, int i) { Console.Write(4); } // overrides 2 } class EntryPoint { static void Main() { Base<long, int> b = new Base<long, int>(); CallOne<long>(b); // 1 CallTwo<int>(b); // 2 b = new Derived<int>(); CallOne<long>(b); // 1 CallTwo<int>(b); // 3 b = new Derived2(); CallOne<long>(b); // 1 CallTwo<int>(b); // 4 } static void CallOne<TL>(Base<TL, int> b) { b.Method(default(TL), default(int)); } static void CallTwo<TI>(Base<long, TI> b) { b.Method(default(long), default(TI)); } } "; CompileAndVerify(source, expectedOutput: "121314"); } [WorkItem(544936, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544936")] [Fact] public void TestAmbiguousInvocationError() { var source = @" public class Base<TLong, TInt> { public virtual void Method(TLong l, int i) { } // 1 public virtual void Method(long l, TInt i) { } // 2 } public class Derived<TInt> : Base<long, TInt> { public override void Method(long l, TInt i) { } // overrides 2 } public class Derived2 : Derived<int> { public override void Method(long l, int i) { } // overrides 2 } class EntryPoint { static void Main() { new Derived2().Method(1L, 2); //CS0121 } } "; CreateCompilation(source).VerifyDiagnostics( // (22,24): error CS0121: The call is ambiguous between the following methods or properties: 'Base<long, int>.Method(long, int)' and 'Base<long, int>.Method(long, int)' // new Derived2().Method(1L, 2); //CS0121 Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("Base<long, int>.Method(long, int)", "Base<long, int>.Method(long, int)").WithLocation(22, 24)); } [Fact] public void TestAmbiguousOverrideError() { var text1 = @" public class Base<TLong, TInt> { public virtual void Method(TLong l, int i) { } public virtual void Method(long l, TInt i) { } } "; var text2 = @" public class Derived<TInt> : Base<long, TInt> { public override void Method(long l, TInt i) { } public override void Method(long l, int i) { } } "; var text3 = @" public class Derived2 : Derived<int> { public override void Method(long l, int i) { } //CS0462 and CS1957 } "; var comp1 = CreateCompilation(text1); var comp1ref = new CSharpCompilationReference(comp1); var ref1 = new List<MetadataReference>() { comp1ref }; var comp2 = CreateCompilation(text2, references: ref1, assemblyName: "Test2"); var comp2ref = new CSharpCompilationReference(comp2); var ref2 = new List<MetadataReference>() { comp1ref, comp2ref }; var comp = CreateCompilation(text3, ref2, assemblyName: "Test3"); var diagnostics = comp.GetDiagnostics(); if (comp.Assembly.RuntimeSupportsDefaultInterfaceImplementation) { comp.VerifyDiagnostics( // (4,26): error CS0462: The inherited members 'Derived<TInt>.Method(long, TInt)' and 'Derived<TInt>.Method(long, int)' have the same signature in type 'Derived2', so they cannot be overridden // public override void Method(long l, int i) { } //CS0462 and CS1957 Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Derived<TInt>.Method(long, TInt)", "Derived<TInt>.Method(long, int)", "Derived2").WithLocation(4, 26) ); } else { comp.VerifyDiagnostics( // (4,26): error CS0462: The inherited members 'Derived<TInt>.Method(long, TInt)' and 'Derived<TInt>.Method(long, int)' have the same signature in type 'Derived2', so they cannot be overridden // public override void Method(long l, int i) { } //CS0462 and CS1957 Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Derived<TInt>.Method(long, TInt)", "Derived<TInt>.Method(long, int)", "Derived2").WithLocation(4, 26), // (4,26): warning CS1957: Member 'Derived2.Method(long, int)' overrides 'Derived<int>.Method(long, int)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime. // public override void Method(long l, TInt i) { } Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "Method").WithArguments("Derived<int>.Method(long, int)", "Derived2.Method(long, int)").WithLocation(4, 26) ); } } [Fact] public void TestAmbiguousOverridesFromSameClass() { // Tests: // Through type argument substitution make two base abstract members with same signature (parameters / return types) – // override member in derived class – invoke member in derived class using base.VirtualMember // Test similar case where conflicting members are split across multiple base types var source = @" abstract class Base<T, U> { public virtual void Method(T x) { } public virtual int Method(int y) { return y; } public virtual void Method(U z) { } public virtual void Method(T x, U y) { } public abstract void Method(U y, T x); } class Derived : Base<int, int> { public override void Method(int a) { } public override void Method(int a, int b) { } void Test() { base.Method(1); base.Method(1, 1); } } abstract class Derived2 : Base<int, long> { public override void Method(int a, long b) { } } "; var comp = CreateCompilation(source); if (comp.Assembly.RuntimeSupportsDefaultInterfaceImplementation) { comp.VerifyDiagnostics( // (15,26): error CS0462: The inherited members 'Base<T, U>.Method(T, U)' and 'Base<T, U>.Method(U, T)' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(int a, int b) Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(T, U)", "Base<T, U>.Method(U, T)", "Derived").WithLocation(15, 26), // (12,26): error CS0462: The inherited members 'Base<T, U>.Method(T)' and 'Base<T, U>.Method(int)' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(int a) Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(T)", "Base<T, U>.Method(int)", "Derived").WithLocation(12, 26), // (10,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base<int, int>.Method(int, int)' // class Derived : Base<int, int> Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base<int, int>.Method(int, int)").WithLocation(10, 7), // (21,14): error CS0121: The call is ambiguous between the following methods or properties: 'Base<T, U>.Method(T, U)' and 'Base<T, U>.Method(U, T)' // base.Method(1, 1); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("Base<T, U>.Method(T, U)", "Base<T, U>.Method(U, T)").WithLocation(21, 14) ); } else { comp.VerifyDiagnostics( // (15,26): error CS0462: The inherited members 'Base<T, U>.Method(T, U)' and 'Base<T, U>.Method(U, T)' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(int a, int b) Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(T, U)", "Base<T, U>.Method(U, T)", "Derived").WithLocation(15, 26), // (7,25): warning CS1957: Member 'Derived.Method(int, int)' overrides 'Base<int, int>.Method(int, int)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime. // public virtual void Method(T x, U y) { } Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "Method").WithArguments("Base<int, int>.Method(int, int)", "Derived.Method(int, int)").WithLocation(7, 25), // (12,26): error CS0462: The inherited members 'Base<T, U>.Method(T)' and 'Base<T, U>.Method(int)' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(int a) Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(T)", "Base<T, U>.Method(int)", "Derived").WithLocation(12, 26), // (4,25): warning CS1957: Member 'Derived.Method(int)' overrides 'Base<int, int>.Method(int)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime. // public virtual void Method(T x) { } Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "Method").WithArguments("Base<int, int>.Method(int)", "Derived.Method(int)").WithLocation(4, 25), // (10,7): error CS0534: 'Derived' does not implement inherited abstract member 'Base<int, int>.Method(int, int)' // class Derived : Base<int, int> Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base<int, int>.Method(int, int)").WithLocation(10, 7), // (21,14): error CS0121: The call is ambiguous between the following methods or properties: 'Base<int, int>.Method(int, int)' and 'Base<int, int>.Method(int, int)' // base.Method(1, 1); Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("Base<int, int>.Method(int, int)", "Base<int, int>.Method(int, int)").WithLocation(21, 14) ); } } [Fact] public void TestAmbiguousOverridesParams() { // Tests: // Test that we continue to report errors / warnings even when ambiguous base methods that we are trying to // override only differ by params var source = @" using System.Collections.Generic; abstract class Base<T, U> { public virtual void Method(List<T> x, params List<U>[] y) { } public virtual void Method(List<U> y, List<T>[] x) { } } class Derived : Base<int, int> { public override void Method(List<int> x, List<int>[] y) { } }"; CSharpCompilation comp = CreateCompilation(source); if (comp.Assembly.RuntimeSupportsDefaultInterfaceImplementation) { comp.VerifyDiagnostics( // (10,26): error CS0462: The inherited members 'Base<T, U>.Method(List<T>, params List<U>[])' and 'Base<T, U>.Method(List<U>, List<T>[])' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(List<int> x, List<int>[] y) { } Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(System.Collections.Generic.List<T>, params System.Collections.Generic.List<U>[])", "Base<T, U>.Method(System.Collections.Generic.List<U>, System.Collections.Generic.List<T>[])", "Derived").WithLocation(10, 26) ); } else { comp.VerifyDiagnostics( // (10,26): error CS0462: The inherited members 'Base<T, U>.Method(List<T>, params List<U>[])' and 'Base<T, U>.Method(List<U>, List<T>[])' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(List<int> x, List<int>[] y) { } Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(System.Collections.Generic.List<T>, params System.Collections.Generic.List<U>[])", "Base<T, U>.Method(System.Collections.Generic.List<U>, System.Collections.Generic.List<T>[])", "Derived").WithLocation(10, 26), // (5,25): warning CS1957: Member 'Derived.Method(List<int>, params List<int>[])' overrides 'Base<int, int>.Method(List<int>, params List<int>[])'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime. // public virtual void Method(List<T> x, params List<U>[] y) { } Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "Method").WithArguments("Base<int, int>.Method(System.Collections.Generic.List<int>, params System.Collections.Generic.List<int>[])", "Derived.Method(System.Collections.Generic.List<int>, params System.Collections.Generic.List<int>[])").WithLocation(5, 25) ); } } [Fact] public void TestAmbiguousOverridesOptionalParameters() { // Tests: // Test that we continue to report errors / warnings even when ambiguous base methods that we are trying to // override only differ by optional parameters var source = @" using System.Collections.Generic; abstract class Base<T, U> { public virtual void Method(List<T> x, List<U>[] y=null) { } public virtual void Method(List<U> y, List<T>[] x) { } } class Derived : Base<int, int> { public override void Method(List<int> x, List<int>[] y=null) { } }"; CSharpCompilation comp = CreateCompilation(source); if (comp.Assembly.RuntimeSupportsDefaultInterfaceImplementation) { comp.VerifyDiagnostics( // (10,26): error CS0462: The inherited members 'Base<T, U>.Method(List<T>, List<U>[])' and 'Base<T, U>.Method(List<U>, List<T>[])' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(List<int> x, List<int>[] y=null) { } Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(System.Collections.Generic.List<T>, System.Collections.Generic.List<U>[])", "Base<T, U>.Method(System.Collections.Generic.List<U>, System.Collections.Generic.List<T>[])", "Derived").WithLocation(10, 26) ); } else { comp.VerifyDiagnostics( // (10,26): error CS0462: The inherited members 'Base<T, U>.Method(List<T>, List<U>[])' and 'Base<T, U>.Method(List<U>, List<T>[])' have the same signature in type 'Derived', so they cannot be overridden // public override void Method(List<int> x, List<int>[] y=null) { } Diagnostic(ErrorCode.ERR_AmbigOverride, "Method").WithArguments("Base<T, U>.Method(System.Collections.Generic.List<T>, System.Collections.Generic.List<U>[])", "Base<T, U>.Method(System.Collections.Generic.List<U>, System.Collections.Generic.List<T>[])", "Derived").WithLocation(10, 26), // (5,25): warning CS1957: Member 'Derived.Method(List<int>, List<int>[])' overrides 'Base<int, int>.Method(List<int>, List<int>[])'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime. // public virtual void Method(List<T> x, List<U>[] y=null) { } Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "Method").WithArguments("Base<int, int>.Method(System.Collections.Generic.List<int>, System.Collections.Generic.List<int>[])", "Derived.Method(System.Collections.Generic.List<int>, System.Collections.Generic.List<int>[])").WithLocation(5, 25) ); } } [Fact] public void TestAmbiguousMethodsWithCustomModifiers() { var text = @"using Metadata; public class Test { void Test1() { LeastModoptsWinAmbiguous obj = new LeastModoptsWin(); obj.M(obj.GetByte(), 121); // CS0121 } } "; var asm = TestReferences.SymbolsTests.CustomModifiers.ModoptTests; CreateCompilation(text, new[] { asm }).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("Metadata.LeastModoptsWinAmbiguous.M(byte, byte)", "Metadata.LeastModoptsWinAmbiguous.M(byte, byte)") ); } /// <summary> /// Dev10 gives errors if all properties contain modopt, but no error for methods (pick the one with least modopt) /// </summary> [Fact] public void TestAmbiguousPropertiesWithCustomModifiers() { var text = @"using Metadata; public class Test { void Test1() { ModoptPropAmbiguous obj = new ModoptPropAmbiguous(); System.Console.Write(obj.P); // CS0229 } } "; var asm = TestReferences.SymbolsTests.CustomModifiers.ModoptTests; CreateCompilation(text, new[] { asm }).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_AmbigMember, "P").WithArguments("Metadata.ModoptPropAmbiguous.P", "Metadata.ModoptPropAmbiguous.P") ); } [Fact] public void TestImplicitImplementInterfaceMethodsWithCustomModifiers() { var text = @"using Metadata; public class CFoo : IFooAmbiguous<string, long> // CS0535 { public long M(string t) { return 127; } } class CBar : IFoo // CS0535 * 2 { public sbyte M1<T, V>(T t, V v) { return 123; } } "; var asm = TestReferences.SymbolsTests.CustomModifiers.ModoptTests; CreateCompilation(text, new[] { asm }).VerifyDiagnostics( // (7,14): error CS0535: 'CBar' does not implement interface member 'IFoo.M<T>(T)' // class CBar : IFoo // CS0535 * 2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IFoo").WithArguments("CBar", "Metadata.IFoo.M<T>(T)").WithLocation(7, 14), // (7,14): error CS0535: 'CBar' does not implement interface member 'IFoo.M<T>(T)' // class CBar : IFoo // CS0535 * 2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IFoo").WithArguments("CBar", "Metadata.IFoo.M<T>(T)").WithLocation(7, 14), // (4,17): error CS0570: 'IFooAmbiguous<T, R>.M(T)' is not supported by the language // public long M(string t) { return 127; } Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("Metadata.IFooAmbiguous<T, R>.M(T)").WithLocation(4, 17) ); } [WorkItem(540518, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540518")] [Fact] public void TestExplicitImplementInterfaceMethodsWithCustomModifiers() { var text = @"using Metadata; public class CFoo : IFooAmbiguous<string, long> // CS0535 *2 { long IFooAmbiguous<string, long>.M(string t) { return -128; } // W CS0437 } "; var asm = TestReferences.SymbolsTests.CustomModifiers.ModoptTests; CreateCompilation(text, new[] { asm }).VerifyDiagnostics( // (4,38): warning CS0473: Explicit interface implementation 'CFoo.IFooAmbiguous<string, long>.M(string)' matches more than one interface member. Which interface member is actually chosen is implementation-dependent. Consider using a non-explicit implementation instead. // long IFooAmbiguous<string, long>.M(string t) { return -128; } // W CS0437 Diagnostic(ErrorCode.WRN_ExplicitImplCollision, "M").WithArguments("CFoo.Metadata.IFooAmbiguous<string, long>.M(string)").WithLocation(4, 38), // (4,38): warning CS0473: Explicit interface implementation 'CFoo.IFooAmbiguous<string, long>.M(string)' matches more than one interface member. Which interface member is actually chosen is implementation-dependent. Consider using a non-explicit implementation instead. // long IFooAmbiguous<string, long>.M(string t) { return -128; } // W CS0437 Diagnostic(ErrorCode.WRN_ExplicitImplCollision, "M").WithArguments("CFoo.Metadata.IFooAmbiguous<string, long>.M(string)").WithLocation(4, 38), // (2,21): error CS0535: 'CFoo' does not implement interface member 'IFooAmbiguous<string, long>.M(string)' // public class CFoo : IFooAmbiguous<string, long> // CS0535 *2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IFooAmbiguous<string, long>").WithArguments("CFoo", "Metadata.IFooAmbiguous<string, long>.M(string)").WithLocation(2, 21), // (2,21): error CS0535: 'CFoo' does not implement interface member 'IFooAmbiguous<string, long>.M(string)' // public class CFoo : IFooAmbiguous<string, long> // CS0535 *2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "IFooAmbiguous<string, long>").WithArguments("CFoo", "Metadata.IFooAmbiguous<string, long>.M(string)").WithLocation(2, 21), // (4,38): error CS0570: 'IFooAmbiguous<T, R>.M(T)' is not supported by the language // long IFooAmbiguous<string, long>.M(string t) { return -128; } // W CS0437 Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("Metadata.IFooAmbiguous<T, R>.M(T)").WithLocation(4, 38) ); } [Fact] public void TestDeriveFromClassWithOnlyModreqCustomModifier() { var text = @"using Metadata; class Test { // Modreg has one method 'M' with modreg on it class D : Modreq { } static void Main() { new D().M(11); // Dev10: error CS0570: 'M' is not supported by the language } } "; var asm = MetadataReference.CreateFromImage(TestResources.SymbolsTests.CustomModifiers.ModoptTests.AsImmutableOrNull()); CreateCompilation(text, new[] { asm }).VerifyDiagnostics( // (11,17): error CS0570: 'Modreq.M(uint)' is not supported by the language // new D().M(11); // Dev10: error CS0570: 'M' is not supported by the language Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("Metadata.Modreq.M(uint)").WithLocation(11, 17) ); } [Fact] public void TestOverrideMethodWithModreqCustomModifier() { var text = @"using System; using Metadata; class Test { // Modreq has one virtual method 'M' with modreq on it class D : Modreq { public override void M(uint x) { Console.Write(x + 1); } // CS0115 } static void Main() { new D().M(22); } } "; var asm = TestReferences.SymbolsTests.CustomModifiers.ModoptTests; CreateCompilation(text, new[] { asm }).VerifyDiagnostics( // (8,30): error CS0570: 'Modreq.M(uint)' is not supported by the language // public override void M(uint x) { Console.Write(x + 1); } // CS0115 Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("Metadata.Modreq.M(uint)").WithLocation(8, 30)); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideMethod_FewestCustomModifiers_BothCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig newslot virtual instance void Foo(int32 modopt(int64) x) cil managed { ret } .method public hidebysig newslot virtual instance void Foo(int32 modopt(int64) modopt(int32) x) cil managed { ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } } // end of class Base "; var csharp = @" public class Derived : Base { public override void Foo(int x) { } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); // No diagnostics - just choose the overload with fewer custom modifiers compilation.VerifyDiagnostics(); Func<int, Func<MethodSymbol, bool>> hasCustomModifierCount = c => m => m.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseMethod1 = baseClass.GetMembers("Foo").Cast<MethodSymbol>().Where(hasCustomModifierCount(1)).Single(); var baseMethod2 = baseClass.GetMembers("Foo").Cast<MethodSymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedMethod = derivedClass.GetMember<MethodSymbol>("Foo"); Assert.Equal(baseMethod1, derivedMethod.OverriddenMethod); Assert.NotEqual(baseMethod2, derivedMethod.OverriddenMethod); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideMethod_FewestCustomModifiers_OneCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { // Dev10 chooses to override this method, since it has fewer custom modifiers - // even thought the return type is less correct. .method public hidebysig newslot virtual instance int64 modopt(int64) Foo(int32 x) cil managed { ret } .method public hidebysig newslot virtual instance char modopt(int64) modopt(int32) Foo(int32 x) cil managed { ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } } // end of class Base "; var csharp = @" public class Derived : Base { public override char Foo(int x) { return 'a'; } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); compilation.VerifyDiagnostics( // (4,26): error CS0508: 'Derived.Foo(int)': return type must be 'long' to match overridden member 'Base.Foo(int)' Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "Foo").WithArguments("Derived.Foo(int)", "Base.Foo(int)", "long")); Func<int, Func<MethodSymbol, bool>> hasCustomModifierCount = c => m => m.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseMethod1 = baseClass.GetMembers("Foo").Cast<MethodSymbol>().Where(hasCustomModifierCount(1)).Single(); var baseMethod2 = baseClass.GetMembers("Foo").Cast<MethodSymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedMethod = derivedClass.GetMember<MethodSymbol>("Foo"); Assert.Equal(baseMethod1, derivedMethod.OverriddenMethod); Assert.NotEqual(baseMethod2, derivedMethod.OverriddenMethod); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideProperty_FewestCustomModifiers_BothCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig newslot specialname virtual instance int32 modopt(int64) get_P() cil managed { ldc.i4.0 ret } .method public hidebysig newslot specialname virtual instance int32 modopt(int64) modopt(int32) get_P() cil managed { ldc.i4.0 ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .property instance int32 modopt(int64) P() { .get instance int32 modopt(int64) Base::get_P() } .property instance int32 modopt(int64) modopt(int32) P() { .get instance int32 modopt(int64) modopt(int32) Base::get_P() } } // end of class Base "; var csharp = @" public class Derived : Base { public override int P { get { return 0; } } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); // No diagnostics - just choose the overload with fewer custom modifiers compilation.VerifyDiagnostics(); Func<int, Func<PropertySymbol, bool>> hasCustomModifierCount = c => p => p.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseProperty1 = baseClass.GetMembers("P").Cast<PropertySymbol>().Where(hasCustomModifierCount(1)).Single(); var baseProperty2 = baseClass.GetMembers("P").Cast<PropertySymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedProperty = derivedClass.GetMember<PropertySymbol>("P"); Assert.Equal(baseProperty1, derivedProperty.OverriddenProperty); Assert.NotEqual(baseProperty2, derivedProperty.OverriddenProperty); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideProperty_FewestCustomModifiers_OneCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig newslot specialname virtual instance char modopt(int64) get_P() cil managed { ldc.i4.0 ret } .method public hidebysig newslot specialname virtual instance int32 modopt(int64) modopt(int32) get_P() cil managed { ldc.i4.0 ret } .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } // Dev10 overrides this property - even though the type is worse - // because it has fewer custom modifiers. .property instance char modopt(int64) P() { .get instance char modopt(int64) Base::get_P() } .property instance int32 modopt(int64) modopt(int32) P() { .get instance int32 modopt(int64) modopt(int32) Base::get_P() } } // end of class Base "; var csharp = @" public class Derived : Base { public override int P { get { return 0; } } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); compilation.VerifyDiagnostics( // (4,25): error CS1715: 'Derived.P': type must be 'char' to match overridden member 'Base.P' Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "P").WithArguments("Derived.P", "Base.P", "char")); Func<int, Func<PropertySymbol, bool>> hasCustomModifierCount = c => p => p.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseProperty1 = baseClass.GetMembers("P").Cast<PropertySymbol>().Where(hasCustomModifierCount(1)).Single(); var baseProperty2 = baseClass.GetMembers("P").Cast<PropertySymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedProperty = derivedClass.GetMember<PropertySymbol>("P"); Assert.Equal(baseProperty1, derivedProperty.OverriddenProperty); Assert.NotEqual(baseProperty2, derivedProperty.OverriddenProperty); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideIndexer_FewestCustomModifiers_BothCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = {string('Item')} .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .method public hidebysig newslot specialname virtual instance int32 get_Item(int32 modopt(int64) x) cil managed { ret } .method public hidebysig newslot specialname virtual instance int32 get_Item(int32 modopt(int64) modopt(int32) x) cil managed { ret } .property instance int32 Item(int32 modopt(int64)) { .get instance int32 Base::get_Item(int32 modopt(int64)) } .property instance int32 Item(int32 modopt(int64) modopt(int32)) { .get instance int32 Base::get_Item(int32 modopt(int64) modopt(int32)) } } // end of class Base "; var csharp = @" public class Derived : Base { public override int this[int x] { get { return 0; } } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); // No diagnostics - just choose the overload with fewer custom modifiers compilation.VerifyDiagnostics(); Func<int, Func<PropertySymbol, bool>> hasCustomModifierCount = c => p => p.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseProperty1 = baseClass.Indexers.Where(hasCustomModifierCount(1)).Single(); var baseProperty2 = baseClass.Indexers.Where(hasCustomModifierCount(2)).Single(); Assert.True(baseProperty1.IsIndexer); Assert.True(baseProperty2.IsIndexer); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedProperty = derivedClass.Indexers.Single(); Assert.True(derivedProperty.IsIndexer); Assert.Equal(baseProperty1, derivedProperty.OverriddenProperty); Assert.NotEqual(baseProperty2, derivedProperty.OverriddenProperty); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideIndexer_FewestCustomModifiers_OneCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = {string('Item')} .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .method public hidebysig newslot specialname virtual instance char get_Item(int32 modopt(int64) x) cil managed { ret } .method public hidebysig newslot specialname virtual instance int32 get_Item(int32 modopt(int64) modopt(int32) x) cil managed { ret } // Dev10 overrides this indexer - even though the type is worse - // because it has fewer custom modifiers. .property instance char Item(int32 modopt(int64)) { .get instance char Base::get_Item(int32 modopt(int64)) } .property instance int32 Item(int32 modopt(int64) modopt(int32)) { .get instance int32 Base::get_Item(int32 modopt(int64) modopt(int32)) } } // end of class Base "; var csharp = @" public class Derived : Base { public override int this[int x] { get { return 0; } } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); compilation.VerifyDiagnostics( // (4,25): error CS1715: 'Derived.this[int]': type must be 'char' to match overridden member 'Base.this[int]' Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "this").WithArguments("Derived.this[int]", "Base.this[int]", "char")); Func<int, Func<PropertySymbol, bool>> hasCustomModifierCount = c => p => p.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseProperty1 = baseClass.Indexers.Where(hasCustomModifierCount(1)).Single(); var baseProperty2 = baseClass.Indexers.Where(hasCustomModifierCount(2)).Single(); Assert.True(baseProperty1.IsIndexer); Assert.True(baseProperty2.IsIndexer); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedProperty = derivedClass.Indexers.Single(); Assert.True(derivedProperty.IsIndexer); Assert.Equal(baseProperty1, derivedProperty.OverriddenProperty); Assert.NotEqual(baseProperty2, derivedProperty.OverriddenProperty); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideEvent_FewestCustomModifiers_BothCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .method public hidebysig newslot specialname virtual instance void add_E(class [mscorlib]System.Action`1<int32 modopt(int64) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void add_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> 'value') cil managed { ret } .event class [mscorlib]System.Action`1<int32 modopt(int64) []> E { .addon instance void Base::add_E(class [mscorlib]System.Action`1<int32 modopt(int64) []>) .removeon instance void Base::remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) []>) } // end of event Base::E .event class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> E { .addon instance void Base::add_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []>) .removeon instance void Base::remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []>) } // end of event Base::E } // end of class Base "; var csharp = @" public class Derived : Base { public override event System.Action<int[]> E; void UseEvent() { E(null); } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); // No diagnostics - just choose the overload with fewer custom modifiers compilation.VerifyDiagnostics(); Func<int, Func<EventSymbol, bool>> hasCustomModifierCount = c => e => e.Type.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseEvent1 = baseClass.GetMembers("E").Cast<EventSymbol>().Where(hasCustomModifierCount(1)).Single(); var baseEvent2 = baseClass.GetMembers("E").Cast<EventSymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedEvent = derivedClass.GetMember<EventSymbol>("E"); Assert.Equal(baseEvent1, derivedEvent.OverriddenEvent); Assert.NotEqual(baseEvent2, derivedEvent.OverriddenEvent); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void TestOverrideEvent_FewestCustomModifiers_OneCorrect() { var il = @" .class public auto ansi beforefieldinit Base extends [mscorlib]System.Object { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ldarg.0 call instance void [mscorlib]System.Object::.ctor() ret } .method public hidebysig newslot specialname virtual instance void add_E(class [mscorlib]System.Action`1<char modopt(int64) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void remove_E(class [mscorlib]System.Action`1<char modopt(int64) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void add_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> 'value') cil managed { ret } .method public hidebysig newslot specialname virtual instance void remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> 'value') cil managed { ret } // Dev10 overrides this event - even though the type is worse - // because it has fewer custom modifiers. .event class [mscorlib]System.Action`1<char modopt(int64) []> E { .addon instance void Base::add_E(class [mscorlib]System.Action`1<char modopt(int64) []>) .removeon instance void Base::remove_E(class [mscorlib]System.Action`1<char modopt(int64) []>) } // end of event Base::E .event class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []> E { .addon instance void Base::add_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []>) .removeon instance void Base::remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) modopt(int32) []>) } // end of event Base::E } // end of class Base "; var csharp = @" public class Derived : Base { public override event System.Action<int[]> E; void UseEvent() { E(null); } } "; var compilation = CreateCompilationWithILAndMscorlib40(csharp, il); compilation.VerifyDiagnostics( // (4,48): error CS1715: 'Derived.E': type must be 'System.Action<char[]>' to match overridden member 'Base.E' // public override event System.Action<int[]> E; Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "E").WithArguments("Derived.E", "Base.E", "System.Action<char[]>")); Func<int, Func<EventSymbol, bool>> hasCustomModifierCount = c => e => e.Type.CustomModifierCount() == c; var baseClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base"); var baseEvent1 = baseClass.GetMembers("E").Cast<EventSymbol>().Where(hasCustomModifierCount(1)).Single(); var baseEvent2 = baseClass.GetMembers("E").Cast<EventSymbol>().Where(hasCustomModifierCount(2)).Single(); var derivedClass = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived"); var derivedEvent = derivedClass.GetMember<EventSymbol>("E"); Assert.Equal(baseEvent1, derivedEvent.OverriddenEvent); Assert.NotEqual(baseEvent2, derivedEvent.OverriddenEvent); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void ModOptTestWithErrors() { // NOTE: removed Microsoft.VisualC attributes var il = @" .class public sequential ansi sealed beforefieldinit ModA extends [mscorlib]System.ValueType { .pack 0 .size 1 // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.MiscellaneousBitsAttribute::.ctor(int32) = ( 01 00 40 00 00 00 00 00 ) // ..@..... .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.NativeCppClassAttribute::.ctor() = ( 01 00 00 00 ) // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.DebugInfoInPDBAttribute::.ctor() = ( 01 00 00 00 ) } // end of class ModA .class public sequential ansi sealed beforefieldinit ModB extends [mscorlib]System.ValueType { .pack 0 .size 1 // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.MiscellaneousBitsAttribute::.ctor(int32) = ( 01 00 40 00 00 00 00 00 ) // ..@..... .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.NativeCppClassAttribute::.ctor() = ( 01 00 00 00 ) // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.DebugInfoInPDBAttribute::.ctor() = ( 01 00 00 00 ) } // end of class ModB .class public auto ansi beforefieldinit CG`1<([mscorlib]System.Object) T> extends [mscorlib]System.Object { // Removing this method makes the C# invocation of F ambiguous, because when // we attempt to figure out which instance of F to overload, we pick the one // with the least amount of modopts. But since theres more than one (the two // below have exactly one modopt), this should result in an error. // // .method public hidebysig newslot virtual // instance void F(!T c) cil managed // { // // Code size 11 (0xb) // .maxstack 1 // IL_0000: ldstr ""CG::F(T)"" // IL_0005: call void [mscorlib]System.Console::WriteLine(string) // IL_000a: ret // } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModA) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [A])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModB) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [B])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModA) modopt(ModB) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [A][B])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method CG`1::.ctor } // end of class CG`1 .class public auto ansi beforefieldinit DG`1<([mscorlib]System.Object) T> extends class CG`1<!T> { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call instance void class CG`1<!T>::.ctor() IL_0006: ret } // end of method DG`1::.ctor } // end of class DG`1 "; var csharp = @" using System; class EG<T> : DG<T> { public override void F(T c) { Console.Write(""C# EG.F(T): ""); base.F(c); } } class EGI : DG<int> { public override void F(int c) { Console.Write(""C# GEI.F(int): ""); base.F(c); } } class M { public static void Main(string[] args) { Console.WriteLine(""***** Start mod opt tests ****""); { Console.WriteLine("" *** Generic Non-ref""); EG<string> e = new EG<string>(); string c = ""Hello""; e.F(c); } { Console.WriteLine("" *** Generic-base Non-ref""); EGI e = new EGI(); int c = 5; e.F(c); } Console.WriteLine(""***** End mod opt tests ****""); } } "; CreateCompilationWithILAndMscorlib40(csharp, il).VerifyDiagnostics( // CONSIDER: Dev10 reports CS1957, even though the runtime has no trouble distinguishing the potentially // overridden methods. // (6,26): error CS0462: The inherited members 'CG<T>.F(T)' and 'CG<T>.F(T)' have the same signature in type 'EG<T>', so they cannot be overridden // public override void F(T c) Diagnostic(ErrorCode.ERR_AmbigOverride, "F").WithArguments("CG<T>.F(T)", "CG<T>.F(T)", "EG<T>").WithLocation(6, 26), // (15,26): error CS0462: The inherited members 'CG<T>.F(T)' and 'CG<T>.F(T)' have the same signature in type 'EGI', so they cannot be overridden // public override void F(int c) Diagnostic(ErrorCode.ERR_AmbigOverride, "F").WithArguments("CG<T>.F(T)", "CG<T>.F(T)", "EGI").WithLocation(15, 26), // NOTE: Dev10 doesn't report these cascading errors. // (9,14): error CS0121: The call is ambiguous between the following methods or properties: 'CG<T>.F(T)' and 'CG<T>.F(T)' // base.F(c); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<T>.F(T)", "CG<T>.F(T)").WithLocation(9, 14), // (18,14): error CS0121: The call is ambiguous between the following methods or properties: 'CG<int>.F(int)' and 'CG<int>.F(int)' // base.F(c); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<int>.F(int)", "CG<int>.F(int)").WithLocation(18, 14), // (34,15): error CS0121: The call is ambiguous between the following methods or properties: 'CG<string>.F(string)' and 'CG<string>.F(string)' // e.F(c); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<string>.F(string)", "CG<string>.F(string)").WithLocation(34, 15), // (43,15): error CS0121: The call is ambiguous between the following methods or properties: 'CG<int>.F(int)' and 'CG<int>.F(int)' // e.F(c); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<int>.F(int)", "CG<int>.F(int)").WithLocation(43, 15)); } [ClrOnlyFact(ClrOnlyReason.Ilasm)] public void ModOptTest() { // NOTE: removed Microsoft.VisualC attributes var il = @" .class public sequential ansi sealed beforefieldinit ModA extends [mscorlib]System.ValueType { .pack 0 .size 1 // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.MiscellaneousBitsAttribute::.ctor(int32) = ( 01 00 40 00 00 00 00 00 ) // ..@..... .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.NativeCppClassAttribute::.ctor() = ( 01 00 00 00 ) // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.DebugInfoInPDBAttribute::.ctor() = ( 01 00 00 00 ) } // end of class ModA .class public sequential ansi sealed beforefieldinit ModB extends [mscorlib]System.ValueType { .pack 0 .size 1 // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.MiscellaneousBitsAttribute::.ctor(int32) = ( 01 00 40 00 00 00 00 00 ) // ..@..... .custom instance void [mscorlib]System.CLSCompliantAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.NativeCppClassAttribute::.ctor() = ( 01 00 00 00 ) // .custom instance void [Microsoft.VisualC]Microsoft.VisualC.DebugInfoInPDBAttribute::.ctor() = ( 01 00 00 00 ) } // end of class ModB .class public auto ansi beforefieldinit CG`1<([mscorlib]System.Object) T> extends [mscorlib]System.Object { // Note that this test works fine because we pick the function with the // least number of modopts, which we can find as this first function. .method public hidebysig newslot virtual instance void F(!T c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T)"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModA) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [A])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModB) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [B])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig newslot virtual instance void F(!T modopt(ModA) modopt(ModB) c) cil managed { // Code size 11 (0xb) .maxstack 1 IL_0000: ldstr ""CG::F(T [A][B])"" IL_0005: call void [mscorlib]System.Console::WriteLine(string) IL_000a: ret } // end of method CG`1::F .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method CG`1::.ctor } // end of class CG`1 .class public auto ansi beforefieldinit DG`1<([mscorlib]System.Object) T> extends class CG`1<!T> { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 1 IL_0000: ldarg.0 IL_0001: call instance void class CG`1<!T>::.ctor() IL_0006: ret } // end of method DG`1::.ctor } // end of class DG`1 "; var csharp = @" using System; class EG<T> : DG<T> { public override void F(T c) { Console.Write(""C# EG.F(T): ""); base.F(c); } } class EGI : DG<int> { public override void F(int c) { Console.Write(""C# GEI.F(int): ""); base.F(c); } } class M { public static void Main(string[] args) { Console.WriteLine(""***** Start mod opt tests ****""); { Console.WriteLine("" *** Generic Non-ref""); EG<string> e = new EG<string>(); string c = ""Hello""; e.F(c); } { Console.WriteLine("" *** Generic-base Non-ref""); EGI e = new EGI(); int c = 5; e.F(c); } Console.WriteLine(""***** End mod opt tests ****""); } } "; var reference = CompileIL(il, prependDefaultHeader: true); var verifier = CompileAndVerify(csharp, new[] { reference }, options: TestOptions.ReleaseExe, expectedOutput: @" ***** Start mod opt tests **** *** Generic Non-ref C# EG.F(T): CG::F(T) *** Generic-base Non-ref C# GEI.F(int): CG::F(T) ***** End mod opt tests ****"); // CONSIDER: Dev10 reports WRN_MultipleRuntimeOverrideMatches twice, which is odd // since the runtime can distinguish signatures with different modopts. verifier.VerifyDiagnostics(); } [Fact] [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void OverloadsWithDifferentParameterModifiers_Ref_In() { var text = @" abstract class TestClass { public void Method(ref int x) { } public void Method(in int x) { } }"; var comp = CreateCompilation(text).VerifyDiagnostics( // (5,17): error CS0663: 'TestClass' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'ref' // public void Method(in int x) { } Diagnostic(ErrorCode.ERR_OverloadRefKind, "Method").WithArguments("TestClass", "method", "in", "ref").WithLocation(5, 17)); } [Fact] [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void OverloadsWithDifferentParameterModifiers_Out_In() { var text = @" abstract class TestClass { public void Method(out int x) { x = 0; } public void Method(in int x) { } }"; var comp = CreateCompilation(text).VerifyDiagnostics( // (5,17): error CS0663: 'TestClass' cannot define an overloaded method that differs only on parameter modifiers 'in' and 'out' // public void Method(in int x) { } Diagnostic(ErrorCode.ERR_OverloadRefKind, "Method").WithArguments("TestClass", "method", "in", "out").WithLocation(5, 17)); } } }