Skip to content
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 aztec_macros/src/utils/parse_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fn empty_item(item: &mut Item) {
ItemKind::Import(use_tree, _) => empty_use_tree(use_tree),
ItemKind::Struct(noir_struct) => empty_noir_struct(noir_struct),
ItemKind::TypeAlias(noir_type_alias) => empty_noir_type_alias(noir_type_alias),
ItemKind::InnerAttribute(_) => (),
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ pub trait Recoverable {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ModuleDeclaration {
pub ident: Ident,
pub outer_attributes: Vec<SecondaryAttribute>,
}

impl std::fmt::Display for ModuleDeclaration {
Expand Down
13 changes: 12 additions & 1 deletion compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
QuotedTypeId,
},
parser::{Item, ItemKind, ParsedSubModule},
token::Tokens,
token::{SecondaryAttribute, Tokens},
ParsedModule, QuotedType,
};

Expand Down Expand Up @@ -432,6 +432,8 @@ pub trait Visitor {
fn visit_struct_pattern(&mut self, _: &Path, _: &[(Ident, Pattern)], _: Span) -> bool {
true
}

fn visit_secondary_attribute(&mut self, _: &SecondaryAttribute, _: Span) {}
}

impl ParsedModule {
Expand Down Expand Up @@ -481,6 +483,9 @@ impl Item {
ItemKind::ModuleDecl(module_declaration) => {
module_declaration.accept(self.span, visitor);
}
ItemKind::InnerAttribute(attribute) => {
attribute.accept(self.span, visitor);
}
}
}
}
Expand Down Expand Up @@ -1289,6 +1294,12 @@ impl Pattern {
}
}

impl SecondaryAttribute {
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
visitor.visit_secondary_attribute(self, span);
}
}

fn visit_expressions(expressions: &[Expression], visitor: &mut impl Visitor) {
for expression in expressions {
expression.accept(visitor);
Expand Down
63 changes: 49 additions & 14 deletions compiler/noirc_frontend/src/elaborator/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use crate::{
comptime::{Interpreter, InterpreterError, Value},
def_collector::{
dc_crate::{
CollectedItems, CompilationError, UnresolvedFunctions, UnresolvedStruct,
UnresolvedTrait, UnresolvedTraitImpl,
CollectedItems, CompilationError, ModuleAttribute, UnresolvedFunctions,
UnresolvedStruct, UnresolvedTrait, UnresolvedTraitImpl,
},
dc_mod,
},
def_map::ModuleId,
resolution::errors::ResolverError,
},
hir_def::expr::HirIdent,
Expand Down Expand Up @@ -96,21 +97,31 @@ impl<'context> Elaborator<'context> {
generated_items: &mut CollectedItems,
) {
for attribute in attributes {
if let SecondaryAttribute::Custom(attribute) = attribute {
if let Err(error) = self.run_comptime_attribute_on_item(
&attribute.contents,
item.clone(),
span,
attribute.contents_span,
generated_items,
) {
self.errors.push(error);
}
}
self.run_comptime_attribute_on_item(attribute, &item, span, generated_items);
}
}

fn run_comptime_attribute_on_item(
&mut self,
attribute: &SecondaryAttribute,
item: &Value,
span: Span,
generated_items: &mut CollectedItems,
) {
if let SecondaryAttribute::Custom(attribute) = attribute {
if let Err(error) = self.run_comptime_attribute_name_on_item(
&attribute.contents,
item.clone(),
span,
attribute.contents_span,
generated_items,
) {
self.errors.push(error);
}
}
}

fn run_comptime_attribute_name_on_item(
&mut self,
attribute: &str,
item: Value,
Expand Down Expand Up @@ -383,7 +394,8 @@ impl<'context> Elaborator<'context> {
| TopLevelStatement::Trait(_)
| TopLevelStatement::Impl(_)
| TopLevelStatement::TypeAlias(_)
| TopLevelStatement::SubModule(_) => {
| TopLevelStatement::SubModule(_)
| TopLevelStatement::InnerAttribute(_) => {
let item = item.to_string();
let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location };
self.errors.push(error.into_compilation_error_pair());
Expand Down Expand Up @@ -422,6 +434,7 @@ impl<'context> Elaborator<'context> {
traits: &BTreeMap<TraitId, UnresolvedTrait>,
types: &BTreeMap<StructId, UnresolvedStruct>,
functions: &[UnresolvedFunctions],
module_attributes: &[ModuleAttribute],
) -> CollectedItems {
let mut generated_items = CollectedItems::default();

Expand All @@ -444,9 +457,31 @@ impl<'context> Elaborator<'context> {
}

self.run_attributes_on_functions(functions, &mut generated_items);

self.run_attributes_on_modules(module_attributes, &mut generated_items);

generated_items
}

fn run_attributes_on_modules(
&mut self,
module_attributes: &[ModuleAttribute],
generated_items: &mut CollectedItems,
) {
for module_attribute in module_attributes {
let local_id = module_attribute.module_id;
let module_id = ModuleId { krate: self.crate_id, local_id };
let item = Value::ModuleDefinition(module_id);
let attribute = &module_attribute.attribute;
let span = Span::default();

self.local_module = module_attribute.attribute_module_id;
self.file = module_attribute.attribute_file_id;

self.run_comptime_attribute_on_item(attribute, &item, span, generated_items);
}
}

fn run_attributes_on_functions(
&mut self,
function_sets: &[UnresolvedFunctions],
Expand Down
7 changes: 6 additions & 1 deletion compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,12 @@ impl<'context> Elaborator<'context> {

// We have to run any comptime attributes on functions before the function is elaborated
// since the generated items are checked beforehand as well.
let generated_items = self.run_attributes(&items.traits, &items.types, &items.functions);
let generated_items = self.run_attributes(
&items.traits,
&items.types,
&items.functions,
&items.module_attributes,
);

// After everything is collected, we can elaborate our generated items.
// It may be better to inline these within `items` entirely since elaborating them
Expand Down
33 changes: 33 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
function_def_set_return_type(self, arguments, location)
}
"module_functions" => module_functions(self, arguments, location),
"module_has_named_attribute" => module_has_named_attribute(self, arguments, location),
"module_is_contract" => module_is_contract(self, arguments, location),
"module_name" => module_name(interner, arguments, location),
"modulus_be_bits" => modulus_be_bits(interner, arguments, location),
Expand Down Expand Up @@ -1816,6 +1817,38 @@ fn module_functions(
Ok(Value::Slice(func_ids, slice_type))
}

// fn has_named_attribute(self, name: Quoted) -> bool
fn module_has_named_attribute(
interpreter: &Interpreter,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let (self_argument, name) = check_two_arguments(arguments, location)?;
let module_id = get_module(self_argument)?;
let module_data = interpreter.elaborator.get_module(module_id);
let name = get_quoted(name)?;

let name = name.iter().map(|token| token.to_string()).collect::<Vec<_>>().join("");

let attributes = module_data.outer_attributes.iter().chain(&module_data.inner_attributes);
for attribute in attributes {
let parse_result = Elaborator::parse_attribute(attribute, location);
let Ok(Some((function, _arguments))) = parse_result else {
continue;
};

let ExpressionKind::Variable(path) = function.kind else {
continue;
};

if path.last_name() == name {
return Ok(Value::Bool(true));
}
}

Ok(Value::Bool(false))
}

// fn is_contract(self) -> bool
fn module_is_contract(
interpreter: &Interpreter,
Expand Down
8 changes: 7 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ fn interpret_helper(src: &str) -> Result<Value, InterpreterError> {
let module_id = LocalModuleId(Index::unsafe_zeroed());
let mut modules = noirc_arena::Arena::default();
let location = Location::new(Default::default(), file);
let root = LocalModuleId(modules.insert(ModuleData::new(None, location, false)));
let root = LocalModuleId(modules.insert(ModuleData::new(
None,
location,
Vec::new(),
Vec::new(),
false,
)));
assert_eq!(root, module_id);

let file_manager = FileManager::new(&PathBuf::new());
Expand Down
18 changes: 18 additions & 0 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleId};
use crate::hir::resolution::errors::ResolverError;
use crate::hir::resolution::path_resolver;
use crate::hir::type_check::TypeCheckError;
use crate::token::SecondaryAttribute;
use crate::{Generics, Type};

use crate::hir::resolution::import::{resolve_import, ImportDirective, PathResolution};
Expand Down Expand Up @@ -111,6 +112,21 @@ pub struct UnresolvedGlobal {
pub stmt_def: LetStatement,
}

pub struct ModuleAttribute {
// The file in which the module is defined
pub file_id: FileId,
// The module this attribute is attached to
pub module_id: LocalModuleId,
// The file where the attribute exists (it could be the same as `file_id`
// or a different one if it's an inner attribute in a different file)
pub attribute_file_id: FileId,
// The module where the attribute is defined (similar to `attribute_file_id`,
// it could be different than `module_id` for inner attributes)
pub attribute_module_id: LocalModuleId,
pub attribute: SecondaryAttribute,
pub is_inner: bool,
}

/// Given a Crate root, collect all definitions in that crate
pub struct DefCollector {
pub(crate) def_map: CrateDefMap,
Expand All @@ -127,6 +143,7 @@ pub struct CollectedItems {
pub globals: Vec<UnresolvedGlobal>,
pub(crate) impls: ImplMap,
pub(crate) trait_impls: Vec<UnresolvedTraitImpl>,
pub(crate) module_attributes: Vec<ModuleAttribute>,
}

impl CollectedItems {
Expand Down Expand Up @@ -238,6 +255,7 @@ impl DefCollector {
impls: HashMap::default(),
globals: vec![],
trait_impls: vec![],
module_attributes: vec![],
},
}
}
Expand Down
Loading