private static DynamicMetaObject MakeSlotDelete(DeleteBindingInfo/*!*/ info, PythonTypeSlot/*!*/ dts) {

            // 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 deleter = Ast.Property(
                    Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonProperty)),
                    "fdel"
                );
                ParameterExpression tmpDeleter = Ast.Variable(typeof(object), "tmpDel");
                info.Body.AddVariable(tmpDeleter);

                info.Body.FinishCondition(
                    Ast.Block(
                        Ast.Assign(tmpDeleter, deleter),
                        Ast.Condition(
                            Ast.NotEqual(
                                tmpDeleter,
                                Ast.Constant(null)
                            ),
                            Ast.Dynamic(
                                new PythonInvokeBinder(
                                    BinderState.GetBinderState(info.Action),
                                    new CallSignature(1)
                                ),
                                typeof(void),
                                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                                tmpDeleter,
                                info.Args[0].Expression
                            ),
                            Ast.Throw(Ast.Call(typeof(PythonOps).GetMethod("UndeletableProperty")))
                        )
                    )
                );
                return info.Body.GetMetaObject();
            }

            info.Body.AddCondition(
                Ast.Call(
                    typeof(PythonOps).GetMethod("SlotTryDeleteValue"),
                    Ast.Constant(BinderState.GetBinderState(info.Action).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)
                    )
                ),
                Ast.Constant(null)
            );
            return null;
        }
        private static void MakeSlotAccess(GetBindingInfo/*!*/ info, PythonTypeSlot dts) {
            ReflectedSlotProperty rsp = dts as ReflectedSlotProperty;
            if (rsp != null) {
                // we need to fall back to __getattr__ if the value is not defined, so call it and check the result.
                info.Body.AddCondition(
                    Ast.NotEqual(
                        Ast.Assign(
                            info.Result,
                            Ast.ArrayAccess(
                                Ast.Call(
                                    Ast.Convert(info.Self, typeof(IObjectWithSlots)),
                                    typeof(IObjectWithSlots).GetMethod("GetSlots")
                                ),
                                Ast.Constant(rsp.Index)
                            )
                        ),
                        Ast.Field(null, typeof(Uninitialized).GetField("Instance"))
                    ),
                    info.Result
                );
                return;
            }

            PythonTypeUserDescriptorSlot slot = dts as PythonTypeUserDescriptorSlot;
            if (slot != null && !(slot.Value is PythonTypeSlot)) {
                PythonType slottype = DynamicHelpers.GetPythonType(slot.Value);
                if (slottype.IsSystemType) {
                    // this is a user slot that's known not to be a descriptor
                    // so we can just burn the value in.  For it to change the
                    // slot will need to be replaced reving the type version.
                    info.Body.FinishCondition(
                        AstUtils.Convert(AstUtils.WeakConstant(slot.Value), typeof(object))
                    );
                    return;
                }
            }

            // 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 getter = Ast.Property(
                    Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonProperty)),
                    "fget"
                );
                ParameterExpression tmpGetter = Ast.Variable(typeof(object), "tmpGet");
                info.Body.AddVariable(tmpGetter);

                info.Body.FinishCondition(
                    Ast.Block(
                        Ast.Assign(tmpGetter, getter),
                        Ast.Condition(
                            Ast.NotEqual(
                                tmpGetter,
                                Ast.Constant(null)
                            ),
                            Ast.Dynamic(
                                new PythonInvokeBinder(
                                    BinderState.GetBinderState(info.Action),
                                    new CallSignature(1)
                                ),
                                typeof(object),
                                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                                tmpGetter,
                                info.Self
                            ),
                            Ast.Throw(Ast.Call(typeof(PythonOps).GetMethod("UnreadableProperty")), typeof(object))
                        )
                    )
                );
                return;
            }

            Expression tryGet = Ast.Call(
                TypeInfo._PythonOps.SlotTryGetBoundValue,
                Ast.Constant(BinderState.GetBinderState(info.Action).Context),
                Ast.Convert(AstUtils.WeakConstant(dts), typeof(PythonTypeSlot)),
                AstUtils.Convert(info.Self, typeof(object)),
                Ast.Property(
                    Ast.Convert(
                        info.Self,
                        typeof(IPythonObject)),
                    TypeInfo._IPythonObject.PythonType
                ),
                info.Result
            );

            if (dts.GetAlwaysSucceeds) {
                info.Body.FinishCondition(
                    Ast.Block(tryGet, info.Result)
                );
            } else {
                info.Body.AddCondition(
                    tryGet,
                    info.Result
                );
            }
        }