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
3 changes: 1 addition & 2 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1803,8 +1803,7 @@
}
}

let could_be_checked_cast = false;
match self.canonicalize_helper(could_be_checked_cast, run_simplifications) {
match self.canonicalize_with_simplifications(run_simplifications) {
Type::Constant(x, constant_kind) => {
if kind.unifies(&constant_kind) {
kind.ensure_value_fits(x, location)
Expand Down Expand Up @@ -2014,7 +2013,7 @@
}

let recur_on_binding = |id, replacement: &Type| {
// Prevent recuring forever if there's a `T := T` binding

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (recuring)
if replacement.type_variable_id() == Some(id) {
replacement.clone()
} else {
Expand Down Expand Up @@ -2100,7 +2099,7 @@
Type::Tuple(fields)
}
Type::Forall(typevars, typ) => {
// Trying to substitute_helper a variable de, substitute_bound_typevarsfined within a nested Forall

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsfined)
// is usually impossible and indicative of an error in the type checker somewhere.
for var in typevars {
assert!(!type_bindings.contains_key(&var.id()));
Expand Down Expand Up @@ -2267,7 +2266,7 @@
}
}

/// Follow bindings if this is a type variable or generic to the first non-typevariable

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevariable)
/// type. Unlike `follow_bindings`, this won't recursively follow any bindings on any
/// fields or arguments of this type.
pub fn follow_bindings_shallow(&self) -> Cow<Type> {
Expand All @@ -2292,7 +2291,7 @@

/// Replace any `Type::NamedGeneric` in this type with a `Type::TypeVariable`
/// using to the same inner `TypeVariable`. This is used during monomorphization
/// to bind to named generics since they are unbindable during type checking.

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (unbindable)
pub fn replace_named_generics_with_type_variables(&mut self) {
match self {
Type::FieldElement
Expand Down Expand Up @@ -2809,7 +2808,7 @@
len.hash(state);
env.hash(state);
}
Type::Tuple(elems) => elems.hash(state),

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)
Type::DataType(def, args) => {
def.hash(state);
args.hash(state);
Expand Down
59 changes: 33 additions & 26 deletions compiler/noirc_frontend/src/hir_def/types/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,43 @@ impl Type {
}
}

pub(crate) fn canonicalize_with_simplifications(&self, run_simplifications: bool) -> Type {
self.follow_bindings().canonicalize_helper(false, run_simplifications)
}

/// Only simplify constants and drop/skip any CheckedCast's
pub(crate) fn canonicalize_checked(&self) -> Type {
self.follow_bindings().canonicalize_checked_helper()
}

/// Only simplify constants and drop/skip any CheckedCast's
fn canonicalize_checked_helper(&self) -> Type {
let found_checked_cast = true;
let skip_simplifications = false;
// We expect `self` to have already called `follow_bindings`
self.canonicalize_helper(found_checked_cast, skip_simplifications)
}

/// Run all simplifications and drop/skip any CheckedCast's
fn canonicalize_unchecked(&self) -> Type {
let found_checked_cast = true;
let run_simplifications = true;
// We expect `self` to have already called `follow_bindings`
self.canonicalize_helper(found_checked_cast, run_simplifications)
}

/// If found_checked_cast, then drop additional CheckedCast's
/// If `found_checked_cast`, then drop additional CheckedCast's
///
/// If run_simplifications is false, then only:
/// If `run_simplifications` is false, then only:
/// - Attempt to evaluate each sub-expression to a constant
/// - Drop nested CheckedCast's
///
/// Otherwise also attempt try_simplify_partial_constants, sort_commutative,
/// and other simplifications
pub(crate) fn canonicalize_helper(
&self,
found_checked_cast: bool,
run_simplifications: bool,
) -> Type {
match self.follow_bindings() {
fn canonicalize_helper(&self, found_checked_cast: bool, run_simplifications: bool) -> Type {
match self {
Type::InfixExpr(lhs, op, rhs, inversion) => {
let kind = lhs.infix_kind(&rhs);
let kind = lhs.infix_kind(rhs);
let dummy_location = Location::dummy();
// evaluate_to_field_element also calls canonicalize so if we just called
// `self.evaluate_to_field_element(..)` we'd get infinite recursion.
Expand All @@ -82,28 +89,28 @@ impl Type {
let rhs = rhs.canonicalize_helper(found_checked_cast, run_simplifications);

if !run_simplifications {
return Type::InfixExpr(Box::new(lhs), op, Box::new(rhs), inversion);
return Type::InfixExpr(Box::new(lhs), *op, Box::new(rhs), *inversion);
}

if let Some(result) = Self::try_simplify_non_constants_in_lhs(&lhs, op, &rhs) {
if let Some(result) = Self::try_simplify_non_constants_in_lhs(&lhs, *op, &rhs) {
return result.canonicalize_unchecked();
}

if let Some(result) = Self::try_simplify_non_constants_in_rhs(&lhs, op, &rhs) {
if let Some(result) = Self::try_simplify_non_constants_in_rhs(&lhs, *op, &rhs) {
return result.canonicalize_unchecked();
}

// Try to simplify partially constant expressions in the form `(N op1 C1) op2 C2`
// where C1 and C2 are constants that can be combined (e.g. N + 5 - 3 = N + 2)
if let Some(result) = Self::try_simplify_partial_constants(&lhs, op, &rhs) {
if let Some(result) = Self::try_simplify_partial_constants(&lhs, *op, &rhs) {
return result.canonicalize_unchecked();
}

if op.is_commutative() {
return Self::sort_commutative(&lhs, op, &rhs);
return Self::sort_commutative(&lhs, *op, &rhs);
}

Type::InfixExpr(Box::new(lhs), op, Box::new(rhs), inversion)
Type::InfixExpr(Box::new(lhs), *op, Box::new(rhs), *inversion)
}
Type::CheckedCast { from, to } => {
let inner_found_checked_cast = true;
Expand All @@ -117,7 +124,7 @@ impl Type {

Type::CheckedCast { from: Box::new(from), to: Box::new(to) }
}
other => other,
other => other.clone(),
}
}

Expand Down Expand Up @@ -195,24 +202,24 @@ impl Type {
op: BinaryTypeOperator,
rhs: &Type,
) -> Option<Type> {
match lhs.follow_bindings() {
match lhs {
Type::CheckedCast { from, to } => {
// Apply operation directly to `from` while attempting simplification to `to`.
let from = Type::infix_expr(from, op, Box::new(rhs.clone()));
let to = Self::try_simplify_non_constants_in_lhs(&to, op, rhs)?;
let from = Type::infix_expr(from.clone(), op, Box::new(rhs.clone()));
let to = Self::try_simplify_non_constants_in_lhs(to, op, rhs)?;
Some(Type::CheckedCast { from: Box::new(from), to: Box::new(to) })
}
Type::InfixExpr(l_lhs, l_op, l_rhs, _) => {
// Note that this is exact, syntactic equality, not unification.
// `rhs` is expected to already be in canonical form.
if l_op.approx_inverse() != Some(op)
|| l_op == BinaryTypeOperator::Division
|| *l_op == BinaryTypeOperator::Division
|| l_rhs.canonicalize_unchecked() != *rhs
{
return None;
}

Some(*l_lhs)
Some(*l_lhs.clone())
}
_ => None,
}
Expand All @@ -232,17 +239,17 @@ impl Type {
op: BinaryTypeOperator,
rhs: &Type,
) -> Option<Type> {
match rhs.follow_bindings() {
match rhs {
Type::CheckedCast { from, to } => {
// Apply operation directly to `from` while attempting simplification to `to`.
let from = Type::infix_expr(Box::new(lhs.clone()), op, from);
let to = Self::try_simplify_non_constants_in_rhs(lhs, op, &to)?;
let from = Type::infix_expr(Box::new(lhs.clone()), op, from.clone());
let to = Self::try_simplify_non_constants_in_rhs(lhs, op, to)?;
Some(Type::CheckedCast { from: Box::new(from), to: Box::new(to) })
}
Type::InfixExpr(r_lhs, r_op, r_rhs, _) => {
// `N / (M * N)` should be simplified to `1 / M`, but we only handle
// simplifying to `M` in this function.
if op == BinaryTypeOperator::Division && r_op == BinaryTypeOperator::Multiplication
if op == BinaryTypeOperator::Division && *r_op == BinaryTypeOperator::Multiplication
{
return None;
}
Expand All @@ -253,7 +260,7 @@ impl Type {
return None;
}

Some(*r_lhs)
Some(*r_lhs.clone())
}
_ => None,
}
Expand Down
Loading