public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) { BoundExpression receiver = (BoundExpression)this.Visit(node.Receiver); BoundExpression whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); BoundExpression whenNullOpt = (BoundExpression)this.Visit(node.WhenNullOpt); TypeSymbol type = this.VisitType(node.Type); return(node.Update(receiver, VisitMethodSymbol(node.HasValueMethodOpt), whenNotNull, whenNullOpt, node.Id, type)); }
public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) { var receiverRefKind = ReceiverSpillRefKind(node.Receiver); BoundSpillSequenceBuilder receiverBuilder = null; var receiver = VisitExpression(ref receiverBuilder, node.Receiver); BoundSpillSequenceBuilder whenNotNullBuilder = null; var whenNotNull = VisitExpression(ref whenNotNullBuilder, node.WhenNotNull); BoundSpillSequenceBuilder whenNullBuilder = null; var whenNullOpt = VisitExpression(ref whenNullBuilder, node.WhenNullOpt); if (whenNotNullBuilder == null && whenNullBuilder == null) { return(UpdateExpression(receiverBuilder, node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNullOpt, node.Id, node.Type))); } if (receiverBuilder == null) { receiverBuilder = new BoundSpillSequenceBuilder(); } if (whenNotNullBuilder == null) { whenNotNullBuilder = new BoundSpillSequenceBuilder(); } if (whenNullBuilder == null) { whenNullBuilder = new BoundSpillSequenceBuilder(); } BoundExpression condition; if (receiver.Type.IsReferenceType || receiver.Type.IsValueType || receiverRefKind == RefKind.None) { // spill to a clone receiver = Spill(receiverBuilder, receiver, RefKind.None); var hasValueOpt = node.HasValueMethodOpt; if (hasValueOpt == null) { condition = _F.ObjectNotEqual( _F.Convert(_F.SpecialType(SpecialType.System_Object), receiver), _F.Null(_F.SpecialType(SpecialType.System_Object))); } else { condition = _F.Call(receiver, hasValueOpt); } } else { Debug.Assert(node.HasValueMethodOpt == null); receiver = Spill(receiverBuilder, receiver, RefKind.Ref); var clone = _F.SynthesizedLocal(receiver.Type, _F.Syntax, refKind: RefKind.None, kind: SynthesizedLocalKind.Spill); receiverBuilder.AddLocal(clone); // (object)default(T) != null var isNotClass = _F.ObjectNotEqual( _F.Convert(_F.SpecialType(SpecialType.System_Object), _F.Default(receiver.Type)), _F.Null(_F.SpecialType(SpecialType.System_Object))); // isNotCalss || {clone = receiver; (object)clone != null} condition = _F.LogicalOr( isNotClass, _F.MakeSequence( _F.AssignmentExpression(_F.Local(clone), receiver), _F.ObjectNotEqual( _F.Convert(_F.SpecialType(SpecialType.System_Object), _F.Local(clone)), _F.Null(_F.SpecialType(SpecialType.System_Object)))) ); receiver = _F.ComplexConditionalReceiver(receiver, _F.Local(clone)); } if (node.Type.SpecialType == SpecialType.System_Void) { var whenNotNullStatement = UpdateStatement(whenNotNullBuilder, _F.ExpressionStatement(whenNotNull)); whenNotNullStatement = ConditionalReceiverReplacer.Replace(whenNotNullStatement, receiver, node.Id, RecursionDepth); Debug.Assert(whenNullOpt == null || !LocalRewriter.ReadIsSideeffecting(whenNullOpt)); receiverBuilder.AddStatement(_F.If(condition, whenNotNullStatement)); return(receiverBuilder.Update(_F.Default(node.Type))); } else { var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax); var whenNotNullStatement = UpdateStatement(whenNotNullBuilder, _F.Assignment(_F.Local(tmp), whenNotNull)); whenNotNullStatement = ConditionalReceiverReplacer.Replace(whenNotNullStatement, receiver, node.Id, RecursionDepth); whenNullOpt = whenNullOpt ?? _F.Default(node.Type); receiverBuilder.AddLocal(tmp); receiverBuilder.AddStatement( _F.If(condition, whenNotNullStatement, UpdateStatement(whenNullBuilder, _F.Assignment(_F.Local(tmp), whenNullOpt)))); return(receiverBuilder.Update(_F.Local(tmp))); } }
public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) { var origStack = StackDepth(); BoundExpression receiver = VisitCallReceiver(node.Receiver); var cookie = GetStackStateCookie(); // implicit branch here // right is evaluated with original stack // (this is not entirely true, codegen will keep receiver on the stack, but that is irrelevant here) SetStackDepth(origStack); BoundExpression whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); EnsureStackState(cookie); // implicit label here var whenNull = node.WhenNullOpt; if (whenNull != null) { SetStackDepth(origStack); // whenNull is evaluated with original stack whenNull = (BoundExpression)this.Visit(whenNull); EnsureStackState(cookie); // implicit label here } else { // compensate for the whenNull that we are not visiting. _counter += 1; } return node.Update(receiver, node.HasValueMethodOpt, whenNotNull, whenNull, node.Id, node.Type); }
public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalAccess node) { BoundExpression receiver = (BoundExpression)this.Visit(node.Receiver); BoundExpression whenNotNull = (BoundExpression)this.Visit(node.WhenNotNull); BoundExpression whenNullOpt = (BoundExpression)this.Visit(node.WhenNullOpt); TypeSymbol type = this.VisitType(node.Type); return node.Update(receiver, VisitMethodSymbol(node.HasValueMethodOpt), whenNotNull, whenNullOpt, node.Id, type); }