<div dir="ltr">Hi,<div class="gmail_extra"><br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


I'm working on project that uses Mono as its C# parser. It uses the AST that comes from calling "Resolve".<br>
<br>
I'm having trouble understanding what happens to LiftedBinaryOperator.<br>
<br>
In particular, this code seems strange:<br>
<br>
            if (left_orig is NullLiteral) {<br>
                left = right;<br>
<br>
One of the effects of this assignment is that, if a user operator is involved, the corresponding UserOperatorCall will have "right" as both of its arguments.<br>
If I replace the assignment with, say:<br>
                left = LiftedNull.Create (right.Type, left.Location);<br>
I get parse errors.<br>
It seems that at least one of the goals is to trigger a check for "left != right".<br></blockquote><div><br></div><div>This is kind of trick to simplify handling of comparisons which always end up with constant result but are allowed by the language.</div>

<div><br></div><div>For example</div><div><br></div><div><div><span style="white-space:pre-wrap">           </span>bool b = false;</div><div><span style="white-space:pre-wrap">          </span>var x = null != b;</div>
<div><br></div></div><div>If you found a case where this breaks valid C# code, please fill a bug report with C# example.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


<br>
Another mysterious thing I noticed is that, in the AST for code like:<br>
int i;<br>
int ?oi;<br>
<br>
i + oi;<br>
<br>
the AST is a LiftedBinaryOperator where "right" is an Unwrap with type int (this part I understand), while "left" is an EmptyCast with type "int?", which I find mysterious. It looks like the "EmitOperator" call casts it back to its original type:<br>


            if (left.Type.IsNullableType) {<br>
                l = NullableInfo.GetUnderlyingType (left.Type);<br>
                left = EmptyCast.Create (left, l);<br>
            }<br>
<br></blockquote><div><br></div><div style>Correct, that's just another wrap so we can use same emit operator routine.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

It would be great if you could explains how all this works.<br></blockquote><div><br></div><div style>All nullable handling is tricky especially cases involving user operators mainly because C# spec is light on details about nullable handling and does not match csc implementation quite few cases.</div>
<div style><br></div><div style>Sorry for late reply I somehow missed your email.</div><div style><br></div><div style>Marek</div></div></div></div>