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 @@ -5,3 +5,4 @@
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc fc27f4091dfa5f938973048209b5fcf22aefa1cfaffaaa3e349f30e9b1f93f49 # shrinks to infix_and_bindings = (((0: numeric bool) % (Numeric(Shared(RefCell { value: Unbound('2, Numeric(bool)) }): bool) + Numeric(Shared(RefCell { value: Unbound('0, Numeric(bool)) }): bool))), [('0, (0: numeric bool)), ('1, (0: numeric bool)), ('2, (0: numeric bool))])
cc ebe53a1b6d6dda87e80761d4c56069bfc39f9f5e7e301e6a8f9e4fbbc33af85c # shrinks to infix_type_bindings = (((Numeric(Shared(RefCell { value: '2 }): bool) + (0: numeric bool)) - ((0: numeric bool) - (0: numeric bool))), bool, [('0, (0: numeric bool)), ('1, (0: numeric bool)), ('2, (0: numeric bool)), ('3, (0: numeric bool)), ('4, (0: numeric bool)), ('5, (0: numeric bool)), ('6, (0: numeric bool)), ('7, (0: numeric bool))])
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ impl Elaborator<'_> {
(lhs, rhs) => {
let infix = Type::infix_expr(Box::new(lhs), op, Box::new(rhs));
Type::CheckedCast { from: Box::new(infix.clone()), to: Box::new(infix) }
.canonicalize()
.canonicalize(&TypeBindings::default())
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,10 +645,11 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
unreachable!("Expected associated type to be numeric");
};
let location = self.elaborator.interner.expr_location(&id);
match associated_type
.typ
.evaluate_to_field_element(&associated_type.typ.kind(), location)
{
match associated_type.typ.evaluate_to_field_element(
&associated_type.typ.kind(),
&TypeBindings::default(),
location,
) {
Ok(value) => self.evaluate_integer(value.into(), id),
Err(err) => Err(InterpreterError::NonIntegerArrayLength {
typ: associated_type.typ.clone(),
Expand All @@ -665,7 +666,11 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
fn evaluate_numeric_generic(&self, value: Type, expected: &Type, id: ExprId) -> IResult<Value> {
let location = self.elaborator.interner.id_location(id);
let value = value
.evaluate_to_field_element(&Kind::Numeric(Box::new(expected.clone())), location)
.evaluate_to_field_element(
&Kind::Numeric(Box::new(expected.clone())),
&TypeBindings::default(),
location,
)
.map_err(|err| {
let typ = value;
let err = Some(Box::new(err));
Expand Down
75 changes: 54 additions & 21 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ impl TypeVariable {

/// TypeBindings are the mutable insides of a TypeVariable.
/// They are either bound to some type, or are unbound.
#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum TypeBinding {
Bound(Type),
Unbound(TypeVariableId, Kind),
Expand Down Expand Up @@ -1099,7 +1099,7 @@ impl std::fmt::Display for Type {
}
Type::Quoted(quoted) => write!(f, "{quoted}"),
Type::InfixExpr(lhs, op, rhs, _) => {
let this = self.canonicalize_checked();
let this = self.canonicalize_checked(&TypeBindings::default());

// Prevent infinite recursion
if this != *self { write!(f, "{this}") } else { write!(f, "({lhs} {op} {rhs})") }
Expand Down Expand Up @@ -1135,6 +1135,15 @@ impl std::fmt::Display for TypeBinding {
}
}

impl std::fmt::Debug for TypeBinding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TypeBinding::Bound(typ) => typ.fmt(f),
TypeBinding::Unbound(id, _) => id.fmt(f),
}
}
}

impl std::fmt::Display for QuotedType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down Expand Up @@ -1841,44 +1850,63 @@ impl Type {
/// If this type is a Type::Constant (used in array lengths), or is bound
/// to a Type::Constant, return the constant as a u32.
pub fn evaluate_to_u32(&self, location: Location) -> Result<u32, TypeCheckError> {
self.evaluate_to_field_element(&Kind::u32(), location).map(|field_element| {
field_element
.try_to_u32()
.expect("ICE: size should have already been checked by evaluate_to_field_element")
})
self.evaluate_to_field_element(&Kind::u32(), &TypeBindings::default(), location).map(
|field_element| {
field_element.try_to_u32().expect(
"ICE: size should have already been checked by evaluate_to_field_element",
)
},
)
}

// TODO(https://github.com/noir-lang/noir/issues/6260): remove
// the unifies checks once all kinds checks are implemented?
pub(crate) fn evaluate_to_field_element(
&self,
kind: &Kind,
bindings: &TypeBindings,
location: Location,
) -> Result<acvm::FieldElement, TypeCheckError> {
let run_simplifications = true;
self.evaluate_to_field_element_helper(kind, location, run_simplifications)
self.evaluate_to_field_element_helper(kind, location, bindings, run_simplifications)
}

/// evaluate_to_field_element with optional generic arithmetic simplifications
pub(crate) fn evaluate_to_field_element_helper(
&self,
kind: &Kind,
location: Location,
bindings: &TypeBindings,
run_simplifications: bool,
) -> Result<acvm::FieldElement, TypeCheckError> {
if let Some((binding, binding_kind)) = self.get_inner_type_variable() {
if let TypeBinding::Bound(binding) = &*binding.borrow() {
if kind.unifies(&binding_kind) {
return binding.evaluate_to_field_element_helper(
&binding_kind,
location,
run_simplifications,
);
match &*binding.borrow() {
TypeBinding::Bound(binding) => {
if kind.unifies(&binding_kind) {
return binding.evaluate_to_field_element_helper(
&binding_kind,
location,
bindings,
run_simplifications,
);
}
}
TypeBinding::Unbound(type_variable_id, kind) => {
if kind.unifies(&binding_kind) {
if let Some((_, _, typ)) = bindings.get(type_variable_id) {
return typ.evaluate_to_field_element_helper(
&binding_kind,
location,
bindings,
run_simplifications,
);
}
}
}
}
}

match self.canonicalize_with_simplifications(run_simplifications) {
match self.canonicalize_with_simplifications(bindings, run_simplifications) {
Type::Constant(x, constant_kind) => {
if kind.unifies(&constant_kind) {
kind.ensure_value_fits(x, location)
Expand All @@ -1896,11 +1924,13 @@ impl Type {
let lhs_value = lhs.evaluate_to_field_element_helper(
&infix_kind,
location,
bindings,
run_simplifications,
)?;
let rhs_value = rhs.evaluate_to_field_element_helper(
&infix_kind,
location,
bindings,
run_simplifications,
)?;
op.function(lhs_value, rhs_value, &infix_kind, location)
Expand All @@ -1913,14 +1943,17 @@ impl Type {
}
}
Type::CheckedCast { from, to } => {
let to_value = to.evaluate_to_field_element(kind, location)?;
let to_value = to.evaluate_to_field_element(kind, bindings, location)?;

// if both 'to' and 'from' evaluate to a constant,
// return None unless they match
let skip_simplifications = false;
if let Ok(from_value) =
from.evaluate_to_field_element_helper(kind, location, skip_simplifications)
{
if let Ok(from_value) = from.evaluate_to_field_element_helper(
kind,
location,
bindings,
skip_simplifications,
) {
if to_value == from_value {
Ok(to_value)
} else {
Expand Down Expand Up @@ -2779,7 +2812,7 @@ impl std::fmt::Debug for Type {
Kind::Numeric(typ) => write!(f, "Numeric({binding:?}: {typ:?})"),
}
} else {
write!(f, "{}", binding.borrow())
write!(f, "{:?}", binding.borrow())
}
}
Type::DataType(s, args) => {
Expand Down
Loading
Loading