Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Roslyn generating a > comparison instead of a != one here?

Tags:

c#

.net

roslyn

I was playing around with the C# compiler on TryRoslyn recently, and I came across a strange problem where an inequality check was getting converted into a greater-than one. Here is the repro code:

using System;
public class C {
    public void M() {
        if (Foo() != 0 || Foo() != 0)
        {
            Console.WriteLine("Hi!");
        }
    }

    private int Foo() => 0;
}

and here is the code that gets generated by the decompiler:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
public class C
{
    public void M()
    {
        bool flag = this.Foo() != 0 || this.Foo() > 0; // this should be an != check
        if (flag)
        {
            Console.WriteLine("Hi!");
        }
    }
    private int Foo()
    {
        return 0;
    }
}

Here's the link to the repro. Why does Roslyn do this; is it a bug?

Some observations I've made after playing around with the code for a while:

  • This only happens with the last boolean expression in the condition. For example if you add another || statement, it will only happen with the last call to Foo().

  • It also only happens with 0, specifically; if you substitute it for 1, or some other number, it won't happen.

like image 551
James Ko Avatar asked Jun 08 '16 04:06

James Ko


People also ask

What is Roslyn code analysis?

NET Compiler Platform (Roslyn) Analyzers inspect your C# or Visual Basic code for style, quality, maintainability, design, and other issues. This inspection or analysis happens during design time in all open files. Analyzers are divided into the following groups: Code style analyzers are built into Visual Studio.

Why is Roslyn a compiler?

One advantage that Roslyn has is when your application needs a scripting interface. With Roslyn, you can directly compile the script as C# source code with same programming possibilities as the source of the application and directly use it. do you mean after compiling, the script is converted to C# source code?

What is Roslyn in .NET core?

Roslyn, the . NET Compiler Platform, empowers the C# compiler on . NET Core and allows developers to leverage the rich code analysis APIs to perform code generation, analysis and compilation.

What is a source generator?

A Source Generator is a . NET Standard 2.0 assembly that is loaded by the compiler along with any analyzers. It's usable in environments where . NET Standard components can be loaded and run.


1 Answers

The decompiled code is wrong; this is a bug in the decompiler, not the compiler. The generated IL is correct. Read the IL very carefully. Do you see why the greater-than comparison is correct and the decompilation is wrong?

As for why this codegen only happens for the right hand side of the operator, that I do not recall. If you want to go spelunking in the code generator it is here:

https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs

You want method EmitIsNonNullOrZero.

like image 158
Eric Lippert Avatar answered Sep 20 '22 19:09

Eric Lippert