|
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
public class CovariantReturnTests : CSharpTestBase
{
private static readonly MetadataReference CorelibraryWithCovariantReturnSupport1;
private static readonly MetadataReference CorelibraryWithCovariantReturnSupport2;
private static readonly MetadataReference CorelibraryWithoutCovariantReturnSupport1;
private static readonly MetadataReference CorelibraryWithoutCovariantReturnSupport2;
private static readonly MetadataReference CorelibraryWithCovariantReturnSupportButWithoutPreserveBaseOverridesAttribute;
static CovariantReturnTests()
{
const string corLibraryCore = @"
namespace System
{
public class Array
{
public static T[] Empty<T>() => throw null;
}
public class Attribute { }
[Flags]
public enum AttributeTargets
{
Assembly = 0x1,
Module = 0x2,
Class = 0x4,
Struct = 0x8,
Enum = 0x10,
Constructor = 0x20,
Method = 0x40,
Property = 0x80,
Field = 0x100,
Event = 0x200,
Interface = 0x400,
Parameter = 0x800,
Delegate = 0x1000,
ReturnValue = 0x2000,
GenericParameter = 0x4000,
All = 0x7FFF
}
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
{
public AttributeUsageAttribute(AttributeTargets validOn) { }
public bool AllowMultiple
{
get => throw null;
set { }
}
public bool Inherited
{
get => throw null;
set { }
}
public AttributeTargets ValidOn => throw null;
}
public struct Boolean { }
public struct Byte { }
public class Delegate
{
public static Delegate CreateDelegate(Type type, object firstArgument, Reflection.MethodInfo method) => null;
}
public abstract class Enum : IComparable { }
public class Exception { }
public class FlagsAttribute : Attribute { }
public delegate T Func<out T>();
public delegate U Func<in T, out U>(T arg);
public interface IComparable { }
public interface IDisposable
{
void Dispose();
}
public struct Int16 { }
public struct Int32 { }
public struct IntPtr { }
public class MulticastDelegate : Delegate { }
public struct Nullable<T> { }
public class Object { }
public sealed class ParamArrayAttribute : Attribute { }
public struct RuntimeMethodHandle { }
public struct RuntimeTypeHandle { }
public class String : IComparable { public static String Empty = null; }
public class Type
{
public static Type GetTypeFromHandle(RuntimeTypeHandle handle) => null;
}
public class ValueType { }
public struct Void { }
namespace Collections
{
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
object Current
{
get;
}
bool MoveNext();
void Reset();
}
}
namespace Collections.Generic
{
public interface IEnumerable<out T> : IEnumerable
{
new IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<out T> : IEnumerator, IDisposable
{
new T Current
{
get;
}
}
}
namespace Linq.Expressions
{
public class Expression
{
public static ParameterExpression Parameter(Type type) => throw null;
public static ParameterExpression Parameter(Type type, string name) => throw null;
public static MethodCallExpression Call(Expression instance, Reflection.MethodInfo method, params Expression[] arguments) => throw null;
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) => throw null;
public static MemberExpression Property(Expression expression, Reflection.MethodInfo propertyAccessor) => throw null;
public static ConstantExpression Constant(object value, Type type) => throw null;
public static UnaryExpression Convert(Expression expression, Type type) => throw null;
}
public class ParameterExpression : Expression { }
public class MethodCallExpression : Expression { }
public abstract class LambdaExpression : Expression { }
public class Expression<T> : LambdaExpression { }
public class MemberExpression : Expression { }
public class ConstantExpression : Expression { }
public sealed class UnaryExpression : Expression { }
}
namespace Reflection
{
public class AssemblyVersionAttribute : Attribute
{
public AssemblyVersionAttribute(string version) { }
}
public class DefaultMemberAttribute : Attribute
{
public DefaultMemberAttribute(string name) { }
}
public abstract class MemberInfo { }
public abstract class MethodBase : MemberInfo
{
public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle) => throw null;
}
public abstract class MethodInfo : MethodBase
{
public virtual Delegate CreateDelegate(Type delegateType, object? target) => throw null;
}
}
namespace Runtime.CompilerServices
{
public static class RuntimeHelpers
{
public static object GetObjectValue(object obj) => null;
}
}
}
";
const string corlibWithoutCovariantSupport = corLibraryCore + @"
namespace System.Runtime.CompilerServices
{
public static class RuntimeFeature
{
public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces);
}
}
";
const string corlibWithCovariantSupport = corLibraryCore + @"
namespace System.Runtime.CompilerServices
{
public static class RuntimeFeature
{
public const string CovariantReturnsOfClasses = nameof(CovariantReturnsOfClasses);
public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces);
}
public sealed class PreserveBaseOverridesAttribute : Attribute { }
}
";
const string corlibWithCovariantSupportButWithoutPreserveBaseOverridesAttribute = corLibraryCore + @"
namespace System.Runtime.CompilerServices
{
public static class RuntimeFeature
{
public const string CovariantReturnsOfClasses = nameof(CovariantReturnsOfClasses);
public const string DefaultImplementationsOfInterfaces = nameof(DefaultImplementationsOfInterfaces);
}
}
";
CorelibraryWithoutCovariantReturnSupport1 = CreateEmptyCompilation(new string[] {
corlibWithoutCovariantSupport,
@"[assembly: System.Reflection.AssemblyVersion(""4.1.0.0"")]"
}, assemblyName: "mscorlib").EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v4.1"));
CorelibraryWithoutCovariantReturnSupport2 = CreateEmptyCompilation(new string[] {
corlibWithoutCovariantSupport,
@"[assembly: System.Reflection.AssemblyVersion(""4.2.0.0"")]"
}, assemblyName: "mscorlib").EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v4.2"));
CorelibraryWithCovariantReturnSupport1 = CreateEmptyCompilation(new string[] {
corlibWithCovariantSupport,
@"[assembly: System.Reflection.AssemblyVersion(""5.0.0.0"")]"
}, assemblyName: "mscorlib").EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v5.0"));
CorelibraryWithCovariantReturnSupport2 = CreateEmptyCompilation(new string[] {
corlibWithCovariantSupport,
@"[assembly: System.Reflection.AssemblyVersion(""5.1.0.0"")]"
}, assemblyName: "mscorlib").EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v5.1"));
CorelibraryWithCovariantReturnSupportButWithoutPreserveBaseOverridesAttribute = CreateEmptyCompilation(new string[] {
corlibWithCovariantSupportButWithoutPreserveBaseOverridesAttribute,
@"[assembly: System.Reflection.AssemblyVersion(""4.9.0.0"")]"
}, assemblyName: "mscorlib").EmitToImageReference(options: new CodeAnalysis.Emit.EmitOptions(runtimeMetadataVersion: "v4.9"));
}
private static void VerifyOverride(
CSharpCompilation comp,
string methodName,
string overridingMemberDisplay,
string overriddenMemberDisplay,
bool requiresMethodimpl = false)
{
var member = comp.GlobalNamespace.GetMember(methodName);
VerifyOverride(comp, member, overridingMemberDisplay, overriddenMemberDisplay, requiresMethodimpl);
}
private static void VerifyOverride(
CSharpCompilation comp,
Symbol member,
string overridingMemberDisplay,
string overriddenMemberDisplay,
bool requiresMethodimpl = false)
{
Assert.Equal(overridingMemberDisplay, member.ToTestDisplayString());
var overriddenMember = member.GetOverriddenMember();
Assert.Equal(overriddenMemberDisplay, overriddenMember?.ToTestDisplayString());
if (member is MethodSymbol method && overriddenMember is MethodSymbol overriddenMethod)
{
Assert.True(method.IsOverride);
Assert.False(method.IsVirtual);
Assert.True(method.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges));
var isCovariant = !method.ReturnType.Equals(overriddenMethod.ReturnType, TypeCompareKind.AllIgnoreOptions);
var checkMetadata = hasReturnConversion(method.ReturnType, overriddenMethod.ReturnType);
if (checkMetadata)
{
requiresMethodimpl = isCovariant | requiresMethodimpl;
Assert.Equal(requiresMethodimpl, method.IsMetadataNewSlot(ignoreInterfaceImplementationChanges: true));
Assert.Equal(requiresMethodimpl, method.RequiresExplicitOverride(out _));
if (method.OriginalDefinition is PEMethodSymbol originalMethod &&
comp.GetSpecialTypeMember(SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor) is MethodSymbol attrConstructor)
{
Assert.Equal(requiresMethodimpl, originalMethod.HasAttribute(attrConstructor));
}
}
switch (member)
{
case RetargetingMethodSymbol m:
{
MethodSymbol explicitlyOverriddenClassMethod = m.ExplicitlyOverriddenClassMethod;
if (explicitlyOverriddenClassMethod != null)
{
Assert.True(overriddenMember.Equals(explicitlyOverriddenClassMethod));
}
}
break;
case PEMethodSymbol m:
{
MethodSymbol explicitlyOverriddenClassMethod = m.ExplicitlyOverriddenClassMethod;
if (explicitlyOverriddenClassMethod != null)
{
Assert.True(overriddenMember.Equals(explicitlyOverriddenClassMethod));
}
}
break;
}
}
else if (member is PropertySymbol property && overriddenMember is PropertySymbol overriddenProperty)
{
var isCovariant = !property.Type.Equals(overriddenProperty.Type, TypeCompareKind.AllIgnoreOptions);
if (property.GetMethod is MethodSymbol getMethod && overriddenProperty.GetMethod is MethodSymbol overriddenGetMethod)
{
Assert.True(getMethod.GetOverriddenMember().Equals(overriddenGetMethod));
var checkMetadata = hasReturnConversion(property.Type, overriddenProperty.Type);
if (checkMetadata)
{
requiresMethodimpl = isCovariant | requiresMethodimpl;
Assert.Equal(requiresMethodimpl, getMethod.IsMetadataNewSlot(ignoreInterfaceImplementationChanges: true));
Assert.Equal(requiresMethodimpl, getMethod.RequiresExplicitOverride(out _)); // implies the presence of a methodimpl
if (getMethod.OriginalDefinition is PEMethodSymbol originalMethod &&
comp.GetSpecialTypeMember(SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor) is MethodSymbol attrConstructor)
{
Assert.Equal(requiresMethodimpl, originalMethod.HasAttribute(attrConstructor));
}
}
}
if (property.SetMethod is MethodSymbol setMethod && overriddenProperty.SetMethod is MethodSymbol overriddenSetMethod)
{
Assert.False(setMethod.IsMetadataNewSlot(ignoreInterfaceImplementationChanges: true));
Assert.False(setMethod.RequiresExplicitOverride(out _));
Assert.Equal(!isCovariant, overriddenSetMethod.Equals(setMethod.GetOverriddenMember(), TypeCompareKind.AllIgnoreOptions));
}
}
else if (member is EventSymbol eventSymbol && overriddenMember is EventSymbol overriddenEvent)
{
var isCovariant = !eventSymbol.Type.Equals(overriddenEvent.Type, TypeCompareKind.AllIgnoreOptions);
if (eventSymbol.AddMethod is MethodSymbol addMethod && overriddenEvent.AddMethod is MethodSymbol overriddenAddMethod)
{
Assert.Equal(!isCovariant, overriddenAddMethod.Equals(addMethod.GetOverriddenMember(), TypeCompareKind.AllIgnoreOptions));
}
if (eventSymbol.RemoveMethod is MethodSymbol removeMethod && overriddenEvent.RemoveMethod is MethodSymbol overriddenRemoveMethod)
{
Assert.Equal(!isCovariant, overriddenRemoveMethod.Equals(removeMethod.GetOverriddenMember(), TypeCompareKind.AllIgnoreOptions));
}
}
else
{
Assert.True(false);
}
bool hasReturnConversion(TypeSymbol fromType, TypeSymbol toType)
{
var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
return comp.Conversions.HasIdentityOrImplicitReferenceConversion(fromType, toType, ref discardedUseSiteInfo);
}
}
private static Symbol MemberOfConstructedType(
CSharpCompilation comp,
string memberName,
string containingTypeName,
params string[] typeArguments)
{
var genericType = (NamedTypeSymbol)comp.GlobalNamespace.GetMember(containingTypeName);
Assert.Equal(typeArguments.Length, genericType.Arity);
var constructedType = genericType.Construct(typeArguments.Select(n => (TypeSymbol)comp.GlobalNamespace.GetMember(n)));
return constructedType.GetMembers(memberName).Single();
}
private static void VerifyNoOverride(CSharpCompilation comp, string methodName)
{
var method = comp.GlobalNamespace.GetMember(methodName);
var overridden = method.GetOverriddenMember();
Assert.Null(overridden);
}
/// <summary>
/// Verify that all assignments in the compilation's source have the same type and converted type.
/// </summary>
private static void VerifyAssignments(CSharpCompilation comp, int expectedAssignments)
{
int foundAssignments = 0;
foreach (var tree in comp.SyntaxTrees)
{
var model = comp.GetSemanticModel(tree);
foreach (var declaration in tree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>())
{
foreach (var declarator in declaration.Declaration.Variables)
{
if (declarator.Initializer is { Value: ExpressionSyntax right })
{
var typeInfo = model.GetTypeInfo(right);
Assert.Equal(typeInfo.Type, typeInfo.ConvertedType);
foundAssignments++;
}
}
}
}
Assert.Equal(expectedAssignments, foundAssignments);
}
private CSharpCompilation CreateCompilationWithCovariantReturns(
string source,
MetadataReference[] references = null,
string assemblyName = "",
CSharpCompilationOptions options = null,
CSharpParseOptions parseOptions = null)
{
parseOptions ??= TestOptions.WithCovariantReturns;
references = references?.Prepend(CorelibraryWithCovariantReturnSupport1).ToArray() ?? new[] { CorelibraryWithCovariantReturnSupport1 };
return CreateCompilation(
source,
parseOptions: parseOptions ?? TestOptions.Regular9,
references: references,
targetFramework: TargetFramework.Empty,
assemblyName: assemblyName,
options: options);
}
private CSharpCompilation CreateCompilationWithoutCovariantReturns(
string source,
MetadataReference[] references = null,
string assemblyName = "",
CSharpCompilationOptions options = null,
CSharpParseOptions parseOptions = null)
{
parseOptions ??= TestOptions.WithoutCovariantReturns;
references = references?.Prepend(CorelibraryWithoutCovariantReturnSupport1).ToArray() ?? new[] { CorelibraryWithoutCovariantReturnSupport1 };
return CreateCompilation(
source,
parseOptions: parseOptions ?? TestOptions.Regular8,
references: references,
targetFramework: TargetFramework.Empty,
assemblyName: assemblyName,
options: options);
}
private CSharpCompilation CreateCompilation(
bool withCovariantReturns,
string source,
MetadataReference[] references = null,
string assemblyName = "",
CSharpCompilationOptions options = null,
CSharpParseOptions parseOptions = null)
{
return withCovariantReturns
? CreateCompilationWithCovariantReturns(source, references, assemblyName, options, parseOptions)
: CreateCompilationWithoutCovariantReturns(source, references, assemblyName, options, parseOptions);
}
private static CSharpCompilation SourceView(
CSharpCompilation comp,
string assignments)
{
return comp.AddSyntaxTrees(CSharpSyntaxTree.ParseText(assignments, (CSharpParseOptions)comp.SyntaxTrees[0].Options, path: "assignments.cs", encoding: Encoding.UTF8));
}
private static CSharpCompilation CompilationReferenceView(
CSharpCompilation comp,
string assignments,
MetadataReference[] references = null,
bool withoutCorlib = false)
{
CompilationReference compAsMetadata = comp.ToMetadataReference();
references = references?.Append(compAsMetadata) ?? new[] { compAsMetadata };
var coreLibrary = comp.GetMetadataReference(comp.Assembly.CorLibrary);
if (!withoutCorlib)
references = references.Prepend(coreLibrary).ToArray();
var result = CreateCompilation(assignments, references: references, targetFramework: TargetFramework.Empty);
result.VerifyDiagnostics();
var originalCorLib = comp.Assembly.CorLibrary;
var newCorLib = result.Assembly.CorLibrary;
Assert.Equal(originalCorLib, newCorLib);
var sourceAssembly = (AssemblySymbol)result.GetAssemblyOrModuleSymbol(compAsMetadata);
Assert.True(sourceAssembly is SourceAssemblySymbol);
return result;
}
private static CSharpCompilation MetadataView(
CSharpCompilation comp,
string assignments,
MetadataReference[] references = null,
bool withoutCorlib = false,
params DiagnosticDescription[] expectedDiagnostics)
{
var compAsImage = comp.EmitToImageReference();
references = references?.Append(compAsImage) ?? new[] { compAsImage };
var coreLibrary = comp.GetMetadataReference(comp.Assembly.CorLibrary);
if (!withoutCorlib)
references = references.Prepend(coreLibrary).ToArray();
var result = CreateCompilation(assignments, references: references, targetFramework: TargetFramework.Empty);
result.VerifyDiagnostics(expectedDiagnostics);
return result;
}
private static CSharpCompilation RetargetingView(
CSharpCompilation comp,
string assignments,
MetadataReference[] references = null,
bool withoutCorlib = false,
params DiagnosticDescription[] expectedDiagnostics)
{
CompilationReference compAsMetadata = comp.ToMetadataReference();
references = references?.Append(compAsMetadata) ?? new[] { compAsMetadata };
if (!withoutCorlib)
{
var coreLibrary = comp.GetMetadataReference(comp.Assembly.CorLibrary);
MetadataReference alternateCorlib =
(coreLibrary == CorelibraryWithCovariantReturnSupport1) ? CorelibraryWithCovariantReturnSupport2 :
(coreLibrary == CorelibraryWithoutCovariantReturnSupport1) ? CorelibraryWithoutCovariantReturnSupport2 :
throw ExceptionUtilities.Unreachable();
references = references.Prepend(alternateCorlib).ToArray();
}
var parseOptions = (CSharpParseOptions)comp.SyntaxTrees[0].Options;
var result = CreateCompilation(
assignments,
references: references,
targetFramework: TargetFramework.Empty,
options: TestOptions.ReleaseDll.WithSpecificDiagnosticOptions("CS1701", ReportDiagnostic.Suppress),
parseOptions: parseOptions);
result.VerifyDiagnostics(expectedDiagnostics);
var originalCorLib = comp.Assembly.CorLibrary;
var newCorLib = result.Assembly.CorLibrary;
Assert.NotEqual(originalCorLib, newCorLib);
var retargetingAssembly = (AssemblySymbol)result.GetAssemblyOrModuleSymbol(compAsMetadata);
Assert.True(retargetingAssembly is RetargetingAssemblySymbol);
return result;
}
[Fact]
public void RequirePreserveBaseOverridesAttribute()
{
var source = @"
public class Base
{
public virtual object M() => null;
}
public class Derived : Base
{
public override string M() => null;
}
";
CreateCompilation(
source,
parseOptions: TestOptions.WithCovariantReturns,
references: new[] { CorelibraryWithCovariantReturnSupportButWithoutPreserveBaseOverridesAttribute },
targetFramework: TargetFramework.Empty)
.VerifyDiagnostics(
// (8,28): error CS8830: 'Derived.M()': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base.M()'
// public override string M() => null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M()", "Base.M()", "object").WithLocation(8, 28)
);
}
[Fact]
public void CovariantReturns_00()
{
var source = @"
public class Base
{
public virtual string M() => null;
}
public class Derived : Base
{
public override string M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
string s1 = b.M();
string s2 = d.M();
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: string s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""string Base.M()""
IL_0006: pop
// sequence point: string s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""string Base.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.String Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void TestCorlibWithCovariantReturnSupport()
{
var source = @"
public class Base
{
public virtual object M1() => null;
public virtual object P1 => null;
public virtual object M2() => null;
public virtual object P2 => null;
public virtual object this[int index] => null;
}
public class Derived : Base
{
public override string M1() => null;
public override string P1 => null;
public override object M2() => null;
public override object P2 => null;
public override string this[int index] => null;
}
public class Derived2 : Base
{
public override object this[int index] => null;
}
";
var assignments = @"";
CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns)
.VerifyDiagnostics(
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M1() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("covariant returns", "9.0").WithLocation(12, 28),
// (13,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P1 => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P1").WithArguments("covariant returns", "9.0").WithLocation(13, 28),
// (16,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string this[int index] => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "this").WithArguments("covariant returns", "9.0").WithLocation(16, 28)
);
var comp = CreateCompilationWithCovariantReturns(source)
.VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, ""));
verify(MetadataView(comp, ""));
verify(RetargetingView(comp, ""));
static void verify(CSharpCompilation comp)
{
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M1"), needsAttribute: true);
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_P1"), needsAttribute: true);
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M2"), needsAttribute: false);
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_P2"), needsAttribute: false);
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_Item"), needsAttribute: true);
verifyAttribute((MethodSymbol)comp.GlobalNamespace.GetMember("Derived2.get_Item"), needsAttribute: false);
}
static void verifyAttribute(MethodSymbol method, bool needsAttribute)
{
var isCovariant = !method.ReturnType.Equals(method.OverriddenMethod.ReturnType);
Assert.Equal(needsAttribute, isCovariant);
var attributeExpected = isCovariant && !method.Locations[0].IsInSource;
var attrs = method.GetAttributes("System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute");
Assert.Equal(attributeExpected, !attrs.IsEmpty());
}
}
[Fact]
public void CovariantReturns_01()
{
var source = @"
public class Base
{
public virtual object M() => null;
}
public class Derived : Base
{
public override string M() => null;
}";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M();
string s2 = d.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
// Test against a runtime that does not admit support for covariant returns.
comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (8,28): error CS8778: 'Derived.M()': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base.M()'
// public override string M() => null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M()", "Base.M()", "object").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithoutCovariantReturns(source, parseOptions: TestOptions.WithCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8778: 'Derived.M()': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base.M()'
// public override string M() => null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M()", "Base.M()", "object").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M()""
IL_0006: pop
// sequence point: string s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_02()
{
var source = @"
public class Base
{
public virtual T M<T, U>() where T : class where U : class, T => null;
}
public class Derived : Base
{
public override U M<T, U>() => null;
}";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M<object, string>();
string s2 = d.M<object, string>();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override U M<T, U>() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M<object, string>();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M<object, string>()""
IL_0006: pop
// sequence point: string s2 = d.M<object, string>();
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M<object, string>()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "U Derived.M<T, U>()", "T Base.M<T, U>()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_03()
{
var source = @"
public class Base<T> where T : class
{
public virtual T M() => null;
}
public class Derived<T, U> : Base<T> where T : class where U : class, T
{
public override U M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base<object> b, Derived<object, string> d)
{
object s1 = b.M();
string s2 = d.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override U M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base<object>, Derived<object, string>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base<object>.M()""
IL_0006: pop
// sequence point: string s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived<object, string>.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "U Derived<T, U>.M()", "T Base<T>.M()");
VerifyOverride(comp, MemberOfConstructedType(comp, "M", "Derived", "System.Object", "System.String"), "System.String Derived<System.Object, System.String>.M()", "System.Object Base<System.Object>.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_04()
{
var source = @"
public class N { }
public class Base
{
public virtual N M() => null;
}
public class Derived<T> : Base where T : N
{
public override T M() => null;
}
public class Q : N { }
";
var assignments = @"
public class Program
{
void M(Base b, Derived<Q> d)
{
N s1 = b.M();
Q s2 = d.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (9,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override T M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(9, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived<Q>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: N s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""N Base.M()""
IL_0006: pop
// sequence point: Q s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""Q Derived<Q>.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "T Derived<T>.M()", "N Base.M()");
VerifyOverride(comp, MemberOfConstructedType(comp, "M", "Derived", "Q"), "Q Derived<Q>.M()", "N Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_05()
{
var source = @"
public class Base
{
public virtual object M => null;
}
public class Derived : Base
{
public override string M => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M;
string s2 = d.M;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
// Test against a runtime that does not admit support for covariant returns.
comp = CreateCompilationWithoutCovariantReturns(source, parseOptions: TestOptions.WithCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8779: 'Derived.M': Target runtime doesn't support covariant types in overrides. Type must be 'object' to match overridden member 'Base.M'
// public override string M => null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantPropertiesOfClasses, "M").WithArguments("Derived.M", "Base.M", "object").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M;
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M.get""
IL_0006: pop
// sequence point: string s2 = d.M;
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M { get; }", "System.Object Base.M { get; }");
VerifyOverride(comp, "Derived.get_M", "System.String Derived.M.get", "System.Object Base.M.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_06()
{
var source = @"
public class Base<T> where T : class
{
public virtual T M => null;
}
public class Derived<T, U> : Base<T> where T : class where U : class, T
{
public override U M => null;
}
";
var assignments = @"
public class Program
{
void M(Base<object> b, Derived<object, string> d)
{
object s1 = b.M;
string s2 = d.M;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override U M => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base<object>, Derived<object, string>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M;
IL_0000: ldarg.1
IL_0001: callvirt ""object Base<object>.M.get""
IL_0006: pop
// sequence point: string s2 = d.M;
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived<object, string>.M.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "U Derived<T, U>.M { get; }", "T Base<T>.M { get; }");
VerifyOverride(comp, "Derived.get_M", "U Derived<T, U>.M.get", "T Base<T>.M.get");
VerifyOverride(comp, MemberOfConstructedType(comp, "M", "Derived", "System.Object", "System.String"), "System.String Derived<System.Object, System.String>.M { get; }", "System.Object Base<System.Object>.M { get; }");
VerifyOverride(comp, MemberOfConstructedType(comp, "get_M", "Derived", "System.Object", "System.String"), "System.String Derived<System.Object, System.String>.M.get", "System.Object Base<System.Object>.M.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_07()
{
var source = @"
public class N { }
public class Base
{
public virtual N M => null;
}
public class Derived<T> : Base where T : N
{
public override T M => null;
}
public class Q : N { }
";
var assignments = @"
public class Program
{
void M(Base b, Derived<Q> d)
{
N s1 = b.M;
Q s2 = d.M;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (9,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override T M => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(9, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived<Q>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: N s1 = b.M;
IL_0000: ldarg.1
IL_0001: callvirt ""N Base.M.get""
IL_0006: pop
// sequence point: Q s2 = d.M;
IL_0007: ldarg.2
IL_0008: callvirt ""Q Derived<Q>.M.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "T Derived<T>.M { get; }", "N Base.M { get; }");
VerifyOverride(comp, "Derived.get_M", "T Derived<T>.M.get", "N Base.M.get");
VerifyOverride(comp, MemberOfConstructedType(comp, "M", "Derived", "Q"), "Q Derived<Q>.M { get; }", "N Base.M { get; }");
VerifyOverride(comp, MemberOfConstructedType(comp, "get_M", "Derived", "Q"), "Q Derived<Q>.M.get", "N Base.M.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_08()
{
var source = @"
public class Base
{
public virtual object this[int i] => null;
}
public class Derived : Base
{
public override string this[int i] => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b[0];
string s2 = d[0];
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string this[int i] => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "this").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 17 (0x11)
.maxstack 2
// sequence point: object s1 = b[0];
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: callvirt ""object Base.this[int].get""
IL_0007: pop
// sequence point: string s2 = d[0];
IL_0008: ldarg.2
IL_0009: ldc.i4.0
IL_000a: callvirt ""string Derived.this[int].get""
IL_000f: pop
// sequence point: }
IL_0010: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.this[]", "System.String Derived.this[System.Int32 i] { get; }", "System.Object Base.this[System.Int32 i] { get; }");
VerifyOverride(comp, "Derived.get_Item", "System.String Derived.this[System.Int32 i].get", "System.Object Base.this[System.Int32 i].get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_09()
{
var source = @"
public class Base<T> where T : class
{
public virtual T this[int i] => null;
}
public class Derived<T, U> : Base<T> where T : class where U : class, T
{
public override U this[int i] => null;
}
";
var assignments = @"
public class Program
{
void M(Base<object> b, Derived<object, string> d)
{
object s1 = b[0];
string s2 = d[0];
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override U this[int i] => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "this").WithArguments("covariant returns", "9.0").WithLocation(8, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base<object>, Derived<object, string>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 17 (0x11)
.maxstack 2
// sequence point: object s1 = b[0];
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: callvirt ""object Base<object>.this[int].get""
IL_0007: pop
// sequence point: string s2 = d[0];
IL_0008: ldarg.2
IL_0009: ldc.i4.0
IL_000a: callvirt ""string Derived<object, string>.this[int].get""
IL_000f: pop
// sequence point: }
IL_0010: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.this[]", "U Derived<T, U>.this[System.Int32 i] { get; }", "T Base<T>.this[System.Int32 i] { get; }");
VerifyOverride(comp, "Derived.get_Item", "U Derived<T, U>.this[System.Int32 i].get", "T Base<T>.this[System.Int32 i].get");
VerifyOverride(comp, MemberOfConstructedType(comp, "this[]", "Derived", "System.Object", "System.String"), "System.String Derived<System.Object, System.String>.this[System.Int32 i] { get; }", "System.Object Base<System.Object>.this[System.Int32 i] { get; }");
VerifyOverride(comp, MemberOfConstructedType(comp, "get_Item", "Derived", "System.Object", "System.String"), "System.String Derived<System.Object, System.String>.this[System.Int32 i].get", "System.Object Base<System.Object>.this[System.Int32 i].get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_10()
{
var source = @"
public class N { }
public class Base
{
public virtual N this[int i] => null;
}
public class Derived<T> : Base where T : N
{
public override T this[int i] => null;
}
public class Q : N { }
";
var assignments = @"
public class Program
{
void M(Base b, Derived<Q> d)
{
N s1 = b[0];
Q s2 = d[0];
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (9,23): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override T this[int i] => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "this").WithArguments("covariant returns", "9.0").WithLocation(9, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived<Q>)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 17 (0x11)
.maxstack 2
// sequence point: N s1 = b[0];
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: callvirt ""N Base.this[int].get""
IL_0007: pop
// sequence point: Q s2 = d[0];
IL_0008: ldarg.2
IL_0009: ldc.i4.0
IL_000a: callvirt ""Q Derived<Q>.this[int].get""
IL_000f: pop
// sequence point: }
IL_0010: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.this[]", "T Derived<T>.this[System.Int32 i] { get; }", "N Base.this[System.Int32 i] { get; }");
VerifyOverride(comp, "Derived.get_Item", "T Derived<T>.this[System.Int32 i].get", "N Base.this[System.Int32 i].get");
VerifyOverride(comp, MemberOfConstructedType(comp, "this[]", "Derived", "Q"), "Q Derived<Q>.this[System.Int32 i] { get; }", "N Base.this[System.Int32 i] { get; }");
VerifyOverride(comp, MemberOfConstructedType(comp, "get_Item", "Derived", "Q"), "Q Derived<Q>.this[System.Int32 i].get", "N Base.this[System.Int32 i].get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_Events()
{
var source = @"
using System;
public class Base
{
public virtual event Func<object> E;
private void SuppressUnusedWarning() => E?.Invoke();
}
public class Derived : Base
{
public override event Func<string> E;
private void SuppressUnusedWarning() => E?.Invoke();
}
";
var assignments = @"";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (10,40): error CS1715: 'Derived.E': type must be 'Func<object>' to match overridden member 'Base.E'
// public override event Func<string> E;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "E").WithArguments("Derived.E", "Base.E", "System.Func<object>").WithLocation(10, 40)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (10,40): error CS1715: 'Derived.E': type must be 'Func<object>' to match overridden member 'Base.E'
// public override event Func<string> E;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "E").WithArguments("Derived.E", "Base.E", "System.Func<object>").WithLocation(10, 40)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.E", "event System.Func<System.String> Derived.E", "event System.Func<System.Object> Base.E");
}
}
[Fact]
public void CovariantReturns_WritableProperties()
{
var source = @"
using System;
public class Base
{
public virtual Func<object> P { get; set; }
}
public class Derived : Base
{
public override Func<string> P { get; set; }
}
";
var assignments = @"
using System;
public class Program
{
void M(Base b, Derived d)
{
Func<object> s1 = b.P;
Func<string> s2 = d.P;
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (9,34): error CS1715: 'Derived.P': type must be 'Func<object>' to match overridden member 'Base.P'
// public override Func<string> P { get; set; }
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "P").WithArguments("Derived.P", "Base.P", "System.Func<object>").WithLocation(9, 34)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (9,34): error CS1715: 'Derived.P': type must be 'Func<object>' to match overridden member 'Base.P'
// public override Func<string> P { get; set; }
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "P").WithArguments("Derived.P", "Base.P", "System.Func<object>").WithLocation(9, 34)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.Func<System.String> Derived.P { get; set; }", "System.Func<System.Object> Base.P { get; set; }");
VerifyNoOverride(comp, "Derived.set_P");
VerifyOverride(comp, "Derived.get_P", "System.Func<System.String> Derived.P.get", "System.Func<System.Object> Base.P.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_MetadataVsSource_01()
{
var s0 = @"
public class Base
{
public virtual object M() => null;
}
";
var baseMetadata = CreateCompilationWithCovariantReturns(s0).EmitToImageReference();
var source = @"
public class Derived : Base
{
public override string M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M();
string s2 = d.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, references: new[] { baseMetadata }, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source, references: new[] { baseMetadata }).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments, new[] { baseMetadata }));
verify(MetadataView(comp, assignments, new[] { baseMetadata }));
verify(RetargetingView(comp, assignments, new[] { baseMetadata }));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M()""
IL_0006: pop
// sequence point: string s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_MetadataVsSource_02()
{
var s0 = @"
public class Base
{
public virtual object M => null;
}
";
var baseMetadata = CreateCompilationWithCovariantReturns(s0).EmitToImageReference();
var source = @"
public class Derived : Base
{
public override string M => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M;
string s2 = d.M;
}
}
";
var references = new[] { baseMetadata };
var comp = CreateCompilationWithCovariantReturns(source, references: references, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source, references: references).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments, references));
verify(MetadataView(comp, assignments, references));
verify(RetargetingView(comp, assignments, references));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M;
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M.get""
IL_0006: pop
// sequence point: string s2 = d.M;
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M { get; }", "System.Object Base.M { get; }");
VerifyOverride(comp, "Derived.get_M", "System.String Derived.M.get", "System.Object Base.M.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_MetadataVsSource_03()
{
var s0 = @"
public class Base
{
public virtual object this[int i] => null;
}
";
var baseMetadata = CreateCompilationWithCovariantReturns(s0).EmitToImageReference();
var source = @"
public class Derived : Base
{
public override string this[int i] => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b[0];
string s2 = d[0];
}
}
";
var references = new[] { baseMetadata };
var comp = CreateCompilationWithCovariantReturns(source, references: references, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string this[int i] => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "this").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source, references: new[] { baseMetadata }).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments, references));
verify(MetadataView(comp, assignments, references));
verify(RetargetingView(comp, assignments, references));
var c = CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped);
c.VerifyMethodBody("Program.M(Base, Derived)", @"
{
// Code size 17 (0x11)
.maxstack 2
// sequence point: object s1 = b[0];
IL_0000: ldarg.1
IL_0001: ldc.i4.0
IL_0002: callvirt ""object Base.this[int].get""
IL_0007: pop
// sequence point: string s2 = d[0];
IL_0008: ldarg.2
IL_0009: ldc.i4.0
IL_000a: callvirt ""string Derived.this[int].get""
IL_000f: pop
// sequence point: }
IL_0010: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.this[]", "System.String Derived.this[System.Int32 i] { get; }", "System.Object Base.this[System.Int32 i] { get; }");
VerifyOverride(comp, "Derived.get_Item", "System.String Derived.this[System.Int32 i].get", "System.Object Base.this[System.Int32 i].get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_11()
{
var source = @"
public abstract class Base
{
public abstract object M();
}
public class Derived : Base
{
public override string M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object s1 = b.M();
string s2 = d.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object s1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M()""
IL_0006: pop
// sequence point: string s2 = d.M();
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M()""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_WrongReturnType()
{
var source = @"
public class Base
{
public virtual string M() => null;
}
public class Derived : Base
{
public override object M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
string s1 = b.M();
object s2 = d.M();
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (8,28): error CS0508: 'Derived.M()': return type must be 'string' to match overridden member 'Base.M()'
// public override object M() => null;
Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "M").WithArguments("Derived.M()", "Base.M()", "string").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (8,28): error CS0508: 'Derived.M()': return type must be 'string' to match overridden member 'Base.M()'
// public override object M() => null;
Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "M").WithArguments("Derived.M()", "Base.M()", "string").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.Object Derived.M()", "System.String Base.M()");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void NonOverrideTests_01()
{
var source = @"
public class Base
{
public virtual object M1 => null;
public virtual object M2 => null;
}
public class Derived : Base
{
public new string M1 => null;
public string M2 => null; // A
}
public class Derived2 : Derived
{
public new string M1 => null;
public string M2 => null; // B
}
public class Derived3 : Derived
{
public new object M1 => null;
public object M2 => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2, Derived3 d3)
{
object x1 = b.M1;
object x2 = b.M2;
string x3 = d1.M1;
string x4 = d1.M2;
string x5 = d2.M1;
string x6 = d2.M2;
object x7 = d3.M1;
object x8 = d3.M2;
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (10,19): warning CS0114: 'Derived.M2' hides inherited member 'Base.M2'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
// public string M2 => null; // A
Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M2").WithArguments("Derived.M2", "Base.M2").WithLocation(10, 19),
// (15,19): warning CS0108: 'Derived2.M2' hides inherited member 'Derived.M2'. Use the new keyword if hiding was intended.
// public string M2 => null; // B
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("Derived2.M2", "Derived.M2").WithLocation(15, 19),
// (20,19): warning CS0108: 'Derived3.M2' hides inherited member 'Derived.M2'. Use the new keyword if hiding was intended.
// public object M2 => null;
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("Derived3.M2", "Derived.M2").WithLocation(20, 19)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (10,19): warning CS0114: 'Derived.M2' hides inherited member 'Base.M2'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
// public string M2 => null; // A
Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "M2").WithArguments("Derived.M2", "Base.M2").WithLocation(10, 19),
// (15,19): warning CS0108: 'Derived2.M2' hides inherited member 'Derived.M2'. Use the new keyword if hiding was intended.
// public string M2 => null; // B
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("Derived2.M2", "Derived.M2").WithLocation(15, 19),
// (20,19): warning CS0108: 'Derived3.M2' hides inherited member 'Derived.M2'. Use the new keyword if hiding was intended.
// public object M2 => null;
Diagnostic(ErrorCode.WRN_NewRequired, "M2").WithArguments("Derived3.M2", "Derived.M2").WithLocation(20, 19)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyNoOverride(comp, "Derived.M1");
VerifyNoOverride(comp, "Derived.M2");
VerifyNoOverride(comp, "Derived2.M1");
VerifyNoOverride(comp, "Derived2.M2");
VerifyNoOverride(comp, "Derived3.M1");
VerifyNoOverride(comp, "Derived3.M2");
VerifyAssignments(comp, 8);
}
}
[Fact]
public void ChainedOverrides_01()
{
var source = @"
public class Base
{
public virtual object M1 => null;
public virtual object M2 => null;
public virtual object M3 => null;
}
public class Derived : Base
{
public override string M1 => null; // A
public override string M2 => null; // B
public override string M3 => null; // C
}
public class Derived2 : Derived
{
public override string M1 => null;
public override object M2 => null; // 1
public override Base M3 => null; // 2
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2)
{
object x1 = b.M1;
object x2 = b.M2;
object x3 = b.M3;
string x4 = d1.M1;
string x5 = d1.M2;
string x6 = d1.M3;
string x7 = d2.M1;
object x8 = d2.M2;
Base x9 = d2.M3;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (10,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M1 => null; // A
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("covariant returns", "9.0").WithLocation(10, 28),
// (11,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M2 => null; // B
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M2").WithArguments("covariant returns", "9.0").WithLocation(11, 28),
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M3 => null; // C
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M3").WithArguments("covariant returns", "9.0").WithLocation(12, 28),
// (17,28): error CS1715: 'Derived2.M2': type must be 'string' to match overridden member 'Derived.M2'
// public override object M2 => null; // 1
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived2.M2", "Derived.M2", "string").WithLocation(17, 28),
// (18,26): error CS1715: 'Derived2.M3': type must be 'string' to match overridden member 'Derived.M3'
// public override Base M3 => null; // 2
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M3").WithArguments("Derived2.M3", "Derived.M3", "string").WithLocation(18, 26)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (17,28): error CS1715: 'Derived2.M2': type must be 'string' to match overridden member 'Derived.M2'
// public override object M2 => null; // 1
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived2.M2", "Derived.M2", "string").WithLocation(17, 28),
// (18,26): error CS1715: 'Derived2.M3': type must be 'string' to match overridden member 'Derived.M3'
// public override Base M3 => null; // 2
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M3").WithArguments("Derived2.M3", "Derived.M3", "string").WithLocation(18, 26)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyAssignments(comp, 9);
VerifyOverride(comp, "Derived.M1", "System.String Derived.M1 { get; }", "System.Object Base.M1 { get; }");
VerifyOverride(comp, "Derived.get_M1", "System.String Derived.M1.get", "System.Object Base.M1.get");
VerifyOverride(comp, "Derived.M2", "System.String Derived.M2 { get; }", "System.Object Base.M2 { get; }");
VerifyOverride(comp, "Derived.get_M2", "System.String Derived.M2.get", "System.Object Base.M2.get");
VerifyOverride(comp, "Derived.M3", "System.String Derived.M3 { get; }", "System.Object Base.M3 { get; }");
VerifyOverride(comp, "Derived.get_M3", "System.String Derived.M3.get", "System.Object Base.M3.get");
VerifyOverride(comp, "Derived2.M1", "System.String Derived2.M1 { get; }", "System.String Derived.M1 { get; }");
VerifyOverride(comp, "Derived2.get_M1", "System.String Derived2.M1.get", "System.String Derived.M1.get");
VerifyOverride(comp, "Derived2.M2", "System.Object Derived2.M2 { get; }", "System.String Derived.M2 { get; }");
VerifyOverride(comp, "Derived2.get_M2", "System.Object Derived2.M2.get", "System.String Derived.M2.get");
VerifyOverride(comp, "Derived2.M3", "Base Derived2.M3 { get; }", "System.String Derived.M3 { get; }");
VerifyOverride(comp, "Derived2.get_M3", "Base Derived2.M3.get", "System.String Derived.M3.get");
}
}
[Fact]
public void NestedVariance_01()
{
var source = @"
public class Base
{
public virtual IIn<string> M1 => null;
public virtual IOut<object> M2 => null;
}
public class Derived : Base
{
public override IIn<object> M1 => null;
public override IOut<string> M2 => null;
}
public interface IOut<out T> { }
public interface IIn<in T> { }
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
IIn<string> x1 = b.M1;
IOut<object> x2 = b.M2;
IIn<object> x3 = d.M1;
IOut<string> x4 = d.M2;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (9,33): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IIn<object> M1 => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("covariant returns", "9.0").WithLocation(9, 33),
// (10,34): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IOut<string> M2 => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M2").WithArguments("covariant returns", "9.0").WithLocation(10, 34)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 29 (0x1d)
.maxstack 1
// sequence point: IIn<string> x1 = b.M1;
IL_0000: ldarg.1
IL_0001: callvirt ""IIn<string> Base.M1.get""
IL_0006: pop
// sequence point: IOut<object> x2 = b.M2;
IL_0007: ldarg.1
IL_0008: callvirt ""IOut<object> Base.M2.get""
IL_000d: pop
// sequence point: IIn<object> x3 = d.M1;
IL_000e: ldarg.2
IL_000f: callvirt ""IIn<object> Derived.M1.get""
IL_0014: pop
// sequence point: IOut<string> x4 = d.M2;
IL_0015: ldarg.2
IL_0016: callvirt ""IOut<string> Derived.M2.get""
IL_001b: pop
// sequence point: }
IL_001c: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M1", "IIn<System.Object> Derived.M1 { get; }", "IIn<System.String> Base.M1 { get; }");
VerifyOverride(comp, "Derived.get_M1", "IIn<System.Object> Derived.M1.get", "IIn<System.String> Base.M1.get");
VerifyOverride(comp, "Derived.M2", "IOut<System.String> Derived.M2 { get; }", "IOut<System.Object> Base.M2 { get; }");
VerifyOverride(comp, "Derived.get_M2", "IOut<System.String> Derived.M2.get", "IOut<System.Object> Base.M2.get");
VerifyAssignments(comp, 4);
}
}
[Fact]
public void NestedVariance_02()
{
var source = @"
public class Base
{
public virtual IIn<object> M1 => null;
public virtual IOut<string> M2 => null;
}
public class Derived : Base
{
public override IIn<string> M1 => null;
public override IOut<object> M2 => null;
}
public interface IOut<out T> { }
public interface IIn<in T> { }
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
IIn<object> x1 = b.M1;
IOut<string> x2 = b.M2;
IIn<string> x3 = d.M1;
IOut<object> x4 = d.M2;
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (9,33): error CS1715: 'Derived.M1': type must be 'IIn<object>' to match overridden member 'Base.M1'
// public override IIn<string> M1 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M1").WithArguments("Derived.M1", "Base.M1", "IIn<object>").WithLocation(9, 33),
// (10,34): error CS1715: 'Derived.M2': type must be 'IOut<string>' to match overridden member 'Base.M2'
// public override IOut<object> M2 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived.M2", "Base.M2", "IOut<string>").WithLocation(10, 34)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (9,33): error CS1715: 'Derived.M1': type must be 'IIn<object>' to match overridden member 'Base.M1'
// public override IIn<string> M1 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M1").WithArguments("Derived.M1", "Base.M1", "IIn<object>").WithLocation(9, 33),
// (10,34): error CS1715: 'Derived.M2': type must be 'IOut<string>' to match overridden member 'Base.M2'
// public override IOut<object> M2 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived.M2", "Base.M2", "IOut<string>").WithLocation(10, 34)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M1", "IIn<System.String> Derived.M1 { get; }", "IIn<System.Object> Base.M1 { get; }");
VerifyOverride(comp, "Derived.get_M1", "IIn<System.String> Derived.M1.get", "IIn<System.Object> Base.M1.get");
VerifyOverride(comp, "Derived.M2", "IOut<System.Object> Derived.M2 { get; }", "IOut<System.String> Base.M2 { get; }");
VerifyOverride(comp, "Derived.get_M2", "IOut<System.Object> Derived.M2.get", "IOut<System.String> Base.M2.get");
VerifyAssignments(comp, 4);
}
}
[Fact]
public void BadCovariantReturnType_01()
{
var source = @"
public class Base
{
public virtual int M1 => 1;
public virtual A M2 => null;
}
public class Derived : Base
{
public override short M1 => 1;
public override B M2 => null;
}
public class A { }
public class B
{
public static implicit operator A(B b) => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
int x1 = b.M1;
A x2 = b.M2;
short x3 = d.M1;
B x4 = d.M2;
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (9,27): error CS1715: 'Derived.M1': type must be 'int' to match overridden member 'Base.M1'
// public override short M1 => 1;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M1").WithArguments("Derived.M1", "Base.M1", "int").WithLocation(9, 27),
// (10,23): error CS1715: 'Derived.M2': type must be 'A' to match overridden member 'Base.M2'
// public override B M2 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived.M2", "Base.M2", "A").WithLocation(10, 23)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (9,27): error CS1715: 'Derived.M1': type must be 'int' to match overridden member 'Base.M1'
// public override short M1 => 1;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M1").WithArguments("Derived.M1", "Base.M1", "int").WithLocation(9, 27),
// (10,23): error CS1715: 'Derived.M2': type must be 'A' to match overridden member 'Base.M2'
// public override B M2 => null;
Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "M2").WithArguments("Derived.M2", "Base.M2", "A").WithLocation(10, 23)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M1", "System.Int16 Derived.M1 { get; }", "System.Int32 Base.M1 { get; }");
VerifyOverride(comp, "Derived.get_M1", "System.Int16 Derived.M1.get", "System.Int32 Base.M1.get");
VerifyOverride(comp, "Derived.M2", "B Derived.M2 { get; }", "A Base.M2 { get; }");
VerifyOverride(comp, "Derived.get_M2", "B Derived.M2.get", "A Base.M2.get");
VerifyAssignments(comp, 4);
}
}
[Fact]
public void CovariantReturns_12()
{
var source = @"
public class Base
{
public virtual System.IComparable M => null;
}
public class Derived : Base
{
public override string M => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
System.IComparable x1 = b.M;
string x2 = d.M;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: System.IComparable x1 = b.M;
IL_0000: ldarg.1
IL_0001: callvirt ""System.IComparable Base.M.get""
IL_0006: pop
// sequence point: string x2 = d.M;
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.M.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M { get; }", "System.IComparable Base.M { get; }");
VerifyOverride(comp, "Derived.get_M", "System.String Derived.M.get", "System.IComparable Base.M.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void NoCovariantImplementations_01()
{
var source = @"
public interface Base
{
public virtual object M1 => null;
public virtual object M2() => null;
}
public interface Derived : Base
{
string Base.M1 => null; // 1
string Base.M2() => null; // 2
}
public class C : Base
{
string Base.M1 => null; // 3
string Base.M2() => null; // 4
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d, C c)
{
object x1 = b.M1;
object x2 = b.M2();
object x3 = d.M1;
object x4 = d.M2();
}
}
";
// these are poor diagnostics; see https://github.com/dotnet/roslyn/issues/43719
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (9,17): error CS0539: 'Derived.M1' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M1 => null; // 1
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M1").WithArguments("Derived.M1").WithLocation(9, 17),
// (10,17): error CS0539: 'Derived.M2()' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M2() => null; // 2
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M2").WithArguments("Derived.M2()").WithLocation(10, 17),
// (14,17): error CS0539: 'C.M1' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M1 => null; // 3
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M1").WithArguments("C.M1").WithLocation(14, 17),
// (15,17): error CS0539: 'C.M2()' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M2() => null; // 4
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M2").WithArguments("C.M2()").WithLocation(15, 17)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (9,17): error CS0539: 'Derived.M1' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M1 => null; // 1
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M1").WithArguments("Derived.M1").WithLocation(9, 17),
// (10,17): error CS0539: 'Derived.M2()' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M2() => null; // 2
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M2").WithArguments("Derived.M2()").WithLocation(10, 17),
// (14,17): error CS0539: 'C.M1' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M1 => null; // 3
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M1").WithArguments("C.M1").WithLocation(14, 17),
// (15,17): error CS0539: 'C.M2()' in explicit interface declaration is not found among members of the interface that can be implemented
// string Base.M2() => null; // 4
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "M2").WithArguments("C.M2()").WithLocation(15, 17)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyNoOverride(comp, "Derived.Base.M1");
VerifyNoOverride(comp, "Derived.Base.M2");
VerifyNoOverride(comp, "C.Base.M1");
VerifyNoOverride(comp, "C.Base.M2");
VerifyAssignments(comp, 4);
}
}
[Fact]
public void CovariantReturns_13()
{
var source = @"
public class Base
{
public virtual object P { get; set; }
}
public class Derived : Base
{
public override string P { get => string.Empty; }
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d)
{
object x1 = b.P;
string x2 = d.P;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P { get => string.Empty; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(8, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 15 (0xf)
.maxstack 1
// sequence point: object x1 = b.P;
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.P.get""
IL_0006: pop
// sequence point: string x2 = d.P;
IL_0007: ldarg.2
IL_0008: callvirt ""string Derived.P.get""
IL_000d: pop
// sequence point: }
IL_000e: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.String Derived.P { get; }", "System.Object Base.P { get; set; }");
VerifyOverride(comp, "Derived.get_P", "System.String Derived.P.get", "System.Object Base.P.get");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_14()
{
var source = @"
public class Base
{
public virtual object P { get; set; }
}
public class Derived : Base
{
public override string P { get => string.Empty; }
}
public class Derived2 : Derived
{
public override string P { get => string.Empty; set { } }
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2)
{
object x1 = b.P;
string x2 = d1.P;
string x3 = d2.P;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P { get => string.Empty; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(8, 28),
// (12,53): error CS0546: 'Derived2.P.set': cannot override because 'Derived.P' does not have an overridable set accessor
// public override string P { get => string.Empty; set { } }
Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived2.P.set", "Derived.P").WithLocation(12, 53)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (12,53): error CS0546: 'Derived2.P.set': cannot override because 'Derived.P' does not have an overridable set accessor
// public override string P { get => string.Empty; set { } }
Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived2.P.set", "Derived.P").WithLocation(12, 53)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.String Derived.P { get; }", "System.Object Base.P { get; set; }");
VerifyOverride(comp, "Derived.get_P", "System.String Derived.P.get", "System.Object Base.P.get");
VerifyOverride(comp, "Derived2.P", "System.String Derived2.P { get; set; }", "System.String Derived.P { get; }");
VerifyOverride(comp, "Derived2.get_P", "System.String Derived2.P.get", "System.String Derived.P.get");
VerifyNoOverride(comp, "Derived2.set_P");
VerifyAssignments(comp, 3);
}
}
[Fact]
public void CovariantReturns_15()
{
var source = @"
public class Base
{
public virtual object P { get; set; }
}
public class Derived : Base
{
public override string P { get => string.Empty; }
}
public class Derived2 : Derived
{
public override string P { set { } }
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2)
{
object x1 = b.P;
string x2 = d1.P;
string x3 = d2.P;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P { get => string.Empty; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(8, 28),
// (12,32): error CS0546: 'Derived2.P.set': cannot override because 'Derived.P' does not have an overridable set accessor
// public override string P { set { } }
Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived2.P.set", "Derived.P").WithLocation(12, 32)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (12,32): error CS0546: 'Derived2.P.set': cannot override because 'Derived.P' does not have an overridable set accessor
// public override string P { set { } }
Diagnostic(ErrorCode.ERR_NoSetToOverride, "set").WithArguments("Derived2.P.set", "Derived.P").WithLocation(12, 32)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.String Derived.P { get; }", "System.Object Base.P { get; set; }");
VerifyOverride(comp, "Derived.get_P", "System.String Derived.P.get", "System.Object Base.P.get");
VerifyOverride(comp, "Derived2.P", "System.String Derived2.P { set; }", "System.String Derived.P { get; }");
VerifyNoOverride(comp, "Derived2.set_P");
VerifyAssignments(comp, 3);
}
}
[Fact]
public void CovariantReturns_16()
{
var source = @"
public class Base
{
public virtual object P { get; set; }
}
public class Derived : Base
{
public override System.IComparable P { get => string.Empty; }
}
public class Derived2 : Derived
{
public override string P { get => string.Empty; }
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2)
{
object x1 = b.P;
System.IComparable x2 = d1.P;
string x3 = d2.P;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,40): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override System.IComparable P { get => string.Empty; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(8, 40),
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P { get => string.Empty; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(12, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived, Derived2)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 22 (0x16)
.maxstack 1
// sequence point: object x1 = b.P;
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.P.get""
IL_0006: pop
// sequence point: System.IComparable x2 = d1.P;
IL_0007: ldarg.2
IL_0008: callvirt ""System.IComparable Derived.P.get""
IL_000d: pop
// sequence point: string x3 = d2.P;
IL_000e: ldarg.3
IL_000f: callvirt ""string Derived2.P.get""
IL_0014: pop
// sequence point: }
IL_0015: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.IComparable Derived.P { get; }", "System.Object Base.P { get; set; }");
VerifyOverride(comp, "Derived.get_P", "System.IComparable Derived.P.get", "System.Object Base.P.get");
VerifyOverride(comp, "Derived2.P", "System.String Derived2.P { get; }", "System.IComparable Derived.P { get; }");
VerifyOverride(comp, "Derived2.get_P", "System.String Derived2.P.get", "System.IComparable Derived.P.get");
VerifyAssignments(comp, 3);
}
}
[Fact]
public void CovariantReturns_17()
{
var source = @"
public class Base<T>
{
public virtual object M(string s) => null;
public virtual System.IComparable M(T s) => null;
}
public class Derived : Base<string>
{
public override string M(string s) => null;
}
";
var assignments = @"
public class Program
{
void M(Base<string> b, Derived d, string s)
{
object x1 = b.M(s);
string x2 = d.M(s);
}
}
";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
// (9,28): error CS0462: The inherited members 'Base<T>.M(string)' and 'Base<T>.M(T)' have the same signature in type 'Derived', so they cannot be overridden
// public override string M(string s) => null;
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Base<T>.M(string)", "Base<T>.M(T)", "Derived").WithLocation(9, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (9,28): error CS0462: The inherited members 'Base<T>.M(string)' and 'Base<T>.M(T)' have the same signature in type 'Derived', so they cannot be overridden
// public override string M(string s) => null;
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Base<T>.M(string)", "Base<T>.M(T)", "Derived").WithLocation(9, 28)
);
verify(SourceView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M(System.String s)", "System.Object Base<System.String>.M(System.String s)");
VerifyAssignments(comp, 2);
}
}
[Fact]
public void CovariantReturns_18()
{
var source = @"
public class Base
{
public virtual object M() => null;
}
public abstract class Derived : Base
{
public abstract override System.IComparable M();
}
public class Derived2 : Derived
{
public override string M() => null;
}
";
var assignments = @"
public class Program
{
void M(Base b, Derived d1, Derived2 d2)
{
object x1 = b.M();
System.IComparable x2 = d1.M();
string x3 = d2.M();
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (8,49): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public abstract override System.IComparable M();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(8, 49),
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(12, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
CompileAndVerify(SourceView(comp, assignments), verify: Verification.Skipped).VerifyIL("Program.M(Base, Derived, Derived2)", source: assignments, sequencePoints: "Program.M", expectedIL: @"
{
// Code size 22 (0x16)
.maxstack 1
// sequence point: object x1 = b.M();
IL_0000: ldarg.1
IL_0001: callvirt ""object Base.M()""
IL_0006: pop
// sequence point: System.IComparable x2 = d1.M();
IL_0007: ldarg.2
IL_0008: callvirt ""System.IComparable Derived.M()""
IL_000d: pop
// sequence point: string x3 = d2.M();
IL_000e: ldarg.3
IL_000f: callvirt ""string Derived2.M()""
IL_0014: pop
// sequence point: }
IL_0015: ret
}
");
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.IComparable Derived.M()", "System.Object Base.M()");
VerifyOverride(comp, "Derived2.M", "System.String Derived2.M()", "System.IComparable Derived.M()");
VerifyAssignments(comp, 3);
}
}
[Fact]
public void TestVBConsumption_01()
{
var source0 = @"
public class Base
{
public virtual object M() => null;
public virtual object P => null;
public virtual object this[int i] => null;
}
public abstract class Derived : Base
{
public override string M() => null;
public override string P => null;
public override string this[int i] => null;
}
";
var csComp = CreateCompilationWithCovariantReturns(source0).VerifyDiagnostics(
);
csComp.VerifyDiagnostics();
var csRef = csComp.EmitToImageReference();
var vbSource = @"
Imports System
Imports System.Linq.Expressions
Public Class Derived2 : Inherits Derived
Public Overrides Function M() As String
Return Nothing
End Function
Public Overrides ReadOnly Property P As String
Get
Return Nothing
End Get
End Property
Public Overrides Default ReadOnly Property Item(i As Integer) As String
Get
Return Nothing
End Get
End Property
Public Sub T(b as Base, d as Derived, d2 as Derived2)
Dim x1 As Object = b.M()
Dim x2 As Object = b.P
Dim x3 As Object = b(0)
Dim x4 As String = d.M()
Dim x5 As String = d.P
Dim x6 As String = d(0)
Dim x7 As String = d2.M()
Dim x8 As String = d2.P
Dim x9 As String = d2(0)
Dim x10 As String = MyBase.M()
Dim x11 As String = MyBase.P
Dim x12 As Func(Of Object) = AddressOf b.M
Dim x13 As Func(Of String) = AddressOf MyBase.M
Dim x14 As Expression(Of Func(Of Derived, String)) = Function(x As Derived) x.M()
Dim x15 As Expression(Of Func(Of Derived, Func(Of String))) = Function(x As Derived) AddressOf x.M
End Sub
End Class
";
var vbComp = CreateVisualBasicCompilation(code: vbSource, referencedAssemblies: csComp.References.Append(csRef));
vbComp.VerifyDiagnostics();
var vbTree = vbComp.SyntaxTrees[0];
var model = vbComp.GetSemanticModel(vbTree);
int count = 0;
foreach (var localDeclaration in vbTree.GetRoot().DescendantNodes().OfType<VisualBasic.Syntax.LocalDeclarationStatementSyntax>())
{
foreach (var declarator in localDeclaration.Declarators)
{
count++;
var initialValue = declarator.Initializer.Value;
var typeInfo = model.GetTypeInfo(initialValue);
switch (count)
{
case 14:
Assert.Null(typeInfo.Type);
Assert.Equal("System.Linq.Expressions.Expression(Of System.Func(Of Derived, String))", typeInfo.ConvertedType.ToDisplayString());
break;
case 15:
Assert.Null(typeInfo.Type);
Assert.Equal("System.Linq.Expressions.Expression(Of System.Func(Of Derived, System.Func(Of String)))", typeInfo.ConvertedType.ToDisplayString());
break;
default:
Assert.Equal(typeInfo.Type, typeInfo.ConvertedType);
break;
}
}
}
Assert.Equal(15, count);
CompileAndVerify(vbComp, verify: Verification.Skipped).VerifyIL("Derived2.T(Base, Derived, Derived2)", source: vbSource, sequencePoints: "Derived2.T", expectedIL: @"
{
// Code size 360 (0x168)
.maxstack 7
.locals init (Object V_0, //x1
Object V_1, //x2
Object V_2, //x3
String V_3, //x4
String V_4, //x5
String V_5, //x6
String V_6, //x7
String V_7, //x8
String V_8, //x9
String V_9, //x10
String V_10, //x11
System.Func(Of Object) V_11, //x12
System.Func(Of String) V_12, //x13
System.Linq.Expressions.Expression(Of System.Func(Of Derived, String)) V_13, //x14
System.Linq.Expressions.Expression(Of System.Func(Of Derived, System.Func(Of String))) V_14, //x15
System.Linq.Expressions.ParameterExpression V_15)
// sequence point: Public Sub T(b as Base, d as Derived, d2 as Derived2)
IL_0000: nop
// sequence point: x1 As Object = b.M()
IL_0001: ldarg.1
IL_0002: callvirt ""Function Base.M() As Object""
IL_0007: call ""Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object""
IL_000c: stloc.0
// sequence point: x2 As Object = b.P
IL_000d: ldarg.1
IL_000e: callvirt ""Function Base.get_P() As Object""
IL_0013: call ""Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object""
IL_0018: stloc.1
// sequence point: x3 As Object = b(0)
IL_0019: ldarg.1
IL_001a: ldc.i4.0
IL_001b: callvirt ""Function Base.get_Item(Integer) As Object""
IL_0020: call ""Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object""
IL_0025: stloc.2
// sequence point: x4 As String = d.M()
IL_0026: ldarg.2
IL_0027: callvirt ""Function Derived.M() As String""
IL_002c: stloc.3
// sequence point: x5 As String = d.P
IL_002d: ldarg.2
IL_002e: callvirt ""Function Derived.get_P() As String""
IL_0033: stloc.s V_4
// sequence point: x6 As String = d(0)
IL_0035: ldarg.2
IL_0036: ldc.i4.0
IL_0037: callvirt ""Function Derived.get_Item(Integer) As String""
IL_003c: stloc.s V_5
// sequence point: x7 As String = d2.M()
IL_003e: ldarg.3
IL_003f: callvirt ""Function Derived2.M() As String""
IL_0044: stloc.s V_6
// sequence point: x8 As String = d2.P
IL_0046: ldarg.3
IL_0047: callvirt ""Function Derived2.get_P() As String""
IL_004c: stloc.s V_7
// sequence point: x9 As String = d2(0)
IL_004e: ldarg.3
IL_004f: ldc.i4.0
IL_0050: callvirt ""Function Derived2.get_Item(Integer) As String""
IL_0055: stloc.s V_8
// sequence point: x10 As String = MyBase.M()
IL_0057: ldarg.0
IL_0058: call ""Function Derived.M() As String""
IL_005d: stloc.s V_9
// sequence point: x11 As String = MyBase.P
IL_005f: ldarg.0
IL_0060: call ""Function Derived.get_P() As String""
IL_0065: stloc.s V_10
// sequence point: x12 As Func(Of Object) = AddressOf b.M
IL_0067: ldarg.1
IL_0068: dup
IL_0069: ldvirtftn ""Function Base.M() As Object""
IL_006f: newobj ""Sub System.Func(Of Object)..ctor(Object, System.IntPtr)""
IL_0074: stloc.s V_11
// sequence point: x13 As Func(Of String) = AddressOf MyBase.M
IL_0076: ldarg.0
IL_0077: ldftn ""Function Derived.M() As String""
IL_007d: newobj ""Sub System.Func(Of String)..ctor(Object, System.IntPtr)""
IL_0082: stloc.s V_12
// sequence point: x14 As Expression(Of Func(Of Derived, String)) = Function(x As Derived) x.M()
IL_0084: ldtoken ""Derived""
IL_0089: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_008e: ldstr ""x""
IL_0093: call ""Function System.Linq.Expressions.Expression.Parameter(System.Type, String) As System.Linq.Expressions.ParameterExpression""
IL_0098: stloc.s V_15
IL_009a: ldloc.s V_15
IL_009c: ldtoken ""Function Derived.M() As String""
IL_00a1: call ""Function System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle) As System.Reflection.MethodBase""
IL_00a6: castclass ""System.Reflection.MethodInfo""
IL_00ab: ldc.i4.0
IL_00ac: newarr ""System.Linq.Expressions.Expression""
IL_00b1: call ""Function System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, ParamArray System.Linq.Expressions.Expression()) As System.Linq.Expressions.MethodCallExpression""
IL_00b6: ldc.i4.1
IL_00b7: newarr ""System.Linq.Expressions.ParameterExpression""
IL_00bc: dup
IL_00bd: ldc.i4.0
IL_00be: ldloc.s V_15
IL_00c0: stelem.ref
IL_00c1: call ""Function System.Linq.Expressions.Expression.Lambda(Of System.Func(Of Derived, String))(System.Linq.Expressions.Expression, ParamArray System.Linq.Expressions.ParameterExpression()) As System.Linq.Expressions.Expression(Of System.Func(Of Derived, String))""
IL_00c6: stloc.s V_13
// sequence point: x15 As Expression(Of Func(Of Derived, Func(Of String))) = Function(x As Derived) AddressOf x.M
IL_00c8: ldtoken ""Derived""
IL_00cd: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_00d2: ldstr ""x""
IL_00d7: call ""Function System.Linq.Expressions.Expression.Parameter(System.Type, String) As System.Linq.Expressions.ParameterExpression""
IL_00dc: stloc.s V_15
IL_00de: ldtoken ""Function Derived.M() As String""
IL_00e3: call ""Function System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle) As System.Reflection.MethodBase""
IL_00e8: castclass ""System.Reflection.MethodInfo""
IL_00ed: ldtoken ""System.Reflection.MethodInfo""
IL_00f2: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_00f7: call ""Function System.Linq.Expressions.Expression.Constant(Object, System.Type) As System.Linq.Expressions.ConstantExpression""
IL_00fc: ldtoken ""Function System.Reflection.MethodInfo.CreateDelegate(System.Type, Object) As System.Delegate""
IL_0101: call ""Function System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle) As System.Reflection.MethodBase""
IL_0106: castclass ""System.Reflection.MethodInfo""
IL_010b: ldc.i4.2
IL_010c: newarr ""System.Linq.Expressions.Expression""
IL_0111: dup
IL_0112: ldc.i4.0
IL_0113: ldtoken ""System.Func(Of String)""
IL_0118: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_011d: ldtoken ""System.Type""
IL_0122: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_0127: call ""Function System.Linq.Expressions.Expression.Constant(Object, System.Type) As System.Linq.Expressions.ConstantExpression""
IL_012c: stelem.ref
IL_012d: dup
IL_012e: ldc.i4.1
IL_012f: ldloc.s V_15
IL_0131: ldtoken ""Object""
IL_0136: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_013b: call ""Function System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type) As System.Linq.Expressions.UnaryExpression""
IL_0140: stelem.ref
IL_0141: call ""Function System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, ParamArray System.Linq.Expressions.Expression()) As System.Linq.Expressions.MethodCallExpression""
IL_0146: ldtoken ""System.Func(Of String)""
IL_014b: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_0150: call ""Function System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type) As System.Linq.Expressions.UnaryExpression""
IL_0155: ldc.i4.1
IL_0156: newarr ""System.Linq.Expressions.ParameterExpression""
IL_015b: dup
IL_015c: ldc.i4.0
IL_015d: ldloc.s V_15
IL_015f: stelem.ref
IL_0160: call ""Function System.Linq.Expressions.Expression.Lambda(Of System.Func(Of Derived, System.Func(Of String)))(System.Linq.Expressions.Expression, ParamArray System.Linq.Expressions.ParameterExpression()) As System.Linq.Expressions.Expression(Of System.Func(Of Derived, System.Func(Of String)))""
IL_0165: stloc.s V_14
// sequence point: End Sub
IL_0167: ret
}
");
}
[Fact]
public void BinaryCompatibility_01()
{
var s0 = @"
public class Base
{
public virtual object M() => null;
}
";
var ref0 = CreateCompilationWithoutCovariantReturns(s0).EmitToImageReference();
var s1a = @"
public class Mid : Base
{
}
";
var ref1a = CreateCompilationWithoutCovariantReturns(
s1a,
references: new[] { ref0 },
assemblyName: "ref1").EmitToImageReference();
var s1b = @"
public class Mid : Base
{
public override string M() => null;
}
";
var ref1b = CreateCompilationWithCovariantReturns(
s1b,
references: new[] { ref0 },
assemblyName: "ref1").EmitToImageReference();
var s2 = @"
public class Derived : Mid
{
public override string M() => null;
}
";
var assignments1 = @"
public class Program
{
void M(Base b, Mid m, Derived d)
{
object x1 = b.M();
object x2 = m.M();
string x3 = d.M();
}
}
";
var assignments2 = @"
public class Program
{
void M(Base b, Mid m, Derived d)
{
object x1 = b.M();
string x2 = m.M();
string x3 = d.M();
}
}
";
var references = new[] { ref0, ref1a };
var comp = CreateCompilationWithCovariantReturns(s2, references, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify1(SourceView(comp, assignments1));
comp = CreateCompilationWithCovariantReturns(s2, references).VerifyDiagnostics(
);
verify1(SourceView(comp, assignments1));
verify1(CompilationReferenceView(comp, assignments1, references));
verify1(MetadataView(comp, assignments1, references));
verify1(RetargetingView(comp, assignments1, references));
references = new[] { ref0, ref1b };
// we do not test CompilationReferenceView because the changed reference would cause us to retarget
verify2(MetadataView(comp, assignments2, references));
verify2(RetargetingView(comp, assignments2, references));
static void verify1(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
}
static void verify2(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
VerifyOverride(comp, "Mid.M", "System.String Mid.M()", "System.Object Base.M()");
}
}
[Fact]
public void BinaryCompatibility_02()
{
var s0 = @"
public class Base
{
public virtual object P => null;
}
";
var ref0 = CreateCompilationWithoutCovariantReturns(s0).EmitToImageReference();
var s1a = @"
public class Mid : Base
{
}
";
var ref1a = CreateCompilationWithoutCovariantReturns(s1a, references: new[] { ref0 }, assemblyName: "ref1").EmitToImageReference();
var s1b = @"
public class Mid : Base
{
public override string P => null;
}
";
var ref1b = CreateCompilationWithCovariantReturns(s1b, references: new[] { ref0 }, assemblyName: "ref1").EmitToImageReference();
var s2 = @"
public class Derived : Mid
{
public override string P => null;
}
";
var assignments = "";
var references = new[] { ref0, ref1a };
var comp = CreateCompilationWithCovariantReturns(s2, references, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify1(comp);
comp = CreateCompilationWithCovariantReturns(s2, references).VerifyDiagnostics(
);
verify1(comp);
verify1(CompilationReferenceView(comp, assignments, references));
verify1(MetadataView(comp, assignments, references));
verify1(RetargetingView(comp, assignments, references));
references = new[] { ref0, ref1b };
// we do not test CompilationReferenceView because the changed reference would cause us to retarget
verify2(MetadataView(comp, assignments, references));
verify2(RetargetingView(comp, assignments, references));
static void verify1(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.P", "System.String Derived.P { get; }", "System.Object Base.P { get; }");
VerifyOverride(comp, "Derived.get_P", "System.String Derived.P.get", "System.Object Base.P.get");
}
static void verify2(CSharpCompilation comp)
{
verify1(comp);
VerifyOverride(comp, "Mid.P", "System.String Mid.P { get; }", "System.Object Base.P { get; }");
VerifyOverride(comp, "Mid.get_P", "System.String Mid.P.get", "System.Object Base.P.get");
}
}
[Fact]
public void BinaryCompatibility_03()
{
var s0 = @"
public class Base
{
public virtual object M() => null;
}
";
var ref0 = CreateCompilationWithoutCovariantReturns(s0).EmitToImageReference();
var s1a = @"
public class Mid : Base
{
}
";
var ref1a = CreateCompilationWithoutCovariantReturns(s1a, references: new[] { ref0 }, assemblyName: "ref1").EmitToImageReference();
var s1b = @"
public class Mid : Base
{
public override object M() => null;
}
";
var ref1b = CreateCompilationWithCovariantReturns(s1b, references: new[] { ref0 }, assemblyName: "ref1").EmitToImageReference();
var s2 = @"
public class Derived : Mid
{
public override string M() => null;
}
";
var assignments = "";
var references = new[] { ref0, ref1a };
var comp = CreateCompilationWithCovariantReturns(s2, references, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(4, 28)
);
verify1(comp);
comp = CreateCompilationWithCovariantReturns(s2, references).VerifyDiagnostics(
);
verify1(comp);
verify1(CompilationReferenceView(comp, assignments, references));
verify1(MetadataView(comp, assignments, references));
verify1(RetargetingView(comp, assignments, references));
references = new[] { ref0, ref1b };
// we do not test CompilationReferenceView because the changed reference would cause us to retarget
verify2(MetadataView(comp, assignments, references));
verify2(RetargetingView(comp, assignments, references));
static void verify1(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
}
static void verify2(CSharpCompilation comp)
{
// When viewed from metadata, we do not see a relationship between Derived.M and Mid.M because
// there is nothing in the metadata to indicate there is relationship. The compiler
// does not simulate the covariant language rules on metadata nor does the compiler simulate the
// virtual slot unification that the runtime does.
VerifyOverride(comp, "Derived.M", "System.String Derived.M()", "System.Object Base.M()");
VerifyOverride(comp, "Mid.M", "System.Object Mid.M()", "System.Object Base.M()");
}
}
[Fact]
public void LegacyMethodimplRequirements_01()
{
var source = @"
public class A
{
public virtual string get_P() => null;
}
public class B : A
{
public virtual string P => null;
}
public class C : B
{
public override string get_P() => null;
}
public class D : C
{
public override string P => null;
}
";
var assignments = "";
var comp = CreateCompilationWithoutCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "C.get_P", "System.String C.get_P()", "System.String A.get_P()", requiresMethodimpl: true);
VerifyOverride(comp, "D.P", "System.String D.P { get; }", "System.String B.P { get; }", requiresMethodimpl: true);
VerifyOverride(comp, "D.get_P", "System.String D.P.get", "System.String B.P.get", requiresMethodimpl: true);
}
}
[Fact]
public void OverlappingMethodimplRequirements_01()
{
var source = @"
public class A
{
public virtual object get_P() => null;
}
public class B : A
{
public virtual object P => null;
}
public class C : B
{
public override string get_P() => null;
}
public class D : C
{
public override string P => null;
}
";
var assignments = "";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (14,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string get_P() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "get_P").WithArguments("covariant returns", "9.0").WithLocation(14, 28),
// (19,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(19, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "C.get_P", "System.String C.get_P()", "System.Object A.get_P()");
VerifyOverride(comp, "D.P", "System.String D.P { get; }", "System.Object B.P { get; }");
VerifyOverride(comp, "D.get_P", "System.String D.P.get", "System.Object B.P.get");
}
}
[Fact]
public void OverlappingMethodimplRequirements_02()
{
var source = @"
public class A
{
public virtual string P => null;
}
public class B : A
{
public virtual new object P => null;
}
public class C : B
{
public override string P => null;
}
";
var assignments = "";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P").WithArguments("covariant returns", "9.0").WithLocation(12, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyNoOverride(comp, "A.P");
VerifyNoOverride(comp, "A.get_P");
VerifyNoOverride(comp, "B.P");
VerifyNoOverride(comp, "B.get_P");
VerifyOverride(comp, "C.P", "System.String C.P { get; }", "System.Object B.P { get; }");
VerifyOverride(comp, "C.get_P", "System.String C.P.get", "System.Object B.P.get");
}
}
[Fact]
public void OverlappingMethodimplRequirements_03()
{
var source = @"
public class A
{
public virtual string M() => null;
}
public class B : A
{
public virtual new object M() => null;
}
public class C : B
{
public override string M() => null;
}
";
var assignments = "";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0").WithLocation(12, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyNoOverride(comp, "A.M");
VerifyNoOverride(comp, "B.M");
VerifyOverride(comp, "C.M", "System.String C.M()", "System.Object B.M()");
}
}
[Fact]
public void InExpressionTree_01()
{
var source = @"
using System;
using System.Linq.Expressions;
public class Base
{
public virtual object M() => null;
public virtual object P => null;
}
public class Derived : Base
{
public override string M() => null;
public override string P => null;
}
public class Program : Derived
{
Expression<Func<Derived, string>> M1()
{
return d => d.M();
}
Expression<Func<Derived, string>> M2()
{
return d => d.P;
}
Expression<Func<Func<string>>> M3()
{
return () => M;
}
Expression<Func<Func<string>>> M4()
{
return () => new Func<string>(M);
}
}
";
var comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Program.M1()", source: source, sequencePoints: "Program.M1", expectedIL: @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0)
// sequence point: return d => d.M();
IL_0000: ldtoken ""Derived""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""d""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldtoken ""string Derived.M()""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: call ""System.Linq.Expressions.Expression[] System.Array.Empty<System.Linq.Expressions.Expression>()""
IL_002a: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_002f: ldc.i4.1
IL_0030: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0035: dup
IL_0036: ldc.i4.0
IL_0037: ldloc.0
IL_0038: stelem.ref
IL_0039: call ""System.Linq.Expressions.Expression<System.Func<Derived, string>> System.Linq.Expressions.Expression.Lambda<System.Func<Derived, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003e: ret
}
");
verifier.VerifyIL("Program.M2()", source: source, sequencePoints: "Program.M2", expectedIL: @"
{
// Code size 58 (0x3a)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0)
// sequence point: return d => d.P;
IL_0000: ldtoken ""Derived""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""d""
IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: ldtoken ""string Derived.P.get""
IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0020: castclass ""System.Reflection.MethodInfo""
IL_0025: call ""System.Linq.Expressions.MemberExpression System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002a: ldc.i4.1
IL_002b: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0030: dup
IL_0031: ldc.i4.0
IL_0032: ldloc.0
IL_0033: stelem.ref
IL_0034: call ""System.Linq.Expressions.Expression<System.Func<Derived, string>> System.Linq.Expressions.Expression.Lambda<System.Func<Derived, string>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0039: ret
}
");
verifier.VerifyIL("Program.M3()", source: source, sequencePoints: "Program.M3", expectedIL: @"
{
// Code size 129 (0x81)
.maxstack 7
// sequence point: return () => M;
IL_0000: ldtoken ""string Derived.M()""
IL_0005: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_000a: castclass ""System.Reflection.MethodInfo""
IL_000f: ldtoken ""System.Reflection.MethodInfo""
IL_0014: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0019: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_001e: ldtoken ""System.Delegate System.Reflection.MethodInfo.CreateDelegate(System.Type, object)""
IL_0023: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0028: castclass ""System.Reflection.MethodInfo""
IL_002d: ldc.i4.2
IL_002e: newarr ""System.Linq.Expressions.Expression""
IL_0033: dup
IL_0034: ldc.i4.0
IL_0035: ldtoken ""System.Func<string>""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: ldtoken ""System.Type""
IL_0044: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0049: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_004e: stelem.ref
IL_004f: dup
IL_0050: ldc.i4.1
IL_0051: ldarg.0
IL_0052: ldtoken ""Program""
IL_0057: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_005c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0061: stelem.ref
IL_0062: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_0067: ldtoken ""System.Func<string>""
IL_006c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0071: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0076: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()""
IL_007b: call ""System.Linq.Expressions.Expression<System.Func<System.Func<string>>> System.Linq.Expressions.Expression.Lambda<System.Func<System.Func<string>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0080: ret
}
");
verifier.VerifyIL("Program.M4()", source: source, sequencePoints: "Program.M4", expectedIL: @"
{
// Code size 129 (0x81)
.maxstack 7
// sequence point: return () => new Func<string>(M);
IL_0000: ldtoken ""string Derived.M()""
IL_0005: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_000a: castclass ""System.Reflection.MethodInfo""
IL_000f: ldtoken ""System.Reflection.MethodInfo""
IL_0014: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0019: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_001e: ldtoken ""System.Delegate System.Reflection.MethodInfo.CreateDelegate(System.Type, object)""
IL_0023: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0028: castclass ""System.Reflection.MethodInfo""
IL_002d: ldc.i4.2
IL_002e: newarr ""System.Linq.Expressions.Expression""
IL_0033: dup
IL_0034: ldc.i4.0
IL_0035: ldtoken ""System.Func<string>""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: ldtoken ""System.Type""
IL_0044: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0049: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_004e: stelem.ref
IL_004f: dup
IL_0050: ldc.i4.1
IL_0051: ldarg.0
IL_0052: ldtoken ""Program""
IL_0057: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_005c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)""
IL_0061: stelem.ref
IL_0062: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])""
IL_0067: ldtoken ""System.Func<string>""
IL_006c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0071: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0076: call ""System.Linq.Expressions.ParameterExpression[] System.Array.Empty<System.Linq.Expressions.ParameterExpression>()""
IL_007b: call ""System.Linq.Expressions.Expression<System.Func<System.Func<string>>> System.Linq.Expressions.Expression.Lambda<System.Func<System.Func<string>>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0080: ret
}
");
}
[Fact]
public void InDelegateCreation_01()
{
var source = @"
using System;
public class Base
{
public virtual object M() => null;
}
public class Derived : Base
{
public override string M() => null;
Func<string> M1() => M;
Func<object> M2() => base.M;
Func<string> M3() => new Func<string>(M);
Func<object> M4() => new Func<object>(base.M);
}
public class Program : Derived
{
Func<string> M1() => M;
Func<string> M2() => base.M;
Func<string> M3() => new Func<string>(M);
Func<string> M4() => new Func<string>(base.M);
}
";
var comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Derived.M1()", source: source, sequencePoints: "Derived.M1", expectedIL: @"
{
// Code size 14 (0xe)
.maxstack 2
// sequence point: M
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldvirtftn ""string Derived.M()""
IL_0008: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000d: ret
}
");
verifier.VerifyIL("Derived.M2()", source: source, sequencePoints: "Derived.M2", expectedIL: @"
{
// Code size 13 (0xd)
.maxstack 2
// sequence point: base.M
IL_0000: ldarg.0
IL_0001: ldftn ""object Base.M()""
IL_0007: newobj ""System.Func<object>..ctor(object, System.IntPtr)""
IL_000c: ret
}
");
verifier.VerifyIL("Derived.M3()", source: source, sequencePoints: "Derived.M3", expectedIL: @"
{
// Code size 14 (0xe)
.maxstack 2
// sequence point: new Func<string>(M)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldvirtftn ""string Derived.M()""
IL_0008: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000d: ret
}
");
verifier.VerifyIL("Derived.M4()", source: source, sequencePoints: "Derived.M4", expectedIL: @"
{
// Code size 13 (0xd)
.maxstack 2
// sequence point: new Func<object>(base.M)
IL_0000: ldarg.0
IL_0001: ldftn ""object Base.M()""
IL_0007: newobj ""System.Func<object>..ctor(object, System.IntPtr)""
IL_000c: ret
}
");
verifier.VerifyIL("Program.M1()", source: source, sequencePoints: "Program.M1", expectedIL: @"
{
// Code size 14 (0xe)
.maxstack 2
// sequence point: M
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldvirtftn ""string Derived.M()""
IL_0008: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000d: ret
}
");
verifier.VerifyIL("Program.M2()", source: source, sequencePoints: "Program.M2", expectedIL: @"
{
// Code size 13 (0xd)
.maxstack 2
// sequence point: base.M
IL_0000: ldarg.0
IL_0001: ldftn ""string Derived.M()""
IL_0007: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000c: ret
}
");
verifier.VerifyIL("Program.M3()", source: source, sequencePoints: "Program.M3", expectedIL: @"
{
// Code size 14 (0xe)
.maxstack 2
// sequence point: new Func<string>(M)
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldvirtftn ""string Derived.M()""
IL_0008: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000d: ret
}
");
verifier.VerifyIL("Program.M4()", source: source, sequencePoints: "Program.M4", expectedIL: @"
{
// Code size 13 (0xd)
.maxstack 2
// sequence point: new Func<string>(base.M)
IL_0000: ldarg.0
IL_0001: ldftn ""string Derived.M()""
IL_0007: newobj ""System.Func<string>..ctor(object, System.IntPtr)""
IL_000c: ret
}
");
}
[Fact]
public void NullableVariance_01()
{
var source = @"
#nullable enable
public class Base
{
public virtual object M1() => null!;
public virtual object P1 => null!;
public virtual object? M2() => null;
public virtual object? P2 => null;
public virtual IOut<object> M3() => null!;
public virtual IOut<object> P3 => null!;
public virtual IOut<object?> M4() => null!;
public virtual IOut<object?> P4 => null!;
public virtual IIn<string> M5() => null!;
public virtual IIn<string> P5 => null!;
public virtual IIn<string?> M6() => null!;
public virtual IIn<string?> P6 => null!;
}
public class Derived : Base
{
public override string? M1() => null;
public override string? P1 => null;
public override string M2() => null!;
public override string P2 => null!;
public override IOut<string?> M3() => null!;
public override IOut<string?> P3 => null!;
public override IOut<string> M4() => null!;
public override IOut<string> P4 => null!;
public override IIn<object?> M5() => null!;
public override IIn<object?> P5 => null!;
public override IIn<object> M6() => null!;
public override IIn<object> P6 => null!;
}
public interface IOut<out T> { }
public interface IIn<in T> { }
";
var assignments = @"
#nullable enable
public class Program
{
void M(Base b, Derived d)
{
object x1 = b.M1();
string? x2 = d.M1();
object x3 = b.P1;
string? x4 = d.P1;
object? x5 = b.M2();
string x6 = d.M2();
object? x7 = b.P2;
string x8 = d.P2;
IOut<object> x9 = b.M3();
IOut<string?> x10 = d.M3();
IOut<object> x11 = b.P3;
IOut<string?> x12 = d.P3;
IOut<object?> x13 = b.M4();
IOut<string> x14 = d.M4();
IOut<object?> x15 = b.P4;
IOut<string> x16 = d.P4;
IIn<string> x17 = b.M5();
IIn<object?> x18 = d.M5();
IIn<string> x19 = b.P5;
IIn<object?> x20 = d.P5;
IIn<string?> x21 = b.M6();
IIn<object> x22 = d.M6();
IIn<string?> x23 = b.P6;
IIn<object> x24 = d.P6;
}
}
";
var comp = CreateCompilationWithCovariantReturns(source, parseOptions: TestOptions.WithoutCovariantReturns).VerifyDiagnostics(
// (20,29): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string? M1() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("covariant returns", "9.0").WithLocation(20, 29),
// (21,29): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string? P1 => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P1").WithArguments("covariant returns", "9.0").WithLocation(21, 29),
// (22,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M2() => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M2").WithArguments("covariant returns", "9.0").WithLocation(22, 28),
// (23,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string P2 => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P2").WithArguments("covariant returns", "9.0").WithLocation(23, 28),
// (24,35): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IOut<string?> M3() => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M3").WithArguments("covariant returns", "9.0").WithLocation(24, 35),
// (25,35): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IOut<string?> P3 => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P3").WithArguments("covariant returns", "9.0").WithLocation(25, 35),
// (26,34): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IOut<string> M4() => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M4").WithArguments("covariant returns", "9.0").WithLocation(26, 34),
// (27,34): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IOut<string> P4 => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P4").WithArguments("covariant returns", "9.0").WithLocation(27, 34),
// (28,34): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IIn<object?> M5() => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M5").WithArguments("covariant returns", "9.0").WithLocation(28, 34),
// (29,34): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IIn<object?> P5 => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P5").WithArguments("covariant returns", "9.0").WithLocation(29, 34),
// (30,33): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IIn<object> M6() => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M6").WithArguments("covariant returns", "9.0").WithLocation(30, 33),
// (31,33): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override IIn<object> P6 => null!;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "P6").WithArguments("covariant returns", "9.0").WithLocation(31, 33)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(source).VerifyDiagnostics(
// (20,29): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// public override string? M1() => null;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "M1").WithLocation(20, 29),
// (21,35): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// public override string? P1 => null;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "null").WithLocation(21, 35),
// (24,35): warning CS8609: Nullability of reference types in return type doesn't match overridden member.
// public override IOut<string?> M3() => null!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "M3").WithLocation(24, 35),
// (25,41): warning CS8609: Nullability of reference types in return type doesn't match overridden member.
// public override IOut<string?> P3 => null!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "null!").WithLocation(25, 41),
// (30,33): warning CS8609: Nullability of reference types in return type doesn't match overridden member.
// public override IIn<object> M6() => null!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "M6").WithLocation(30, 33),
// (31,39): warning CS8609: Nullability of reference types in return type doesn't match overridden member.
// public override IIn<object> P6 => null!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "null!").WithLocation(31, 39)
);
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments));
verify(MetadataView(comp, assignments));
verify(RetargetingView(comp, assignments));
static void verify(CSharpCompilation comp)
{
VerifyOverride(comp, "Derived.M1", "System.String? Derived.M1()", "System.Object Base.M1()");
VerifyOverride(comp, "Derived.P1", "System.String? Derived.P1 { get; }", "System.Object Base.P1 { get; }");
VerifyOverride(comp, "Derived.M2", "System.String Derived.M2()", "System.Object? Base.M2()");
VerifyOverride(comp, "Derived.P2", "System.String Derived.P2 { get; }", "System.Object? Base.P2 { get; }");
VerifyOverride(comp, "Derived.M3", "IOut<System.String?> Derived.M3()", "IOut<System.Object> Base.M3()");
VerifyOverride(comp, "Derived.P3", "IOut<System.String?> Derived.P3 { get; }", "IOut<System.Object> Base.P3 { get; }");
VerifyOverride(comp, "Derived.M4", "IOut<System.String> Derived.M4()", "IOut<System.Object?> Base.M4()");
VerifyOverride(comp, "Derived.P4", "IOut<System.String> Derived.P4 { get; }", "IOut<System.Object?> Base.P4 { get; }");
VerifyOverride(comp, "Derived.M5", "IIn<System.Object?> Derived.M5()", "IIn<System.String> Base.M5()");
VerifyOverride(comp, "Derived.P5", "IIn<System.Object?> Derived.P5 { get; }", "IIn<System.String> Base.P5 { get; }");
VerifyOverride(comp, "Derived.M6", "IIn<System.Object> Derived.M6()", "IIn<System.String?> Base.M6()");
VerifyOverride(comp, "Derived.P6", "IIn<System.Object> Derived.P6 { get; }", "IIn<System.String?> Base.P6 { get; }");
VerifyAssignments(comp, 24);
}
}
[Fact]
public void PEMethodSymbol_ExplicitlyOverriddenClassMethod_WhenAmbiguous()
{
// See also related scenario in ExplicitOverrideWithoutCSharpOverride
var ilSource = @"
.assembly ilSource {}
.assembly extern mscorlib
{
.ver 4:1:0:0
}
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.method public hidebysig newslot virtual
instance object M1() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method Base::M1
.method public hidebysig newslot virtual
instance object M2() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method Base::M2
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Base::.ctor
} // end of class Base
.class public auto ansi beforefieldinit Derived
extends Base
{
.method public hidebysig newslot virtual
instance string M3() cil managed
{
.override method instance object class Base::M1() // different name, type
.override method instance object class Base::M2() // different name, type
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method Derived::M3
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void Base::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Derived::.ctor
}
";
var cSharpSource = @"
public class Override : Derived
{
public override string M1() => null;
public override string M2() => null;
public override string M3() => null;
}
";
var assignments = @"
public class Program
{
public void M(Derived d, Override o)
{
object x1 = d.M1();
object x2 = d.M2();
string x3 = d.M3();
string x4 = o.M1();
string x5 = o.M2();
string x6 = o.M3();
}
}
";
MetadataReference ilReference = CreateMetadataReferenceFromIlSource(ilSource, prependDefaultHeader: false);
var references = new[] { ilReference };
var comp = CreateCompilationWithCovariantReturns(cSharpSource, references, parseOptions: TestOptions.WithoutCovariantReturns);
comp.VerifyDiagnostics(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M1() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M1").WithArguments("covariant returns", "9.0").WithLocation(4, 28),
// (5,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M2() => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M2").WithArguments("covariant returns", "9.0").WithLocation(5, 28)
);
verify(SourceView(comp, assignments));
comp = CreateCompilationWithCovariantReturns(cSharpSource, references);
comp.VerifyDiagnostics();
verify(SourceView(comp, assignments));
verify(CompilationReferenceView(comp, assignments, references));
verify(MetadataView(comp, assignments, references));
verify(RetargetingView(comp, assignments, references));
void verify(CSharpCompilation comp)
{
VerifyNoOverride(comp, "Base.M1");
VerifyNoOverride(comp, "Base.M2");
VerifyNoOverride(comp, "Derived.M3");
VerifyOverride(comp, "Override.M1", "System.String Override.M1()", "System.Object Base.M1()");
VerifyOverride(comp, "Override.M2", "System.String Override.M2()", "System.Object Base.M2()");
VerifyOverride(comp, "Override.M3", "System.String Override.M3()", "System.String Derived.M3()");
VerifyAssignments(comp, 6);
var globalNamespace = comp.GlobalNamespace;
var derivedClass = globalNamespace.GetMember<NamedTypeSymbol>("Derived");
var overrideClass = globalNamespace.GetMember<NamedTypeSymbol>("Override");
var derivedMethod = derivedClass.GetMember<MethodSymbol>("M3");
var overrideMethod = overrideClass.GetMember<MethodSymbol>("M3");
// Note that the following values are inconsistent. That is "legacy" (early Roslyn) behavior that we preserve.
Assert.True(derivedMethod.IsOverride);
Assert.Null(derivedMethod.OverriddenMethod);
Assert.True(overrideMethod.IsOverride);
Assert.Equal(derivedMethod, overrideMethod.OverriddenMethod);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_01(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool methodRuntimeOverriddenSignatureAmbiguity,
bool overriddenRuntimeSignatureAmbiguity,
bool useCovariantReturns,
bool useSeparateCompilation
)
{
var overriddenMethodReturnType = useCovariantReturns ? "object" : "string";
var baseSource = $@"
public class Base1<Ptring>
{{
public virtual {overriddenMethodReturnType} M(ref Ptring x, out string y) {{ y = null; return null; }}
{(overriddenRuntimeSignatureAmbiguity ? @$"public virtual {overriddenMethodReturnType} M(ref Ptring x, ref Ptring y) {{ return null; }}" : "")}
}}
public class Base2<Ptring> : Base1<Ptring>
{{
public virtual string M(out string x, ref Ptring y) {{ x = null; return null; }}
{(methodRuntimeOverriddenSignatureAmbiguity ? "public virtual string M(out string x, out string y) { x = y = null; return null; }" : "")}
}}
";
var source = $@"
public class Derived : Base2<string>
{{
public override string M(ref string x, out string y) {{ y = null; return null; }}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var expectedDiagnostics = new DiagnosticDescription[0];
bool anyErrors = false;
if (useCovariantReturns)
{
if (!withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8778: 'Derived.M(ref string, out string)': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base1<string>.M(ref string, out string)'
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M(ref string, out string)", "Base1<string>.M(ref string, out string)", "object")
).ToArray();
anyErrors = true;
}
else if (!withCovariantReturnFeatureEnabled)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (15,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0")
).ToArray();
anyErrors = true;
}
}
bool warned = false;
if (overriddenRuntimeSignatureAmbiguity && !withCovariantCapableRuntime && !useCovariantReturns)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,27): warning CS1957: Member 'Derived.M(ref string, out string)' overrides 'Base1<string>.M(ref string, out string)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual string M(ref Ptring x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "M").WithArguments("Base1<string>.M(ref string, out string)", "Derived.M(ref string, out string)").WithLocation(4, 27)
).ToArray();
warned = true;
}
// All of the overrides in this test require a methodimpl because they are on a different class from the runtime override.
bool requiresMethodImpl = true;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
baseCompilation.VerifyDiagnostics();
var baseMetadata = baseCompilation.ToMetadataReference();
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.Equal(warned, shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
if (!anyErrors)
verify(MetadataView(comp, "", references: references, withoutCorlib: true));
void verify(CSharpCompilation compilation)
{
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "System.String Derived.M(ref System.String x, out System.String y)",
overriddenMemberDisplay: $"System.{(useCovariantReturns ? "Object" : "String")} Base1<System.String>.M(ref System.String x, out System.String y)",
requiresMethodimpl: requiresMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_02(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool methodRuntimeOverriddenSignatureAmbiguity,
bool overriddenRuntimeSignatureAmbiguity,
bool useCovariantReturns,
bool useSeparateCompilation
)
{
var overriddenMethodReturnType = useCovariantReturns ? "object" : "string";
var baseSource = $@"
public class Base1<Ptring>
{{
{(overriddenRuntimeSignatureAmbiguity ? @$"public virtual {overriddenMethodReturnType} M(ref Ptring x, ref Ptring y) {{ return null; }}" : "")}
public virtual {overriddenMethodReturnType} M(ref Ptring x, out string y) {{ y = null; return null; }}
}}
public class Base2<Ptring> : Base1<Ptring>
{{
{(methodRuntimeOverriddenSignatureAmbiguity ? "public virtual string M(out string x, out string y) { x = y = null; return null; }" : "")}
public virtual string M(out string x, ref Ptring y) {{ x = null; return null; }}
}}
";
var source = $@"
public class Derived : Base2<string>
{{
public override string M(ref string x, out string y) {{ y = null; return null; }}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
baseCompilation.VerifyDiagnostics();
var baseMetadata = baseCompilation.ToMetadataReference();
var expectedDiagnostics = new DiagnosticDescription[0];
bool anyErrors = false;
if (useCovariantReturns)
{
if (!withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8778: 'Derived.M(ref string, out string)': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base1<string>.M(ref string, out string)'
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M(ref string, out string)", "Base1<string>.M(ref string, out string)", "object")
).ToArray();
anyErrors = true;
}
else if (!withCovariantReturnFeatureEnabled)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (15,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0")
).ToArray();
anyErrors = true;
}
}
bool warned = false;
if (overriddenRuntimeSignatureAmbiguity && !withCovariantCapableRuntime && !useCovariantReturns)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (5,27): warning CS1957: Member 'Derived.M(ref string, out string)' overrides 'Base1<string>.M(ref string, out string)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual string M(ref Ptring x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "M").WithArguments("Base1<string>.M(ref string, out string)", "Derived.M(ref string, out string)").WithLocation(5, 27)
).ToArray();
warned = true;
}
// All of the overrides in this test require a methodimpl because they are on a different class from the runtime override.
bool requiresMethodImpl = true;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.Equal(warned, shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
if (!useCovariantReturns)
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
if (!anyErrors)
verify(MetadataView(comp, "", references: references, withoutCorlib: true));
void verify(CSharpCompilation compilation)
{
var lastReference = compilation.GetAssemblyOrModuleSymbol(compilation.References.Last());
// Due to https://github.com/dotnet/roslyn/issues/45566 retargeting methods do not resolve properly for this scenario
var isRetargeting = lastReference is RetargetingAssemblySymbol;
// Similarly, there is probably a corresponding bug in resolving PE method symbols
var isMetadata = lastReference is PEAssemblySymbol;
if (overriddenRuntimeSignatureAmbiguity && (isRetargeting || isMetadata))
return;
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "System.String Derived.M(ref System.String x, out System.String y)",
overriddenMemberDisplay: $"System.{(useCovariantReturns ? "Object" : "String")} Base1<System.String>.M(ref System.String x, out System.String y)",
requiresMethodimpl: requiresMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_03(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool methodRuntimeOverriddenSignatureAmbiguity,
bool overriddenRuntimeSignatureAmbiguity,
bool useCovariantReturns,
bool useSeparateCompilation
)
{
var overriddenMethodReturnType = useCovariantReturns ? "object" : "string";
var baseSource = $@"
public class Base<Ptring>
{{
public virtual {overriddenMethodReturnType} M(ref Ptring x, out string y) {{ y = null; return null; }}
{(overriddenRuntimeSignatureAmbiguity ? @$"public virtual {overriddenMethodReturnType} M(ref Ptring x, ref Ptring y) {{ return null; }}" : "")}
public virtual string M(out string x, ref Ptring y) {{ x = null; return null; }}
{(methodRuntimeOverriddenSignatureAmbiguity ? "public virtual string M(out string x, out string y) { x = y = null; return null; }" : "")}
}}
";
var source = $@"
public class Derived : Base<string>
{{
public override string M(ref string x, out string y) {{ y = null; return null; }}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var expectedDiagnostics = new DiagnosticDescription[0];
bool anyErrors = false;
if (useCovariantReturns)
{
if (!withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8778: 'Derived.M(ref string, out string)': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base<string>.M(ref string, out string)'
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M(ref string, out string)", "Base<string>.M(ref string, out string)", "object")
).ToArray();
anyErrors = true;
}
else if (!withCovariantReturnFeatureEnabled)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0")
).ToArray();
anyErrors = true;
}
}
bool warned = false;
if (!withCovariantCapableRuntime && !useCovariantReturns)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,27): warning CS1957: Member 'Derived.M(ref string, out string)' overrides 'Base<string>.M(ref string, out string)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual string M(ref Ptring x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "M").WithArguments("Base<string>.M(ref string, out string)", "Derived.M(ref string, out string)").WithLocation(4, 27)
).ToArray();
warned = true;
}
// Only if we warned did we not produce a methodimpl due to https://github.com/dotnet/roslyn/issues/45453
bool requiresMethodImpl = !warned;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
baseCompilation.VerifyDiagnostics();
var baseMetadata = baseCompilation.ToMetadataReference();
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.Equal(warned, shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
if (!anyErrors)
verify(MetadataView(comp, "", references: references, withoutCorlib: true));
void verify(CSharpCompilation compilation)
{
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "System.String Derived.M(ref System.String x, out System.String y)",
overriddenMemberDisplay: $"System.{(useCovariantReturns ? "Object" : "String")} Base<System.String>.M(ref System.String x, out System.String y)",
requiresMethodimpl: requiresMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_04(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool methodRuntimeOverriddenSignatureAmbiguity,
bool overriddenRuntimeSignatureAmbiguity,
bool useCovariantReturns,
bool useSeparateCompilation
)
{
var overriddenMethodReturnType = useCovariantReturns ? "object" : "string";
var baseSource = $@"
public class Base<Ptring>
{{
{(overriddenRuntimeSignatureAmbiguity ? @$"public virtual {overriddenMethodReturnType} M(ref Ptring x, ref Ptring y) {{ return null; }}" : "")}
public virtual {overriddenMethodReturnType} M(ref Ptring x, out string y) {{ y = null; return null; }}
{(methodRuntimeOverriddenSignatureAmbiguity ? "public virtual string M(out string x, out string y) { x = y = null; return null; }" : "")}
public virtual string M(out string x, ref Ptring y) {{ x = null; return null; }}
}}
";
var source = $@"
public class Derived : Base<string>
{{
public override string M(ref string x, out string y) {{ y = null; return null; }}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var expectedDiagnostics = new DiagnosticDescription[0];
bool anyErrors = false;
if (useCovariantReturns)
{
if (!withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8778: 'Derived.M(ref string, out string)': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base<string>.M(ref string, out string)'
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M(ref string, out string)", "Base<string>.M(ref string, out string)", "object")
).ToArray();
anyErrors = true;
}
else if (!withCovariantReturnFeatureEnabled)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (12,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M(ref string x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0")
).ToArray();
anyErrors = true;
}
}
bool warned = false;
if (!withCovariantCapableRuntime && !useCovariantReturns)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (5,27): warning CS1957: Member 'Derived.M(ref string, out string)' overrides 'Base<string>.M(ref string, out string)'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual string M(ref Ptring x, out string y) { y = null; return null; }
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "M").WithArguments("Base<string>.M(ref string, out string)", "Derived.M(ref string, out string)").WithLocation(5, 27)
).ToArray();
warned = true;
}
// Only if we warned did we not produce a methodimpl due to https://github.com/dotnet/roslyn/issues/45453
bool requiresMethodImpl = !warned;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
baseCompilation.VerifyDiagnostics();
var baseMetadata = baseCompilation.ToMetadataReference();
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.Equal(warned, shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
if (!useCovariantReturns)
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
if (!anyErrors)
verify(MetadataView(comp, "", references: references, withoutCorlib: true));
void verify(CSharpCompilation compilation)
{
var lastReference = compilation.GetAssemblyOrModuleSymbol(compilation.References.Last());
// Due to https://github.com/dotnet/roslyn/issues/45566 retargeting methods do not resolve properly for this scenario
var isRetargeting = lastReference is RetargetingAssemblySymbol;
// Similarly, there is probably a corresponding bug in resolving PE method symbols
var isMetadata = lastReference is PEAssemblySymbol;
if (isRetargeting || isMetadata)
return;
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "System.String Derived.M(ref System.String x, out System.String y)",
overriddenMemberDisplay: $"System.{(useCovariantReturns ? "Object" : "String")} Base<System.String>.M(ref System.String x, out System.String y)",
requiresMethodimpl: requiresMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_05(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool useSeparateCompilation
)
{
var baseSource = $@"
public class Base1<Ptring>
{{
public virtual string M(out string y) {{ y = null; return null; }}
public virtual string M(ref Ptring y) {{ return null; }}
}}
public class Base2<Ptring> : Base1<Ptring>
{{
public virtual new object M(out string y) {{ y = null; return null; }}
}}
";
var source = $@"
public class Derived : Base2<string>
{{
public override string M(out string y) {{ y = null; return null; }}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var expectedDiagnostics = new DiagnosticDescription[0];
bool anyErrors = false;
if (!withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8778: 'Derived.M(out string)': Target runtime doesn't support covariant return types in overrides. Return type must be 'object' to match overridden member 'Base2<string>.M(out string)'
// public override string M(out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantReturnsOfClasses, "M").WithArguments("Derived.M(out string)", "Base2<string>.M(out string)", "object")
).ToArray();
anyErrors = true;
}
else if (!withCovariantReturnFeatureEnabled)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (14,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string M(out string y) { y = null; return null; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "M").WithArguments("covariant returns", "9.0")
).ToArray();
anyErrors = true;
}
// All of the overrides in this test require a methodimpl because they are on a different class from the runtime override.
bool requiresMethodImpl = true;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
baseCompilation.VerifyDiagnostics();
var baseMetadata = baseCompilation.ToMetadataReference();
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
if (!anyErrors)
verify(MetadataView(comp, "", references: references, withoutCorlib: true));
void verify(CSharpCompilation compilation)
{
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "System.String Derived.M(out System.String y)",
overriddenMemberDisplay: "System.Object Base2<System.String>.M(out System.String y)",
requiresMethodimpl: requiresMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void OverrideAmbiguities_06(
bool withCovariantReturnFeatureEnabled,
bool withCovariantCapableRuntime,
bool withPropertyDeclarationFirst,
bool overrideProperty,
bool useCovariantReturns,
bool useSeparateCompilation
)
{
var propertyDeclaration = "public virtual Pbject Prop => default(Pbject);";
var methodDeclaration = "public virtual object get_Prop() => default(object);";
var baseSource = $@"
public class Base<Pbject>
{{
{(withPropertyDeclarationFirst ? propertyDeclaration : "")}
{methodDeclaration}
{(withPropertyDeclarationFirst ? "" : propertyDeclaration)}
}}
";
var overrideReturnType = useCovariantReturns ? "string" : "object";
var propertyOverride = $"public override {overrideReturnType} Prop => null;";
var methodOverride = $"public override {overrideReturnType} get_Prop() => null;";
var source = $@"
public class Derived : Base<object>
{{
{(overrideProperty ? propertyOverride : methodOverride)}
}}
";
var parseOptions = withCovariantReturnFeatureEnabled ? TestOptions.WithCovariantReturns : TestOptions.WithoutCovariantReturns;
var corlibRef = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport1 : CorelibraryWithoutCovariantReturnSupport1;
var corlib2Ref = withCovariantCapableRuntime ? CorelibraryWithCovariantReturnSupport2 : CorelibraryWithoutCovariantReturnSupport2;
var expectedDiagnostics = new DiagnosticDescription[0];
if (useCovariantReturns)
{
if (!withCovariantCapableRuntime)
{
if (overrideProperty)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8779: 'Derived.Prop': Target runtime doesn't support covariant types in overrides. Type must be 'object' to match overridden member 'Base<object>.Prop'
// public override string Prop => null;
Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportCovariantPropertiesOfClasses, "Prop").WithArguments("Derived.Prop", "Base<object>.Prop", "object")
).ToArray();
}
else
{
// This is treated as a suppressed cascaded diagnostic and therefore not reported.
}
}
else if (!withCovariantReturnFeatureEnabled)
{
if (overrideProperty)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS8400: Feature 'covariant returns' is not available in C# 8.0. Please use language version 9.0 or greater.
// public override string Prop => null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "Prop").WithArguments("covariant returns", "9.0")
).ToArray();
}
else
{
// This is treated as a suppressed cascaded diagnostic and therefore not reported.
}
}
}
// The ERR_AmbigOverride errors are all cascaded diagnostics, a consequence of ERR_MemberReserved in Base.
if (overrideProperty)
{
if (!useCovariantReturns ||
useCovariantReturns && withCovariantReturnFeatureEnabled && withCovariantCapableRuntime)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,36): error CS0462: The inherited members 'Base<Pbject>.Prop.get' and 'Base<Pbject>.get_Prop()' have the same signature in type 'Derived', so they cannot be overridden
// public override object Prop => null;
Diagnostic(ErrorCode.ERR_AmbigOverride, "null").WithArguments("Base<Pbject>.Prop.get", "Base<Pbject>.get_Prop()", "Derived")
).ToArray();
}
}
else
{
expectedDiagnostics = expectedDiagnostics.Append(
// (4,28): error CS0462: The inherited members 'Base<Pbject>.get_Prop()' and 'Base<Pbject>.Prop.get' have the same signature in type 'Derived', so they cannot be overridden
// public override object get_Prop() => null;
Diagnostic(ErrorCode.ERR_AmbigOverride, "get_Prop").WithArguments("Base<Pbject>.get_Prop()", "Base<Pbject>.Prop.get", "Derived")
).ToArray();
}
bool deservesAmbiguousOverrideWarning = !withCovariantCapableRuntime && !useCovariantReturns;
if (deservesAmbiguousOverrideWarning)
{
if (overrideProperty)
{
expectedDiagnostics = expectedDiagnostics.Append(
// (6,35): warning CS1957: Member 'Derived.Prop.get' overrides 'Base<object>.Prop.get'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual Pbject Prop => default(Pbject);
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "default(Pbject)").WithArguments("Base<object>.Prop.get", "Derived.Prop.get")
).ToArray();
}
else
{
expectedDiagnostics = expectedDiagnostics.Append(
// (5,27): warning CS1957: Member 'Derived.get_Prop()' overrides 'Base<object>.get_Prop()'. There are multiple override candidates at run-time. It is implementation dependent which method will be called. Please use a newer runtime.
// public virtual object get_Prop() => default(object);
Diagnostic(ErrorCode.WRN_MultipleRuntimeOverrideMatches, "get_Prop").WithArguments("Base<object>.get_Prop()", "Derived.get_Prop()")
).ToArray();
}
}
bool requiresMethodImpl = useCovariantReturns || withCovariantCapableRuntime || withPropertyDeclarationFirst != overrideProperty;
MetadataReference[] references;
MetadataReference[] retargetReferences;
string compilationSource;
if (useSeparateCompilation)
{
var baseCompilation = CreateCompilation(baseSource, references: new[] { corlibRef }, targetFramework: TargetFramework.Empty, parseOptions: parseOptions);
var baseDiagnostic =
// (6,35): error CS0082: Type 'Base<Pbject>' already reserves a member called 'get_Prop' with the same parameter types
// public virtual Pbject Prop => default(Pbject);
Diagnostic(ErrorCode.ERR_MemberReserved, "default(Pbject)").WithArguments("get_Prop", "Base<Pbject>").WithLocation(withPropertyDeclarationFirst ? 4 : 6, 35);
baseCompilation.VerifyDiagnostics(baseDiagnostic);
var baseMetadata = baseCompilation.ToMetadataReference();
references = new[] { corlibRef, baseMetadata };
retargetReferences = new[] { corlib2Ref, baseMetadata };
compilationSource = source;
verify(RetargetingView(baseCompilation, compilationSource, expectedDiagnostics: expectedDiagnostics));
}
else
{
references = new[] { corlibRef };
retargetReferences = new[] { corlib2Ref };
compilationSource = baseSource + source;
expectedDiagnostics = expectedDiagnostics.Prepend(
// (6,35): error CS0082: Type 'Base<Pbject>' already reserves a member called 'get_Prop' with the same parameter types
// public virtual Pbject Prop => default(Pbject);
Diagnostic(ErrorCode.ERR_MemberReserved, "default(Pbject)").WithArguments("get_Prop", "Base<Pbject>").WithLocation(withPropertyDeclarationFirst ? 4 : 6, 35)
).ToArray();
}
var comp = CreateCompilation(compilationSource, references: references, parseOptions: parseOptions, targetFramework: TargetFramework.Empty);
comp.VerifyDiagnostics(expectedDiagnostics);
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_Prop");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.Equal(deservesAmbiguousOverrideWarning, shouldWarn);
Assert.Equal(requiresMethodImpl, useMethodImpl);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", references: references, withoutCorlib: true));
if (overrideProperty == withPropertyDeclarationFirst)
{
verify(RetargetingView(comp, "", references: retargetReferences, withoutCorlib: true));
}
else
{
// retargeting tests skipped due to https://github.com/dotnet/roslyn/issues/45566
}
void verify(CSharpCompilation compilation)
{
var overrideReturnType = useCovariantReturns ? "String" : "Object";
if (overrideProperty)
{
VerifyOverride(compilation,
methodName: "Derived.get_Prop",
overridingMemberDisplay: $"System.{overrideReturnType} Derived.Prop.get",
overriddenMemberDisplay: "System.Object Base<System.Object>.Prop.get",
requiresMethodimpl: requiresMethodImpl);
}
else
{
VerifyOverride(compilation,
methodName: "Derived.get_Prop",
overridingMemberDisplay: $"System.{overrideReturnType} Derived.get_Prop()",
overriddenMemberDisplay: "System.Object Base<System.Object>.get_Prop()",
requiresMethodimpl: requiresMethodImpl);
}
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_01(
bool withCovariantReturns
)
{
var source = @"
class Base
{
public virtual void M(int x) => throw null; // 1
public virtual void M(int y) => throw null; // 2
}
class Derived : Base
{
public override void M(int z) => throw null; // 3
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source);
comp.VerifyDiagnostics(
// (5,25): error CS0111: Type 'Base' already defines a member called 'M' with the same parameter types
// public virtual void M(int y) => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Base").WithLocation(5, 25)
);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, ""));
verify(RetargetingView(comp, ""));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(withCovariantReturns, useMethodImpl);
Assert.Equal(withCovariantReturns, member.IsMetadataNewSlot());
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "void Derived.M(System.Int32 z)",
overriddenMemberDisplay: "void Base.M(System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_02(
bool withCovariantReturns
)
{
var source = @"
class Base<T>
{
public virtual void M(int x) => throw null; // 1
public virtual void M(int y) => throw null; // 2
}
class Derived : Base<int>
{
public override void M(int z) => throw null; // 3
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source);
comp.VerifyDiagnostics(
// (5,25): error CS0111: Type 'Base<T>' already defines a member called 'M' with the same parameter types
// public virtual void M(int y) => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Base<T>").WithLocation(5, 25),
// (10,26): error CS0462: The inherited members 'Base<T>.M(int)' and 'Base<T>.M(int)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(int z) => throw null; // 3
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Base<T>.M(int)", "Base<T>.M(int)", "Derived").WithLocation(10, 26)
);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, ""));
verify(RetargetingView(comp, ""));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(withCovariantReturns, useMethodImpl);
Assert.Equal(withCovariantReturns, member.IsMetadataNewSlot());
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "void Derived.M(System.Int32 z)",
overriddenMemberDisplay: "void Base<System.Int32>.M(System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_03(
bool withCovariantReturns
)
{
var source = @"
class Container<T>
{
class Base
{
public virtual void M(int x) => throw null; // 1
public virtual void M(int y) => throw null; // 2
}
class Derived : Base
{
public override void M(int z) => throw null; // 3
}
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source);
comp.VerifyDiagnostics(
// (7,29): error CS0111: Type 'Container<T>.Base' already defines a member called 'M' with the same parameter types
// public virtual void M(int y) => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Container<T>.Base").WithLocation(7, 29)
);
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, ""));
verify(RetargetingView(comp, ""));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Container.Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(withCovariantReturns, useMethodImpl);
Assert.Equal(useMethodImpl, member.IsMetadataNewSlot());
VerifyOverride(compilation,
methodName: "Container.Derived.M",
overridingMemberDisplay: "void Container<T>.Derived.M(System.Int32 z)",
overriddenMemberDisplay: "void Container<T>.Base.M(System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_04(
bool withCovariantReturns
)
{
var s0 = @"
public class Container<T>
{
public class Base
{
public virtual void M(int x) => throw null; // 1
public virtual void M(int y) => throw null; // 2
}
}
";
var baseCompilation = CreateCompilation(withCovariantReturns: withCovariantReturns, s0);
baseCompilation.VerifyDiagnostics(
// (7,29): error CS0111: Type 'Container<T>.Base' already defines a member called 'M' with the same parameter types
// public virtual void M(int y) => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Container<T>.Base").WithLocation(7, 29)
);
var baseMetadata = baseCompilation.ToMetadataReference();
var source = @"
class Derived : Container<int>.Base
{
public override void M(int z) => throw null; // 3
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source, references: new[] { baseMetadata });
comp.VerifyDiagnostics(
// (4,26): error CS0462: The inherited members 'Container<T>.Base.M(int)' and 'Container<T>.Base.M(int)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(int z) => throw null; // 3
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Container<T>.Base.M(int)", "Container<T>.Base.M(int)", "Derived").WithLocation(4, 26)
);
verify(RetargetingView(baseCompilation, source, expectedDiagnostics:
// (4,26): error CS0462: The inherited members 'Container<T>.Base.M(int)' and 'Container<T>.Base.M(int)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(int z) => throw null; // 3
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Container<T>.Base.M(int)", "Container<T>.Base.M(int)", "Derived").WithLocation(4, 26)
));
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", new[] { baseMetadata }));
verify(RetargetingView(comp, "", new[] { baseMetadata }));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(withCovariantReturns, useMethodImpl);
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "void Derived.M(System.Int32 z)",
overriddenMemberDisplay: "void Container<System.Int32>.Base.M(System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_05(
bool withCovariantReturns
)
{
var s0 = @"
public class Container<T>
{
public class Base
{
public virtual void M(int x) => throw null; // 1
public virtual void M(T y) => throw null; // 2
public virtual void M(int z) => throw null; // 3
}
}
";
var baseCompilation = CreateCompilation(withCovariantReturns: withCovariantReturns, s0);
baseCompilation.VerifyDiagnostics(
// (8,29): error CS0111: Type 'Container<T>.Base' already defines a member called 'M' with the same parameter types
// public virtual void M(int z) => throw null; // 3
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Container<T>.Base").WithLocation(8, 29)
);
var baseMetadata = baseCompilation.ToMetadataReference();
var source = @"
class Derived : Container<int>.Base
{
public override void M(int w) => throw null; // 4
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source, references: new[] { baseMetadata });
comp.VerifyDiagnostics(
// (4,26): error CS0462: The inherited members 'Container<T>.Base.M(int)' and 'Container<T>.Base.M(T)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(int w) => throw null; // 4
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Container<T>.Base.M(int)", "Container<T>.Base.M(T)", "Derived").WithLocation(4, 26)
);
verify(RetargetingView(baseCompilation, source, expectedDiagnostics:
// (4,26): error CS0462: The inherited members 'Container<T>.Base.M(int)' and 'Container<T>.Base.M(T)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(int w) => throw null; // 4
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Container<T>.Base.M(int)", "Container<T>.Base.M(T)", "Derived").WithLocation(4, 26)
));
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", new[] { baseMetadata }));
verify(RetargetingView(comp, "", references: new[] { baseMetadata }));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.Equal(withCovariantReturns, useMethodImpl);
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "void Derived.M(System.Int32 w)",
overriddenMemberDisplay: "void Container<System.Int32>.Base.M(System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_06(
bool withCovariantReturns
)
{
var s0 = @"
public class Root
{
public virtual int get_P() => throw null; // 1
public virtual int get_P() => throw null; // 2
}
public class Base : Root
{
public virtual int P => 1;
}
";
var baseCompilation = CreateCompilation(withCovariantReturns: withCovariantReturns, s0);
baseCompilation.VerifyDiagnostics(
// (5,24): error CS0111: Type 'Root' already defines a member called 'get_P' with the same parameter types
// public virtual int get_P() => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "get_P").WithArguments("get_P", "Root").WithLocation(5, 24)
);
var baseMetadata = baseCompilation.ToMetadataReference();
var source = @"
class Derived : Base
{
public override int get_P() => throw null; // 3
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source, references: new[] { baseMetadata });
comp.VerifyDiagnostics(
);
verify(RetargetingView(baseCompilation, source));
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", new[] { baseMetadata }));
verify(RetargetingView(comp, "", references: new[] { baseMetadata }));
void verify(CSharpCompilation compilation)
{
var member = (SourceMethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_P");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.True(useMethodImpl);
VerifyOverride(compilation,
methodName: "Derived.get_P",
overridingMemberDisplay: "System.Int32 Derived.get_P()",
overriddenMemberDisplay: "System.Int32 Root.get_P()",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_07(
bool withCovariantReturns
)
{
var s0 = @"
public class Root<T>
{
public virtual int get_P() => throw null; // 1
public virtual int get_P() => throw null; // 2
}
public class Base : Root<int>
{
public virtual int P => 1;
}
";
var baseCompilation = CreateCompilation(withCovariantReturns: withCovariantReturns, s0);
baseCompilation.VerifyDiagnostics(
// (5,24): error CS0111: Type 'Root<T>' already defines a member called 'get_P' with the same parameter types
// public virtual int get_P() => throw null; // 2
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "get_P").WithArguments("get_P", "Root<T>").WithLocation(5, 24)
);
var baseMetadata = baseCompilation.ToMetadataReference();
var source = @"
class Derived : Base
{
public override int get_P() => throw null; // 3
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source, references: new[] { baseMetadata });
comp.VerifyDiagnostics(
// (4,25): error CS0462: The inherited members 'Root<T>.get_P()' and 'Root<T>.get_P()' have the same signature in type 'Derived', so they cannot be overridden
// public override int get_P() => throw null; // 3
Diagnostic(ErrorCode.ERR_AmbigOverride, "get_P").WithArguments("Root<T>.get_P()", "Root<T>.get_P()", "Derived").WithLocation(4, 25)
);
verify(RetargetingView(baseCompilation, source, expectedDiagnostics:
// (4,25): error CS0462: The inherited members 'Root<T>.get_P()' and 'Root<T>.get_P()' have the same signature in type 'Derived', so they cannot be overridden
// public override int get_P() => throw null; // 3
Diagnostic(ErrorCode.ERR_AmbigOverride, "get_P").WithArguments("Root<T>.get_P()", "Root<T>.get_P()", "Derived").WithLocation(4, 25)
));
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", new[] { baseMetadata }));
verify(RetargetingView(comp, "", references: new[] { baseMetadata }));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.get_P");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.True(useMethodImpl);
VerifyOverride(compilation,
methodName: "Derived.get_P",
overridingMemberDisplay: "System.Int32 Derived.get_P()",
overriddenMemberDisplay: "System.Int32 Root<System.Int32>.get_P()",
requiresMethodimpl: useMethodImpl);
}
}
[Theory]
[CombinatorialData]
public void DuplicateDeclarations_08(
bool withCovariantReturns
)
{
var s0 = @"
public class Root<T>
{
public virtual void M(ref int x) => throw null; // 1
public virtual void M(ref T y) => throw null; // 2
public virtual void M(ref int z) => throw null; // 3
}
public class Base : Root<int>
{
public virtual void M(out int w) { w = 0; } // 4
}
";
var baseCompilation = CreateCompilation(withCovariantReturns: withCovariantReturns, s0);
baseCompilation.VerifyDiagnostics(
// (6,25): error CS0111: Type 'Root<T>' already defines a member called 'M' with the same parameter types
// public virtual void M(ref int z) => throw null; // 3
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "M").WithArguments("M", "Root<T>").WithLocation(6, 25)
);
var baseMetadata = baseCompilation.ToMetadataReference();
var source = @"
class Derived : Base
{
public override void M(ref int a) => throw null; // 5
}
";
var comp = CreateCompilation(withCovariantReturns: withCovariantReturns, source, references: new[] { baseMetadata });
comp.VerifyDiagnostics(
// (4,26): error CS0462: The inherited members 'Root<T>.M(ref int)' and 'Root<T>.M(ref T)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(ref int a) => throw null; // 5
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Root<T>.M(ref int)", "Root<T>.M(ref T)", "Derived").WithLocation(4, 26)
);
verify(RetargetingView(baseCompilation, source, expectedDiagnostics:
// (4,26): error CS0462: The inherited members 'Root<T>.M(ref int)' and 'Root<T>.M(ref T)' have the same signature in type 'Derived', so they cannot be overridden
// public override void M(ref int a) => throw null; // 5
Diagnostic(ErrorCode.ERR_AmbigOverride, "M").WithArguments("Root<T>.M(ref int)", "Root<T>.M(ref T)", "Derived").WithLocation(4, 26)
));
verify(SourceView(comp, ""));
verify(CompilationReferenceView(comp, "", new[] { baseMetadata }));
verify(RetargetingView(comp, "", references: new[] { baseMetadata }));
void verify(CSharpCompilation compilation)
{
var member = (MethodSymbol)comp.GlobalNamespace.GetMember("Derived.M");
bool useMethodImpl = member.RequiresExplicitOverride(out bool shouldWarn);
Assert.False(shouldWarn);
Assert.True(useMethodImpl);
VerifyOverride(compilation,
methodName: "Derived.M",
overridingMemberDisplay: "void Derived.M(ref System.Int32 a)",
overriddenMemberDisplay: "void Root<System.Int32>.M(ref System.Int32 x)",
requiresMethodimpl: useMethodImpl);
}
}
}
}
|