Skip to content

Commit

Permalink
Merge branch 'master' into jf/remove-comptime
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Aug 8, 2023
2 parents b2012ce + 34be264 commit 38bf134
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 56 deletions.
6 changes: 6 additions & 0 deletions crates/nargo/src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ use crate::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE};
pub enum PackageType {
Library,
Binary,
Contract,
}

impl Display for PackageType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Library => write!(f, "lib"),
Self::Binary => write!(f, "bin"),
Self::Contract => write!(f, "contract"),
}
}
}
Expand Down Expand Up @@ -64,6 +66,10 @@ impl Package {
self.package_type == PackageType::Binary
}

pub fn is_contract(&self) -> bool {
self.package_type == PackageType::Contract
}

pub fn is_library(&self) -> bool {
self.package_type == PackageType::Library
}
Expand Down
16 changes: 5 additions & 11 deletions crates/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ pub(crate) struct CompileCommand {
#[arg(long)]
include_keys: bool,

/// Compile each contract function used within the program
#[arg(short, long)]
contracts: bool,

/// The name of the package to compile
#[clap(long)]
package: Option<CrateName>,
Expand All @@ -60,10 +56,10 @@ pub(crate) fn run<B: Backend>(

let mut common_reference_string = read_cached_common_reference_string();

// If contracts is set we're compiling every function in a 'contract' rather than just 'main'.
if args.contracts {
for package in &workspace {
let (mut context, crate_id) = prepare_package(package);
for package in &workspace {
let (mut context, crate_id) = prepare_package(package);
// If `contract` package type, we're compiling every function in a 'contract' rather than just 'main'.
if package.is_contract() {
let result = compile_contracts(&mut context, crate_id, &args.compile_options);
let contracts = report_errors(result, &context, args.compile_options.deny_warnings)?;

Expand Down Expand Up @@ -105,9 +101,7 @@ pub(crate) fn run<B: Backend>(
&circuit_dir,
);
}
}
} else {
for package in &workspace {
} else {
let (_, program) = compile_package(backend, package, &args.compile_options)?;

common_reference_string =
Expand Down
26 changes: 23 additions & 3 deletions crates/nargo_cli/src/cli/init_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ pub(crate) struct InitCommand {
name: Option<String>,

/// Use a library template
#[arg(long, conflicts_with = "bin")]
#[arg(long, conflicts_with = "bin", conflicts_with = "contract")]
pub(crate) lib: bool,

/// Use a binary template [default]
#[arg(long, conflicts_with = "lib")]
#[arg(long, conflicts_with = "lib", conflicts_with = "contract")]
pub(crate) bin: bool,

/// Use a contract template
#[arg(long, conflicts_with = "lib", conflicts_with = "bin")]
pub(crate) contract: bool,
}

const BIN_EXAMPLE: &str = r#"fn main(x : Field, y : pub Field) {
Expand All @@ -37,6 +41,13 @@ fn test_main() {
}
"#;

const CONTRACT_EXAMPLE: &str = r#"contract Main {
internal fn double(x: Field) -> pub Field { x * 2 }
fn triple(x: Field) -> pub Field { x * 3 }
fn quadruple(x: Field) -> pub Field { double(double(x)) }
}
"#;

const LIB_EXAMPLE: &str = r#"fn my_util(x : Field, y : Field) -> bool {
x != y
}
Expand All @@ -60,7 +71,13 @@ pub(crate) fn run<B: Backend>(
.name
.unwrap_or_else(|| config.program_dir.file_name().unwrap().to_str().unwrap().to_owned());

let package_type = if args.lib { PackageType::Library } else { PackageType::Binary };
let package_type = if args.lib {
PackageType::Library
} else if args.contract {
PackageType::Contract
} else {
PackageType::Binary
};
initialize_project(config.program_dir, &package_name, package_type);
Ok(())
}
Expand Down Expand Up @@ -88,6 +105,9 @@ compiler_version = "{CARGO_PKG_VERSION}"
// This uses the `match` syntax instead of `if` so we get a compile error when we add new package types (which likely need new template files)
match package_type {
PackageType::Binary => write_to_file(BIN_EXAMPLE.as_bytes(), &src_dir.join("main.nr")),
PackageType::Contract => {
write_to_file(CONTRACT_EXAMPLE.as_bytes(), &src_dir.join("main.nr"))
}
PackageType::Library => write_to_file(LIB_EXAMPLE.as_bytes(), &src_dir.join("lib.nr")),
};
println!("Project successfully created! It is located at {}", package_dir.display());
Expand Down
16 changes: 13 additions & 3 deletions crates/nargo_cli/src/cli/new_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ pub(crate) struct NewCommand {
name: Option<String>,

/// Use a library template
#[arg(long, conflicts_with = "bin")]
#[arg(long, conflicts_with = "bin", conflicts_with = "contract")]
pub(crate) lib: bool,

/// Use a binary template [default]
#[arg(long, conflicts_with = "lib")]
#[arg(long, conflicts_with = "lib", conflicts_with = "contract")]
pub(crate) bin: bool,

/// Use a contract template
#[arg(long, conflicts_with = "lib", conflicts_with = "bin")]
pub(crate) contract: bool,
}

pub(crate) fn run<B: Backend>(
Expand All @@ -39,7 +43,13 @@ pub(crate) fn run<B: Backend>(

let package_name =
args.name.unwrap_or_else(|| args.path.file_name().unwrap().to_str().unwrap().to_owned());
let package_type = if args.lib { PackageType::Library } else { PackageType::Binary };
let package_type = if args.lib {
PackageType::Library
} else if args.contract {
PackageType::Contract
} else {
PackageType::Binary
};
initialize_project(package_dir, &package_name, package_type);
Ok(())
}
3 changes: 2 additions & 1 deletion crates/nargo_cli/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl PackageConfig {
let package_type = match self.package.package_type.as_deref() {
Some("lib") => PackageType::Library,
Some("bin") => PackageType::Binary,
Some("contract") => PackageType::Contract,
Some(invalid) => {
return Err(ManifestError::InvalidPackageType(
root_dir.join("Nargo.toml"),
Expand All @@ -63,7 +64,7 @@ impl PackageConfig {
PackageType::Library => {
root_dir.join("src").join("lib").with_extension(FILE_EXTENSION)
}
PackageType::Binary => {
PackageType::Binary | PackageType::Contract => {
root_dir.join("src").join("main").with_extension(FILE_EXTENSION)
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "contracts"
type = "bin"
type = "contract"
authors = [""]
compiler_version = "0.1"

Expand Down
10 changes: 10 additions & 0 deletions crates/nargo_cli/tests/execution_success/references/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ fn main(mut x: Field) {

regression_1887();
regression_2054();
regression_2030();
}

fn add1(x: &mut Field) {
Expand Down Expand Up @@ -87,3 +88,12 @@ fn regression_2054() {
x += 1;
assert(z == 2);
}

// The compiler was still trying to convert an LValue from an array of structs to struct of arrays indexing,
// even though this conversion was mostly removed elsewhere.
fn regression_2030() {
let ref = &mut 0;
let mut array = [ref, ref];
let _ = *array[0];
*array[0] = 1;
}
1 change: 1 addition & 0 deletions crates/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ pub fn compile_contracts(
) -> Result<(Vec<CompiledContract>, Warnings), ErrorsAndWarnings> {
let warnings = check_crate(context, crate_id, options.deny_warnings)?;

// TODO: We probably want to error if contracts is empty
let contracts = context.get_all_contracts(&crate_id);
let mut compiled_contracts = vec![];
let mut errors = warnings;
Expand Down
5 changes: 5 additions & 0 deletions crates/noirc_evaluator/src/ssa/ir/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ impl Binary {
let zero = dfg.make_constant(FieldElement::zero(), Type::bool());
return SimplifyResult::SimplifiedTo(zero);
}
if operand_type.is_unsigned() && rhs_is_zero {
// Unsigned values cannot be less than zero.
let zero = dfg.make_constant(FieldElement::zero(), Type::bool());
return SimplifyResult::SimplifiedTo(zero);
}
}
BinaryOp::And => {
if lhs_is_zero || rhs_is_zero {
Expand Down
5 changes: 5 additions & 0 deletions crates/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ pub(crate) enum Type {
}

impl Type {
/// Returns whether the `Type` represents an unsigned numeric type.
pub(crate) fn is_unsigned(&self) -> bool {
matches!(self, Type::Numeric(NumericType::Unsigned { .. }))
}

/// Create a new signed integer type with the given amount of bits.
pub(crate) fn signed(bit_size: u32) -> Type {
Type::Numeric(NumericType::Signed { bit_size })
Expand Down
21 changes: 17 additions & 4 deletions crates/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use crate::hir::Context;
use crate::node_interner::{FuncId, NodeInterner, StmtId, StructId, TypeAliasId};
use crate::{
ExpressionKind, Generics, Ident, LetStatement, Literal, NoirFunction, NoirStruct,
NoirTypeAlias, ParsedModule, Shared, Type, TypeBinding, UnresolvedGenerics, UnresolvedType,
NoirTypeAlias, ParsedModule, Shared, StructType, Type, TypeBinding, UnresolvedGenerics,
UnresolvedType,
};
use fm::FileId;
use iter_extended::vecmap;
Expand Down Expand Up @@ -233,7 +234,19 @@ fn collect_impls(

extend_errors(errors, unresolved.file_id, resolver.take_errors());

if let Some(type_module) = get_local_id_from_type(&typ) {
if let Some(struct_type) = get_struct_type(&typ) {
let struct_type = struct_type.borrow();
let type_module = struct_type.id.0.local_id;

// `impl`s are only allowed on types defined within the current crate
if struct_type.id.0.krate != crate_id {
let span = *span;
let type_name = struct_type.name.to_string();
let error = DefCollectorErrorKind::ForeignImpl { span, type_name };
errors.push(error.into_file_diagnostic(unresolved.file_id));
continue;
}

// Grab the module defined by the struct type. Note that impls are a case
// where the module the methods are added to is not the same as the module
// they are resolved in.
Expand All @@ -258,9 +271,9 @@ fn collect_impls(
}
}

fn get_local_id_from_type(typ: &Type) -> Option<LocalModuleId> {
fn get_struct_type(typ: &Type) -> Option<&Shared<StructType>> {
match typ {
Type::Struct(definition, _) => Some(definition.borrow().id.0.local_id),
Type::Struct(definition, _) => Some(definition),
_ => None,
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/noirc_frontend/src/hir/def_collector/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub enum DefCollectorErrorKind {
PathResolutionError(PathResolutionError),
#[error("Non-struct type used in impl")]
NonStructTypeInImpl { span: Span },
#[error("Cannot `impl` a type defined outside the current crate")]
ForeignImpl { span: Span, type_name: String },
}

impl DefCollectorErrorKind {
Expand Down Expand Up @@ -101,6 +103,11 @@ impl From<DefCollectorErrorKind> for Diagnostic {
"Only struct types may have implementation methods".into(),
span,
),
DefCollectorErrorKind::ForeignImpl { span, type_name } => Diagnostic::simple_error(
"Cannot `impl` a type that was defined outside the current crate".into(),
format!("{type_name} was defined outside the current crate"),
span,
),
}
}
}
43 changes: 10 additions & 33 deletions crates/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use acvm::FieldElement;
use iter_extended::{btree_map, vecmap};
use noirc_abi::FunctionSignature;
use noirc_errors::Location;
use std::collections::{BTreeMap, HashMap, VecDeque};

use crate::{
Expand Down Expand Up @@ -956,56 +955,34 @@ impl<'interner> Monomorphizer<'interner> {

fn assign(&mut self, assign: HirAssignStatement) -> ast::Expression {
let expression = Box::new(self.expr(assign.expression));
let (lvalue, index_lvalue) = self.lvalue(assign.lvalue);

match index_lvalue {
Some((index, element_type, location)) => {
let lvalue =
ast::LValue::Index { array: Box::new(lvalue), index, element_type, location };
ast::Expression::Assign(ast::Assign { lvalue, expression })
}
None => ast::Expression::Assign(ast::Assign { expression, lvalue }),
}
let lvalue = self.lvalue(assign.lvalue);
ast::Expression::Assign(ast::Assign { expression, lvalue })
}

/// Returns the lvalue along with an optional LValue::Index to add to the end, if needed.
/// This is added to the end separately as part of converting arrays of structs to structs
/// of arrays.
fn lvalue(
&mut self,
lvalue: HirLValue,
) -> (ast::LValue, Option<(Box<ast::Expression>, ast::Type, Location)>) {
) -> ast::LValue {
match lvalue {
HirLValue::Ident(ident, _) => {
let lvalue = ast::LValue::Ident(self.local_ident(&ident).unwrap());
(lvalue, None)
ast::LValue::Ident(self.local_ident(&ident).unwrap())
}
HirLValue::MemberAccess { object, field_index, .. } => {
let field_index = field_index.unwrap();
let (object, index) = self.lvalue(*object);
let object = Box::new(object);
let lvalue = ast::LValue::MemberAccess { object, field_index };
(lvalue, index)
let object = Box::new(self.lvalue(*object));
ast::LValue::MemberAccess { object, field_index }
}
HirLValue::Index { array, index, typ } => {
let location = self.interner.expr_location(&index);

let (array, prev_index) = self.lvalue(*array);
assert!(
prev_index.is_none(),
"Nested arrays are currently unsupported in noir: location is {location:?}"
);

let array = Box::new(self.lvalue(*array));
let index = Box::new(self.expr(index));
let element_type = Self::convert_type(&typ);
(array, Some((index, element_type, location)))
ast::LValue::Index { array, index, element_type, location }
}
HirLValue::Dereference { lvalue, element_type } => {
let (reference, index) = self.lvalue(*lvalue);
let reference = Box::new(reference);
let reference = Box::new(self.lvalue(*lvalue));
let element_type = Self::convert_type(&element_type);
let lvalue = ast::LValue::Dereference { reference, element_type };
(lvalue, index)
ast::LValue::Dereference { reference, element_type }
}
}
}
Expand Down

0 comments on commit 38bf134

Please sign in to comment.