Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions tooling/ast_fuzzer/src/program/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,24 +1073,22 @@ impl<'a> FunctionContext<'a> {
// Find a type we can produce in the current scope which we can pass as input
// to the operations we selected, and it returns the desired output.
fn collect_input_types<'a, K: Ord>(
this: &FunctionContext,
op: BinaryOp,
type_out: &Type,
scope: &'a Scope<K>,
) -> Vec<&'a Type> {
scope
.types_produced()
.filter(|type_in| types::can_binary_op_return_from_input(&op, type_in, type_out))
.filter(|type_in| !this.ctx.should_avoid_literals(type_in))
.collect::<Vec<_>>()
}

// Try local variables first.
let mut lhs_opts = collect_input_types(self, op, typ, self.locals.current());
let mut lhs_opts = collect_input_types(op, typ, self.locals.current());

// If the locals don't have any type compatible with `op`, try the globals.
if lhs_opts.is_empty() {
lhs_opts = collect_input_types(self, op, typ, &self.globals);
lhs_opts = collect_input_types(op, typ, &self.globals);
}

// We might not have any input that works for this operation.
Expand Down Expand Up @@ -1256,8 +1254,7 @@ impl<'a> FunctionContext<'a> {
// Generate a type or choose an existing one.
let max_depth = self.max_depth();
let comptime_friendly = self.config().comptime_friendly;
let mut typ =
self.ctx.gen_type(u, max_depth, false, false, true, comptime_friendly, true)?;
let mut typ = self.ctx.gen_type(u, max_depth, false, false, comptime_friendly, true)?;

// If we picked the target type to be a slice, we can consider popping from it.
if let Type::Slice(ref item_type) = typ {
Expand Down
40 changes: 2 additions & 38 deletions tooling/ast_fuzzer/src/program/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ impl Context {
self.config.max_depth,
true,
false,
false,
self.config.comptime_friendly,
true,
)?;
Expand Down Expand Up @@ -227,7 +226,6 @@ impl Context {
self.config.max_depth,
false,
is_main || is_abi,
false,
self.config.comptime_friendly,
true,
)?;
Expand Down Expand Up @@ -266,7 +264,6 @@ impl Context {
self.config.max_depth,
false,
is_main || is_abi,
false,
self.config.comptime_friendly,
true,
)?
Expand Down Expand Up @@ -417,21 +414,13 @@ impl Context {
/// functions.
///
/// With a `max_depth` of 0 only leaf types are created.
///
/// With `is_frontend_friendly` we try to only consider types which are less likely to result
/// in literals that the frontend does not like when it has to infer their types. For example
/// without further constraints on the type, the frontend expects integer literals to be `u32`.
/// It also cannot infer the type of empty array literals, e.g. `let x = [];` would not compile.
/// When we generate types for e.g. function parameters, where the type is going to be declared
/// along with the variable name, this is not a concern.
#[allow(clippy::too_many_arguments)]
fn gen_type(
&mut self,
u: &mut Unstructured,
max_depth: usize,
is_global: bool,
is_main: bool,
is_frontend_friendly: bool,
is_comptime_friendly: bool,
is_slice_allowed: bool,
) -> arbitrary::Result<Type> {
Expand All @@ -443,7 +432,6 @@ impl Context {
.filter(|typ| !is_global || types::can_be_global(typ))
.filter(|typ| !is_main || types::can_be_main(typ))
.filter(|typ| types::type_depth(typ) <= max_depth)
.filter(|typ| !is_frontend_friendly || !self.should_avoid_literals(typ))
.filter(|typ| is_slice_allowed || !types::contains_slice(typ))
.collect::<Vec<_>>();

Expand All @@ -462,7 +450,6 @@ impl Context {
max_depth - 1,
is_global,
is_main,
is_frontend_friendly,
is_comptime_friendly,
is_slice_allowed,
)
Expand All @@ -476,17 +463,11 @@ impl Context {
1 => Type::Field,
2 => {
// i1 is deprecated, and i128 does not exist yet
let sign = if is_frontend_friendly {
Signedness::Unsigned
} else {
*u.choose(&[Signedness::Signed, Signedness::Unsigned])?
};
let sign = *u.choose(&[Signedness::Signed, Signedness::Unsigned])?;
let sizes = IntegerBitSize::iter()
.filter(|bs| {
// i1 and i128 are rejected by the frontend
(!sign.is_signed() || (bs.bit_size() != 1 && bs.bit_size() != 128)) &&
// The frontend doesn't like non-u32 literals
(!is_frontend_friendly || bs.bit_size() <= 32) &&
// Comptime doesn't allow for u1 either
(!is_comptime_friendly || bs.bit_size() != 1)
})
Expand All @@ -508,7 +489,7 @@ impl Context {
Type::Slice(Box::new(typ))
}
6 | 7 => {
let min_size = if is_frontend_friendly { 1 } else { 0 };
let min_size = 0;
let size = u.int_in_range(min_size..=self.config.max_array_size)?;
let typ = gen_inner_type(self, u, false)?;
Type::Array(size as u32, Box::new(typ))
Expand All @@ -533,23 +514,6 @@ impl Context {

Ok(typ)
}

/// Is a type likely to cause type inference problems in the frontend when standing alone.
fn should_avoid_literals(&self, typ: &Type) -> bool {
match typ {
Type::Integer(sign, size) => {
// The frontend expects u32 literals.
sign.is_signed() && self.config.avoid_negative_int_literals
|| size.bit_size() > 32 && self.config.avoid_large_int_literals
}
Type::Array(0, _) => {
// With 0 length arrays we run the risk of ending up with `let x = [];`,
// or similar expressions returning `[]`, the type fo which the fronted could not infer.
true
}
_ => false,
}
}
}

/// Derive a variable name from the ID.
Expand Down
Loading