private static void MakeDictionarySetTarget(SetBindingInfo/*!*/ info) {
     // return UserTypeOps.SetDictionaryValue(rule.Parameters[0], name, value);
     info.Body.FinishCondition(
         Ast.Call(
             typeof(UserTypeOps).GetMethod("SetDictionaryValue"),
             Ast.Convert(info.Args[0].Expression, typeof(IPythonObject)),
             AstUtils.Constant(SymbolTable.StringToId(info.Action.Name)),
             AstUtils.Convert(info.Args[1].Expression, typeof(object))
         )
     );
 }
        private void MakeSetAttrTarget(SetBindingInfo bindingInfo, IPythonObject sdo, PythonTypeSlot dts) {
            ParameterExpression tmp = Ast.Variable(typeof(object), "boundVal");
            bindingInfo.Body.AddVariable(tmp);

            bindingInfo.Body.AddCondition(
                Ast.Call(
                    typeof(PythonOps).GetMethod("SlotTryGetValue"),
                    Ast.Constant(BinderState.GetBinderState(bindingInfo.Action).Context),
                    AstUtils.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                    AstUtils.Convert(bindingInfo.Args[0].Expression, typeof(object)),
                    AstUtils.Convert(AstUtils.WeakConstant(sdo.PythonType), typeof(PythonType)),
                    tmp
                ),
                Ast.Dynamic(
                    new PythonInvokeBinder(
                        BinderState.GetBinderState(bindingInfo.Action),
                        new CallSignature(2)
                    ),
                    typeof(object),
                    BinderState.GetCodeContext(bindingInfo.Action),
                    tmp,
                    Ast.Constant(bindingInfo.Action.Name),
                    bindingInfo.Args[1].Expression
                )
            );

            bindingInfo.Body.FinishCondition(
                FallbackSetError(bindingInfo.Action, bindingInfo.Args[1]).Expression
            );
        }
        private static DynamicMetaObject MakeSlotSet(SetBindingInfo/*!*/ info, PythonTypeSlot/*!*/ dts) {
            ParameterExpression tmp = Ast.Variable(info.Args[1].Expression.Type, "res");
            info.Body.AddVariable(tmp);

            // users can subclass PythonProperty so check the type explicitly 
            // and only in-line the ones we fully understand.
            if (dts.GetType() == typeof(PythonProperty)) {
                // properties are mutable so we generate code to get the value rather
                // than burning it into the rule.
                Expression setter = Ast.Property(
                    Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonProperty)),
                    "fset"
                );
                ParameterExpression tmpSetter = Ast.Variable(typeof(object), "tmpSet");
                info.Body.AddVariable(tmpSetter);

                info.Body.FinishCondition(
                    Ast.Block(
                        Ast.Assign(tmpSetter, setter),
                        Ast.Condition(
                            Ast.NotEqual(
                                tmpSetter,
                                Ast.Constant(null)
                            ),
                            Ast.Block(
                                Ast.Assign(tmp, info.Args[1].Expression),
                                Ast.Dynamic(
                                    new PythonInvokeBinder(
                                        BinderState.GetBinderState(info.Action),
                                        new CallSignature(1)
                                    ),
                                    typeof(void),
                                    Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                                    tmpSetter,
                                    info.Args[0].Expression,
                                    AstUtils.Convert(tmp, typeof(object))
                                ),
                                tmp
                            ),
                            Ast.Throw(Ast.Call(typeof(PythonOps).GetMethod("UnsetableProperty")), tmp.Type)
                        )
                    )
                );
                return info.Body.GetMetaObject();
            }

            CodeContext context = BinderState.GetBinderState(info.Action).Context;
            Debug.Assert(context != null);

            info.Body.AddCondition(
                Ast.Block(
                    Ast.Assign(tmp, info.Args[1].Expression),
                    Ast.Call(
                        typeof(PythonOps).GetMethod("SlotTrySetValue"),
                        Ast.Constant(context),
                        AstUtils.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                        AstUtils.Convert(info.Args[0].Expression, typeof(object)),
                        Ast.Convert(
                            Ast.Property(
                                Ast.Convert(
                                    info.Args[0].Expression,
                                    typeof(IPythonObject)),
                                TypeInfo._IPythonObject.PythonType
                            ),
                            typeof(PythonType)
                        ),
                        AstUtils.Convert(tmp, typeof(object))
                    )
                ),
                tmp
            );
            return null;
        }
        public override DynamicMetaObject/*!*/ BindSetMember(SetMemberBinder/*!*/ action, DynamicMetaObject/*!*/ value) {
            DynamicMetaObject self = Restrict(Value.GetType());
            CodeContext context = BinderState.GetBinderState(action).Context;
            IPythonObject sdo = Value;
            SetBindingInfo bindingInfo = new SetBindingInfo(
                action,
                new DynamicMetaObject[] { this, value },
                new ConditionalBuilder(action),
                BindingHelpers.GetValidationInfo(self.Expression, sdo.PythonType)
            );

            DynamicMetaObject res = null;
            // call __setattr__ if it exists
            PythonTypeSlot dts;
            if (sdo.PythonType.TryResolveSlot(context, Symbols.SetAttr, out dts) && !IsStandardObjectMethod(dts)) {
                // skip the fake __setattr__ on mixed new-style/old-style types
                if (dts != null) {
                    MakeSetAttrTarget(bindingInfo, sdo, dts);
                    res = bindingInfo.Body.GetMetaObject(this, value);
                }
            }

            if (res == null) {
                // then see if we have a set descriptor
                bool isOldStyle;
                bool systemTypeResolution;
                dts = FindSlot(context, action.Name, sdo, out isOldStyle, out systemTypeResolution);
                
                ReflectedSlotProperty rsp = dts as ReflectedSlotProperty;
                if (rsp != null) {
                    MakeSlotsSetTarget(bindingInfo, rsp, value.Expression);
                    res = bindingInfo.Body.GetMetaObject(this, value);
                } else if (dts != null && dts.IsSetDescriptor(context, sdo.PythonType)) {
                    if (systemTypeResolution) {
                        res = Fallback(action, value);
                    } else {
                        res = MakeSlotSet(bindingInfo, dts);
                    }
                }
            }

            if (res == null) {
                // finally if we have a dictionary set the value there.
                if (sdo.HasDictionary) {
                    MakeDictionarySetTarget(bindingInfo);
                } else {
                    bindingInfo.Body.FinishCondition(
                        FallbackSetError(action, value).Expression
                    );
                }

                res = bindingInfo.Body.GetMetaObject(this, value);
            }

            res = new DynamicMetaObject(
                res.Expression,
                self.Restrictions.Merge(res.Restrictions)
            );

            return BindingHelpers.AddDynamicTestAndDefer(
                action,
                res,
                new DynamicMetaObject[] { this, value },
                bindingInfo.Validation
            );
        }