Skip to content

Commit a6cdb5c

Browse files
authored
use unerased proxies for associated consts and statics (#1793)
1 parent 98768b1 commit a6cdb5c

File tree

8 files changed

+586
-211
lines changed

8 files changed

+586
-211
lines changed

source/builtin_macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod struct_decl_inv;
2525
mod structural;
2626
mod syntax_trait;
2727
mod topological_sort;
28+
mod unerased_proxies;
2829

2930
decl_derive!([Structural] => structural::derive_structural);
3031

source/builtin_macros/src/syntax.rs

Lines changed: 10 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ use syn_verus::{
3636
};
3737

3838
pub(crate) const VERUS_SPEC: &str = "VERUS_SPEC__";
39-
const VERUS_UNERASED_PROXY: &str = "VERUS_UNERASED_PROXY__";
4039

4140
fn take_expr(expr: &mut Expr) -> Expr {
4241
let dummy: Expr = Expr::Verbatim(TokenStream::new());
@@ -69,8 +68,8 @@ enum InsideArith {
6968
Fixed,
7069
}
7170

72-
struct Visitor {
73-
erase_ghost: EraseGhost,
71+
pub(crate) struct Visitor {
72+
pub(crate) erase_ghost: EraseGhost,
7473
// TODO: this should always be true
7574
use_spec_traits: bool,
7675
// inside_ghost > 0 means we're currently visiting ghost code
@@ -94,7 +93,7 @@ struct Visitor {
9493
assign_to: bool,
9594

9695
// Add extra verus signature information to the docstring
97-
rustdoc: bool,
96+
pub(crate) rustdoc: bool,
9897
}
9998

10099
// For exec "let pat = init" declarations, recursively find Tracked(x), Ghost(x), x in pat
@@ -463,10 +462,6 @@ fn merge_default_ensures(
463462
}
464463

465464
impl Visitor {
466-
fn needs_unerased_proxies(&self) -> bool {
467-
self.erase_ghost.keep() && !self.rustdoc
468-
}
469-
470465
fn take_ghost<T: Default>(&self, dest: &mut T) -> T {
471466
take_ghost(self.erase_ghost, dest)
472467
}
@@ -511,8 +506,7 @@ impl Visitor {
511506
spec: &mut SignatureSpec,
512507
ret_pat: Option<(Pat, TType)>,
513508
final_ret_pat: Option<Pat>, // Some(pat) if different from ret_pat,
514-
is_const: bool,
515-
span: Span,
509+
_span: Span,
516510
) -> Vec<Stmt> {
517511
let requires = self.take_ghost(&mut spec.requires);
518512
let recommends = self.take_ghost(&mut spec.recommends);
@@ -741,16 +735,7 @@ impl Visitor {
741735
}
742736
}
743737

744-
if is_const {
745-
vec![Stmt::Expr(
746-
Expr::Verbatim(
747-
quote_spanned!(span => #[verus::internal(const_header_wrapper)] || { #(#spec_stmts)* };),
748-
),
749-
None,
750-
)]
751-
} else {
752-
spec_stmts
753-
}
738+
spec_stmts
754739
}
755740

756741
fn visit_fn(
@@ -945,8 +930,7 @@ impl Visitor {
945930
self.inside_ghost += 1; // for requires, ensures, etc.
946931

947932
let sig_span = sig.span().clone();
948-
let spec_stmts =
949-
self.take_sig_specs(&mut sig.spec, ret_pat, None, sig.constness.is_some(), sig_span);
933+
let spec_stmts = self.take_sig_specs(&mut sig.spec, ret_pat, None, sig_span);
950934
if !self.erase_ghost.erase() {
951935
stmts.extend(spec_stmts);
952936
}
@@ -992,36 +976,14 @@ impl Visitor {
992976
})));
993977
}
994978
} else {
995-
let ensures = self.take_ghost(con_ensures);
996-
if let Some(Ensures { token, mut exprs, attrs }) = ensures {
997-
self.inside_ghost += 1;
998-
let mut stmts: Vec<Stmt> = Vec::new();
999-
if attrs.len() > 0 {
1000-
let err = "outer attributes only allowed on function's ensures";
1001-
let expr = Expr::Verbatim(quote_spanned!(token.span => compile_error!(#err)));
1002-
stmts.push(Stmt::Expr(expr, Some(Semi { spans: [token.span] })));
1003-
} else if exprs.exprs.len() > 0 {
1004-
for expr in exprs.exprs.iter_mut() {
1005-
self.visit_expr_mut(expr);
1006-
}
1007-
// Use a closure in the ensures to avoid circular const definition.
1008-
// Note: we can't use con.ident as the closure pattern,
1009-
// because Rust would treat this as a const path pattern.
1010-
// So we use a 0-parameter closure.
1011-
stmts.push(stmt_with_semi!(builtin, token.span => #[verus::internal(const_header_wrapper)] || { #builtin::ensures(|| [#exprs]); }));
1012-
}
1013-
let mut block = std::mem::take(con_block).expect("const-with-ensures block");
1014-
block.stmts.splice(0..0, stmts);
1015-
*con_block = Some(block);
1016-
self.inside_ghost -= 1;
1017-
}
1018979
if let Some(block) = std::mem::take(con_block) {
1019980
let expr_block = syn_verus::ExprBlock { attrs: vec![], label: None, block: *block };
1020981
*con_expr = Some(Box::new(Expr::Block(expr_block)));
1021982
*con_eq_token = Some(syn_verus::token::Eq { spans: [con_span] });
1022983
*con_semi_token = Some(Semi { spans: [con_span] });
1023984
}
1024985
}
986+
*con_ensures = None;
1025987
}
1026988

1027989
fn visit_const_or_static(
@@ -1791,161 +1753,9 @@ impl Visitor {
17911753
}
17921754
}
17931755

1794-
fn item_needs_unerased_proxy(&self, item: &Item) -> bool {
1795-
match item {
1796-
Item::Const(item_const) => !is_external(&item_const.attrs),
1797-
Item::Fn(item_fn) => item_fn.sig.constness.is_some() && !is_external(&item_fn.attrs),
1798-
_ => false,
1799-
}
1800-
}
1801-
1802-
fn item_translate_const_to_0_arg_fn(&self, item: Item) -> Item {
1803-
match item {
1804-
Item::Const(item_const) => {
1805-
let span = item_const.span();
1806-
let ItemConst {
1807-
mut attrs,
1808-
vis,
1809-
const_token,
1810-
ident,
1811-
generics,
1812-
colon_token,
1813-
ty,
1814-
eq_token: _,
1815-
expr,
1816-
semi_token: _,
1817-
publish,
1818-
mode,
1819-
ensures,
1820-
block,
1821-
} = item_const;
1822-
attrs.push(mk_verus_attr(span, quote! { encoded_const }));
1823-
1824-
let publish = match (publish, &mode, &vis) {
1825-
(publish, _, Visibility::Inherited) => publish,
1826-
(
1827-
Publish::Default,
1828-
FnMode::Spec(_) | FnMode::SpecChecked(_) | FnMode::Default,
1829-
_,
1830-
) => Publish::Open(syn_verus::Open { token: token::Open { span } }),
1831-
(publish, _, _) => publish,
1832-
};
1833-
1834-
Item::Fn(ItemFn {
1835-
attrs,
1836-
vis,
1837-
sig: Signature {
1838-
spec: SignatureSpec {
1839-
prover: None,
1840-
requires: None,
1841-
recommends: None,
1842-
ensures,
1843-
default_ensures: None,
1844-
returns: None,
1845-
decreases: None,
1846-
invariants: None,
1847-
unwind: None,
1848-
with: None,
1849-
},
1850-
publish,
1851-
constness: None,
1852-
asyncness: None,
1853-
unsafety: None,
1854-
abi: None,
1855-
broadcast: None,
1856-
mode: mode,
1857-
fn_token: token::Fn { span: const_token.span },
1858-
ident: ident.clone(),
1859-
generics,
1860-
paren_token: Paren { span: into_spans(colon_token.span) },
1861-
inputs: Punctuated::new(),
1862-
variadic: None,
1863-
output: ReturnType::Type(
1864-
token::RArrow { spans: [colon_token.span, colon_token.span] },
1865-
None,
1866-
None, /*
1867-
Some(Box::new((
1868-
Paren { span: into_spans(colon_token.span) },
1869-
Pat::Verbatim(quote!{ #ident }),
1870-
colon_token,
1871-
))), */
1872-
ty,
1873-
),
1874-
},
1875-
block: (match block {
1876-
Some(block) => block,
1877-
_ => {
1878-
let expr = expr.unwrap();
1879-
Box::new(Block {
1880-
brace_token: Brace { span: into_spans(expr.span()) },
1881-
stmts: vec![Stmt::Expr(*expr, None)],
1882-
})
1883-
}
1884-
}),
1885-
semi_token: None,
1886-
})
1887-
}
1888-
item => item,
1889-
}
1890-
}
1891-
1892-
fn item_make_proxy(&self, item: Item) -> Item {
1893-
let mut item = item;
1894-
item = self.item_translate_const_to_0_arg_fn(item);
1895-
match &mut item {
1896-
Item::Fn(item_fn) => {
1897-
item_fn.sig.ident = Ident::new(
1898-
&format!("{}{}", VERUS_UNERASED_PROXY, &item_fn.sig.ident),
1899-
item_fn.sig.span(),
1900-
);
1901-
item_fn.attrs.push(mk_verus_attr(item_fn.span(), quote! { unerased_proxy }));
1902-
}
1903-
_ => unreachable!(),
1904-
}
1905-
item
1906-
}
1907-
1908-
fn item_make_external_and_erased(&mut self, item: Item) -> Item {
1909-
let mut item = item;
1910-
1911-
self.erase_ghost = EraseGhost::Erase;
1912-
self.visit_item_mut(&mut item);
1913-
self.erase_ghost = EraseGhost::Keep;
1914-
1915-
let span = item.span();
1916-
let attributes = match &mut item {
1917-
Item::Fn(item_fn) => &mut item_fn.attrs,
1918-
Item::Const(item_const) => &mut item_const.attrs,
1919-
_ => unreachable!(),
1920-
};
1921-
attributes.push(mk_verifier_attr(span, quote! { external }));
1922-
attributes.push(mk_verus_attr(span, quote! { uses_unerased_proxy }));
1923-
1924-
item
1925-
}
1926-
1927-
fn visit_items_make_unerased_proxies(&mut self, items: &mut Vec<Item>) {
1928-
if !self.needs_unerased_proxies() {
1929-
return;
1930-
}
1931-
1932-
let mut new_items = vec![];
1933-
1934-
for item in std::mem::take(items).into_iter() {
1935-
if self.item_needs_unerased_proxy(&item) {
1936-
let proxy = self.item_make_proxy(item.clone());
1937-
let erased = self.item_make_external_and_erased(item);
1938-
new_items.push(proxy);
1939-
new_items.push(erased);
1940-
} else {
1941-
new_items.push(item);
1942-
}
1943-
}
1944-
1945-
*items = new_items;
1946-
}
1947-
19481756
fn visit_impl_items_prefilter(&mut self, items: &mut Vec<ImplItem>, for_trait: bool) {
1757+
self.visit_impl_items_make_unerased_proxies(items, for_trait);
1758+
19491759
if self.erase_ghost.erase_all() {
19501760
items.retain(|item| match item {
19511761
ImplItem::Fn(fun) => match fun.sig.mode {
@@ -4816,13 +4626,7 @@ pub(crate) fn sig_specs_attr(
48164626
rustdoc: env_rustdoc(),
48174627
};
48184628
let sig_span = sig.span().clone();
4819-
spec_stmts.extend(visitor.take_sig_specs(
4820-
&mut spec,
4821-
ret_pat,
4822-
final_ret_pat,
4823-
sig.constness.is_some(),
4824-
sig_span,
4825-
));
4629+
spec_stmts.extend(visitor.take_sig_specs(&mut spec, ret_pat, final_ret_pat, sig_span));
48264630
spec_stmts
48274631
}
48284632

0 commit comments

Comments
 (0)