public override bool CanConvertFrom(Type fromType, DynamicMetaObject fromArg, ParameterWrapper toParameter, NarrowingLevel level) { if ((fromType == typeof(List) || fromType.IsSubclassOf(typeof(List)))) { if (toParameter.Type.IsGenericType() && toParameter.Type.GetGenericTypeDefinition() == typeof(IList<>) && (toParameter.ParameterInfo.IsDefined(typeof(BytesConversionAttribute), false) || toParameter.ParameterInfo.IsDefined(typeof(BytesConversionNoStringAttribute), false))) { return false; } } else if (fromType == typeof(string)) { if (toParameter.Type == typeof(IList<byte>) && !Binder.Context.PythonOptions.Python30 && toParameter.ParameterInfo.IsDefined(typeof(BytesConversionAttribute), false)) { // string -> byte array, we allow this in Python 2.6 return true; } } else if (fromType == typeof(Bytes)) { if (toParameter.Type == typeof(string) && !Binder.Context.PythonOptions.Python30 && toParameter.ParameterInfo.IsDefined(typeof(BytesConversionAttribute), false)) { return true; } } return base.CanConvertFrom(fromType, fromArg, toParameter, level); }
public override bool CanConvertFrom(Type fromType, DynamicMetaObject fromArgument, ParameterWrapper toParameter, NarrowingLevel level) { if (toParameter.Type == typeof(string) && (level == NarrowingLevel.Three || level == NarrowingLevel.All)) return true; if (toParameter.IsParamsArray == true && typeof(IList<object>).IsAssignableFrom(fromType)) { var toType = toParameter.Type.GetElementType(); var list = (IList<object>)fromArgument.Value; for(var i = 0; i < list.Count; i++) { var itm = list[i]; var argExp = Expression.Call( Expression.Convert(fromArgument.Expression, fromArgument.LimitType), (typeof(IList<object>).GetMethod("get_Item")), Expression.Constant(i, typeof(int)) ); var arg = new DynamicMetaObject( argExp, fromArgument.Restrictions, itm ); if(!CanConvertFrom(itm.GetType(), arg, new ParameterWrapper(null, toType, null, ParameterBindingFlags.None), level)) return false; } return true; } return base.CanConvertFrom(fromType, fromArgument, toParameter, level); }
/// <summary> /// Builds a new MethodCandidate which takes count arguments and the provided list of keyword arguments. /// /// The basic idea here is to figure out which parameters map to params or a dictionary params and /// fill in those spots w/ extra ParameterWrapper's. /// </summary> internal MethodCandidate MakeParamsExtended(int count, IList<string> names) { Debug.Assert(_overload.IsVariadic); List<ParameterWrapper> newParameters = new List<ParameterWrapper>(count); // keep track of which named args map to a real argument, and which ones // map to the params dictionary. List<string> unusedNames = new List<string>(names); List<int> unusedNameIndexes = new List<int>(); for (int i = 0; i < unusedNames.Count; i++) { unusedNameIndexes.Add(i); } // if we don't have a param array we'll have a param dict which is type object ParameterWrapper paramsArrayParameter = null; int paramsArrayIndex = -1; for (int i = 0; i < _parameters.Count; i++) { ParameterWrapper parameter = _parameters[i]; if (parameter.IsParamsArray) { paramsArrayParameter = parameter; paramsArrayIndex = i; } else { int j = unusedNames.IndexOf(parameter.Name); if (j != -1) { unusedNames.RemoveAt(j); unusedNameIndexes.RemoveAt(j); } newParameters.Add(parameter); } } if (paramsArrayIndex != -1) { ParameterWrapper expanded = paramsArrayParameter.Expand(); while (newParameters.Count < (count - unusedNames.Count)) { newParameters.Insert(System.Math.Min(paramsArrayIndex, newParameters.Count), expanded); } } if (_paramsDict != null) { var flags = (_overload.ProhibitsNullItems(_paramsDict.ParameterInfo.Position) ? ParameterBindingFlags.ProhibitNull : 0) | (_paramsDict.IsHidden ? ParameterBindingFlags.IsHidden : 0); foreach (string name in unusedNames) { newParameters.Add(new ParameterWrapper(_paramsDict.ParameterInfo, typeof(object), name, flags)); } } else if (unusedNames.Count != 0) { // unbound kw args and no where to put them, can't call... // TODO: We could do better here because this results in an incorrect arg # error message. return null; } // if we have too many or too few args we also can't call if (count != newParameters.Count) { return null; } return MakeParamsExtended(unusedNames.ToArray(), unusedNameIndexes.ToArray(), newParameters); }
internal static Candidate GetPreferredCandidate(MethodCandidate one, MethodCandidate two, CallTypes callType, MetaObject[] actualTypes) { Candidate cmpParams = ParameterWrapper.GetPreferredParameters(one.Parameters, two.Parameters, actualTypes); if (cmpParams.Chosen()) { return(cmpParams); } Candidate ret = MethodTarget.CompareEquivalentParameters(one.Target, two.Target); if (ret.Chosen()) { return(ret); } if (CompilerHelpers.IsStatic(one.Target.Method) && !CompilerHelpers.IsStatic(two.Target.Method)) { return(callType == CallTypes.ImplicitInstance ? Candidate.Two : Candidate.One); } else if (!CompilerHelpers.IsStatic(one.Target.Method) && CompilerHelpers.IsStatic(two.Target.Method)) { return(callType == CallTypes.ImplicitInstance ? Candidate.One : Candidate.Two); } return(Candidate.Equivalent); }
public override bool CanConvertFrom(Type fromType, DynamicMetaObject fromArgument, ParameterWrapper toParameter, NarrowingLevel level) { if (level >= NarrowingLevel.Two) { if (toParameter.Type == typeof(string)) return true; } return base.CanConvertFrom(fromType, fromArgument, toParameter, level); }
public override bool CanConvertFrom(Type fromType, ParameterWrapper toParameter, NarrowingLevel level) { if ((fromType == typeof(List) || fromType.IsSubclassOf(typeof(List))) && toParameter.Type.IsGenericType && toParameter.Type.GetGenericTypeDefinition() == typeof(IList<>)) { if (toParameter.ParameterInfo.IsDefined(typeof(ProhibitGenericListConversionAttribute), false)) { return false; } } return base.CanConvertFrom(fromType, toParameter, level); }
private SimpleArgBuilder AddSimpleParameterMapping(ParameterInfo info, int index) { var param = CreateParameterWrapper(info); if (param.IsParamsDict) { _paramsDict = param; } else { _parameters.Add(param); } return(new SimpleArgBuilder(info, info.ParameterType, index, param.IsParamsArray, param.IsParamsDict)); }
private static Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo) { Assert.NotNull(candidateOne, candidateTwo); if (candidateOne._binder.ParametersEquivalent(candidateOne, candidateTwo)) { return(Candidate.Equivalent); } Type t1 = candidateOne.Type; Type t2 = candidateTwo.Type; if (candidateOne._binder.CanConvertFrom(t2, candidateOne, NarrowingLevel.None)) { if (candidateOne._binder.CanConvertFrom(t1, candidateTwo, NarrowingLevel.None)) { return(Candidate.Ambiguous); } else { return(Candidate.Two); } } if (candidateOne._binder.CanConvertFrom(t1, candidateTwo, NarrowingLevel.None)) { return(Candidate.One); } // Special additional rules to order numeric value types Candidate preferred = candidateOne._binder.PreferConvert(t1, t2); if (preferred.Chosen()) { return(preferred); } preferred = candidateOne._binder.PreferConvert(t2, t1).TheOther(); if (preferred.Chosen()) { return(preferred); } return(Candidate.Ambiguous); }
internal MethodCandidate(OverloadResolver resolver, MethodBase method, List<ParameterWrapper> parameters, ParameterWrapper paramsDict, ReturnBuilder returnBuilder, ArgBuilder instanceBuilder, IList<ArgBuilder> argBuilders) { Assert.NotNull(resolver, method, instanceBuilder, returnBuilder); Assert.NotNullItems(parameters); Assert.NotNullItems(argBuilders); _resolver = resolver; _method = method; _instanceBuilder = instanceBuilder; _argBuilders = argBuilders; _returnBuilder = returnBuilder; _parameters = parameters; _paramsDict = paramsDict; _paramsArrayIndex = ParameterWrapper.IndexOfParamsArray(parameters); parameters.TrimExcess(); }
internal MethodCandidate(OverloadResolver resolver, OverloadInfo method, List <ParameterWrapper> parameters, ParameterWrapper paramsDict, ReturnBuilder returnBuilder, InstanceBuilder instanceBuilder, IList <ArgBuilder> argBuilders, Dictionary <DynamicMetaObject, BindingRestrictions> restrictions) { Assert.NotNull(resolver, method, instanceBuilder, returnBuilder); Assert.NotNullItems(parameters); Assert.NotNullItems(argBuilders); Resolver = resolver; Overload = method; _instanceBuilder = instanceBuilder; ArgBuilders = argBuilders; ReturnBuilder = returnBuilder; _parameters = parameters; _paramsDict = paramsDict; Restrictions = restrictions; ParamsArrayIndex = ParameterWrapper.IndexOfParamsArray(parameters); parameters.TrimExcess(); }
private static Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo, MetaObject 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.LimitType, candidateOne, candidateTwo, curLevel); if (candidate.Chosen()) { return(candidate); } } return(GetPreferredParameter(candidateOne, candidateTwo)); }
internal MethodCandidate(OverloadResolver resolver, OverloadInfo method, List<ParameterWrapper> parameters, ParameterWrapper paramsDict, ReturnBuilder returnBuilder, InstanceBuilder instanceBuilder, IList<ArgBuilder> argBuilders, Dictionary<DynamicMetaObject, BindingRestrictions> restrictions) { Assert.NotNull(resolver, method, instanceBuilder, returnBuilder); Assert.NotNullItems(parameters); Assert.NotNullItems(argBuilders); _resolver = resolver; _overload = method; _instanceBuilder = instanceBuilder; _argBuilders = argBuilders; _returnBuilder = returnBuilder; _parameters = parameters; _paramsDict = paramsDict; _restrictions = restrictions; _paramsArrayIndex = ParameterWrapper.IndexOfParamsArray(parameters); parameters.TrimExcess(); }
/// <summary> /// Creates a new list of ParameterWrappers for the generic method replacing the old parameters with the new ones. /// </summary> private static List <ParameterWrapper> CreateNewWrappers(MethodCandidate candidate, OverloadInfo newOverload, OverloadInfo oldOverload) { List <ParameterWrapper> newWrappers = new List <ParameterWrapper>(); for (int i = 0; i < candidate.ParameterCount; i++) { ParameterWrapper oldWrap = candidate.GetParameter(i); ParameterInfo pi = null; Type newType = oldWrap.Type; if (oldWrap.ParameterInfo != null) { pi = newOverload.Parameters[oldWrap.ParameterInfo.Position]; ParameterInfo oldParam = oldOverload.Parameters[oldWrap.ParameterInfo.Position]; if (oldParam.ParameterType == oldWrap.Type) { newType = pi.ParameterType; } else if (pi.ParameterType.IsByRef) { newType = pi.ParameterType.GetElementType(); if (oldParam.ParameterType.GetElementType() != oldWrap.Type) { Debug.Assert(CompilerHelpers.IsStrongBox(oldWrap.Type)); newType = typeof(StrongBox <>).MakeGenericType(newType); } } else { Debug.Assert(oldParam.ParameterType.GetElementType() == oldWrap.Type); newType = pi.ParameterType.GetElementType(); } } newWrappers.Add(new ParameterWrapper(pi, newType, oldWrap.Name, oldWrap.Flags)); } return(newWrappers); }
/// <summary> /// Returns a mapping from generic type parameter to the input DMOs which map to it. /// </summary> private static Dictionary <Type /*!*/, ArgumentInputs /*!*/> /*!*/ GetArgumentToInputMapping(MethodCandidate /*!*/ candidate, IList <DynamicMetaObject /*!*/> /*!*/ args) { Dictionary <Type, ArgumentInputs> inputs = new Dictionary <Type, ArgumentInputs>(); for (int curParam = 0; curParam < candidate.ParameterCount; curParam++) { ParameterWrapper param = candidate.GetParameter(curParam); if (param.IsParamsArray) { AddOneInput(inputs, args[curParam], param.Type.GetElementType()); } else if (param.IsByRef) { AddOneInput(inputs, args[curParam], param.ParameterInfo.ParameterType); } else { AddOneInput(inputs, args[curParam], param.Type); } } return(inputs); }
private static Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo) { Assert.NotNull(candidateOne, candidateTwo); if (candidateOne._binder.ParametersEquivalent(candidateOne, candidateTwo)) { return Candidate.Equivalent; } Type t1 = candidateOne.Type; Type t2 = candidateTwo.Type; if (candidateOne._binder.CanConvertFrom(t2, candidateOne, NarrowingLevel.None)) { if (candidateOne._binder.CanConvertFrom(t1, candidateTwo, NarrowingLevel.None)) { return Candidate.Ambiguous; } else { return Candidate.Two; } } if (candidateOne._binder.CanConvertFrom(t1, candidateTwo, NarrowingLevel.None)) { return Candidate.One; } // Special additional rules to order numeric value types Candidate preferred = candidateOne._binder.PreferConvert(t1, t2); if (preferred.Chosen()) { return preferred; } preferred = candidateOne._binder.PreferConvert(t2, t1).TheOther(); if (preferred.Chosen()) { return preferred; } return Candidate.Ambiguous; }
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 nil is passed as a block argument prefer BlockParam over missing block: if (actualType == typeof(DynamicNull)) { 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 (actualType == typeof(MissingBlockParam)) { if (typeOne == typeof(BlockParam) && typeTwo == typeof(MissingBlockParam)) { return Candidate.Two; } if (typeOne == typeof(MissingBlockParam) && typeTwo == typeof(BlockParam)) { return Candidate.One; } } else if (actualType == typeof(BlockParam)) { if (typeOne == typeof(BlockParam) && typeTwo == typeof(MissingBlockParam)) { return Candidate.One; } if (typeOne == typeof(MissingBlockParam) && typeTwo == typeof(BlockParam)) { return Candidate.Two; } if (typeOne == typeof(BlockParam) && typeTwo == typeof(BlockParam)) { if (candidateOne.ProhibitNull) { return Candidate.One; } else if (candidateTwo.ProhibitNull) { return Candidate.Two; } } } return base.SelectBestConversionFor(arg, candidateOne, candidateTwo, level); }
private SimpleArgBuilder AddSimpleParameterMapping(ParameterInfo info, int index) { var param = CreateParameterWrapper(info); if (param.IsParamsDict) { _paramsDict = param; } else { _parameters.Add(param); } return new SimpleArgBuilder(info, info.ParameterType, index, param.IsParamsArray, param.IsParamsDict); }
private bool HasExplicitProtocolConversion(ParameterWrapper/*!*/ parameter) { return parameter.ParameterInfo != null && parameter.ParameterInfo.IsDefined(typeof(DefaultProtocolAttribute), false) && !parameter.IsParamsArray; // default protocol doesn't apply on param-array/dict itself, only on the expanded parameters }
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); }
/// <summary> /// Returns true if fromArg of type fromType can be assigned to toParameter with a conversion on given narrowing level. /// </summary> public override bool CanConvertFrom(Type/*!*/ fromType, DynamicMetaObject fromArg, ParameterWrapper/*!*/ toParameter, NarrowingLevel level) { return Converter.CanConvertFrom(fromArg, fromType, toParameter.Type, toParameter.ProhibitNull, level, HasExplicitProtocolConversion(toParameter), _implicitProtocolConversions ); }
public override bool CanConvertFrom(ParameterWrapper/*!*/ fromParameter, ParameterWrapper/*!*/ toParameter) { return Converter.CanConvertFrom(null, fromParameter.Type, toParameter.Type, toParameter.ProhibitNull, NarrowingLevel.None, false, false); }
internal Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo, Type argType) { Assert.NotNull(candidateOne, candidateTwo, argType); if (ParametersEquivalent(candidateOne, candidateTwo)) { return Candidate.Equivalent; } for (NarrowingLevel curLevel = NarrowingLevel.None; curLevel <= NarrowingLevel.All; curLevel++) { Candidate candidate = SelectBestConversionFor(argType, candidateOne, candidateTwo, curLevel); if (candidate.Chosen()) { return candidate; } } return GetPreferredParameter(candidateOne, candidateTwo); }
/// <summary> /// Returns true if fromArg of type fromType can be assigned to toParameter with a conversion on given narrowing level. /// </summary> public override bool CanConvertFrom(Type/*!*/ fromType, DynamicMetaObject fromArg, ParameterWrapper/*!*/ toParameter, NarrowingLevel level) { var result = Converter.CanConvertFrom(fromArg, fromType, toParameter.Type, toParameter.ProhibitNull, level, HasExplicitProtocolConversion(toParameter), _implicitProtocolConversions ); if (result.Assumption != null) { if (_argumentAssumptions == null) { _argumentAssumptions = new List<Key<int, NarrowingLevel, Ast>>(); } if (_argumentAssumptions.FindIndex((k) => k.First == toParameter.ParameterInfo.Position && k.Second == level) < 0) { _argumentAssumptions.Add(Key.Create(toParameter.ParameterInfo.Position, level, result.Assumption)); } } return result.IsConvertible; }
public void MapParameter(ParameterInfo pi) { int indexForArgBuilder; int nameIndex = _argNames.IndexOf(pi.Name); if (nameIndex == -1) { // positional argument, we simply consume the next argument indexForArgBuilder = _argIndex++; } else { // keyword argument, we just tell the simple arg builder to consume arg 0. // KeywordArgBuilder will then pass in the correct single argument based // upon the actual argument number provided by the user. indexForArgBuilder = 0; } // if the parameter is default we need to build a default arg builder and then // build a reduced method at the end. if (!CompilerHelpers.IsMandatoryParameter(pi)) { // We need to build the default builder even if we have a parameter for it already to // get good consistency of our error messages. But consider a method like // def foo(a=1, b=2) and the user calls it as foo(b=3). Then adding the default // value breaks an otherwise valid call. This is because we only generate MethodCandidates // filling in the defaults from right to left (so the method - 1 arg requires a, // and the method minus 2 args requires b). So we only add the default if it's // a positional arg or we don't already have a default value. if (nameIndex == -1 || !_hasDefaults) { _defaultArguments.Add(new DefaultArgBuilder(pi)); _hasDefaults = true; } else { _defaultArguments.Add(null); } } else if (_defaultArguments.Count > 0) { // non-contigious default parameter _defaultArguments.Add(null); } ArgBuilder ab; if (pi.ParameterType.IsByRef) { _hasByRefOrOut = true; Type refType = typeof(StrongBox<>).MakeGenericType(pi.ParameterType.GetElementType()); _parameters.Add(new ParameterWrapper(pi, refType, pi.Name, true, false, false, false)); ab = new ReferenceArgBuilder(pi, refType, indexForArgBuilder); } else if (BinderHelpers.IsParamDictionary(pi)) { _paramsDict = new ParameterWrapper(pi); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else if (pi.Position == 0 && CompilerHelpers.IsExtension(pi.Member)) { _parameters.Add(new ParameterWrapper(pi, pi.ParameterType, pi.Name, true, false, false, true)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else { _hasByRefOrOut |= CompilerHelpers.IsOutParameter(pi); _parameters.Add(new ParameterWrapper(pi)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } if (nameIndex == -1) { _arguments.Add(ab); } else { Debug.Assert(KeywordArgBuilder.BuilderExpectsSingleParameter(ab)); _arguments.Add(new KeywordArgBuilder(ab, _argNames.Count, nameIndex)); } }
public void AddParameter(ParameterWrapper parameter) { _parameters.Add(parameter); }
public override bool CanConvertFrom(Type/*!*/ fromType, ParameterWrapper/*!*/ toParameter, NarrowingLevel level) { Type toType = toParameter.Type; if (toType == fromType) { return true; } if (fromType == typeof(DynamicNull)) { if (toParameter.ProhibitNull) { return false; } if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) { return true; } if (!toType.IsValueType) { return true; } } // blocks: if (fromType == typeof(MissingBlockParam)) { return toType == typeof(BlockParam) && !toParameter.ProhibitNull; } if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam)) { return true; } // protocol conversions: if (toParameter.ParameterInfo != null && toParameter.ParameterInfo.IsDefined(typeof(DefaultProtocolAttribute), false) && // default protocol doesn't apply on param-array/dict itself, only on the expanded parameters: !toParameter.IsParamsArray) { // any type is potentially convertible, except for nil if [NotNull] is used or the target type is a value type: return fromType != typeof(DynamicNull) || !(toParameter.ProhibitNull || toType.IsValueType); } if (Converter.CanConvertFrom(fromType, toType, level, _implicitProtocolConversions)) { return true; } return false; }
public virtual bool ParametersEquivalent(ParameterWrapper parameter1, ParameterWrapper parameter2) { return parameter1.Type == parameter2.Type && parameter1.ProhibitNull == parameter2.ProhibitNull; }
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 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 Candidate SelectBestConversionFor(Type/*!*/ actualType, ParameterWrapper/*!*/ candidateOne, ParameterWrapper/*!*/ candidateTwo, NarrowingLevel level) { Type typeOne = candidateOne.Type; Type typeTwo = candidateTwo.Type; if (actualType == typeof(DynamicNull)) { // if nil is passed as a block argument prefer BlockParam over missing block; if (typeOne == typeof(BlockParam) && typeTwo == typeof(MissingBlockParam)) { return Candidate.One; } if (typeOne == typeof(MissingBlockParam) && typeTwo == typeof(BlockParam)) { return Candidate.Two; } } else { if (actualType == typeOne && candidateOne.ProhibitNull) { return Candidate.One; } if (actualType == typeTwo && candidateTwo.ProhibitNull) { return Candidate.Two; } } if (actualType == typeOne) { return Candidate.One; } if (actualType == typeTwo) { return Candidate.Two; } return Candidate.Equivalent; }
public void AddParameter(ParameterWrapper parameter) { _parameters.Add(parameter); }
/// <summary> /// Builds a new MethodCandidate which takes count arguments and the provided list of keyword arguments. /// /// The basic idea here is to figure out which parameters map to params or a dictionary params and /// fill in those spots w/ extra ParameterWrapper's. /// </summary> internal MethodCandidate MakeParamsExtended(ActionBinder binder, int count, SymbolId[] names) { Debug.Assert(BinderHelpers.IsParamsMethod(_target.Method)); List <ParameterWrapper> newParameters = new List <ParameterWrapper>(count); // if we don't have a param array we'll have a param dict which is type object Type elementType = null; int index = -1, kwIndex = -1; // keep track of which kw args map to a real argument, and which ones // map to the params dictionary. List <SymbolId> unusedNames = new List <SymbolId>(names); List <int> unusedNameIndexes = new List <int>(); for (int i = 0; i < unusedNames.Count; i++) { unusedNameIndexes.Add(i); } for (int i = 0; i < _parameters.Count; i++) { ParameterWrapper pw = _parameters[i]; if (_parameters[i].IsParamsDict) { kwIndex = i; } else if (_parameters[i].IsParamsArray) { elementType = pw.Type.GetElementType(); index = i; } else { for (int j = 0; j < unusedNames.Count; j++) { if (unusedNames[j] == _parameters[i].Name) { unusedNames.RemoveAt(j); unusedNameIndexes.RemoveAt(j); break; } } newParameters.Add(pw); } } if (index != -1) { while (newParameters.Count < (count - unusedNames.Count)) { ParameterWrapper param = new ParameterWrapper(binder, elementType, SymbolId.Empty, false); newParameters.Insert(System.Math.Min(index, newParameters.Count), param); } } if (kwIndex != -1) { foreach (SymbolId si in unusedNames) { newParameters.Add(new ParameterWrapper(binder, typeof(object), si, false)); } } else if (unusedNames.Count != 0) { // unbound kw args and no where to put them, can't call... // TODO: We could do better here because this results in an incorrect arg # error message. return(null); } // if we have too many or too few args we also can't call if (count != newParameters.Count) { return(null); } return(new MethodCandidate(_target.MakeParamsExtended(count, unusedNames.ToArray(), unusedNameIndexes.ToArray()), newParameters)); }
private void MapParameterReduceByRef(ParameterInfo pi) { Debug.Assert(_returnArgs != null); // See KeywordArgBuilder.BuilderExpectsSingleParameter int indexForArgBuilder = 0; int nameIndex = -1; if (!CompilerHelpers.IsOutParameter(pi)) { nameIndex = _argNames.IndexOf(pi.Name); if (nameIndex == -1) { indexForArgBuilder = _argIndex++; } } ArgBuilder ab; if (CompilerHelpers.IsOutParameter(pi)) { _returnArgs.Add(_arguments.Count); ab = new OutArgBuilder(pi); } else if (pi.ParameterType.IsByRef) { // if the parameter is marked as [In] it is not returned. if ((pi.Attributes & (ParameterAttributes.In | ParameterAttributes.Out)) != ParameterAttributes.In) { _returnArgs.Add(_arguments.Count); } _parameters.Add(new ParameterWrapper(pi, pi.ParameterType.GetElementType(), pi.Name, false, false, false, false)); ab = new ReturnReferenceArgBuilder(pi, indexForArgBuilder); } else if (BinderHelpers.IsParamDictionary(pi)) { _paramsDict = new ParameterWrapper(pi); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } else { _parameters.Add(new ParameterWrapper(pi)); ab = new SimpleArgBuilder(pi, indexForArgBuilder); } if (nameIndex == -1) { _arguments.Add(ab); } else { Debug.Assert(KeywordArgBuilder.BuilderExpectsSingleParameter(ab)); _arguments.Add(new KeywordArgBuilder(ab, _argNames.Count, nameIndex)); } }
/// <summary> /// Selects the best (of two) candidates for conversion from actualType /// </summary> public virtual Candidate SelectBestConversionFor(DynamicMetaObject arg, ParameterWrapper candidateOne, ParameterWrapper candidateTwo, NarrowingLevel level) { return Candidate.Equivalent; }
public virtual bool CanConvertFrom(ParameterWrapper parameter1, ParameterWrapper parameter2) { return CanConvertFrom(parameter1.Type, null, parameter2, NarrowingLevel.None); }
/// <summary> /// Selects the best (of two) candidates for conversion from actualType /// </summary> public virtual Candidate SelectBestConversionFor(Type actualType, ParameterWrapper candidateOne, ParameterWrapper candidateTwo, NarrowingLevel level) { return Candidate.Equivalent; }
private static Candidate GetPreferredParameter(ParameterWrapper candidateOne, ParameterWrapper candidateTwo, MetaObject 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.LimitType, candidateOne, candidateTwo, curLevel); if (candidate.Chosen()) { return candidate; } } return GetPreferredParameter(candidateOne, candidateTwo); }
public virtual bool CanConvertFrom(Type fromType, DynamicMetaObject fromArgument, ParameterWrapper toParameter, NarrowingLevel level) { Assert.NotNull(fromType, toParameter); Type toType = toParameter.Type; if (fromType == typeof(DynamicNull)) { if (toParameter.ProhibitNull) { return false; } if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) { return true; } if (!toType.IsValueType) { return true; } } if (fromType == toType) { return true; } return _binder.CanConvertFrom(fromType, toType, toParameter.ProhibitNull, level); }