SemanticModel does not return symbol for built-in operator && and ||
#2,901 创建于 2015年5月19日
描述
I originally reported this issue on CodePlex, where @gafter confirmed that it is a bug:
According to the language spec (7.12 Conditional logical operators) the operator is selected by using overload resolution. Therefore the Semantic Model should reflect that.
I'm reopening this issue here on GitHub so that I can track its progress - in the current VS2015 RC, the bug still has not been fixed and as far as I can tell, no progress has been made to resolve it. Maybe you lost track of the bug when you made the switch to GitHub?
Original bug report:
The code below produces the output
Bool symbol: Unknown
User Defined symbol: S.operator |(S, S)
whereas I expected
Bool symbol: bool.operator |(bool, bool)
User Defined symbol: S.operator |(S, S)
Apparently, Roslyn's semantic model does not resolve the built-in logical operators, whereas user-defined ones are resolved correctly. This is in contrast to all other operators that I've checked. Roslyn provides a symbol for all of these built-in operators (such as +, -, &, |, ...). I know that under the hoods, there is no method for && and || for built-in types. But it's an annoying inconsistency because you actually do get symbols for other built-in operators. For instance, when you resolve the symbol for 1 + 1, you get a SynthesizedIntrinsicOperatorSymbol representing Method System.Int32 System.Int32.op_Addition(System.Int32 left, System.Int32 right).
I don't really see a reason why that shouldn't also be the case for operators || and &&. Here's the code that I used to produce the above output (using the latest Nuget packages of Roslyn, version 1.0.0-rc2):
namespace RoslynSymbolTest
{
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
internal class Program
{
private static void Main(string[] args)
{
var code = @"
struct S
{
public static S operator&(S s1, S s2) { return s2; }
public static S operator|(S s1, S s2) { return s1; }
public static bool operator true(S s) { return false; }
public static bool operator false(S s) { return false; }
}
class X
{
bool BoolTest()
{
return true || false;
}
S UserDefinedTest()
{
S s;
return s || s;
}
}";
var tree = SyntaxFactory.ParseSyntaxTree(code);
var compilation = CSharpCompilation.Create("test", new[] { tree },
new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) },
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var model = compilation.GetSemanticModel(tree, true);
var boolLogicalAnd = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().First();
var userDefinedLogicalAnd = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Skip(1).First();
var boolSymbol = model.GetSymbolInfo(boolLogicalAnd);
var userDefinedSymbol = model.GetSymbolInfo(userDefinedLogicalAnd);
Console.WriteLine("Bool symbol: {0}", boolSymbol.Symbol == null ? "Unknown" : boolSymbol.Symbol.ToDisplayString());
Console.WriteLine("User Defined symbol: {0}", userDefinedSymbol.Symbol == null ? "Unknown" : userDefinedSymbol.Symbol.ToDisplayString());
}
}
}