Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: single integral type #6843

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ca8058d
wip moving bool/unit/field -> integer
michaeljklein Dec 17, 2024
59bce77
wip updating UnresolvedTypeData
michaeljklein Dec 17, 2024
60b83d7
updated all cases of Unit/Bool/FieldElement to Type::Integer
michaeljklein Dec 17, 2024
c165c2e
wip updating tests
michaeljklein Dec 17, 2024
07ed018
wip debugging failing tests, cleanup
michaeljklein Dec 17, 2024
1acbbf2
wip debugging failing tests, fix UnsupportedNumericGenericType behavior
michaeljklein Dec 17, 2024
7de5cc7
wip TODO's
michaeljklein Dec 18, 2024
4c7e416
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Dec 18, 2024
5e0e56d
wip debugging last failures, fixed unit binding to polymprhic int
michaeljklein Dec 18, 2024
820e32e
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Dec 19, 2024
81530f1
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Dec 21, 2024
6dc11c4
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Jan 3, 2025
db10049
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Jan 7, 2025
0caf41b
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Jan 7, 2025
0aa635f
debug after merging master
michaeljklein Jan 7, 2025
4ea4d02
wip distinguishing bool from u1 in IntegerBitSize
michaeljklein Jan 7, 2025
b866d23
wip updating crates after bool/u1 split in frontend, all frontend tes…
michaeljklein Jan 7, 2025
cdd2343
remove debug for displaying IntType, fix bool case
michaeljklein Jan 9, 2025
5972603
wip debugging failures, use is_bool in noirc_driver
michaeljklein Jan 9, 2025
cd409ac
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Jan 10, 2025
5f96a87
Merge branch 'master' into michaeljklein/single-integral-type
michaeljklein Jan 10, 2025
e8b312f
wip debugging max bits failures
michaeljklein Jan 14, 2025
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
11 changes: 8 additions & 3 deletions compiler/noirc_driver/src/abi_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ fn build_abi_error_type(context: &Context, typ: ErrorType) -> AbiErrorType {

pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType {
match typ {
Type::FieldElement => AbiType::Field,
Type::Array(size, typ) => {
let span = get_main_function_span(context);
let length = size
Expand All @@ -82,6 +81,14 @@ pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType {
AbiType::Array { length, typ: Box::new(abi_type_from_hir_type(context, typ)) }
}
Type::Integer(sign, bit_width) => {
// TODO: combine Bool, etc in ABI
michaeljklein marked this conversation as resolved.
Show resolved Hide resolved
if bit_width.is_zero() {
unreachable!("{typ} cannot be used in the abi")
} else if bit_width.is_one() {
return AbiType::Boolean;
} else if bit_width.is_field_element_bits() {
return AbiType::Field;
}
let sign = match sign {
Signedness::Unsigned => Sign::Unsigned,
Signedness::Signed => Sign::Signed,
Expand All @@ -101,7 +108,6 @@ pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType {
unreachable!("{typ} cannot be used in the abi")
}
}
Type::Bool => AbiType::Boolean,
Type::String(size) => {
let span = get_main_function_span(context);
let size = size
Expand All @@ -126,7 +132,6 @@ pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType {
AbiType::Tuple { fields }
}
Type::Error
| Type::Unit
| Type::Constant(..)
| Type::InfixExpr(..)
| Type::TraitAsType(..)
Expand Down
16 changes: 13 additions & 3 deletions compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ impl UnresolvedGeneric {
&self,
typ: &UnresolvedType,
) -> Result<Type, UnsupportedNumericGenericType> {
use crate::ast::UnresolvedTypeData::{FieldElement, Integer};
use crate::ast::UnresolvedTypeData::Integer;

// TODO: only fields and "regular integers"?
match typ.typ {
FieldElement => Ok(Type::FieldElement),
Integer(sign, bits) => Ok(Type::Integer(sign, bits)),
// TODO: fix comment after seeing if this is buggy
// Only fields and integers are supported for numeric kinds
_ => Err(UnsupportedNumericGenericType {
ident: self.ident().clone(),
Expand Down Expand Up @@ -345,6 +346,15 @@ impl BinaryOpKind {
)
}

pub fn is_bitwise(&self) -> bool {
matches!(
self,
BinaryOpKind::And
| BinaryOpKind::Or
| BinaryOpKind::Xor
)
}

pub fn is_valid_for_field_type(self) -> bool {
matches!(
self,
Expand Down Expand Up @@ -888,7 +898,7 @@ impl FunctionReturnType {
pub fn get_type(&self) -> Cow<UnresolvedType> {
match self {
FunctionReturnType::Default(span) => {
Cow::Owned(UnresolvedType { typ: UnresolvedTypeData::Unit, span: *span })
Cow::Owned(UnresolvedTypeData::unit().with_span(*span))
}
FunctionReturnType::Ty(typ) => Cow::Borrowed(typ),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/ast/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl NoirFunction {

pub fn return_type(&self) -> UnresolvedType {
match &self.def.return_type {
FunctionReturnType::Default(span) => UnresolvedTypeData::Unit.with_span(*span),
FunctionReturnType::Default(span) => UnresolvedTypeData::unit().with_span(*span),
FunctionReturnType::Ty(ty) => ty.clone(),
}
}
Expand Down
94 changes: 70 additions & 24 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,41 @@ use iter_extended::vecmap;
#[cfg_attr(test, derive(Arbitrary))]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)]
pub enum IntegerBitSize {
Zero, // bit size of Unit
One,
Eight,
Sixteen,
ThirtyTwo,
SixtyFour,
FieldElementBits, // max bit size of FieldElement
}

impl IntegerBitSize {
pub fn bit_size(&self) -> u8 {
match self {
IntegerBitSize::Zero => 0,
IntegerBitSize::One => 1,
IntegerBitSize::Eight => 8,
IntegerBitSize::Sixteen => 16,
IntegerBitSize::ThirtyTwo => 32,
IntegerBitSize::SixtyFour => 64,
IntegerBitSize::FieldElementBits => {
FieldElement::max_num_bits().try_into().expect("ICE: FieldElement has more than u8::MAX bits")
}
}
}

pub fn is_zero(&self) -> bool {
matches!(self, IntegerBitSize::Zero)
}

pub fn is_one(&self) -> bool {
matches!(self, IntegerBitSize::One)
}

pub fn is_field_element_bits(&self) -> bool {
matches!(self, IntegerBitSize::FieldElementBits)
}
}

impl IntegerBitSize {
Expand All @@ -72,11 +90,13 @@ impl From<IntegerBitSize> for u32 {
fn from(size: IntegerBitSize) -> u32 {
use IntegerBitSize::*;
match size {
Zero => 0,
One => 1,
Eight => 8,
Sixteen => 16,
ThirtyTwo => 32,
SixtyFour => 64,
FieldElementBits => FieldElement::max_num_bits(),
}
}
}
Expand All @@ -88,7 +108,11 @@ impl TryFrom<u32> for IntegerBitSize {

fn try_from(value: u32) -> Result<Self, Self::Error> {
use IntegerBitSize::*;
if value == FieldElement::max_num_bits() {
return Ok(FieldElementBits);
}
match value {
0 => Ok(Zero),
1 => Ok(One),
8 => Ok(Eight),
16 => Ok(Sixteen),
Expand All @@ -110,15 +134,12 @@ impl core::fmt::Display for IntegerBitSize {
/// for structs within, but are otherwise identical to Types.
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum UnresolvedTypeData {
FieldElement,
Array(UnresolvedTypeExpression, Box<UnresolvedType>), // [Field; 4] = Array(4, Field)
Slice(Box<UnresolvedType>),
Integer(Signedness, IntegerBitSize), // u32 = Integer(unsigned, ThirtyTwo)
Bool,
Expression(UnresolvedTypeExpression),
String(UnresolvedTypeExpression),
FormatString(UnresolvedTypeExpression, Box<UnresolvedType>),
Unit,

Parenthesized(Box<UnresolvedType>),

Expand Down Expand Up @@ -287,21 +308,28 @@ impl std::fmt::Display for UnresolvedTypeData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use UnresolvedTypeData::*;
match self {
FieldElement => write!(f, "Field"),
Array(len, typ) => write!(f, "[{typ}; {len}]"),
Slice(typ) => write!(f, "[{typ}]"),
Integer(sign, num_bits) => match sign {
Signedness::Signed => write!(f, "i{num_bits}"),
Signedness::Unsigned => write!(f, "u{num_bits}"),
},
Integer(sign, num_bits) => {
if num_bits.is_zero() {
return write!(f, "()");
} else if num_bits.is_one() {
return write!(f, "bool");
} else if num_bits.is_field_element_bits() {
return write!(f, "Field");
}
match sign {
Signedness::Signed => write!(f, "i{num_bits}"),
Signedness::Unsigned => write!(f, "u{num_bits}"),
}
}
Named(s, args, _) => write!(f, "{s}{args}"),
TraitAsType(s, args) => write!(f, "impl {s}{args}"),
Tuple(elements) => {
let elements = vecmap(elements, ToString::to_string);
write!(f, "({})", elements.join(", "))
}
Expression(expression) => expression.fmt(f),
Bool => write!(f, "bool"),
String(len) => write!(f, "str<{len}>"),
FormatString(len, elements) => write!(f, "fmt<{len}, {elements}"),
Function(args, ret, env, unconstrained) => {
Expand All @@ -310,21 +338,18 @@ impl std::fmt::Display for UnresolvedTypeData {
}

let args = vecmap(args, ToString::to_string).join(", ");

match &env.as_ref().typ {
UnresolvedTypeData::Unit => {
write!(f, "fn({args}) -> {ret}")
}
UnresolvedTypeData::Tuple(env_types) => {
let env_types = vecmap(env_types, |arg| arg.typ.to_string()).join(", ");
write!(f, "fn[{env_types}]({args}) -> {ret}")
}
other => write!(f, "fn[{other}]({args}) -> {ret}"),
let env_typ = &env.as_ref().typ;
if env_typ.is_unit() {
write!(f, "fn({args}) -> {ret}")
} else if let UnresolvedTypeData::Tuple(env_types) = env_typ {
let env_types = vecmap(env_types, |arg| arg.typ.to_string()).join(", ");
write!(f, "fn[{env_types}]({args}) -> {ret}")
} else {
write!(f, "fn[{env_typ}]({args}) -> {ret}")
}
}
MutableReference(element) => write!(f, "&mut {element}"),
Quoted(quoted) => write!(f, "{}", quoted),
Unit => write!(f, "()"),
Error => write!(f, "error"),
Unspecified => write!(f, "unspecified"),
Parenthesized(typ) => write!(f, "({typ})"),
Expand Down Expand Up @@ -437,17 +462,38 @@ impl UnresolvedTypeData {
}
UnresolvedTypeData::Unspecified => true,

UnresolvedTypeData::FieldElement
| UnresolvedTypeData::Integer(_, _)
| UnresolvedTypeData::Bool
| UnresolvedTypeData::Unit
UnresolvedTypeData::Integer(_, _)
| UnresolvedTypeData::Quoted(_)
| UnresolvedTypeData::AsTraitPath(_)
| UnresolvedTypeData::Resolved(_)
| UnresolvedTypeData::Interned(_)
| UnresolvedTypeData::Error => false,
}
}

pub(crate) fn unit() -> UnresolvedTypeData {
UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::Zero)
}

pub(crate) fn bool() -> UnresolvedTypeData {
UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::One)
}

pub(crate) fn field_element() -> UnresolvedTypeData {
UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::FieldElementBits)
}

pub(crate) fn is_unit(&self) -> bool {
matches!(self, UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::Zero))
}

pub(crate) fn is_bool(&self) -> bool {
matches!(self, UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::One))
}

pub(crate) fn is_field_element(&self) -> bool {
matches!(self, UnresolvedTypeData::Integer(Signedness::Unsigned, IntegerBitSize::FieldElementBits))
}
}

#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
Expand Down
9 changes: 0 additions & 9 deletions compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,8 @@ pub trait Visitor {

fn visit_quoted_type(&mut self, _: &QuotedType, _: Span) {}

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

fn visit_integer_type(&mut self, _: Signedness, _: IntegerBitSize, _: Span) {}

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

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

fn visit_resolved_type(&mut self, _: QuotedTypeId, _: Span) {}

fn visit_interned_type(&mut self, _: InternedUnresolvedTypeData, _: Span) {}
Expand Down Expand Up @@ -1321,12 +1315,9 @@ impl UnresolvedType {
UnresolvedTypeData::String(expr) => visitor.visit_string_type(expr, self.span),
UnresolvedTypeData::Unspecified => visitor.visit_unspecified_type(self.span),
UnresolvedTypeData::Quoted(typ) => visitor.visit_quoted_type(typ, self.span),
UnresolvedTypeData::FieldElement => visitor.visit_field_element_type(self.span),
UnresolvedTypeData::Integer(signdness, size) => {
visitor.visit_integer_type(*signdness, *size, self.span);
}
UnresolvedTypeData::Bool => visitor.visit_bool_type(self.span),
UnresolvedTypeData::Unit => visitor.visit_unit_type(self.span),
UnresolvedTypeData::Resolved(id) => visitor.visit_resolved_type(*id, self.span),
UnresolvedTypeData::Interned(id) => visitor.visit_interned_type(*id, self.span),
UnresolvedTypeData::Error => visitor.visit_error_type(self.span),
Expand Down
20 changes: 10 additions & 10 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'context> Elaborator<'context> {

fn elaborate_block_expression(&mut self, block: BlockExpression) -> (HirBlockExpression, Type) {
self.push_scope();
let mut block_type = Type::Unit;
let mut block_type = Type::unit();
let mut statements = Vec::with_capacity(block.statements.len());

for (i, statement) in block.statements.into_iter().enumerate() {
Expand All @@ -125,7 +125,7 @@ impl<'context> Elaborator<'context> {
let inner_expr_type = self.interner.id_type(expr);
let span = self.interner.expr_span(&expr);

self.unify(&inner_expr_type, &Type::Unit, || TypeCheckError::UnusedResultError {
self.unify(&inner_expr_type, &Type::unit(), || TypeCheckError::UnusedResultError {
expr_type: inner_expr_type.clone(),
expr_span: span,
});
Expand Down Expand Up @@ -156,8 +156,8 @@ impl<'context> Elaborator<'context> {
fn elaborate_literal(&mut self, literal: Literal, span: Span) -> (HirExpression, Type) {
use HirExpression::Literal as Lit;
match literal {
Literal::Unit => (Lit(HirLiteral::Unit), Type::Unit),
Literal::Bool(b) => (Lit(HirLiteral::Bool(b)), Type::Bool),
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())
Expand Down Expand Up @@ -771,8 +771,8 @@ impl<'context> Elaborator<'context> {
let (condition, cond_type) = self.elaborate_expression(if_expr.condition);
let (consequence, mut ret_type) = self.elaborate_expression(if_expr.consequence);

self.unify(&cond_type, &Type::Bool, || TypeCheckError::TypeMismatch {
expected_typ: Type::Bool.to_string(),
self.unify(&cond_type, &Type::bool(), || TypeCheckError::TypeMismatch {
expected_typ: Type::bool().to_string(),
expr_typ: cond_type.to_string(),
expr_span,
});
Expand All @@ -788,9 +788,9 @@ impl<'context> Elaborator<'context> {
expr_span,
};

let context = if ret_type == Type::Unit {
let context = if ret_type.is_unit() {
"Are you missing a semicolon at the end of your 'else' branch?"
} else if else_type == Type::Unit {
} else if else_type.is_unit() {
"Are you missing a semicolon at the end of the first block of this 'if'?"
} else {
"Expected the types of both if branches to be equal"
Expand All @@ -802,7 +802,7 @@ impl<'context> Elaborator<'context> {
});

if alternative.is_none() {
ret_type = Type::Unit;
ret_type = Type::unit();
}

let if_expr = HirIfExpression { condition, consequence, alternative };
Expand Down Expand Up @@ -854,7 +854,7 @@ impl<'context> Elaborator<'context> {
});

let env_type =
if captured_vars.is_empty() { Type::Unit } else { Type::Tuple(captured_vars) };
if captured_vars.is_empty() { Type::unit() } else { Type::Tuple(captured_vars) };

let captures = lambda_context.captures;
let expr = HirExpression::Lambda(HirLambda { parameters, return_type, body, captures });
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub(super) fn oracle_called_from_constrained_function(
/// `pub` is required on return types for entry point functions
pub(super) fn missing_pub(func: &FuncMeta, modifiers: &FunctionModifiers) -> Option<ResolverError> {
if func.is_entry_point
&& func.return_type() != &Type::Unit
&& !func.return_type().is_unit()
&& func.return_visibility == Visibility::Private
{
let ident = func_meta_name_ident(func, modifiers);
Expand Down
Loading
Loading