contracts: Put contract-bound function body in a `try` block if needed

This makes Topola dependent on nightly Rust. If `try` blocks aren't
stabilized before the first release, we'll trivially just undo this
change temporarily, as contracts are just elaborate assertions.
This commit is contained in:
Mikolaj Wielgus 2023-10-29 15:24:41 +00:00
parent 0cf7c718f3
commit f0e2ba6e3a
2 changed files with 21 additions and 3 deletions

View File

@ -1,3 +1,4 @@
#![feature(try_blocks)]
extern crate sdl2; extern crate sdl2;
macro_rules! dbg_dot { macro_rules! dbg_dot {

View File

@ -5,8 +5,8 @@
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens; use quote::ToTokens;
use syn::{ use syn::{
spanned::Spanned, visit_mut as visitor, Attribute, Expr, ExprCall, spanned::Spanned, visit_mut as visitor, Attribute, Expr, ExprCall, ExprTry,
ReturnType, TypeImplTrait, ReturnType, Type, TypeImplTrait,
}; };
use crate::implementation::{ use crate::implementation::{
@ -341,7 +341,14 @@ pub(crate) fn generate(
if let ReturnType::Type(.., ref return_type) = if let ReturnType::Type(.., ref return_type) =
func.function.sig.output func.function.sig.output
{ {
break 'blk quote::quote! { let ret: #return_type = 'run: #block; }; let mut try_detector = TryDetector { found_try: false };
syn::visit::visit_block(&mut try_detector, &mut block);
if try_detector.found_try {
break 'blk quote::quote! { let ret: #return_type = 'run: { try { #block? } }; };
} else {
break 'blk quote::quote! { let ret: #return_type = 'run: #block; };
}
} }
} }
@ -401,3 +408,13 @@ impl<'a> syn::visit::Visit<'a> for ImplDetector {
self.found_impl = true; self.found_impl = true;
} }
} }
struct TryDetector {
found_try: bool,
}
impl<'a> syn::visit::Visit<'a> for TryDetector {
fn visit_expr_try(&mut self, _node: &'a ExprTry) {
self.found_try = true;
}
}