Skip to content

Commit

Permalink
feat: add prelude.nr (#3693)
Browse files Browse the repository at this point in the history
# Description

## Additional Context

## Documentation

Check one:
- [x] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.

---------

Co-authored-by: kevaundray <[email protected]>
Co-authored-by: Tom French <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2023
1 parent 059ce4c commit 5f0f81f
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 53 deletions.
68 changes: 62 additions & 6 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::hir::resolution::errors::ResolverError;
use crate::hir::resolution::import::{resolve_imports, ImportDirective};
use crate::hir::resolution::resolver::Resolver;
use crate::hir::resolution::{
collect_impls, collect_trait_impls, resolve_free_functions, resolve_globals, resolve_impls,
resolve_structs, resolve_trait_by_path, resolve_trait_impls, resolve_traits,
collect_impls, collect_trait_impls, path_resolver, resolve_free_functions, resolve_globals,
resolve_impls, resolve_structs, resolve_trait_by_path, resolve_trait_impls, resolve_traits,
resolve_type_aliases,
};
use crate::hir::type_check::{type_check_func, TypeCheckError, TypeChecker};
Expand All @@ -19,8 +19,9 @@ use crate::node_interner::{FuncId, NodeInterner, StmtId, StructId, TraitId, Type

use crate::parser::{ParserError, SortedModule};
use crate::{
ExpressionKind, LetStatement, Literal, NoirFunction, NoirStruct, NoirTrait, NoirTypeAlias,
Path, Type, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType,
ExpressionKind, Ident, LetStatement, Literal, NoirFunction, NoirStruct, NoirTrait,
NoirTypeAlias, Path, PathKind, Type, UnresolvedGenerics, UnresolvedTraitConstraint,
UnresolvedType,
};
use fm::FileId;
use iter_extended::vecmap;
Expand Down Expand Up @@ -243,9 +244,20 @@ impl DefCollector {
context,
));

let submodules = vecmap(def_collector.def_map.modules().iter(), |(index, _)| index);
// Add the current crate to the collection of DefMaps
context.def_maps.insert(crate_id, def_collector.def_map);

inject_prelude(crate_id, context, crate_root, &mut def_collector.collected_imports);
for submodule in submodules {
inject_prelude(
crate_id,
context,
LocalModuleId(submodule),
&mut def_collector.collected_imports,
);
}

// Resolve unresolved imports collected from the crate
let (resolved, unresolved_imports) =
resolve_imports(crate_id, def_collector.collected_imports, &context.def_maps);
Expand All @@ -264,8 +276,11 @@ impl DefCollector {
for resolved_import in resolved {
let name = resolved_import.name;
for ns in resolved_import.resolved_namespace.iter_defs() {
let result = current_def_map.modules[resolved_import.module_scope.0]
.import(name.clone(), ns);
let result = current_def_map.modules[resolved_import.module_scope.0].import(
name.clone(),
ns,
resolved_import.is_prelude,
);

if let Err((first_def, second_def)) = result {
let err = DefCollectorErrorKind::Duplicate {
Expand Down Expand Up @@ -358,6 +373,47 @@ impl DefCollector {
}
}

fn inject_prelude(
crate_id: CrateId,
context: &Context,
crate_root: LocalModuleId,
collected_imports: &mut Vec<ImportDirective>,
) {
let segments: Vec<_> = "std::prelude"
.split("::")
.map(|segment| crate::Ident::new(segment.into(), Span::default()))
.collect();

let path =
Path { segments: segments.clone(), kind: crate::PathKind::Dep, span: Span::default() };

if !crate_id.is_stdlib() {
if let Ok(module_def) = path_resolver::resolve_path(
&context.def_maps,
ModuleId { krate: crate_id, local_id: crate_root },
path,
) {
let module_id = module_def.as_module().expect("std::prelude should be a module");
let prelude = context.module(module_id).scope().names();

for path in prelude {
let mut segments = segments.clone();
segments.push(Ident::new(path.to_string(), Span::default()));

collected_imports.insert(
0,
ImportDirective {
module_id: crate_root,
path: Path { segments, kind: PathKind::Dep, span: Span::default() },
alias: None,
is_prelude: true,
},
);
}
}
}
}

/// Separate the globals Vec into two. The first element in the tuple will be the
/// literal globals, except for arrays, and the second will be all other globals.
/// We exclude array literals as they can contain complex types
Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub fn collect_defs(
) -> Vec<(CompilationError, FileId)> {
let mut collector = ModCollector { def_collector, file_id, module_id };
let mut errors: Vec<(CompilationError, FileId)> = vec![];

// First resolve the module declarations
for decl in ast.module_decls {
errors.extend(collector.parse_module_declaration(context, &decl, crate_id));
Expand All @@ -57,6 +58,7 @@ pub fn collect_defs(
module_id: collector.module_id,
path: import.path,
alias: import.alias,
is_prelude: false,
});
}

Expand Down
77 changes: 44 additions & 33 deletions compiler/noirc_frontend/src/hir/def_map/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ use crate::{
};
use std::collections::{hash_map::Entry, HashMap};

type Scope = HashMap<Option<TraitId>, (ModuleDefId, Visibility, bool /*is_prelude*/)>;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Visibility {
Public,
}

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

defs: Vec<ModuleDefId>,
}
Expand All @@ -25,7 +27,7 @@ impl ItemScope {
mod_def: ModuleDefId,
trait_id: Option<TraitId>,
) -> Result<(), (Ident, Ident)> {
self.add_item_to_namespace(name, mod_def, trait_id)?;
self.add_item_to_namespace(name, mod_def, trait_id, false)?;
self.defs.push(mod_def);
Ok(())
}
Expand All @@ -38,25 +40,31 @@ impl ItemScope {
name: Ident,
mod_def: ModuleDefId,
trait_id: Option<TraitId>,
is_prelude: bool,
) -> Result<(), (Ident, Ident)> {
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));
let add_item = |map: &mut HashMap<Ident, Scope>| {
if let Entry::Occupied(mut o) = map.entry(name.clone()) {
let trait_hashmap = o.get_mut();
if let Entry::Occupied(mut n) = trait_hashmap.entry(trait_id) {
let is_prelude = std::mem::replace(&mut n.get_mut().2, is_prelude);
let old_ident = o.key();

if is_prelude {
Ok(())
} else {
Err((old_ident.clone(), name))
}
} else {
let mut trait_hashmap = HashMap::new();
trait_hashmap.insert(trait_id, (mod_def, Visibility::Public));
map.insert(name, trait_hashmap);
trait_hashmap.insert(trait_id, (mod_def, Visibility::Public, is_prelude));
Ok(())
}
};
} else {
let mut trait_hashmap = HashMap::new();
trait_hashmap.insert(trait_id, (mod_def, Visibility::Public, is_prelude));
map.insert(name, trait_hashmap);
Ok(())
}
};

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

pub fn find_module_with_name(&self, mod_name: &Ident) -> Option<&ModuleId> {
let (module_def, _) = self.types.get(mod_name)?.get(&None)?;
let (module_def, _, _) = self.types.get(mod_name)?.get(&None)?;
match module_def {
ModuleDefId::ModuleId(id) => Some(id),
_ => None,
Expand All @@ -81,13 +89,13 @@ impl ItemScope {
// 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 {
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()?)?;
let (module_def, _, _) = trait_hashmap.get(trait_hashmap.keys().last()?)?;
match module_def {
ModuleDefId::FunctionId(id) => Some(*id),
_ => None,
Expand All @@ -105,7 +113,7 @@ impl ItemScope {
func_name: &Ident,
trait_id: &Option<TraitId>,
) -> Option<FuncId> {
let (module_def, _) = self.values.get(func_name)?.get(trait_id)?;
let (module_def, _, _) = self.values.get(func_name)?.get(trait_id)?;
match module_def {
ModuleDefId::FunctionId(id) => Some(*id),
_ => None,
Expand All @@ -115,20 +123,19 @@ impl ItemScope {
pub fn find_name(&self, name: &Ident) -> PerNs {
// 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
}
let find_name_in = |a: &HashMap<Ident, Scope>| {
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) }
}
Expand All @@ -144,15 +151,19 @@ impl ItemScope {
}
}

pub fn names(&self) -> impl Iterator<Item = &Ident> {
self.types.keys().chain(self.values.keys())
}

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

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

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

Expand Down
17 changes: 13 additions & 4 deletions compiler/noirc_frontend/src/hir/def_map/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ impl ModuleData {
}
}

pub(crate) fn scope(&self) -> &ItemScope {
&self.scope
}

fn declare(
&mut self,
name: Ident,
Expand Down Expand Up @@ -104,21 +108,26 @@ impl ModuleData {
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, None)
pub fn import(
&mut self,
name: Ident,
id: ModuleDefId,
is_prelude: bool,
) -> Result<(), (Ident, Ident)> {
self.scope.add_item_to_namespace(name, id, None, is_prelude)
}

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().flat_map(|a| a.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().flat_map(|a| a.values().map(|(id, _)| *id))
self.definitions.values().values().flat_map(|a| a.values().map(|(id, _, _)| *id))
}
}
7 changes: 7 additions & 0 deletions compiler/noirc_frontend/src/hir/def_map/module_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ impl ModuleDefId {
ModuleDefId::GlobalId(_) => "global",
}
}

pub fn as_module(&self) -> Option<ModuleId> {
match self {
Self::ModuleId(v) => Some(*v),
_ => None,
}
}
}

impl From<ModuleId> for ModuleDefId {
Expand Down
8 changes: 4 additions & 4 deletions compiler/noirc_frontend/src/hir/def_map/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use super::{item_scope::Visibility, ModuleDefId};
// This works exactly the same as in r-a, just simplified
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct PerNs {
pub types: Option<(ModuleDefId, Visibility)>,
pub values: Option<(ModuleDefId, Visibility)>,
pub types: Option<(ModuleDefId, Visibility, bool)>,
pub values: Option<(ModuleDefId, Visibility, bool)>,
}

impl PerNs {
pub fn types(t: ModuleDefId) -> PerNs {
PerNs { types: Some((t, Visibility::Public)), values: None }
PerNs { types: Some((t, Visibility::Public, false)), values: None }
}

pub fn take_types(self) -> Option<ModuleDefId> {
Expand All @@ -24,7 +24,7 @@ impl PerNs {
self.types.map(|it| it.0).into_iter().chain(self.values.map(|it| it.0))
}

pub fn iter_items(self) -> impl Iterator<Item = (ModuleDefId, Visibility)> {
pub fn iter_items(self) -> impl Iterator<Item = (ModuleDefId, Visibility, bool)> {
self.types.into_iter().chain(self.values)
}

Expand Down
Loading

0 comments on commit 5f0f81f

Please sign in to comment.