public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { // TestExpression ?? ElseExpression if (node.ConstantValue == null && !node.HasErrors) { var testExpression = node.TestExpression; ConstantValue testExpressionConstantValue = testExpression.ConstantValue; if (testExpressionConstantValue != null) { // testExpression is a known compile time constant if (testExpressionConstantValue == ConstantValue.Null) { // testExpression is always null return(Visit(node.ElseExpression)); } // testExpression is always non null constant return(Visit(node.LeftConversion ?? node.TestExpression)); } else { TypeSymbol exprType = node.Type; BoundExpression elseExpression = node.ElseExpression; BoundExpression leftConversion = node.LeftConversion; //it's a BoundConversion, but we're passing by ref // There are two ways that a conversion of the test expression can be represented: // 1) If it was cast in source, then node.TestExpression could be a BoundConversion, or // 2) If the compiler generated a conversion to reconcile the types, then node.LeftConversion could be non-null. if (leftConversion == null) { if (IsUpdateRequiredForExplicitConversion(exprType, ref testExpression, ref elseExpression)) { return(node.Update( testExpression, elseExpression, leftConversion: null, constantValueOpt: null, type: exprType)); } } else if (IsUpdateRequiredForExplicitConversion(exprType, ref leftConversion, ref elseExpression)) { return(node.Update( (BoundExpression)Visit(testExpression), elseExpression, (BoundConversion)leftConversion, constantValueOpt: null, type: exprType)); } } } return(base.VisitNullCoalescingOperator(node)); }
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { BoundSpillSequenceBuilder builder = null; var right = VisitExpression(ref builder, node.RightOperand); BoundExpression left; if (builder == null) { left = VisitExpression(ref builder, node.LeftOperand); } else { var leftBuilder = new BoundSpillSequenceBuilder(); left = VisitExpression(ref leftBuilder, node.LeftOperand); left = Spill(leftBuilder, left); var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax); leftBuilder.AddLocal(tmp); leftBuilder.AddStatement(_F.Assignment(_F.Local(tmp), left)); leftBuilder.AddStatement(_F.If( _F.ObjectEqual(_F.Local(tmp), _F.Null(left.Type)), UpdateStatement(builder, _F.Assignment(_F.Local(tmp), right)))); return(UpdateExpression(leftBuilder, _F.Local(tmp))); } return(UpdateExpression(builder, node.Update(left, right, node.LeftConversion, node.OperatorResultKind, node.Type))); }
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { BoundSpillSequenceBuilder builder = null; var right = VisitExpression(ref builder, node.RightOperand); BoundExpression left; if (builder == null) { left = VisitExpression(ref builder, node.LeftOperand); } else { var leftBuilder = new BoundSpillSequenceBuilder(); left = VisitExpression(ref leftBuilder, node.LeftOperand); left = Spill(leftBuilder, left); leftBuilder.AddStatement(_F.If( _F.ObjectEqual(left, _F.Null(left.Type)), UpdateStatement(builder, _F.Assignment(left, right), substituteTemps: false))); return(UpdateExpression(leftBuilder, left)); } return(UpdateExpression(builder, node.Update(left, right, node.LeftConversion, node.Type))); }
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { BoundSpillSequence2 ss = null; var right = VisitExpression(ref ss, node.RightOperand); BoundExpression left; if (ss == null) { left = VisitExpression(ref ss, node.LeftOperand); } else { var ssLeft = new BoundSpillSequence2(); left = VisitExpression(ref ssLeft, node.LeftOperand); left = Spill(ssLeft, left); ssLeft.Add(F.If( F.ObjectEqual(left, F.Null(left.Type)), UpdateStatement(ss, F.Assignment(left, right)) )); return(UpdateExpression(ssLeft, left)); } return(UpdateExpression(ss, node.Update(left, right, node.LeftConversion, node.Type))); }
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { var origStack = StackDepth(); BoundExpression left = (BoundExpression)this.Visit(node.LeftOperand); var cookie = GetStackStateCookie(); // implicit branch here // right is evaluated with original stack // (this is not entirely true, codegen may keep left on the stack as an ephemeral temp, but that is irrelevant here) SetStackDepth(origStack); BoundExpression right = (BoundExpression)this.Visit(node.RightOperand); EnsureStackState(cookie); // implicit label here return node.Update(left, right, node.LeftConversion, node.Type); }
public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node) { // TestExpression ?? ElseExpression if (node.ConstantValue == null && !node.HasErrors) { var testExpression = node.TestExpression; ConstantValue testExpressionConstantValue = testExpression.ConstantValue; if (testExpressionConstantValue != null) { // testExpression is a known compile time constant if (testExpressionConstantValue == ConstantValue.Null) { // testExpression is always null return Visit(node.ElseExpression); } // testExpression is always non null constant return Visit(node.LeftConversion ?? node.TestExpression); } else { TypeSymbol exprType = node.Type; BoundExpression elseExpression = node.ElseExpression; BoundExpression leftConversion = node.LeftConversion; //it's a BoundConversion, but we're passing by ref // There are two ways that a conversion of the test expression can be represented: // 1) If it was cast in source, then node.TestExpression could be a BoundConversion, or // 2) If the compiler generated a conversion to reconcile the types, then node.LeftConversion could be non-null. if (leftConversion == null) { if (IsUpdateRequiredForExplicitConversion(exprType, ref testExpression, ref elseExpression)) { return node.Update( testExpression, elseExpression, leftConversion: null, constantValueOpt: null, type: exprType); } } else if (IsUpdateRequiredForExplicitConversion(exprType, ref leftConversion, ref elseExpression)) { return node.Update( (BoundExpression)Visit(testExpression), elseExpression, (BoundConversion)leftConversion, constantValueOpt: null, type: exprType); } } } return base.VisitNullCoalescingOperator(node); }