@@ -260,15 +260,22 @@ pub(super) struct Closure {
260260 pub name : Option < Ident > ,
261261 /// Captured values from outer scopes.
262262 pub captured : Scope ,
263- /// The parameter names and default values. Parameters with default value
264- /// are named parameters.
265- pub params : Vec < ( Ident , Option < Value > ) > ,
266- /// The name of an argument sink where remaining arguments are placed.
267- pub sink : Option < Ident > ,
263+ /// The list of parameters.
264+ pub params : Vec < Param > ,
268265 /// The expression the closure should evaluate to.
269266 pub body : Expr ,
270267}
271268
269+ #[ derive( Hash ) ]
270+ pub enum Param {
271+ /// A positional parameter: `x`.
272+ Pos ( Ident ) ,
273+ /// A named parameter with a default value: `draw: false`.
274+ Named ( Ident , Value ) ,
275+ /// An argument sink: `..args`.
276+ Sink ( Option < Ident > ) ,
277+ }
278+
272279impl Closure {
273280 /// Call the function in the context with the arguments.
274281 #[ allow( clippy:: too_many_arguments) ]
@@ -304,21 +311,38 @@ impl Closure {
304311 }
305312
306313 // Parse the arguments according to the parameter list.
307- for ( param, default) in & closure. params {
308- vm. define (
309- param. clone ( ) ,
310- match default {
311- Some ( default) => {
312- args. named :: < Value > ( param) ?. unwrap_or_else ( || default. clone ( ) )
314+ let num_pos_params =
315+ closure. params . iter ( ) . filter ( |p| matches ! ( p, Param :: Pos ( _) ) ) . count ( ) ;
316+ let num_pos_args = args. to_pos ( ) . len ( ) as usize ;
317+ let sink_size = num_pos_args. checked_sub ( num_pos_params) ;
318+
319+ let mut sink = None ;
320+ let mut sink_pos_values = None ;
321+ for p in & closure. params {
322+ match p {
323+ Param :: Pos ( ident) => {
324+ vm. define ( ident. clone ( ) , args. expect :: < Value > ( ident) ?) ;
325+ }
326+ Param :: Sink ( ident) => {
327+ sink = ident. clone ( ) ;
328+ if let Some ( sink_size) = sink_size {
329+ sink_pos_values = Some ( args. consume ( sink_size) ?) ;
313330 }
314- None => args. expect :: < Value > ( param) ?,
315- } ,
316- ) ;
331+ }
332+ Param :: Named ( ident, default) => {
333+ let value =
334+ args. named :: < Value > ( ident) ?. unwrap_or_else ( || default. clone ( ) ) ;
335+ vm. define ( ident. clone ( ) , value) ;
336+ }
337+ }
317338 }
318339
319- // Put the remaining arguments into the sink.
320- if let Some ( sink) = & closure. sink {
321- vm. define ( sink. clone ( ) , args. take ( ) ) ;
340+ if let Some ( sink) = sink {
341+ let mut remaining_args = args. take ( ) ;
342+ if let Some ( sink_pos_values) = sink_pos_values {
343+ remaining_args. items . extend ( sink_pos_values) ;
344+ }
345+ vm. define ( sink, remaining_args) ;
322346 }
323347
324348 // Ensure all arguments have been used.
@@ -407,7 +431,8 @@ impl<'a> CapturesVisitor<'a> {
407431 match param {
408432 ast:: Param :: Pos ( ident) => self . bind ( ident) ,
409433 ast:: Param :: Named ( named) => self . bind ( named. name ( ) ) ,
410- ast:: Param :: Sink ( ident) => self . bind ( ident) ,
434+ ast:: Param :: Sink ( Some ( ident) ) => self . bind ( ident) ,
435+ _ => { }
411436 }
412437 }
413438
0 commit comments