Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
76 changes: 44 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,17 @@ impl<'a> ModCollector<'a> {
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 func_id = match collect_function(
&mut context.def_interner,
&mut self.def_collector.def_map,
&function,
module,
self.file_id,
&mut errors,
) {
Some(value) => value,
None => 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 +267,6 @@ impl<'a> ModCollector<'a> {
// 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 @@ -842,6 +821,39 @@ fn push_child_module(
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