|
// 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.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols
{
public class CheckedUserDefinedOperatorsTests : CSharpTestBase
{
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void UnaryOperators_Supported_01(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x) => x;
public static C operator " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10);
compilation1.VerifyDiagnostics(
// (4,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked ++(C x) => x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 30)
);
validator(compilation1.SourceModule);
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol.MethodKind);
Assert.Equal(name, opSymbol.Name);
Assert.Equal("C C." + name + "(C x)", opSymbol.ToTestDisplayString());
Assert.Equal("C.operator checked " + op + "(C)", opSymbol.ToDisplayString());
Assert.True(opSymbol.IsStatic);
Assert.True(opSymbol.HasSpecialName);
Assert.False(opSymbol.HasRuntimeSpecialName);
Assert.Equal(Accessibility.Public, opSymbol.DeclaredAccessibility);
}
}
[Theory]
[InlineData("-", "op_UnaryNegation", "op_CheckedUnaryNegation")]
[InlineData("++", "op_Increment", "op_CheckedIncrement")]
[InlineData("--", "op_Decrement", "op_CheckedDecrement")]
public void UnaryOperators_Supported_02(string op, string name, string checkedName)
{
var source1 =
@"
class C
{
public static C operator " + op + @"(C x) => x;
public static C operator checked " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C C." + checkedName + "(C x)", opSymbols[1].ToTestDisplayString());
}
}
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void UnaryOperators_Supported_03(string op, string name)
{
var source1 =
@"
struct C
{
public static C operator checked" + op + @"(C x) => x;
public static C? operator checked " + op + @"(C? x) => x;
public static C operator " + op + @"(C x) => x;
public static C? operator " + op + @"(C? x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C? C." + name + "(C? x)", opSymbols[1].ToTestDisplayString());
}
}
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void UnaryOperators_Supported_04(string op, string name)
{
var source1 =
@"
struct C
{
public static C operator checked" + op + @"(C x) => x;
public static C? operator checked " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
if (op == "-")
{
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (5,39): error CS0111: Type 'C' already defines a member called 'op_CheckedDecrement' with the same parameter types
// public static C? operator checked --(C x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(5, 39)
);
}
else
{
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (5,39): error CS0448: The return type for ++ or -- operator must match the parameter type or be derived from the parameter type
// public static C? operator checked --(C x) => x;
Diagnostic(ErrorCode.ERR_BadIncDecRetType, op).WithLocation(5, 39),
// (5,39): error CS0111: Type 'C' already defines a member called 'op_CheckedDecrement' with the same parameter types
// public static C? operator checked --(C x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(5, 39)
);
}
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C? C." + name + "(C x)", opSymbols[1].ToTestDisplayString());
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_05(string op)
{
var source1 =
@"
class C
{
public static int operator checked" + op + @"(C x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,39): error CS0448: The return type for ++ or -- operator must match the parameter type or be derived from the parameter type
// public static int operator checked--(C x) => default;
Diagnostic(ErrorCode.ERR_BadIncDecRetType, op).WithLocation(4, 39)
);
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_06(string op)
{
var source1 =
@"
class C
{
public static C operator checked" + op + @"(int x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,37): error CS0559: The parameter type for ++ or -- operator must be the containing type
// public static C operator checked++(int x) => default;
Diagnostic(ErrorCode.ERR_BadIncDecSignature, op).WithLocation(4, 37)
);
}
[Fact]
public void UnaryOperators_Supported_07()
{
var source1 =
@"
class C
{
public static C operator checked -(int x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS0562: The parameter of a unary operator must be the containing type
// public static C operator checked -(int x) => default;
Diagnostic(ErrorCode.ERR_BadUnaryOperatorSignature, "-").WithLocation(4, 38)
);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_08(string op)
{
var source1 =
@"
class C
{
C operator checked" + op + @"(C x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,23): error CS0558: User-defined operator 'C.operator checked --(C)' must be declared static and public
// C operator checked--(C x) => default;
Diagnostic(ErrorCode.ERR_OperatorsMustBeStatic, op).WithArguments("C.operator checked " + op + "(C)").WithLocation(4, 23)
);
}
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void UnaryOperators_Supported_09(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x) => x;
C Test(C x)
{
return C." + name + @"(x);
}
}
class C1
{
public static C1 operator checked " + op + @"(C1 x) => x;
static C1 " + name + @"(C1 x) => x;
}
class C2
{
static C2 " + name + @"(C2 x) => x;
public static C2 operator checked " + op + @"(C2 x) => x;
}
class C3
{
public static C3 operator checked " + op + @"(C3 x) => x;
int " + name + @" { get; }
}
class C4
{
C4 " + name + @" { get; }
public static C4 operator checked " + op + @"(C4 x) => x;
}
class C5
{
public static C5 operator checked " + op + @"(C5 x) => x;
public static C5 operator checked " + op + @"(C5 y) => y;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (8,18): error CS0571: 'C.operator checked -(C)': cannot explicitly call operator or accessor
// return C.op_CheckedUnaryNegation(x);
Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, name).WithArguments("C.operator checked " + op + "(C)").WithLocation(8, 18),
// (16,15): error CS0111: Type 'C1' already defines a member called 'op_CheckedUnaryNegation' with the same parameter types
// static C1 op_CheckedUnaryNegation(C1 x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, name).WithArguments(name, "C1").WithLocation(16, 15),
// (23,39): error CS0111: Type 'C2' already defines a member called 'op_CheckedUnaryNegation' with the same parameter types
// public static C2 operator checked -(C2 x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C2").WithLocation(23, 39),
// (30,9): error CS0102: The type 'C3' already contains a definition for 'op_CheckedUnaryNegation'
// int op_CheckedUnaryNegation { get; }
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, name).WithArguments("C3", name).WithLocation(30, 9),
// (37,39): error CS0102: The type 'C4' already contains a definition for 'op_CheckedUnaryNegation'
// public static C4 operator checked -(C4 x) => x;
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, op).WithArguments("C4", name).WithLocation(37, 39),
// (44,39): error CS0111: Type 'C5' already defines a member called 'op_CheckedSubtraction' with the same parameter types
// public static C5 operator checked -(C5 x, C5 y) => y;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C5").WithLocation(44, 39)
);
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_10(string op)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x, C y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1020: Overloadable binary operator expected
// public static C operator checked --(C x, C y) => x;
Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, op).WithLocation(4, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked " + op + "(C, C)", opSymbol.ToDisplayString());
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_11(string op)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"() => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1535: Overloaded unary operator '--' takes one parameter
// public static C operator checked --() => default;
Diagnostic(ErrorCode.ERR_BadUnOpArgs, op).WithArguments(op).WithLocation(4, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked " + op + "()", opSymbol.ToDisplayString());
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_12(string op)
{
var source1 =
@"
static class C
{
public static C operator checked " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,19): error CS0722: 'C': static types cannot be used as return types
// public static C operator checked ++(C x) => x;
Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "C").WithArguments("C").WithLocation(4, 19),
// (4,38): error CS0715: 'C.operator checked ++(C)': static classes cannot contain user-defined operators
// public static C operator checked ++(C x) => x;
Diagnostic(ErrorCode.ERR_OperatorInStaticClass, op).WithArguments("C.operator checked " + op + "(C)").WithLocation(4, 38),
// (4,41): error CS0721: 'C': static types cannot be used as parameters
// public static C operator checked ++(C x) => x;
Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(4, 39 + op.Length)
);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperators_Supported_13(string op)
{
var source1 =
@"
struct C
{
public static C operator checked " + op + @"(C x) => x;
public static C? operator " + op + @"(C? x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,38): error CS9152: The operator 'C.operator checked -(C)' requires a matching non-checked version of the operator to also be defined
// public static C operator checked -(C x) => x;
Diagnostic(ErrorCode.ERR_CheckedOperatorNeedsMatch, op).WithArguments("C.operator checked " + op + "(C)").WithLocation(4, 38)
);
}
[Fact]
public void UnaryOperators_Missing_01()
{
var source1 =
@"
class C
{
public static C operator checked (C x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,38): error CS1019: Overloadable unary operator expected
// public static C operator checked (C x) => default;
Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(").WithLocation(4, 38),
// (4,39): error CS1003: Syntax error, '(' expected
// public static C operator checked (C x) => default;
Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 39)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator +(C)", opSymbol.ToDisplayString());
Assert.Equal("op_UnaryPlus", opSymbol.Name);
}
[Fact]
public void UnaryOperators_Missing_02()
{
var source1 =
@"
class C
{
public static C operator (C x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,30): error CS1019: Overloadable unary operator expected
// public static C operator (C x) => default;
Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(").WithLocation(4, 30),
// (4,31): error CS1003: Syntax error, '(' expected
// public static C operator (C x) => default;
Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 31)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator +(C)", opSymbol.ToDisplayString());
Assert.Equal("op_UnaryPlus", opSymbol.Name);
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_NoParameters_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c)
{
return null;
}
public static C operator " + op + @"(C c)
{
return null;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked ++'
// /// See <see cref="operator checked ++"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked ++"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked ++(C c)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_NoParameters_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator " + op + @"""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator ++' that could not be resolved
// /// See <see cref="operator ++"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator " + op).WithArguments("operator " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_NoParameters_03(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked -' that could not be resolved
// /// See <see cref="operator checked -"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
/// <summary>
/// The behavior is consistent with <see cref="CrefTests.UnaryOperator_NoParameters_02"/>
/// </summary>
[Fact]
public void UnaryOperator_Supported_CRef_NoParameters_04()
{
var source = @"
/// <summary>
/// See <see cref=""operator checked -""/>.
/// </summary>
class C
{
public static C operator checked -(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked -' that could not be resolved
// /// See <see cref="operator checked -"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked -").WithArguments("operator checked -").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked -'
// /// See <see cref="operator checked -"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked -").WithArguments("operator checked -").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked -"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked -(C c)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_OneParameter_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C)""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c)
{
return null;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked ++(C)'
// /// See <see cref="operator checked ++(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked ++(C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked ++(C c)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_OneParameter_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator " + op + @"(C)""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator --(C)' that could not be resolved
// /// See <see cref="operator --(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator " + op + "(C)").WithArguments("operator " + op + "(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void UnaryOperator_Supported_CRef_OneParameter_03(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C)""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked -(C)' that could not be resolved
// /// See <see cref="operator checked -(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void UnaryOperator_MissingToken_CRef_OneParameter_01()
{
var source = @"
/// <summary>
/// See <see cref=""operator checked (C)""/>.
/// </summary>
class C
{
public static C operator +(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked (C)'
// /// See <see cref="operator checked (C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked (C)").WithArguments("operator checked (C)").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked (C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Fact]
public void UnaryOperator_MissingToken_CRef_OneParameter_02()
{
var source = @"
/// <summary>
/// See <see cref=""operator (C)""/>.
/// </summary>
class C
{
public static C operator +(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator (C)'
// /// See <see cref="operator (C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator (C)").WithArguments("operator (C)").WithLocation(3, 20),
// (3,29): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator (C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 29)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("+", "op_UnaryPlus")]
[InlineData("!", "op_LogicalNot")]
[InlineData("~", "op_OnesComplement")]
public void UnaryOperators_Unsupported_01(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x) => x;
}
";
foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 })
{
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options);
compilation1.VerifyDiagnostics(
// (4,30): error CS9150: User-defined operator '~' cannot be declared checked
// public static C operator checked ~(C x) => x;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(4, 30)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol.MethodKind);
Assert.Equal(name, opSymbol.Name);
Assert.Equal("C C." + name + "(C x)", opSymbol.ToTestDisplayString());
Assert.Equal("C.operator " + op + "(C)", opSymbol.ToDisplayString());
}
}
[Fact]
public void UnaryOperators_Unsupported_02()
{
var source1 =
@"
class C
{
public static bool operator checked true(C x) => true;
public static bool operator checked false(C x) => false;
}
";
foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 })
{
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options);
compilation1.VerifyDiagnostics(
// (4,33): error CS9150: User-defined operator 'true' cannot be declared checked
// public static bool operator checked true(C x) => true;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments("true").WithLocation(4, 33),
// (5,33): error CS9150: User-defined operator 'false' cannot be declared checked
// public static bool operator checked false(C x) => false;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments("false").WithLocation(5, 33)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
var opSymbol1 = opSymbols[0];
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol1.MethodKind);
Assert.Equal("op_True", opSymbol1.Name);
Assert.Equal("System.Boolean C.op_True(C x)", opSymbol1.ToTestDisplayString());
Assert.Equal("C.operator true(C)", opSymbol1.ToDisplayString());
var opSymbol2 = opSymbols[1];
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol2.MethodKind);
Assert.Equal("op_False", opSymbol2.Name);
Assert.Equal("System.Boolean C.op_False(C x)", opSymbol2.ToTestDisplayString());
Assert.Equal("C.operator false(C)", opSymbol2.ToDisplayString());
}
}
[Theory]
[InlineData("+", "op_UnaryPlus")]
[InlineData("!", "op_LogicalNot")]
[InlineData("~", "op_OnesComplement")]
public void UnaryOperators_Unsupported_03(string op, string name)
{
var source1 =
@"
class C
{
public static C operator " + op + @"(C x) => x;
public static C operator checked " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (5,30): error CS9150: User-defined operator '~' cannot be declared checked
// public static C operator checked ~(C x) => x;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(5, 30),
// (5,38): error CS0111: Type 'C' already defines a member called 'op_OnesComplement' with the same parameter types
// public static C operator checked ~(C x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(5, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C C." + name + "(C x)", opSymbols[1].ToTestDisplayString());
}
[Theory]
[InlineData("true", "op_True")]
[InlineData("false", "op_False")]
public void UnaryOperators_Unsupported_04(string op, string name)
{
var source1 =
@"
class C
{
public static bool operator true(C x) => true;
public static bool operator false(C x) => false;
public static bool operator checked " + op + @"(C x) => false;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (6,33): error CS9150: User-defined operator 'false' cannot be declared checked
// public static bool operator checked false(C x) => false;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(6, 33),
// (6,41): error CS0111: Type 'C' already defines a member called 'op_False' with the same parameter types
// public static bool operator checked false(C x) => false;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(6, 41)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(3, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal("System.Boolean C.op_True(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("System.Boolean C.op_False(C x)", opSymbols[1].ToTestDisplayString());
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[2].MethodKind);
Assert.Equal("System.Boolean C." + name + "(C x)", opSymbols[2].ToTestDisplayString());
}
[Theory]
[InlineData("+")]
[InlineData("!")]
[InlineData("~")]
public void UnaryOperator_Unsupported_CRef_NoParameters_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked !' that could not be resolved
// /// See <see cref="operator checked !"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +'
// /// See <see cref="operator checked +"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked +"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("true")]
[InlineData("false")]
public void UnaryOperator_Unsupported_CRef_NoParameters_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static bool operator true(C x) => true;
public static bool operator false(C x) => false;
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked true' that could not be resolved
// /// See <see cref="operator checked true"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked false'
// /// See <see cref="operator checked false"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked true"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("!")]
[InlineData("~")]
public void UnaryOperator_Unsupported_CRef_OneParameter_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C)""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked ~(C)' that could not be resolved
// /// See <see cref="operator checked ~(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +(C)'
// /// See <see cref="operator checked +(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked +(C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("true")]
[InlineData("false")]
public void UnaryOperator_Unsupported_CRef_OneParameter_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C)""/>.
/// </summary>
class C
{
public static bool operator true(C x) => true;
public static bool operator false(C x) => false;
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked true(C)' that could not be resolved
// /// See <see cref="operator checked true(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics( // (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked true(C)'
// /// See <see cref="operator checked true(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C)").WithArguments("operator checked " + op + "(C)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked true(C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void BinaryOperators_Supported_01(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x, C y) => x;
public static C operator " + op + @"(C x, C y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10);
compilation1.VerifyDiagnostics(
// (4,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked +(C x, C y) => x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 30)
);
validator(compilation1.SourceModule);
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol.MethodKind);
Assert.Equal(name, opSymbol.Name);
Assert.Equal("C C." + name + "(C x, C y)", opSymbol.ToTestDisplayString());
Assert.Equal("C.operator checked " + op + "(C, C)", opSymbol.ToDisplayString());
Assert.True(opSymbol.IsStatic);
Assert.True(opSymbol.HasSpecialName);
Assert.False(opSymbol.HasRuntimeSpecialName);
Assert.Equal(Accessibility.Public, opSymbol.DeclaredAccessibility);
}
}
[Theory]
[InlineData("+", "op_Addition", "op_CheckedAddition")]
[InlineData("-", "op_Subtraction", "op_CheckedSubtraction")]
[InlineData("*", "op_Multiply", "op_CheckedMultiply")]
[InlineData("/", "op_Division", "op_CheckedDivision")]
public void BinaryOperators_Supported_02(string op, string name, string checkedName)
{
var source1 =
@"
class C
{
public static C operator " + op + @"(C x, C y) => x;
public static C operator checked " + op + @"(C x, C y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x, C y)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C C." + checkedName + "(C x, C y)", opSymbols[1].ToTestDisplayString());
}
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void BinaryOperators_Supported_03(string op, string name)
{
var source1 =
@"
struct C
{
public static C operator checked" + op + @"(C x, C y) => x;
public static C? operator checked " + op + @"(C? x, C? y) => x;
public static C operator " + op + @"(C x, C y) => x;
public static C? operator " + op + @"(C? x, C? y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x, C y)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C? C." + name + "(C? x, C? y)", opSymbols[1].ToTestDisplayString());
}
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void BinaryOperators_Supported_04(string op, string name)
{
var source1 =
@"
struct C
{
public static C operator checked" + op + @"(C x, C y) => x;
public static C? operator checked " + op + @"(C x, C y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (5,39): error CS0111: Type 'C' already defines a member called 'op_CheckedSubtraction' with the same parameter types
// public static C? operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(5, 39)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x, C y)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C? C." + name + "(C x, C y)", opSymbols[1].ToTestDisplayString());
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_06(string op)
{
var source1 =
@"
class C
{
public static C operator checked" + op + @"(int x, int y) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,37): error CS0563: One of the parameters of a binary operator must be the containing type
// public static C operator checked/(int x, int y) => default;
Diagnostic(ErrorCode.ERR_BadBinaryOperatorSignature, op).WithLocation(4, 37)
);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_08(string op)
{
var source1 =
@"
class C
{
C operator checked" + op + @"(C x, C y) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,23): error CS0558: User-defined operator 'C.operator checked -(C, C)' must be declared static and public
// C operator checked-(C x, C y) => default;
Diagnostic(ErrorCode.ERR_OperatorsMustBeStatic, op).WithArguments("C.operator checked " + op + "(C, C)").WithLocation(4, 23)
);
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void BinaryOperators_Supported_09(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x, C y) => x;
C Test(C x)
{
return C." + name + @"(x, x);
}
}
class C1
{
public static C1 operator checked " + op + @"(C1 x, C1 y) => x;
static C1 " + name + @"(C1 x, C1 y) => x;
}
class C2
{
static C2 " + name + @"(C2 x, C2 y) => x;
public static C2 operator checked " + op + @"(C2 x, C2 y) => x;
}
class C3
{
public static C3 operator checked " + op + @"(C3 x, C3 y) => x;
int " + name + @" { get; }
}
class C4
{
C4 " + name + @" { get; }
public static C4 operator checked " + op + @"(C4 x, C4 y) => x;
}
class C5
{
public static C5 operator checked " + op + @"(C5 x, C5 y) => x;
public static C5 operator checked " + op + @"(C5 x, C5 y) => y;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (8,18): error CS0571: 'C.operator checked -(C, C)': cannot explicitly call operator or accessor
// return C.op_CheckedSubtraction(x, x);
Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, name).WithArguments("C.operator checked " + op + "(C, C)").WithLocation(8, 18),
// (16,15): error CS0111: Type 'C1' already defines a member called 'op_CheckedSubtraction' with the same parameter types
// static C1 op_CheckedSubtraction(C1 x, C1 y) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, name).WithArguments(name, "C1").WithLocation(16, 15),
// (23,39): error CS0111: Type 'C2' already defines a member called 'op_CheckedSubtraction' with the same parameter types
// public static C2 operator checked -(C2 x, C2 y) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C2").WithLocation(23, 39),
// (30,9): error CS0102: The type 'C3' already contains a definition for 'op_CheckedSubtraction'
// int op_CheckedSubtraction { get; }
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, name).WithArguments("C3", name).WithLocation(30, 9),
// (37,39): error CS0102: The type 'C4' already contains a definition for 'op_CheckedSubtraction'
// public static C4 operator checked -(C4 x, C4 y) => x;
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, op).WithArguments("C4", name).WithLocation(37, 39),
// (44,39): error CS0111: Type 'C5' already defines a member called 'op_CheckedSubtraction' with the same parameter types
// public static C5 operator checked -(C5 x, C5 y) => y;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C5").WithLocation(44, 39)
);
}
[Theory]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_10(string op)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1019: Overloadable unary operator expected
// public static C operator checked /(C x) => x;
Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, op).WithLocation(4, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked " + op + "(C)", opSymbol.ToDisplayString());
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_11(string op)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"() => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1534: Overloaded binary operator '*' takes two parameters
// public static C operator checked *() => default;
Diagnostic(ErrorCode.ERR_BadBinOpArgs, op).WithArguments(op).WithLocation(4, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked " + op + "()", opSymbol.ToDisplayString());
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_12(string op)
{
var source1 =
@"
static class C
{
public static C operator checked " + op + @"(C x, C y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,19): error CS0722: 'C': static types cannot be used as return types
// public static C operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_ReturnTypeIsStaticClass, "C").WithArguments("C").WithLocation(4, 19),
// (4,38): error CS0715: 'C.operator checked -(C, C)': static classes cannot contain user-defined operators
// public static C operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_OperatorInStaticClass, op).WithArguments("C.operator checked " + op + "(C, C)").WithLocation(4, 38),
// (4,40): error CS0721: 'C': static types cannot be used as parameters
// public static C operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(4, 40),
// (4,45): error CS0721: 'C': static types cannot be used as parameters
// public static C operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(4, 45)
);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperators_Supported_13(string op)
{
var source1 =
@"
struct C
{
public static C operator checked " + op + @"(C x, C y) => x;
public static C operator " + op + @"(C x, int y) => x;
public static C operator " + op + @"(int x, C y) => y;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,38): error CS9152: The operator 'C.operator checked -(C, C)' requires a matching non-checked version of the operator to also be defined
// public static C operator checked -(C x, C y) => x;
Diagnostic(ErrorCode.ERR_CheckedOperatorNeedsMatch, op).WithArguments("C.operator checked " + op + "(C, C)").WithLocation(4, 38)
);
}
[Fact]
public void BinaryOperators_Missing_01()
{
var source1 =
@"
class C
{
public static C operator checked (C x, C y) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1020: Overloadable binary operator expected
// public static C operator checked (C x, C y) => default;
Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, "(").WithLocation(4, 38),
// (4,39): error CS1003: Syntax error, '(' expected
// public static C operator checked (C x, C y) => default;
Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 39)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked +(C, C)", opSymbol.ToDisplayString());
Assert.Equal("op_CheckedAddition", opSymbol.Name);
}
[Fact]
public void BinaryOperators_Missing_02()
{
var source1 =
@"
class C
{
public static C operator (C x, C y) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,30): error CS1020: Overloadable binary operator expected
// public static C operator (C x, C y) => default;
Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, "(").WithLocation(4, 30),
// (4,31): error CS1003: Syntax error, '(' expected
// public static C operator (C x, C y) => default;
Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 31)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator +(C, C)", opSymbol.ToDisplayString());
Assert.Equal("op_Addition", opSymbol.Name);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperator_Supported_CRef_NoParameters_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c, C y)
{
return null;
}
public static C operator " + op + @"(C c, C y)
{
return null;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +'
// /// See <see cref="operator checked +"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked +"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked +(C c, C y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperator_Supported_CRef_NoParameters_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator " + op + @"""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator +' that could not be resolved
// /// See <see cref="operator +"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator " + op).WithArguments("operator " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperator_Supported_CRef_NoParameters_03(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked -' that could not be resolved
// /// See <see cref="operator checked -"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op).WithArguments("operator checked " + op).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void BinaryOperator_MissingToken_CRef_NoParameters_01()
{
var source = @"
/// <summary>
/// See <see cref=""operator checked ""/>.
/// </summary>
class C
{
public static C operator checked +(C c, C y)
{
return null;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked'
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked").WithArguments("operator checked").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37)
);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked'
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked").WithArguments("operator checked").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked +(C c, C y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked'
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked").WithArguments("operator checked").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked "/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Fact]
public void BinaryOperator_MissingToken_CRef_NoParameters_02()
{
var source = @"
/// <summary>
/// See <see cref=""operator ""/>.
/// </summary>
class C
{
public static C operator +(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator'
// /// See <see cref="operator "/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator").WithArguments("operator").WithLocation(3, 20),
// (3,29): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator "/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, @"""").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 29)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperator_Supported_CRef_TwoParameters_01(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C, C)""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c, C y)
{
return null;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked +(C, C)'
// /// See <see cref="operator checked +(C, C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + op + "(C, C)").WithArguments("operator checked " + op + "(C, C)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked +(C, C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked +(C c, C y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinaryOperator_Supported_CRef_TwoParameters_02(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator " + op + @"(C, C)""/>.
/// </summary>
class C
{
public static C operator checked " + op + @"(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator -(C)' that could not be resolved
// /// See <see cref="operator -(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator " + op + "(C, C)").WithArguments("operator " + op + "(C, C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void BinarOperator_Supported_CRef_TwoParameters_03(string op)
{
var source = @"
/// <summary>
/// See <see cref=""operator checked " + op + @"(C, C)""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked -(C, C)' that could not be resolved
// /// See <see cref="operator checked -(C, C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + op + "(C, C)").WithArguments("operator checked " + op + "(C, C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void BinaryOperator_MissingToken_CRef_TwoParameters_01()
{
var source = @"
/// <summary>
/// See <see cref=""operator checked (C, C)""/>.
/// </summary>
class C
{
public static C operator checked +(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked (C, C)'
// /// See <see cref="operator checked (C, C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked (C, C)").WithArguments("operator checked (C, C)").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked (C, C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked (C, C)'
// /// See <see cref="operator checked (C, C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked (C, C)").WithArguments("operator checked (C, C)").WithLocation(3, 20),
// (3,37): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator checked (C, C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 37),
// (7,30): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked +(C c, C y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 30)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Fact]
public void BinaryOperator_MissingToken_CRef_TwoParameters_02()
{
var source = @"
/// <summary>
/// See <see cref=""operator (C, C)""/>.
/// </summary>
class C
{
public static C operator +(C c, C y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator (C, C)'
// /// See <see cref="operator (C, C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator (C, C)").WithArguments("operator (C, C)").WithLocation(3, 20),
// (3,29): warning CS1658: Overloadable operator expected. See also error CS1037.
// /// See <see cref="operator (C, C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "(").WithArguments("Overloadable operator expected", "1037").WithLocation(3, 29)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Theory]
[InlineData("%", "op_Modulus")]
[InlineData("&", "op_BitwiseAnd")]
[InlineData("|", "op_BitwiseOr")]
[InlineData("^", "op_ExclusiveOr")]
[InlineData("<<", "op_LeftShift")]
[InlineData(">>", "op_RightShift")]
[InlineData(">>>", "op_UnsignedRightShift")]
[InlineData("==", "op_Equality")]
[InlineData("!=", "op_Inequality")]
[InlineData(">", "op_GreaterThan")]
[InlineData("<", "op_LessThan")]
[InlineData(">=", "op_GreaterThanOrEqual")]
[InlineData("<=", "op_LessThanOrEqual")]
public void BinaryOperators_Unsupported_01(string op, string name)
{
var source1 =
@"
class C
{
public static C operator checked " + op + @"(C x, int y) => x;
}
";
foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 })
{
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options);
if (op == ">>>" && options == TestOptions.Regular10)
{
compilation1.VerifyDiagnostics(
// (4,30): error CS9023: User-defined operator '>>>' cannot be declared checked
// public static C operator checked >>>(C x, int y) => x;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(">>>").WithLocation(4, 30),
// (4,38): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator checked >>>(C x, int y) => x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(4, 38)
);
}
else
{
compilation1.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify(
// (4,30): error CS9150: User-defined operator '%' cannot be declared checked
// public static C operator checked %(C x, int y) => x;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(4, 30)
);
}
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal(MethodKind.UserDefinedOperator, opSymbol.MethodKind);
Assert.Equal(name, opSymbol.Name);
Assert.Equal("C C." + name + "(C x, System.Int32 y)", opSymbol.ToTestDisplayString());
Assert.Equal("C.operator " + op + "(C, int)", opSymbol.ToDisplayString());
}
}
[Theory]
[InlineData("%", "op_Modulus")]
[InlineData("&", "op_BitwiseAnd")]
[InlineData("|", "op_BitwiseOr")]
[InlineData("^", "op_ExclusiveOr")]
[InlineData("<<", "op_LeftShift")]
[InlineData(">>", "op_RightShift")]
[InlineData(">>>", "op_UnsignedRightShift")]
[InlineData("==", "op_Equality")]
[InlineData("!=", "op_Inequality")]
[InlineData(">", "op_GreaterThan")]
[InlineData("<", "op_LessThan")]
[InlineData(">=", "op_GreaterThanOrEqual")]
[InlineData("<=", "op_LessThanOrEqual")]
public void BinaryOperators_Unsupported_03(string op, string name)
{
var source1 =
@"
class C
{
public static C operator " + op + @"(C x, int y) => x;
public static C operator checked " + op + @"(C x, int y) => x;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify(
// (5,30): error CS9150: User-defined operator '%' cannot be declared checked
// public static C operator checked %(C x) => x;
Diagnostic(ErrorCode.ERR_OperatorCantBeChecked, "checked").WithArguments(op).WithLocation(5, 30),
// (5,38): error CS0111: Type 'C' already defines a member called 'op_Modulus' with the same parameter types
// public static C operator checked %(C x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, op).WithArguments(name, "C").WithLocation(5, 38)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.UserDefinedOperator, opSymbols[1].MethodKind);
Assert.Equal("C C." + name + "(C x, System.Int32 y)", opSymbols[0].ToTestDisplayString());
Assert.Equal("C C." + name + "(C x, System.Int32 y)", opSymbols[1].ToTestDisplayString());
}
[Theory]
[InlineData("%")]
[InlineData("&")]
[InlineData("|")]
[InlineData("^")]
[InlineData("<<")]
[InlineData(">>")]
[InlineData(">>>")]
[InlineData("==")]
[InlineData("!=")]
[InlineData(">")]
[InlineData("<")]
[InlineData(">=")]
[InlineData("<=")]
public void BinaryOperator_Unsupported_CRef_NoParameters_01(string op)
{
string opForXml = GetOperatorTokenForXml(op);
var source = @"
/// <summary>
/// See <see cref=""operator checked " + opForXml + @"""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c, int y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked !' that could not be resolved
// /// See <see cref="operator checked %"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + opForXml).WithArguments("operator checked " + opForXml).WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
if (op != ">>>")
{
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}'
// /// See <see cref="operator checked }}"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml).WithArguments("operator checked " + opForXml).WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
}
else
{
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}'
// /// See <see cref="operator checked }}}"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}").WithArguments("operator checked }}}").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}}"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (3,37): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}}"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 37),
// (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator >>>(C c, int y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30)
);
}
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
private static string GetOperatorTokenForXml(string op)
{
return op switch { "&" => "&", "<<" => "{{", ">>" => "}}", ">>>" => "}}}", ">" => "}", "<" => "{", ">=" => "}=", "<=" => "{=", _ => op };
}
[Theory]
[InlineData("%")]
[InlineData("&")]
[InlineData("|")]
[InlineData("^")]
[InlineData("<<")]
[InlineData(">>")]
[InlineData(">>>")]
[InlineData("==")]
[InlineData("!=")]
[InlineData(">")]
[InlineData("<")]
[InlineData(">=")]
[InlineData("<=")]
public void BinaryOperator_Unsupported_CRef_TwoParameters_01(string op)
{
string opForXml = GetOperatorTokenForXml(op);
var source = @"
/// <summary>
/// See <see cref=""operator checked " + opForXml + @"(C, int)""/>.
/// </summary>
class C
{
public static C operator " + op + @"(C c, int y)
{
return null;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'operator checked %(C, int)' that could not be resolved
// /// See <see cref="operator checked %(C, int)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "operator checked " + opForXml + "(C, int)").WithArguments("operator checked " + opForXml + "(C, int)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
if (op != ">>>")
{
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}(C, int)'
// /// See <see cref="operator checked }}(C, int)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked " + opForXml + "(C, int)").WithArguments("operator checked " + opForXml + "(C, int)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}(C, int)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29)
);
}
else
{
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator checked }}}(C, int)'
// /// See <see cref="operator checked }}}(C, int)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator checked }}}(C, int)").WithArguments("operator checked }}}(C, int)").WithLocation(3, 20),
// (3,29): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}}(C, int)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 29),
// (3,37): warning CS1658: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="operator checked }}}(C, int)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "}}}").WithArguments("Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 37),
// (7,30): error CS8936: Feature 'unsigned right shift' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static C operator >>>(C c, int y)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, ">>>").WithArguments("unsigned right shift", "11.0").WithLocation(7, 30)
);
}
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).
Verify(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void MissingOperatorTokenAndNoParameters_01()
{
var source1 =
@"
class C
{
public static C operator checked () => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,38): error CS1037: Overloadable operator expected
// public static C operator checked () => default;
Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(4, 38),
// (4,39): error CS1003: Syntax error, '(' expected
// public static C operator checked () => default;
Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(4, 39)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator checked +()", opSymbol.ToDisplayString());
Assert.Equal("op_CheckedAddition", opSymbol.Name);
}
[Fact]
public void MissingOperatorTokenAndNoParameters_02()
{
var source1 =
@"
class C
{
public static C operator () => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,30): error CS1037: Overloadable operator expected
// public static C operator () => default;
Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(4, 30),
// (4,31): error CS1003: Syntax error, '(' expected
// public static C operator () => default;
Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(4, 31)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.operator +()", opSymbol.ToDisplayString());
Assert.Equal("op_Addition", opSymbol.Name);
}
[Fact]
public void ConversionOperators_Supported_01()
{
var source1 =
@"
class C
{
public static explicit operator checked int(C x) => 0;
public static explicit operator int(C x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular10);
compilation1.VerifyDiagnostics(
// (4,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(4, 37)
);
validator(compilation1.SourceModule);
compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
Assert.Equal(MethodKind.Conversion, opSymbol.MethodKind);
Assert.Equal("op_CheckedExplicit", opSymbol.Name);
Assert.Equal("System.Int32 C.op_CheckedExplicit(C x)", opSymbol.ToTestDisplayString());
Assert.Equal("C.explicit operator checked int(C)", opSymbol.ToDisplayString());
Assert.True(opSymbol.IsStatic);
Assert.True(opSymbol.HasSpecialName);
Assert.False(opSymbol.HasRuntimeSpecialName);
Assert.Equal(Accessibility.Public, opSymbol.DeclaredAccessibility);
}
}
[Fact]
public void ConversionOperators_Supported_02()
{
var source1 =
@"
class C
{
public static explicit operator int(C x) => 0;
public static explicit operator checked int(C x) => 0;
}
class C1
{
public static explicit operator checked int(C1 x) => 0;
public static explicit operator int(C1 x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.Conversion, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.Conversion, opSymbols[1].MethodKind);
Assert.Equal("System.Int32 C.op_Explicit(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("System.Int32 C.op_CheckedExplicit(C x)", opSymbols[1].ToTestDisplayString());
}
}
[Fact]
public void ConversionOperators_Supported_03()
{
var source1 =
@"
struct C
{
public static explicit operator checked int(C x) => 0;
public static explicit operator checked long(C x) => 0;
public static explicit operator int(C x) => 0;
public static explicit operator long(C x) => 0;
}
struct C1
{
public static explicit operator checked long(C1 x) => 0;
public static explicit operator checked int(C1 x) => 0;
public static explicit operator int(C1 x) => 0;
public static explicit operator long(C1 x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics();
void validator(ModuleSymbol m)
{
var c = m.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(MethodKind.Conversion, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.Conversion, opSymbols[1].MethodKind);
Assert.Equal("System.Int32 C.op_CheckedExplicit(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("System.Int64 C.op_CheckedExplicit(C x)", opSymbols[1].ToTestDisplayString());
}
}
[Fact]
public void ConversionOperators_Supported_04()
{
var source1 =
@"
struct C
{
public static implicit operator int(C x) => 0;
public static explicit operator checked int(C x) => 0;
}
struct C1
{
public static explicit operator checked int(C1 x) => 0;
public static implicit operator int(C1 x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (5,45): error CS0557: Duplicate user-defined conversion in type 'C'
// public static explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_DuplicateConversionInClass, "int").WithArguments("C").WithLocation(5, 45),
// (11,37): error CS0557: Duplicate user-defined conversion in type 'C1'
// public static implicit operator int(C1 x) => 0;
Diagnostic(ErrorCode.ERR_DuplicateConversionInClass, "int").WithArguments("C1").WithLocation(11, 37)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.Conversion, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.Conversion, opSymbols[1].MethodKind);
Assert.Equal("System.Int32 C.op_Implicit(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("System.Int32 C.op_CheckedExplicit(C x)", opSymbols[1].ToTestDisplayString());
}
[Fact]
public void ConversionOperators_Supported_05()
{
var source1 =
@"
class C
{
public static explicit operator checked int(string x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,45): error CS0556: User-defined conversion must convert to or from the enclosing type
// public static explicit operator checked int(string x) => 0;
Diagnostic(ErrorCode.ERR_ConversionNotInvolvingContainedType, "int").WithLocation(4, 45)
);
}
[Fact]
public void ConversionOperators_Supported_08()
{
var source1 =
@"
class C
{
explicit operator checked int(C x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,31): error CS0558: User-defined operator 'C.explicit operator checked int(C)' must be declared static and public
// explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_OperatorsMustBeStatic, "int").WithArguments("C.explicit operator checked int(C)").WithLocation(4, 31)
);
}
[Fact]
public void ConversionOperators_Supported_09()
{
var source1 =
@"
class C
{
public static explicit operator checked int(C x) => 0;
int Test(C x)
{
return C.op_CheckedExplicit(x);
}
}
class C1
{
public static explicit operator checked int(C1 x) => 0;
static C1 op_CheckedExplicit(C1 x) => x;
}
class C2
{
static C2 op_CheckedExplicit(C2 x) => x;
public static explicit operator checked int(C2 x) => 0;
}
class C3
{
public static explicit operator checked int(C3 x) => 0;
int op_CheckedExplicit { get; }
}
class C4
{
C4 op_CheckedExplicit { get; }
public static explicit operator checked int(C4 x) => 0;
}
class C5
{
public static explicit operator checked int(C5 x) => 0;
public static explicit operator checked int(C5 y) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (8,18): error CS0571: 'C.explicit operator checked int(C)': cannot explicitly call operator or accessor
// return C.op_CheckedExplicit(x);
Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, "op_CheckedExplicit").WithArguments("C.explicit operator checked int(C)").WithLocation(8, 18),
// (16,15): error CS0111: Type 'C1' already defines a member called 'op_CheckedExplicit' with the same parameter types
// static C1 op_CheckedExplicit(C1 x) => x;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "op_CheckedExplicit").WithArguments("op_CheckedExplicit", "C1").WithLocation(16, 15),
// (23,45): error CS0111: Type 'C2' already defines a member called 'op_CheckedExplicit' with the same parameter types
// public static explicit operator checked int(C2 x) => 0;
Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "int").WithArguments("op_CheckedExplicit", "C2").WithLocation(23, 45),
// (30,9): error CS0102: The type 'C3' already contains a definition for 'op_CheckedExplicit'
// int op_CheckedExplicit { get; }
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "op_CheckedExplicit").WithArguments("C3", "op_CheckedExplicit").WithLocation(30, 9),
// (37,45): error CS0102: The type 'C4' already contains a definition for 'op_CheckedExplicit'
// public static explicit operator checked int(C4 x) => 0;
Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "int").WithArguments("C4", "op_CheckedExplicit").WithLocation(37, 45),
// (44,45): error CS0557: Duplicate user-defined conversion in type 'C5'
// public static explicit operator checked int(C5 y) => 0;
Diagnostic(ErrorCode.ERR_DuplicateConversionInClass, "int").WithArguments("C5").WithLocation(44, 45)
);
}
[Fact]
public void ConversionOperators_Supported_10()
{
var source1 =
@"
class C
{
public static explicit operator checked int(C x, C y) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,48): error CS1019: Overloadable unary operator expected
// public static explicit operator checked int(C x, C y) => 0;
Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(C x, C y)").WithLocation(4, 48)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.explicit operator checked int(C, C)", opSymbol.ToDisplayString());
}
[Fact]
public void ConversionOperators_Supported_11()
{
var source1 =
@"
class C
{
public static explicit operator checked int() => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,48): error CS1019: Overloadable unary operator expected
// public static explicit operator checked int() => 0;
Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "()").WithLocation(4, 48)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal("C.explicit operator checked int()", opSymbol.ToDisplayString());
}
[Fact]
public void ConversionOperators_Supported_12()
{
var source1 =
@"
static class C
{
public static explicit operator checked int(C x) => 0;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (4,45): error CS0715: 'C.explicit operator checked int(C)': static classes cannot contain user-defined operators
// public static explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_OperatorInStaticClass, "int").WithArguments("C.explicit operator checked int(C)").WithLocation(4, 45),
// (4,49): error CS0721: 'C': static types cannot be used as parameters
// public static explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "C").WithArguments("C").WithLocation(4, 49)
);
}
[Fact]
public void ConversionOperators_Supported_13()
{
var source1 =
@"
struct C
{
public static explicit operator checked int(C x) => 0;
public static explicit operator C(int x) => default;
public static explicit operator int(C? x) => default;
public static explicit operator long(C x) => default;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (4,45): error CS9152: The operator 'C.explicit operator checked int(C)' requires a matching non-checked version of the operator to also be defined
// public static explicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_CheckedOperatorNeedsMatch, "int").WithArguments("C.explicit operator checked int(C)").WithLocation(4, 45)
);
}
[Fact]
public void ConversionOperator_Supported_CRef_NoParameters_01()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
public static explicit operator int(C c)
{
return 0;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator checked int'
// /// See <see cref="explicit operator checked int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "explicit operator checked int").WithArguments("explicit operator checked int").WithLocation(3, 20),
// (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="explicit operator checked int"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38),
// (7,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static explicit operator checked int(C c)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 37)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).First();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_NoParameters_02()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator int""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator int' that could not be resolved
// /// See <see cref="explicit operator int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator int").WithArguments("explicit operator int").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_NoParameters_03()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int""/>.
/// </summary>
class C
{
public static explicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator checked int' that could not be resolved
// /// See <see cref="explicit operator checked int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator checked int").WithArguments("explicit operator checked int").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_NoParameters_05()
{
var source = @"
/// <summary>
/// See <see cref=""implicit operator int""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'implicit operator int' that could not be resolved
// /// See <see cref="implicit operator int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "implicit operator int").WithArguments("implicit operator int").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_NoParameters_06()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int""/>.
/// </summary>
class C
{
public static implicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator checked int' that could not be resolved
// /// See <see cref="explicit operator checked int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator checked int").WithArguments("explicit operator checked int").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_OneParameter_01()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int(C)""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
}
";
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator checked int(C)'
// /// See <see cref="explicit operator checked int(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "explicit operator checked int(C)").WithArguments("explicit operator checked int(C)").WithLocation(3, 20),
// (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="explicit operator checked int(C)"/>.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38),
// (7,37): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// public static explicit operator checked int(C c)
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "checked").WithArguments("checked user-defined operators", "11.0").WithLocation(7, 37)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify();
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
expectedSymbol = compilation.SourceModule.GlobalNamespace.GetTypeMember("C").GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation);
Assert.Equal(expectedSymbol, actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_OneParameter_02()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator int(C)""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator int' that could not be resolved
// /// See <see cref="explicit operator int(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator int(C)").WithArguments("explicit operator int(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_OneParameter_03()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int(C)""/>.
/// </summary>
class C
{
public static explicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator checked int' that could not be resolved
// /// See <see cref="explicit operator checked int(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator checked int(C)").WithArguments("explicit operator checked int(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_OneParameter_05()
{
var source = @"
/// <summary>
/// See <see cref=""implicit operator int(C)""/>.
/// </summary>
class C
{
public static explicit operator checked int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'implicit operator int' that could not be resolved
// /// See <see cref="implicit operator int(C)"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "implicit operator int(C)").WithArguments("implicit operator int(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Supported_CRef_OneParameter_06()
{
var source = @"
/// <summary>
/// See <see cref=""explicit operator checked int(C)""/>.
/// </summary>
class C
{
public static implicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'explicit operator checked int' that could not be resolved
// /// See <see cref="explicit operator checked int"/>.
Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator checked int(C)").WithArguments("explicit operator checked int(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperators_Unsupported_01()
{
var source1 =
@"
class C
{
public static implicit operator checked int(C x) => 0;
}
";
foreach (var options in new[] { TestOptions.RegularPreview, TestOptions.Regular10, TestOptions.Regular11 })
{
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: options);
compilation1.VerifyDiagnostics(
// (4,37): error CS9151: An 'implicit' user-defined conversion operator cannot be declared checked
// public static implicit operator checked int(C x) => 0;
Diagnostic(ErrorCode.ERR_ImplicitConversionOperatorCantBeChecked, "checked").WithLocation(4, 37)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbol = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).Single();
Assert.Equal(MethodKind.Conversion, opSymbol.MethodKind);
Assert.Equal("op_Implicit", opSymbol.Name);
Assert.Equal("System.Int32 C.op_Implicit(C x)", opSymbol.ToTestDisplayString());
Assert.Equal("C.implicit operator int(C)", opSymbol.ToDisplayString());
}
}
[Fact]
public void ConversionOperators_Unsupported_03()
{
var source1 =
@"
class C
{
public static implicit operator int(C x) => 0;
public static implicit operator checked int(C x) => 1;
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (5,37): error CS9151: An 'implicit' user-defined conversion operator cannot be declared checked
// public static implicit operator checked int(C x) => 1;
Diagnostic(ErrorCode.ERR_ImplicitConversionOperatorCantBeChecked, "checked").WithLocation(5, 37),
// (5,45): error CS0557: Duplicate user-defined conversion in type 'C'
// public static implicit operator checked int(C x) => 1;
Diagnostic(ErrorCode.ERR_DuplicateConversionInClass, "int").WithArguments("C").WithLocation(5, 45)
);
var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C");
var opSymbols = c.GetMembers().OfType<MethodSymbol>().Where(m => m.MethodKind != MethodKind.Constructor).ToArray();
Assert.Equal(2, opSymbols.Length);
Assert.Equal(MethodKind.Conversion, opSymbols[0].MethodKind);
Assert.Equal(MethodKind.Conversion, opSymbols[1].MethodKind);
Assert.Equal("System.Int32 C.op_Implicit(C x)", opSymbols[0].ToTestDisplayString());
Assert.Equal("System.Int32 C.op_Implicit(C x)", opSymbols[1].ToTestDisplayString());
}
[Fact]
public void ConversionOperator_Unsupported_CRef_NoParameters_01()
{
var source = @"
/// <summary>
/// See <see cref=""implicit operator checked int"" />.
/// </summary>
class C
{
public static implicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'implicit operator checked int' that could not be resolved
// /// See <see cref="implicit operator checked int" />.
Diagnostic(ErrorCode.WRN_BadXMLRef, "implicit operator checked int").WithArguments("implicit operator checked int").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator checked int'
// /// See <see cref="implicit operator checked int" />.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "implicit operator checked int").WithArguments("implicit operator checked int").WithLocation(3, 20),
// (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="implicit operator checked int" />.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Fact]
public void ConversionOperator_Unsupported_CRef_OneParameter_01()
{
var source = @"
/// <summary>
/// See <see cref=""implicit operator checked int(C)"" />.
/// </summary>
class C
{
public static implicit operator int(C c)
{
return 0;
}
}
";
var expected = new[] {
// (3,20): warning CS1574: XML comment has cref attribute 'implicit operator checked int' that could not be resolved
// /// See <see cref="implicit operator checked int(C)" />.
Diagnostic(ErrorCode.WRN_BadXMLRef, "implicit operator checked int(C)").WithArguments("implicit operator checked int(C)").WithLocation(3, 20)
};
var compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.RegularPreview.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
var crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
var actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular10.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(
// (3,20): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator checked int(C)'
// /// See <see cref="implicit operator checked int(C)" />.
Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "implicit operator checked int(C)").WithArguments("implicit operator checked int(C)").WithLocation(3, 20),
// (3,38): warning CS1658: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.. See also error CS8936.
// /// See <see cref="implicit operator checked int(C)" />.
Diagnostic(ErrorCode.WRN_ErrorOverride, "checked").WithArguments("Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.", "8936").WithLocation(3, 38)
);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
compilation = CreateCompilationWithMscorlib40AndDocumentationComments(source, parseOptions: TestOptions.Regular11.WithDocumentationMode(DocumentationMode.Diagnose));
compilation.VerifyDiagnostics(expected);
crefSyntax = CrefTests.GetCrefSyntaxes(compilation).Single();
actualSymbol = CrefTests.GetReferencedSymbol(crefSyntax, compilation, expected);
Assert.Null(actualSymbol);
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void OverloadResolution_UnaryOperators_01(string op)
{
var source1 =
@"
public class C0
{
public static C0 operator checked " + op + @"(C0 x)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
public class C1 : C0
{
public static C1 operator checked " + op + @"(C1 x)
{
System.Console.WriteLine(""checked C1"");
return x;
}
public static C1 operator " + op + @"(C1 x)
{
System.Console.WriteLine(""regular C1"");
return x;
}
}
public class C2 : C1
{
public static C2 operator " + op + @"(C2 x)
{
System.Console.WriteLine(""regular C2"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
TestUncheckedC0(new C0());
TestCheckedC1(new C1());
TestUncheckedC1(new C1());
TestCheckedC2(new C2());
TestUncheckedC2(new C2());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(" + op + @"x); // C0
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(" + op + @"x);
}
public static C1 TestCheckedC1(C1 x)
{
return checked(" + op + @"x); // C1
}
public static C1 TestUncheckedC1(C1 x)
{
return unchecked(" + op + @"x);
}
public static C2 TestCheckedC2(C2 x)
{
return checked(" + op + @"x); // C2
}
public static C2 TestUncheckedC2(C2 x)
{
return unchecked(" + op + @"x);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (16,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(++x); // C0
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 24),
// (26,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(++x); // C1
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 24)
);
}
[Fact]
public void OverloadResolution_UnaryOperators_02()
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked -(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
//
// public static C0 operator -(C0 x)
// {
// System.Console.WriteLine(""regular C0"");
// return x;
// }
// }
//
// class C1 : C0
// {
// public static C1 operator checked -(C1 x)
// {
// System.Console.WriteLine(""checked C1"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 op_CheckedUnaryNegation (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname static
class C0 op_UnaryNegation (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""regular C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
.class public auto ansi beforefieldinit C1
extends C0
{
.method public hidebysig specialname static
class C1 op_CheckedUnaryNegation (
class C1 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C1
)
IL_0000: nop
IL_0001: ldstr ""checked C1""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void C0::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C1());
TestUncheckedC0(new C1());
TestCheckedC1(new C1());
TestUncheckedC1(new C1());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(-x);
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(-x);
}
public static C1 TestCheckedC1(C1 x)
{
return checked(-x);
}
public static C0 TestUncheckedC1(C1 x)
{
return unchecked(-x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C0
").VerifyDiagnostics();
}
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void OverloadResolution_UnaryOperators_03(string op, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked " + op + @"(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 " + checkedName + @" (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(" + op + @"x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
").VerifyDiagnostics();
}
[Theory]
[InlineData("-", "op_CheckedUnaryNegation")]
[InlineData("++", "op_CheckedIncrement")]
[InlineData("--", "op_CheckedDecrement")]
public void OverloadResolution_UnaryOperators_04(string op, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked " + op + @"(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 " + checkedName + @" (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestUncheckedC0(new C0());
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(" + op + @"x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (11,26): error CS0023: Operator '-' cannot be applied to operand of type 'C0'
// return unchecked(-x);
Diagnostic(ErrorCode.ERR_BadUnaryOp, op + "x").WithArguments(op, "C0").WithLocation(11, 26)
);
}
/// <summary>
/// Lifted nullable
/// </summary>
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void OverloadResolution_UnaryOperators_05(string op)
{
var source1 =
@"
public struct C0
{
public static C0 operator checked " + op + @"(C0 x)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
System.Console.WriteLine(TestCheckedC0(new C0()) is null ? ""null"" : ""not null"");
System.Console.WriteLine(TestCheckedC0(null) is null ? ""null"" : ""not null"");
}
public static C0? TestCheckedC0(C0? x)
{
return checked(" + op + @"x);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (12,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(++x);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, op + "x").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 24)
);
}
[Theory]
[InlineData("++")]
[InlineData("--")]
public void ExpressionTree_UnaryOperators_01(string op)
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator checked " + op + @"(C0 x)
{
return x;
}
public static C0 operator " + op + @"(C0 x)
{
return x;
}
}
class Program
{
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(" + op + @"x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(" + op + @"x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (22,29): error CS0832: An expression tree may not contain an assignment operator
// return x => checked(++x);
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, op + "x").WithLocation(22, 29),
// (27,31): error CS0832: An expression tree may not contain an assignment operator
// return x => unchecked(++x);
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, op + "x").WithLocation(27, 31)
);
}
[Fact]
public void ExpressionTree_UnaryOperators_02()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator checked -(C0 x)
{
return x;
}
public static C0 operator -(C0 x)
{
return x;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(-x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(-x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput: @"
x => -x
x => -x
").VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""C0 C0.op_CheckedUnaryNegation(C0)""
IL_001c: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0021: castclass ""System.Reflection.MethodInfo""
IL_0026: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.NegateChecked(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002b: ldc.i4.1
IL_002c: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0031: dup
IL_0032: ldc.i4.0
IL_0033: ldloc.0
IL_0034: stelem.ref
IL_0035: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003a: stloc.1
IL_003b: br.s IL_003d
IL_003d: ldloc.1
IL_003e: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""C0 C0.op_UnaryNegation(C0)""
IL_001c: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0021: castclass ""System.Reflection.MethodInfo""
IL_0026: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Negate(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002b: ldc.i4.1
IL_002c: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0031: dup
IL_0032: ldc.i4.0
IL_0033: ldloc.0
IL_0034: stelem.ref
IL_0035: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003a: stloc.1
IL_003b: br.s IL_003d
IL_003d: ldloc.1
IL_003e: ret
}
");
}
[Fact]
public void ExpressionTree_UnaryOperators_03()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator -(C0 x)
{
return x;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(-x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(-x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput: @"
x => -x
x => -x
").VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""C0 C0.op_UnaryNegation(C0)""
IL_001c: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0021: castclass ""System.Reflection.MethodInfo""
IL_0026: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Negate(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002b: ldc.i4.1
IL_002c: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0031: dup
IL_0032: ldc.i4.0
IL_0033: ldloc.0
IL_0034: stelem.ref
IL_0035: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003a: stloc.1
IL_003b: br.s IL_003d
IL_003d: ldloc.1
IL_003e: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 63 (0x3f)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""C0 C0.op_UnaryNegation(C0)""
IL_001c: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0021: castclass ""System.Reflection.MethodInfo""
IL_0026: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Negate(System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002b: ldc.i4.1
IL_002c: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0031: dup
IL_0032: ldc.i4.0
IL_0033: ldloc.0
IL_0034: stelem.ref
IL_0035: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003a: stloc.1
IL_003b: br.s IL_003d
IL_003d: ldloc.1
IL_003e: ret
}
");
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void OverloadResolution_BinaryOperators_01(string op)
{
var source1 =
@"
public class C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
public class C1 : C0
{
public static C1 operator checked " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""checked C1"");
return x;
}
public static C1 operator " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""regular C1"");
return x;
}
}
public class C2 : C1
{
public static C2 operator " + op + @"(C2 x, C2 y)
{
System.Console.WriteLine(""regular C2"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
TestUncheckedC0(new C0());
TestCheckedC1(new C1());
TestUncheckedC1(new C1());
TestCheckedC2(new C2());
TestUncheckedC2(new C2());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(x " + op + @" x); // C0
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(x " + op + @" x);
}
public static C1 TestCheckedC1(C1 x)
{
return checked(x " + op + @" x); // C1
}
public static C1 TestUncheckedC1(C1 x)
{
return unchecked(x " + op + @" x);
}
public static C2 TestCheckedC2(C2 x)
{
return checked(x " + op + @" x); // C2
}
public static C2 TestUncheckedC2(C2 x)
{
return unchecked(x " + op + @" x);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (16,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(x + x); // C0
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 24),
// (26,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(x + x); // C1
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 24)
);
}
[Theory]
[InlineData("+", "op_Addition", "op_CheckedAddition")]
[InlineData("-", "op_Subtraction", "op_CheckedSubtraction")]
[InlineData("*", "op_Multiply", "op_CheckedMultiply")]
[InlineData("/", "op_Division", "op_CheckedDivision")]
public void OverloadResolution_BinaryOperators_02(string op, string name, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked -(C0 x, C0 y)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
//
// public static C0 operator -(C0 x, C0 y)
// {
// System.Console.WriteLine(""regular C0"");
// return x;
// }
// }
//
// class C1 : C0
// {
// public static C1 operator checked -(C1 x, C1 y)
// {
// System.Console.WriteLine(""checked C1"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 " + checkedName + @" (
class C0 x,
class C0 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname static
class C0 " + name + @" (
class C0 x,
class C0 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""regular C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
.class public auto ansi beforefieldinit C1
extends C0
{
.method public hidebysig specialname static
class C1 " + checkedName + @" (
class C1 x,
class C1 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C1
)
IL_0000: nop
IL_0001: ldstr ""checked C1""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void C0::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C1());
TestUncheckedC0(new C1());
TestCheckedC1(new C1());
TestUncheckedC1(new C1());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(x " + op + @" x);
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(x " + op + @" x);
}
public static C1 TestCheckedC1(C1 x)
{
return checked(x " + op + @" x);
}
public static C0 TestUncheckedC1(C1 x)
{
return unchecked(x " + op + @" x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C0
").VerifyDiagnostics();
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void OverloadResolution_BinaryOperators_03(string op, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked -(C0 x, C0 y)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 " + checkedName + @" (
class C0 x,
class C0 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(x " + op + @" x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
").VerifyDiagnostics();
}
[Theory]
[InlineData("+", "op_CheckedAddition")]
[InlineData("-", "op_CheckedSubtraction")]
[InlineData("*", "op_CheckedMultiply")]
[InlineData("/", "op_CheckedDivision")]
public void OverloadResolution_BinaryOperators_04(string op, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static C0 operator checked -(C0 x, C0 y)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 " + checkedName + @" (
class C0 x,
class C0 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestUncheckedC0(new C0());
}
public static C0 TestUncheckedC0(C0 x)
{
return unchecked(x " + op + @" x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (11,26): error CS0019: Operator '-' cannot be applied to operands of type 'C0' and 'C0'
// return unchecked(x - x);
Diagnostic(ErrorCode.ERR_BadBinaryOps, "x " + op + " x").WithArguments(op, "C0", "C0").WithLocation(11, 26)
);
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void OverloadResolution_BinaryOperators_05(string op)
{
var source1 =
@"
public class C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
public class C1 : C0
{
public static C1 operator checked " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""checked C1"");
return x;
}
public static C1 operator " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""regular C1"");
return x;
}
}
public class C2 : C1
{
public static C2 operator " + op + @"(C2 x, C2 y)
{
System.Console.WriteLine(""regular C2"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
TestUncheckedC0(new C0());
TestCheckedC1(new C1());
TestUncheckedC1(new C1());
TestCheckedC2(new C2());
TestUncheckedC2(new C2());
}
public static void TestCheckedC0(C0 x)
{
checked { x " + op + @"= x; } // C0
}
public static void TestUncheckedC0(C0 x)
{
unchecked { x " + op + @"= x; }
}
public static void TestCheckedC1(C1 x)
{
checked { x " + op + @"= x; } // C1
}
public static void TestUncheckedC1(C1 x)
{
unchecked { x " + op + @"= x; }
}
public static void TestCheckedC2(C2 x)
{
checked { x " + op + @"= x; } // C2
}
public static void TestUncheckedC2(C2 x)
{
unchecked { x " + op + @"= x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (16,19): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// checked { x += x; } // C0
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= x").WithArguments("checked user-defined operators", "11.0").WithLocation(16, 19),
// (26,19): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// checked { x += x; } // C1
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + "= x").WithArguments("checked user-defined operators", "11.0").WithLocation(26, 19)
);
}
[Fact]
public void OverloadResolution_BinaryOperators_06()
{
var source1 =
@"
public class C0
{
public static C0 operator checked /(C0 x, int y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator /(C0 x, int y)
{
return x;
}
public static C0 operator /(C0 x, byte y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
class Program
{
static void Main()
{
TestChecked(new C0(), 1);
}
public static void TestChecked(C0 x, byte y)
{
_ = checked(x / y);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
").VerifyDiagnostics();
}
/// <summary>
/// Lifted nullable
/// </summary>
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void OverloadResolution_BinaryOperators_07(string op)
{
var source1 =
@"
public struct C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
System.Console.WriteLine(TestCheckedC0(new C0(), new C0()) is null ? ""null"" : ""not null"");
System.Console.WriteLine(TestCheckedC0(null, new C0()) is null ? ""null"" : ""not null"");
System.Console.WriteLine(TestCheckedC0(new C0(), null) is null ? ""null"" : ""not null"");
System.Console.WriteLine(TestCheckedC0(null, null) is null ? ""null"" : ""not null"");
}
public static C0? TestCheckedC0(C0? x, C0? y)
{
return checked(x " + op + @" y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
null
null
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
null
null
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (14,24): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// return checked(x + y);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "x " + op + " y").WithArguments("checked user-defined operators", "11.0").WithLocation(14, 24)
);
}
[Fact]
public void ExpressionTree_BinaryOperators_01()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator checked /(C0 x, C0 y)
{
return x;
}
public static C0 operator /(C0 x, C0 y)
{
return x;
}
}
class Program
{
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(x / x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(x / x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (22,29): error CS7053: An expression tree may not contain 'C0.operator checked /(C0, C0)'
// return x => checked(x / x);
Diagnostic(ErrorCode.ERR_FeatureNotValidInExpressionTree, "x / x").WithArguments("C0.operator checked /(C0, C0)").WithLocation(22, 29)
);
}
[Theory]
[InlineData("+", "op_Addition", "op_CheckedAddition", "Add", "AddChecked")]
[InlineData("-", "op_Subtraction", "op_CheckedSubtraction", "Subtract", "SubtractChecked")]
[InlineData("*", "op_Multiply", "op_CheckedMultiply", "Multiply", "MultiplyChecked")]
public void ExpressionTree_BinaryOperators_02(string op, string name, string checkedName, string factory, string checkedFactory)
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
return x;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(x " + op + @" x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(x " + op + @" x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput: @"
x => (x " + op + @" x)
x => (x " + op + @" x)
").VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 64 (0x40)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldloc.0
IL_0018: ldtoken ""C0 C0." + checkedName + @"(C0, C0)""
IL_001d: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0022: castclass ""System.Reflection.MethodInfo""
IL_0027: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression." + checkedFactory + @"(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002c: ldc.i4.1
IL_002d: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0032: dup
IL_0033: ldc.i4.0
IL_0034: ldloc.0
IL_0035: stelem.ref
IL_0036: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003b: stloc.1
IL_003c: br.s IL_003e
IL_003e: ldloc.1
IL_003f: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 64 (0x40)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldloc.0
IL_0018: ldtoken ""C0 C0." + name + @"(C0, C0)""
IL_001d: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0022: castclass ""System.Reflection.MethodInfo""
IL_0027: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression." + factory + @"(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002c: ldc.i4.1
IL_002d: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0032: dup
IL_0033: ldc.i4.0
IL_0034: ldloc.0
IL_0035: stelem.ref
IL_0036: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003b: stloc.1
IL_003c: br.s IL_003e
IL_003e: ldloc.1
IL_003f: ret
}
");
}
[Theory]
[InlineData("+", "op_Addition", "Add")]
[InlineData("-", "op_Subtraction", "Subtract")]
[InlineData("*", "op_Multiply", "Multiply")]
[InlineData("/", "op_Division", "Divide")]
public void ExpressionTree_BinaryOperators_03(string op, string name, string factory)
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator " + op + @"(C0 x, C0 y)
{
return x;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, C0>> TestChecked()
{
return x => checked(x " + op + @" x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return x => unchecked(x " + op + @" x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput: @"
x => (x " + op + @" x)
x => (x " + op + @" x)
").VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 64 (0x40)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldloc.0
IL_0018: ldtoken ""C0 C0." + name + @"(C0, C0)""
IL_001d: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0022: castclass ""System.Reflection.MethodInfo""
IL_0027: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression." + factory + @"(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002c: ldc.i4.1
IL_002d: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0032: dup
IL_0033: ldc.i4.0
IL_0034: ldloc.0
IL_0035: stelem.ref
IL_0036: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003b: stloc.1
IL_003c: br.s IL_003e
IL_003e: ldloc.1
IL_003f: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 64 (0x40)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, C0>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldloc.0
IL_0018: ldtoken ""C0 C0." + name + @"(C0, C0)""
IL_001d: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_0022: castclass ""System.Reflection.MethodInfo""
IL_0027: call ""System.Linq.Expressions.BinaryExpression System.Linq.Expressions.Expression." + factory + @"(System.Linq.Expressions.Expression, System.Linq.Expressions.Expression, System.Reflection.MethodInfo)""
IL_002c: ldc.i4.1
IL_002d: newarr ""System.Linq.Expressions.ParameterExpression""
IL_0032: dup
IL_0033: ldc.i4.0
IL_0034: ldloc.0
IL_0035: stelem.ref
IL_0036: call ""System.Linq.Expressions.Expression<System.Func<C0, C0>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, C0>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_003b: stloc.1
IL_003c: br.s IL_003e
IL_003e: ldloc.1
IL_003f: ret
}
");
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void ExpressionTree_BinaryOperators_04(string op)
{
var source1 =
@"
using System;
using System.Linq.Expressions;
class C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
return x;
}
}
class Program
{
public static Expression<Func<C0, C0>> TestChecked()
{
return checked(x => x " + op + @"= x);
}
public static Expression<Func<C0, C0>> TestUnchecked()
{
return unchecked(x => x " + op + @"= x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
compilation1.VerifyDiagnostics(
// (22,29): error CS0832: An expression tree may not contain an assignment operator
// return checked(x => x /= x);
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "x " + op + "= x").WithLocation(22, 29),
// (27,31): error CS0832: An expression tree may not contain an assignment operator
// return unchecked(x => x /= x);
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "x " + op + "= x").WithLocation(27, 31)
);
}
[Fact]
public void OverloadResolution_Conversion_01()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
public static implicit operator int(C0 x)
{
System.Console.WriteLine(""implicit C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedImplicitLong(new C0());
TestCheckedExplicitLong(new C0());
TestUncheckedImplicitLong(new C0());
TestUncheckedExplicitLong(new C0());
TestCheckedImplicitInt(new C0());
TestCheckedExplicitInt(new C0());
TestUncheckedImplicitInt(new C0());
TestUncheckedExplicitInt(new C0());
}
public static long TestCheckedImplicitLong(C0 x)
{
checked { return x; }
}
public static long TestCheckedExplicitLong(C0 x)
{
checked { return (long)x; }
}
public static long TestUncheckedImplicitLong(C0 x)
{
unchecked { return x; }
}
public static long TestUncheckedExplicitLong(C0 x)
{
unchecked { return (long)x; }
}
public static int TestCheckedImplicitInt(C0 x)
{
checked { return x; }
}
public static int TestCheckedExplicitInt(C0 x)
{
checked { return (int)x; }
}
public static int TestUncheckedImplicitInt(C0 x)
{
unchecked { return x; }
}
public static int TestUncheckedExplicitInt(C0 x)
{
unchecked { return (int)x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
implicit C0
checked C0
implicit C0
regular C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
implicit C0
checked C0
implicit C0
regular C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (23,26): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// checked { return (long)x; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(long)x").WithArguments("checked user-defined operators", "11.0").WithLocation(23, 26)
);
}
[Fact]
public void OverloadResolution_Conversion_02()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedExplicitLong(new C0());
TestUncheckedExplicitLong(new C0());
TestCheckedExplicitInt(new C0());
TestUncheckedExplicitInt(new C0());
}
public static long TestCheckedExplicitLong(C0 x)
{
checked { return (long)x; }
}
public static long TestUncheckedExplicitLong(C0 x)
{
unchecked { return (long)x; }
}
public static int TestCheckedExplicitInt(C0 x)
{
checked { return (int)x; }
}
public static int TestUncheckedExplicitInt(C0 x)
{
unchecked { return (int)x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
regular C0
checked C0
regular C0
").VerifyDiagnostics();
var source3 =
@"
class Program
{
static void Main()
{
}
public static long TestCheckedImplicitLong(C0 x)
{
checked { return x; }
}
public static long TestUncheckedImplicitLong(C0 x)
{
unchecked { return x; }
}
public static int TestCheckedImplicitInt(C0 x)
{
checked { return x; }
}
public static int TestUncheckedImplicitInt(C0 x)
{
unchecked { return x; }
}
}
";
var compilation2 = CreateCompilation(source1 + source3, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
compilation2.VerifyDiagnostics(
// (25,26): error CS0266: Cannot implicitly convert type 'C0' to 'long'. An explicit conversion exists (are you missing a cast?)
// checked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "long").WithLocation(25, 26),
// (30,28): error CS0266: Cannot implicitly convert type 'C0' to 'long'. An explicit conversion exists (are you missing a cast?)
// unchecked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "long").WithLocation(30, 28),
// (35,26): error CS0266: Cannot implicitly convert type 'C0' to 'int'. An explicit conversion exists (are you missing a cast?)
// checked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "int").WithLocation(35, 26),
// (40,28): error CS0266: Cannot implicitly convert type 'C0' to 'int'. An explicit conversion exists (are you missing a cast?)
// unchecked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "int").WithLocation(40, 28)
);
}
[Fact]
public void OverloadResolution_Conversion_03()
{
// The IL is equivalent to
//
// public class C0
// {
// public static explicit operator checked long(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return 0;
// }
//
// public static implicit operator int(C0 x)
// {
// System.Console.WriteLine(""implicit C0"");
// return 0;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
int64 op_CheckedExplicit (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] int64
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: conv.i8
IL_000e: stloc.0
IL_000f: br.s IL_0011
IL_0011: ldloc.0
IL_0012: ret
}
.method public hidebysig specialname static
int32 op_Implicit (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] int32
)
IL_0000: nop
IL_0001: ldstr ""implicit C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedImplicitLong(new C0());
TestCheckedExplicitLong(new C0());
TestUncheckedImplicitLong(new C0());
TestUncheckedExplicitLong(new C0());
TestCheckedImplicitInt(new C0());
TestCheckedExplicitInt(new C0());
TestUncheckedImplicitInt(new C0());
TestUncheckedExplicitInt(new C0());
}
public static long TestCheckedImplicitLong(C0 x)
{
checked { return x; }
}
public static long TestCheckedExplicitLong(C0 x)
{
checked { return (long)x; }
}
public static long TestUncheckedImplicitLong(C0 x)
{
unchecked { return x; }
}
public static long TestUncheckedExplicitLong(C0 x)
{
unchecked { return (long)x; }
}
public static int TestCheckedImplicitInt(C0 x)
{
checked { return x; }
}
public static int TestCheckedExplicitInt(C0 x)
{
checked { return (int)x; }
}
public static int TestUncheckedImplicitInt(C0 x)
{
unchecked { return x; }
}
public static int TestUncheckedExplicitInt(C0 x)
{
unchecked { return (int)x; }
}
}
";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
implicit C0
checked C0
implicit C0
implicit C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
}
[Fact]
public void OverloadResolution_Conversion_04()
{
// The IL is equivalent to
//
// public class C0
// {
// public static explicit operator checked long(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return 0;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
int64 op_CheckedExplicit (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] int64
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: conv.i8
IL_000e: stloc.0
IL_000f: br.s IL_0011
IL_0011: ldloc.0
IL_0012: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedExplicitLong(new C0());
TestCheckedExplicitInt(new C0());
}
public static long TestCheckedExplicitLong(C0 x)
{
checked { return (long)x; }
}
public static int TestCheckedExplicitInt(C0 x)
{
checked { return (int)x; }
}
}
";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
checked C0
").VerifyDiagnostics();
var source2 =
@"
class Program
{
static void Main()
{
}
public static long TestCheckedImplicitLong(C0 x)
{
checked { return x; }
}
public static long TestUncheckedImplicitLong(C0 x)
{
unchecked { return x; }
}
public static long TestUncheckedExplicitLong(C0 x)
{
unchecked { return (long)x; }
}
public static int TestCheckedImplicitInt(C0 x)
{
checked { return x; }
}
public static int TestUncheckedImplicitInt(C0 x)
{
unchecked { return x; }
}
public static int TestUncheckedExplicitInt(C0 x)
{
unchecked { return (int)x; }
}
}
";
var compilation2 = CreateCompilationWithIL(source2, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
compilation2.VerifyDiagnostics(
// (10,26): error CS0266: Cannot implicitly convert type 'C0' to 'long'. An explicit conversion exists (are you missing a cast?)
// checked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "long").WithLocation(10, 26),
// (15,28): error CS0029: Cannot implicitly convert type 'C0' to 'long'
// unchecked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("C0", "long").WithLocation(15, 28),
// (20,28): error CS0030: Cannot convert type 'C0' to 'long'
// unchecked { return (long)x; }
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(long)x").WithArguments("C0", "long").WithLocation(20, 28),
// (25,26): error CS0266: Cannot implicitly convert type 'C0' to 'int'. An explicit conversion exists (are you missing a cast?)
// checked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("C0", "int").WithLocation(25, 26),
// (30,28): error CS0029: Cannot implicitly convert type 'C0' to 'int'
// unchecked { return x; }
Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("C0", "int").WithLocation(30, 28),
// (35,28): error CS0030: Cannot convert type 'C0' to 'int'
// unchecked { return (int)x; }
Diagnostic(ErrorCode.ERR_NoExplicitConv, "(int)x").WithArguments("C0", "int").WithLocation(35, 28)
);
}
/// <summary>
/// Lifted nullable
/// </summary>
[Fact]
public void OverloadResolution_Conversion_05()
{
var source1 =
@"
public struct C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
System.Console.WriteLine(TestCheckedExplicitLong(new C0()) is null ? ""null"" : ""not null"");
System.Console.WriteLine(TestCheckedExplicitLong(null) is null ? ""null"" : ""not null"");
}
public static long? TestCheckedExplicitLong(C0? x)
{
checked { return (long?)x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
").VerifyDiagnostics();
compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
not null
null
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
compilation3.VerifyDiagnostics(
// (12,26): error CS8936: Feature 'checked user-defined operators' is not available in C# 10.0. Please use language version 11.0 or greater.
// checked { return (long?)x; }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion10, "(long?)x").WithArguments("checked user-defined operators", "11.0").WithLocation(12, 26)
);
}
[Fact]
public void ExpressionTree_Conversion_01()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
public class C0
{
public static explicit operator checked long(C0 x)
{
return 0;
}
public static explicit operator long(C0 x)
{
return 0;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestCheckedLong());
System.Console.WriteLine(TestUncheckedLong());
System.Console.WriteLine(TestCheckedInt());
System.Console.WriteLine(TestUncheckedInt());
System.Console.WriteLine(TestCheckedNullableLong());
System.Console.WriteLine(TestUncheckedNullableLong());
}
public static Expression<Func<C0, long>> TestCheckedLong()
{
return x => checked((long)x);
}
public static Expression<Func<C0, long>> TestUncheckedLong()
{
return x => unchecked((long)x);
}
public static Expression<Func<C0, int>> TestCheckedInt()
{
return x => checked((int)x);
}
public static Expression<Func<C0, int>> TestUncheckedInt()
{
return x => unchecked((int)x);
}
public static Expression<Func<C0, long?>> TestCheckedNullableLong()
{
return x => checked((long?)x);
}
public static Expression<Func<C0, long?>> TestUncheckedNullableLong()
{
return x => unchecked((long?)x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput:
ExecutionConditionUtil.IsDesktop ?
@"
x => ConvertChecked(x)
x => Convert(x)
x => ConvertChecked(ConvertChecked(x))
x => Convert(Convert(x))
x => Convert(ConvertChecked(x))
x => Convert(Convert(x))
"
:
@"
x => ConvertChecked(x, Int64)
x => Convert(x, Int64)
x => ConvertChecked(ConvertChecked(x, Int64), Int32)
x => Convert(Convert(x, Int64), Int32)
x => Convert(ConvertChecked(x, Int64), Nullable`1)
x => Convert(Convert(x, Int64), Nullable`1)
"
).VerifyDiagnostics();
verifier.VerifyIL("Program.TestCheckedLong", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_CheckedExplicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.ConvertChecked(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
verifier.VerifyIL("Program.TestUncheckedLong", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Explicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
verifier.VerifyIL("Program.TestCheckedInt", @"
{
// Code size 88 (0x58)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, int>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_CheckedExplicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.ConvertChecked(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldtoken ""int""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.ConvertChecked(System.Linq.Expressions.Expression, System.Type)""
IL_0044: ldc.i4.1
IL_0045: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004a: dup
IL_004b: ldc.i4.0
IL_004c: ldloc.0
IL_004d: stelem.ref
IL_004e: call ""System.Linq.Expressions.Expression<System.Func<C0, int>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, int>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0053: stloc.1
IL_0054: br.s IL_0056
IL_0056: ldloc.1
IL_0057: ret
}
");
verifier.VerifyIL("Program.TestUncheckedInt", @"
{
// Code size 88 (0x58)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, int>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Explicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldtoken ""int""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0044: ldc.i4.1
IL_0045: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004a: dup
IL_004b: ldc.i4.0
IL_004c: ldloc.0
IL_004d: stelem.ref
IL_004e: call ""System.Linq.Expressions.Expression<System.Func<C0, int>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, int>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0053: stloc.1
IL_0054: br.s IL_0056
IL_0056: ldloc.1
IL_0057: ret
}
");
verifier.VerifyIL("Program.TestCheckedNullableLong", @"
{
// Code size 88 (0x58)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long?>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_CheckedExplicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.ConvertChecked(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldtoken ""long?""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0044: ldc.i4.1
IL_0045: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004a: dup
IL_004b: ldc.i4.0
IL_004c: ldloc.0
IL_004d: stelem.ref
IL_004e: call ""System.Linq.Expressions.Expression<System.Func<C0, long?>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long?>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0053: stloc.1
IL_0054: br.s IL_0056
IL_0056: ldloc.1
IL_0057: ret
}
");
verifier.VerifyIL("Program.TestUncheckedNullableLong", @"
{
// Code size 88 (0x58)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long?>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Explicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldtoken ""long?""
IL_003a: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_003f: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)""
IL_0044: ldc.i4.1
IL_0045: newarr ""System.Linq.Expressions.ParameterExpression""
IL_004a: dup
IL_004b: ldc.i4.0
IL_004c: ldloc.0
IL_004d: stelem.ref
IL_004e: call ""System.Linq.Expressions.Expression<System.Func<C0, long?>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long?>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0053: stloc.1
IL_0054: br.s IL_0056
IL_0056: ldloc.1
IL_0057: ret
}
");
}
[Fact]
public void ExpressionTree_Conversion_02()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
public class C0
{
public static explicit operator long(C0 x)
{
return 0;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, long>> TestChecked()
{
return x => checked((long)x);
}
public static Expression<Func<C0, long>> TestUnchecked()
{
return x => unchecked((long)x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput:
ExecutionConditionUtil.IsDesktop ?
@"
x => Convert(x)
x => Convert(x)
"
:
@"
x => Convert(x, Int64)
x => Convert(x, Int64)
"
).VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Explicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Explicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
}
[Fact]
public void ExpressionTree_Conversion_03()
{
var source1 =
@"
using System;
using System.Linq.Expressions;
public class C0
{
public static implicit operator long(C0 x)
{
return 0;
}
}
class Program
{
static void Main()
{
System.Console.WriteLine(TestChecked());
System.Console.WriteLine(TestUnchecked());
}
public static Expression<Func<C0, long>> TestChecked()
{
return x => checked((long)x);
}
public static Expression<Func<C0, long>> TestUnchecked()
{
return x => unchecked((long)x);
}
}
";
var compilation1 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(compilation1, expectedOutput:
ExecutionConditionUtil.IsDesktop ?
@"
x => Convert(x)
x => Convert(x)
"
:
@"
x => Convert(x, Int64)
x => Convert(x, Int64)
"
).VerifyDiagnostics();
verifier.VerifyIL("Program.TestChecked", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Implicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
verifier.VerifyIL("Program.TestUnchecked", @"
{
// Code size 73 (0x49)
.maxstack 5
.locals init (System.Linq.Expressions.ParameterExpression V_0,
System.Linq.Expressions.Expression<System.Func<C0, long>> V_1)
IL_0000: nop
IL_0001: ldtoken ""C0""
IL_0006: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000b: ldstr ""x""
IL_0010: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)""
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: ldtoken ""long""
IL_001c: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_0021: ldtoken ""long C0.op_Implicit(C0)""
IL_0026: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)""
IL_002b: castclass ""System.Reflection.MethodInfo""
IL_0030: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type, System.Reflection.MethodInfo)""
IL_0035: ldc.i4.1
IL_0036: newarr ""System.Linq.Expressions.ParameterExpression""
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldloc.0
IL_003e: stelem.ref
IL_003f: call ""System.Linq.Expressions.Expression<System.Func<C0, long>> System.Linq.Expressions.Expression.Lambda<System.Func<C0, long>>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])""
IL_0044: stloc.1
IL_0045: br.s IL_0047
IL_0047: ldloc.1
IL_0048: ret
}
");
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void Dynamic_UnaryOperators_01(string op)
{
var source1 =
@"
public class C0
{
public static C0 operator checked " + op + @"(C0 x)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
public class C1 : C0
{
public static C1 operator checked " + op + @"(C1 x)
{
System.Console.WriteLine(""checked C1"");
return x;
}
public static C1 operator " + op + @"(C1 x)
{
System.Console.WriteLine(""regular C1"");
return x;
}
}
public class C2 : C1
{
public static C2 operator " + op + @"(C2 x)
{
System.Console.WriteLine(""regular C2"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestChecked(new C0());
TestUnchecked(new C0());
TestChecked(new C1());
TestUnchecked(new C1());
TestChecked(new C2());
TestUnchecked(new C2());
}
public static dynamic TestChecked(dynamic x)
{
return checked(" + op + @"x);
}
public static dynamic TestUnchecked(dynamic x)
{
return unchecked(" + op + @"x);
}
}
";
var compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilationWithCSharp(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
CompileAndVerify(compilation3, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void Dynamic_BinaryOperators_01(string op)
{
var source1 =
@"
public class C0
{
public static C0 operator checked " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
public class C1 : C0
{
public static C1 operator checked " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""checked C1"");
return x;
}
public static C1 operator " + op + @"(C1 x, C1 y)
{
System.Console.WriteLine(""regular C1"");
return x;
}
}
public class C2 : C1
{
public static C2 operator " + op + @"(C2 x, C2 y)
{
System.Console.WriteLine(""regular C2"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestChecked(new C0());
TestUnchecked(new C0());
TestChecked(new C1());
TestUnchecked(new C1());
TestChecked(new C2());
TestUnchecked(new C2());
}
public static dynamic TestChecked(dynamic x)
{
return checked(x " + op + @" x);
}
public static dynamic TestUnchecked(dynamic x)
{
return unchecked(x " + op + @" x);
}
}
";
var compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilationWithCSharp(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
CompileAndVerify(compilation3, expectedOutput: @"
regular C0
regular C0
regular C1
regular C1
regular C2
regular C2
").VerifyDiagnostics();
}
[Fact]
public void Dynamic_Conversion_01()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
public static implicit operator int(C0 x)
{
System.Console.WriteLine(""implicit C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedImplicitLong(new C0());
TestCheckedExplicitLong(new C0());
TestUncheckedImplicitLong(new C0());
TestUncheckedExplicitLong(new C0());
TestCheckedImplicitInt(new C0());
TestCheckedExplicitInt(new C0());
TestUncheckedImplicitInt(new C0());
TestUncheckedExplicitInt(new C0());
}
public static long TestCheckedImplicitLong(dynamic x)
{
checked { return x; }
}
public static long TestCheckedExplicitLong(dynamic x)
{
checked { return (long)x; }
}
public static long TestUncheckedImplicitLong(dynamic x)
{
unchecked { return x; }
}
public static long TestUncheckedExplicitLong(dynamic x)
{
unchecked { return (long)x; }
}
public static int TestCheckedImplicitInt(dynamic x)
{
checked { return x; }
}
public static int TestCheckedExplicitInt(dynamic x)
{
checked { return (int)x; }
}
public static int TestUncheckedImplicitInt(dynamic x)
{
unchecked { return x; }
}
public static int TestUncheckedExplicitInt(dynamic x)
{
unchecked { return (int)x; }
}
}
";
var compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
implicit C0
regular C0
implicit C0
regular C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
compilation1 = CreateCompilationWithCSharp(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular11);
CompileAndVerify(compilation1, expectedOutput: @"
implicit C0
regular C0
implicit C0
regular C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilationWithCSharp(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10, references: new[] { compilation2.ToMetadataReference() });
CompileAndVerify(compilation3, expectedOutput: @"
implicit C0
regular C0
implicit C0
regular C0
implicit C0
implicit C0
implicit C0
implicit C0
").VerifyDiagnostics();
}
[Theory]
[InlineData("-")]
[InlineData("++")]
[InlineData("--")]
public void Matching_UnaryOperators_01(string op)
{
var source1 =
@"
#nullable enable
public class C0
{
public static C0 operator checked " + op + @"(C0 x)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0? operator " + op + @"(C0? x)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(" + op + @"x);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Fact]
public void Matching_UnaryOperators_02()
{
// The IL is equivalent to
//
// class C0
// {
// public static modopt(System.Object) C0 operator checked -(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
//
// public static C0 operator -(modopt(System.Object) C0 x)
// {
// System.Console.WriteLine(""regular C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 modopt(System.Object) op_CheckedUnaryNegation (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname static
class C0 op_UnaryNegation (
class C0 modopt(System.Object) x
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""regular C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(-x);
}
}
";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void Matching_BinaryOperators_01(string op)
{
var source1 =
@"
#nullable enable
public class C0
{
public static (C0 a, object b, nint c) operator checked " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return default;
}
public static (C0? d, dynamic e, System.IntPtr f) operator " + op + @"(C0 x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return default;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0(), new C0());
}
public static object TestCheckedC0(C0 x, C0 y)
{
return checked(x " + op + @" y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void Matching_BinaryOperators_02(string op)
{
var source1 =
@"
#nullable enable
public class C0
{
public static C0 operator checked " + op + @"((C0 a, object b, nint c) x, C0 y)
{
System.Console.WriteLine(""checked C0"");
return y;
}
public static C0 operator " + op + @"((C0? d, dynamic e, System.IntPtr f) x, C0 y)
{
System.Console.WriteLine(""regular C0"");
return y;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(default, new C0());
}
public static object TestCheckedC0((C0, object, nint) x, C0 y)
{
return checked(x " + op + @" y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Theory]
[InlineData("+")]
[InlineData("-")]
[InlineData("*")]
[InlineData("/")]
public void Matching_BinaryOperators_03(string op)
{
var source1 =
@"
#nullable enable
public class C0
{
public static C0 operator checked " + op + @"(C0 x, (C0 a, object b, nint c) y)
{
System.Console.WriteLine(""checked C0"");
return x;
}
public static C0 operator " + op + @"(C0 x, (C0? d, dynamic e, System.IntPtr f) y)
{
System.Console.WriteLine(""regular C0"");
return x;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0(), default);
}
public static object TestCheckedC0(C0 x, (C0, object, nint) y)
{
return checked(x " + op + @" y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Theory]
[InlineData("+", "op_Addition", "op_CheckedAddition")]
[InlineData("-", "op_Subtraction", "op_CheckedSubtraction")]
[InlineData("*", "op_Multiply", "op_CheckedMultiply")]
[InlineData("/", "op_Division", "op_CheckedDivision")]
public void Matching_BinaryOperators_04(string op, string name, string checkedName)
{
// The IL is equivalent to
//
// class C0
// {
// public static modopt(System.Object) C0 operator checked -(C0 x, modopt(System.Object) C0 y)
// {
// System.Console.WriteLine(""checked C0"");
// return x;
// }
//
// public static C0 operator -(modopt(System.Object) C0 x, C0 y)
// {
// System.Console.WriteLine(""regular C0"");
// return x;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
class C0 modopt(System.Object) " + checkedName + @" (
class C0 x,
class C0 modopt(System.Object) y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname static
class C0 " + name + @" (
class C0 modopt(System.Object) x,
class C0 y
) cil managed
{
.maxstack 1
.locals init (
[0] class C0
)
IL_0000: nop
IL_0001: ldstr ""regular C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: stloc.0
IL_000e: br.s IL_0010
IL_0010: ldloc.0
IL_0011: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedC0(new C0());
}
public static C0 TestCheckedC0(C0 x)
{
return checked(x " + op + @" x);
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Fact]
public void Matching_Conversion_01()
{
var source1 =
@"
#nullable enable
public class C0
{
public static explicit operator checked (C0 a, object b, nint c)(C0 x)
{
System.Console.WriteLine(""checked C0"");
return default;
}
public static explicit operator (C0? d, dynamic e, System.IntPtr f)(C0 x)
{
System.Console.WriteLine(""regular C0"");
return default;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedExplicitLong(new C0());
}
public static (C0, object, nint) TestCheckedExplicitLong(C0 x)
{
checked { return ((C0, object, nint))x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Fact]
public void Matching_Conversion_02()
{
var source1 =
@"
#nullable enable
public class C0
{
public static explicit operator checked C0((C0 a, object b, nint c) x)
{
System.Console.WriteLine(""checked C0"");
return new C0();
}
public static explicit operator C0((C0? d, dynamic e, System.IntPtr f) x)
{
System.Console.WriteLine(""regular C0"");
return new C0();
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestCheckedExplicitLong(default);
}
public static C0 TestCheckedExplicitLong((C0, object, nint) x)
{
checked { return (C0)x; }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview);
var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, references: new[] { compilation2.EmitToImageReference() });
CompileAndVerify(compilation3, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Fact]
public void Matching_Conversion_03()
{
// The IL is equivalent to
//
// public class C0
// {
// public static explicit operator checked modopt(System.Object) long(C0 x)
// {
// System.Console.WriteLine(""checked C0"");
// return 0;
// }
//
// public static explicit operator long(modopt(System.Object) C0 x)
// {
// System.Console.WriteLine(""regular C0"");
// return 0;
// }
// }
var ilSource = @"
.class public auto ansi beforefieldinit C0
extends System.Object
{
.method public hidebysig specialname static
int64 modopt(System.Object) op_CheckedExplicit (
class C0 x
) cil managed
{
.maxstack 1
.locals init (
[0] int64
)
IL_0000: nop
IL_0001: ldstr ""checked C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: conv.i8
IL_000e: stloc.0
IL_000f: br.s IL_0011
IL_0011: ldloc.0
IL_0012: ret
}
.method public hidebysig specialname static
int64 op_Explicit (
class C0 modopt(System.Object) x
) cil managed
{
.maxstack 1
.locals init (
[0] int64
)
IL_0000: nop
IL_0001: ldstr ""regular C0""
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldc.i4.0
IL_000d: conv.i8
IL_000e: stloc.0
IL_000f: br.s IL_0011
IL_0011: ldloc.0
IL_0012: ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void System.Object::.ctor()
IL_0006: nop
IL_0007: ret
}
}
";
var source1 =
@"
class Program
{
static void Main()
{
TestCheckedExplicitLong(new C0());
}
public static long TestCheckedExplicitLong(C0 x)
{
checked { return (long)x; }
}
}
";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"checked C0").VerifyDiagnostics();
}
[Fact]
[WorkItem(60419, "https://github.com/dotnet/roslyn/issues/60419")]
public void ClassifyConversion_01()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestExplicitLong1(new C0());
TestExplicitLong2(new C0());
}
public static long TestExplicitLong1(C0 x)
{
checked { return (long)x; }
}
public static long TestExplicitLong2(C0 y)
{
return checked( (long)y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
checked C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var int64 = ((IMethodSymbol)model.GetSymbolInfo(xNode.Parent).Symbol).ReturnType;
Assert.Equal("System.Int64", int64.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_CheckedExplicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
}
[Fact]
public void ClassifyConversion_02()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestExplicitLong1(new C0());
TestExplicitLong2(new C0());
}
public static long TestExplicitLong1(C0 x)
{
unchecked { return (long)x; }
}
public static long TestExplicitLong2(C0 y)
{
return unchecked( (long)y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var int64 = ((IMethodSymbol)model.GetSymbolInfo(xNode.Parent).Symbol).ReturnType;
Assert.Equal("System.Int64", int64.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
}
[Fact]
[WorkItem(60419, "https://github.com/dotnet/roslyn/issues/60419")]
public void ClassifyConversion_03()
{
var source1 =
@"
public class C0
{
public static explicit operator checked long(C0 x)
{
System.Console.WriteLine(""checked C0"");
return 0;
}
public static explicit operator long(C0 x)
{
System.Console.WriteLine(""regular C0"");
return 0;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
TestExplicitLong1(new C0());
TestExplicitLong2(new C0());
}
public static long TestExplicitLong1(C0 x)
{
checked { unchecked { return (long)x; }}
}
public static long TestExplicitLong2(C0 y)
{
checked { return unchecked( (long)y); }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var int64 = ((IMethodSymbol)model.GetSymbolInfo(xNode.Parent).Symbol).ReturnType;
Assert.Equal("System.Int64", int64.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode.SpanStart, xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode.SpanStart, yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(xNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: false).Method.ToTestDisplayString());
Assert.Equal("System.Int64 C0.op_Explicit(C0 x)", model.ClassifyConversion(yNode, int64, isExplicitInSource: true).Method.ToTestDisplayString());
}
[Fact]
[WorkItem(60419, "https://github.com/dotnet/roslyn/issues/60419")]
public void GetSpeculativeSymbolInfo_01()
{
var source1 =
@"
public class C0
{
public static C0 operator checked -(C0 a)
{
System.Console.WriteLine(""checked C0"");
return a;
}
public static C0 operator -(C0 a)
{
System.Console.WriteLine(""regular C0"");
return a;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
Test1(new C0());
Test2(new C0());
}
public static C0 Test1(C0 x)
{
checked { return -x; }
}
public static C0 Test2(C0 y)
{
return checked( -y);
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
checked C0
checked C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var xNodeToSpeculate = SyntaxFactory.ParseExpression("-x");
var yNodeToSpeculate = SyntaxFactory.ParseExpression("-y");
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(xNode.SpanStart, xNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_CheckedUnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(yNode.SpanStart, yNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
}
[Fact]
[WorkItem(60419, "https://github.com/dotnet/roslyn/issues/60419")]
public void GetSpeculativeSymbolInfo_02()
{
var source1 =
@"
public class C0
{
public static C0 operator checked -(C0 a)
{
System.Console.WriteLine(""checked C0"");
return a;
}
public static C0 operator -(C0 a)
{
System.Console.WriteLine(""regular C0"");
return a;
}
}
";
var source2 =
@"
class Program
{
static void Main()
{
Test1(new C0());
Test2(new C0());
}
public static C0 Test1(C0 x)
{
checked { unchecked { return -x; } }
}
public static C0 Test2(C0 y)
{
checked { return unchecked( -y); }
}
}
";
var compilation1 = CreateCompilation(source1 + source2, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(compilation1, expectedOutput: @"
regular C0
regular C0
").VerifyDiagnostics();
var tree = compilation1.SyntaxTrees.Single();
var model = compilation1.GetSemanticModel(tree);
var xNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x").Single();
var yNode = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y").Single();
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSymbolInfo(xNode.Parent).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSymbolInfo(yNode.Parent).Symbol.ToTestDisplayString());
var xNodeToSpeculate = SyntaxFactory.ParseExpression("-x");
var yNodeToSpeculate = SyntaxFactory.ParseExpression("-y");
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(xNode.SpanStart, xNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
Assert.Equal("C0 C0.op_UnaryNegation(C0 a)", model.GetSpeculativeSymbolInfo(yNode.SpanStart, yNodeToSpeculate, SpeculativeBindingOption.BindAsExpression).Symbol.ToTestDisplayString());
}
}
}
|