@@ -25,6 +25,7 @@ enum ArgumentType {
25
25
26
26
enum Position {
27
27
Exact ( usize ) ,
28
+ Capture ( usize ) ,
28
29
Named ( Symbol ) ,
29
30
}
30
31
@@ -49,6 +50,8 @@ struct Context<'a, 'b> {
49
50
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
50
51
/// * `names` (in JSON): `{"foo": 2}`
51
52
args : Vec < P < ast:: Expr > > ,
53
+ /// The number of arguments that were added by implicit capturing.
54
+ num_captured_args : usize ,
52
55
/// Placeholder slot numbers indexed by argument.
53
56
arg_types : Vec < Vec < usize > > ,
54
57
/// Unique format specs seen for each argument.
@@ -231,6 +234,11 @@ fn parse_args<'a>(
231
234
}
232
235
233
236
impl < ' a , ' b > Context < ' a , ' b > {
237
+ /// The number of arguments that were explicitly given.
238
+ fn num_args ( & self ) -> usize {
239
+ self . args . len ( ) - self . num_captured_args
240
+ }
241
+
234
242
fn resolve_name_inplace ( & self , p : & mut parse:: Piece < ' _ > ) {
235
243
// NOTE: the `unwrap_or` branch is needed in case of invalid format
236
244
// arguments, e.g., `format_args!("{foo}")`.
@@ -345,7 +353,7 @@ impl<'a, 'b> Context<'a, 'b> {
345
353
}
346
354
347
355
fn describe_num_args ( & self ) -> Cow < ' _ , str > {
348
- match self . args . len ( ) {
356
+ match self . num_args ( ) {
349
357
0 => "no arguments were given" . into ( ) ,
350
358
1 => "there is 1 argument" . into ( ) ,
351
359
x => format ! ( "there are {} arguments" , x) . into ( ) ,
@@ -371,7 +379,7 @@ impl<'a, 'b> Context<'a, 'b> {
371
379
372
380
let count = self . pieces . len ( )
373
381
+ self . arg_with_formatting . iter ( ) . filter ( |fmt| fmt. precision_span . is_some ( ) ) . count ( ) ;
374
- if self . names . is_empty ( ) && !numbered_position_args && count != self . args . len ( ) {
382
+ if self . names . is_empty ( ) && !numbered_position_args && count != self . num_args ( ) {
375
383
e = self . ecx . struct_span_err (
376
384
sp,
377
385
& format ! (
@@ -419,7 +427,7 @@ impl<'a, 'b> Context<'a, 'b> {
419
427
if let Some ( span) = fmt. precision_span {
420
428
let span = self . fmtsp . from_inner ( span) ;
421
429
match fmt. precision {
422
- parse:: CountIsParam ( pos) if pos > self . args . len ( ) => {
430
+ parse:: CountIsParam ( pos) if pos > self . num_args ( ) => {
423
431
e. span_label (
424
432
span,
425
433
& format ! (
@@ -462,7 +470,7 @@ impl<'a, 'b> Context<'a, 'b> {
462
470
if let Some ( span) = fmt. width_span {
463
471
let span = self . fmtsp . from_inner ( span) ;
464
472
match fmt. width {
465
- parse:: CountIsParam ( pos) if pos > self . args . len ( ) => {
473
+ parse:: CountIsParam ( pos) if pos > self . num_args ( ) => {
466
474
e. span_label (
467
475
span,
468
476
& format ! (
@@ -494,12 +502,15 @@ impl<'a, 'b> Context<'a, 'b> {
494
502
/// Actually verifies and tracks a given format placeholder
495
503
/// (a.k.a. argument).
496
504
fn verify_arg_type ( & mut self , arg : Position , ty : ArgumentType ) {
505
+ if let Exact ( arg) = arg {
506
+ if arg >= self . num_args ( ) {
507
+ self . invalid_refs . push ( ( arg, self . curpiece ) ) ;
508
+ return ;
509
+ }
510
+ }
511
+
497
512
match arg {
498
- Exact ( arg) => {
499
- if self . args . len ( ) <= arg {
500
- self . invalid_refs . push ( ( arg, self . curpiece ) ) ;
501
- return ;
502
- }
513
+ Exact ( arg) | Capture ( arg) => {
503
514
match ty {
504
515
Placeholder ( _) => {
505
516
// record every (position, type) combination only once
@@ -526,7 +537,7 @@ impl<'a, 'b> Context<'a, 'b> {
526
537
match self . names . get ( & name) {
527
538
Some ( & idx) => {
528
539
// Treat as positional arg.
529
- self . verify_arg_type ( Exact ( idx) , ty)
540
+ self . verify_arg_type ( Capture ( idx) , ty)
530
541
}
531
542
None => {
532
543
// For the moment capturing variables from format strings expanded from macros is
@@ -541,9 +552,10 @@ impl<'a, 'b> Context<'a, 'b> {
541
552
} else {
542
553
self . fmtsp
543
554
} ;
555
+ self . num_captured_args += 1 ;
544
556
self . args . push ( self . ecx . expr_ident ( span, Ident :: new ( name, span) ) ) ;
545
557
self . names . insert ( name, idx) ;
546
- self . verify_arg_type ( Exact ( idx) , ty)
558
+ self . verify_arg_type ( Capture ( idx) , ty)
547
559
} else {
548
560
let msg = format ! ( "there is no argument named `{}`" , name) ;
549
561
let sp = if self . is_literal {
@@ -1051,6 +1063,7 @@ pub fn expand_preparsed_format_args(
1051
1063
let mut cx = Context {
1052
1064
ecx,
1053
1065
args,
1066
+ num_captured_args : 0 ,
1054
1067
arg_types,
1055
1068
arg_unique_types,
1056
1069
names,
0 commit comments