Skip to content

Commit

Permalink
Merge branch 'master' into tf/abi-proptests
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench authored Jun 13, 2024
2 parents f0a3dc5 + 939bad2 commit e0e990c
Show file tree
Hide file tree
Showing 165 changed files with 702 additions and 717 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion aztec_macros/src/utils/ast_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,17 @@ pub fn method_call(
object,
method_name: ident(method_name),
arguments,
is_macro_call: false,
generics: None,
})))
}

pub fn call(func: Expression, arguments: Vec<Expression>) -> Expression {
expression(ExpressionKind::Call(Box::new(CallExpression { func: Box::new(func), arguments })))
expression(ExpressionKind::Call(Box::new(CallExpression {
func: Box::new(func),
is_macro_call: false,
arguments,
})))
}

pub fn pattern(name: &str) -> Pattern {
Expand Down
106 changes: 98 additions & 8 deletions compiler/noirc_driver/src/abi_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use std::collections::BTreeMap;

use acvm::acir::circuit::ErrorSelector;
use iter_extended::vecmap;
use noirc_abi::{Abi, AbiErrorType, AbiParameter, AbiReturnType, AbiType, AbiValue};
use noirc_frontend::ast::Visibility;
use noirc_abi::{
Abi, AbiErrorType, AbiParameter, AbiReturnType, AbiType, AbiValue, AbiVisibility, Sign,
};
use noirc_frontend::ast::{Signedness, Visibility};
use noirc_frontend::{
hir::Context,
hir_def::{expr::HirArrayLiteral, function::Param, stmt::HirPattern, types::Type},
macros_api::{HirExpression, HirLiteral},
node_interner::{FuncId, NodeInterner},
};
use noirc_frontend::{TypeBinding, TypeVariableKind};

/// Arranges a function signature and a generated circuit's return witnesses into a
/// `noirc_abi::Abi`.
Expand All @@ -20,15 +23,102 @@ pub(super) fn gen_abi(
error_types: BTreeMap<ErrorSelector, Type>,
) -> Abi {
let (parameters, return_type) = compute_function_abi(context, func_id);
let return_type = return_type
.map(|typ| AbiReturnType { abi_type: typ, visibility: return_visibility.into() });
let return_type = return_type.map(|typ| AbiReturnType {
abi_type: typ,
visibility: to_abi_visibility(return_visibility),
});
let error_types = error_types
.into_iter()
.map(|(selector, typ)| (selector, AbiErrorType::from_type(context, &typ)))
.map(|(selector, typ)| (selector, build_abi_error_type(context, &typ)))
.collect();
Abi { parameters, return_type, error_types }
}

fn build_abi_error_type(context: &Context, typ: &Type) -> AbiErrorType {
match typ {
Type::FmtString(len, item_types) => {
let length = len.evaluate_to_u32().expect("Cannot evaluate fmt length");
let Type::Tuple(item_types) = item_types.as_ref() else {
unreachable!("FmtString items must be a tuple")
};
let item_types =
item_types.iter().map(|typ| abi_type_from_hir_type(context, typ)).collect();
AbiErrorType::FmtString { length, item_types }
}
_ => AbiErrorType::Custom(abi_type_from_hir_type(context, typ)),
}
}

pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType {
match typ {
Type::FieldElement => AbiType::Field,
Type::Array(size, typ) => {
let length = size
.evaluate_to_u32()
.expect("Cannot have variable sized arrays as a parameter to main");
let typ = typ.as_ref();
AbiType::Array { length, typ: Box::new(abi_type_from_hir_type(context, typ)) }
}
Type::Integer(sign, bit_width) => {
let sign = match sign {
Signedness::Unsigned => Sign::Unsigned,
Signedness::Signed => Sign::Signed,
};

AbiType::Integer { sign, width: (*bit_width).into() }
}
Type::TypeVariable(binding, TypeVariableKind::IntegerOrField)
| Type::TypeVariable(binding, TypeVariableKind::Integer) => match &*binding.borrow() {
TypeBinding::Bound(typ) => abi_type_from_hir_type(context, typ),
TypeBinding::Unbound(_) => {
abi_type_from_hir_type(context, &Type::default_int_or_field_type())
}
},
Type::Bool => AbiType::Boolean,
Type::String(size) => {
let size = size
.evaluate_to_u32()
.expect("Cannot have variable sized strings as a parameter to main");
AbiType::String { length: size }
}

Type::Struct(def, args) => {
let struct_type = def.borrow();
let fields = struct_type.get_fields(args);
let fields =
vecmap(fields, |(name, typ)| (name, abi_type_from_hir_type(context, &typ)));
// For the ABI, we always want to resolve the struct paths from the root crate
let path = context.fully_qualified_struct_path(context.root_crate_id(), struct_type.id);
AbiType::Struct { fields, path }
}
Type::Alias(def, args) => abi_type_from_hir_type(context, &def.borrow().get_type(args)),
Type::Tuple(fields) => {
let fields = vecmap(fields, |typ| abi_type_from_hir_type(context, typ));
AbiType::Tuple { fields }
}
Type::Error
| Type::Unit
| Type::Constant(_)
| Type::TraitAsType(..)
| Type::TypeVariable(_, _)
| Type::NamedGeneric(..)
| Type::Forall(..)
| Type::Code
| Type::Slice(_)
| Type::Function(_, _, _) => unreachable!("{typ} cannot be used in the abi"),
Type::FmtString(_, _) => unreachable!("format strings cannot be used in the abi"),
Type::MutableReference(_) => unreachable!("&mut cannot be used in the abi"),
}
}

fn to_abi_visibility(value: Visibility) -> AbiVisibility {
match value {
Visibility::Public => AbiVisibility::Public,
Visibility::Private => AbiVisibility::Private,
Visibility::DataBus => AbiVisibility::DataBus,
}
}

pub(super) fn compute_function_abi(
context: &Context,
func_id: &FuncId,
Expand All @@ -37,7 +127,7 @@ pub(super) fn compute_function_abi(

let (parameters, return_type) = func_meta.function_signature();
let parameters = into_abi_params(context, parameters);
let return_type = return_type.map(|typ| AbiType::from_type(context, &typ));
let return_type = return_type.map(|typ| abi_type_from_hir_type(context, &typ));
(parameters, return_type)
}

Expand All @@ -57,8 +147,8 @@ fn into_abi_params(context: &Context, params: Vec<Param>) -> Vec<AbiParameter> {
let param_name = get_param_name(&pattern, &context.def_interner)
.expect("Abi for tuple and struct parameters is unimplemented")
.to_owned();
let as_abi = AbiType::from_type(context, &typ);
AbiParameter { name: param_name, typ: as_abi, visibility: vis.into() }
let as_abi = abi_type_from_hir_type(context, &typ);
AbiParameter { name: param_name, typ: as_abi, visibility: to_abi_visibility(vis) }
})
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![warn(unreachable_pub)]
#![warn(clippy::semicolon_if_nothing_returned)]

use abi_gen::value_from_hir_expression;
use abi_gen::{abi_type_from_hir_type, value_from_hir_expression};
use acvm::acir::circuit::ExpressionWidth;
use clap::Args;
use fm::{FileId, FileManager};
Expand Down Expand Up @@ -468,7 +468,7 @@ fn compile_contract_inner(
let typ = context.def_interner.get_struct(struct_id);
let typ = typ.borrow();
let fields = vecmap(typ.get_fields(&[]), |(name, typ)| {
(name, AbiType::from_type(context, &typ))
(name, abi_type_from_hir_type(context, &typ))
});
let path =
context.fully_qualified_struct_path(context.root_crate_id(), typ.id);
Expand Down
41 changes: 27 additions & 14 deletions compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub enum ExpressionKind {
Tuple(Vec<Expression>),
Lambda(Box<Lambda>),
Parenthesized(Box<Expression>),
Quote(BlockExpression),
Quote(BlockExpression, Span),
Comptime(BlockExpression, Span),

// This variant is only emitted when inlining the result of comptime
Expand Down Expand Up @@ -179,19 +179,21 @@ impl Expression {

pub fn member_access_or_method_call(
lhs: Expression,
(rhs, args): UnaryRhsMemberAccess,
rhs: UnaryRhsMemberAccess,
span: Span,
) -> Expression {
let kind = match args {
None => ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { lhs, rhs })),
Some((generics, arguments)) => {
ExpressionKind::MethodCall(Box::new(MethodCallExpression {
object: lhs,
method_name: rhs,
generics,
arguments,
}))
let kind = match rhs.method_call {
None => {
let rhs = rhs.method_or_field;
ExpressionKind::MemberAccess(Box::new(MemberAccessExpression { lhs, rhs }))
}
Some(method_call) => ExpressionKind::MethodCall(Box::new(MethodCallExpression {
object: lhs,
method_name: rhs.method_or_field,
generics: method_call.turbofish,
arguments: method_call.args,
is_macro_call: method_call.macro_call,
})),
};
Expression::new(kind, span)
}
Expand All @@ -206,7 +208,12 @@ impl Expression {
Expression::new(kind, span)
}

pub fn call(lhs: Expression, arguments: Vec<Expression>, span: Span) -> Expression {
pub fn call(
lhs: Expression,
is_macro_call: bool,
arguments: Vec<Expression>,
span: Span,
) -> Expression {
// Need to check if lhs is an if expression since users can sequence if expressions
// with tuples without calling them. E.g. `if c { t } else { e }(a, b)` is interpreted
// as a sequence of { if, tuple } rather than a function call. This behavior matches rust.
Expand All @@ -224,7 +231,11 @@ impl Expression {
],
})
} else {
ExpressionKind::Call(Box::new(CallExpression { func: Box::new(lhs), arguments }))
ExpressionKind::Call(Box::new(CallExpression {
func: Box::new(lhs),
is_macro_call,
arguments,
}))
};
Expression::new(kind, span)
}
Expand Down Expand Up @@ -447,6 +458,7 @@ pub enum ArrayLiteral {
pub struct CallExpression {
pub func: Box<Expression>,
pub arguments: Vec<Expression>,
pub is_macro_call: bool,
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand All @@ -456,6 +468,7 @@ pub struct MethodCallExpression {
/// Method calls have an optional list of generics if the turbofish operator was used
pub generics: Option<Vec<UnresolvedType>>,
pub arguments: Vec<Expression>,
pub is_macro_call: bool,
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -535,7 +548,7 @@ impl Display for ExpressionKind {
}
Lambda(lambda) => lambda.fmt(f),
Parenthesized(sub_expr) => write!(f, "({sub_expr})"),
Quote(block) => write!(f, "quote {block}"),
Quote(block, _) => write!(f, "quote {block}"),
Comptime(block, _) => write!(f, "comptime {block}"),
Error => write!(f, "Error"),
Resolved(_) => write!(f, "?Resolved"),
Expand Down
12 changes: 10 additions & 2 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,16 @@ pub struct UnresolvedType {
}

/// Type wrapper for a member access
pub(crate) type UnaryRhsMemberAccess =
(Ident, Option<(Option<Vec<UnresolvedType>>, Vec<Expression>)>);
pub struct UnaryRhsMemberAccess {
pub method_or_field: Ident,
pub method_call: Option<UnaryRhsMethodCall>,
}

pub struct UnaryRhsMethodCall {
pub turbofish: Option<Vec<UnresolvedType>>,
pub macro_call: bool,
pub args: Vec<Expression>,
}

/// The precursor to TypeExpression, this is the type that the parser allows
/// to be used in the length position of an array type. Only constants, variables,
Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ impl ForRange {
object: Expression::new(array_ident.clone(), array_span),
method_name: Ident::new("len".to_string(), array_span),
generics: None,
is_macro_call: false,
arguments: vec![],
}));
let end_range = Expression::new(end_range, array_span);
Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ fn build_assign_var_stmt(var_id: SourceVarId, expr: ast::Expression) -> ast::Sta
),
span,
}),
is_macro_call: false,
arguments: vec![uint_expr(var_id.0 as u128, span), expr],
}));
ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span }
Expand All @@ -599,6 +600,7 @@ fn build_drop_var_stmt(var_id: SourceVarId, span: Span) -> ast::Statement {
),
span,
}),
is_macro_call: false,
arguments: vec![uint_expr(var_id.0 as u128, span)],
}));
ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span }
Expand Down Expand Up @@ -626,6 +628,7 @@ fn build_assign_member_stmt(
),
span,
}),
is_macro_call: false,
arguments: [
vec![uint_expr(var_id.0 as u128, span)],
vec![expr.clone()],
Expand All @@ -649,6 +652,7 @@ fn build_debug_call_stmt(fname: &str, fn_id: DebugFnId, span: Span) -> ast::Stat
),
span,
}),
is_macro_call: false,
arguments: vec![uint_expr(fn_id.0 as u128, span)],
}));
ast::Statement { kind: ast::StatementKind::Semi(ast::Expression { kind, span }), span }
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'context> Elaborator<'context> {
ExpressionKind::Tuple(tuple) => self.elaborate_tuple(tuple),
ExpressionKind::Lambda(lambda) => self.elaborate_lambda(*lambda),
ExpressionKind::Parenthesized(expr) => return self.elaborate_expression(*expr),
ExpressionKind::Quote(quote) => self.elaborate_quote(quote),
ExpressionKind::Quote(quote, _) => self.elaborate_quote(quote),
ExpressionKind::Comptime(comptime, _) => {
return self.elaborate_comptime_block(comptime, expr.span)
}
Expand Down
Loading

0 comments on commit e0e990c

Please sign in to comment.