diff --git a/Src/IronPython/Runtime/Binding/MetaPythonFunction.cs b/Src/IronPython/Runtime/Binding/MetaPythonFunction.cs index cd492f595..d2bc0044c 100644 --- a/Src/IronPython/Runtime/Binding/MetaPythonFunction.cs +++ b/Src/IronPython/Runtime/Binding/MetaPythonFunction.cs @@ -551,6 +551,7 @@ private bool TryFinishList(Expression[] exprArgs, List paramsArgs) { // make a single copy. exprArgs[_func.Value.ExpandListPosition] = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.GetOrCopyParamsTuple)), + _codeContext ?? AstUtils.Constant(DefaultContext.Default), GetFunctionParam(), AstUtils.Convert(_userProvidedParams, typeof(object)) ); @@ -653,7 +654,7 @@ private void AddCheckForNoExtraParameters(Expression[] exprArgs) { Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.CheckParamsZero)), AstUtils.Convert(GetFunctionParam(), typeof(PythonFunction)), - _params + _params // Queue ) ); } else if (_userProvidedParams != null) { @@ -805,7 +806,7 @@ private Expression ExtractDefaultValue(string argName, int dfltIndex) { AstUtils.Convert(GetFunctionParam(), typeof(PythonFunction)), AstUtils.Constant(dfltIndex), AstUtils.Constant(argName, typeof(string)), - VariableOrNull(_params, typeof(PythonList)), + VariableOrNull(_params, typeof(Queue)), VariableOrNull(_dict, typeof(PythonDictionary)) ); } @@ -843,7 +844,7 @@ private Expression ExtractFromListOrDictionary(string name) { AstUtils.Convert(GetFunctionParam(), typeof(PythonFunction)), // function AstUtils.Constant(name, typeof(string)), // name _paramsLen, // arg count - _params, // params list + _params, // Queue AstUtils.Convert(_dict, typeof(IDictionary)) // dictionary ); } @@ -860,17 +861,13 @@ private void EnsureParams() { /// Helper function to extract the next argument from the params list. /// private Expression ExtractNextParamsArg() { - if (!_extractedParams) { - MakeParamsCopy(_userProvidedParams); - - _extractedParams = true; - } + EnsureParams(); return Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.ExtractParamsArgument)), AstUtils.Convert(GetFunctionParam(), typeof(PythonFunction)), // function AstUtils.Constant(Signature.ArgumentCount), // arg count - _params // list + _params // Queue ); } @@ -945,7 +942,7 @@ private static Expression VariableOrNull(ParameterExpression var, Type type) { private void MakeParamsCopy(Expression/*!*/ userList) { Debug.Assert(_params == null); - _temps.Add(_params = Ast.Variable(typeof(PythonList), "$list")); + _temps.Add(_params = Ast.Variable(typeof(Queue), "$list")); _temps.Add(_paramsLen = Ast.Variable(typeof(int), "$paramsLen")); EnsureInit(); @@ -965,7 +962,7 @@ private void MakeParamsCopy(Expression/*!*/ userList) { _init.Add( Ast.Assign(_paramsLen, Ast.Add( - Ast.Call(_params, typeof(PythonList).GetMethod(nameof(PythonList.__len__))), + Ast.Property(_params, nameof(Queue.Count)), AstUtils.Constant(Signature.GetProvidedPositionalArgumentCount()) ) ) diff --git a/Src/IronPython/Runtime/Operations/PythonOps.cs b/Src/IronPython/Runtime/Operations/PythonOps.cs index 380c5006f..2d4554f9b 100644 --- a/Src/IronPython/Runtime/Operations/PythonOps.cs +++ b/Src/IronPython/Runtime/Operations/PythonOps.cs @@ -938,7 +938,7 @@ internal static bool TryInvokeLengthHint(CodeContext context, object? sequence, return CallWithContext(context, func, args); } - [Obsolete("Use ObjectOpertaions instead")] + [Obsolete("Use ObjectOperations instead")] public static object? CallWithArgsTupleAndKeywordDictAndContext(CodeContext/*!*/ context, object func, object[] args, string[] names, object argsTuple, object kwDict) { IDictionary? kws = kwDict as IDictionary; if (kws == null && kwDict != null) throw PythonOps.TypeError("argument after ** must be a dictionary"); @@ -2634,11 +2634,26 @@ public static void VerifyUnduplicatedByName(PythonFunction function, string name } - public static PythonList CopyAndVerifyParamsList(CodeContext context, PythonFunction function, object list) { - return new PythonList(context, list); + [EditorBrowsable(EditorBrowsableState.Never)] + public static Queue CopyAndVerifyParamsList(CodeContext context, PythonFunction function, object list) { + if (list is not IEnumerable e) { + if (!TryGetEnumerator(context, list, out IEnumerator? enumerator)) { + // TODO: CPython 3.5 uses "an iterable" in the error message instead of "a sequence" + throw TypeError($"{function.__name__}() argument after * must be a sequence, not {PythonOps.GetPythonTypeName(list)}"); + } + e = IEnumerableFromEnumerator(enumerator); + } + return new Queue(e); + + static IEnumerable IEnumerableFromEnumerator(IEnumerator ie) { + while (ie.MoveNext()) { + yield return ie.Current; + } + } } - public static PythonTuple UserMappingToPythonTuple(CodeContext/*!*/ context, object list, string funcName) { + [EditorBrowsable(EditorBrowsableState.Never)] + public static PythonTuple UserMappingToPythonTuple(CodeContext/*!*/ context, object? list, string funcName) { if (!TryGetEnumeratorObject(context, list, out object? enumerator)) { // TODO: CPython 3.5 uses "an iterable" in the error message instead of "a sequence" throw TypeError($"{funcName}() argument after * must be a sequence, not {PythonOps.GetPythonTypeName(list)}"); @@ -2647,35 +2662,43 @@ public static PythonTuple UserMappingToPythonTuple(CodeContext/*!*/ context, obj return PythonTuple.Make(enumerator); } - public static PythonTuple GetOrCopyParamsTuple(PythonFunction function, object input) { - if (input == null) { - throw PythonOps.TypeError("{0}() argument after * must be a sequence, not NoneType", function.__name__); + [EditorBrowsable(EditorBrowsableState.Never)] + public static PythonTuple GetOrCopyParamsTuple(CodeContext/*!*/ context, PythonFunction function, object? input) { + if (input is PythonTuple t && t.GetType() == typeof(PythonTuple)) { + return t; } - - return PythonTuple.Make(input); + return UserMappingToPythonTuple(context, input, function.__name__); } - public static object? ExtractParamsArgument(PythonFunction function, int argCnt, PythonList list) { - if (list.__len__() != 0) { - return list.pop(0); + [EditorBrowsable(EditorBrowsableState.Never)] + public static object? ExtractParamsArgument(PythonFunction function, int argCnt, Queue list) { + if (list.Count != 0) { + return list.Dequeue(); } throw function.BadArgumentError(argCnt); } - public static void AddParamsArguments(PythonList list, params object[] args) { - for (int i = 0; i < args.Length; i++) { - list.insert(i, args[i]); + [EditorBrowsable(EditorBrowsableState.Never)] + public static void AddParamsArguments(Queue list, params object[] args) { + var len = list.Count; + foreach (var arg in args) { + list.Enqueue(arg); + } + // put existing arguments at the end + for (int i = 0; i < len; i++) { + list.Enqueue(list.Dequeue()); } } /// /// Extracts an argument from either the dictionary or params /// - public static object? ExtractAnyArgument(PythonFunction function, string name, int argCnt, PythonList list, IDictionary dict) { + [EditorBrowsable(EditorBrowsableState.Never)] + public static object? ExtractAnyArgument(PythonFunction function, string name, int argCnt, Queue list, IDictionary dict) { object? val; if (dict.Contains(name)) { - if (list.__len__() != 0) { + if (list.Count != 0) { throw MultipleKeywordArgumentError(function, name); } val = dict[name]; @@ -2683,8 +2706,8 @@ public static void AddParamsArguments(PythonList list, params object[] args) { return val; } - if (list.__len__() != 0) { - return list.pop(0); + if (list.Count != 0) { + return list.Dequeue(); } if (function.ExpandDictPosition == -1 && dict.Count > 0) { @@ -2726,9 +2749,10 @@ public static ArgumentTypeException SimpleTypeError(string message) { return function.Defaults[index]; } - public static object? GetFunctionParameterValue(PythonFunction function, int index, string name, PythonList? extraArgs, PythonDictionary? dict) { - if (extraArgs != null && extraArgs.__len__() > 0) { - return extraArgs.pop(0); + [EditorBrowsable(EditorBrowsableState.Never)] + public static object? GetFunctionParameterValue(PythonFunction function, int index, string name, Queue? extraArgs, PythonDictionary? dict) { + if (extraArgs != null && extraArgs.Count > 0) { + return extraArgs.Dequeue(); } if (dict != null && dict.TryRemoveValue(name, out object val)) { @@ -2746,9 +2770,10 @@ public static ArgumentTypeException SimpleTypeError(string message) { return function.__kwdefaults__?[name]; } - public static void CheckParamsZero(PythonFunction function, PythonList extraArgs) { - if (extraArgs.__len__() != 0) { - throw function.BadArgumentError(extraArgs.__len__() + function.NormalArgumentCount); + [EditorBrowsable(EditorBrowsableState.Never)] + public static void CheckParamsZero(PythonFunction function, Queue extraArgs) { + if (extraArgs.Count != 0) { + throw function.BadArgumentError(extraArgs.Count + function.NormalArgumentCount); } }