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 @@ -252,6 +252,7 @@ impl<'a> ModCollector<'a> {
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 @@ -1344,88 +1344,14 @@ fn undo_instantiation_bindings(bindings: TypeBindings) {
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 @@ mod tests {
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 @@ pub struct NodeInterner {
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,
/// 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 @@ impl FunctionModifiers {
#[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 @@ -594,6 +600,7 @@ impl NodeInterner {
// 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 @@ impl NodeInterner {
}

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