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
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ impl FunctionContext<'_> {
}

fn codegen_match(&mut self, match_expr: &ast::Match) -> Result<Values, RuntimeError> {
let variable = self.lookup(match_expr.variable_to_match);
let variable = self.lookup(match_expr.variable_to_match.0);

// Any matches with only a single case we don't need to check the tag at all.
// Note that this includes all matches on struct / tuple values.
Expand Down Expand Up @@ -962,7 +962,7 @@ impl FunctionContext<'_> {
"Expected enum variant to contain a value for each variant argument"
);

for (value, arg) in variant.into_iter().zip(&case.arguments) {
for (value, (arg, _)) in variant.into_iter().zip(&case.arguments) {
self.define(*arg, value);
}
}
Expand All @@ -978,7 +978,7 @@ impl FunctionContext<'_> {
"Expected field length to match constructor argument count"
);

for (value, arg) in fields.into_iter().zip(&case.arguments) {
for (value, (arg, _)) in fields.into_iter().zip(&case.arguments) {
self.define(*arg, value);
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/monomorphization/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ pub struct If {

#[derive(Debug, Clone, Hash)]
pub struct Match {
pub variable_to_match: LocalId,
pub variable_to_match: (LocalId, String),
pub cases: Vec<MatchCase>,
pub default_case: Option<Box<Expression>>,
pub typ: Type,
Expand All @@ -314,7 +314,7 @@ pub struct Match {
#[derive(Debug, Clone, Hash)]
pub struct MatchCase {
pub constructor: Constructor,
pub arguments: Vec<LocalId>,
pub arguments: Vec<(LocalId, String)>,
pub branch: Expression,
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2181,16 +2181,18 @@ impl<'interner> Monomorphizer<'interner> {
Ok(ast::Expression::If(ast::If { condition, consequence, alternative, typ }))
}
HirMatch::Switch(variable_to_match, cases, default) => {
let variable_to_match = match self.lookup_local(variable_to_match) {
let variable_name = self.interner.definition(variable_to_match).name.clone();
let variable_id = match self.lookup_local(variable_to_match) {
Some(Definition::Local(id)) => id,
other => unreachable!("Expected match variable to be defined. Found {other:?}"),
};

let cases = try_vecmap(cases, |case| {
let arguments = vecmap(case.arguments, |arg| {
let arg_name = self.interner.definition(arg).name.clone();
let new_id = self.next_local_id();
self.define_local(arg, new_id);
new_id
(new_id, arg_name)
});
let branch = self.match_expr(case.body, expr_id)?;
Ok(ast::MatchCase { constructor: case.constructor, arguments, branch })
Expand All @@ -2203,7 +2205,7 @@ impl<'interner> Monomorphizer<'interner> {

let typ = Self::convert_type(&result_type, location)?;
Ok(ast::Expression::Match(ast::Match {
variable_to_match,
variable_to_match: (variable_id, variable_name),
cases,
default_case,
typ,
Expand Down
9 changes: 7 additions & 2 deletions compiler/noirc_frontend/src/monomorphization/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ impl AstPrinter {
self.fmt_ident(name, &Definition::Function(id))
}

fn fmt_match(&self, name: &str, id: LocalId) -> String {
if self.show_id { format!("${}", id.0) } else { self.fmt_local(name, id) }
}

pub fn print_program(&mut self, program: &Program, f: &mut Formatter) -> std::fmt::Result {
for (id, global) in &program.globals {
self.print_global(id, global, f)?;
Expand Down Expand Up @@ -437,13 +441,14 @@ impl AstPrinter {
match_expr: &super::ast::Match,
f: &mut Formatter,
) -> Result<(), std::fmt::Error> {
write!(f, "match ${} {{", match_expr.variable_to_match.0)?;
let (var_id, var_name) = &match_expr.variable_to_match;
write!(f, "match {} {{", self.fmt_match(var_name, *var_id))?;
self.indent_level += 1;
self.next_line(f)?;

for (i, case) in match_expr.cases.iter().enumerate() {
write!(f, "{}", case.constructor)?;
let args = vecmap(&case.arguments, |arg| format!("${}", arg.0)).join(", ");
let args = vecmap(&case.arguments, |(id, name)| self.fmt_match(name, *id)).join(", ");
if !args.is_empty() {
write!(f, "({args})")?;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/ownership/last_uses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ impl LastUseContext {
let match_id = self.next_if_or_match_id();

for (i, case) in match_expr.cases.iter().enumerate() {
for argument in &case.arguments {
for (argument, _) in &case.arguments {
self.declare_variable(*argument);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub fn fuzz(u: &mut Unstructured) -> eyre::Result<()> {
avoid_negative_int_literals: true,
// Avoid break/continue
avoid_loop_control: true,
// Match is not yet implemented in comptime.
avoid_match: true,
// Has to only use expressions valid in comptime
comptime_friendly: true,
// Force brillig, to generate loops that the interpreter can do but ACIR cannot.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub fn fuzz(u: &mut Unstructured) -> eyre::Result<()> {
avoid_negative_int_literals: true,
// Avoid break/continue
avoid_loop_control: true,
// Match is not yet implemented in comptime.
avoid_match: true,
// Has to only use expressions valid in comptime
comptime_friendly: true,
// Force brillig, to generate loops that the interpreter can do but ACIR cannot.
Expand Down
24 changes: 20 additions & 4 deletions tooling/ast_fuzzer/fuzz/src/targets/orig_vs_morph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ mod rules {

// Duplicate the expression, then assign new IDs to all variables created in it.
let mut alt = expr.clone();

reassign_ids(vars, &mut alt);

expr::replace(expr, |expr| expr::if_else(cond, expr, alt, typ));
Expand Down Expand Up @@ -581,8 +582,9 @@ mod rules {
&& !expr::exists(expr, |expr| {
matches!(
expr,
Expression::Let(_) // Creating a variable needs a new ID
| Expression::Block(_) // Applying logical operations on blocks would look odd
Expression::Let(_) // Creating a variable needs a new ID
| Expression::Match(_) // Match creates variables which would need new IDs
| Expression::Block(_) // Applying logical operations on blocks would look odd
)
})
} else {
Expand Down Expand Up @@ -762,6 +764,7 @@ mod helpers {
/// Types we can consider using in this context.
static TYPES: OnceLock<Vec<Type>> = OnceLock::new();

/// Assign new IDs to variables and identifiers created in the expression.
pub(super) fn reassign_ids(vars: &mut VariableContext, expr: &mut Expression) {
fn replace_local_id(
vars: &mut VariableContext,
Expand All @@ -778,8 +781,12 @@ mod helpers {

visit_expr_be_mut(
expr,
// Assign a new ID where variables are created, and remember what original value they replaced.
&mut |expr| {
match expr {
Expression::Ident(ident) => {
ident.id = vars.next_ident_id();
}
Expression::Let(let_) => {
replace_local_id(vars, &mut replacements.borrow_mut(), &mut let_.id)
}
Expand All @@ -788,14 +795,23 @@ mod helpers {
&mut replacements.borrow_mut(),
&mut for_.index_variable,
),
Expression::Ident(ident) => {
ident.id = vars.next_ident_id();
Expression::Match(match_) => {
let mut replacements = replacements.borrow_mut();
if let Some(replacement) = replacements.get(&match_.variable_to_match.0) {
match_.variable_to_match.0 = *replacement;
}
for case in match_.cases.iter_mut() {
for (arg, _) in case.arguments.iter_mut() {
replace_local_id(vars, &mut replacements, arg);
}
}
}
_ => (),
}
(true, ())
},
&mut |_, _| {},
// Update the IDs in identifiers based on the replacements we remember from above.
&mut |ident| {
if let Definition::Local(id) = &mut ident.definition {
if let Some(replacement) = replacements.borrow().get(id) {
Expand Down
21 changes: 15 additions & 6 deletions tooling/ast_fuzzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ pub struct Config {
pub vary_loop_size: bool,
/// Maximum number of recursive calls to make at runtime.
pub max_recursive_calls: usize,
/// Maximum number of match cases.
pub max_match_cases: usize,
/// Frequency of expressions, which produce a value.
pub expr_freqs: Freqs,
/// Frequency of statements in ACIR functions.
Expand All @@ -70,6 +72,8 @@ pub struct Config {
pub avoid_print: bool,
/// Avoid using constrain statements.
pub avoid_constrain: bool,
/// Avoid match statements and expressions.
pub avoid_match: bool,
/// Avoid using the slice type.
pub avoid_slices: bool,
/// Only use comptime friendly expressions.
Expand All @@ -82,6 +86,7 @@ impl Default for Config {
("unary", 10),
("binary", 20),
("if", 15),
("match", 30),
("block", 30),
("vars", 25),
("literal", 5),
Expand All @@ -90,19 +95,21 @@ impl Default for Config {
let stmt_freqs_acir = Freqs::new(&[
("assign", 30),
("if", 10),
("for", 22),
("match", 10),
("for", 25),
("let", 25),
("call", 5),
("constrain", 4),
]);
let stmt_freqs_brillig = Freqs::new(&[
("break", 20),
("continue", 20),
("break", 25),
("continue", 25),
("assign", 30),
("if", 10),
("for", 15),
("loop", 15),
("while", 15),
("match", 15),
("for", 17),
("loop", 17),
("while", 17),
("let", 20),
("call", 5),
("print", 15),
Expand All @@ -121,6 +128,7 @@ impl Default for Config {
max_loop_size: 10,
vary_loop_size: true,
max_recursive_calls: 25,
max_match_cases: 3,
expr_freqs,
stmt_freqs_acir,
stmt_freqs_brillig,
Expand All @@ -133,6 +141,7 @@ impl Default for Config {
avoid_lambdas: false,
avoid_print: false,
avoid_constrain: false,
avoid_match: false,
avoid_slices: false,
comptime_friendly: false,
}
Expand Down
Loading
Loading