// 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))); }
public StandardRule <T> MakeRule() { Type toType = Action.ToType; Type knownType = CompilerHelpers.GetVisibleType(_rule.Parameters[0].Type); // check for conversion to object first... if (TryConvertToObject(toType, knownType)) { _rule.AddTest(Ast.Constant(true)); return(_rule); } // do checks that aren't based upon strongly knowing the object's type (and don't require tests) if (TryAllConversions(toType, knownType)) { _rule.AddTest(Ast.Constant(true)); return(_rule); } // try again w/ a test for the known-type Type type = CompilerHelpers.GetType(_arg); _rule.AddTest(_rule.MakeTypeTest(type, 0)); if (TryAllConversions(toType, type)) { return(_rule); } // no conversion is available, make an error rule. MakeErrorTarget(); return(_rule); }
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> /// Helper to produce a rule when no conversion is required (the strong type of the expression /// input matches the type we're converting to or has an implicit conversion at the IL level) /// </summary> private void MakeSimpleConversionTarget(Type toType, Type knownType) { if (toType.IsValueType && _rule.ReturnType == typeof(object) && _rule.Parameters[0].Type == typeof(object)) { // boxed value type is being converted back to object. We've done // the type check, there's no need to unbox & rebox the value. infact // it breaks calls on instance methods so we need to avoid it. _rule.Target = _rule.MakeReturn( Binder, _rule.Parameters[0] ); } else { Expression arg = _rule.Parameters[0]; if (arg.Type != knownType && knownType != typeof(Null)) { arg = Ast.Convert(arg, CompilerHelpers.GetVisibleType(knownType)); } _rule.Target = _rule.MakeReturn( Binder, AstUtils.Convert(arg, CompilerHelpers.GetVisibleType(toType)) ); } }
public static MetaObject Restrict(this MetaObject self, Type type) { ContractUtils.RequiresNotNull(self, "self"); ContractUtils.RequiresNotNull(type, "type"); IRestrictedMetaObject rmo = self as IRestrictedMetaObject; if (rmo != null) { return(rmo.Restrict(type)); } if (type == self.Expression.Type) { if (type.IsSealedOrValueType()) { return(self); } if (self.Expression.NodeType == ExpressionType.New || self.Expression.NodeType == ExpressionType.NewArrayBounds || self.Expression.NodeType == ExpressionType.NewArrayInit) { return(self); } } if (type == typeof(Null)) { return(new MetaObject( Expression.Constant(null), self.Restrictions.Merge(Restrictions.GetInstanceRestriction(self.Expression, null)), self.Value )); } if (self.HasValue) { return(new MetaObject( AstUtils.Convert( self.Expression, CompilerHelpers.GetVisibleType(type) ), self.Restrictions.Merge(Restrictions.GetTypeRestriction(self.Expression, type)), self.Value )); } return(new MetaObject( AstUtils.Convert( self.Expression, CompilerHelpers.GetVisibleType(type) ), self.Restrictions.Merge(Restrictions.GetTypeRestriction(self.Expression, type)) )); }
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 static DynamicMetaObject Restrict(this DynamicMetaObject self, Type type) { ContractUtils.RequiresNotNull(self, "self"); ContractUtils.RequiresNotNull(type, "type"); IRestrictedMetaObject rmo = self as IRestrictedMetaObject; if (rmo != null) { return(rmo.Restrict(type)); } if (type == self.Expression.Type) { if (type.IsSealed || self.Expression.NodeType == ExpressionType.New || self.Expression.NodeType == ExpressionType.NewArrayBounds || self.Expression.NodeType == ExpressionType.NewArrayInit) { return(self.Clone(self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, type)))); } } if (type == typeof(DynamicNull)) { return(self.Clone( AstUtils.Constant(null), self.Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(self.Expression, null)) )); } Expression converted; // if we're converting to a value type just unbox to preserve // object identity. If we're converting from Enum then we're // going to a specific enum value and an unbox is not allowed. if (type.IsValueType && self.Expression.Type != typeof(Enum)) { converted = Expression.Unbox( self.Expression, CompilerHelpers.GetVisibleType(type) ); } else { converted = AstUtils.Convert( self.Expression, CompilerHelpers.GetVisibleType(type) ); } return(self.Clone(converted, self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, type)))); }
internal virtual void BuildInvoke(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { Assert.NotNull(metaBuilder, args); Debug.Assert(args.Target == this); // first argument must be this method: metaBuilder.AddRestriction(Ast.Equal(args.TargetExpression, AstUtils.Constant(this))); // set the target (becomes self in the called method): args.SetTarget(AstUtils.Constant(_target, CompilerHelpers.GetVisibleType(_target)), _target); _info.BuildCall(metaBuilder, args, _name); }
private MethodBase[] GetBoundMemberTargets(BoundMemberTracker bmt) { Debug.Assert(bmt.Instance == null); // should be null for trackers that leak to user code MethodBase[] targets; _instance = Ast.Convert( Ast.ReadProperty( Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)), typeof(BoundMemberTracker).GetProperty("ObjectInstance") ), CompilerHelpers.GetVisibleType(CompilerHelpers.GetType(bmt.ObjectInstance)) ); _test = Ast.AndAlso( _test, Ast.Equal( Ast.ReadProperty( Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)), typeof(BoundMemberTracker).GetProperty("BoundTo") ), Ast.RuntimeConstant(bmt.BoundTo) ) ); _test = Ast.AndAlso( _test, Rule.MakeTypeTest( CompilerHelpers.GetType(bmt.ObjectInstance), Ast.ReadProperty( Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)), typeof(BoundMemberTracker).GetProperty("ObjectInstance") ) ) ); switch (bmt.BoundTo.MemberType) { case TrackerTypes.MethodGroup: targets = ((MethodGroup)bmt.BoundTo).GetMethodBases(); break; case TrackerTypes.Method: targets = new MethodBase[] { ((MethodTracker)bmt.BoundTo).Method }; break; default: throw new InvalidOperationException(); // nothing else binds yet } return(targets); }
private static void AddArgument(List <Expression> /*!*/ actualArgs, object arg, Expression /*!*/ expr) { if (arg == null) { actualArgs.Add(Ast.Constant(null)); } else { var type = CompilerHelpers.GetVisibleType(arg); if (type.IsValueType) { actualArgs.Add(expr); } else { actualArgs.Add(AstUtils.Convert(expr, type)); } } }
/// <summary> /// Helper to produce a rule when no conversion is required (the strong type of the expression /// input matches the type we're converting to or has an implicit conversion at the IL level) /// </summary> private static DynamicMetaObject MakeSimpleConversionTarget(Type toType, BindingRestrictions restrictions, DynamicMetaObject arg) { return(new DynamicMetaObject( AstUtils.Convert(arg.Expression, CompilerHelpers.GetVisibleType(toType)), restrictions)); /* * if (toType.IsValueType && _rule.ReturnType == typeof(object) && Expression.Type == typeof(object)) { * // boxed value type is being converted back to object. We've done * // the type check, there's no need to unbox & rebox the value. infact * // it breaks calls on instance methods so we need to avoid it. * _rule.Target = * _rule.MakeReturn( * Binder, * Expression * ); * } * */ }
/// <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> /// Creates a call to this MethodTarget with the specified parameters. Casts are inserted to force /// the types to the provided known types. /// /// TODO: Remove RuleBuilder and knownTypes once we're fully meta /// </summary> /// <param name="parameterBinder">ParameterBinder used to map arguments to parameters.</param> /// <param name="parameters">The explicit arguments</param> /// <param name="knownTypes">If non-null, the type for each element in parameters</param> /// <returns></returns> internal Expression MakeExpression(ParameterBinder parameterBinder, IList <Expression> parameters, IList <Type> knownTypes) { Debug.Assert(knownTypes == null || parameters.Count == knownTypes.Count); IList <Expression> args = parameters; if (knownTypes != null) { args = new Expression[parameters.Count]; for (int i = 0; i < args.Count; i++) { args[i] = parameters[i]; if (knownTypes[i] != null && !knownTypes[i].IsAssignableFrom(parameters[i].Type)) { args[i] = Ast.Convert(parameters[i], CompilerHelpers.GetVisibleType(knownTypes[i])); } } } return(MakeExpression(parameterBinder, args)); }
public void MakeRule() { Type toType = Action.ToType; Type knownType = CompilerHelpers.GetVisibleType(_rule.Parameters[0].Type); // check for conversion to object first... if (TryConvertToObject(toType, knownType)) { _rule.AddTest(Ast.Constant(true)); return; } // do checks that aren't based upon strongly knowing the object's type (and don't require tests) if (TryAllConversions(toType, knownType)) { _rule.AddTest(Ast.Constant(true)); return; } // try again w/ a test for the known-type Type type = CompilerHelpers.GetType(_arg); _rule.AddTest(_rule.MakeTypeTest(type, 0)); if (TryAllConversions(toType, type)) { return; } // finally try conversions that aren't based upon the incoming type at all but // are last chance conversions based on the destination type if (TryExtraConversions(toType)) { return; } // no conversion is available, make an error rule. MakeErrorTarget(); }
private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType) { Assert.NotNull(instance, testType); object instanceValue = Value.BindingSelf; BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType); // cast the instance to the correct type if (CompilerHelpers.IsStrongBox(instanceValue)) { instance = ReadStrongBoxValue(instance); instanceValue = ((IStrongBox)instanceValue).Value; } else if (!testType.IsEnum) { // We need to deal w/ wierd types like MarshalByRefObject. // We could have an MBRO whos DeclaringType is completely different. // Therefore we special case it here and cast to the declaring type Type selfType = CompilerHelpers.GetType(Value.BindingSelf); selfType = CompilerHelpers.GetVisibleType(selfType); if (selfType == typeof(object) && Value.DeclaringType.IsInterface) { selfType = Value.DeclaringType; } if (Value.DeclaringType.IsInterface && selfType.IsValueType) { // explicit interface implementation dispatch on a value type, don't // unbox the value type before the dispatch. instance = AstUtils.Convert(instance, Value.DeclaringType); } else if (selfType.IsValueType) { // We might be calling a a mutating method (like // Rectangle.Intersect). If so, we want it to mutate // the boxed value directly instance = Ast.Unbox(instance, selfType); } else { #if SILVERLIGHT instance = AstUtils.Convert(instance, selfType); #else Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType; instance = AstUtils.Convert(instance, convType); #endif } } else { // we don't want to cast the enum to its real type, it will unbox it // and turn it into its underlying type. We presumably want to call // a method on the Enum class though - so we cast to Enum instead. instance = AstUtils.Convert(instance, typeof(Enum)); } return(new DynamicMetaObject( instance, restrictions, instanceValue )); }
public override Expression /*!*/ Convert(DynamicMetaObject /*!*/ metaObject, Type restrictedType, ParameterInfo info, Type /*!*/ toType) { Expression expr = metaObject.Expression; Type fromType = restrictedType ?? expr.Type; // block: if (fromType == typeof(MissingBlockParam)) { Debug.Assert(toType == typeof(BlockParam) || toType == typeof(MissingBlockParam)); return(AstUtils.Constant(null)); } if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam)) { return(AstUtils.Constant(null)); } // protocol conversions: if (info != null && info.IsDefined(typeof(DefaultProtocolAttribute), false)) { var action = RubyConversionAction.TryGetDefaultConversionAction(Context, toType); if (action != null) { // TODO: inline implicit conversions: return(AstUtils.LightDynamic(action, toType, expr)); } // Do not throw an exception here to allow generic type parameters to be used with D.P. attribute. // The semantics should be to use DP if available for the current instantiation and ignore it otherwise. } if (restrictedType != null) { if (restrictedType == typeof(DynamicNull)) { if (!toType.IsValueType || toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>)) { return(AstUtils.Constant(null, toType)); } else if (toType == typeof(bool)) { return(AstUtils.Constant(false)); } } if (toType.IsAssignableFrom(restrictedType)) { // expr can be converted to restrictedType, which can be converted toType => we can convert expr to toType: return(AstUtils.Convert(expr, CompilerHelpers.GetVisibleType(toType))); } // if there is a simple conversion from restricted type, convert the expression to the restricted type and use that conversion: Type visibleRestrictedType = CompilerHelpers.GetVisibleType(restrictedType); if (Converter.CanConvertFrom(metaObject, visibleRestrictedType, toType, false, NarrowingLevel.None, false, false).IsConvertible) { expr = AstUtils.Convert(expr, visibleRestrictedType); } } return(Converter.ConvertExpression(expr, toType, _args.RubyContext, _args.MetaContext.Expression, _implicitProtocolConversions)); }
/// <summary> /// Helper to produce a rule when no conversion is required (the strong type of the expression /// input matches the type we're converting to or has an implicit conversion at the IL level) /// </summary> private static MSAst MakeSimpleConversionTarget(Type toType, MSAst arg) { return(AstUtils.Convert(arg, CompilerHelpers.GetVisibleType(toType))); }
public override Expression ConvertExpression(Expression /*!*/ expr, Type /*!*/ toType, ConversionResultKind kind, Expression context) { Type fromType = expr.Type; if (toType == typeof(object)) { if (fromType.IsValueType) { return(Ast.Convert(expr, toType)); } else { return(expr); } } if (toType.IsAssignableFrom(fromType)) { return(expr); } // We used to have a special case for int -> double... if (fromType != typeof(object) && fromType.IsValueType) { expr = Ast.Convert(expr, typeof(object)); } MethodInfo fastConvertMethod = GetFastConvertMethod(toType); if (fastConvertMethod != null) { return(Ast.Call(fastConvertMethod, AstUtils.Convert(expr, typeof(object)))); } if (typeof(Delegate).IsAssignableFrom(toType)) { return(Ast.Convert( Ast.Call( typeof(Converter).GetMethod("ConvertToDelegate"), AstUtils.Convert(expr, typeof(object)), Ast.Constant(toType) ), toType )); } Expression typeIs; Type visType = CompilerHelpers.GetVisibleType(toType); if (toType.IsVisible) { typeIs = Ast.TypeIs(expr, toType); } else { typeIs = Ast.Call( AstUtils.Convert(Ast.Constant(toType), typeof(Type)), typeof(Type).GetMethod("IsInstanceOfType"), AstUtils.Convert(expr, typeof(object)) ); } return(Ast.Condition( typeIs, Ast.Convert( expr, visType), Ast.Convert( Ast.Call( GetGenericConvertMethod(visType), AstUtils.Convert(expr, typeof(object)), Ast.Constant(visType.TypeHandle) ), visType ) )); }
private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType) { Assert.NotNull(instance, testType); object instanceValue = Value.BindingSelf; BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType); // cast the instance to the correct type if (CompilerHelpers.IsStrongBox(instanceValue)) { instance = ReadStrongBoxValue(instance); instanceValue = ((IStrongBox)instanceValue).Value; } else if (!testType.IsEnum) { // We need to deal w/ wierd types like MarshalByRefObject. // We could have an MBRO whos DeclaringType is completely different. // Therefore we special case it here and cast to the declaring type Type selfType = CompilerHelpers.GetType(Value.BindingSelf); selfType = CompilerHelpers.GetVisibleType(selfType); if (selfType == typeof(object) && Value.DeclaringType.IsInterface) { selfType = Value.DeclaringType; Type genericTypeDefinition = null; if (Value.DeclaringType.IsGenericType && Value.DeclaringType.FullName == null && Value.DeclaringType.ContainsGenericParameters && !Value.DeclaringType.IsGenericTypeDefinition) { // from MSDN: If the current type contains generic type parameters that have not been replaced by // specific types (that is, the ContainsGenericParameters property returns true), but the type // is not a generic type definition (that is, the IsGenericTypeDefinition property returns false), // this property returns Nothing. For example, consider the classes Base and Derived in the following code. // if this type is completely generic (no type arguments specified) then we'll go ahead and get the // generic type definition for the this parameter - that'll let us successfully type infer on it later. var genericArgs = Value.DeclaringType.GetGenericArguments(); bool hasOnlyGenerics = genericArgs.Length > 0; foreach (var genericParam in genericArgs) { if (!genericParam.IsGenericParameter) { hasOnlyGenerics = false; break; } } if (hasOnlyGenerics) { genericTypeDefinition = Value.DeclaringType.GetGenericTypeDefinition(); } } else if (Value.DeclaringType.IsGenericTypeDefinition) { genericTypeDefinition = Value.DeclaringType; } if (genericTypeDefinition != null) { // we're a generic interface method on a non-public type. // We need to see if we can match any types implemented on // the concrete selfType. var interfaces = CompilerHelpers.GetType(Value.BindingSelf).GetInterfaces(); foreach (var iface in interfaces) { if (iface.IsGenericType && iface.GetGenericTypeDefinition() == genericTypeDefinition) { selfType = iface; break; } } } } if (Value.DeclaringType.IsInterface && selfType.IsValueType) { // explicit interface implementation dispatch on a value type, don't // unbox the value type before the dispatch. instance = AstUtils.Convert(instance, Value.DeclaringType); } else if (selfType.IsValueType) { // We might be calling a a mutating method (like // Rectangle.Intersect). If so, we want it to mutate // the boxed value directly instance = Ast.Unbox(instance, selfType); } else { #if SILVERLIGHT instance = AstUtils.Convert(instance, selfType); #else Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType; instance = AstUtils.Convert(instance, convType); #endif } } else { // we don't want to cast the enum to its real type, it will unbox it // and turn it into its underlying type. We presumably want to call // a method on the Enum class though - so we cast to Enum instead. instance = AstUtils.Convert(instance, typeof(Enum)); } return(new DynamicMetaObject( instance, restrictions, instanceValue )); }