Skip to content

Commit d57fbf4

Browse files
authored
Handle generic defaults in BoundedArbitrary derives (#4117)
For structs with defaults for the generic parameters, Kani's `#[derive(BoundedArbitrary)]` macro was generating incorrect code. This PR fixes the issue through ensuring that the defaults are not included in the where clause or the impl definition. Resolves #4116 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent d7a0b91 commit d57fbf4

File tree

3 files changed

+39
-7
lines changed

3 files changed

+39
-7
lines changed

library/kani_macros/src/derive_bounded.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,14 @@ pub(crate) fn expand_derive_bounded_arbitrary(
5353
};
5454

5555
// add `T: Arbitrary` bounds for generics
56-
let (generics, clauses) = quote_generics(&parsed.generics);
56+
let clauses = quote_generics(&parsed.generics);
57+
let (impl_generics, ty_generics, _) = parsed.generics.split_for_impl();
5758
let name = &parsed.ident;
5859

5960
// generate the implementation
6061
let kani_path = kani_path();
6162
quote! {
62-
impl #generics #kani_path::BoundedArbitrary for #name #generics
63+
impl #impl_generics #kani_path::BoundedArbitrary for #name #ty_generics
6364
#clauses
6465
{
6566
fn bounded_any<const N: usize>() -> Self {
@@ -127,12 +128,14 @@ fn union_constructor(ident: &syn::Ident, _data_union: &syn::DataUnion) -> TokenS
127128
/// ...
128129
/// }
129130
/// ```
130-
fn quote_generics(generics: &syn::Generics) -> (TokenStream, TokenStream) {
131+
fn quote_generics(generics: &syn::Generics) -> TokenStream {
131132
let kani_path = kani_path();
132-
let params = generics.type_params().map(|param| quote!(#param)).collect::<Vec<_>>();
133-
let where_clauses = generics.type_params().map(|param| quote!(#param : #kani_path::Arbitrary));
134-
if !params.is_empty() {
135-
(quote!(<#(#params),*>), quote!(where #(#where_clauses),*))
133+
let where_clauses = generics.type_params().map(|param| {
134+
let ident = &param.ident;
135+
quote!(#ident : #kani_path::Arbitrary)
136+
});
137+
if generics.type_params().count() > 0 {
138+
quote!(where #(#where_clauses),*)
136139
} else {
137140
Default::default()
138141
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Checking harness check_my_vec...
2+
3+
** 2 of 2 cover properties satisfied
4+
5+
VERIFICATION:- SUCCESSFUL
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! Check that derive BoundedArbitrary macro works on structs with a generic default
5+
//! which had an issue in the past:
6+
//! https://github.com/model-checking/kani/issues/4116
7+
8+
extern crate kani;
9+
use kani::BoundedArbitrary;
10+
11+
#[derive(BoundedArbitrary)]
12+
#[allow(unused)]
13+
struct MyVector<T = i32> {
14+
#[bounded]
15+
vector: Vec<T>,
16+
}
17+
18+
#[kani::proof]
19+
#[kani::unwind(6)]
20+
fn check_my_vec() {
21+
let my_vec: MyVector<u8> = kani::bounded_any::<_, 1>();
22+
kani::cover!(my_vec.vector.len() == 0);
23+
kani::cover!(my_vec.vector.len() == 1);
24+
}

0 commit comments

Comments
 (0)