Skip to content

Commit

Permalink
Merge branch 'master' into tf/acir-var-euclid
Browse files Browse the repository at this point in the history
* master:
  chore: Add Spell Checker to recommended VS Code extensions (#3136)
  chore: run `nargo fmt` on integration tests (#3059)
  feat(traits): allow multiple traits to share the same associated function name and to be implemented for the same type (#3126)
  chore(fmt): format parentheses expression (#3132)
  chore(fmt): restore removed comment (#3129)
  • Loading branch information
TomAFrench committed Oct 13, 2023
2 parents b8940d6 + e88ce80 commit 21b3637
Show file tree
Hide file tree
Showing 107 changed files with 435 additions and 269 deletions.
4 changes: 3 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"jnoortheen.nix-ide",
"rust-lang.rust-analyzer",
"redhat.vscode-yaml",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
// Spell checking
"streetsidesoftware.code-spell-checker",
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub enum ExpressionKind {
Variable(Path),
Tuple(Vec<Expression>),
Lambda(Box<Lambda>),
Parenthesized(Box<Expression>),
Error,
}

Expand Down Expand Up @@ -479,6 +480,7 @@ impl Display for ExpressionKind {
write!(f, "({})", elements.join(", "))
}
Lambda(lambda) => lambda.fmt(f),
Parenthesized(subexpr) => write!(f, "({subexpr})"),
Error => write!(f, "Error"),
}
}
Expand Down
10 changes: 6 additions & 4 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,17 +499,18 @@ fn add_method_to_struct_namespace(
struct_type: &Shared<StructType>,
func_id: FuncId,
name_ident: &Ident,
trait_id: TraitId,
) -> Result<(), DefCollectorErrorKind> {
let struct_type = struct_type.borrow();
let type_module = struct_type.id.local_module_id();
let module = &mut current_def_map.modules[type_module.0];
module.declare_function(name_ident.clone(), func_id).map_err(|(first_def, second_def)| {
DefCollectorErrorKind::Duplicate {
module.declare_trait_function(name_ident.clone(), func_id, trait_id).map_err(
|(first_def, second_def)| DefCollectorErrorKind::Duplicate {
typ: DuplicateType::TraitImplementation,
first_def,
second_def,
}
})
},
)
}

fn collect_trait_impl(
Expand Down Expand Up @@ -550,6 +551,7 @@ fn collect_trait_impl(
struct_type,
*func_id,
ast.name_ident(),
trait_id,
) {
Ok(()) => {}
Err(err) => {
Expand Down
106 changes: 88 additions & 18 deletions compiler/noirc_frontend/src/hir/def_map/item_scope.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use super::{namespace::PerNs, ModuleDefId, ModuleId};
use crate::{node_interner::FuncId, Ident};
use crate::{
node_interner::{FuncId, TraitId},
Ident,
};
use std::collections::{hash_map::Entry, HashMap};

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
Expand All @@ -9,8 +12,8 @@ pub enum Visibility {

#[derive(Default, Debug, PartialEq, Eq)]
pub struct ItemScope {
types: HashMap<Ident, (ModuleDefId, Visibility)>,
values: HashMap<Ident, (ModuleDefId, Visibility)>,
types: HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>>,
values: HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>>,

defs: Vec<ModuleDefId>,
}
Expand All @@ -20,8 +23,9 @@ impl ItemScope {
&mut self,
name: Ident,
mod_def: ModuleDefId,
trait_id: Option<TraitId>,
) -> Result<(), (Ident, Ident)> {
self.add_item_to_namespace(name, mod_def)?;
self.add_item_to_namespace(name, mod_def, trait_id)?;
self.defs.push(mod_def);
Ok(())
}
Expand All @@ -33,16 +37,26 @@ impl ItemScope {
&mut self,
name: Ident,
mod_def: ModuleDefId,
trait_id: Option<TraitId>,
) -> Result<(), (Ident, Ident)> {
let add_item = |map: &mut HashMap<Ident, (ModuleDefId, Visibility)>| {
if let Entry::Occupied(o) = map.entry(name.clone()) {
let old_ident = o.key();
Err((old_ident.clone(), name))
} else {
map.insert(name, (mod_def, Visibility::Public));
Ok(())
}
};
let add_item =
|map: &mut HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>>| {
if let Entry::Occupied(mut o) = map.entry(name.clone()) {
let trait_hashmap = o.get_mut();
if let Entry::Occupied(_) = trait_hashmap.entry(trait_id) {
let old_ident = o.key();
Err((old_ident.clone(), name))
} else {
trait_hashmap.insert(trait_id, (mod_def, Visibility::Public));
Ok(())
}
} else {
let mut trait_hashmap = HashMap::new();
trait_hashmap.insert(trait_id, (mod_def, Visibility::Public));
map.insert(name, trait_hashmap);
Ok(())
}
};

match mod_def {
ModuleDefId::ModuleId(_) => add_item(&mut self.types),
Expand All @@ -55,34 +69,90 @@ impl ItemScope {
}

pub fn find_module_with_name(&self, mod_name: &Ident) -> Option<&ModuleId> {
let (module_def, _) = self.types.get(mod_name)?;
let (module_def, _) = self.types.get(mod_name)?.get(&None)?;
match module_def {
ModuleDefId::ModuleId(id) => Some(id),
_ => None,
}
}

pub fn find_func_with_name(&self, func_name: &Ident) -> Option<FuncId> {
let (module_def, _) = self.values.get(func_name)?;
let trait_hashmap = self.values.get(func_name)?;
// methods introduced without trait take priority and hide methods with the same name that come from a trait
let a = trait_hashmap.get(&None);
match a {
Some((module_def, _)) => match module_def {
ModuleDefId::FunctionId(id) => Some(*id),
_ => None,
},
None => {
if trait_hashmap.len() == 1 {
let (module_def, _) = trait_hashmap.get(trait_hashmap.keys().last()?)?;
match module_def {
ModuleDefId::FunctionId(id) => Some(*id),
_ => None,
}
} else {
// ambiguous name (multiple traits, containing the same function name)
None
}
}
}
}

pub fn find_func_with_name_and_trait_id(
&self,
func_name: &Ident,
trait_id: &Option<TraitId>,
) -> Option<FuncId> {
let (module_def, _) = self.values.get(func_name)?.get(trait_id)?;
match module_def {
ModuleDefId::FunctionId(id) => Some(*id),
_ => None,
}
}

pub fn find_name(&self, name: &Ident) -> PerNs {
PerNs { types: self.types.get(name).cloned(), values: self.values.get(name).cloned() }
// Names, not associated with traits are searched first. If not found, we search for name, coming from a trait.
// If we find only one name from trait, we return it. If there are multiple traits, providing the same name, we return None.
let find_name_in =
|a: &HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>>| {
if let Some(t) = a.get(name) {
if let Some(tt) = t.get(&None) {
Some(*tt)
} else if t.len() == 1 {
t.values().last().cloned()
} else {
None
}
} else {
None
}
};

PerNs { types: find_name_in(&self.types), values: find_name_in(&self.values) }
}

pub fn find_name_for_trait_id(&self, name: &Ident, trait_id: &Option<TraitId>) -> PerNs {
PerNs {
types: if let Some(t) = self.types.get(name) { t.get(trait_id).cloned() } else { None },
values: if let Some(v) = self.values.get(name) {
v.get(trait_id).cloned()
} else {
None
},
}
}

pub fn definitions(&self) -> Vec<ModuleDefId> {
self.defs.clone()
}

pub fn types(&self) -> &HashMap<Ident, (ModuleDefId, Visibility)> {
pub fn types(&self) -> &HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>> {
&self.types
}

pub fn values(&self) -> &HashMap<Ident, (ModuleDefId, Visibility)> {
pub fn values(&self) -> &HashMap<Ident, HashMap<Option<TraitId>, (ModuleDefId, Visibility)>> {
&self.values
}

Expand Down
38 changes: 26 additions & 12 deletions compiler/noirc_frontend/src/hir/def_map/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,30 @@ impl ModuleData {
}
}

fn declare(&mut self, name: Ident, item_id: ModuleDefId) -> Result<(), (Ident, Ident)> {
self.scope.add_definition(name.clone(), item_id)?;
fn declare(
&mut self,
name: Ident,
item_id: ModuleDefId,
trait_id: Option<TraitId>,
) -> Result<(), (Ident, Ident)> {
self.scope.add_definition(name.clone(), item_id, trait_id)?;

// definitions is a subset of self.scope so it is expected if self.scope.define_func_def
// returns without error, so will self.definitions.define_func_def.
self.definitions.add_definition(name, item_id)
self.definitions.add_definition(name, item_id, trait_id)
}

pub fn declare_function(&mut self, name: Ident, id: FuncId) -> Result<(), (Ident, Ident)> {
self.declare(name, id.into())
self.declare(name, id.into(), None)
}

pub fn declare_trait_function(
&mut self,
name: Ident,
id: FuncId,
trait_id: TraitId,
) -> Result<(), (Ident, Ident)> {
self.declare(name, id.into(), Some(trait_id))
}

pub fn remove_function(&mut self, name: &Ident) {
Expand All @@ -59,52 +73,52 @@ impl ModuleData {
}

pub fn declare_global(&mut self, name: Ident, id: StmtId) -> Result<(), (Ident, Ident)> {
self.declare(name, id.into())
self.declare(name, id.into(), None)
}

pub fn declare_struct(&mut self, name: Ident, id: StructId) -> Result<(), (Ident, Ident)> {
self.declare(name, ModuleDefId::TypeId(id))
self.declare(name, ModuleDefId::TypeId(id), None)
}

pub fn declare_type_alias(
&mut self,
name: Ident,
id: TypeAliasId,
) -> Result<(), (Ident, Ident)> {
self.declare(name, id.into())
self.declare(name, id.into(), None)
}

pub fn declare_trait(&mut self, name: Ident, id: TraitId) -> Result<(), (Ident, Ident)> {
self.declare(name, ModuleDefId::TraitId(id))
self.declare(name, ModuleDefId::TraitId(id), None)
}

pub fn declare_child_module(
&mut self,
name: Ident,
child_id: ModuleId,
) -> Result<(), (Ident, Ident)> {
self.declare(name, child_id.into())
self.declare(name, child_id.into(), None)
}

pub fn find_func_with_name(&self, name: &Ident) -> Option<FuncId> {
self.scope.find_func_with_name(name)
}

pub fn import(&mut self, name: Ident, id: ModuleDefId) -> Result<(), (Ident, Ident)> {
self.scope.add_item_to_namespace(name, id)
self.scope.add_item_to_namespace(name, id, None)
}

pub fn find_name(&self, name: &Ident) -> PerNs {
self.scope.find_name(name)
}

pub fn type_definitions(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
self.definitions.types().values().map(|(id, _)| *id)
self.definitions.types().values().flat_map(|a| a.values().map(|(id, _)| *id))
}

/// Return an iterator over all definitions defined within this module,
/// excluding any type definitions.
pub fn value_definitions(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
self.definitions.values().values().map(|(id, _)| *id)
self.definitions.values().values().flat_map(|a| a.values().map(|(id, _)| *id))
}
}
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,7 @@ impl<'a> Resolver<'a> {
captures: lambda_context.captures,
})
}),
ExpressionKind::Parenthesized(subexpr) => return self.resolve_expression(*subexpr),
};

let expr_id = self.interner.push_expr(hir_expr);
Expand Down
Loading

0 comments on commit 21b3637

Please sign in to comment.