|
// 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,9): error CS0121: The call is ambiguous between the following methods or properties: 'Base<TLong, TInt>.Method(long, TInt)' and 'Base<TLong, TInt>.Method(TLong, int)'
// new Derived2().Method(1L, 2); //CS0121
Diagnostic(ErrorCode.ERR_AmbigCall, "Method").WithArguments("Base<TLong, TInt>.Method(long, TInt)", "Base<TLong, TInt>.Method(TLong, int)"));
}
[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<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)
);
}
}
[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>"),
// (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"),
// NOTE: Dev10 doesn't report these cascading errors.
// (9,9): 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)"),
// (18,9): 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)"),
// (34,13): error CS0121: The call is ambiguous between the following methods or properties: 'CG<T>.F(T)' and 'CG<T>.F(T)'
// e.F(c);
Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<T>.F(T)", "CG<T>.F(T)"),
// (43,13): error CS0121: The call is ambiguous between the following methods or properties: 'CG<T>.F(T)' and 'CG<T>.F(T)'
// e.F(c);
Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("CG<T>.F(T)", "CG<T>.F(T)"));
}
[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));
}
}
}
|