1
1
use std:: borrow:: Cow ;
2
- use std:: collections:: HashSet ;
3
2
use std:: collections:: hash_map:: { Entry , HashMap } ;
4
- use std:: fmt:: Write ;
3
+ use std:: fmt:: { self , Write } ;
5
4
use std:: mem;
6
5
7
6
use parser:: node:: {
@@ -1434,8 +1433,9 @@ fn macro_call_ensure_arg_count(
1434
1433
call. span ( ) ,
1435
1434
) ) ;
1436
1435
}
1437
- // First we list of arguments position then we remove them one by one.
1438
- let mut args = ( 0 ..def. args . len ( ) ) . collect :: < HashSet < _ > > ( ) ;
1436
+
1437
+ // First we list of arguments position, then we remove every argument with a value.
1438
+ let mut args: Vec < _ > = def. args . iter ( ) . map ( |& ( name, _) | Some ( name) ) . collect ( ) ;
1439
1439
for ( pos, arg) in call. args . iter ( ) . enumerate ( ) {
1440
1440
let pos = match * * arg {
1441
1441
Expr :: NamedArgument ( name, ..) => {
@@ -1444,11 +1444,11 @@ fn macro_call_ensure_arg_count(
1444
1444
_ => Some ( pos) ,
1445
1445
} ;
1446
1446
if let Some ( pos) = pos {
1447
- if !args . remove ( & pos) {
1447
+ if mem :: take ( & mut args [ pos] ) . is_none ( ) {
1448
1448
// This argument was already passed, so error.
1449
1449
return Err ( ctx. generate_error (
1450
1450
format_args ! (
1451
- "argument `{}` is passed more than once when calling macro `{}`" ,
1451
+ "argument `{}` was passed more than once when calling macro `{}`" ,
1452
1452
def. args[ pos] . 0 , def. name,
1453
1453
) ,
1454
1454
call. span ( ) ,
@@ -1457,41 +1457,55 @@ fn macro_call_ensure_arg_count(
1457
1457
}
1458
1458
}
1459
1459
1460
- // Now we need to filter out arguments with default value.
1461
- let args = args
1462
- . into_iter ( )
1463
- . filter ( |pos| def. args [ * pos] . 1 . is_none ( ) )
1464
- . collect :: < Vec < _ > > ( ) ;
1465
- let ( extra, error) = match args. len ( ) {
1466
- 0 => return Ok ( ( ) ) ,
1467
- 1 => ( "" , format ! ( "`{}`" , def. args[ 0 ] . 0 ) ) ,
1468
- 2 => ( "s" , format ! ( "`{}` and `{}`" , def. args[ 0 ] . 0 , def. args[ 1 ] . 0 ) ) ,
1469
- _ => {
1470
- let mut error_s =
1471
- args. iter ( )
1472
- . take ( args. len ( ) - 2 )
1473
- . fold ( String :: new ( ) , |mut acc, arg| {
1474
- if !acc. is_empty ( ) {
1475
- acc. push_str ( ", " ) ;
1476
- }
1477
- acc. push_str ( & format ! ( "`{}`" , def. args[ * arg] . 0 ) ) ;
1478
- acc
1479
- } ) ;
1480
- error_s. push_str ( & format ! (
1481
- " and `{}`" ,
1482
- def. args[ * args. last( ) . expect( "no last args" ) ] . 0
1483
- ) ) ;
1484
- ( "s" , error_s)
1460
+ // Now we can check off arguments with a default value, too.
1461
+ for ( pos, ( _, dflt) ) in def. args . iter ( ) . enumerate ( ) {
1462
+ if dflt. is_some ( ) {
1463
+ args[ pos] = None ;
1485
1464
}
1486
- } ;
1465
+ }
1466
+
1467
+ // Now that we have a needed information, we can print an error message (if needed).
1468
+ struct FmtMissing < ' a , I > {
1469
+ count : usize ,
1470
+ missing : I ,
1471
+ name : & ' a str ,
1472
+ }
1473
+
1474
+ impl < ' a , I : Iterator < Item = & ' a str > + Clone > fmt:: Display for FmtMissing < ' a , I > {
1475
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1476
+ if self . count == 1 {
1477
+ let a = self . missing . clone ( ) . next ( ) . unwrap ( ) ;
1478
+ write ! (
1479
+ f,
1480
+ "missing argument when calling macro `{}`: `{a}`" ,
1481
+ self . name
1482
+ )
1483
+ } else {
1484
+ write ! ( f, "missing arguments when calling macro `{}`: " , self . name) ?;
1485
+ for ( idx, a) in self . missing . clone ( ) . enumerate ( ) {
1486
+ if idx == self . count - 1 {
1487
+ write ! ( f, " and " ) ?;
1488
+ } else if idx > 0 {
1489
+ write ! ( f, ", " ) ?;
1490
+ }
1491
+ write ! ( f, "`{a}`" ) ?;
1492
+ }
1493
+ Ok ( ( ) )
1494
+ }
1495
+ }
1496
+ }
1487
1497
1488
- Err ( ctx. generate_error (
1489
- format_args ! (
1490
- "missing argument{extra} when calling macro `{}`: {error}" ,
1491
- def. name
1492
- ) ,
1493
- call. span ( ) ,
1494
- ) )
1498
+ let missing = args. iter ( ) . filter_map ( Option :: as_deref) ;
1499
+ let fmt_missing = FmtMissing {
1500
+ count : missing. clone ( ) . count ( ) ,
1501
+ missing,
1502
+ name : def. name ,
1503
+ } ;
1504
+ if fmt_missing. count == 0 {
1505
+ Ok ( ( ) )
1506
+ } else {
1507
+ Err ( ctx. generate_error ( fmt_missing, call. span ( ) ) )
1508
+ }
1495
1509
}
1496
1510
1497
1511
#[ derive( Clone , Copy , PartialEq ) ]
0 commit comments