/// <summary> /// Builds the restrictions for calling with keyword arguments. The restrictions include /// tests on the individual keys of the dictionary to ensure they have the same names. /// </summary> private static BindingRestrictions MakeParamsDictionaryTest(IList <DynamicMetaObject> args, bool testTypes) { IDictionary dict = (IDictionary)args[args.Count - 1].Value; IDictionaryEnumerator dictEnum = dict.GetEnumerator(); // verify the dictionary has the same count and arguments. string[] names = new string[dict.Count]; Type[] types = testTypes ? new Type[dict.Count] : null; int index = 0; while (dictEnum.MoveNext()) { if (dictEnum.Entry.Key is string name) { names[index] = name; } else if (dictEnum.Entry.Key is Extensible <string> ename) { names[index] = ename.Value; } else { throw ScriptingRuntimeHelpers.SimpleTypeError( $"expected string for dictionary argument, got {dictEnum.Entry.Key}"); } if (types != null) { types[index] = CompilerHelpers.GetType(dictEnum.Entry.Value); } index++; } return(BindingRestrictions.GetExpressionRestriction( Expression.AndAlso( Expression.TypeIs(args[args.Count - 1].Expression, typeof(IDictionary)), Expression.Call( typeof(BinderOps).GetMethod(nameof(BinderOps.CheckDictionaryMembers)), Expression.Convert(args[args.Count - 1].Expression, typeof(IDictionary)), AstUtils.Constant(names), testTypes ? AstUtils.Constant(types) : AstUtils.Constant(null, typeof(Type[])) ) ) )); }
/// <summary> /// Throws a formatted exception if no overload matchs. /// </summary> /// <param name="sig">Passed signature which should be used</param> /// <param name="targets">Given targets, which does not fit to the signature</param> /// <example> /// <code language="cs" title="Cause overload exceptiob"><![CDATA[ /// # Will cause an exception: /// from System import Convert, Double /// Convert.ToInt32.Overloads[Double, Double](24) /// ]]></code> /// </example> public void ThrowOverloadException(Type[] sig, IList <MethodBase> targets) { // Create info for given signature System.Text.StringBuilder sigInfo = new System.Text.StringBuilder(); sigInfo.Append((targets.Count > 0 ? targets[0].Name : "") + "["); foreach (var type in sig) { if (!sigInfo.ToString().endswith("[")) { sigInfo.Append(", "); } sigInfo.Append(type.Name); } sigInfo.Append("]"); // Get possible overloads. System.Text.StringBuilder possibleOverloads = new System.Text.StringBuilder(); foreach (var overload in targets) { if (possibleOverloads.Length > 0) { possibleOverloads.Append(", "); } possibleOverloads.Append("["); foreach (var param in overload.GetParameters()) { if (!possibleOverloads.ToString().endswith("[")) { possibleOverloads.Append(", "); } possibleOverloads.Append(param.ParameterType.Name); } possibleOverloads.Append("]"); } throw ScriptingRuntimeHelpers.SimpleTypeError(String.Format("No match found for the method signature {0}. Expected {1}", sigInfo.ToString(), possibleOverloads.ToString())); }
private object GetOverload(Type[] sig, IList <MethodBase> targets, bool wrapCtors) { // We can still end up with more than one target since generic and non-generic // methods can share the same name and signature. So we'll build up a new // reflected method with all the candidate targets. A caller can then index this // reflected method if necessary in order to provide generic type arguments and // fully disambiguate the target. // Search for targets with the right number of arguments. BuiltinFunction bf; BuiltinFunction.TypeList tl = new BuiltinFunction.TypeList(sig); lock (_function.OverloadDictionary) { if (!_function.OverloadDictionary.TryGetValue(tl, out bf)) { MethodBase[] newTargets = FindMatchingTargets(sig, targets); if (targets == null) { throw ScriptingRuntimeHelpers.SimpleTypeError(String.Format("No match found for the method signature {0}", sig)); // TODO: Sig to usable display } _function.OverloadDictionary[tl] = bf = new BuiltinFunction(_function.Name, newTargets, Function.DeclaringType, _function.FunctionType); } } if (_instance != null) { return(bf.BindToInstance(_instance)); } else if (wrapCtors) { return(GetTargetFunction(bf)); } else { return(bf); } }
/// <summary> /// Builds the restrictions for calling with keyword arguments. The restrictions include /// tests on the individual keys of the dictionary to ensure they have the same names. /// </summary> private static Restrictions MakeParamsDictionaryTest(IList <MetaObject> args, bool testTypes) { IDictionary dict = (IDictionary)args[args.Count - 1].Value; IDictionaryEnumerator dictEnum = dict.GetEnumerator(); // verify the dictionary has the same count and arguments. string[] names = new string[dict.Count]; Type[] types = testTypes ? new Type[dict.Count] : null; int index = 0; while (dictEnum.MoveNext()) { string name = dictEnum.Entry.Key as string; if (name == null) { throw ScriptingRuntimeHelpers.SimpleTypeError(String.Format("expected string for dictionary argument got {0}", dictEnum.Entry.Key)); } names[index] = name; if (types != null) { types[index] = CompilerHelpers.GetType(dictEnum.Entry.Value); } index++; } return(Restrictions.GetExpressionRestriction( Ast.AndAlso( Ast.TypeIs(args[args.Count - 1].Expression, typeof(IDictionary)), Ast.Call( typeof(BinderOps).GetMethod("CheckDictionaryMembers"), Ast.Convert(args[args.Count - 1].Expression, typeof(IDictionary)), Ast.Constant(names), testTypes ? Ast.Constant(types) : Ast.Constant(null, typeof(Type[])) ) ) )); }