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

Attributes and symbols in preparation for the test framework. #28448

Draft
wants to merge 1 commit into
base: mainnet
Choose a base branch
from
Draft
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 compiler/ast/src/functions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl Function {
Variant::Inline => write!(f, "inline ")?,
Variant::Function | Variant::AsyncFunction => write!(f, "function ")?,
Variant::Transition | Variant::AsyncTransition => write!(f, "transition ")?,
Variant::Interpret => write!(f, "interpret")?,
}
write!(f, "{}", self.identifier)?;

Expand Down
1 change: 1 addition & 0 deletions compiler/ast/src/functions/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum Variant {
Transition,
AsyncTransition,
AsyncFunction,
Interpret,
}

impl Variant {
Expand Down
1 change: 1 addition & 0 deletions compiler/ast/src/stub/function_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ impl FunctionStub {
Variant::Inline => write!(f, "inline ")?,
Variant::Function | Variant::AsyncFunction => write!(f, "function ")?,
Variant::Transition | Variant::AsyncTransition => write!(f, "transition ")?,
Variant::Interpret => write!(f, "interpret")?,
}
write!(f, "{}", self.identifier)?;

Expand Down
1 change: 1 addition & 0 deletions compiler/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ impl<'a, N: Network> Compiler<'a, N> {
&self.type_table,
self.compiler_options.build.conditional_block_max_depth,
self.compiler_options.build.disable_conditional_branch_type_checking,
false, // is_test
))?;
if self.compiler_options.output.type_checked_symbol_table {
self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?;
Expand Down
7 changes: 4 additions & 3 deletions compiler/parser/src/parser/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl<N: Network> ParserContext<'_, N> {
let (id, mapping) = self.parse_mapping()?;
mappings.push((id, mapping));
}
Token::At | Token::Async | Token::Function | Token::Transition | Token::Inline => {
Token::At | Token::Async | Token::Function | Token::Transition | Token::Inline | Token::Interpret => {
let (id, function) = self.parse_function()?;

// Partition into transitions and functions so that we don't have to sort later.
Expand Down Expand Up @@ -334,8 +334,9 @@ impl<N: Network> ParserContext<'_, N> {
// Parse a potential async signifier.
let (is_async, start_async) =
if self.token.token == Token::Async { (true, self.expect(&Token::Async)?) } else { (false, Span::dummy()) };
// Parse `<variant> IDENT`, where `<variant>` is `function`, `transition`, or `inline`.
// Parse `<variant> IDENT`, where `<variant>` is `function`, `transition`, `inline`, or `interpret`.
let (variant, start) = match self.token.token.clone() {
Token::Interpret => (Variant::Interpret, self.expect(&Token::Interpret)?),
Token::Inline => (Variant::Inline, self.expect(&Token::Inline)?),
Token::Function => {
(if is_async { Variant::AsyncFunction } else { Variant::Function }, self.expect(&Token::Function)?)
Expand All @@ -344,7 +345,7 @@ impl<N: Network> ParserContext<'_, N> {
if is_async { Variant::AsyncTransition } else { Variant::Transition },
self.expect(&Token::Transition)?,
),
_ => self.unexpected("'function', 'transition', or 'inline'")?,
_ => self.unexpected("'function', 'transition', 'inline', or 'interpret'")?,
};
let name = self.expect_identifier()?;

Expand Down
1 change: 1 addition & 0 deletions compiler/parser/src/tokenizer/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ impl Token {
"import" => Token::Import,
"in" => Token::In,
"inline" => Token::Inline,
"interpret" => Token::Interpret,
"let" => Token::Let,
"leo" => Token::Leo,
"mapping" => Token::Mapping,
Expand Down
4 changes: 4 additions & 0 deletions compiler/parser/src/tokenizer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ pub enum Token {
Import,
In,
Inline,
Interpret,
Let,
Mapping,
Network,
Expand Down Expand Up @@ -205,6 +206,7 @@ pub const KEYWORD_TOKENS: &[Token] = &[
Token::Import,
Token::In,
Token::Inline,
Token::Interpret,
Token::Let,
Token::Mapping,
Token::Network,
Expand Down Expand Up @@ -262,6 +264,7 @@ impl Token {
Token::Import => sym::import,
Token::In => sym::In,
Token::Inline => sym::inline,
Token::Interpret => sym::interpret,
Token::Let => sym::Let,
Token::Leo => sym::leo,
Token::Mapping => sym::mapping,
Expand Down Expand Up @@ -396,6 +399,7 @@ impl fmt::Display for Token {
Import => write!(f, "import"),
In => write!(f, "in"),
Inline => write!(f, "inline"),
Interpret => write!(f, "interpret"),
Let => write!(f, "let"),
Mapping => write!(f, "mapping"),
Network => write!(f, "network"),
Expand Down
2 changes: 1 addition & 1 deletion compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl<'a> CodeGenerator<'a> {
Variant::Transition | Variant::AsyncTransition => format!("\nfunction {}:\n", function.identifier),
Variant::Function => format!("\nclosure {}:\n", function.identifier),
Variant::AsyncFunction => format!("\nfinalize {}:\n", self.finalize_caller.unwrap()),
Variant::Inline => return String::new(),
Variant::Inline | Variant::Interpret => return String::new(),
};

// Construct and append the input declarations of the function.
Expand Down
8 changes: 5 additions & 3 deletions compiler/passes/src/function_inlining/inline_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ impl ExpressionReconstructor for FunctionInliner<'_> {

(result, inlined_statements)
}
Variant::Function | Variant::AsyncFunction | Variant::Transition | Variant::AsyncTransition => {
(Expression::Call(input), Default::default())
}
Variant::Function
| Variant::AsyncFunction
| Variant::Transition
| Variant::AsyncTransition
| Variant::Interpret => (Expression::Call(input), Default::default()),
}
}
}
2 changes: 1 addition & 1 deletion compiler/passes/src/type_checking/check_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<'a, N: Network> ExpressionVisitor<'a> for TypeChecker<'a, N> {
// Check core struct name and function.
if let Some(core_instruction) = self.get_core_function_call(&access.variant, &access.name) {
// Check that operation is not restricted to finalize blocks.
if self.scope_state.variant != Some(Variant::AsyncFunction)
if !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Interpret))
&& core_instruction.is_finalize_command()
{
self.emit_err(TypeCheckerError::operation_must_be_in_finalize_block(input.span()));
Expand Down
14 changes: 11 additions & 3 deletions compiler/passes/src/type_checking/check_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,18 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {

fn visit_function(&mut self, function: &'a Function) {
// Check that the function's annotations are valid.
// Note that Leo does not natively support any specific annotations.
let valid_annotations = [sym::should_fail, sym::native_test, sym::interpreted_test];
for annotation in function.annotations.iter() {
// TODO: Change to compiler warning.
self.emit_err(TypeCheckerError::unknown_annotation(annotation, annotation.span))
// All Leo annotations currently apply only to test code.
if !self.is_test || !valid_annotations.contains(&annotation.identifier.name) {
// TODO: Change to compiler warning.
self.emit_err(TypeCheckerError::unknown_annotation(annotation, annotation.span));
}
}

// `interpret` can only be used for tests.
if !self.is_test && function.variant == Variant::Interpret {
self.emit_err(TypeCheckerError::interpret_outside_test(function.span));
}

// Set type checker variables for function variant details.
Expand Down
8 changes: 7 additions & 1 deletion compiler/passes/src/type_checking/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct TypeChecker<'a, N: Network> {
pub(crate) async_function_input_types: IndexMap<Location, Vec<Type>>,
/// The set of used composites.
pub(crate) used_structs: IndexSet<Symbol>,
/// Are we compiling tests?
pub(crate) is_test: bool,
// Allows the type checker to be generic over the network.
phantom: PhantomData<N>,
}
Expand Down Expand Up @@ -109,6 +111,7 @@ impl<'a, N: Network> TypeChecker<'a, N> {
handler: &'a Handler,
max_depth: usize,
disabled: bool,
is_test: bool,
) -> Self {
let struct_names = symbol_table.structs.keys().map(|loc| loc.name).collect();
let function_names = symbol_table.functions.keys().map(|loc| loc.name).collect();
Expand All @@ -124,6 +127,7 @@ impl<'a, N: Network> TypeChecker<'a, N> {
await_checker: AwaitChecker::new(max_depth, !disabled),
async_function_input_types: IndexMap::new(),
used_structs: IndexSet::new(),
is_test,
phantom: Default::default(),
}
}
Expand Down Expand Up @@ -1375,7 +1379,9 @@ impl<'a, N: Network> TypeChecker<'a, N> {
// Check that the function context matches.
if self.scope_state.variant == Some(Variant::AsyncFunction) && !finalize_op {
self.handler.emit_err(TypeCheckerError::invalid_operation_inside_finalize(name, span))
} else if self.scope_state.variant != Some(Variant::AsyncFunction) && finalize_op {
} else if finalize_op
&& !matches!(self.scope_state.variant, Some(Variant::AsyncFunction) | Some(Variant::Interpret))
{
self.handler.emit_err(TypeCheckerError::invalid_operation_outside_finalize(name, span))
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/passes/src/type_checking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ use leo_errors::{Result, emitter::Handler};
use snarkvm::prelude::Network;

impl<'a, N: Network> Pass for TypeChecker<'a, N> {
type Input = (&'a Ast, &'a Handler, SymbolTable, &'a TypeTable, usize, bool);
type Input = (&'a Ast, &'a Handler, SymbolTable, &'a TypeTable, usize, bool, bool);
type Output = Result<(SymbolTable, StructGraph, CallGraph)>;

fn do_pass((ast, handler, st, tt, max_depth, await_checking): Self::Input) -> Self::Output {
let mut visitor = TypeChecker::<N>::new(st, tt, handler, max_depth, await_checking);
fn do_pass((ast, handler, st, tt, max_depth, await_checking, is_test): Self::Input) -> Self::Output {
let mut visitor = TypeChecker::<N>::new(st, tt, handler, max_depth, await_checking, is_test);
visitor.visit_program(ast.as_repr());
handler.last_err().map_err(|e| *e)?;

Expand Down
6 changes: 6 additions & 0 deletions compiler/span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ symbols! {
False: "false",
True: "true",

// annotations
should_fail,
native_test,
interpreted_test,

// general keywords
As: "as",
assert,
Expand All @@ -250,6 +255,7 @@ symbols! {
increment,
inline,
input,
interpret,
Let: "let",
leo,
main,
Expand Down
7 changes: 7 additions & 0 deletions errors/src/errors/type_checker/type_checker_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -894,4 +894,11 @@ create_messages!(
msg: format!("Cannot define a function with no parameters."),
help: None,
}

@formatted
interpret_outside_test {
args: (),
msg: "Cannot define an `interpret` function outside of tests.".to_string(),
help: None,
}
);

This file was deleted.