internal static void TransformDynamicSetMemberInstruction(DynamicSetMemberInstruction inst, StatementTransformContext context) { if (!inst.BinderFlags.HasFlag(CSharpBinderFlags.ValueFromCompoundAssignment)) { return; } if (!(inst.Value is DynamicBinaryOperatorInstruction binaryOp)) { return; } if (!(binaryOp.Left is DynamicGetMemberInstruction dynamicGetMember)) { return; } if (!dynamicGetMember.Target.Match(inst.Target).Success) { return; } if (!SemanticHelper.IsPure(dynamicGetMember.Target.Flags)) { return; } if (inst.Name != dynamicGetMember.Name || !DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation)) { return; } context.Step("dynamic.setmember.compound -> dynamic.compound.op", inst); inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.BinderFlags, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo)); }
/// <summary> /// if (logic.not(ldloc V_1)) Block IL_0149 { /// dynamic.setmember.compound B(target, dynamic.binary.operator AddAssign(ldloc V_2, value)) /// } else Block IL_0151 { /// dynamic.invokemember.invokespecial.discard add_B(target, value) /// } /// </summary> static bool MatchIsEventAssignmentIfInstruction(ILInstruction ifInst, DynamicIsEventInstruction isEvent, ILVariable flagVar, ILVariable getMemberVar, out DynamicSetMemberInstruction setMemberInst, out ILInstruction getMemberVarUse, out ILInstruction isEventConditionUse) { setMemberInst = null; getMemberVarUse = null; isEventConditionUse = null; if (!ifInst.MatchIfInstruction(out var condition, out var trueInst, out var falseInst)) { return(false); } if (MatchFlagEqualsZero(condition, flagVar)) { if (!condition.MatchCompEquals(out var left, out _)) { return(false); } isEventConditionUse = left; } else if (condition.MatchLdLoc(flagVar)) { var tmp = trueInst; trueInst = falseInst; falseInst = tmp; isEventConditionUse = condition; } else { return(false); } setMemberInst = Block.Unwrap(trueInst) as DynamicSetMemberInstruction; if (!(setMemberInst != null)) { return(false); } if (!isEvent.Argument.Match(setMemberInst.Target).Success) { return(false); } if (!(Block.Unwrap(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2)) { return(false); } if (!isEvent.Argument.Match(invokeMemberInst.Arguments[0]).Success) { return(false); } if (!(setMemberInst.Value is DynamicBinaryOperatorInstruction binOp && binOp.Left.MatchLdLoc(getMemberVar))) { return(false); } getMemberVarUse = binOp.Left; return(true); }
/// <summary> /// dynamic.setmember.compound Name(target, dynamic.binary.operator op(dynamic.getmember Name(target), value)) /// => /// dynamic.compound.op (dynamic.getmember Name(target), value) /// </summary> protected internal override void VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst) { base.VisitDynamicSetMemberInstruction(inst); TransformDynamicSetMemberInstruction(inst, context); }