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

feat: Support printing more types #4071

Merged
merged 10 commits into from
Jan 18, 2024
16 changes: 10 additions & 6 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
TypeVariable(TypeVariable, TypeVariableKind),

/// `impl Trait` when used in a type position.
/// These are only matched based on the TraitId. The trait name paramer is only

Check warning on line 67 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (paramer)
/// used for displaying error messages using the name of the trait.
TraitAsType(TraitId, /*name:*/ Rc<String>, /*generics:*/ Vec<Type>),

Expand Down Expand Up @@ -1408,7 +1408,7 @@
Type::MutableReference(element) => Type::MutableReference(Box::new(
element.substitute_helper(type_bindings, substitute_bound_typevars),
)),

Check warning on line 1411 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsn)
Type::FieldElement
| Type::Integer(_, _)
| Type::Bool
Expand All @@ -1423,7 +1423,7 @@
/// True if the given TypeVariableId is free anywhere within self
fn occurs(&self, target_id: TypeVariableId) -> bool {
match self {
Type::Array(len, elem) => len.occurs(target_id) || elem.occurs(target_id),

Check warning on line 1426 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsfined)
Type::String(len) => len.occurs(target_id),
Type::FmtString(len, fields) => {
let len_occurs = len.occurs(target_id);
Expand Down Expand Up @@ -1583,7 +1583,7 @@
match value {
Type::FieldElement => PrintableType::Field,
Type::Array(size, typ) => {
let length = size.evaluate_to_u64().expect("Cannot print variable sized arrays");
let length = size.evaluate_to_u64();
let typ = typ.as_ref();
PrintableType::Array { length, typ: Box::new(typ.into()) }
}
Expand All @@ -1604,21 +1604,25 @@
}
Type::FmtString(_, _) => unreachable!("format strings cannot be printed"),
Type::Error => unreachable!(),
Type::Unit => unreachable!(),
Type::Unit => PrintableType::Unit,
Type::Constant(_) => unreachable!(),
Type::Struct(def, ref args) => {
let struct_type = def.borrow();
let fields = struct_type.get_fields(args);
let fields = vecmap(fields, |(name, typ)| (name, typ.into()));
PrintableType::Struct { fields, name: struct_type.name.to_string() }
}
Type::TraitAsType(..) => unreachable!(),
Type::Tuple(_) => todo!("printing tuple types is not yet implemented"),
Type::TraitAsType(_, _, _) => unreachable!(),
Type::Tuple(types) => PrintableType::Tuple { types: vecmap(types, |typ| typ.into()) },
Type::TypeVariable(_, _) => unreachable!(),
Type::NamedGeneric(..) => unreachable!(),
Type::Forall(..) => unreachable!(),
Type::Function(_, _, _) => unreachable!(),
Type::MutableReference(_) => unreachable!("cannot print &mut"),
Type::Function(_, _, env) => {
PrintableType::Function { env: Box::new(env.as_ref().into()) }
}
Type::MutableReference(typ) => {
PrintableType::MutableReference { typ: Box::new(typ.as_ref().into()) }
}
Type::NotConstant => unreachable!(),
}
}
Expand Down
5 changes: 0 additions & 5 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,11 +1029,6 @@ impl<'interner> Monomorphizer<'interner> {
}

fn append_printable_type_info_inner(typ: &Type, arguments: &mut Vec<ast::Expression>) {
if let HirType::Array(size, _) = typ {
if let HirType::NotConstant = **size {
unreachable!("println does not support slices. Convert the slice to an array before passing it to println");
ggiraldez marked this conversation as resolved.
Show resolved Hide resolved
}
}
let printable_type: PrintableType = typ.into();
let abi_as_string = serde_json::to_string(&printable_type)
.expect("ICE: expected PrintableType to serialize");
Expand Down
113 changes: 69 additions & 44 deletions compiler/noirc_printable_type/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
pub enum PrintableType {
Field,
Array {
length: u64,
length: Option<u64>,
#[serde(rename = "type")]
typ: Box<PrintableType>,
},
Tuple {
types: Vec<PrintableType>,
},
SignedInteger {
width: u32,
},
Expand All @@ -29,23 +32,13 @@
String {
length: u64,
},
}

impl PrintableType {
/// Returns the number of field elements required to represent the type once encoded.
fn field_count(&self) -> u32 {
match self {
Self::Field
| Self::SignedInteger { .. }
| Self::UnsignedInteger { .. }
| Self::Boolean => 1,
Self::Array { length, typ } => typ.field_count() * (*length as u32),
Self::Struct { fields, .. } => {
fields.iter().fold(0, |acc, (_, field_type)| acc + field_type.field_count())
}
Self::String { length } => *length as u32,
}
}
Function {
env: Box<PrintableType>,
},
MutableReference {
typ: Box<PrintableType>,
},
Unit,
}

/// This is what all formats eventually transform into
Expand Down Expand Up @@ -114,43 +107,26 @@
fn convert_fmt_string_inputs(
foreign_call_inputs: &[ForeignCallParam],
) -> Result<PrintableValueDisplay, ForeignCallError> {
let (message, input_and_printable_values) =
let (message, input_and_printable_types) =
foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?;

let message_as_fields = vecmap(message.values(), |value| value.to_field());
let message_as_string = decode_string_value(&message_as_fields);

let (num_values, input_and_printable_values) = input_and_printable_values
let (num_values, input_and_printable_types) = input_and_printable_types
.split_first()
.ok_or(ForeignCallError::MissingForeignCallInputs)?;

let mut output = Vec::new();
let num_values = num_values.unwrap_value().to_field().to_u128() as usize;

for (i, printable_value) in input_and_printable_values
let types_start_at = input_and_printable_types.len() - num_values;
let mut input_iter = input_and_printable_types[0..types_start_at]
.iter()
.skip(input_and_printable_values.len() - num_values)
.enumerate()
{
let printable_type = fetch_printable_type(printable_value)?;
let type_size = printable_type.field_count() as usize;
let value = match printable_type {
PrintableType::Array { .. } | PrintableType::String { .. } => {
// Arrays and strings are represented in a single value vector rather than multiple separate input values
let mut input_values_as_fields = input_and_printable_values[i]
.values()
.into_iter()
.map(|value| value.to_field());
decode_value(&mut input_values_as_fields, &printable_type)
}
_ => {
// We must use a flat map here as each value in a struct will be in a separate input value
let mut input_values_as_fields = input_and_printable_values[i..(i + type_size)]
.iter()
.flat_map(|param| vecmap(param.values(), |value| value.to_field()));
decode_value(&mut input_values_as_fields, &printable_type)
}
};
.flat_map(|param| vecmap(param.values(), |value| value.to_field()));
for printable_type in input_and_printable_types.iter().skip(types_start_at) {
let printable_type = fetch_printable_type(printable_type)?;
let value = decode_value(&mut input_iter, &printable_type);

output.push((value, printable_type));
}
Expand Down Expand Up @@ -196,6 +172,12 @@
output.push_str("false");
}
}
(PrintableValue::Field(_), PrintableType::Function { .. }) => {
output.push_str("<<function>>");
}
(_, PrintableType::MutableReference { .. }) => {
output.push_str("<<mutable ref>>");
}
(PrintableValue::Vec(vector), PrintableType::Array { typ, .. }) => {
output.push('[');
let mut values = vector.iter().peekable();
Expand Down Expand Up @@ -233,6 +215,22 @@
output.push_str(" }");
}

(PrintableValue::Vec(values), PrintableType::Tuple { types }) => {
output.push('(');
let mut elems = values.iter().zip(types).peekable();

Check warning on line 220 in compiler/noirc_printable_type/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)
while let Some((value, typ)) = elems.next() {

Check warning on line 221 in compiler/noirc_printable_type/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)
output.push_str(
&PrintableValueDisplay::Plain(value.clone(), typ.clone()).to_string(),
);
if elems.peek().is_some() {

Check warning on line 225 in compiler/noirc_printable_type/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)
output.push_str(", ");
}
}
output.push(')');
}

(_, PrintableType::Unit) => output.push_str("()"),

_ => return None,
};

Expand Down Expand Up @@ -308,7 +306,19 @@

PrintableValue::Field(field_element)
}
PrintableType::Array { length, typ } => {
PrintableType::Array { length: None, typ } => {
let length = field_iterator
.next()
.expect("not enough data to decode variable array length")
.to_u128() as usize;
let mut array_elements = Vec::with_capacity(length);
for _ in 0..length {
array_elements.push(decode_value(field_iterator, typ));
}

PrintableValue::Vec(array_elements)
}
PrintableType::Array { length: Some(length), typ } => {
let length = *length as usize;
let mut array_elements = Vec::with_capacity(length);
for _ in 0..length {
Expand All @@ -317,6 +327,9 @@

PrintableValue::Vec(array_elements)
}
PrintableType::Tuple { types } => {
PrintableValue::Vec(vecmap(types, |typ| decode_value(field_iterator, typ)))
}
PrintableType::String { length } => {
let field_elements: Vec<FieldElement> = field_iterator.take(*length as usize).collect();

Expand All @@ -333,6 +346,18 @@

PrintableValue::Struct(struct_map)
}
PrintableType::Function { env } => {
let field_element = field_iterator.next().unwrap();
let func_ref = PrintableValue::Field(field_element);
// we want to consume the fields from the environment, but for now they are not actually printed
decode_value(field_iterator, env);
func_ref
}
PrintableType::MutableReference { typ } => {
// we decode the reference, but it's not really used for printing
decode_value(field_iterator, typ)
}
PrintableType::Unit => PrintableValue::Field(FieldElement::zero()),
}
}

Expand Down
40 changes: 40 additions & 0 deletions test_programs/execution_success/debug_logs/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,28 @@ fn main(x: Field, y: pub Field) {
let struct_string = if x != 5 { f"{foo}" } else { f"{bar}" };
std::println(struct_string);

let one_tuple = (1, 2, 3);
let another_tuple = (4, 5, 6);
std::println(f"one_tuple: {one_tuple}, another_tuple: {another_tuple}");
std::println(one_tuple);

let tuples_nested = (one_tuple, another_tuple);
std::println(f"tuples_nested: {tuples_nested}");
std::println(tuples_nested);

regression_2906();

let free_lambda = |x| x + 1;
let sentinel: u32 = 8888;
std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}");
std::println(free_lambda);

let one = 1;
let closured_lambda = |x| x + one;
std::println(f"closured_lambda: {closured_lambda}, sentinel: {sentinel}");
std::println(closured_lambda);

types_printable_in_brillig_only();
}

fn string_identity(string: fmtstr<14, (Field, Field)>) -> fmtstr<14, (Field, Field)> {
Expand Down Expand Up @@ -79,3 +100,22 @@ fn regression_2906() {

dep::std::println(f"array_five_vals: {array_five_vals}, label_five_vals: {label_five_vals}");
}

unconstrained fn types_printable_in_brillig_only() {
let mut a_tuple = (1,2,3);
let mut tuple_mut_ref = &mut a_tuple;
let sentinel: u32 = 8888;
std::println(f"tuple_mut_ref: {tuple_mut_ref}, sentinel: {sentinel}");
std::println(tuple_mut_ref);

let mut a_vector: Vec<Field> = Vec::new();
a_vector.push(10);
a_vector.push(20);
a_vector.push(30);
std::println(f"a_vector: {a_vector}, sentinel: {sentinel}");
std::println(a_vector);

let vec_slice = a_vector.slice;
std::println(f"vec_slice: {vec_slice}, sentinel: {sentinel}");
std::println(vec_slice);
}
Loading