Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Roslyn failed to compile code

Tags:

c#

.net

linq

roslyn

After I have migrated my project from VS2013 to VS2015 the project no longer builds. A compilation error occurs in the following LINQ statement:

static void Main(string[] args) {     decimal a, b;     IEnumerable<dynamic> array = new string[] { "10", "20", "30" };     var result = (from v in array                   where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here                   orderby decimal.Parse(v)                   select v).ToArray(); } 

The compiler returns an error:

Error CS0165 Use of unassigned local variable 'b'

What causes this issue? Is it possible to fix it through a compiler setting?

like image 401
ramil89 Avatar asked Aug 12 '15 09:08

ramil89


People also ask

Is Roslyn a compiler?

NET Compiler Platform, also known by its codename Roslyn, is a set of open-source compilers and code analysis APIs for C# and Visual Basic (VB.NET) languages from Microsoft.

What is Roslyn folder in bin?

Roslyn is a complete rewrite of the C# and VB.net compilers with each written in their respective language for example the C# compiler is written in C# rather than C++.

What is the Roslyn compiler and how can I use it?

Roslyn is a collection of open-source compilers, code analysis and refactoring tools which work with C# and Visual Basic source codes. This set of compilers and tools can be used to create full-fledged compilers, including, first and foremost, source code analysis tools.


2 Answers

What does cause this issue?

Looks like a compiler bug to me. At least, it did. Although the decimal.TryParse(v, out a) and decimal.TryParse(v, out b) expressions are evaluated dynamically, I expected the compiler to still understand that by the time it reaches a <= b, both a and b are definitely assigned. Even with the weirdnesses you can come up with in dynamic typing, I'd expect to only ever evaluate a <= b after evaluating both of the TryParse calls.

However, it turns out that through operator and conversion tricky, it's entirely feasible to have an expression A && B && C which evaluates A and C but not B - if you're cunning enough. See the Roslyn bug report for Neal Gafter's ingenious example.

Making that work with dynamic is even harder - the semantics involved when the operands are dynamic are harder to describe, because in order to perform overload resolution, you need to evaluate operands to find out what types are involved, which can be counter-intuitive. However, again Neal has come up with an example which shows that the compiler error is required... this isn't a bug, it's a bug fix. Huge amounts of kudos to Neal for proving it.

Is it possible to fix it through compiler settings?

No, but there are alternatives which avoid the error.

Firstly, you could stop it from being dynamic - if you know that you'll only ever use strings, then you could use IEnumerable<string> or give the range variable v a type of string (i.e. from string v in array). That would be my preferred option.

If you really need to keep it dynamic, just give b a value to start with:

decimal a, b = 0m; 

This won't do any harm - we know that actually your dynamic evaluation won't do anything crazy, so you'll still end up assigning a value to b before you use it, making the initial value irrelevant.

Additionally, it seems that adding parentheses works too:

where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b) 

That changes the point at which various pieces of overload resolution are triggered, and happens to make the compiler happy.

There is one issue still remaining - the spec's rules on definite assignment with the && operator need to be clarified to state that they only apply when the && operator is being used in its "regular" implementation with two bool operands. I'll try to make sure this is fixed for the next ECMA standard.

like image 84
Jon Skeet Avatar answered Sep 22 '22 14:09

Jon Skeet


This does appear to be a bug, or at the least a regression, in the Roslyn compiler. The following bug has been filed to track it:

https://github.com/dotnet/roslyn/issues/4509

In the meantime, Jon's excellent answer has a couple of work arounds.

like image 26
JaredPar Avatar answered Sep 21 '22 14:09

JaredPar