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: collect functions generated by attributes #5930

Merged
merged 3 commits into from
Sep 4, 2024
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
29 changes: 16 additions & 13 deletions compiler/noirc_frontend/src/elaborator/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,21 +326,24 @@ impl<'context> Elaborator<'context> {
) {
match item {
TopLevelStatement::Function(function) => {
let id = self.interner.push_empty_fn();
let module = self.module_id();
self.interner.push_function(id, &function.def, module, location);
let module_id = self.module_id();

if self.interner.is_in_lsp_mode() && !function.def.is_test() {
self.interner.register_function(id, &function.def);
if let Some(id) = dc_mod::collect_function(
self.interner,
self.def_maps.get_mut(&self.crate_id).unwrap(),
&function,
module_id,
self.file,
&mut self.errors,
) {
let functions = vec![(self.local_module, id, function)];
generated_items.functions.push(UnresolvedFunctions {
file_id: self.file,
functions,
trait_id: None,
self_type: None,
});
}

let functions = vec![(self.local_module, id, function)];
generated_items.functions.push(UnresolvedFunctions {
file_id: self.file,
functions,
trait_id: None,
self_type: None,
});
}
TopLevelStatement::TraitImpl(mut trait_impl) => {
let (methods, associated_types, associated_constants) =
Expand Down
75 changes: 43 additions & 32 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,25 +248,16 @@
let module = ModuleId { krate, local_id: self.module_id };

for function in functions {
// check if optional field attribute is compatible with native field
if let Some(field) = function.attributes().get_field_attribute() {
if !is_native_field(&field) {
continue;
}
}

let name = function.name_ident().clone();
let func_id = context.def_interner.push_empty_fn();
let visibility = function.def.visibility;

// First create dummy function in the DefInterner
// So that we can get a FuncId
let location = Location::new(function.span(), self.file_id);
context.def_interner.push_function(func_id, &function.def, module, location);

if context.def_interner.is_in_lsp_mode() && !function.def.is_test() {
context.def_interner.register_function(func_id, &function.def);
}
let Some(func_id) = collect_function(
&mut context.def_interner,
&mut self.def_collector.def_map,
&function,
module,
self.file_id,
&mut errors,
) else {
continue;
};

// Now link this func_id to a crate level map with the noir function and the module id
// Encountering a NoirFunction, we retrieve it's module_data to get the namespace
Expand All @@ -275,19 +266,6 @@
// With this method we iterate each function in the Crate and not each module
// This may not be great because we have to pull the module_data for each function
unresolved_functions.push_fn(self.module_id, func_id, function);

// Add function to scope/ns of the module
let result = self.def_collector.def_map.modules[self.module_id.0]
.declare_function(name, visibility, func_id);

if let Err((first_def, second_def)) = result {
let error = DefCollectorErrorKind::Duplicate {
typ: DuplicateType::Function,
first_def,
second_def,
};
errors.push((error.into(), self.file_id));
}
}

self.def_collector.items.functions.push(unresolved_functions);
Expand Down Expand Up @@ -792,7 +770,7 @@
// if it's an inline module, or the first char of a the file if it's an external module.
// - `location` will always point to the token "foo" in `mod foo` regardless of whether
// it's inline or external.
// Eventually the location put in `ModuleData` is used for codelenses about `contract`s,

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

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
// so we keep using `location` so that it continues to work as usual.
let location = Location::new(mod_name.span(), mod_location.file);
let new_module =
Expand Down Expand Up @@ -842,6 +820,39 @@
Ok(mod_id)
}

pub fn collect_function(
interner: &mut NodeInterner,
def_map: &mut CrateDefMap,
function: &NoirFunction,
module: ModuleId,
file: FileId,
errors: &mut Vec<(CompilationError, FileId)>,
) -> Option<crate::node_interner::FuncId> {
if let Some(field) = function.attributes().get_field_attribute() {
if !is_native_field(&field) {
return None;
}
}
let name = function.name_ident().clone();
let func_id = interner.push_empty_fn();
let visibility = function.def.visibility;
let location = Location::new(function.span(), file);
interner.push_function(func_id, &function.def, module, location);
if interner.is_in_lsp_mode() && !function.def.is_test() {
interner.register_function(func_id, &function.def);
}
let result = def_map.modules[module.local_id.0].declare_function(name, visibility, func_id);
if let Err((first_def, second_def)) = result {
let error = DefCollectorErrorKind::Duplicate {
typ: DuplicateType::Function,
first_def,
second_def,
};
errors.push((error.into(), file));
}
Some(func_id)
}

pub fn collect_struct(
interner: &mut NodeInterner,
def_map: &mut CrateDefMap,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "unquote_function"
type = "bin"
authors = [""]
compiler_version = ">=0.33.0"

[dependencies]
12 changes: 12 additions & 0 deletions test_programs/compile_success_empty/unquote_function/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main() {
bar();
}

#[output_function]
fn foo() {}

comptime fn output_function(_f: FunctionDefinition) -> Quoted {
quote {
fn bar() {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ fn foo(x: Field, y: u32) -> u32 {

// Given a function, wrap its parameters in a struct definition
comptime fn output_struct(f: FunctionDefinition) -> Quoted {
let fields = f.parameters().map(|param: (Quoted, Type)| {
let fields = f.parameters().map(
|param: (Quoted, Type)| {
let name = param.0;
let typ = param.1;
quote { $name: $typ, }
}).join(quote {});
}
).join(quote {});

quote {
struct Foo { $fields }
Expand Down
Loading