///////////////////////////////////////////////////////////////////////////////// private static Expression ConvertResult(Expression binding, ICSharpBinder action) { // Need to handle the following cases: // (1) Call to a constructor: no conversions. // (2) Call to a void-returning method: return null iff result is discarded. // (3) Call to a value-type returning method: box to object. // // In all other cases, binding.Type should be equivalent or // reference assignable to resultType. // No conversions needed for , the call site has the correct type. if (action is CSharpInvokeConstructorBinder) { return(binding); } if (binding.Type == typeof(void)) { if (action is ICSharpInvokeOrInvokeMemberBinder invoke && invoke.ResultDiscarded) { Debug.Assert(action.ReturnType == typeof(object)); return(Expression.Block(binding, Expression.Default(action.ReturnType))); } throw Error.BindToVoidMethodButExpectResult(); } if (binding.Type.IsValueType && !action.ReturnType.IsValueType) { Debug.Assert(action.ReturnType == typeof(object)); return(Expression.Convert(binding, action.ReturnType)); } return(binding); }
///////////////////////////////////////////////////////////////////////////////// private static Type GetTypeForErrorMetaObject(ICSharpBinder action, DynamicMetaObject[] args) { // This is similar to ConvertResult but has fewer things to worry about. if (action is CSharpInvokeConstructorBinder) { Debug.Assert(args != null); Debug.Assert(args.Length != 0); Debug.Assert(args[0].Value is Type); return(args[0].Value as Type); } return(action.ReturnType); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpIsEventBinder; if (otherBinder == null) { return(false); } if (_callingContext != otherBinder._callingContext || Name != otherBinder.Name) { return(false); } return(true); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpGetIndexBinder; if (otherBinder == null) { return(false); } if (_callingContext != otherBinder._callingContext || _argumentInfo.Length != otherBinder._argumentInfo.Length) { return(false); } return(BinderHelper.CompareArgInfos(_argumentInfo, otherBinder._argumentInfo)); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpUnaryOperationBinder; if (otherBinder == null) { return(false); } if (Operation != otherBinder.Operation || IsChecked != otherBinder.IsChecked || _callingContext != otherBinder._callingContext) { return(false); } return(BinderHelper.CompareArgInfos(_argumentInfo, otherBinder._argumentInfo)); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpConvertBinder; if (otherBinder == null) { return(false); } if (ConversionKind != otherBinder.ConversionKind || IsChecked != otherBinder.IsChecked || _callingContext != otherBinder._callingContext || Type != otherBinder.Type) { return(false); } return(true); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpInvokeMemberBinder; if (otherBinder == null) { return(false); } if (Flags != otherBinder.Flags || CallingContext != otherBinder.CallingContext || Name != otherBinder.Name || TypeArguments.Length != otherBinder.TypeArguments.Length || _argumentInfo.Length != otherBinder._argumentInfo.Length) { return(false); } return(BinderHelper.CompareArgInfos(TypeArguments, otherBinder.TypeArguments, _argumentInfo, otherBinder._argumentInfo)); }
public bool IsEquivalentTo(ICSharpBinder other) { var otherBinder = other as CSharpSetMemberBinder; if (otherBinder == null) { return(false); } if (Name != otherBinder.Name || _callingContext != otherBinder._callingContext || IsChecked != otherBinder.IsChecked || IsCompoundAssignment != otherBinder.IsCompoundAssignment || _argumentInfo.Length != otherBinder._argumentInfo.Length) { return(false); } return(BinderHelper.CompareArgInfos(_argumentInfo, otherBinder._argumentInfo)); }
///////////////////////////////////////////////////////////////////////////////// private static bool IsIncrementOrDecrementActionOnLocal(ICSharpBinder action) => action is CSharpUnaryOperationBinder operatorPayload &&
internal static DynamicMetaObject Bind( ICSharpBinder action, RuntimeBinder binder, DynamicMetaObject[] args, IEnumerable <CSharpArgumentInfo> arginfos, DynamicMetaObject onBindingError) { Expression[] parameters = new Expression[args.Length]; BindingRestrictions restrictions = BindingRestrictions.Empty; ICSharpInvokeOrInvokeMemberBinder callPayload = action as ICSharpInvokeOrInvokeMemberBinder; ParameterExpression tempForIncrement = null; IEnumerator <CSharpArgumentInfo> arginfosEnum = (arginfos ?? Array.Empty <CSharpArgumentInfo>()).GetEnumerator(); for (int index = 0; index < args.Length; ++index) { DynamicMetaObject o = args[index]; // Our contract with the DLR is such that we will not enter a bind unless we have // values for the meta-objects involved. Debug.Assert(o.HasValue); CSharpArgumentInfo info = arginfosEnum.MoveNext() ? arginfosEnum.Current : null; if (index == 0 && IsIncrementOrDecrementActionOnLocal(action)) { // We have an inc or a dec operation. Insert the temp local instead. // // We need to do this because for value types, the object will come // in boxed, and we'd need to unbox it to get the original type in order // to increment. The only way to do that is to create a new temporary. object value = o.Value; tempForIncrement = Expression.Variable(value != null ? value.GetType() : typeof(object), "t0"); parameters[0] = tempForIncrement; } else { parameters[index] = o.Expression; } BindingRestrictions r = DeduceArgumentRestriction(index, callPayload, o, info); restrictions = restrictions.Merge(r); // Here we check the argument info. If the argument info shows that the current argument // is a literal constant, then we also add an instance restriction on the value of // the constant. if (info != null && info.LiteralConstant) { if (o.Value is double && double.IsNaN((double)o.Value)) { MethodInfo isNaN = s_DoubleIsNaN ?? (s_DoubleIsNaN = typeof(double).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else if (o.Value is float && float.IsNaN((float)o.Value)) { MethodInfo isNaN = s_SingleIsNaN ?? (s_SingleIsNaN = typeof(float).GetMethod("IsNaN")); Expression e = Expression.Call(null, isNaN, o.Expression); restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(e)); } else { Expression e = Expression.Equal(o.Expression, Expression.Constant(o.Value, o.Expression.Type)); r = BindingRestrictions.GetExpressionRestriction(e); restrictions = restrictions.Merge(r); } } } // Get the bound expression. try { Expression expression = binder.Bind(action, parameters, args, out DynamicMetaObject deferredBinding); if (deferredBinding != null) { expression = ConvertResult(deferredBinding.Expression, action); restrictions = deferredBinding.Restrictions.Merge(restrictions); return(new DynamicMetaObject(expression, restrictions)); } if (tempForIncrement != null) { // If we have a ++ or -- payload, we need to do some temp rewriting. // We rewrite to the following: // // temp = (type)o; // temp++; // o = temp; // return o; DynamicMetaObject arg0 = args[0]; expression = Expression.Block( new[] { tempForIncrement }, Expression.Assign(tempForIncrement, Expression.Convert(arg0.Expression, arg0.Value.GetType())), expression, Expression.Assign(arg0.Expression, Expression.Convert(tempForIncrement, arg0.Expression.Type))); } expression = ConvertResult(expression, action); return(new DynamicMetaObject(expression, restrictions)); } catch (RuntimeBinderException e) { if (onBindingError != null) { return(onBindingError); } return(new DynamicMetaObject( Expression.Throw( Expression.New( typeof(RuntimeBinderException).GetConstructor(new Type[] { typeof(string) }), Expression.Constant(e.Message) ), GetTypeForErrorMetaObject(action, args) ), restrictions )); } }