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 Mai
Since I got schooled so hard in the bug report, I'm going to try to explain this myself.
Imagine T
is some user-defined type with an implicit cast to bool
that alternates between false
and true
, starting with false
. As far as the compiler knows, the dynamic
first argument to the first &&
might evaluate to that type, so it has to be pessimistic.
If, then, it let the code compile, this could happen:
&&
, it does the following:
T
- implicitly cast it to bool
.false
, so we don't need to evaluate the second argument.&&
evaluate as the first argument. (No, not false
, for some reason.)&&
, it does the following:
T
- implicitly cast it to bool
.true
, so evaluate the second argument.b
isn't assigned.In spec terms, in short, there are special "definite assignment" rules that let us say not only whether a variable is "definitely assigned" or "not definitely assigned", but also if it is "definitely assigned after false
statement" or "definitely assigned after true
statement".
These exist so that when dealing with &&
and ||
(and !
and ??
and ?:
) the compiler can examine whether variables may be assigned in particular branches of a complex boolean expression.
However, these only work while the expressions' types remain boolean. When part of the expression is dynamic
(or a non-boolean static type) we can no longer reliably say that the expression is true
or false
- the next time we cast it to bool
to decide which branch to take, it may have changed its mind.
Update: this has now been resolved and documented:
The definite assignment rules implemented by previous compilers for dynamic expressions allowed some cases of code that could result in variables being read that are not definitely assigned. See https://github.com/dotnet/roslyn/issues/4509 for one report of this.
...
Because of this possibility the compiler must not allow this program to be compiled if val has no initial value. Previous versions of the compiler (prior to VS2015) allowed this program to compile even if val has no initial value. Roslyn now diagnoses this attempt to read a possibly uninitialized variable.