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; }
private DynamicMetaObject MakeDeleteMemberTarget(SetOrDeleteMemberInfo delInfo, DynamicMetaObject target, DynamicMetaObject errorSuggestion) { Type type = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; DynamicMetaObject self = target; if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); type = ((TypeTracker)target.Value).Type; self = null; } delInfo.Body.Restrictions = restrictions; if (self == null || !MakeOperatorDeleteMemberBody(delInfo, self, type, "DeleteMember")) { MemberGroup group = GetMember(MemberRequestKind.Delete, type, delInfo.Name); if (group.Count != 0) { if (group[0].MemberType == TrackerTypes.Property) { MethodInfo del = ((PropertyTracker)group[0]).GetDeleteMethod(PrivateBinding); if (del != null) { MakePropertyDeleteStatement(delInfo, self, del); return delInfo.Body.GetMetaObject(target); } } delInfo.Body.FinishCondition(errorSuggestion ?? MakeError(MakeUndeletableMemberError(GetDeclaringMemberType(group), delInfo.Name), typeof(void))); } else { delInfo.Body.FinishCondition(errorSuggestion ?? MakeError(MakeMissingMemberErrorForDelete(type, self, delInfo.Name), typeof(void))); } } return delInfo.Body.GetMetaObject(target); }
public static PythonType/*!*/ GetPythonType(DynamicMetaObject/*!*/ value) { if (value.HasValue) { return DynamicHelpers.GetPythonType(value.Value); } return DynamicHelpers.GetPythonTypeFromType(value.GetLimitType()); }
/// <summary> /// Provides default binding for performing a call on the specified meta objects. /// </summary> /// <param name="signature">The signature describing the call</param> /// <param name="target">The meta object to be called.</param> /// <param name="args"> /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction. /// </param> /// <param name="resolverFactory">Overload resolver factory.</param> /// <param name="errorSuggestion">The result should the object be uncallable.</param> /// <returns>A MetaObject representing the call or the error.</returns> public DynamicMetaObject Call(CallSignature signature, DynamicMetaObject errorSuggestion, OverloadResolverFactory resolverFactory,ClrMethod method, DynamicMetaObject target, params DynamicMetaObject[] args) { ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory"); TargetInfo targetInfo = GetTargetInfo(method, target, args); if (targetInfo != null) { // we're calling a well-known MethodBase DynamicMetaObject res = MakeMetaMethodCall(signature, resolverFactory, targetInfo); if (res.Expression.Type.IsValueType) { if (res.Expression.Type == Types.Void) res = new DynamicMetaObject( Expression.Block(Types.Object[0], res.Expression, Expression.Constant(null)), res.Restrictions ); else res = new DynamicMetaObject( Expression.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; } else { // we can't call this object return errorSuggestion ?? MakeCannotCallRule(target, target.GetLimitType()); } }
internal static DynamicMetaObject Call(DynamicMetaObjectBinder call, DynamicMetaObject target, DynamicMetaObject[] args) { Assert.NotNull(call, args); Assert.NotNullItems(args); if (target.NeedsDeferral()) return call.Defer(ArrayUtils.Insert(target, args)); foreach (var mo in args) { if (mo.NeedsDeferral()) { RestrictTypes(args); return call.Defer( ArrayUtils.Insert(target, args) ); } } DynamicMetaObject self = target.Restrict(target.GetLimitType()); ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target); TotemType tt = DynamicHelpers.GetTotemType(target.Value); TotemContext toContext = GetTotemContext(call); throw new NotImplementedException(); }
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); }
public static TotemType GetTotemType(DynamicMetaObject value) { if (value.HasValue) { return DynamicHelpers.GetTotemType(value.Value); } return DynamicHelpers.GetTotemType(value.GetLimitType()); }
public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, OverloadResolverFactory resolutionFactory) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, resolutionFactory ), target.Restrict(target.GetLimitType()) ); }
private DynamicMetaObject MakeSetMemberTarget(SetOrDeleteMemberInfo memInfo, DynamicMetaObject target, DynamicMetaObject value) { Type type = target.GetLimitType(); Expression self = target.Expression; target = target.Restrict(target.GetLimitType()); memInfo.Body.Restrictions = target.Restrictions; if (typeof(TypeTracker).IsAssignableFrom(type)) { type = ((TypeTracker)target.Value).Type; self = null; memInfo.Body.Restrictions = memInfo.Body.Restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); } MakeSetMemberRule(memInfo, type, self, value); return memInfo.Body.GetMetaObject(target, value); }
public DynamicMetaObject DeleteMember(string name, DynamicMetaObject target, Expression codeContext) { ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(target, "target"); return MakeDeleteMemberTarget( new SetOrDeleteMemberInfo( name, codeContext ), target.Restrict(target.GetLimitType()) ); }
/// <summary> /// Provides default binding for performing a call on the specified meta objects. /// </summary> /// <param name="signature">The signature describing the call</param> /// <param name="target">The meta object to be called.</param> /// <param name="args"> /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction. /// </param> /// <param name="resolverFactory">Overload resolver factory.</param> /// <returns>A MetaObject representing the call or the error.</returns> public DynamicMetaObject Call(CallSignature signature, OverloadResolverFactory resolverFactory, DynamicMetaObject target, params DynamicMetaObject[] args) { ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory"); TargetInfo targetInfo = GetTargetInfo(signature, target, args); if (targetInfo != null) { // we're calling a well-known MethodBase return MakeMetaMethodCall(signature, resolverFactory, targetInfo); } else { // we can't call this object return MakeCannotCallRule(target, target.GetLimitType()); } }
private DynamicMetaObject MakeDeleteMemberTarget(SetOrDeleteMemberInfo delInfo, DynamicMetaObject target) { Type type = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; Expression self = target.Expression; // needed for DeleteMember call until DynamicAction goes away OldDynamicAction act = OldDeleteMemberAction.Make( this, delInfo.Name ); if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); type = ((TypeTracker)target.Value).Type; self = null; } delInfo.Body.Restrictions = restrictions; if (self == null || !MakeOperatorDeleteMemberBody(delInfo, self, type, "DeleteMember")) { MemberGroup group = GetMember(act, type, delInfo.Name); if (group.Count != 0) { if (group[0].MemberType == TrackerTypes.Property) { MethodInfo del = ((PropertyTracker)group[0]).GetDeleteMethod(PrivateBinding); if (del != null) { MakePropertyDeleteStatement(delInfo, self, del); return delInfo.Body.GetMetaObject(target); } } delInfo.Body.FinishCondition(MakeError(MakeUndeletableMemberError(GetDeclaringMemberType(group), delInfo.Name))); } else { delInfo.Body.FinishCondition(MakeError(MakeMissingMemberError(type, delInfo.Name))); } } return delInfo.Body.GetMetaObject(target); }
/// <summary> /// Provides default binding for performing a call on the specified meta objects. /// </summary> /// <param name="signature">The signature describing the call</param> /// <param name="target">The meta object to be called.</param> /// <param name="args"> /// Additional meta objects are the parameters for the call as specified by the CallSignature in the CallAction. /// </param> /// <param name="resolverFactory">Overload resolver factory.</param> /// <returns>A MetaObject representing the call or the error.</returns> public DynamicMetaObject Call(CallSignature signature, OverloadResolverFactory resolverFactory, DynamicMetaObject target, params DynamicMetaObject[] args) { ContractUtils.RequiresNotNullItems(args, "args"); ContractUtils.RequiresNotNull(resolverFactory, "resolverFactory"); TargetInfo targetInfo = GetTargetInfo(target, args); if (targetInfo != null) { // we're calling a well-known MethodBase DynamicMetaObject res = MakeMetaMethodCall(signature, resolverFactory, targetInfo); if (res.Expression.Type.IsValueType) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; } else { // we can't call this object return MakeCannotCallRule(target, target.GetLimitType()); } }
private static DynamicMetaObject MakeCallSignatureResult(MethodBase[] methods, DynamicMetaObject target) { List<string> arrres = new List<string>(); if (methods != null) { foreach (MethodBase mb in methods) { StringBuilder res = new StringBuilder(); string comma = ""; foreach (ParameterInfo param in mb.GetParameters()) { res.Append(comma); res.Append(param.ParameterType.Name); res.Append(" "); res.Append(param.Name); comma = ", "; } arrres.Add(res.ToString()); } } return new DynamicMetaObject( AstUtils.Constant(arrres.ToArray()), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target.Expression, target.GetLimitType()).Merge(target.Restrictions) ); }
private DynamicMetaObject TryInvertedComparison(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject target, DynamicMetaObject[] args) { ExpressionType revOp = GetInvertedOperator(info.Operator); OperatorInfo revInfo = OperatorInfo.GetOperatorInfo(revOp); Debug.Assert(revInfo != null); // try the 1st type's opposite function result negated MethodBase[] targets = GetApplicableMembers(target.GetLimitType(), revInfo); if (targets.Length > 0) { return TryMakeInvertedBindingTarget(resolverFactory, targets, args); } return null; }
private DynamicMetaObject TryComparisonMethod(OperatorInfo info, OverloadResolverFactory resolverFactory, DynamicMetaObject target, DynamicMetaObject[] args) { MethodInfo[] targets = GetApplicableMembers(target.GetLimitType(), info); if (targets.Length > 0) { return TryMakeBindingTarget(resolverFactory, targets, args, BindingRestrictions.Empty); } return null; }
public override DynamicMetaObject FallbackConvert(DynamicMetaObject self, DynamicMetaObject onBindingError) { if (self.NeedsDeferral()) { return Defer(self); } Type type = Type; DynamicMetaObject res = null; switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: res = MakeToBoolConversion(self); break; case TypeCode.Char: res = TryToCharConversion(self); break; case TypeCode.Object: // !!! Deferral? if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1) { res = MakeToArrayConversion(self, type); } else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) { Type genTo = type.GetGenericTypeDefinition(); // Interface conversion helpers... if (genTo == typeof(IList<>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IList<object>), typeof(ListGenericWrapper<>)); } else if (genTo == typeof(IDictionary<,>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary<object, object>), typeof(DictionaryGenericWrapper<,>)); } else if (genTo == typeof(IEnumerable<>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper<>)); } } else if (type == typeof(IEnumerable)) { if (self.GetLimitType() == typeof(string)) { // replace strings normal enumeration with our own which returns strings instead of chars. res = new DynamicMetaObject( Ast.Call( typeof(StringOps).GetMethod("ConvertToIEnumerable"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(string)) ); } else if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = PythonProtocol.ConvertToIEnumerable(this, self.Restrict(self.GetLimitType())); } } else if (type == typeof(IEnumerator) ) { if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) && !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = PythonProtocol.ConvertToIEnumerator(this, self.Restrict(self.GetLimitType())); } } break; } if (type.IsEnum && Enum.GetUnderlyingType(type) == self.GetLimitType()) { // numeric type to enum, this is ok if the value is zero object value = Activator.CreateInstance(type); return new DynamicMetaObject( Ast.Condition( Ast.Equal( AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)), Ast.Constant(Activator.CreateInstance(self.GetLimitType())) ), Ast.Constant(value), Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type), AstUtils.Convert(self.Expression, typeof(object)) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())), value ); } return res ?? Binder.Binder.ConvertTo(Type, ResultKind, self); }
private DynamicMetaObject RestrictArgument(DynamicMetaObject arg, ParameterWrapper parameter) { if (parameter.Type == typeof(object)) { // don't use Restrict as it'll box & unbox. return new DynamicMetaObject(arg.Expression, BindingRestrictionsHelpers.GetRuntimeTypeRestriction(arg.Expression, arg.GetLimitType())); } else { return arg.Restrict(arg.GetLimitType()); } }
public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { // Used in combination with GetMember to compose InvokeMember operation. // Gets here only if the target is not a callable meta-object. var metaBuilder = new MetaObjectBuilder(this, target, args); var callArgs = new CallArguments(_context, target, args, CallInfo); metaBuilder.AddTypeRestriction(target.GetLimitType(), target.Expression); var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, callArgs, 0, 0); if (!metaBuilder.Error) { // no arguments => just return the target: metaBuilder.Result = target.Expression; } else { // any arguments found (expected none): metaBuilder.SetMetaResult(errorSuggestion, false); } return metaBuilder.CreateMetaObject(this); }
private static Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo, DynamicMetaObject actualType) { Assert.NotNull(candidateOne, candidateTwo, actualType); if (candidateOne._binder.ParametersEquivalent(candidateOne, candidateTwo)) { return Candidate.Equivalent; } for (NarrowingLevel curLevel = NarrowingLevel.None; curLevel <= NarrowingLevel.All; curLevel++) { Candidate candidate = candidateOne._binder.SelectBestConversionFor(actualType.GetLimitType(), candidateOne, candidateTwo, curLevel); if (candidate.Chosen()) { return candidate; } } return GetPreferredParameter(candidateOne, candidateTwo); }
private DynamicMetaObject MakeGetMemberTarget(GetMemberInfo getMemInfo, DynamicMetaObject target) { Type type = target.GetLimitType(); BindingRestrictions restrictions = target.Restrictions; Expression self = target.Expression; target = target.Restrict(target.GetLimitType()); // needed for GetMember call until DynamicAction goes away OldDynamicAction act = OldGetMemberAction.Make( this, getMemInfo.Name ); // Specially recognized types: TypeTracker, NamespaceTracker, and StrongBox. // TODO: TypeTracker and NamespaceTracker should technically be IDO's. MemberGroup members = MemberGroup.EmptyGroup; if (typeof(TypeTracker).IsAssignableFrom(type)) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, target.Value) ); TypeGroup tg = target.Value as TypeGroup; Type nonGen; if (tg == null || tg.TryGetNonGenericType(out nonGen)) { members = GetMember(act, ((TypeTracker)target.Value).Type, getMemInfo.Name); if (members.Count > 0) { // we have a member that's on the type associated w/ the tracker, return that... type = ((TypeTracker)target.Value).Type; self = null; } } } if (members.Count == 0) { // Get the members members = GetMember(act, type, getMemInfo.Name); } if (members.Count == 0) { if (typeof(TypeTracker).IsAssignableFrom(type)) { // ensure we don't have a non-generic type, and if we do report an error now. This matches // the rule version of the default binder but should probably be removed long term Type x = ((TypeTracker)target.Value).Type; } else if (type.IsInterface) { // all interfaces have object members type = typeof(object); members = GetMember(act, type, getMemInfo.Name); } } Expression propSelf = self; // if lookup failed try the strong-box type if available. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type)) { // properties/fields need the direct value, methods hold onto the strong box. propSelf = Ast.Field(AstUtils.Convert(self, type), type.GetField("Value")); type = type.GetGenericArguments()[0]; members = GetMember( act, type, getMemInfo.Name ); } MakeBodyHelper(getMemInfo, self, propSelf, type, members); getMemInfo.Body.Restrictions = restrictions; return getMemInfo.Body.GetMetaObject(target); }
private DynamicMetaObject TryComparisonMethod(OperatorInfo info, Expression codeContext, DynamicMetaObject target, DynamicMetaObject[] args) { MethodInfo[] targets = GetApplicableMembers(target.GetLimitType(), info); if (targets.Length > 0) { return TryMakeBindingTarget(targets, args, codeContext, BindingRestrictions.Empty); } return null; }
private Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo, DynamicMetaObject arg, NarrowingLevel level) { Assert.NotNull(candidateOne, candidateTwo); if (ParametersEquivalent(candidateOne, candidateTwo)) { return Candidate.Equivalent; } Candidate candidate = SelectBestConversionFor(arg, candidateOne, candidateTwo, level); if (candidate.Chosen()) { return candidate; } if (CanConvertFrom(candidateTwo, candidateOne)) { if (CanConvertFrom(candidateOne, candidateTwo)) { return Candidate.Ambiguous; } else { return Candidate.Two; } } else if (CanConvertFrom(candidateOne, candidateTwo)) { return Candidate.One; } // Special additional rules to order numeric value types Type t1 = candidateOne.Type; Type t2 = candidateTwo.Type; Candidate preferred = PreferConvert(t1, t2); if (preferred.Chosen()) { return preferred; } preferred = PreferConvert(t2, t1).TheOther(); if (preferred.Chosen()) { return preferred; } // consider the actual argument type: Type argType = arg.GetLimitType(); NarrowingLevel levelOne = NarrowingLevel.None; while (levelOne < level && !CanConvertFrom(argType, arg, candidateOne, levelOne)) { if (levelOne == NarrowingLevel.All) { Debug.Assert(false, "Each argument should be convertible to the corresponding parameter"); break; } levelOne++; } NarrowingLevel levelTwo = NarrowingLevel.None; while (levelTwo < level && !CanConvertFrom(argType, arg, candidateTwo, levelTwo)) { if (levelTwo == NarrowingLevel.All) { Debug.Assert(false, "Each argument should be convertible to the corresponding parameter"); break; } levelTwo++; } if (levelOne < levelTwo) { return Candidate.One; } else if (levelOne > levelTwo) { return Candidate.Two; } else { return Candidate.Ambiguous; } }
private DynamicMetaObject GetForeignObject(DynamicMetaObject self) { return new DynamicMetaObject( Expression.Dynamic( new CompatibilityGetMember(_state, Name), typeof(object), self.Expression ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())) ); }
internal static DynamicMetaObject FallbackWorker(DynamicMetaObject/*!*/ self, Expression/*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action) { if (self.NeedsDeferral()) { return action.Defer(self); } bool isNoThrow = ((options & GetMemberOptions.IsNoThrow) != 0) ? true : false; Type limitType = self.GetLimitType() ; if (limitType == typeof(DynamicNull) || PythonBinder.IsPythonType(limitType)) { // look up in the PythonType so that we can // get our custom method names (e.g. string.startswith) PythonType argType = DynamicHelpers.GetPythonTypeFromType(limitType); // if the name is defined in the CLS context but not the normal context then // we will hide it. if (argType.IsHiddenMember(name)) { DynamicMetaObject baseRes = BinderState.GetBinderState(action).Binder.GetMember( name, self, codeContext, isNoThrow ); Expression failure = GetFailureExpression(limitType, name, isNoThrow, action); return BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure); } } if (self.GetLimitType() == typeof(OldInstance)) { if ((options & GetMemberOptions.IsNoThrow) != 0) { return new DynamicMetaObject( Ast.Field( null, typeof(OperationFailed).GetField("Value") ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } else { return new DynamicMetaObject( Ast.Throw( Ast.Call( typeof(PythonOps).GetMethod("AttributeError"), Ast.Constant("{0} instance has no attribute '{1}'"), Ast.NewArrayInit( typeof(object), Ast.Constant(((OldInstance)self.Value)._class._name), Ast.Constant(name) ) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance))) ); } } var res = BinderState.GetBinderState(action).Binder.GetMember(name, self, codeContext, isNoThrow); // Default binder can return something typed to boolean or int. // If that happens, we need to apply Python's boxing rules. if (res.Expression.Type == typeof(bool) || res.Expression.Type == typeof(int)) { res = new DynamicMetaObject( AstUtils.Convert(res.Expression, typeof(object)), res.Restrictions ); } return res; }
protected static DynamicMetaObject GetMemberFallback(DynamicMetaObject self, DynamicMetaObjectBinder member, DynamicMetaObject codeContext) { PythonGetMemberBinder gmb = member as PythonGetMemberBinder; if (gmb != null) { return gmb.Fallback(self, codeContext); } GetMemberBinder gma = (GetMemberBinder)member; return gma.FallbackGetMember(self.Restrict(self.GetLimitType())); }
public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { var exprs = RubyBinder.ToExpressions(args, -1); exprs[0] = target.Expression; return new DynamicMetaObject( Expression.Dynamic(new Return(_context, CallInfo), typeof(object), exprs), target.Restrictions.Merge(BindingRestrictions.Combine(args)). // TODO: ??? Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.GetLimitType())) ); }
public override Candidate SelectBestConversionFor(DynamicMetaObject/*!*/ arg, ParameterWrapper/*!*/ candidateOne, ParameterWrapper/*!*/ candidateTwo, NarrowingLevel level) { Type typeOne = candidateOne.Type; Type typeTwo = candidateTwo.Type; Type actualType = arg.GetLimitType(); if (actualType == typeof(DynamicNull)) { // if nil is passed as a block argument prefers BlockParam over a missing block: if (typeOne == typeof(BlockParam) && typeTwo == typeof(MissingBlockParam)) { Debug.Assert(!candidateOne.ProhibitNull); return Candidate.One; } if (typeOne == typeof(MissingBlockParam) && typeTwo == typeof(BlockParam)) { Debug.Assert(!candidateTwo.ProhibitNull); return Candidate.Two; } } else { if (typeOne == actualType) { if (typeTwo == actualType) { // prefer non-nullable reference type over nullable: if (!actualType.IsValueType) { if (candidateOne.ProhibitNull) { return Candidate.One; } else if (candidateTwo.ProhibitNull) { return Candidate.Two; } } } else { return Candidate.One; } } else if (typeTwo == actualType) { return Candidate.Two; } } // prefer integer type over enum: if (typeOne.IsEnum && Enum.GetUnderlyingType(typeOne) == typeTwo) { return Candidate.Two; } if (typeTwo.IsEnum && Enum.GetUnderlyingType(typeTwo) == typeOne) { return Candidate.One; } return base.SelectBestConversionFor(arg, candidateOne, candidateTwo, level); }
internal static DynamicMetaObject Call(DynamicMetaObjectBinder/*!*/ call, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ args) { Assert.NotNull(call, args); Assert.NotNullItems(args); if (target.NeedsDeferral()) { return call.Defer(ArrayUtils.Insert(target, args)); } foreach (DynamicMetaObject mo in args) { if (mo.NeedsDeferral()) { RestrictTypes(args); return call.Defer( ArrayUtils.Insert(target, args) ); } } DynamicMetaObject self = target.Restrict(target.GetLimitType()); ValidationInfo valInfo = BindingHelpers.GetValidationInfo(target); PythonType pt = DynamicHelpers.GetPythonType(target.Value); BinderState state = BinderState.GetBinderState(call); // look for __call__, if it's present dispatch to it. Otherwise fall back to the // default binder PythonTypeSlot callSlot; if (!typeof(Delegate).IsAssignableFrom(target.GetLimitType()) && pt.TryResolveSlot(state.Context, Symbols.Call, out callSlot)) { ConditionalBuilder cb = new ConditionalBuilder(call); Expression body; callSlot.MakeGetExpression( state.Binder, BinderState.GetCodeContext(call), self.Expression, GetPythonType(self), cb ); if (!cb.IsFinal) { cb.FinishCondition(GetCallError(self)); } Expression[] callArgs = ArrayUtils.Insert( BinderState.GetCodeContext(call), cb.GetMetaObject().Expression, DynamicUtils.GetExpressions(args) ); body = Ast.Dynamic( BinderState.GetBinderState(call).Invoke( BindingHelpers.GetCallSignature(call) ), typeof(object), callArgs ); return BindingHelpers.AddDynamicTestAndDefer( call, new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))), args, valInfo ); } return null; }
private static DynamicMetaObject MakeIMembersListRule(Expression codeContext, DynamicMetaObject target) { return new DynamicMetaObject( Ast.Call( typeof(BinderOps).GetMethod("GetStringMembers"), Ast.Call( AstUtils.Convert(target.Expression, typeof(IMembersList)), typeof(IMembersList).GetMethod("GetMemberNames"), codeContext ) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(target.Expression, target.GetLimitType()).Merge(target.Restrictions) ); }