@@ -260,15 +260,22 @@ pub(super) struct Closure {
260
260
pub name : Option < Ident > ,
261
261
/// Captured values from outer scopes.
262
262
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 > ,
268
265
/// The expression the closure should evaluate to.
269
266
pub body : Expr ,
270
267
}
271
268
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
+
272
279
impl Closure {
273
280
/// Call the function in the context with the arguments.
274
281
#[ allow( clippy:: too_many_arguments) ]
@@ -304,21 +311,38 @@ impl Closure {
304
311
}
305
312
306
313
// 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) ?) ;
313
330
}
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
+ }
317
338
}
318
339
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) ;
322
346
}
323
347
324
348
// Ensure all arguments have been used.
@@ -407,7 +431,8 @@ impl<'a> CapturesVisitor<'a> {
407
431
match param {
408
432
ast:: Param :: Pos ( ident) => self . bind ( ident) ,
409
433
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
+ _ => { }
411
436
}
412
437
}
413
438
0 commit comments