Skip to content

Commit

Permalink
Merge branch 'jf/quoted-to-trait-constraints' into jf/value-print
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Jul 31, 2024
2 parents 287b1bd + e592a10 commit d7a3a8a
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 26 deletions.
31 changes: 21 additions & 10 deletions compiler/noirc_frontend/src/elaborator/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'context> Elaborator<'context> {
generated_items: &mut CollectedItems,
) -> Result<(), (CompilationError, FileId)> {
let location = Location::new(span, self.file);
let Some((function, arguments)) = Self::parse_attribute(attribute) else {
let Some((function, arguments)) = Self::parse_attribute(attribute, self.file)? else {
// Do not issue an error if the attribute is unknown
return Ok(());
};
Expand All @@ -129,12 +129,17 @@ impl<'context> Elaborator<'context> {
_ => return Ok(()),
};

let definition = self.interner.try_definition(definition_id);
let Some(DefinitionKind::Function(function)) = definition.map(|d| &d.kind) else {
let Some(definition) = self.interner.try_definition(definition_id) else {
// If there's no such function, don't return an error.
// This preserves backwards compatibility in allowing custom attributes that
// do not refer to comptime functions.
return Ok(());
};

let DefinitionKind::Function(function) = definition.kind else {
return Err((ResolverError::NonFunctionInAnnotation { span }.into(), self.file));
};

let function = *function;
let mut interpreter = self.setup_interpreter();
let mut arguments =
Self::handle_attribute_arguments(&mut interpreter, function, arguments, location)
Expand Down Expand Up @@ -162,19 +167,25 @@ impl<'context> Elaborator<'context> {

/// Parses an attribute in the form of a function call (e.g. `#[foo(a b, c d)]`) into
/// the function and quoted arguments called (e.g. `("foo", vec![(a b, location), (c d, location)])`)
fn parse_attribute(annotation: &str) -> Option<(Expression, Vec<Expression>)> {
let (tokens, lexing_errors) = Lexer::lex(annotation);
#[allow(clippy::type_complexity)]
fn parse_attribute(
annotation: &str,
file: FileId,
) -> Result<Option<(Expression, Vec<Expression>)>, (CompilationError, FileId)> {
let (tokens, mut lexing_errors) = Lexer::lex(annotation);
if !lexing_errors.is_empty() {
return None;
return Err((lexing_errors.swap_remove(0).into(), file));
}

let expression = parser::expression().parse(tokens).ok()?;
let expression = parser::expression()
.parse(tokens)
.map_err(|mut errors| (errors.swap_remove(0).into(), file))?;

match expression.kind {
Ok(match expression.kind {
ExpressionKind::Call(call) => Some((*call.func, call.arguments)),
ExpressionKind::Variable(_) => Some((expression, Vec::new())),
_ => None,
}
})
}

fn handle_attribute_arguments(
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1214,8 +1214,8 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
let mut result = self.call_function(function_id, arguments, bindings, location)?;
if call.is_macro_call {
let expr = result.into_expression(self.elaborator.interner, location)?;
let expr = self.elaborate_item(self.current_function, |elab| {
elab.elaborate_expression(expr).0
let expr = self.elaborate_item(self.current_function, |elaborator| {
elaborator.elaborate_expression(expr).0
});
result = self.evaluate(expr)?;
}
Expand Down
9 changes: 0 additions & 9 deletions compiler/noirc_frontend/src/hir/resolution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ pub enum ResolverError {
MacroIsNotComptime { span: Span },
#[error("Annotation name must refer to a comptime function")]
NonFunctionInAnnotation { span: Span },
#[error("Unknown annotation")]
UnknownAnnotation { span: Span },
}

impl ResolverError {
Expand Down Expand Up @@ -460,13 +458,6 @@ impl<'a> From<&'a ResolverError> for Diagnostic {
*span,
)
},
ResolverError::UnknownAnnotation { span } => {
Diagnostic::simple_warning(
"Unknown annotation".into(),
"No matching comptime function found in scope".into(),
*span,
)
},
}
}
}
7 changes: 7 additions & 0 deletions compiler/noirc_frontend/src/lexer/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::hir::def_collector::dc_crate::CompilationError;
use crate::parser::ParserError;
use crate::parser::ParserErrorReason;
use crate::token::SpannedToken;
Expand Down Expand Up @@ -42,6 +43,12 @@ impl From<LexerErrorKind> for ParserError {
}
}

impl From<LexerErrorKind> for CompilationError {
fn from(error: LexerErrorKind) -> Self {
ParserError::from(error).into()
}
}

impl LexerErrorKind {
pub fn span(&self) -> Span {
match self {
Expand Down
11 changes: 6 additions & 5 deletions test_programs/compile_success_empty/attribute_args/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
#[attr_with_args(a b, c d)]
#[varargs(one, two)]
#[varargs(one, two, three, four)]
#[attr_with_args(1, 2)]
#[varargs(1, 2)]
#[varargs(1, 2, 3, 4)]
struct Foo {}

comptime fn attr_with_args(s: StructDefinition, a: Quoted, b: Quoted) {
comptime fn attr_with_args(s: StructDefinition, a: Field, b: Field) {
// Ensure all variables are in scope.
// We can't print them since that breaks the test runner.
let _ = s;
let _ = a;
let _ = b;
}

comptime fn varargs(s: StructDefinition, t: [Quoted]) {
#[varargs]
comptime fn varargs(s: StructDefinition, t: [Field]) {
let _ = s;
for _ in t {}
assert(t.len() < 5);
Expand Down

0 comments on commit d7a3a8a

Please sign in to comment.