@@ -23,6 +23,7 @@ enum ArgumentType {
23
23
24
24
enum Position {
25
25
Exact ( usize ) ,
26
+ Capture ( usize ) ,
26
27
Named ( Symbol ) ,
27
28
}
28
29
@@ -47,6 +48,8 @@ struct Context<'a, 'b> {
47
48
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
48
49
/// * `names` (in JSON): `{"foo": 2}`
49
50
args : Vec < P < ast:: Expr > > ,
51
+ /// The number of arguments that were added by implicit capturing.
52
+ num_captured_args : usize ,
50
53
/// Placeholder slot numbers indexed by argument.
51
54
arg_types : Vec < Vec < usize > > ,
52
55
/// Unique format specs seen for each argument.
@@ -229,6 +232,11 @@ fn parse_args<'a>(
229
232
}
230
233
231
234
impl < ' a , ' b > Context < ' a , ' b > {
235
+ /// The number of arguments that were explicitly given.
236
+ fn num_args ( & self ) -> usize {
237
+ self . args . len ( ) - self . num_captured_args
238
+ }
239
+
232
240
fn resolve_name_inplace ( & self , p : & mut parse:: Piece < ' _ > ) {
233
241
// NOTE: the `unwrap_or` branch is needed in case of invalid format
234
242
// arguments, e.g., `format_args!("{foo}")`.
@@ -343,7 +351,7 @@ impl<'a, 'b> Context<'a, 'b> {
343
351
}
344
352
345
353
fn describe_num_args ( & self ) -> Cow < ' _ , str > {
346
- match self . args . len ( ) {
354
+ match self . num_args ( ) {
347
355
0 => "no arguments were given" . into ( ) ,
348
356
1 => "there is 1 argument" . into ( ) ,
349
357
x => format ! ( "there are {} arguments" , x) . into ( ) ,
@@ -369,7 +377,7 @@ impl<'a, 'b> Context<'a, 'b> {
369
377
370
378
let count = self . pieces . len ( )
371
379
+ self . arg_with_formatting . iter ( ) . filter ( |fmt| fmt. precision_span . is_some ( ) ) . count ( ) ;
372
- if self . names . is_empty ( ) && !numbered_position_args && count != self . args . len ( ) {
380
+ if self . names . is_empty ( ) && !numbered_position_args && count != self . num_args ( ) {
373
381
e = self . ecx . struct_span_err (
374
382
sp,
375
383
& format ! (
@@ -417,7 +425,7 @@ impl<'a, 'b> Context<'a, 'b> {
417
425
if let Some ( span) = fmt. precision_span {
418
426
let span = self . fmtsp . from_inner ( span) ;
419
427
match fmt. precision {
420
- parse:: CountIsParam ( pos) if pos > self . args . len ( ) => {
428
+ parse:: CountIsParam ( pos) if pos > self . num_args ( ) => {
421
429
e. span_label (
422
430
span,
423
431
& format ! (
@@ -460,7 +468,7 @@ impl<'a, 'b> Context<'a, 'b> {
460
468
if let Some ( span) = fmt. width_span {
461
469
let span = self . fmtsp . from_inner ( span) ;
462
470
match fmt. width {
463
- parse:: CountIsParam ( pos) if pos > self . args . len ( ) => {
471
+ parse:: CountIsParam ( pos) if pos > self . num_args ( ) => {
464
472
e. span_label (
465
473
span,
466
474
& format ! (
@@ -492,12 +500,15 @@ impl<'a, 'b> Context<'a, 'b> {
492
500
/// Actually verifies and tracks a given format placeholder
493
501
/// (a.k.a. argument).
494
502
fn verify_arg_type ( & mut self , arg : Position , ty : ArgumentType ) {
503
+ if let Exact ( arg) = arg {
504
+ if arg >= self . num_args ( ) {
505
+ self . invalid_refs . push ( ( arg, self . curpiece ) ) ;
506
+ return ;
507
+ }
508
+ }
509
+
495
510
match arg {
496
- Exact ( arg) => {
497
- if self . args . len ( ) <= arg {
498
- self . invalid_refs . push ( ( arg, self . curpiece ) ) ;
499
- return ;
500
- }
511
+ Exact ( arg) | Capture ( arg) => {
501
512
match ty {
502
513
Placeholder ( _) => {
503
514
// record every (position, type) combination only once
@@ -524,7 +535,7 @@ impl<'a, 'b> Context<'a, 'b> {
524
535
match self . names . get ( & name) {
525
536
Some ( & idx) => {
526
537
// Treat as positional arg.
527
- self . verify_arg_type ( Exact ( idx) , ty)
538
+ self . verify_arg_type ( Capture ( idx) , ty)
528
539
}
529
540
None => {
530
541
// For the moment capturing variables from format strings expanded from macros is
@@ -539,9 +550,10 @@ impl<'a, 'b> Context<'a, 'b> {
539
550
} else {
540
551
self . fmtsp
541
552
} ;
553
+ self . num_captured_args += 1 ;
542
554
self . args . push ( self . ecx . expr_ident ( span, Ident :: new ( name, span) ) ) ;
543
555
self . names . insert ( name, idx) ;
544
- self . verify_arg_type ( Exact ( idx) , ty)
556
+ self . verify_arg_type ( Capture ( idx) , ty)
545
557
} else {
546
558
let msg = format ! ( "there is no argument named `{}`" , name) ;
547
559
let sp = if self . is_literal {
@@ -1010,6 +1022,7 @@ pub fn expand_preparsed_format_args(
1010
1022
let mut cx = Context {
1011
1023
ecx,
1012
1024
args,
1025
+ num_captured_args : 0 ,
1013
1026
arg_types,
1014
1027
arg_unique_types,
1015
1028
names,
0 commit comments