diff --git a/crates/nargo_cli/src/cli/check_cmd.rs b/crates/nargo_cli/src/cli/check_cmd.rs index b5e7b0ac604..29864521380 100644 --- a/crates/nargo_cli/src/cli/check_cmd.rs +++ b/crates/nargo_cli/src/cli/check_cmd.rs @@ -135,7 +135,7 @@ mod tests { typed_param( "d", AbiType::Struct { - name: String::from("MyStruct"), + path: String::from("MyStruct"), fields: vec![ (String::from("d1"), AbiType::Field), ( diff --git a/crates/noirc_abi/src/input_parser/mod.rs b/crates/noirc_abi/src/input_parser/mod.rs index 11d40f338d5..badfb1f5b08 100644 --- a/crates/noirc_abi/src/input_parser/mod.rs +++ b/crates/noirc_abi/src/input_parser/mod.rs @@ -133,7 +133,7 @@ mod serialization_tests { AbiParameter { name: "bar".into(), typ: AbiType::Struct { - name: "MyStruct".into(), + path: "MyStruct".into(), fields: vec![ ("field1".into(), AbiType::Integer { sign: Sign::Unsigned, width: 8 }), ( diff --git a/crates/noirc_abi/src/lib.rs b/crates/noirc_abi/src/lib.rs index 76ecba9bff2..d0c7e4e58c1 100644 --- a/crates/noirc_abi/src/lib.rs +++ b/crates/noirc_abi/src/lib.rs @@ -12,7 +12,7 @@ use acvm::{ use errors::AbiError; use input_parser::InputValue; use iter_extended::{try_btree_map, try_vecmap, vecmap}; -use noirc_frontend::{Signedness, Type, TypeBinding, TypeVariableKind, Visibility}; +use noirc_frontend::{hir::Context, Signedness, Type, TypeBinding, TypeVariableKind, Visibility}; use serde::{Deserialize, Serialize}; // This is the ABI used to bridge the different TOML formats for the initial // witness, the partial witness generator and the interpreter. @@ -53,7 +53,7 @@ pub enum AbiType { }, Boolean, Struct { - name: String, + path: String, #[serde( serialize_with = "serialization::serialize_struct_fields", deserialize_with = "serialization::deserialize_struct_fields" @@ -116,8 +116,7 @@ pub enum Sign { } impl AbiType { - // TODO: Add `Context` argument for resolving fully qualified struct paths - pub fn from_type(typ: &Type) -> Self { + pub fn from_type(context: &Context, typ: &Type) -> Self { // Note; use strict_eq instead of partial_eq when comparing field types // in this method, you most likely want to distinguish between public and private match typ { @@ -127,7 +126,7 @@ impl AbiType { .evaluate_to_u64() .expect("Cannot have variable sized arrays as a parameter to main"); let typ = typ.as_ref(); - Self::Array { length, typ: Box::new(Self::from_type(typ)) } + Self::Array { length, typ: Box::new(Self::from_type(context, typ)) } } Type::Integer(sign, bit_width) => { let sign = match sign { @@ -139,8 +138,8 @@ impl AbiType { } Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => { match &*binding.borrow() { - TypeBinding::Bound(typ) => Self::from_type(typ), - TypeBinding::Unbound(_) => Self::from_type(&Type::default_int_type()), + TypeBinding::Bound(typ) => Self::from_type(context, typ), + TypeBinding::Unbound(_) => Self::from_type(context, &Type::default_int_type()), } } Type::Bool => Self::Boolean, @@ -157,8 +156,11 @@ impl AbiType { Type::Struct(def, ref args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); - let fields = vecmap(fields, |(name, typ)| (name, Self::from_type(&typ))); - Self::Struct { fields, name: struct_type.name.to_string() } + let fields = vecmap(fields, |(name, typ)| (name, Self::from_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); + Self::Struct { fields, path } } Type::Tuple(_) => todo!("AbiType::from_type not yet implemented for tuple types"), Type::TypeVariable(_, _) => unreachable!(), diff --git a/crates/noirc_abi/src/serialization.rs b/crates/noirc_abi/src/serialization.rs index 7d32874bb7e..ed838803fab 100644 --- a/crates/noirc_abi/src/serialization.rs +++ b/crates/noirc_abi/src/serialization.rs @@ -88,11 +88,11 @@ mod tests { let deserialized_array: AbiParameter = serde_json::from_str(serialized_array).unwrap(); assert_eq!(deserialized_array, expected_array); - let serialized_struct = "{ + let serialized_struct = "{ \"name\":\"thing3\", \"type\": { \"kind\":\"struct\", - \"name\": \"MyStruct\", + \"path\": \"MyStruct\", \"fields\": [ { \"name\": \"field1\", @@ -120,7 +120,7 @@ mod tests { let expected_struct = AbiParameter { name: "thing3".to_string(), typ: AbiType::Struct { - name: "MyStruct".to_string(), + path: "MyStruct".to_string(), fields: vec![ ("field1".to_string(), AbiType::Integer { sign: Sign::Unsigned, width: 3 }), ( diff --git a/crates/noirc_driver/src/lib.rs b/crates/noirc_driver/src/lib.rs index 3511fbeabb6..d187dea2028 100644 --- a/crates/noirc_driver/src/lib.rs +++ b/crates/noirc_driver/src/lib.rs @@ -141,8 +141,8 @@ pub fn compute_function_abi( let func_meta = context.def_interner.function_meta(&main_function); let (parameters, return_type) = func_meta.into_function_signature(); - let parameters = into_abi_params(parameters, &context.def_interner); - let return_type = return_type.map(|typ| AbiType::from_type(&typ)); + let parameters = into_abi_params(context, parameters); + let return_type = return_type.map(|typ| AbiType::from_type(context, &typ)); Some((parameters, return_type)) } diff --git a/crates/noirc_evaluator/src/ssa.rs b/crates/noirc_evaluator/src/ssa.rs index 7dbd627a949..6112cecdc6b 100644 --- a/crates/noirc_evaluator/src/ssa.rs +++ b/crates/noirc_evaluator/src/ssa.rs @@ -94,7 +94,7 @@ pub fn create_circuit( current_witness_index, return_witnesses, locations, input_witnesses, .. } = generated_acir; - let abi = gen_abi(&context.def_interner, func_sig, &input_witnesses, return_witnesses.clone()); + let abi = gen_abi(context, func_sig, &input_witnesses, return_witnesses.clone()); let public_abi = abi.clone().public_abi(); let public_parameters = diff --git a/crates/noirc_evaluator/src/ssa/abi_gen/mod.rs b/crates/noirc_evaluator/src/ssa/abi_gen/mod.rs index f2c61715e37..e4b4026bf21 100644 --- a/crates/noirc_evaluator/src/ssa/abi_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa/abi_gen/mod.rs @@ -4,6 +4,7 @@ use acvm::acir::native_types::Witness; use iter_extended::{btree_map, vecmap}; use noirc_abi::{Abi, AbiParameter, AbiType}; use noirc_frontend::{ + hir::Context, hir_def::{ function::{FunctionSignature, Param}, stmt::HirPattern, @@ -22,12 +23,12 @@ fn get_param_name<'a>(pattern: &HirPattern, interner: &'a NodeInterner) -> Optio } } -pub fn into_abi_params(params: Vec, interner: &NodeInterner) -> Vec { +pub fn into_abi_params(context: &Context, params: Vec) -> Vec { vecmap(params, |(pattern, typ, vis)| { - let param_name = get_param_name(&pattern, interner) + 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(&typ); + let as_abi = AbiType::from_type(context, &typ); AbiParameter { name: param_name, typ: as_abi, visibility: vis.into() } }) } @@ -35,14 +36,14 @@ pub fn into_abi_params(params: Vec, interner: &NodeInterner) -> Vec, ) -> Abi { let (parameters, return_type) = func_sig; - let parameters = into_abi_params(parameters, interner); - let return_type = return_type.map(|typ| AbiType::from_type(&typ)); + let parameters = into_abi_params(context, parameters); + let return_type = return_type.map(|typ| AbiType::from_type(context, &typ)); let param_witnesses = param_witnesses_from_abi_param(¶meters, input_witnesses); Abi { parameters, return_type, param_witnesses, return_witnesses } } diff --git a/crates/noirc_frontend/src/graph/mod.rs b/crates/noirc_frontend/src/graph/mod.rs index 0305854ca32..c8299b9417d 100644 --- a/crates/noirc_frontend/src/graph/mod.rs +++ b/crates/noirc_frontend/src/graph/mod.rs @@ -275,6 +275,12 @@ impl std::ops::Index for CrateGraph { &self.arena[&crate_id] } } +impl std::ops::Index<&CrateId> for CrateGraph { + type Output = CrateData; + fn index(&self, crate_id: &CrateId) -> &CrateData { + &self.arena[crate_id] + } +} /// XXX: This is bare-bone for two reasons: // There are no display names currently diff --git a/crates/noirc_frontend/src/hir/mod.rs b/crates/noirc_frontend/src/hir/mod.rs index d0b24e90a76..30cba237228 100644 --- a/crates/noirc_frontend/src/hir/mod.rs +++ b/crates/noirc_frontend/src/hir/mod.rs @@ -4,9 +4,9 @@ pub mod resolution; pub mod scope; pub mod type_check; -use crate::graph::{CrateGraph, CrateId}; +use crate::graph::{CrateGraph, CrateId, Dependency}; use crate::hir_def::function::FuncMeta; -use crate::node_interner::{FuncId, NodeInterner}; +use crate::node_interner::{FuncId, NodeInterner, StructId}; use def_map::{Contract, CrateDefMap}; use fm::FileManager; use std::collections::HashMap; @@ -86,6 +86,36 @@ impl Context { } } + /// Returns a fully-qualified path to the given [StructId] from the given [CrateId]. This function also + /// account for the crate names of dependencies. + /// + /// For example, if you project contains a `main.nr` and `foo.nr` and you provide the `main_crate_id` and the + /// `bar_struct_id` where the `Bar` struct is inside `foo.nr`, this function would return `foo::Bar` as a [String]. + pub fn fully_qualified_struct_path(&self, crate_id: &CrateId, id: StructId) -> String { + let module_id = id.0; + let child_id = module_id.local_id.0; + let def_map = + self.def_map(&module_id.krate).expect("The local crate should be analyzed already"); + + let module = self.module(module_id); + + let module_path = def_map.get_module_path_with_separator(child_id, module.parent, "::"); + + if &module_id.krate == crate_id { + module_path + } else { + let crate_name = &self.crate_graph[crate_id] + .dependencies + .iter() + .find_map(|dep| match dep { + Dependency { name, crate_id } if crate_id == &module_id.krate => Some(name), + _ => None, + }) + .expect("The Struct was supposed to be defined in a dependency"); + format!("{crate_name}::{module_path}") + } + } + pub fn function_meta(&self, func_id: &FuncId) -> FuncMeta { self.def_interner.function_meta(func_id) }