diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 2fb83875607f4..ba2678ebb3385 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -5,13 +5,13 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; -using System.Threading; using System.Reflection; using System.Reflection.Metadata; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.DocumentationComments; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using Microsoft.CodeAnalysis.CSharp.Emit; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -803,13 +803,35 @@ private bool IsValidExtensionMethodSignature() } } - private bool IsValidUserDefinedOperatorSignature(int parameterCount) => - !this.ReturnsVoid && - !this.IsGenericMethod && - !this.IsVararg && - this.ParameterCount == parameterCount && - this.ParameterRefKinds.IsDefault && // No 'ref' or 'out' - !this.IsParams(); + private bool IsValidUserDefinedOperatorSignature(int parameterCount) + { + if (this.ReturnsVoid || this.IsGenericMethod || this.IsVararg || this.ParameterCount != parameterCount || this.IsParams()) + { + return false; + } + + if (this.ParameterRefKinds.IsDefault) + { + return true; + } + + foreach (var kind in this.ParameterRefKinds) + { + switch (kind) + { + case RefKind.None: + case RefKind.In: + continue; + case RefKind.Out: + case RefKind.Ref: + return false; + default: + throw ExceptionUtilities.UnexpectedValue(kind); + } + } + + return true; + } private MethodKind ComputeMethodKind() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs index 43ef4decdf48a..549777585f2c1 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs @@ -1,10 +1,5 @@ // Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; -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; @@ -1918,5 +1913,158 @@ .maxstack 1 IL_002d: ret }"); } + + [Fact] + [WorkItem(530136, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=530136")] + public void OperatorsWithInParametersFromMetadata_Binary() + { + var reference = CreateStandardCompilation(@" +public class Test +{ + public int Value { get; set; } + + public static int operator +(in Test a, in Test b) + { + return a.Value + b.Value; + } +}"); + + var code = @" +class Program +{ + static void Main(string[] args) + { + var a = new Test { Value = 3 }; + var b = new Test { Value = 6 }; + + System.Console.WriteLine(a + b); + } +}"; + + CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "9"); + CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "9"); + } + + [Fact] + [WorkItem(530136, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=530136")] + public void OperatorsWithInParametersFromMetadata_Binary_Right() + { + var reference = CreateStandardCompilation(@" +public class Test +{ + public int Value { get; set; } + + public static int operator +(Test a, in Test b) + { + return a.Value + b.Value; + } +}"); + + var code = @" +class Program +{ + static void Main(string[] args) + { + var a = new Test { Value = 3 }; + var b = new Test { Value = 6 }; + + System.Console.WriteLine(a + b); + } +}"; + + CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "9"); + CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "9"); + } + + [Fact] + [WorkItem(530136, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=530136")] + public void OperatorsWithInParametersFromMetadata_Binary_Left() + { + var reference = CreateStandardCompilation(@" +public class Test +{ + public int Value { get; set; } + + public static int operator +(in Test a, Test b) + { + return a.Value + b.Value; + } +}"); + + var code = @" +class Program +{ + static void Main(string[] args) + { + var a = new Test { Value = 3 }; + var b = new Test { Value = 6 }; + + System.Console.WriteLine(a + b); + } +}"; + + CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "9"); + CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "9"); + } + + [Fact] + [WorkItem(530136, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=530136")] + public void OperatorsWithInParametersFromMetadata_Unary() + { + var reference = CreateStandardCompilation(@" +public class Test +{ + public bool Value { get; set; } + + public static bool operator !(in Test a) + { + return !a.Value; + } +}"); + + var code = @" +class Program +{ + static void Main(string[] args) + { + var a = new Test { Value = true }; + + System.Console.WriteLine(!a); + } +}"; + + CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "False"); + CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "False"); + } + + [Fact] + [WorkItem(530136, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=530136")] + public void OperatorsWithInParametersFromMetadata_Conversion() + { + var reference = CreateStandardCompilation(@" +public class Test +{ + public bool Value { get; set; } + + public static explicit operator int(in Test a) + { + return a.Value ? 3 : 5; + } +}"); + + var code = @" +class Program +{ + static void Main(string[] args) + { + var a = new Test { Value = true }; + + System.Console.WriteLine((int)a); + } +}"; + + CompileAndVerify(code, additionalRefs: new[] { reference.ToMetadataReference() }, expectedOutput: "3"); + CompileAndVerify(code, additionalRefs: new[] { reference.EmitToImageReference() }, expectedOutput: "3"); + } } } diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/InAttributeModifierTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/InAttributeModifierTests.vb index b9413b2610854..b9169d00463d8 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/InAttributeModifierTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/InAttributeModifierTests.vb @@ -701,6 +701,184 @@ BC30657: 'EndInvoke' has a return type that is not supported or parameter types ) End Sub + + Public Sub InOperatorsAreNotSupported_Binary() + Dim reference = CreateCSharpCompilation(" +public class Test +{ + public int Value { get; set; } + + public static int operator +(in Test a, in Test b) + { + return a.Value + b.Value; + } +}", parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = + + +Class Program + Shared Sub Main() + Dim a = New Test With { .Value = 3 } + Dim b = New Test With { .Value = 6 } + + System.Console.WriteLine(a + b) + End Sub +End Class + + + + Dim compilation = CreateCompilationWithMscorlib(source, references:={reference}) + + AssertTheseDiagnostics(compilation, +BC30452: Operator '+' is not defined for types 'Test' and 'Test'. + System.Console.WriteLine(a + b) + ~~~~~ + ) + End Sub + + + Public Sub InOperatorsAreNotSupported_Binary_Left() + Dim reference = CreateCSharpCompilation(" +public class Test +{ + public int Value { get; set; } + + public static int operator +(in Test a, Test b) + { + return a.Value + b.Value; + } +}", parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = + + +Class Program + Shared Sub Main() + Dim a = New Test With { .Value = 3 } + Dim b = New Test With { .Value = 6 } + + System.Console.WriteLine(a + b) + End Sub +End Class + + + + Dim compilation = CreateCompilationWithMscorlib(source, references:={reference}) + + AssertTheseDiagnostics(compilation, +BC30452: Operator '+' is not defined for types 'Test' and 'Test'. + System.Console.WriteLine(a + b) + ~~~~~ + ) + End Sub + + + Public Sub InOperatorsAreNotSupported_Binary_Right() + Dim reference = CreateCSharpCompilation(" +public class Test +{ + public int Value { get; set; } + + public static int operator +(Test a, in Test b) + { + return a.Value + b.Value; + } +}", parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = + + +Class Program + Shared Sub Main() + Dim a = New Test With { .Value = 3 } + Dim b = New Test With { .Value = 6 } + + System.Console.WriteLine(a + b) + End Sub +End Class + + + + Dim compilation = CreateCompilationWithMscorlib(source, references:={reference}) + + AssertTheseDiagnostics(compilation, +BC30452: Operator '+' is not defined for types 'Test' and 'Test'. + System.Console.WriteLine(a + b) + ~~~~~ + ) + End Sub + + + Public Sub InOperatorsAreNotSupported_Unary() + Dim reference = CreateCSharpCompilation(" +public class Test +{ + public bool Value { get; set; } + + public static bool operator !(in Test a) + { + return !a.Value; + } +}", parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = + + +Class Program + Shared Sub Main() + Dim a = New Test With { .Value = True } + + System.Console.WriteLine(Not a) + End Sub +End Class + + + + Dim compilation = CreateCompilationWithMscorlib(source, references:={reference}) + + AssertTheseDiagnostics(compilation, +BC30487: Operator 'Not' is not defined for type 'Test'. + System.Console.WriteLine(Not a) + ~~~~~ + ) + End Sub + + + Public Sub InOperatorsAreNotSupported_Conversion() + Dim reference = CreateCSharpCompilation(" +public class Test +{ + public bool Value { get; set; } + + public static explicit operator int(in Test a) + { + return a.Value ? 3 : 5; + } +}", parseOptions:=New CSharpParseOptions(CSharp.LanguageVersion.Latest)).EmitToImageReference() + + Dim source = + + +Class Program + Shared Sub Main() + Dim a = New Test With { .Value = True } + + System.Console.WriteLine(CType(a, Integer)) + End Sub +End Class + + + + Dim compilation = CreateCompilationWithMscorlib(source, references:={reference}) + + AssertTheseDiagnostics(compilation, +BC30311: Value of type 'Test' cannot be converted to 'Integer'. + System.Console.WriteLine(CType(a, Integer)) + ~ + ) + End Sub + Public Sub OverloadResolutionShouldBeAbleToPickOverloadsWithNoModreqsOverOnesWithModreq_Methods_Parameters() Dim reference = CreateCSharpCompilation("