Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: separate methods in dc_crate into their own modules #3585

Merged
merged 5 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
771 changes: 23 additions & 748 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use std::{collections::BTreeMap, rc::Rc};

use fm::FileId;
use iter_extended::vecmap;
use noirc_errors::Span;

use crate::{
graph::CrateId,
hir::{
def_collector::dc_crate::{CompilationError, UnresolvedFunctions},
def_map::{CrateDefMap, ModuleId},
},
node_interner::{FuncId, NodeInterner, TraitImplId},
Shared, Type, TypeBinding,
};

use super::{path_resolver::StandardPathResolver, resolver::Resolver};

#[allow(clippy::too_many_arguments)]
pub(crate) fn resolve_function_set(
interner: &mut NodeInterner,
crate_id: CrateId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
mut unresolved_functions: UnresolvedFunctions,
self_type: Option<Type>,
trait_impl_id: Option<TraitImplId>,
impl_generics: Vec<(Rc<String>, Shared<TypeBinding>, Span)>,
errors: &mut Vec<(CompilationError, FileId)>,
) -> Vec<(FileId, FuncId)> {
let file_id = unresolved_functions.file_id;

let where_clause_errors =
unresolved_functions.resolve_trait_bounds_trait_ids(def_maps, crate_id);
errors.extend(where_clause_errors.iter().cloned().map(|e| (e.into(), file_id)));

vecmap(unresolved_functions.functions, |(mod_id, func_id, func)| {
let module_id = ModuleId { krate: crate_id, local_id: mod_id };
let path_resolver = StandardPathResolver::new(module_id);

let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file_id);
// Must use set_generics here to ensure we re-use the same generics from when
// the impl was originally collected. Otherwise the function will be using different
// TypeVariables for the same generic, causing it to instantiate incorrectly.
resolver.set_generics(impl_generics.clone());
resolver.set_self_type(self_type.clone());
resolver.set_trait_id(unresolved_functions.trait_id);
resolver.set_trait_impl_id(trait_impl_id);

// Without this, impl methods can accidentally be placed in contracts. See #3254
if self_type.is_some() {
resolver.set_in_contract(false);
}

let (hir_func, func_meta, errs) = resolver.resolve_function(func, func_id);
interner.push_fn_meta(func_meta, func_id);
interner.update_fn(func_id, hir_func);
errors.extend(errs.iter().cloned().map(|e| (e.into(), file_id)));
(file_id, func_id)
})
}

pub(crate) fn resolve_free_functions(
interner: &mut NodeInterner,
crate_id: CrateId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
collected_functions: Vec<UnresolvedFunctions>,
self_type: Option<Type>,
errors: &mut Vec<(CompilationError, FileId)>,
) -> Vec<(FileId, FuncId)> {
// Lower each function in the crate. This is now possible since imports have been resolved
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
collected_functions
.into_iter()
.flat_map(|unresolved_functions| {
resolve_function_set(
interner,
crate_id,
def_maps,
unresolved_functions,
self_type.clone(),
None,
vec![], // no impl generics
errors,
)
})
.collect()
}
56 changes: 56 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/globals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::{path_resolver::StandardPathResolver, resolver::Resolver, take_errors};
use crate::{
graph::CrateId,
hir::{
def_collector::dc_crate::{CompilationError, UnresolvedGlobal},
def_map::ModuleId,
Context,
},
node_interner::StmtId,
};
use fm::FileId;
use iter_extended::vecmap;

pub(crate) struct ResolvedGlobals {
pub(crate) globals: Vec<(FileId, StmtId)>,
pub(crate) errors: Vec<(CompilationError, FileId)>,
}

impl ResolvedGlobals {
pub(crate) fn extend(&mut self, oth: Self) {
self.globals.extend(oth.globals);
self.errors.extend(oth.errors);
}
}

pub(crate) fn resolve_globals(
context: &mut Context,
globals: Vec<UnresolvedGlobal>,
crate_id: CrateId,
) -> ResolvedGlobals {
let mut errors: Vec<(CompilationError, FileId)> = vec![];
let globals = vecmap(globals, |global| {
let module_id = ModuleId { local_id: global.module_id, krate: crate_id };
let path_resolver = StandardPathResolver::new(module_id);
let storage_slot = context.next_storage_slot(module_id);

let mut resolver = Resolver::new(
&mut context.def_interner,
&path_resolver,
&context.def_maps,
global.file_id,
);

let name = global.stmt_def.pattern.name_ident().clone();

let hir_stmt = resolver.resolve_global_let(global.stmt_def);
errors.extend(take_errors(global.file_id, resolver));

context.def_interner.update_global(global.stmt_id, hir_stmt);

context.def_interner.push_global(global.stmt_id, name, global.module_id, storage_slot);

(global.file_id, global.stmt_id)
});
ResolvedGlobals { globals, errors }
}
137 changes: 137 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::collections::BTreeMap;

use fm::FileId;

use crate::{
graph::CrateId,
hir::{
def_collector::{
dc_crate::{CompilationError, ImplMap},
errors::DefCollectorErrorKind,
},
def_map::{CrateDefMap, ModuleId},
Context,
},
node_interner::{FuncId, NodeInterner},
Type,
};

use super::{
errors::ResolverError, functions, get_module_mut, get_struct_type,
path_resolver::StandardPathResolver, resolver::Resolver, take_errors,
};

/// Go through the list of impls and add each function within to the scope
/// of the module defined by its type.
pub(crate) fn collect_impls(
context: &mut Context,
crate_id: CrateId,
collected_impls: &ImplMap,
) -> Vec<(CompilationError, FileId)> {
let interner = &mut context.def_interner;
let def_maps = &mut context.def_maps;
let mut errors: Vec<(CompilationError, FileId)> = vec![];

for ((unresolved_type, module_id), methods) in collected_impls {
let path_resolver =
StandardPathResolver::new(ModuleId { local_id: *module_id, krate: crate_id });

let file = def_maps[&crate_id].file_id(*module_id);

for (generics, span, unresolved) in methods {
let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file);
resolver.add_generics(generics);
let typ = resolver.resolve_type(unresolved_type.clone());

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

if let Some(struct_type) = get_struct_type(&typ) {
let struct_type = struct_type.borrow();

// `impl`s are only allowed on types defined within the current crate
if struct_type.id.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(), 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.
let module = get_module_mut(def_maps, struct_type.id.module_id());

for (_, method_id, method) in &unresolved.functions {
// If this method was already declared, remove it from the module so it cannot
// be accessed with the `TypeName::method` syntax. We'll check later whether the
// object types in each method overlap or not. If they do, we issue an error.
// If not, that is specialization which is allowed.
if module.declare_function(method.name_ident().clone(), *method_id).is_err() {
module.remove_function(method.name_ident());
}
}
// Prohibit defining impls for primitive types if we're not in the stdlib
} else if typ != Type::Error && !crate_id.is_stdlib() {
let span = *span;
let error = DefCollectorErrorKind::NonStructTypeInImpl { span };
errors.push((error.into(), unresolved.file_id));
}
}
}
errors
}

pub(crate) fn resolve_impls(
interner: &mut NodeInterner,
crate_id: CrateId,
def_maps: &BTreeMap<CrateId, CrateDefMap>,
collected_impls: ImplMap,
errors: &mut Vec<(CompilationError, FileId)>,
) -> Vec<(FileId, FuncId)> {
let mut file_method_ids = Vec::new();

for ((unresolved_type, module_id), methods) in collected_impls {
let path_resolver =
StandardPathResolver::new(ModuleId { local_id: module_id, krate: crate_id });

let file = def_maps[&crate_id].file_id(module_id);

for (generics, _, functions) in methods {
let mut resolver = Resolver::new(interner, &path_resolver, def_maps, file);
resolver.add_generics(&generics);
let generics = resolver.get_generics().to_vec();
let self_type = resolver.resolve_type(unresolved_type.clone());

let mut file_func_ids = functions::resolve_function_set(
interner,
crate_id,
def_maps,
functions,
Some(self_type.clone()),
None,
generics,
errors,
);
if self_type != Type::Error {
for (file_id, method_id) in &file_func_ids {
let method_name = interner.function_name(method_id).to_owned();

if let Some(first_fn) =
interner.add_method(&self_type, method_name.clone(), *method_id, false)
{
let error = ResolverError::DuplicateDefinition {
name: method_name,
first_span: interner.function_ident(&first_fn).span(),
second_span: interner.function_ident(method_id).span(),
};
errors.push((error.into(), *file_id));
}
}
}
file_method_ids.append(&mut file_func_ids);
}
}

file_method_ids
}
47 changes: 47 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,50 @@ pub mod errors;
pub mod import;
pub mod path_resolver;
pub mod resolver;

mod functions;
mod globals;
mod impls;
mod structs;
mod traits;
mod type_aliases;

pub(crate) use functions::resolve_free_functions;
pub(crate) use globals::resolve_globals;
pub(crate) use impls::{collect_impls, resolve_impls};
pub(crate) use structs::resolve_structs;
pub(crate) use traits::{
collect_trait_impls, resolve_trait_by_path, resolve_trait_impls, resolve_traits,
};
pub(crate) use type_aliases::resolve_type_aliases;

use crate::{
graph::CrateId,
hir::{
def_collector::dc_crate::CompilationError,
def_map::{CrateDefMap, ModuleData, ModuleId},
},
Shared, StructType, Type,
};
use fm::FileId;
use iter_extended::vecmap;
use resolver::Resolver;
use std::collections::BTreeMap;

fn take_errors(file_id: FileId, resolver: Resolver<'_>) -> Vec<(CompilationError, FileId)> {
vecmap(resolver.take_errors(), |e| (e.into(), file_id))
}

fn get_module_mut(
def_maps: &mut BTreeMap<CrateId, CrateDefMap>,
module: ModuleId,
) -> &mut ModuleData {
&mut def_maps.get_mut(&module.krate).unwrap().modules[module.local_id.0]
}

fn get_struct_type(typ: &Type) -> Option<&Shared<StructType>> {
match typ {
Type::Struct(definition, _) => Some(definition),
_ => None,
}
}
53 changes: 53 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/structs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::collections::BTreeMap;

use fm::FileId;
use iter_extended::vecmap;

use crate::{
graph::CrateId,
hir::{
def_collector::dc_crate::{CompilationError, UnresolvedStruct},
def_map::ModuleId,
Context,
},
node_interner::StructId,
Generics, Ident, Type,
};

use super::{errors::ResolverError, path_resolver::StandardPathResolver, resolver::Resolver};

/// Create the mappings from TypeId -> StructType
/// so that expressions can access the fields of structs
pub(crate) fn resolve_structs(
context: &mut Context,
structs: BTreeMap<StructId, UnresolvedStruct>,
crate_id: CrateId,
) -> Vec<(CompilationError, FileId)> {
let mut errors: Vec<(CompilationError, FileId)> = vec![];
// Resolve each field in each struct.
// Each struct should already be present in the NodeInterner after def collection.
for (type_id, typ) in structs {
let file_id = typ.file_id;
let (generics, fields, resolver_errors) = resolve_struct_fields(context, crate_id, typ);
errors.extend(vecmap(resolver_errors, |err| (err.into(), file_id)));
context.def_interner.update_struct(type_id, |struct_def| {
struct_def.set_fields(fields);
struct_def.generics = generics;
});
}
errors
}

fn resolve_struct_fields(
context: &mut Context,
krate: CrateId,
unresolved: UnresolvedStruct,
) -> (Generics, Vec<(Ident, Type)>, Vec<ResolverError>) {
let path_resolver =
StandardPathResolver::new(ModuleId { local_id: unresolved.module_id, krate });
let file_id = unresolved.file_id;
let (generics, fields, errors) =
Resolver::new(&mut context.def_interner, &path_resolver, &context.def_maps, file_id)
.resolve_struct_fields(unresolved.struct_def);
(generics, fields, errors)
}
Loading
Loading