This commit is contained in:
evan-schott 2024-03-08 16:42:55 -08:00
parent c01c61c5e4
commit 997b9051fd
20 changed files with 204 additions and 126 deletions

View File

@ -44,11 +44,10 @@ use snarkvm::{
FinalizeType::{Future as FutureFinalizeType, Plaintext as PlaintextFinalizeType},
RegisterType::{ExternalRecord, Future, Plaintext, Record},
},
prelude::{Network, ValueType},
prelude::{FinalizeType, Network, ValueType},
synthesizer::program::{ClosureCore, CommandTrait, FunctionCore, InstructionTrait},
};
use std::fmt;
use snarkvm::prelude::FinalizeType;
/// A function stub definition.
#[derive(Clone, Serialize, Deserialize)]
@ -187,15 +186,13 @@ impl FunctionStub {
span: Default::default(),
id: Default::default(),
}),
ValueType::ExternalRecord(loc) => {
Output::External(External {
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
program_name: ProgramId::from(loc.program_id()).name,
record: Identifier::from(loc.resource()),
span: Default::default(),
id: Default::default(),
})
}
ValueType::ExternalRecord(loc) => Output::External(External {
identifier: Identifier::new(Symbol::intern("dummy"), Default::default()),
program_name: ProgramId::from(loc.program_id()).name,
record: Identifier::from(loc.resource()),
span: Default::default(),
id: Default::default(),
}),
ValueType::Future(_) => Output::Internal(FunctionOutput {
mode: Mode::Public,
type_: Type::Future(FutureType::new(Vec::new())),

View File

@ -14,14 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Type};
use crate::Type;
use serde::{Deserialize, Serialize};
use std::fmt;
/// A future type consisting of the type of the inputs.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Default)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub struct FutureType {
// Optional type specification of inputs.
pub inputs: Vec<Type>,
@ -39,7 +38,6 @@ impl FutureType {
}
}
impl fmt::Display for crate::FutureType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Future<{}>", self.inputs.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))

View File

@ -103,7 +103,11 @@ pub fn get_build_options(test_config: &TestConfig) -> Vec<BuildOptions> {
})
.collect()
}
None => vec![BuildOptions { dce_enabled: true, conditional_block_max_depth: 10, disable_conditional_branch_type_checking: false }],
None => vec![BuildOptions {
dce_enabled: true,
conditional_block_max_depth: 10,
disable_conditional_branch_type_checking: false,
}],
}
}

View File

@ -752,7 +752,7 @@ impl ParserContext<'_> {
}
Token::Future => {
Expression::Identifier(Identifier { name: sym::Future, span, id: self.node_builder.next_id() })
},
}
t if crate::type_::TYPE_TOKENS.contains(&t) => Expression::Identifier(Identifier {
name: t.keyword_to_symbol().unwrap(),
span,

View File

@ -17,7 +17,7 @@
use crate::{CallGraph, StructGraph, SymbolTable, TypeTable};
use leo_ast::{Function, Program, ProgramId};
use leo_span::{Symbol};
use leo_span::Symbol;
use indexmap::IndexMap;
@ -51,7 +51,7 @@ pub struct CodeGenerator<'a> {
/// The program ID of the current program.
pub(crate) program_id: Option<ProgramId>,
/// A reference to the finalize caller.
pub(crate) finalize_caller: Option<Symbol>,
pub(crate) finalize_caller: Option<Symbol>,
}
impl<'a> CodeGenerator<'a> {

View File

@ -15,7 +15,32 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::CodeGenerator;
use leo_ast::{AccessExpression, ArrayAccess, ArrayExpression, AssociatedConstant, AssociatedFunction, BinaryExpression, BinaryOperation, CallExpression, CastExpression, ErrExpression, Expression, Identifier, Literal, MemberAccess, MethodCall, Node, StructExpression, TernaryExpression, TupleExpression, Type, UnaryExpression, UnaryOperation, UnitExpression, Variant};
use leo_ast::{
AccessExpression,
ArrayAccess,
ArrayExpression,
AssociatedConstant,
AssociatedFunction,
BinaryExpression,
BinaryOperation,
CallExpression,
CastExpression,
ErrExpression,
Expression,
Identifier,
Literal,
MemberAccess,
MethodCall,
Node,
StructExpression,
TernaryExpression,
TupleExpression,
Type,
UnaryExpression,
UnaryOperation,
UnitExpression,
Variant,
};
use leo_span::sym;
use std::borrow::Borrow;
@ -465,7 +490,7 @@ impl<'a> CodeGenerator<'a> {
}
_ => {
unreachable!("All core functions should be known at this phase of compilation")
},
}
};
// Add the instruction to the list of instructions.
instructions.push_str(&instruction);
@ -546,7 +571,7 @@ impl<'a> CodeGenerator<'a> {
self.next_register += 1;
}
}
// Add a register for async functions to represent the future created.
if func.is_async && func.variant == Variant::Standard {
let destination_register = format!("r{}", self.next_register);

View File

@ -16,11 +16,26 @@
use crate::CodeGenerator;
use leo_ast::{AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression, ExpressionStatement, IterationStatement, Mode, Output, ReturnStatement, Statement, Type};
use leo_ast::{
AssertStatement,
AssertVariant,
AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionStatement,
IterationStatement,
Mode,
Output,
ReturnStatement,
Statement,
Type,
};
use itertools::Itertools;
impl<'a> CodeGenerator<'a> {
fn visit_statement(&mut self, input: &'a Statement) -> String {
match input {
@ -74,7 +89,7 @@ impl<'a> CodeGenerator<'a> {
// Get the output type of the function.
let output = self.current_function.unwrap().output.iter();
// If the operand string is empty, initialize an empty vector.
let mut operand_strings = match operand.is_empty() {
let operand_strings = match operand.is_empty() {
true => vec![],
false => operand.split(' ').collect_vec(),
};
@ -106,7 +121,9 @@ impl<'a> CodeGenerator<'a> {
if let Type::Future(_) = output.type_ {
future_output = format!(
" output {} as {}.aleo/{}.future;\n",
operand, self.program_id.unwrap().name, self.current_function.unwrap().identifier,
operand,
self.program_id.unwrap().name,
self.current_function.unwrap().identifier,
);
String::new()
} else {

View File

@ -15,9 +15,9 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use indexmap::IndexSet;
use leo_ast::Identifier;
use std::{fmt::Debug, hash::Hash};
use leo_span::Symbol;
use std::{fmt::Debug, hash::Hash};
/// A binary search tree to store all paths through nested conditional blocks.
pub type ConditionalTreeNode = TreeNode<Symbol>;

View File

@ -16,7 +16,16 @@
use crate::Destructurer;
use leo_ast::{AccessExpression, Expression, ExpressionReconstructor, Identifier, MemberAccess, Statement, TupleAccess, Type};
use leo_ast::{
AccessExpression,
Expression,
ExpressionReconstructor,
Identifier,
MemberAccess,
Statement,
TupleAccess,
Type,
};
use leo_span::Symbol;
impl ExpressionReconstructor for Destructurer<'_> {

View File

@ -16,7 +16,32 @@
use crate::{RenameTable, StaticSingleAssigner};
use leo_ast::{AccessExpression, AssertStatement, AssertVariant, AssignStatement, AssociatedFunction, Block, CallExpression, ConditionalStatement, ConsoleStatement, ConstDeclaration, DefinitionStatement, Expression, ExpressionConsumer, ExpressionStatement, Identifier, IterationStatement, MethodCall, Node, ReturnStatement, Statement, StatementConsumer, TernaryExpression, TupleExpression, Type};
use leo_ast::{
AccessExpression,
AssertStatement,
AssertVariant,
AssignStatement,
AssociatedFunction,
Block,
CallExpression,
ConditionalStatement,
ConsoleStatement,
ConstDeclaration,
DefinitionStatement,
Expression,
ExpressionConsumer,
ExpressionStatement,
Identifier,
IterationStatement,
MethodCall,
Node,
ReturnStatement,
Statement,
StatementConsumer,
TernaryExpression,
TupleExpression,
Type,
};
use leo_span::Symbol;
use indexmap::IndexSet;

View File

@ -16,7 +16,7 @@
use leo_ast::*;
use leo_errors::emitter::Handler;
use leo_span::sym::function;
use leo_span::Symbol;
use crate::{SymbolTable, VariableSymbol, VariableType};

View File

@ -15,8 +15,8 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ConditionalTreeNode, TreeNode};
use indexmap::{IndexSet};
use leo_ast::{Identifier};
use indexmap::IndexSet;
use leo_ast::Identifier;
use leo_errors::TypeCheckerError;
use leo_span::{Span, Symbol};
@ -92,15 +92,11 @@ impl AwaitChecker {
parent_nodes: Vec<ConditionalTreeNode>,
) -> Vec<ConditionalTreeNode> {
// Check if a nested conditional statement signaled their existence.
if is_finalize && self.enabled {
core::mem::replace(&mut self.to_await, parent_nodes)
} else {
Vec::new()
}
if is_finalize && self.enabled { core::mem::replace(&mut self.to_await, parent_nodes) } else { Vec::new() }
}
/// Exit scope for conditional statement at current depth.
pub fn exit_statement_scope(&mut self, is_finalize: bool, then_nodes: Vec<ConditionalTreeNode>) {
pub fn exit_statement_scope(&mut self, is_finalize: bool, then_nodes: Vec<ConditionalTreeNode>) {
if is_finalize && self.enabled {
// Merge together the current set of nodes (from `otherwise` branch) with `then` nodes.
self.to_await.extend(then_nodes);

View File

@ -21,10 +21,13 @@ use leo_errors::{emitter::Handler, TypeCheckerError};
use leo_span::{sym, Span, Symbol};
use itertools::Itertools;
use leo_ast::{CoreFunction::FutureAwait, Variant::Standard};
use leo_ast::{
CoreFunction::FutureAwait,
Type::{Future, Tuple},
Variant::Standard,
};
use snarkvm::console::network::{Network, Testnet3};
use std::str::FromStr;
use leo_ast::Type::{Future, Tuple};
fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: &Option<Type>) -> Option<Type> {
match (t1, t2) {
@ -187,7 +190,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}
Future(_) => {
// Get the fully inferred type.
if let Some(Type::Future(inferred_f)) = self.type_table.get(&access.tuple.id()) {
if let Some(Type::Future(inferred_f)) = self.type_table.get(&access.tuple.id()) {
// Make sure in range.
if access.index.value() >= inferred_f.inputs().len() {
self.emit_err(TypeCheckerError::invalid_future_access(
@ -659,13 +662,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
let mut ret = if func.is_async && func.variant == Standard {
if let Some(Type::Future(_)) = expected {
Type::Future(FutureType::new(Vec::new()))
}
else {
} else {
self.emit_err(TypeCheckerError::return_type_of_finalize_function_is_future(input.span));
Type::Unit
}
}
else {
} else {
self.assert_and_return_type(func.output_type, expected, input.span())
};
@ -686,7 +687,9 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
// Extract information about futures that are being consumed.
if func.is_async && func.variant == Standard && matches!(expected.type_(), Type::Future(_)) {
match argument {
Expression::Identifier(_) | Expression::Call(_) | Expression::Access(AccessExpression::Tuple(_)) => {
Expression::Identifier(_)
| Expression::Call(_)
| Expression::Access(AccessExpression::Tuple(_)) => {
match self.scope_state.call_location.clone() {
Some(location) => {
// Get the external program and function name.
@ -701,7 +704,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
));
}
}
},
}
_ => {
self.emit_err(TypeCheckerError::unknown_future_consumed(
"unknown",
@ -709,8 +712,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
));
}
}
}
else {
} else {
inferred_finalize_inputs.push(ty.unwrap());
}
});
@ -752,20 +754,20 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
let future_type = Type::Future(FutureType::new(
// Assumes that external function stubs have been processed.
self.finalize_input_types
.get(&Location::new(input.program.unwrap(), Symbol::intern(&format!("finalize/{}",ident.name))))
.get(&Location::new(
input.program.unwrap(),
Symbol::intern(&format!("finalize/{}", ident.name)),
))
.unwrap()
.clone(),
));
ret = match ret.clone() {
Tuple(tup) => {
Tuple(TupleType::new(tup.elements().iter().map(|t| {
if matches!(t, Future(_)) {
future_type.clone()
} else {
t.clone()
}
}).collect::<Vec<Type>>()))
}
Tuple(tup) => Tuple(TupleType::new(
tup.elements()
.iter()
.map(|t| if matches!(t, Future(_)) { future_type.clone() } else { t.clone() })
.collect::<Vec<Type>>(),
)),
Future(_) => future_type,
_ => {
self.emit_err(TypeCheckerError::async_transition_invalid_output(input.span));
@ -795,8 +797,10 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
)
.unwrap();
// Create expectation for finalize inputs that will be checked when checking corresponding finalize function signature.
self.finalize_input_types
.insert(Location::new(self.scope_state.program_name.unwrap(), ident.name), inferred_finalize_inputs.clone());
self.finalize_input_types.insert(
Location::new(self.scope_state.program_name.unwrap(), ident.name),
inferred_finalize_inputs.clone(),
);
// Set scope state flag.
self.scope_state.has_called_finalize = true;
@ -886,7 +890,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
Some(future) => {
self.scope_state.call_location = Some(future.clone());
return Some(var.type_.clone());
},
}
None => {
self.emit_err(TypeCheckerError::unknown_future_consumed(input.name, input.span));
}

View File

@ -18,11 +18,10 @@ use crate::{DiGraphError, TypeChecker};
use leo_ast::*;
use leo_errors::{TypeCheckerError, TypeCheckerWarning};
use leo_span::{sym, Symbol};
use leo_span::sym;
use snarkvm::console::network::{Network, Testnet3};
use leo_ast::{
Input::{External, Internal},
Type::Future,
@ -92,7 +91,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
if input.variant == Variant::Standard && input.is_async {
let finalize_input_map = &mut self.finalize_input_types;
let mut future_stubs = input.future_locations.clone();
let resolved_inputs:Vec<Type> = input
let resolved_inputs: Vec<Type> = input
.input
.iter()
.map(|input_mode| {

View File

@ -24,7 +24,6 @@ use leo_ast::{
};
use leo_errors::TypeCheckerError;
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
fn visit_statement(&mut self, input: &'a Statement) {
// No statements can follow a return statement.
@ -252,7 +251,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Insert the variables into the symbol table.
match &input.place {
Expression::Identifier(identifier) => self.insert_variable(inferred_type.clone(), identifier, input.type_.clone(), 0, identifier.span),
Expression::Identifier(identifier) => {
self.insert_variable(inferred_type.clone(), identifier, input.type_.clone(), 0, identifier.span)
}
Expression::Tuple(tuple_expression) => {
let tuple_type = match &input.type_ {
Type::Tuple(tuple_type) => tuple_type,
@ -289,8 +290,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Expression statements can only be function calls.
if !matches!(
input.expression,
Expression::Call(_) | Expression::Access(AccessExpression::AssociatedFunction(_)) | Expression::Access(AccessExpression::MethodCall(_)))
{
Expression::Call(_)
| Expression::Access(AccessExpression::AssociatedFunction(_))
| Expression::Access(AccessExpression::MethodCall(_))
) {
self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
} else {
// Check the expression.
@ -383,13 +386,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// We can safely unwrap all self.parent instances because
// statements should always have some parent block
let parent = self.scope_state.function.unwrap();
let func = self
.symbol_table
.borrow()
.lookup_fn_symbol(self.scope_state.program_name.unwrap(), parent)
.map(|f| f.clone());
let mut return_type = func.clone()
.map(|f| f.output_type.clone());
let func = self.symbol_table.borrow().lookup_fn_symbol(self.scope_state.program_name.unwrap(), parent).cloned();
let mut return_type = func.clone().map(|f| f.output_type.clone());
// Fully type the expected return value.
if self.scope_state.is_async_transition && self.scope_state.has_called_finalize {
@ -402,15 +400,13 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Need to modify return type since the function signature is just default future, but the actual return type is the fully inferred future of the finalize input type.
return_type = match return_type {
Some(Future(_)) => Some(inferred_future_type),
Some(Tuple(tuple)) => {
Some(Tuple(TupleType::new(tuple.elements().iter().map(|t| {
if matches!(t, Future(_)) {
inferred_future_type.clone()
} else {
t.clone()
}
}).collect::<Vec<Type>>())))
}
Some(Tuple(tuple)) => Some(Tuple(TupleType::new(
tuple
.elements()
.iter()
.map(|t| if matches!(t, Future(_)) { inferred_future_type.clone() } else { t.clone() })
.collect::<Vec<Type>>(),
))),
_ => {
return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
}

View File

@ -39,12 +39,14 @@ use leo_span::{Span, Symbol};
use snarkvm::console::network::{Network, Testnet3};
use crate::type_checking::{await_checker::AwaitChecker, scope_state::ScopeState};
use indexmap::{IndexMap};
use indexmap::IndexMap;
use itertools::Itertools;
use leo_ast::Type::{Future, Tuple};
use std::{cell::RefCell};
use leo_ast::Input::Internal;
use leo_ast::Mode::Public;
use leo_ast::{
Input::Internal,
Mode::Public,
Type::{Future, Tuple},
};
use std::cell::RefCell;
pub struct TypeChecker<'a> {
/// The symbol table for the program.
@ -1251,7 +1253,7 @@ impl<'a> TypeChecker<'a> {
if !function.output.is_empty() {
self.emit_err(TypeCheckerError::finalize_function_cannot_return_value(function.span()));
}
// Check that the input types are consistent with when the function is invoked.
if let Some(inferred_input_types) = self.finalize_input_types.get(&self.scope_state.location()) {
// Check same number of inputs as expected.
@ -1263,30 +1265,26 @@ impl<'a> TypeChecker<'a> {
));
}
// Check that the input parameters match the inferred types from when the async function is invoked.
function
.input
.iter()
.zip_eq(inferred_input_types.iter())
.for_each(|(t1, t2)| {
if let Internal(fn_input) = t1 {
// Allow partial type matching of futures since inferred are fully typed, whereas AST has default futures.
if !(matches!(t2, Type::Future(_)) && matches!(fn_input.type_, Type::Future(_))) {
self.check_eq_types(&Some(t1.type_()), &Some(t2.clone()), t1.span())
} else {
// Insert to symbol table
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
fn_input.identifier.name,
VariableSymbol {
type_: t2.clone(),
span: fn_input.identifier.span(),
declaration: VariableType::Input(Public),
},
) {
self.handler.emit_err(err);
}
function.input.iter().zip_eq(inferred_input_types.iter()).for_each(|(t1, t2)| {
if let Internal(fn_input) = t1 {
// Allow partial type matching of futures since inferred are fully typed, whereas AST has default futures.
if !(matches!(t2, Type::Future(_)) && matches!(fn_input.type_, Type::Future(_))) {
self.check_eq_types(&Some(t1.type_()), &Some(t2.clone()), t1.span())
} else {
// Insert to symbol table
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
fn_input.identifier.name,
VariableSymbol {
type_: t2.clone(),
span: fn_input.identifier.span(),
declaration: VariableType::Input(Public),
},
) {
self.handler.emit_err(err);
}
}
});
}
});
} else {
self.emit_warning(TypeCheckerWarning::async_function_is_never_called_by_transition_function(
function.identifier.name,
@ -1319,7 +1317,10 @@ impl<'a> TypeChecker<'a> {
}
// Check that the finalize input parameter is not constant or private.
if self.scope_state.is_finalize && (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private) && (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private) {
if self.scope_state.is_finalize
&& (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private)
&& (input_var.mode() == Mode::Constant || input_var.mode() == Mode::Private)
{
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
}
@ -1338,11 +1339,13 @@ impl<'a> TypeChecker<'a> {
// Add function inputs to the symbol table. Futures have already been added.
if !matches!(&input_var.type_(), &Type::Future(_)) {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
}) {
if let Err(err) =
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
type_: input_var.type_(),
span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()),
})
{
self.handler.emit_err(err);
}
}
@ -1390,7 +1393,8 @@ impl<'a> TypeChecker<'a> {
// Async transitions must return exactly one future, and it must be in the last position.
if self.scope_state.is_async_transition
&& ((index < function.output.len() - 1 && matches!(function_output.type_, Type::Future(_)))
|| (index == function.output.len() - 1 && !matches!(function_output.type_, Type::Future(_))))
|| (index == function.output.len() - 1
&& !matches!(function_output.type_, Type::Future(_))))
{
self.emit_err(TypeCheckerError::async_transition_invalid_output(function_output.span));
}

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use indexmap::IndexMap;
use leo_ast::{Identifier, Location, Variant};
use leo_ast::{Location, Variant};
use leo_span::Symbol;
pub struct ScopeState {

View File

@ -923,14 +923,14 @@ create_messages!(
msg: "An async transition must return a future.".to_string(),
help: Some("Call an async function inside of the async transition body so that there is a future to return.".to_string()),
}
@formatted
finalize_function_cannot_return_value {
args: (),
msg: "An async function is not allowed to return a value.".to_string(),
help: Some("Remove an output type in the function signature, and remove the return statement from the function.".to_string()),
}
@formatted
return_type_of_finalize_function_is_future {
args: (),

View File

@ -37,7 +37,7 @@ create_messages!(
msg: format!("Some paths through the function contain duplicate future awaits. {num_duplicate_await_paths}/{num_total_paths} paths contain at least one future that is awaited more than once."),
help: Some("Look at the times `.await()` is called, and try to reduce redundancies. Remove this warning by including the `--disable-conditional-branch-type-checking` flag.".to_string()),
}
@formatted
async_function_is_never_called_by_transition_function {
args: (name: impl Display),

View File

@ -89,7 +89,11 @@ fn new_compiler(handler: &Handler) -> Compiler<'_> {
PathBuf::from(String::new()),
PathBuf::from(String::new()),
Some(CompilerOptions {
build: BuildOptions { dce_enabled: true, conditional_block_max_depth: 10, disable_conditional_branch_type_checking: false },
build: BuildOptions {
dce_enabled: true,
conditional_block_max_depth: 10,
disable_conditional_branch_type_checking: false,
},
output: OutputOptions {
symbol_table_spans_enabled: false,
initial_symbol_table: false,