Skip to content
4 changes: 3 additions & 1 deletion compiler/noirc_driver/src/abi_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,9 @@ pub(super) fn value_from_hir_expression(context: &Context, expression: HirExpres
},
HirLiteral::Bool(value) => AbiValue::Boolean { value },
HirLiteral::Str(value) => AbiValue::String { value },
HirLiteral::Integer(field, sign) => AbiValue::Integer { value: field.to_hex(), sign },
HirLiteral::Integer(value) => {
AbiValue::Integer { value: value.field.to_hex(), sign: value.is_negative }
}
_ => unreachable!("Literal cannot be used in the abi"),
},
_ => unreachable!("Type cannot be used in the abi {:?}", expression),
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_evaluator/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//! An Error of the former is a user Error
//!
//! An Error of the latter is an error in the implementation of the compiler
use acvm::FieldElement;
use iter_extended::vecmap;
use noirc_errors::{CustomDiagnostic as Diagnostic, FileDiagnostic, Location};
use noirc_frontend::signed_field::SignedField;
use thiserror::Error;

use crate::ssa::ir::{call_stack::CallStack, types::NumericType};
Expand All @@ -23,7 +23,7 @@ pub enum RuntimeError {
InvalidRangeConstraint { num_bits: u32, call_stack: CallStack },
#[error("The value `{value:?}` cannot fit into `{typ}` which has range `{range}`")]
IntegerOutOfBounds {
value: FieldElement,
value: SignedField,
typ: NumericType,
range: String,
call_stack: CallStack,
Expand Down
33 changes: 15 additions & 18 deletions compiler/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use noirc_frontend::signed_field::SignedField;
use serde::{Deserialize, Serialize};
use std::sync::Arc;

Expand Down Expand Up @@ -58,18 +59,14 @@ impl NumericType {
/// Returns None if the given Field value is within the numeric limits
/// for the current NumericType. Otherwise returns a string describing
/// the limits, as a range.
pub(crate) fn value_is_outside_limits(
self,
field: FieldElement,
negative: bool,
) -> Option<String> {
pub(crate) fn value_is_outside_limits(self, value: SignedField) -> Option<String> {
match self {
NumericType::Unsigned { bit_size } => {
let max = if bit_size == 128 { u128::MAX } else { 2u128.pow(bit_size) - 1 };
if negative {
if value.is_negative {
return Some(format!("0..={}", max));
}
if field <= max.into() {
if value.field <= max.into() {
None
} else {
Some(format!("0..={}", max))
Expand All @@ -78,8 +75,8 @@ impl NumericType {
NumericType::Signed { bit_size } => {
let min = 2u128.pow(bit_size - 1);
let max = 2u128.pow(bit_size - 1) - 1;
let target_max = if negative { min } else { max };
if field <= target_max.into() {
let target_max = if value.is_negative { min } else { max };
if value.field <= target_max.into() {
None
} else {
Some(format!("-{}..={}", min, max))
Expand Down Expand Up @@ -307,19 +304,19 @@ mod tests {
#[test]
fn test_u8_value_is_outside_limits() {
let u8 = NumericType::Unsigned { bit_size: 8 };
assert!(u8.value_is_outside_limits(FieldElement::from(1_i128), true).is_some());
assert!(u8.value_is_outside_limits(FieldElement::from(0_i128), false).is_none());
assert!(u8.value_is_outside_limits(FieldElement::from(255_i128), false).is_none());
assert!(u8.value_is_outside_limits(FieldElement::from(256_i128), false).is_some());
assert!(u8.value_is_outside_limits(SignedField::negative(1_i128)).is_some());
assert!(u8.value_is_outside_limits(SignedField::positive(0_i128)).is_none());
assert!(u8.value_is_outside_limits(SignedField::positive(255_i128)).is_none());
assert!(u8.value_is_outside_limits(SignedField::positive(256_i128)).is_some());
}

#[test]
fn test_i8_value_is_outside_limits() {
let i8 = NumericType::Signed { bit_size: 8 };
assert!(i8.value_is_outside_limits(FieldElement::from(129_i128), true).is_some());
assert!(i8.value_is_outside_limits(FieldElement::from(128_i128), true).is_none());
assert!(i8.value_is_outside_limits(FieldElement::from(0_i128), false).is_none());
assert!(i8.value_is_outside_limits(FieldElement::from(127_i128), false).is_none());
assert!(i8.value_is_outside_limits(FieldElement::from(128_i128), false).is_some());
assert!(i8.value_is_outside_limits(SignedField::negative(129_i128)).is_some());
assert!(i8.value_is_outside_limits(SignedField::negative(128_i128)).is_none());
assert!(i8.value_is_outside_limits(SignedField::positive(0_i128)).is_none());
assert!(i8.value_is_outside_limits(SignedField::positive(127_i128)).is_none());
assert!(i8.value_is_outside_limits(SignedField::positive(128_i128)).is_some());
}
}
18 changes: 8 additions & 10 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use noirc_errors::Location;
use noirc_frontend::ast::{BinaryOpKind, Signedness};
use noirc_frontend::monomorphization::ast::{self, GlobalId, InlineType, LocalId, Parameters};
use noirc_frontend::monomorphization::ast::{FuncId, Program};
use noirc_frontend::signed_field::SignedField;

use crate::errors::RuntimeError;
use crate::ssa::function_builder::FunctionBuilder;
Expand Down Expand Up @@ -289,33 +290,30 @@ impl<'a> FunctionContext<'a> {
/// otherwise values like 2^128 can be assigned to a u8 without error or wrapping.
pub(super) fn checked_numeric_constant(
&mut self,
value: impl Into<FieldElement>,
negative: bool,
value: SignedField,
numeric_type: NumericType,
) -> Result<ValueId, RuntimeError> {
let value = value.into();

if let Some(range) = numeric_type.value_is_outside_limits(value, negative) {
if let Some(range) = numeric_type.value_is_outside_limits(value) {
let call_stack = self.builder.get_call_stack();
return Err(RuntimeError::IntegerOutOfBounds {
value: if negative { -value } else { value },
value,
typ: numeric_type,
range,
call_stack,
});
}

let value = if negative {
let value = if value.is_negative {
match numeric_type {
NumericType::NativeField => -value,
NumericType::NativeField => -value.field,
NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => {
assert!(bit_size < 128);
let base = 1_u128 << bit_size;
FieldElement::from(base) - value
FieldElement::from(base) - value.field
}
}
} else {
value
value.field
};

Ok(self.builder.numeric_constant(value, numeric_type))
Expand Down
8 changes: 3 additions & 5 deletions compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@
_ => unreachable!("ICE: unexpected slice literal type, got {}", array.typ),
})
}
ast::Literal::Integer(value, negative, typ, location) => {
ast::Literal::Integer(value, typ, location) => {
self.builder.set_location(*location);
let typ = Self::convert_non_tuple_type(typ).unwrap_numeric();
self.checked_numeric_constant(*value, *negative, typ).map(Into::into)
self.checked_numeric_constant(*value, typ).map(Into::into)
}
ast::Literal::Bool(value) => {
// Don't need to call checked_numeric_constant here since `value` can only be true or false
Expand Down Expand Up @@ -526,7 +526,7 @@
/// br loop_entry(v0)
/// loop_entry(i: Field):
/// v2 = lt i v1
/// brif v2, then: loop_body, else: loop_end

Check warning on line 529 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// loop_body():
/// v3 = ... codegen body ...
/// v4 = add 1, i
Expand Down Expand Up @@ -670,7 +670,7 @@
///
/// ```text
/// v0 = ... codegen cond ...
/// brif v0, then: then_block, else: else_block

Check warning on line 673 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// then_block():
/// v1 = ... codegen a ...
/// br end_if(v1)
Expand All @@ -685,7 +685,7 @@
///
/// ```text
/// v0 = ... codegen cond ...
/// brif v0, then: then_block, else: end_if

Check warning on line 688 in compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (brif)
/// then_block:
/// v1 = ... codegen a ...
/// br end_if()
Expand Down Expand Up @@ -820,9 +820,7 @@
typ: NumericType,
) -> Result<ValueId, RuntimeError> {
match constructor {
Constructor::Int(value) => {
self.checked_numeric_constant(value.field, value.is_negative, typ)
}
Constructor::Int(value) => self.checked_numeric_constant(*value, typ),
other => Ok(self.builder.numeric_constant(other.variant_index(), typ)),
}
}
Expand Down
19 changes: 8 additions & 11 deletions compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use crate::ast::{
UnresolvedType, UnresolvedTypeData, Visibility,
};
use crate::node_interner::{ExprId, InternedExpressionKind, InternedStatementKind, QuotedTypeId};
use crate::signed_field::SignedField;
use crate::token::{Attributes, FmtStrFragment, FunctionAttribute, Token, Tokens};
use crate::{Kind, Type};
use acvm::{acir::AcirField, FieldElement};
use acvm::FieldElement;
use iter_extended::vecmap;
use noirc_errors::{Located, Location, Span};

Expand Down Expand Up @@ -170,8 +171,8 @@ impl ExpressionKind {
match (operator, &rhs) {
(
UnaryOp::Minus,
Expression { kind: ExpressionKind::Literal(Literal::Integer(field, sign)), .. },
) => ExpressionKind::Literal(Literal::Integer(*field, !sign)),
Expression { kind: ExpressionKind::Literal(Literal::Integer(field)), .. },
) => ExpressionKind::Literal(Literal::Integer(-*field)),
_ => ExpressionKind::Prefix(Box::new(PrefixExpression { operator, rhs })),
}
}
Expand Down Expand Up @@ -199,7 +200,7 @@ impl ExpressionKind {
}

pub fn integer(contents: FieldElement) -> ExpressionKind {
ExpressionKind::Literal(Literal::Integer(contents, false))
ExpressionKind::Literal(Literal::Integer(SignedField::positive(contents)))
}

pub fn boolean(contents: bool) -> ExpressionKind {
Expand Down Expand Up @@ -409,7 +410,7 @@ pub enum Literal {
Array(ArrayLiteral),
Slice(ArrayLiteral),
Bool(bool),
Integer(FieldElement, /*sign*/ bool), // false for positive integer and true for negative
Integer(SignedField),
Str(String),
RawStr(String, u8),
FmtStr(Vec<FmtStrFragment>, u32 /* length */),
Expand Down Expand Up @@ -686,12 +687,8 @@ impl Display for Literal {
write!(f, "&[{repeated_element}; {length}]")
}
Literal::Bool(boolean) => write!(f, "{}", if *boolean { "true" } else { "false" }),
Literal::Integer(integer, sign) => {
if *sign {
write!(f, "-{}", integer.to_u128())
} else {
write!(f, "{}", integer.to_u128())
}
Literal::Integer(signed_field) => {
write!(f, "{signed_field}")
}
Literal::Str(string) => write!(f, "\"{string}\""),
Literal::RawStr(string, num_hashes) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@

fn from_expr_helper(expr: Expression) -> Result<UnresolvedTypeExpression, Expression> {
match expr.kind {
ExpressionKind::Literal(Literal::Integer(int, _)) => match int.try_to_u32() {
ExpressionKind::Literal(Literal::Integer(int)) => match int.try_to_unsigned::<u32>() {
Some(int) => Ok(UnresolvedTypeExpression::Constant(int.into(), expr.location)),
None => Err(expr),
},
Expand Down Expand Up @@ -604,7 +604,7 @@
Self::Public => write!(f, "pub"),
Self::Private => write!(f, "priv"),
Self::CallData(id) => write!(f, "calldata{id}"),
Self::ReturnData => write!(f, "returndata"),

Check warning on line 607 in compiler/noirc_frontend/src/ast/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (returndata)
}
}
}
8 changes: 4 additions & 4 deletions compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use acvm::FieldElement;
use noirc_errors::Span;

use crate::{
Expand All @@ -16,6 +15,7 @@ use crate::{
InternedUnresolvedTypeData, QuotedTypeId,
},
parser::{Item, ItemKind, ParsedSubModule},
signed_field::SignedField,
token::{FmtStrFragment, MetaAttribute, SecondaryAttribute, Tokens},
ParsedModule, QuotedType,
};
Expand Down Expand Up @@ -172,7 +172,7 @@ pub trait Visitor {

fn visit_literal_bool(&mut self, _: bool, _: Span) {}

fn visit_literal_integer(&mut self, _value: FieldElement, _negative: bool, _: Span) {}
fn visit_literal_integer(&mut self, _value: SignedField, _: Span) {}

fn visit_literal_str(&mut self, _: &str, _: Span) {}

Expand Down Expand Up @@ -946,8 +946,8 @@ impl Literal {
}
}
Literal::Bool(value) => visitor.visit_literal_bool(*value, span),
Literal::Integer(value, negative) => {
visitor.visit_literal_integer(*value, *negative, span);
Literal::Integer(value) => {
visitor.visit_literal_integer(*value, span);
}
Literal::Str(str) => visitor.visit_literal_str(str, span),
Literal::RawStr(str, length) => visitor.visit_literal_raw_str(str, *length, span),
Expand Down
7 changes: 5 additions & 2 deletions compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::ast::PathSegment;
use crate::parse_program;
use crate::parser::ParsedModule;
use crate::signed_field::SignedField;
use crate::{
ast,
ast::Path,
Expand Down Expand Up @@ -314,7 +315,7 @@
}
ast::LValue::Dereference(_lv, location) => {
// TODO: this is a dummy statement for now, but we should
// somehow track the derefence and update the pointed to

Check warning on line 318 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (derefence)
// variable
ast::Statement {
kind: ast::StatementKind::Expression(uint_expr(0, *location)),
Expand Down Expand Up @@ -718,9 +719,9 @@
ast::Pattern::Tuple(patterns, _) => {
stack.extend(patterns.iter().map(|pattern| (pattern, false)));
}
ast::Pattern::Struct(_, pids, _) => {

Check warning on line 722 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
stack.extend(pids.iter().map(|(_, pattern)| (pattern, is_mut)));

Check warning on line 723 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
vars.extend(pids.iter().map(|(id, _)| (id.clone(), false)));

Check warning on line 724 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
}
ast::Pattern::Interned(_, _) => (),
}
Expand All @@ -731,7 +732,7 @@
fn pattern_to_string(pattern: &ast::Pattern) -> String {
match pattern {
ast::Pattern::Identifier(id) => id.0.contents.clone(),
ast::Pattern::Mutable(mpat, _, _) => format!("mut {}", pattern_to_string(mpat.as_ref())),

Check warning on line 735 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mpat)
ast::Pattern::Tuple(elements, _) => format!(
"({})",
elements.iter().map(pattern_to_string).collect::<Vec<String>>().join(", ")
Expand Down Expand Up @@ -768,11 +769,13 @@
}

fn uint_expr(x: u128, location: Location) -> ast::Expression {
let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(x.into(), false));
let value = SignedField::positive(x);
let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(value));
ast::Expression { kind, location }
}

fn sint_expr(x: i128, location: Location) -> ast::Expression {
let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(x.abs().into(), x < 0));
let value = SignedField::from_signed(x);
let kind = ast::ExpressionKind::Literal(ast::Literal::Integer(value));
ast::Expression { kind, location }
}
7 changes: 4 additions & 3 deletions compiler/noirc_frontend/src/elaborator/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ use crate::{
hir_def::{
expr::{
Case, Constructor, HirBlockExpression, HirEnumConstructorExpression, HirExpression,
HirIdent, HirMatch, SignedField,
HirIdent, HirMatch,
},
function::{FuncMeta, FunctionBody, HirFunction, Parameters},
stmt::{HirLetStatement, HirPattern, HirStatement},
},
node_interner::{DefinitionId, DefinitionKind, ExprId, FunctionModifiers, GlobalValue, TypeId},
signed_field::SignedField,
token::Attributes,
DataType, Kind, Shared, Type,
};
Expand Down Expand Up @@ -316,10 +317,10 @@ impl Elaborator<'_> {
};

match expression.kind {
ExpressionKind::Literal(Literal::Integer(value, negative)) => {
ExpressionKind::Literal(Literal::Integer(value)) => {
let actual = self.interner.next_type_variable_with_kind(Kind::IntegerOrField);
unify_with_expected_type(self, &actual);
Pattern::Int(SignedField::new(value, negative))
Pattern::Int(value)
}
ExpressionKind::Literal(Literal::Bool(value)) => {
unify_with_expected_type(self, &Type::Bool);
Expand Down
5 changes: 2 additions & 3 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,8 @@ impl<'context> Elaborator<'context> {
match literal {
Literal::Unit => (Lit(HirLiteral::Unit), Type::Unit),
Literal::Bool(b) => (Lit(HirLiteral::Bool(b)), Type::Bool),
Literal::Integer(integer, sign) => {
let int = HirLiteral::Integer(integer, sign);
(Lit(int), self.polymorphic_integer_or_field())
Literal::Integer(integer) => {
(Lit(HirLiteral::Integer(integer)), self.polymorphic_integer_or_field())
}
Literal::Str(str) | Literal::RawStr(str, _) => {
let len = Type::Constant(str.len().into(), Kind::u32());
Expand Down
12 changes: 7 additions & 5 deletions compiler/noirc_frontend/src/elaborator/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,13 @@ pub(crate) fn overflowing_int(

let mut errors = Vec::with_capacity(2);
match expr {
HirExpression::Literal(HirLiteral::Integer(value, negative)) => match annotated_type {
HirExpression::Literal(HirLiteral::Integer(value)) => match annotated_type {
Type::Integer(Signedness::Unsigned, bit_size) => {
let bit_size: u32 = (*bit_size).into();
let max = if bit_size == 128 { u128::MAX } else { 2u128.pow(bit_size) - 1 };
if value > max.into() || negative {
if value.field > max.into() || value.is_negative {
errors.push(TypeCheckError::OverflowingAssignment {
expr: if negative { -value } else { value },
expr: value,
ty: annotated_type.clone(),
range: format!("0..={}", max),
location,
Expand All @@ -218,9 +218,11 @@ pub(crate) fn overflowing_int(
let bit_count: u32 = (*bit_count).into();
let min = 2u128.pow(bit_count - 1);
let max = 2u128.pow(bit_count - 1) - 1;
if (negative && value > min.into()) || (!negative && value > max.into()) {
if (value.is_negative && value.field > min.into())
|| (!value.is_negative && value.field > max.into())
{
errors.push(TypeCheckError::OverflowingAssignment {
expr: if negative { -value } else { value },
expr: value,
ty: annotated_type.clone(),
range: format!("-{}..={}", min, max),
location,
Expand Down
4 changes: 3 additions & 1 deletion compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::{
DependencyId, ExprId, FuncId, GlobalValue, ImplSearchErrorKind, NodeInterner, TraitId,
TraitImplKind, TraitMethodId,
},
signed_field::SignedField,
token::SecondaryAttribute,
Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeBindings, UnificationError,
};
Expand Down Expand Up @@ -965,8 +966,9 @@ impl<'context> Elaborator<'context> {
) -> Type {
let from_follow_bindings = from.follow_bindings();

use HirExpression::Literal;
let from_value_opt = match self.interner.expression(from_expr_id) {
HirExpression::Literal(HirLiteral::Integer(int, false)) => Some(int),
Literal(HirLiteral::Integer(SignedField { field, is_negative: false })) => Some(field),

// TODO(https://github.com/noir-lang/noir/issues/6247):
// handle negative literals
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir/comptime/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ fn remove_interned_in_literal(interner: &NodeInterner, literal: Literal) -> Lite
Literal::Array(remove_interned_in_array_literal(interner, array_literal))
}
Literal::Bool(_)
| Literal::Integer(_, _)
| Literal::Integer(_)
| Literal::Str(_)
| Literal::RawStr(_, _)
| Literal::FmtStr(_, _)
Expand Down
Loading
Loading