/// <summary> /// Helper to produce an error when a conversion cannot occur /// </summary> private DynamicMetaObject MakeErrorTarget(Type toType, ConversionResultKind kind, BindingRestrictions restrictions, DynamicMetaObject arg) { DynamicMetaObject target; switch (kind) { case ConversionResultKind.ImplicitCast: case ConversionResultKind.ExplicitCast: target = MakeError( MakeConversionError(toType, arg.Expression), restrictions, toType ); break; case ConversionResultKind.ImplicitTry: case ConversionResultKind.ExplicitTry: target = new DynamicMetaObject( GetTryConvertReturnValue(toType), restrictions ); break; default: throw new InvalidOperationException(kind.ToString()); } return(target); }
// TODO: revisit /// <summary> /// Converts the provided expression to the given type. The expression is safe to evaluate multiple times. /// </summary> public virtual Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { ContractUtils.RequiresNotNull(expr, "expr"); ContractUtils.RequiresNotNull(toType, "toType"); Type exprType = expr.Type; if (toType == typeof(object)) { if (exprType.IsValueType()) { return(AstUtils.Convert(expr, toType)); } else { return(expr); } } if (toType.IsAssignableFrom(exprType)) { return(expr); } return(Expression.Convert(expr, CompilerHelpers.GetVisibleType(toType))); }
/// <summary>Helper to produce the rule for converting T to Nullable of T</summary> private static MSAst MakeConvertingToTToNullableOfTTarget(Type toType, ConversionResultKind kind, MSAst arg) { var valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (kind == ConversionResultKind.ExplicitCast) { // if the conversion to T fails we just throw var conversion = ConvertExpression(arg, valueType); return(MSAst.New( toType.GetConstructor(new[] { valueType }), conversion)); } else { var conversion = ConvertExpression(arg, valueType); // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) return(MSAst.Condition( MSAst.NotEqual( conversion, AstUtils.Constant(null)), MSAst.New( toType.GetConstructor(new[] { valueType }), MSAst.Convert( conversion, valueType)), GetTryConvertReturnValue(toType))); } }
public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg, OverloadResolverFactory resolverFactory, DynamicMetaObject errorSuggestion) { ContractUtils.RequiresNotNull(toType, "toType"); ContractUtils.RequiresNotNull(arg, "arg"); Type knownType = arg.GetLimitType(); // try all the conversions - first look for conversions against the expression type, // these can be done w/o any additional tests. Then look for conversions against the // restricted type. BindingRestrictions typeRestrictions = arg.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType())); DynamicMetaObject res = TryConvertToObject(toType, arg.Expression.Type, arg, typeRestrictions) ?? TryAllConversions(resolverFactory, toType, kind, arg.Expression.Type, typeRestrictions, arg) ?? TryAllConversions(resolverFactory, toType, kind, arg.GetLimitType(), typeRestrictions, arg) ?? errorSuggestion ?? MakeErrorTarget(toType, kind, typeRestrictions, arg); if ((kind == ConversionResultKind.ExplicitTry || kind == ConversionResultKind.ImplicitTry) && toType.IsValueType) { res = new DynamicMetaObject( AstUtils.Convert( res.Expression, typeof(object) ), res.Restrictions ); } return res; }
/// <summary>Helper to produce a conversion rule by calling the helper method to do the convert</summary> private static MSAst MakeConversionTarget( ConversionResultKind kind, MethodTracker method, Type fromType, bool isImplicit, MSAst arg) { var param = AstUtils.Convert(arg, fromType); return(MakeConversionTargetWorker(kind, method, isImplicit, param)); }
/// <summary>Helper to produce an error when a conversion cannot occur</summary> private static MSAst MakeErrorTarget(Type toType, ConversionResultKind kind, MSAst arg) { MSAst target; switch (kind) { case ConversionResultKind.ImplicitCast: case ConversionResultKind.ExplicitCast: //target = DefaultBinder.MakeError( // _binder.Binder.MakeConversionError(toType, arg), // toType); target = arg; break; case ConversionResultKind.ImplicitTry: case ConversionResultKind.ExplicitTry: target = GetTryConvertReturnValue(toType); break; default: throw new InvalidOperationException(kind.ToString()); } return(target); }
private static Expression /*!*/ AddExtensibleSelfCheck(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, Expression /*!*/ callExpr) { ParameterExpression tmp = Ast.Variable(callExpr.Type, "tmp"); ConversionResultKind resKind = GetResultKind(convertToAction); Type retType = (resKind == ConversionResultKind.ExplicitTry || resKind == ConversionResultKind.ImplicitTry) ? typeof(object) : toType; callExpr = Ast.Block( new ParameterExpression[] { tmp }, Ast.Block( Ast.Assign(tmp, callExpr), Ast.Condition( Ast.Equal(tmp, self.Expression), AstUtils.Convert( Ast.Property( AstUtils.Convert(self.Expression, self.GetLimitType()), self.GetLimitType().GetProperty("Value") ), retType ), Ast.Dynamic( new PythonConversionBinder( PythonContext.GetPythonContext(convertToAction), toType, GetResultKind(convertToAction) ), retType, tmp ) ) ) ); return(callExpr); }
public override Expression/*!*/ ConvertExpression(Expression/*!*/ expr, Type/*!*/ toType, ConversionResultKind kind, Expression context) { ContractUtils.RequiresNotNull(expr, "expr"); ContractUtils.RequiresNotNull(toType, "toType"); Type exprType = expr.Type; if (toType == typeof(object)) { if (exprType.IsValueType) { return AstUtils.Convert(expr, toType); } else { return expr; } } if (toType.IsAssignableFrom(exprType)) { return expr; } Type visType = CompilerHelpers.GetVisibleType(toType); if (exprType == typeof(PythonType) && visType == typeof(Type)) { return AstUtils.Convert(expr, visType); // use the implicit conversion } return Binders.Convert( context, _context.DefaultBinderState, visType, visType == typeof(char) ? ConversionResultKind.ImplicitCast : kind, expr ); }
public ConversionBinder(BinderState/*!*/ state, Type/*!*/ type, ConversionResultKind resultKind) : base(type, resultKind == ConversionResultKind.ExplicitCast || resultKind == ConversionResultKind.ExplicitTry) { Assert.NotNull(state, type); _state = state; _kind = resultKind; }
internal SxeConvertBinder Convert(Type type, ConversionResultKind resultKind, OverloadResolverFactory resolverFactory) { if (_conversionBinders == null) { Interlocked.CompareExchange( ref _conversionBinders, new Dictionary <Type, SxeConvertBinder> [(int)ConversionResultKind.ExplicitTry + 1], // max conversion result kind null ); } if (_conversionBinders[(int)resultKind] == null) { Interlocked.CompareExchange( ref _conversionBinders[(int)resultKind], new Dictionary <Type, SxeConvertBinder>(), null ); } var binders = _conversionBinders[(int)resultKind]; lock (binders) { SxeConvertBinder result; if (!binders.TryGetValue(type, out result)) { binders[type] = result = new SxeConvertBinder(this, type, resultKind, resolverFactory); } return(result); } }
internal DynamicMetaObjectBinder ConvertAndReturnObject(Type type, ConversionResultKind resultKind) { if (_convertRetObjectBinders == null) { Interlocked.CompareExchange( ref _convertRetObjectBinders, new Dictionary <Type, DynamicMetaObjectBinder> [(int)ConversionResultKind.ExplicitTry + 1], // max conversion result kind null); } if (_convertRetObjectBinders[(int)resultKind] == null) { Interlocked.CompareExchange( ref _convertRetObjectBinders[(int)resultKind], new Dictionary <Type, DynamicMetaObjectBinder>(), null); } var binder = _convertRetObjectBinders[(int)resultKind]; lock (binder) { DynamicMetaObjectBinder result; if (!binder.TryGetValue(type, out result)) { binder[type] = result = new SxeConvertBinder(this, type, resultKind, _binder.Context.OverloadResolver); } return(result); } }
public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { Type exprType = expr.Type; Type visType = CompilerHelpers.GetVisibleType(toType); if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType)) return Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType)); // Follow through on our promise to convert IEnumerable<Object> or IEnumerable to IEnumerable<T> for any T if (toType.IsGenericType && ! toType.IsAssignableFrom(expr.Type)) { // The following is inspired by IronPython.Runtime.Binding.Python.ConversionBinder.FallbackConvert Type genTo = toType.GetGenericTypeDefinition(); if ( genTo == typeof(IList<>)) { return MakeToGenericConversion(expr,toType,typeof(IList<object>),typeof(ListGenericWrapper<>)); } else if (genTo == typeof(IDictionary<,>)) { return MakeToGenericConversion(expr,toType,typeof(IDictionary<object,object>),typeof(DictionaryGenericWrapper<,>)); } else if (genTo == typeof(IEnumerable<>)) { return MakeToGenericConversion(expr, toType, typeof(IEnumerable),typeof(IEnumerableOfTWrapper<>)); } } return base.ConvertExpression(expr, toType, kind, resolverFactory); }
public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg, OverloadResolverFactory resolverFactory, DynamicMetaObject errorSuggestion) { ContractUtils.RequiresNotNull(toType, nameof(toType)); ContractUtils.RequiresNotNull(arg, nameof(arg)); // try all the conversions - first look for conversions against the expression type, // these can be done w/o any additional tests. Then look for conversions against the // restricted type. BindingRestrictions typeRestrictions = arg.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType())); DynamicMetaObject res = TryConvertToObject(toType, arg.Expression.Type, arg, typeRestrictions) ?? TryAllConversions(resolverFactory, toType, kind, arg.Expression.Type, typeRestrictions, arg) ?? TryAllConversions(resolverFactory, toType, kind, arg.GetLimitType(), typeRestrictions, arg) ?? errorSuggestion ?? MakeErrorTarget(toType, kind, typeRestrictions, arg); if ((kind == ConversionResultKind.ExplicitTry || kind == ConversionResultKind.ImplicitTry) && toType.IsValueType) { res = new DynamicMetaObject( AstUtils.Convert( res.Expression, typeof(object) ), res.Restrictions ); } return(res); }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) { if (toType.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, toType, Restrict(typeof(Method))); } return FallbackConvert(binder); }
public override Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { ContractUtils.RequiresNotNull(expr, "expr"); ContractUtils.RequiresNotNull(toType, "toType"); Type exprType = expr.Type; if (toType == typeof(object)) { if (exprType.IsValueType()) return Utils.Convert(expr, toType); else return expr; } if (toType.IsAssignableFrom(exprType)) return expr; Type visType = Context.Binder.PrivateBinding ? toType : CompilerHelpers.GetVisibleType(toType); return Binders.Convert( _context, visType, kind, expr ); }
public static MSAst Convert(BinderState binder, Type type, ConversionResultKind resultKind, MSAst target, OverloadResolverFactory resolverFactory) { return(MSAst.Dynamic( binder.Convert(type, resultKind, resolverFactory), type, target)); }
/// <summary>Checks if there's a conversion to/from Nullable of T.</summary> private static MSAst TryNullableConversion(Type toType, ConversionResultKind kind, Type knownType, MSAst arg) { if (toType.IsGenericType && (toType.GetGenericTypeDefinition() == typeof(Nullable <>))) { if (knownType == typeof(DynamicNull)) { return(MakeNullToNullableOfTTarget(toType)); } if (knownType == toType.GetGenericArguments()[0]) { return(MakeTToNullableOfTTarget(toType, knownType, arg)); } if ((kind == ConversionResultKind.ExplicitCast) || (kind == ConversionResultKind.ExplicitTry)) { if (knownType != typeof(object)) { // when doing an explicit cast we'll do things like int -> Nullable<float> return(MakeConvertingToTToNullableOfTTarget(toType, kind, arg)); } } } return(null); }
public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { Type exprType = expr.Type; Type visType = CompilerHelpers.GetVisibleType(toType); if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType)) { return(Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType))); } // Follow through on our promise to convert IEnumerable<Object> or IEnumerable to IEnumerable<T> for any T if (toType.IsGenericType && !toType.IsAssignableFrom(expr.Type)) { // The following is inspired by IronPython.Runtime.Binding.Python.ConversionBinder.FallbackConvert Type genTo = toType.GetGenericTypeDefinition(); if (genTo == typeof(IList <>)) { return(MakeToGenericConversion(expr, toType, typeof(IList <object>), typeof(ListGenericWrapper <>))); } else if (genTo == typeof(IDictionary <,>)) { return(MakeToGenericConversion(expr, toType, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>))); } else if (genTo == typeof(IEnumerable <>)) { return(MakeToGenericConversion(expr, toType, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>))); } } return(base.ConvertExpression(expr, toType, kind, resolverFactory)); }
/// <summary> /// Backwards compatible Convert for the old sites that need to flow CodeContext /// </summary> public static Expression/*!*/ Convert(Expression/*!*/ codeContext, PythonContext/*!*/ binder, Type/*!*/ type, ConversionResultKind resultKind, Expression/*!*/ target) { return Ast.Dynamic( binder.Convert(type, resultKind), type, target ); }
/// <summary> /// Checks if there's a conversion to/from Nullable of T. /// </summary> private MetaObject TryNullableConversion(Type toType, ConversionResultKind kind, Type knownType, Restrictions restrictions, MetaObject arg) { if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>)) { if (knownType == typeof(Null)) { // null -> Nullable<T> return(MakeNullToNullableOfTTarget(toType, restrictions)); } else if (knownType == toType.GetGenericArguments()[0]) { return(MakeTToNullableOfTTarget(toType, knownType, restrictions, arg)); } else if (kind == ConversionResultKind.ExplicitCast || kind == ConversionResultKind.ExplicitTry) { if (knownType != typeof(object)) { // when doing an explicit cast we'll do things like int -> Nullable<float> return(MakeConvertingToTToNullableOfTTarget(toType, kind, restrictions, arg)); } } } return(null); }
public static DynamicExpression ConvertTo(ActionBinder binder, Type toType, ConversionResultKind kind, Type actionExpressionType, params Expression[] arguments) { ContractUtils.RequiresNotNull(toType, "toType"); ContractUtils.RequiresNotNull(arguments, "arguments"); ContractUtils.Requires(arguments.Length > 0, "arguments"); return(Expression.Dynamic(OldConvertToAction.Make(binder, toType, kind), actionExpressionType, arguments)); }
public static Expression Convert(TotemContext state, Type type, ConversionResultKind kind, Expression target) { return DynamicExpression.Dynamic( state.Convert(type, kind), type, target ); }
public PythonConversionBinder(PythonContext /*!*/ context, Type /*!*/ type, ConversionResultKind resultKind) { Assert.NotNull(context, type); _context = context; _kind = resultKind; _type = type; }
public override Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, Expression context) { if (toType.IsAssignableFrom(expr.Type)) { return(expr); } return(Expression.Convert(expr, toType)); }
public override Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, OverloadResolverFactory factory) { if (toType.IsAssignableFrom(expr.Type)) { return(expr); } return(Ast.Utils.Convert(expr, toType)); }
/// <summary> /// Checks if any conversions are available and if so builds the target for that conversion. /// </summary> private DynamicMetaObject TryAllConversions(Type toType, ConversionResultKind kind, Type knownType, BindingRestrictions restrictions, DynamicMetaObject arg) { return TryAssignableConversion(toType, knownType, restrictions, arg) ?? // known type -> known type TryExtensibleConversion(toType, knownType, restrictions, arg) ?? // Extensible<T> -> Extensible<T>.Value TryUserDefinedConversion(kind, toType, knownType, restrictions, arg) ?? // op_Implicit TryImplicitNumericConversion(toType, knownType, restrictions, arg) ?? // op_Implicit TryNullableConversion(toType, kind, knownType, restrictions, arg) ?? // null -> Nullable<T> or T -> Nullable<T> TryNullConversion(toType, knownType, restrictions); // null -> reference type }
private static CallSite <Func <CallSite, object, T> > MakeConvertSite <T>(ConversionResultKind kind) { return(CallSite <Func <CallSite, object, T> > .Create( DefaultContext.DefaultPythonContext.Convert( typeof(T), kind ) )); }
public TotemConversionBinder(TotemContext/*!*/ context, Type/*!*/ type, ConversionResultKind resultKind, bool retObj) : base(retObj ? typeof(object) : type, resultKind == ConversionResultKind.ExplicitCast || resultKind == ConversionResultKind.ExplicitTry) { Assert.NotNull(context); _context = context; _kind = resultKind; _retObject = retObj; _type = type; }
/// <summary> /// Checks if any conversions are available and if so builds the target for that conversion. /// </summary> private MetaObject TryAllConversions(Type toType, ConversionResultKind kind, Type knownType, Restrictions restrictions, MetaObject arg) { return (TryAssignableConversion(toType, knownType, restrictions, arg) ?? // known type -> known type TryExtensibleConversion(toType, knownType, restrictions, arg) ?? // Extensible<T> -> Extensible<T>.Value TryUserDefinedConversion(kind, toType, knownType, restrictions, arg) ?? // op_Implicit TryImplicitNumericConversion(toType, knownType, restrictions, arg) ?? // op_Implicit TryNullableConversion(toType, kind, knownType, restrictions, arg) ?? // null -> Nullable<T> or T -> Nullable<T> TryNullConversion(toType, knownType, restrictions)); // null -> reference type }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "BuiltinFunc Convert " + toType); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "BuiltinFunc Convert"); if (toType.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, toType, Restrict(LimitType)); } return FallbackConvert(binder); }
public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { Type exprType = expr.Type; Type visType = CompilerHelpers.GetVisibleType(toType); if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType)) return Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType)); return base.ConvertExpression(expr, toType, kind, resolverFactory); }
/// <summary> /// Backwards compatible Convert for the old sites that need to flow CodeContext /// </summary> public static Expression/*!*/ Convert(Expression/*!*/ codeContext, BinderState/*!*/ binder, Type/*!*/ type, ConversionResultKind resultKind, Expression/*!*/ target) { return Ast.Dynamic( new ConversionBinder( binder, type, resultKind ), type, target ); }
/// <summary> /// Helper to produce a conversion rule by calling the method to do the convert. This version takes the parameter /// to be passed to the conversion function and we call it w/ our own value or w/ our Extensible.Value. /// </summary> private static MSAst MakeConversionTargetWorker( ConversionResultKind kind, MethodTracker method, bool isImplicit, MSAst param) { return(WrapForThrowingTry( kind, isImplicit, AstUtils.SimpleCallHelper( method.Method, param ), method.Method.ReturnType)); }
public override Ast ConvertExpression(Ast expr, Type toType, ConversionResultKind kind, OverloadResolverFactory resolverFactory) { Type exprType = expr.Type; Type visType = CompilerHelpers.GetVisibleType(toType); if (typeof(IFn).IsAssignableFrom(exprType) && typeof(Delegate).IsAssignableFrom(visType)) { return(Ast.Call(typeof(Converter).GetMethod("ConvertToDelegate"), Ast.Convert(expr, typeof(IFn)), Expression.Constant(visType))); } return(base.ConvertExpression(expr, toType, kind, resolverFactory)); }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type type, Type retType, ConversionResultKind kind) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Conversion " + type.FullName); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Conversion"); ValidationInfo typeTest = BindingHelpers.GetValidationInfo(this, Value.PythonType); return BindingHelpers.AddDynamicTestAndDefer( binder, TryPythonConversion(binder, type) ?? FallbackConvert(binder), new DynamicMetaObject[] { this }, typeTest, retType ); }
/// <summary> /// Helper that checkes both types to see if either one defines the specified conversion /// method. /// </summary> private DynamicMetaObject TryOneConversion(ConversionResultKind kind, Type toType, Type type, Type fromType, string methodName, bool isImplicit, BindingRestrictions restrictions, DynamicMetaObject arg) { MemberGroup conversions = GetMember(MemberRequestKind.Convert, fromType, methodName); DynamicMetaObject res = TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg); if (res != null) { return(res); } // then on the type we're trying to convert to conversions = GetMember(MemberRequestKind.Convert, toType, methodName); return(TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg)); }
/// <summary> /// Helper to produce a conversion rule by calling the method to do the convert. This version takes the parameter /// to be passed to the conversion function and we call it w/ our own value or w/ our Extensible.Value. /// </summary> private static DynamicMetaObject MakeConversionTargetWorker(ConversionResultKind kind, MethodTracker method, bool isImplicit, BindingRestrictions restrictions, Expression param) { return(new DynamicMetaObject( WrapForThrowingTry( kind, isImplicit, AstUtils.SimpleCallHelper( method.Method, param ), method.Method.ReturnType ), restrictions )); }
/// <summary> /// Helper that checkes both types to see if either one defines the specified conversion /// method. /// </summary> private MetaObject TryOneConversion(ConversionResultKind kind, Type toType, Type type, Type fromType, string methodName, bool isImplicit, Restrictions restrictions, MetaObject arg) { OldConvertToAction action = OldConvertToAction.Make(this, toType, kind); MemberGroup conversions = GetMember(action, fromType, methodName); MetaObject res = TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg); if (res != null) { return(res); } // then on the type we're trying to convert to conversions = GetMember(action, toType, methodName); return(TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg)); }
public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg) { ContractUtils.RequiresNotNull(toType, "toType"); ContractUtils.RequiresNotNull(arg, "arg"); Type knownType = arg.GetLimitType(); // try all the conversions - first look for conversions against the expression type, // these can be done w/o any additional tests. Then look for conversions against the // restricted type. BindingRestrictions typeRestrictions = arg.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType())); return TryConvertToObject(toType, arg.Expression.Type, arg) ?? TryAllConversions(toType, kind, arg.Expression.Type, arg.Restrictions, arg) ?? TryAllConversions(toType, kind, arg.GetLimitType(), typeRestrictions, arg) ?? MakeErrorTarget(toType, kind, typeRestrictions, arg); }
/// <summary> /// Helper to produce the rule for converting T to Nullable of T /// </summary> private MetaObject MakeConvertingToTToNullableOfTTarget(Type toType, ConversionResultKind kind, Restrictions restrictions, MetaObject arg) { Type valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (kind == ConversionResultKind.ExplicitCast) { // if the conversion to T fails we just throw Expression conversion = ConvertExpression(arg.Expression, valueType, kind, Ast.Constant(null, typeof(CodeContext))); return(new MetaObject( Ast.New( toType.GetConstructor(new Type[] { valueType }), conversion ), restrictions )); } else { Expression conversion = ConvertExpression(arg.Expression, valueType, kind, Ast.Constant(null, typeof(CodeContext))); // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) ParameterExpression tmp = Ast.Variable(typeof(object), "tmp"); return(new MetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign(tmp, conversion), Ast.Constant(null) ), Ast.New( toType.GetConstructor(new Type[] { valueType }), Ast.Convert( tmp, valueType ) ), GetTryConvertReturnValue(toType) ) ), restrictions )); } }
public MetaObject ConvertTo(Type toType, ConversionResultKind kind, MetaObject arg) { ContractUtils.RequiresNotNull(toType, "toType"); ContractUtils.RequiresNotNull(arg, "arg"); Type knownType = arg.LimitType; // try all the conversions - first look for conversions against the expression type, // these can be done w/o any additional tests. Then look for conversions against the // restricted type. Restrictions typeRestrictions = arg.Restrictions.Merge(Restrictions.GetTypeRestriction(arg.Expression, arg.LimitType)); return (TryConvertToObject(toType, arg.Expression.Type, arg) ?? TryAllConversions(toType, kind, arg.Expression.Type, arg.Restrictions, arg) ?? TryAllConversions(toType, kind, arg.LimitType, typeRestrictions, arg) ?? MakeErrorTarget(toType, kind, typeRestrictions, arg)); }
/// <summary>Checks if the conversion can be handled by calling a user-defined conversion method.</summary> internal MSAst TryUserDefinedConversion(ConversionResultKind kind, Type toType, Type type, MSAst arg) { var fromType = GetUnderlyingType(type); var res = TryOneConversion(kind, toType, type, fromType, "op_Implicit", true, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, true, arg); if (kind == ConversionResultKind.ExplicitCast || kind == ConversionResultKind.ExplicitTry) { // finally try explicit conversions res = res ?? TryOneConversion(kind, toType, type, fromType, "op_Explicit", false, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, false, arg); } return(res); }
/// <summary> /// Checks if the conversion can be handled by calling a user-defined conversion method. /// </summary> private DynamicMetaObject TryUserDefinedConversion(ConversionResultKind kind, Type toType, Type type, BindingRestrictions restrictions, DynamicMetaObject arg) { Type fromType = GetUnderlyingType(type); DynamicMetaObject res = TryOneConversion(kind, toType, type, fromType, "op_Implicit", true, restrictions, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, true, restrictions, arg); if (kind == ConversionResultKind.ExplicitCast || kind == ConversionResultKind.ExplicitTry) { // finally try explicit conversions res = res ?? TryOneConversion(kind, toType, type, fromType, "op_Explicit", false, restrictions, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, false, restrictions, arg); } return(res); }
/// <summary> /// Helper to wrap explicit conversion call into try/catch incase it throws an exception. If /// it throws the default value is returned. /// </summary> private static Expression WrapForThrowingTry(ConversionResultKind kind, bool isImplicit, Expression ret, Type retType) { if (!isImplicit && kind == ConversionResultKind.ExplicitTry) { Expression convFailed = GetTryConvertReturnValue(retType); ParameterExpression tmp = Expression.Variable(convFailed.Type == typeof(object) ? typeof(object) : ret.Type, "tmp"); ret = Expression.Block( new ParameterExpression[] { tmp }, AstUtils.Try( Expression.Assign(tmp, AstUtils.Convert(ret, tmp.Type)) ).Catch( typeof(Exception), Expression.Assign(tmp, convFailed) ), tmp ); } return(ret); }
/// <summary> /// Converts the provided expression to the given type. The expression is safe to evaluate multiple times. /// </summary> public virtual Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, Expression context) { ContractUtils.RequiresNotNull(expr, "expr"); ContractUtils.RequiresNotNull(toType, "toType"); Type exprType = expr.Type; if (toType == typeof(object)) { if (exprType.IsValueType) { return(Expression.Convert(expr, toType)); } else { return(expr); } } if (toType.IsAssignableFrom(exprType)) { return(expr); } Type visType = CompilerHelpers.GetVisibleType(toType); Expression[] args; if (context != null) { args = new Expression[] { context, expr }; } else { args = new Expression[] { expr }; } return(Expression.Dynamic( OldConvertToAction.Make(this, visType, kind), visType, args )); }
/// <summary> /// Helper to wrap explicit conversion call into try/catch incase it throws an exception. If /// it throws the default value is returned. /// </summary> private static Expression WrapForThrowingTry(ConversionResultKind kind, bool isImplicit, Expression ret, Type retType) { if (!isImplicit && kind == ConversionResultKind.ExplicitTry) { Expression convFailed = GetTryConvertReturnValue(retType); ParameterExpression tmp = Ast.Variable(convFailed.Type == typeof(object) ? typeof(object) : ret.Type, "tmp"); ret = Ast.Block( new ParameterExpression[] { tmp }, AstUtils.Try( Ast.Assign(tmp, AstUtils.Convert(ret, tmp.Type)) ).Catch( typeof(Exception), Ast.Assign(tmp, convFailed) ), tmp ); } return ret; }
/// <summary> /// Helper that checkes both types to see if either one defines the specified conversion /// method. /// </summary> private DynamicMetaObject TryOneConversion(ConversionResultKind kind, Type toType, Type type, Type fromType, string methodName, bool isImplicit, BindingRestrictions restrictions, DynamicMetaObject arg) { MemberGroup conversions = GetMember(MemberRequestKind.Convert, fromType, methodName); DynamicMetaObject res = TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg); if (res != null) { return res; } // then on the type we're trying to convert to conversions = GetMember(MemberRequestKind.Convert, toType, methodName); return TryUserDefinedConversion(kind, toType, type, conversions, isImplicit, restrictions, arg); }
public MSAst.Expression/*!*/ Convert(Type/*!*/ type, ConversionResultKind resultKind, MSAst.Expression/*!*/ target) { return Globals.Dynamic( BinderState.Convert( type, resultKind ), type, target ); }
/// <summary> /// Checks if any of the members of the MemberGroup provide the applicable conversion and /// if so uses it to build a conversion rule. /// </summary> private static DynamicMetaObject TryUserDefinedConversion(ConversionResultKind kind, Type toType, Type type, MemberGroup conversions, bool isImplicit, BindingRestrictions restrictions, DynamicMetaObject arg) { Type checkType = GetUnderlyingType(type); foreach (MemberTracker mt in conversions) { if (mt.MemberType != TrackerTypes.Method) continue; MethodTracker method = (MethodTracker)mt; if (isImplicit && method.Method.IsDefined(typeof(ExplicitConversionMethodAttribute), true)) { continue; } if (method.Method.ReturnType == toType) { // TODO: IsAssignableFrom? IsSubclass? ParameterInfo[] pis = method.Method.GetParameters(); if (pis.Length == 1 && pis[0].ParameterType.IsAssignableFrom(checkType)) { // we can use this method if (type == checkType) { return MakeConversionTarget(kind, method, type, isImplicit, restrictions, arg); } else { return MakeExtensibleConversionTarget(kind, method, type, isImplicit, restrictions, arg); } } } } return null; }
/// <summary> /// Helper to produce the rule for converting T to Nullable of T /// </summary> private DynamicMetaObject MakeConvertingToTToNullableOfTTarget(OverloadResolverFactory resolverFactory, Type toType, ConversionResultKind kind, BindingRestrictions restrictions, DynamicMetaObject arg) { Type valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (kind == ConversionResultKind.ExplicitCast) { // if the conversion to T fails we just throw Expression conversion = ConvertExpression(arg.Expression, valueType, kind, resolverFactory); return new DynamicMetaObject( Ast.New( toType.GetConstructor(new Type[] { valueType }), conversion ), restrictions ); } else { Expression conversion = ConvertExpression(arg.Expression, valueType, kind, resolverFactory); // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) ParameterExpression tmp = Ast.Variable(typeof(object), "tmp"); return new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Ast.NotEqual( Ast.Assign(tmp, conversion), AstUtils.Constant(null) ), Ast.New( toType.GetConstructor(new Type[] { valueType }), Ast.Convert( tmp, valueType ) ), GetTryConvertReturnValue(toType) ) ), restrictions ); } }
/// <summary> /// Checks if the conversion can be handled by calling a user-defined conversion method. /// </summary> private DynamicMetaObject TryUserDefinedConversion(ConversionResultKind kind, Type toType, Type type, BindingRestrictions restrictions, DynamicMetaObject arg) { Type fromType = GetUnderlyingType(type); DynamicMetaObject res = TryOneConversion(kind, toType, type, fromType, "op_Implicit", true, restrictions, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, true, restrictions, arg); if (kind == ConversionResultKind.ExplicitCast || kind == ConversionResultKind.ExplicitTry) { // finally try explicit conversions res = res ?? TryOneConversion(kind, toType, type, fromType, "op_Explicit", false, restrictions, arg) ?? TryOneConversion(kind, toType, type, fromType, "ConvertTo" + toType.Name, false, restrictions, arg); } return res; }
/// <summary> /// Checks if there's a conversion to/from Nullable of T. /// </summary> private DynamicMetaObject TryNullableConversion(OverloadResolverFactory factory, Type toType, ConversionResultKind kind, Type knownType, BindingRestrictions restrictions, DynamicMetaObject arg) { if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) { if (knownType == typeof(DynamicNull)) { // null -> Nullable<T> return MakeNullToNullableOfTTarget(toType, restrictions); } else if (knownType == toType.GetGenericArguments()[0]) { return MakeTToNullableOfTTarget(toType, knownType, restrictions, arg); } else if (kind == ConversionResultKind.ExplicitCast || kind == ConversionResultKind.ExplicitTry) { if (knownType != typeof(object)) { // when doing an explicit cast we'll do things like int -> Nullable<float> return MakeConvertingToTToNullableOfTTarget(factory, toType, kind, restrictions, arg); } } } return null; }
/// <summary> /// Helper to produce a conversion rule by calling the method to do the convert. This version takes the parameter /// to be passed to the conversion function and we call it w/ our own value or w/ our Extensible.Value. /// </summary> private static DynamicMetaObject MakeConversionTargetWorker(ConversionResultKind kind, MethodTracker method, bool isImplicit, BindingRestrictions restrictions, Expression param) { return new DynamicMetaObject( WrapForThrowingTry( kind, isImplicit, AstUtils.SimpleCallHelper( method.Method, param ), method.Method.ReturnType ), restrictions ); }
/// <summary> /// Helper to produce a conversion rule by calling the helper method to do the convert /// </summary> private static DynamicMetaObject MakeExtensibleConversionTarget(ConversionResultKind kind, MethodTracker method, Type fromType, bool isImplicit, BindingRestrictions restrictions, DynamicMetaObject arg) { return MakeConversionTargetWorker(kind, method, isImplicit, restrictions, GetExtensibleValue(fromType, arg)); }
/// <summary> /// Helper to produce a conversion rule by calling the helper method to do the convert /// </summary> private static DynamicMetaObject MakeConversionTarget(ConversionResultKind kind, MethodTracker method, Type fromType, bool isImplicit, BindingRestrictions restrictions, DynamicMetaObject arg) { Expression param = AstUtils.Convert(arg.Expression, fromType); return MakeConversionTargetWorker(kind, method, isImplicit, restrictions, param); }
/// <summary> /// Helper to produce an error when a conversion cannot occur /// </summary> private DynamicMetaObject MakeErrorTarget(Type toType, ConversionResultKind kind, BindingRestrictions restrictions, DynamicMetaObject arg) { DynamicMetaObject target; switch (kind) { case ConversionResultKind.ImplicitCast: case ConversionResultKind.ExplicitCast: target = MakeError( MakeConversionError(toType, arg.Expression), restrictions, toType ); break; case ConversionResultKind.ImplicitTry: case ConversionResultKind.ExplicitTry: target = new DynamicMetaObject( GetTryConvertReturnValue(toType), restrictions ); break; default: throw new InvalidOperationException(kind.ToString()); } return target; }
public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type type, Type retType, ConversionResultKind kind) { if (!type.IsEnum) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: return MakeConvertToBool(binder); case TypeCode.Int32: return MakeConvertToCommon(binder, type, retType, "__int__"); case TypeCode.Double: return MakeConvertToCommon(binder, type, retType, "__float__"); case TypeCode.String: return MakeConvertToCommon(binder, type, retType, "__str__"); case TypeCode.Object: if (type == typeof(BigInteger)) { return MakeConvertToCommon(binder, type, retType, "__long__"); } else if (type == typeof(Complex64)) { return MakeConvertToCommon(binder, type, retType, "__complex__"); } else if (type == typeof(IEnumerable)) { return MakeConvertToIEnumerable(binder); } else if (type == typeof(IEnumerator)) { return MakeConvertToIEnumerator(binder); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return MakeConvertToIEnumerable(binder, type, type.GetGenericArguments()[0]); } else if (type.IsSubclassOf(typeof(Delegate))) { return MakeDelegateTarget(binder, type, Restrict(typeof(OldInstance))); } break; } } return FallbackConvert(binder); }
public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg) { return ConvertTo(toType, kind, arg, new DefaultOverloadResolverFactory(this)); }
public DynamicMetaObject ConvertTo(Type toType, ConversionResultKind kind, DynamicMetaObject arg, OverloadResolverFactory resolverFactory) { return ConvertTo(toType, kind, arg, resolverFactory, null); }
public override Expression ConvertExpression(Expression expr, Type toType, ConversionResultKind kind, OverloadResolverFactory context) { throw new InvalidOperationException("OBSOLETE"); }