-
Notifications
You must be signed in to change notification settings - Fork 310
fix bad-argument-count false positive with unpacking #3138 #3143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,7 @@ use pyrefly_util::prelude::SliceExt; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use pyrefly_util::prelude::VecExt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use pyrefly_util::visit::VisitMut; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ruff_python_ast::Expr; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ruff_python_ast::ExprSubscript; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ruff_python_ast::Identifier; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ruff_python_ast::Keyword; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use ruff_python_ast::name::Name; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -285,6 +286,11 @@ impl<'a> CallArg<'a> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let bounded_len = if let TypeOrExpr::Expr(Expr::Subscript(subscript)) = e { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::bounded_star_slice_len(subscript, solver, arg_errors) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let ty = e.infer(solver, arg_errors); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let iterables = solver.iterate(&ty, *_range, arg_errors, None); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If we have a union of iterables, use a fixed length only if every iterable is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -310,13 +316,43 @@ impl<'a> CallArg<'a> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let tys = fixed_tys.into_map(|tys| solver.unions(tys)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CallArgPreEval::Fixed(tys, 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if let Some(max_len) = bounded_len { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CallArgPreEval::Bounded(solver.get_produced_type(iterables), 0, max_len) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let ty = solver.get_produced_type(iterables); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CallArgPreEval::Star(ty, false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Some simple slices have a statically known upper bound on how many values | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// they can contribute when star-unpacked. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn bounded_star_slice_len<Ans: LookupAnswer>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| subscript: &ExprSubscript, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solver: &AnswersSolver<Ans>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| arg_errors: &ErrorCollector, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) -> Option<usize> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let Expr::Slice(slice) = &*subscript.slice else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return None; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if slice.step.is_some() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return None; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let parse_literal = |expr: &Option<Box<Expr>>| -> Option<i64> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let expr = expr.as_ref()?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| match solver.expr_infer(expr, arg_errors) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Type::Literal(lit) => lit.value.as_index_i64(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _ => None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let lower = parse_literal(&slice.lower)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let upper = parse_literal(&slice.upper)?; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (lower < 0 && upper >= 0) || (lower >= 0 && upper < 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return None; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| usize::try_from((upper - lower).max(0)).ok() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Pre-evaluated args are iterable. Type/Expr/Star variants iterate once (tracked via bool field), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -326,19 +362,25 @@ enum CallArgPreEval<'a> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Type(&'a Type, bool), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr(&'a Expr, bool), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Star(Type, bool), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Bounded(Type, usize, usize), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Fixed(Vec<Type>, usize), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| impl CallArgPreEval<'_> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn step(&self) -> bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| match self { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Type(_, done) | Self::Expr(_, done) | Self::Star(_, done) => !*done, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Bounded(_, consumed, max_len) => *consumed < *max_len, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Fixed(tys, i) => *i < tys.len(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn is_star(&self) -> bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matches!(self, Self::Star(..)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matches!(self, Self::Star(..) | Self::Bounded(..)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn is_bounded_star(&self) -> bool { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matches!(self, Self::Bounded(..)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Check the argument against a parameter hint and return the inferred argument type. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -381,6 +423,11 @@ impl CallArgPreEval<'_> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solver.check_type(ty, hint, range, call_errors, tcc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Some(ty.clone()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Bounded(ty, consumed, max_len) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *consumed = if vararg { *max_len } else { *consumed + 1 }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solver.check_type(ty, hint, range, call_errors, tcc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Some(ty.clone()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Fixed(tys, i) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let arg_ty = tys[*i].clone(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| solver.check_type(&arg_ty, hint, range, call_errors, tcc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -397,6 +444,9 @@ impl CallArgPreEval<'_> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Type(_, done) | Self::Expr(_, done) | Self::Star(_, done) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *done = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Bounded(_, consumed, max_len) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *consumed = *max_len; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Fixed(_, i) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *i += 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -409,6 +459,9 @@ impl CallArgPreEval<'_> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Type(_, done) | Self::Expr(_, done) | Self::Star(_, done) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *done = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Bounded(_, consumed, max_len) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *consumed = *max_len; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Self::Fixed(tys, i) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| *i = tys.len(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -616,6 +669,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut unpacked_vararg_matched_args: Vec<CallArgPreEval<'_>> = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut variadic_name: Option<&Name> = None; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let mut variadic_collected: Vec<Type> = Vec::new(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let positional_args = self_arg.iter().chain(args.iter()).collect::<Vec<_>>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Resolve a deferred ParamSpec Var into additional parameters. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Returns `Err(q)` when the Var resolved to a quantified ParamSpec `q` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -647,8 +701,25 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ok(param_list_owner.push(ps).items().iter().rev().collect()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for arg in self_arg.iter().chain(args.iter()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let min_remaining_positional_args = |args: &[&CallArg<'_>]| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args.iter() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(|arg| match arg { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CallArg::Arg(_) => 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CallArg::Star(TypeOrExpr::Expr(expr), _) => match expr { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr::List(list_expr) => list_expr.elts.len(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr::Set(set_expr) => set_expr.elts.len(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr::Tuple(tuple_expr) => tuple_expr.elts.len(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+709
to
+711
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr::List(list_expr) => list_expr.elts.len(), | |
| Expr::Set(set_expr) => set_expr.elts.len(), | |
| Expr::Tuple(tuple_expr) => tuple_expr.elts.len(), | |
| Expr::List(list_expr) => list_expr | |
| .elts | |
| .iter() | |
| .filter(|elt| !matches!(elt, Expr::Starred(_))) | |
| .count(), | |
| Expr::Set(set_expr) => set_expr | |
| .elts | |
| .iter() | |
| .filter(|elt| !matches!(elt, Expr::Starred(_))) | |
| .count(), | |
| Expr::Tuple(tuple_expr) => tuple_expr | |
| .elts | |
| .iter() | |
| .filter(|elt| !matches!(elt, Expr::Starred(_))) | |
| .count(), |
Copilot
AI
Apr 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remaining_positional_args is recomputed for every argument by scanning the suffix of positional_args, making this loop O(n^2) in the number of positional arguments. Since callable_infer_params is on a hot path, consider precomputing a suffix-min array once (single reverse pass) and indexing into it for each arg_idx to keep this O(n).
| let min_remaining_positional_args = |args: &[&CallArg<'_>]| { | |
| args.iter() | |
| .map(|arg| match arg { | |
| CallArg::Arg(_) => 1, | |
| CallArg::Star(TypeOrExpr::Expr(expr), _) => match expr { | |
| Expr::List(list_expr) => list_expr.elts.len(), | |
| Expr::Set(set_expr) => set_expr.elts.len(), | |
| Expr::Tuple(tuple_expr) => tuple_expr.elts.len(), | |
| _ => 0, | |
| }, | |
| CallArg::Star(..) => 0, | |
| }) | |
| .sum::<usize>() | |
| }; | |
| for (arg_idx, arg) in positional_args.iter().enumerate() { | |
| let arg = *arg; | |
| let mut arg_pre = arg.pre_eval(self, arg_errors); | |
| let remaining_positional_args = | |
| min_remaining_positional_args(&positional_args[arg_idx + 1..]); | |
| let positional_arg_count = |arg: &CallArg<'_>| match arg { | |
| CallArg::Arg(_) => 1, | |
| CallArg::Star(TypeOrExpr::Expr(expr), _) => match expr { | |
| Expr::List(list_expr) => list_expr.elts.len(), | |
| Expr::Set(set_expr) => set_expr.elts.len(), | |
| Expr::Tuple(tuple_expr) => tuple_expr.elts.len(), | |
| _ => 0, | |
| }, | |
| CallArg::Star(..) => 0, | |
| }; | |
| let mut remaining_positional_args_by_index = vec![0; positional_args.len() + 1]; | |
| for arg_idx in (0..positional_args.len()).rev() { | |
| remaining_positional_args_by_index[arg_idx] = | |
| remaining_positional_args_by_index[arg_idx + 1] | |
| + positional_arg_count(positional_args[arg_idx]); | |
| } | |
| for (arg_idx, arg) in positional_args.iter().enumerate() { | |
| let arg = *arg; | |
| let mut arg_pre = arg.pre_eval(self, arg_errors); | |
| let remaining_positional_args = remaining_positional_args_by_index[arg_idx + 1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bounded_star_slice_lenderives a max length purely from the slice bounds syntax and applies it to anyExpr::Subscriptslice. For user-defined__getitem__implementations, there is no guarantee thatobj[a:b]produces an iterable whose length is bounded byb-a, so this can suppress realbad-argument-counterrors. Consider gating this optimization to known built-in sequence types (e.g., list/tuple/str/bytes/range) or to cases where the inferred type of the subscript expression is a built-in sliceable sequence with standard semantics.