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
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,7 @@ fn print_lambda() {

let printed_output = expect_printed_output(src);

insta::assert_snapshot!(printed_output, @"
<<fn([Field]) -> Field>>
");
insta::assert_snapshot!(printed_output, @"<<fn(Field) -> Field>>");
}

#[test]
Expand Down
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 @@ -2722,12 +2722,16 @@ impl From<&Type> for PrintableType {
Type::CheckedCast { to, .. } => to.as_ref().into(),
Type::NamedGeneric(..) => unreachable!(),
Type::Forall(..) => unreachable!(),
Type::Function(arguments, return_type, env, unconstrained) => PrintableType::Function {
arguments: arguments.iter().map(|arg| arg.into()).collect(),
return_type: Box::new(return_type.as_ref().into()),
env: Box::new(env.as_ref().into()),
unconstrained: *unconstrained,
},
Type::Function(arguments, return_type, env, _unconstrained) => {
// Mimicking `Monomorphizer::convert_type_helper`: functions are represented as a tuple of constrained and unconstrained version.
let make_function = |unconstrained| PrintableType::Function {
arguments: arguments.iter().map(|arg| arg.into()).collect(),
return_type: Box::new(return_type.as_ref().into()),
env: Box::new(env.as_ref().into()),
unconstrained,
};
PrintableType::Tuple { types: vecmap([false, true], make_function) }
}
Type::Reference(typ, mutable) => {
PrintableType::Reference { typ: Box::new(typ.as_ref().into()), mutable: *mutable }
}
Expand Down
36 changes: 36 additions & 0 deletions compiler/noirc_frontend/src/monomorphization/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,47 @@ impl AstPrinter {
tuple: &[Expression],
f: &mut Formatter,
) -> Result<(), std::fmt::Error> {
if self.print_function_tuple(tuple, f)? {
return Ok(());
}
write!(f, "(")?;
self.print_comma_separated(tuple, f)?;
write!(f, ")")
}

/// Check if we have a tuple of (constrained, unconstrained) functions and if we want to print specials as std calls,
/// then assume that we would rather see `println(foo)` than `println((foo, foo))`, so we can render the AST as Noir
/// without duplicating into `println(((foo, foo), (foo, foo)))` if we print the AST and re-parse it, for example for comptime tests.
///
/// Returns a flag to indicate if the items were handled.
fn print_function_tuple(
&mut self,
tuple: &[Expression],
f: &mut Formatter,
) -> Result<bool, std::fmt::Error> {
if !self.show_specials_as_std || tuple.len() != 2 {
return Ok(false);
}

fn maybe_func(expr: &Expression) -> Option<&str> {
// The AST fuzzer generates Type::Function; the Monomorphizer would be Type::Tuple([Type::Function, Type::Function])
if let Expression::Ident(Ident { typ: Type::Function(_, _, _, _), name, .. }) = expr {
Some(name.as_str())
} else {
None
}
}

match (maybe_func(&tuple[0]), maybe_func(&tuple[1])) {
(Some(c), Some(u)) if c == u => {
// Only print the first element.
self.print_expr(&tuple[0], f)?;
Ok(true)
}
_ => Ok(false),
}
}

fn get_called_function(expr: &Expression) -> Option<(bool, &Definition, &String)> {
let is_unconstrained = |typ: &Type| match typ {
Type::Function(_, _, _, unconstrained) => *unconstrained,
Expand Down
47 changes: 45 additions & 2 deletions compiler/noirc_printable_type/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,49 @@ pub enum PrintableType {
Unit,
}

/// Display type for the purpose of showing in function signatures.
impl std::fmt::Display for PrintableType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PrintableType::Field => write!(f, "Field"),
PrintableType::Array { length, typ } => write!(f, "[{typ}; {length}]"),
PrintableType::Slice { typ } => write!(f, "[{typ}]"),
PrintableType::Tuple { types } => {
let types = vecmap(types, ToString::to_string);
if types.len() == 1 {
write!(f, "({},)", types[0])
} else {
write!(f, "({})", types.join(", "))
}
}
PrintableType::SignedInteger { width } => write!(f, "i{width}"),
PrintableType::UnsignedInteger { width } => write!(f, "u{width}"),
PrintableType::Boolean => write!(f, "bool"),
PrintableType::Struct { name, fields: _ } => {
write!(f, "{name}")
}
PrintableType::Enum { name, variants: _ } => {
write!(f, "{name}")
}
PrintableType::String { length } => write!(f, "str<{length}>"),
PrintableType::FmtString { length, typ } => write!(f, "fmtstr<{length}, {typ}>"),
PrintableType::Function { arguments, return_type, env: _, unconstrained } => {
let cons = if *unconstrained { "unconstrained " } else { "" };
let args = vecmap(arguments, ToString::to_string).join(", ");
write!(f, "{cons}fn({args}) -> {return_type}")
}
PrintableType::Reference { typ, mutable } => {
if *mutable {
write!(f, "&mut {typ}")
} else {
write!(f, "&{typ}")
}
}
PrintableType::Unit => write!(f, "()"),
}
}
}

/// This is what all formats eventually transform into
/// For example, a toml file will parse into TomlTypes
/// and those TomlTypes will be mapped to Value
Expand Down Expand Up @@ -132,8 +175,8 @@ fn to_string<F: AcirField>(value: &PrintableValue<F>, typ: &PrintableType) -> Op
output.push_str("false");
}
}
(PrintableValue::Field(_), PrintableType::Function { arguments, return_type, .. }) => {
output.push_str(&format!("<<fn({arguments:?}) -> {return_type:?}>>",));
(PrintableValue::Field(_), PrintableType::Function { .. }) => {
output.push_str(&format!("<<{typ}>>"));
}
(_, PrintableType::Reference { mutable: false, .. }) => {
output.push_str("<<ref>>");
Expand Down
6 changes: 6 additions & 0 deletions test_programs/execution_success/regression_10158/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "regression_10158"
type = "bin"
authors = [""]

[dependencies]
7 changes: 7 additions & 0 deletions test_programs/execution_success/regression_10158/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub fn main() {
println((foo, 10_u32));
}

fn foo(_a: u32, _b: bool) -> Field {
0
}
17 changes: 15 additions & 2 deletions tooling/ast_fuzzer/src/program/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,17 +1460,30 @@ impl<'a> FunctionContext<'a> {

// Print one of the variables as-is.
let (id, typ) = u.choose_iter(opts)?;
let id = *id;

// The print oracle takes 2 parameters: the newline marker and the value,
// but it takes 2 more arguments: the type descriptor and the format string marker,
// which are inserted automatically by the monomorphizer.
let param_types = vec![Type::Bool, typ.clone()];
let hir_type = types::to_hir_type(typ);
let ident = self.local_ident(*id);
let ident = self.local_ident(id);

// Functions need to be passed as a tuple.
let arg = if types::is_function(&ident.typ) {
Expression::Tuple(vec![
Expression::Ident(ident),
Expression::Ident(self.local_ident(id)),
])
} else {
Expression::Ident(ident)
};

let mut args = vec![
expr::lit_bool(true), // include newline,
Expression::Ident(ident),
arg,
];

append_printable_type_info_for_type(hir_type, &mut args);

let print_oracle_ident = Ident {
Expand Down
4 changes: 3 additions & 1 deletion tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn main() -> Result<(), String> {

/// Some tests are explicitly ignored in brillig due to them failing.
/// These should be fixed and removed from this list.
const IGNORED_BRILLIG_TESTS: [&str; 10] = [
const IGNORED_BRILLIG_TESTS: [&str; 11] = [
// bit sizes for bigint operation doesn't match up.
"bigint",
// ICE due to looking for function which doesn't exist.
Expand All @@ -86,6 +86,8 @@ const IGNORED_BRILLIG_TESTS: [&str; 10] = [
"fold_numeric_generic_poseidon",
// Expected to fail as test asserts on which runtime it is in.
"is_unconstrained",
// The output depends on function IDs of lambdas, and with --force-brillig we only get one kind.
"regression_10158",
];

/// Tests which aren't expected to work with the default minimum inliner cases.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading