Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add compile-time assertions on generic arguments of stdlib functions #6981

Merged
merged 35 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c671b1e
change two assertions on generics to static assertions, wip finding s…
michaeljklein Jan 7, 2025
4a701ed
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 8, 2025
e835376
rename ToRadix -> ToRadixUnsafe, ToBits -> ToBitsUnsafe, add size che…
michaeljklein Jan 9, 2025
0896b08
wip implementing comptime static_assert, add tests for comptime stati…
michaeljklein Jan 9, 2025
ee45436
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 9, 2025
89a0253
rename after merge
michaeljklein Jan 9, 2025
36cdd91
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 9, 2025
3cc4f7d
debug failing tests by updating '<' -> '<=' where needed, cargo clipp…
michaeljklein Jan 9, 2025
9607e6b
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 10, 2025
dea58ad
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 10, 2025
a79c443
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 14, 2025
75eb48c
reverting To(Bits|Radix)Unsafe changes, wip testing 'self.range_const…
michaeljklein Jan 14, 2025
fbc93ca
cargo clippy
michaeljklein Jan 14, 2025
32f0d6d
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 14, 2025
dc2a89f
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 15, 2025
713d9b7
update test fixed by recent PR, remove broken wip range constraint, c…
michaeljklein Jan 15, 2025
f9739a5
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 15, 2025
68c3060
nargo fmt
michaeljklein Jan 15, 2025
507292c
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 15, 2025
93afedf
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 16, 2025
b4c8c36
Update noir_stdlib/src/uint128.nr
michaeljklein Jan 16, 2025
ba79d2f
Update noir_stdlib/src/uint128.nr
michaeljklein Jan 16, 2025
5b4c5d4
Update compiler/noirc_frontend/src/tests/metaprogramming.rs
michaeljklein Jan 16, 2025
c7c3e8f
Update tooling/nargo_cli/src/cli/compile_cmd.rs
michaeljklein Jan 16, 2025
8214dad
Update compiler/noirc_frontend/src/tests/metaprogramming.rs
michaeljklein Jan 16, 2025
21810b9
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 21, 2025
d1536d5
cargo fmt
michaeljklein Jan 21, 2025
8a1e7d2
nargo fmt
michaeljklein Jan 21, 2025
55fcc95
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 21, 2025
41dc327
Merge branch 'master' into michaeljklein/stdlib-static-assertions
TomAFrench Jan 22, 2025
7d442d8
add static_assert's to to_le_radix, add noir stdlib and compile failu…
michaeljklein Jan 22, 2025
99710bd
remove compile_failure tests now that stdlib tests are working, remov…
michaeljklein Jan 22, 2025
39f3150
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 22, 2025
3608f63
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 22, 2025
2957752
Merge branch 'master' into michaeljklein/stdlib-static-assertions
michaeljklein Jan 22, 2025
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
4 changes: 2 additions & 2 deletions compiler/noirc_evaluator/src/acir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2145,7 +2145,7 @@ impl<'a> Context<'a> {
Intrinsic::ApplyRangeConstraint => {
unreachable!("ICE: `Intrinsic::ApplyRangeConstraint` calls should be transformed into an `Instruction::RangeCheck`");
}
Intrinsic::ToRadix(endian) => {
Intrinsic::ToRadixUnsafe(endian) => {
let field = self.convert_value(arguments[0], dfg).into_var()?;
let radix = self.convert_value(arguments[1], dfg).into_var()?;

Expand All @@ -2164,7 +2164,7 @@ impl<'a> Context<'a> {
)
.map(|array| vec![array])
}
Intrinsic::ToBits(endian) => {
Intrinsic::ToBitsUnsafe(endian) => {
let field = self.convert_value(arguments[0], dfg).into_var()?;

let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ impl<'block> BrilligBlock<'block> {
arguments,
);
}
Intrinsic::ToBits(endianness) => {
Intrinsic::ToBitsUnsafe(endianness) => {
let results = dfg.instruction_results(instruction_id);

let source = self.convert_ssa_single_addr_value(arguments[0], dfg);
Expand Down Expand Up @@ -526,7 +526,7 @@ impl<'block> BrilligBlock<'block> {
self.brillig_context.deallocate_single_addr(two);
}

Intrinsic::ToRadix(endianness) => {
Intrinsic::ToRadixUnsafe(endianness) => {
let results = dfg.instruction_results(instruction_id);

let source = self.convert_ssa_single_addr_value(arguments[0], dfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ impl DependencyContext {
| Intrinsic::SliceRemove
| Intrinsic::StaticAssert
| Intrinsic::StrAsBytes
| Intrinsic::ToBits(..)
| Intrinsic::ToRadix(..)
| Intrinsic::ToBitsUnsafe(..)
| Intrinsic::ToRadixUnsafe(..)
| Intrinsic::FieldLessThan => {
// Record all the function arguments as parents of the results
self.update_children(&arguments, &results);
Expand Down Expand Up @@ -586,8 +586,8 @@ impl Context {
| Intrinsic::SliceRemove
| Intrinsic::StaticAssert
| Intrinsic::StrAsBytes
| Intrinsic::ToBits(..)
| Intrinsic::ToRadix(..)
| Intrinsic::ToBitsUnsafe(..)
| Intrinsic::ToRadixUnsafe(..)
| Intrinsic::FieldLessThan => {
self.value_sets.push(instruction_arguments_and_results);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/function_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ mod tests {
let one = builder.numeric_constant(FieldElement::one(), NumericType::bool());
let zero = builder.numeric_constant(FieldElement::zero(), NumericType::bool());

let to_bits_id = builder.import_intrinsic_id(Intrinsic::ToBits(Endian::Little));
let to_bits_id = builder.import_intrinsic_id(Intrinsic::ToBitsUnsafe(Endian::Little));
let input = builder.field_constant(FieldElement::from(7_u128));
let length = builder.field_constant(FieldElement::from(8_u128));
let result_types = vec![Type::Array(Arc::new(vec![Type::bool()]), 8)];
Expand Down
28 changes: 14 additions & 14 deletions compiler/noirc_evaluator/src/ssa/ir/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
SliceRemove,
ApplyRangeConstraint,
StrAsBytes,
ToBits(Endian),
ToRadix(Endian),
ToBitsUnsafe(Endian),
ToRadixUnsafe(Endian),
BlackBox(BlackBoxFunc),
Hint(Hint),
AsWitness,
Expand All @@ -89,10 +89,10 @@
Intrinsic::SliceRemove => write!(f, "slice_remove"),
Intrinsic::StrAsBytes => write!(f, "str_as_bytes"),
Intrinsic::ApplyRangeConstraint => write!(f, "apply_range_constraint"),
Intrinsic::ToBits(Endian::Big) => write!(f, "to_be_bits"),
Intrinsic::ToBits(Endian::Little) => write!(f, "to_le_bits"),
Intrinsic::ToRadix(Endian::Big) => write!(f, "to_be_radix"),
Intrinsic::ToRadix(Endian::Little) => write!(f, "to_le_radix"),
Intrinsic::ToBitsUnsafe(Endian::Big) => write!(f, "to_be_bits_unsafe"),
Intrinsic::ToBitsUnsafe(Endian::Little) => write!(f, "to_le_bits_unsafe"),
Intrinsic::ToRadixUnsafe(Endian::Big) => write!(f, "to_be_radix_unsafe"),
Intrinsic::ToRadixUnsafe(Endian::Little) => write!(f, "to_le_radix_unsafe"),
Intrinsic::BlackBox(function) => write!(f, "{function}"),
Intrinsic::Hint(Hint::BlackBox) => write!(f, "black_box"),
Intrinsic::AsWitness => write!(f, "as_witness"),
Expand Down Expand Up @@ -124,7 +124,7 @@
| Intrinsic::AsWitness => true,

// These apply a constraint that the input must fit into a specified number of limbs.
Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true,
Intrinsic::ToBitsUnsafe(_) | Intrinsic::ToRadixUnsafe(_) => true,

// These imply a check that the slice is non-empty and should fail otherwise.
Intrinsic::SlicePopBack | Intrinsic::SlicePopFront | Intrinsic::SliceRemove => true,
Expand Down Expand Up @@ -164,8 +164,8 @@
// directly depend on the corresponding `enable_side_effect` instruction any more.
// However, to conform with the expectations of `Instruction::can_be_deduplicated` and
// `constant_folding` we only use this information if the caller shows interest in it.
Intrinsic::ToBits(_)
| Intrinsic::ToRadix(_)
Intrinsic::ToBitsUnsafe(_)
| Intrinsic::ToRadixUnsafe(_)
| Intrinsic::BlackBox(
BlackBoxFunc::MultiScalarMul
| BlackBoxFunc::EmbeddedCurveAdd
Expand Down Expand Up @@ -203,10 +203,10 @@
"slice_insert" => Some(Intrinsic::SliceInsert),
"slice_remove" => Some(Intrinsic::SliceRemove),
"str_as_bytes" => Some(Intrinsic::StrAsBytes),
"to_le_radix" => Some(Intrinsic::ToRadix(Endian::Little)),
"to_be_radix" => Some(Intrinsic::ToRadix(Endian::Big)),
"to_le_bits" => Some(Intrinsic::ToBits(Endian::Little)),
"to_be_bits" => Some(Intrinsic::ToBits(Endian::Big)),
"to_le_radix_unsafe" => Some(Intrinsic::ToRadixUnsafe(Endian::Little)),
"to_be_radix_unsafe" => Some(Intrinsic::ToRadixUnsafe(Endian::Big)),
"to_le_bits_unsafe" => Some(Intrinsic::ToBitsUnsafe(Endian::Little)),
"to_be_bits_unsafe" => Some(Intrinsic::ToBitsUnsafe(Endian::Big)),
"as_witness" => Some(Intrinsic::AsWitness),
"is_unconstrained" => Some(Intrinsic::IsUnconstrained),
"derive_pedersen_generators" => Some(Intrinsic::DerivePedersenGenerators),
Expand All @@ -220,7 +220,7 @@
}
}

/// The endian-ness of bits when encoding values as bits in e.g. ToBits or ToRadix
/// The endian-ness of bits when encoding values as bits in e.g. ToBitsUnsafe or ToRadixUnsafe
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) enum Endian {
Big,
Expand Down Expand Up @@ -407,7 +407,7 @@
// These can fail.
Constrain(..) | RangeCheck { .. } => true,

// This should never be side-effectful

Check warning on line 410 in compiler/noirc_evaluator/src/ssa/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (effectful)
MakeArray { .. } | Noop => false,

// Some binary math can overflow or underflow
Expand Down
14 changes: 7 additions & 7 deletions compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ pub(super) fn simplify_call(
arguments.iter().map(|value_id| dfg.get_numeric_constant(*value_id)).collect();

let simplified_result = match intrinsic {
Intrinsic::ToBits(endian) => {
Intrinsic::ToBitsUnsafe(endian) => {
// TODO: simplify to a range constraint if `limb_count == 1`
if let (Some(constant_args), Some(return_type)) = (constant_args, return_type.clone()) {
let field = constant_args[0];
let limb_count = if let Type::Array(_, array_len) = return_type {
array_len
} else {
unreachable!("ICE: Intrinsic::ToRadix return type must be array")
unreachable!("ICE: Intrinsic::ToRadixUnsafe return type must be array")
};
constant_to_radix(endian, field, 2, limb_count, |values| {
constant_to_radix_unsafe(endian, field, 2, limb_count, |values| {
make_constant_array(
dfg,
values.into_iter(),
Expand All @@ -74,17 +74,17 @@ pub(super) fn simplify_call(
SimplifyResult::None
}
}
Intrinsic::ToRadix(endian) => {
Intrinsic::ToRadixUnsafe(endian) => {
// TODO: simplify to a range constraint if `limb_count == 1`
if let (Some(constant_args), Some(return_type)) = (constant_args, return_type.clone()) {
let field = constant_args[0];
let radix = constant_args[1].to_u128() as u32;
let limb_count = if let Type::Array(_, array_len) = return_type {
array_len
} else {
unreachable!("ICE: Intrinsic::ToRadix return type must be array")
unreachable!("ICE: Intrinsic::ToRadixUnsafe return type must be array")
};
constant_to_radix(endian, field, radix, limb_count, |values| {
constant_to_radix_unsafe(endian, field, radix, limb_count, |values| {
make_constant_array(
dfg,
values.into_iter(),
Expand Down Expand Up @@ -623,7 +623,7 @@ fn make_array(
}

/// Returns a slice (represented by a tuple (len, slice)) of constants corresponding to the limbs of the radix decomposition.
fn constant_to_radix(
fn constant_to_radix_unsafe(
endian: Endian,
field: FieldElement,
radix: u32,
Expand Down
16 changes: 8 additions & 8 deletions compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1557,28 +1557,28 @@ mod test {
// After EnableSideEffectsIf removal:
brillig(inline) fn main f0 {
b0(v0: Field, v1: Field, v2: u1):
v7 = call to_be_radix(v0, u32 256) -> [u8; 1] // `a.to_be_radix(256)`;
v7 = call to_be_radix_unsafe(v0, u32 256) -> [u8; 1] // `a.to_be_radix_unsafe(256)`;
inc_rc v7
v8 = call to_be_radix(v0, u32 256) -> [u8; 1] // duplicate load of `a`
v8 = call to_be_radix_unsafe(v0, u32 256) -> [u8; 1] // duplicate load of `a`
inc_rc v8
v9 = cast v2 as Field // `if c { a.to_be_radix(256) }`
v10 = mul v0, v9 // attaching `c` to `a`
v11 = call to_be_radix(v10, u32 256) -> [u8; 1] // calling `to_radix(c * a)`
v9 = cast v2 as Field // `if c { a.to_be_radix_unsafe(256) }`
v10 = mul v0, v9 // attaching `c` to `a`
v11 = call to_be_radix_unsafe(v10, u32 256) -> [u8; 1] // calling `to_radix(c * a)`
inc_rc v11
enable_side_effects v2 // side effect var for `c` shifted down by removal
enable_side_effects v2 // side effect var for `c` shifted down by removal
return
}
";
let ssa = Ssa::from_str(src).unwrap();
let expected = "
brillig(inline) fn main f0 {
b0(v0: Field, v1: Field, v2: u1):
v5 = call to_be_radix(v0, u32 256) -> [u8; 1]
v5 = call to_be_radix_unsafe(v0, u32 256) -> [u8; 1]
inc_rc v5
inc_rc v5
v6 = cast v2 as Field
v7 = mul v0, v6
v8 = call to_be_radix(v7, u32 256) -> [u8; 1]
v8 = call to_be_radix_unsafe(v7, u32 256) -> [u8; 1]
inc_rc v8
enable_side_effects v2
return
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ impl<'f> Context<'f> {
}
Instruction::Call { func, mut arguments } => match self.inserter.function.dfg[func]
{
Value::Intrinsic(Intrinsic::ToBits(_) | Intrinsic::ToRadix(_)) => {
Value::Intrinsic(Intrinsic::ToBitsUnsafe(_) | Intrinsic::ToRadixUnsafe(_)) => {
let field = arguments[0];
let argument_type = self.inserter.function.dfg.type_of_value(field);

Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl Context<'_> {
fn pow(&mut self, lhs: ValueId, rhs: ValueId) -> ValueId {
let typ = self.function.dfg.type_of_value(rhs);
if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ {
let to_bits = self.function.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little));
let to_bits = self.function.dfg.import_intrinsic(Intrinsic::ToBitsUnsafe(Endian::Little));
let result_types = vec![Type::Array(Arc::new(vec![Type::bool()]), bit_size)];
let rhs_bits = self.insert_call(to_bits, vec![rhs], result_types);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ impl Context {
| Intrinsic::StaticAssert
| Intrinsic::ApplyRangeConstraint
| Intrinsic::StrAsBytes
| Intrinsic::ToBits(_)
| Intrinsic::ToRadix(_)
| Intrinsic::ToBitsUnsafe(_)
| Intrinsic::ToRadixUnsafe(_)
| Intrinsic::BlackBox(_)
| Intrinsic::Hint(Hint::BlackBox)
| Intrinsic::AsSlice
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ fn slice_capacity_change(
| Intrinsic::AsWitness
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators
| Intrinsic::ToBits(_)
| Intrinsic::ToRadix(_)
| Intrinsic::ToBitsUnsafe(_)
| Intrinsic::ToRadixUnsafe(_)
| Intrinsic::ArrayRefCount
| Intrinsic::SliceRefCount
| Intrinsic::FieldLessThan => SizeChange::None,
Expand Down
46 changes: 33 additions & 13 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"array_as_str_unchecked" => array_as_str_unchecked(interner, arguments, location),
"array_len" => array_len(interner, arguments, location),
"array_refcount" => Ok(Value::U32(0)),
"assert_constant" => Ok(Value::Bool(true)),
"assert_constant" => Ok(Value::Unit),
"as_slice" => as_slice(interner, arguments, location),
"ctstring_eq" => ctstring_eq(arguments, location),
"ctstring_hash" => ctstring_hash(arguments, location),
Expand Down Expand Up @@ -175,6 +175,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"slice_push_front" => slice_push_front(interner, arguments, location),
"slice_refcount" => Ok(Value::U32(0)),
"slice_remove" => slice_remove(interner, arguments, location, call_stack),
"static_assert" => static_assert(interner, arguments, location, call_stack),
"str_as_bytes" => str_as_bytes(interner, arguments, location),
"str_as_ctstring" => str_as_ctstring(interner, arguments, location),
"struct_def_add_attribute" => struct_def_add_attribute(interner, arguments, location),
Expand All @@ -190,10 +191,10 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"struct_def_module" => struct_def_module(self, arguments, location),
"struct_def_name" => struct_def_name(interner, arguments, location),
"struct_def_set_fields" => struct_def_set_fields(interner, arguments, location),
"to_be_radix" => to_be_radix(arguments, return_type, location),
"to_le_radix" => to_le_radix(arguments, return_type, location),
"to_be_bits" => to_be_bits(arguments, return_type, location),
"to_le_bits" => to_le_bits(arguments, return_type, location),
"to_be_radix_unsafe" => to_be_radix_unsafe(arguments, return_type, location),
"to_le_radix_unsafe" => to_le_radix_unsafe(arguments, return_type, location),
"to_be_bits_unsafe" => to_be_bits_unsafe(arguments, return_type, location),
"to_le_bits_unsafe" => to_le_bits_unsafe(arguments, return_type, location),
"trait_constraint_eq" => trait_constraint_eq(arguments, location),
"trait_constraint_hash" => trait_constraint_hash(arguments, location),
"trait_def_as_trait_constraint" => {
Expand Down Expand Up @@ -322,6 +323,25 @@ fn slice_push_back(
Ok(Value::Slice(values, typ))
}

// static_assert<let N: u32>(predicate: bool, message: str<N>)
fn static_assert(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
call_stack: &im::Vector<Location>,
) -> IResult<Value> {
let (predicate, message) = check_two_arguments(arguments, location)?;
let predicate = get_bool(predicate)?;
let message = get_str(interner, message)?;

"TODO need to evaluate static_assert's predicate more?!";
if predicate {
Ok(Value::Unit)
} else {
failing_constraint((*message).clone(), location, call_stack)
}
}

fn str_as_bytes(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -778,7 +798,7 @@ fn quoted_tokens(arguments: Vec<(Value, Location)>, location: Location) -> IResu
))
}

fn to_be_bits(
fn to_be_bits_unsafe(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
Expand All @@ -788,7 +808,7 @@ fn to_be_bits(
to_be_radix(vec![value, radix], return_type, location)
}

fn to_le_bits(
fn to_le_bits_unsafe(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
Expand All @@ -798,22 +818,22 @@ fn to_le_bits(
to_le_radix(vec![value, radix], return_type, location)
}

fn to_be_radix(
fn to_be_radix_unsafe(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let le_radix_limbs = to_le_radix(arguments, return_type, location)?;
let le_radix_limbs = to_le_radix_unsafe(arguments, return_type, location)?;

let Value::Array(limbs, typ) = le_radix_limbs else {
unreachable!("`to_le_radix` should always return an array");
unreachable!("`to_le_radix_unsafe` should always return an array");
};
let be_radix_limbs = limbs.into_iter().rev().collect();

Ok(Value::Array(be_radix_limbs, typ))
}

fn to_le_radix(
fn to_le_radix_unsafe(
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
Expand All @@ -837,7 +857,7 @@ fn to_le_radix(
};

// Decompose the integer into its radix digits in little endian form.
let decomposed_integer = compute_to_radix_le(value, radix);
let decomposed_integer = compute_to_radix_le_unsafe(value, radix);
let decomposed_integer =
vecmap(0..limb_count.to_u128() as usize, |i| match decomposed_integer.get(i) {
Some(digit) => Value::U8(*digit),
Expand All @@ -847,7 +867,7 @@ fn to_le_radix(
Ok(Value::Array(decomposed_integer.into(), result_type))
}

fn compute_to_radix_le(field: FieldElement, radix: u32) -> Vec<u8> {
fn compute_to_radix_le_unsafe(field: FieldElement, radix: u32) -> Vec<u8> {
let bit_size = u32::BITS - (radix - 1).leading_zeros();
let radix_big = BigUint::from(radix);
assert_eq!(BigUint::from(2u128).pow(bit_size), radix_big, "ICE: Radix must be a power of 2");
Expand Down
Loading
Loading