/// <summary> /// Binds named arguments to the parameters. Returns a permutation of indices that captures the relationship between /// named arguments and their corresponding parameters. Checks for duplicate and unbound named arguments. /// /// Ensures that for all i: namedArgs[i] binds to parameters[args.Length + bindingPermutation[i]] /// </summary> internal bool TryBindNamedArguments(MethodCandidate method, out ArgumentBinding binding, out CallFailure failure) { if (_namedArgs.Count == 0) { binding = new ArgumentBinding(_args.Count); failure = null; return true; } var permutation = new int[_namedArgs.Count]; var boundParameters = new BitArray(_namedArgs.Count); for (int i = 0; i < permutation.Length; i++) { permutation[i] = -1; } List<string> unboundNames = null; List<string> duppedNames = null; int positionalArgCount = _args.Count; for (int i = 0; i < _names.Count; i++) { int paramIndex = method.IndexOfParameter(_names[i]); if (paramIndex >= 0) { int nameIndex = paramIndex - positionalArgCount; // argument maps to already bound parameter: if (paramIndex < positionalArgCount || boundParameters[nameIndex]) { if (duppedNames == null) { duppedNames = new List<string>(); } duppedNames.Add(_names[i]); } else { permutation[i] = nameIndex; boundParameters[nameIndex] = true; } } else { if (unboundNames == null) { unboundNames = new List<string>(); } unboundNames.Add(_names[i]); } } binding = new ArgumentBinding(positionalArgCount, permutation); if (unboundNames != null) { failure = new CallFailure(method, unboundNames.ToArray(), true); return false; } else if (duppedNames != null) { failure = new CallFailure(method, duppedNames.ToArray(), false); return false; } failure = null; return true; }
/// <summary> /// Creates a new BindingTarget when the method binding has failued due to /// one or more parameters which could not be converted. /// </summary> internal BindingTarget(string name, int actualArgumentCount, CallFailure[] failures) { _name = name; _result = BindingResult.CallFailure; _callFailures = failures; _actualArgs = actualArgumentCount; }
private BindingTarget MakeFailedBindingTarget(CallFailure[] failures) { return new BindingTarget(_methodName, _actualArguments.VisibleCount, failures); }
private bool TryConvertCollapsedArguments(MethodCandidate candidate, NarrowingLevel narrowingLevel, out CallFailure failure) { Debug.Assert(_actualArguments.CollapsedCount > 0); // There must be at least one expanded parameter preceding splat index (see MethodBinder.GetSplatLimits): ParameterWrapper parameter = candidate.GetParameter(_actualArguments.SplatIndex - 1); Debug.Assert(parameter.ParameterInfo != null && CompilerHelpers.IsParamArray(parameter.ParameterInfo)); for (int i = 0; i < _actualArguments.CollapsedCount; i++) { object value = GetCollapsedArgumentValue(i); Type argType = CompilerHelpers.GetType(value); if (!CanConvertFrom(argType, null, parameter, narrowingLevel)) { failure = new CallFailure(candidate, new[] { new ConversionResult(value, argType, parameter.Type, false) }); return false; } } failure = null; return true; }
private bool TryConvertArguments(MethodCandidate candidate, ArgumentBinding namesBinding, NarrowingLevel narrowingLevel, out CallFailure failure) { Debug.Assert(_actualArguments.Count == candidate.ParameterCount); BitArray hasConversion = new BitArray(_actualArguments.Count); bool success = true; for (int i = 0; i < _actualArguments.Count; i++) { success &= (hasConversion[i] = CanConvertFrom(_actualArguments[i].GetLimitType(), _actualArguments[i], candidate.GetParameter(i, namesBinding), narrowingLevel)); } if (!success) { var conversionResults = new ConversionResult[_actualArguments.Count]; for (int i = 0; i < _actualArguments.Count; i++) { conversionResults[i] = new ConversionResult(_actualArguments[i].Value, _actualArguments[i].GetLimitType(), candidate.GetParameter(i, namesBinding).Type, !hasConversion[i]); } failure = new CallFailure(candidate, conversionResults); } else { failure = null; } return success; }
private static void AddFailure(ref List<CallFailure> failures, CallFailure failure) { if (failures == null) { failures = new List<CallFailure>(1); } failures.Add(failure); }
/// <summary> /// Binds named arguments to the parameters. Returns a permutation of indices that captures the relationship between /// named arguments and their corresponding parameters. Checks for duplicate and unbound named arguments. /// Ensures that for all i: namedArgs[i] binds to parameters[args.Length + bindingPermutation[i]] /// </summary> internal bool TryBindNamedArguments(MethodCandidate method, out ArgumentBinding binding, out CallFailure failure) { if (NamedArguments.Count == 0) { binding = new ArgumentBinding(Arguments.Count); failure = null; return(true); } var permutation = new int[NamedArguments.Count]; var boundParameters = new BitArray(NamedArguments.Count); for (int i = 0; i < permutation.Length; i++) { permutation[i] = -1; } List <string> unboundNames = null; List <string> duppedNames = null; List <int> duppedPositionals = null; int positionalArgCount = Arguments.Count; for (int i = 0; i < ArgNames.Count; i++) { int paramIndex = method.IndexOfParameter(ArgNames[i]); if (paramIndex >= 0) { int nameIndex = paramIndex - positionalArgCount; if (paramIndex < positionalArgCount) { // argument maps to already bound positional parameter duppedNames ??= new List <string>(); duppedPositionals ??= Enumerable.Repeat(0, duppedNames.Count).ToList(); duppedNames.Add(ArgNames[i]); duppedPositionals.Add(method.PositionOfParameter(ArgNames[i])); } else if (boundParameters[nameIndex]) { // argument maps to already bound named parameter duppedNames ??= new List <string>(); duppedNames.Add(ArgNames[i]); duppedPositionals?.Add(0); } else { permutation[i] = nameIndex; boundParameters[nameIndex] = true; } } else { unboundNames ??= new List <string>(); unboundNames.Add(ArgNames[i]); } } Debug.Assert(duppedPositionals == null || (duppedNames != null && duppedNames.Count == duppedPositionals.Count)); binding = new ArgumentBinding(positionalArgCount, permutation); if (unboundNames != null) { failure = new CallFailure(method, unboundNames.ToArray()); return(false); } if (duppedNames != null) { failure = new CallFailure(method, duppedNames.ToArray(), duppedPositionals?.ToArray()); return(false); } failure = null; return(true); }
internal bool TryGetNormalizedArguments <T>(T[] argTypes, SymbolId[] names, out T[] args, out CallFailure failure) { if (names.Length == 0) { // no named arguments, success! args = argTypes; failure = null; return(true); } T[] res = new T[argTypes.Length]; Array.Copy(argTypes, res, argTypes.Length - names.Length); List <SymbolId> unboundNames = null; List <SymbolId> duppedNames = null; for (int i = 0; i < names.Length; i++) { bool found = false; for (int j = 0; j < _parameters.Count; j++) { if (_parameters[j].Name == names[i]) { found = true; if (res[j] != null) { if (duppedNames == null) { duppedNames = new List <SymbolId>(); } duppedNames.Add(names[i]); } else { res[j] = argTypes[i + argTypes.Length - names.Length]; } break; } } if (!found) { if (unboundNames == null) { unboundNames = new List <SymbolId>(); } unboundNames.Add(names[i]); } } if (unboundNames != null) { failure = new CallFailure(Target, unboundNames.ToArray(), true); args = null; return(false); } else if (duppedNames != null) { failure = new CallFailure(Target, duppedNames.ToArray(), false); args = null; return(false); } failure = null; args = res; return(true); }