11use std:: borrow:: Cow ;
2- use std:: collections:: HashSet ;
32use std:: collections:: hash_map:: { Entry , HashMap } ;
4- use std:: fmt:: Write ;
3+ use std:: fmt:: { self , Write } ;
54use std:: mem;
65
76use parser:: node:: {
@@ -1434,8 +1433,9 @@ fn macro_call_ensure_arg_count(
14341433 call. span ( ) ,
14351434 ) ) ;
14361435 }
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 ( ) ;
14391439 for ( pos, arg) in call. args . iter ( ) . enumerate ( ) {
14401440 let pos = match * * arg {
14411441 Expr :: NamedArgument ( name, ..) => {
@@ -1444,11 +1444,11 @@ fn macro_call_ensure_arg_count(
14441444 _ => Some ( pos) ,
14451445 } ;
14461446 if let Some ( pos) = pos {
1447- if !args . remove ( & pos) {
1447+ if mem :: take ( & mut args [ pos] ) . is_none ( ) {
14481448 // This argument was already passed, so error.
14491449 return Err ( ctx. generate_error (
14501450 format_args ! (
1451- "argument `{}` is passed more than once when calling macro `{}`" ,
1451+ "argument `{}` was passed more than once when calling macro `{}`" ,
14521452 def. args[ pos] . 0 , def. name,
14531453 ) ,
14541454 call. span ( ) ,
@@ -1457,41 +1457,55 @@ fn macro_call_ensure_arg_count(
14571457 }
14581458 }
14591459
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 ;
14851464 }
1486- } ;
1465+ }
1466+
1467+ // No 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+ }
14871497
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+ }
14951509}
14961510
14971511#[ derive( Clone , Copy , PartialEq ) ]
0 commit comments