Skip to content

Commit

Permalink
feat: Unquote multiple items from annotations (#5441)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

## Summary\*

Allows us to insert possibly multiple top-level-items from an annotation
instead of just one.

This enables code like `#[derive(Eq, Default)]` which should insert
multiple trait impls.

## Additional Context



## Documentation\*

Check one:
- [ ] No documentation needed.
- [ ] Documentation included in this PR.
- [x] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist\*

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
jfecher authored Jul 8, 2024
1 parent 75f98ed commit be8eac6
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 75 deletions.
140 changes: 71 additions & 69 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,11 +1288,11 @@ impl<'context> Elaborator<'context> {
.map_err(|error| error.into_compilation_error_pair())?;

if value != Value::Unit {
let item = value
.into_top_level_item(location)
let items = value
.into_top_level_items(location)
.map_err(|error| error.into_compilation_error_pair())?;

self.add_item(item, generated_items, location);
self.add_items(items, generated_items, location);
}

Ok(())
Expand Down Expand Up @@ -1544,79 +1544,81 @@ impl<'context> Elaborator<'context> {
(comptime, items)
}

fn add_item(
fn add_items(
&mut self,
item: TopLevelStatement,
items: Vec<TopLevelStatement>,
generated_items: &mut CollectedItems,
location: Location,
) {
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 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 = dc_mod::collect_trait_impl_functions(
self.interner,
&mut trait_impl,
self.crate_id,
self.file,
self.local_module,
);
for item in items {
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 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 = dc_mod::collect_trait_impl_functions(
self.interner,
&mut trait_impl,
self.crate_id,
self.file,
self.local_module,
);

generated_items.trait_impls.push(UnresolvedTraitImpl {
file_id: self.file,
module_id: self.local_module,
trait_generics: trait_impl.trait_generics,
trait_path: trait_impl.trait_name,
object_type: trait_impl.object_type,
methods,
generics: trait_impl.impl_generics,
where_clause: trait_impl.where_clause,

// These last fields are filled in later
trait_id: None,
impl_id: None,
resolved_object_type: None,
resolved_generics: Vec::new(),
resolved_trait_generics: Vec::new(),
});
}
TopLevelStatement::Global(global) => {
let (global, error) = dc_mod::collect_global(
self.interner,
self.def_maps.get_mut(&self.crate_id).unwrap(),
global,
self.file,
self.local_module,
);
generated_items.trait_impls.push(UnresolvedTraitImpl {
file_id: self.file,
module_id: self.local_module,
trait_generics: trait_impl.trait_generics,
trait_path: trait_impl.trait_name,
object_type: trait_impl.object_type,
methods,
generics: trait_impl.impl_generics,
where_clause: trait_impl.where_clause,

// These last fields are filled in later
trait_id: None,
impl_id: None,
resolved_object_type: None,
resolved_generics: Vec::new(),
resolved_trait_generics: Vec::new(),
});
}
TopLevelStatement::Global(global) => {
let (global, error) = dc_mod::collect_global(
self.interner,
self.def_maps.get_mut(&self.crate_id).unwrap(),
global,
self.file,
self.local_module,
);

generated_items.globals.push(global);
if let Some(error) = error {
self.errors.push(error);
generated_items.globals.push(global);
if let Some(error) = error {
self.errors.push(error);
}
}
// Assume that an error has already been issued
TopLevelStatement::Error => (),

TopLevelStatement::Module(_)
| TopLevelStatement::Import(_)
| TopLevelStatement::Struct(_)
| TopLevelStatement::Trait(_)
| TopLevelStatement::Impl(_)
| TopLevelStatement::TypeAlias(_)
| TopLevelStatement::SubModule(_) => {
let item = item.to_string();
let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location };
self.errors.push(error.into_compilation_error_pair());
}
}
// Assume that an error has already been issued
TopLevelStatement::Error => (),

TopLevelStatement::Module(_)
| TopLevelStatement::Import(_)
| TopLevelStatement::Struct(_)
| TopLevelStatement::Trait(_)
| TopLevelStatement::Impl(_)
| TopLevelStatement::TypeAlias(_)
| TopLevelStatement::SubModule(_) => {
let item = item.to_string();
let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location };
self.errors.push(error.into_compilation_error_pair());
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,12 @@ impl Value {
}
}

pub(crate) fn into_top_level_item(self, location: Location) -> IResult<TopLevelStatement> {
pub(crate) fn into_top_level_items(
self,
location: Location,
) -> IResult<Vec<TopLevelStatement>> {
match self {
Value::Code(tokens) => parse_tokens(tokens, parser::top_level_item(), location.file),
Value::Code(tokens) => parse_tokens(tokens, parser::top_level_items(), location.file),
value => Err(InterpreterError::CannotInlineMacro { value, location }),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use chumsky::primitive::Container;
pub use errors::ParserError;
pub use errors::ParserErrorReason;
use noirc_errors::Span;
pub use parser::{expression, parse_program, top_level_item};
pub use parser::{expression, parse_program, top_level_items};

#[derive(Debug, Clone)]
pub enum TopLevelStatement {
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ fn module() -> impl NoirParser<ParsedModule> {
}

/// This parser is used for parsing top level statements in macros
pub fn top_level_item() -> impl NoirParser<TopLevelStatement> {
top_level_statement(module())
pub fn top_level_items() -> impl NoirParser<Vec<TopLevelStatement>> {
top_level_statement(module()).repeated()
}

/// top_level_statement: function_definition
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "unquote_multiple_items_from_annotation"
type = "bin"
authors = [""]
compiler_version = ">=0.31.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[foo]
struct Foo {}

fn main() {
assert_eq(ONE, 1);
assert_eq(TWO, 2);
}

comptime fn foo(_: StructDefinition) -> Quoted {
quote {
global ONE = 1;
global TWO = 2;
}
}
3 changes: 2 additions & 1 deletion tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ const IGNORED_BRILLIG_TESTS: [&str; 11] = [
/// Certain features are only available in the elaborator.
/// We skip these tests for non-elaborator code since they are not
/// expected to work there. This can be removed once the old code is removed.
const IGNORED_NEW_FEATURE_TESTS: [&str; 7] = [
const IGNORED_NEW_FEATURE_TESTS: [&str; 8] = [
"macros",
"wildcard_type",
"type_definition_annotation",
"numeric_generics_explicit",
"derive_impl",
"comptime_traits",
"comptime_slice_methods",
"unquote_multiple_items_from_annotation",
];

fn read_test_cases(
Expand Down

0 comments on commit be8eac6

Please sign in to comment.