|
1 | 1 | use syn::{ |
2 | 2 | Attribute, Error, Expr, Ident, Meta, Pat, PatIdent, |
3 | 3 | parse::{Parse, ParseStream, Result}, |
4 | | - parse_quote, |
5 | 4 | spanned::Spanned, |
6 | 5 | }; |
7 | 6 |
|
@@ -120,7 +119,7 @@ impl Parse for Spec { |
120 | 119 | } |
121 | 120 | } |
122 | 121 | Keyword::Ensures => { |
123 | | - if let Err(error) = arg.parse_postconditions(&binds_pattern, &mut ensures) { |
| 122 | + if let Err(error) = arg.parse_postconditions(&mut ensures) { |
124 | 123 | errors.add(error); |
125 | 124 | } |
126 | 125 | } |
@@ -152,6 +151,7 @@ impl Parse for Spec { |
152 | 151 | requires, |
153 | 152 | maintains, |
154 | 153 | captures, |
| 154 | + binds: binds_pattern, |
155 | 155 | ensures, |
156 | 156 | span: input.span(), |
157 | 157 | }) |
@@ -295,15 +295,12 @@ impl SpecArg { |
295 | 295 | if let Expr::Array(conditions) = expr { |
296 | 296 | for expr in conditions.elems { |
297 | 297 | preconditions.push(PreCondition { |
298 | | - closure: interpret_expr_as_precondition(expr)?, |
| 298 | + expr, |
299 | 299 | cfg: cfg.clone(), |
300 | 300 | }); |
301 | 301 | } |
302 | 302 | } else { |
303 | | - preconditions.push(PreCondition { |
304 | | - closure: interpret_expr_as_precondition(expr)?, |
305 | | - cfg, |
306 | | - }); |
| 303 | + preconditions.push(PreCondition { expr, cfg }); |
307 | 304 | } |
308 | 305 | Ok(()) |
309 | 306 | } |
@@ -343,31 +340,23 @@ impl SpecArg { |
343 | 340 | Ok(()) |
344 | 341 | } |
345 | 342 |
|
346 | | - fn parse_postconditions( |
347 | | - self, |
348 | | - binds_pattern: &Option<Pat>, |
349 | | - postconditions: &mut Vec<PostCondition>, |
350 | | - ) -> Result<()> { |
| 343 | + fn parse_postconditions(self, postconditions: &mut Vec<PostCondition>) -> Result<()> { |
351 | 344 | let cfg_attr = find_cfg_attribute(&self.attrs)?; |
352 | 345 | let cfg: Option<Meta> = if let Some(attr) = cfg_attr { |
353 | 346 | Some(attr.parse_args()?) |
354 | 347 | } else { |
355 | 348 | None |
356 | 349 | }; |
357 | 350 | let expr = self.value.try_into_expr()?; |
358 | | - let default_pattern = binds_pattern.clone().unwrap_or(parse_quote! { output }); |
359 | 351 | if let Expr::Array(conditions) = expr { |
360 | 352 | for expr in conditions.elems { |
361 | 353 | postconditions.push(PostCondition { |
362 | | - closure: interpret_expr_as_postcondition(expr, default_pattern.clone())?, |
| 354 | + expr, |
363 | 355 | cfg: cfg.clone(), |
364 | 356 | }); |
365 | 357 | } |
366 | 358 | } else { |
367 | | - postconditions.push(PostCondition { |
368 | | - closure: interpret_expr_as_postcondition(expr, default_pattern)?, |
369 | | - cfg, |
370 | | - }); |
| 359 | + postconditions.push(PostCondition { expr, cfg }); |
371 | 360 | } |
372 | 361 | Ok(()) |
373 | 362 | } |
@@ -442,96 +431,6 @@ fn interpret_capture_expr_as_capture(capture_expr: CaptureExpr) -> Result<Captur |
442 | 431 | } |
443 | 432 | } |
444 | 433 |
|
445 | | -/// Interpret expression as precondition, i.e. a closure that returns `bool` and takes no inputs. |
446 | | -fn interpret_expr_as_precondition(expr: Expr) -> Result<syn::ExprClosure> { |
447 | | - match expr { |
448 | | - // Already a closure. |
449 | | - Expr::Closure(closure) => { |
450 | | - // Ensure it returns `bool`. |
451 | | - let predicate = interpret_closure_as_predicate(closure)?; |
452 | | - // Ensure it takes no inputs. |
453 | | - if predicate.inputs.is_empty() { |
454 | | - Ok(predicate) |
455 | | - } else { |
456 | | - Err(Error::new_spanned( |
457 | | - predicate.or1_token, |
458 | | - format!( |
459 | | - "precondition closure must have no arguments, found {}", |
460 | | - predicate.inputs.len() |
461 | | - ), |
462 | | - )) |
463 | | - } |
464 | | - } |
465 | | - // Naked expression, wrap in an argumentless closure. |
466 | | - expr => Ok(syn::ExprClosure { |
467 | | - attrs: vec![], |
468 | | - lifetimes: None, |
469 | | - constness: None, |
470 | | - movability: None, |
471 | | - asyncness: None, |
472 | | - capture: None, |
473 | | - or1_token: Default::default(), |
474 | | - inputs: syn::punctuated::Punctuated::new(), |
475 | | - or2_token: Default::default(), |
476 | | - output: parse_quote!(-> bool), |
477 | | - body: Box::new(expr), |
478 | | - }), |
479 | | - } |
480 | | -} |
481 | | - |
482 | | -/// Interpret expression as postcondition, i.e. a closure that returns `bool` and takes one input. |
483 | | -fn interpret_expr_as_postcondition(expr: Expr, default_binding: Pat) -> Result<syn::ExprClosure> { |
484 | | - match expr { |
485 | | - // Already a closure. |
486 | | - Expr::Closure(closure) => { |
487 | | - // Ensure it returns `bool`. |
488 | | - let predicate = interpret_closure_as_predicate(closure)?; |
489 | | - // Ensure it takes exactly one input. |
490 | | - if predicate.inputs.len() == 1 { |
491 | | - Ok(predicate) |
492 | | - } else { |
493 | | - Err(Error::new_spanned( |
494 | | - predicate.or1_token, |
495 | | - format!( |
496 | | - "postcondition closure must have exactly one argument, found {}", |
497 | | - predicate.inputs.len() |
498 | | - ), |
499 | | - )) |
500 | | - } |
501 | | - } |
502 | | - // Naked expression, wrap in a closure with default binding. |
503 | | - expr => Ok(syn::ExprClosure { |
504 | | - attrs: vec![], |
505 | | - lifetimes: None, |
506 | | - constness: None, |
507 | | - movability: None, |
508 | | - asyncness: None, |
509 | | - capture: None, |
510 | | - or1_token: Default::default(), |
511 | | - inputs: syn::punctuated::Punctuated::from_iter([default_binding]), |
512 | | - or2_token: Default::default(), |
513 | | - output: parse_quote!(-> bool), |
514 | | - body: Box::new(expr), |
515 | | - }), |
516 | | - } |
517 | | -} |
518 | | - |
519 | | -fn interpret_closure_as_predicate(mut closure: syn::ExprClosure) -> Result<syn::ExprClosure> { |
520 | | - match &closure.output { |
521 | | - syn::ReturnType::Default => { |
522 | | - closure.output = parse_quote!(-> bool); |
523 | | - Ok(closure) |
524 | | - } |
525 | | - syn::ReturnType::Type(_, ty) if matches!(ty.as_ref(), syn::Type::Path(path) if path.qself.is_none() && path.path.is_ident("bool")) => { |
526 | | - Ok(closure) |
527 | | - } |
528 | | - syn::ReturnType::Type(_, ty) => Err(Error::new_spanned( |
529 | | - ty, |
530 | | - "predicate must return `bool`".to_string(), |
531 | | - )), |
532 | | - } |
533 | | -} |
534 | | - |
535 | 434 | fn find_cfg_attribute(attrs: &[Attribute]) -> Result<Option<&Attribute>> { |
536 | 435 | let mut cfg_attr: Option<&Attribute> = None; |
537 | 436 |
|
|
0 commit comments