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

fix: Fix panic in some cases when calling a private function #2799

Merged
merged 2 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
let mut func_ids_in_trait = HashSet::new();

for item in &trait_def.items {
// TODO(Maddiaa): Investigate trait implementations with attributes see: https://github.com/noir-lang/noir/issues/2629

Check warning on line 229 in compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (Maddiaa)
if let TraitItem::Function {
name,
generics,
Expand All @@ -252,6 +252,7 @@
let method_name = name.0.contents.clone();
let func_id = context.def_interner.push_empty_fn();
let modifiers = FunctionModifiers {
name: name.0.contents.clone(),
// trait functions are always public
visibility: crate::Visibility::Public,
attributes: Attributes::empty(),
Expand Down
125 changes: 2 additions & 123 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@
expr: node_interner::ExprId,
) -> (ast::Expression, ast::Expression) {
// returns (<closure setup>, <closure variable>)
// which can be used directly in callsites or transformed

Check warning on line 1083 in compiler/noirc_frontend/src/monomorphization/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (callsites)
// directly to a single `Expression`
// for other cases by `lambda` which is called by `expr`
//
Expand Down Expand Up @@ -1344,88 +1344,14 @@
mod tests {
use std::collections::{BTreeMap, HashMap};

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

use crate::{
graph::CrateId,
hir::{
def_map::{CrateDefMap, LocalModuleId, ModuleData, ModuleDefId, ModuleId},
resolution::{
import::PathResolutionError, path_resolver::PathResolver, resolver::Resolver,
},
def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId},
resolution::{import::PathResolutionError, path_resolver::PathResolver},
},
node_interner::{FuncId, NodeInterner},
parse_program,
};

use super::monomorphize;

// TODO: refactor into a more general test utility?
// mostly copied from hir / type_check / mod.rs and adapted a bit
fn type_check_src_code(src: &str, func_namespace: Vec<String>) -> (FuncId, NodeInterner) {
let (program, errors) = parse_program(src);
let mut interner = NodeInterner::default();

// Using assert_eq here instead of assert(errors.is_empty()) displays
// the whole vec if the assert fails rather than just two booleans
assert_eq!(errors, vec![]);

let main_id = interner.push_test_function_definition("main".into());

let func_ids =
vecmap(&func_namespace, |name| interner.push_test_function_definition(name.into()));

let mut path_resolver = TestPathResolver(HashMap::new());
for (name, id) in func_namespace.into_iter().zip(func_ids.clone()) {
path_resolver.insert_func(name.to_owned(), id);
}

let mut def_maps = BTreeMap::new();
let file = FileId::default();

let mut modules = arena::Arena::new();
let location = Location::new(Default::default(), file);
modules.insert(ModuleData::new(None, location, false));

def_maps.insert(
CrateId::dummy_id(),
CrateDefMap {
root: path_resolver.local_module_id(),
modules,
krate: CrateId::dummy_id(),
extern_prelude: BTreeMap::new(),
},
);

let func_meta = vecmap(program.functions, |nf| {
let resolver = Resolver::new(&mut interner, &path_resolver, &def_maps, file);
let (hir_func, func_meta, _resolver_errors) = resolver.resolve_function(nf, main_id);
// TODO: not sure why, we do get an error here,
// but otherwise seem to get an ok monomorphization result
// assert_eq!(resolver_errors, vec![]);
(hir_func, func_meta)
});

println!("Before update_fn");

for ((hir_func, meta), func_id) in func_meta.into_iter().zip(func_ids.clone()) {
interner.update_fn(func_id, hir_func);
interner.push_fn_meta(meta, func_id);
}

println!("Before type_check_func");

// Type check section
let errors = crate::hir::type_check::type_check_func(
&mut interner,
func_ids.first().cloned().unwrap(),
);
assert_eq!(errors, vec![]);
(func_ids.first().cloned().unwrap(), interner)
}

// TODO: refactor into a more general test utility?
// TestPathResolver struct and impls copied from hir / type_check / mod.rs
struct TestPathResolver(HashMap<String, ModuleDefId>);
Expand All @@ -1452,51 +1378,4 @@
ModuleId { krate: CrateId::dummy_id(), local_id: self.local_module_id() }
}
}

impl TestPathResolver {
fn insert_func(&mut self, name: String, func_id: FuncId) {
self.0.insert(name, func_id.into());
}
}

// a helper test method
// TODO: maybe just compare trimmed src/expected
// for easier formatting?
fn check_rewrite(src: &str, expected: &str) {
let (func, interner) = type_check_src_code(src, vec!["main".to_string()]);
let program = monomorphize(func, &interner);
// println!("[{}]", program);
assert!(format!("{}", program) == expected);
}

#[test]
fn simple_closure_with_no_captured_variables() {
let src = r#"
fn main() -> pub Field {
let x = 1;
let closure = || x;
closure()
}
"#;

let expected_rewrite = r#"fn main$f0() -> Field {
let x$0 = 1;
let closure$3 = {
let closure_variable$2 = {
let env$1 = (x$l0);
(env$l1, lambda$f1)
};
closure_variable$l2
};
{
let tmp$4 = closure$l3;
tmp$l4.1(tmp$l4.0)
}
}
fn lambda$f1(mut env$l1: (Field)) -> Field {
env$l1.0
}
"#;
check_rewrite(src, expected_rewrite);
}
}
10 changes: 8 additions & 2 deletions compiler/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,12 @@
primitive_methods: HashMap<(TypeMethodKey, String), FuncId>,
}

/// All the information from a function that is filled out during definition collection rather than
/// name resolution. Resultingly, if information about a function is needed during name resolution,

Check warning on line 118 in compiler/noirc_frontend/src/node_interner.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (Resultingly)
/// this is the only place where it is safe to retrieve it (where all fields are guaranteed to be initialized).
pub struct FunctionModifiers {
pub name: String,

/// Whether the function is `pub` or not.
pub visibility: Visibility,

Expand All @@ -138,6 +143,7 @@
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
name: String::new(),
visibility: Visibility::Public,
attributes: Attributes::empty(),
is_unconstrained: false,
Expand Down Expand Up @@ -572,7 +578,7 @@
id
}

/// Push a function with the default modifiers and moduleid for testing

Check warning on line 581 in compiler/noirc_frontend/src/node_interner.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (moduleid)
#[cfg(test)]
pub fn push_test_function_definition(&mut self, name: String) -> FuncId {
let id = self.push_fn(HirFunction::empty());
Expand All @@ -594,6 +600,7 @@
// We're filling in contract_function_type and is_internal now, but these will be verified
// later during name resolution.
let modifiers = FunctionModifiers {
name: function.name.0.contents.clone(),
visibility: if function.is_public { Visibility::Public } else { Visibility::Private },
attributes: function.attributes.clone(),
is_unconstrained: function.is_unconstrained,
Expand Down Expand Up @@ -656,8 +663,7 @@
}

pub fn function_name(&self, func_id: &FuncId) -> &str {
let name_id = self.function_meta(func_id).name.id;
self.definition_name(name_id)
&self.function_modifiers[func_id].name
}

pub fn function_modifiers(&self, func_id: &FuncId) -> &FunctionModifiers {
Expand Down
Loading