Retrieve external future locations during disassembling instead of in TYC

This commit is contained in:
evan-schott 2024-04-08 11:15:48 -07:00
parent e99d7df699
commit 0ed5cd6924
9 changed files with 25 additions and 71 deletions

View File

@ -58,8 +58,6 @@ pub struct FunctionStub {
pub variant: Variant,
/// The function identifier, e.g., `foo` in `function foo(...) { ... }`.
pub identifier: Identifier,
/// Ordered list of futures inputted to finalize.
pub future_locations: Vec<Location>,
/// The function's input parameters.
pub input: Vec<Input>,
/// The function's output declarations.
@ -109,7 +107,6 @@ impl FunctionStub {
annotations,
variant,
identifier,
future_locations: Vec::new(),
input,
output,
output_type,
@ -192,7 +189,7 @@ impl FunctionStub {
}),
ValueType::Future(_) => Output::Internal(FunctionOutput {
mode: Mode::Public,
type_: Type::Future(FutureType::new(Vec::new())),
type_: Type::Future(FutureType::new(Vec::new(), Some(Location::new(Some(program), Identifier::from(function.name()).name)))),
span: Default::default(),
id: Default::default(),
}),
@ -220,7 +217,6 @@ impl FunctionStub {
false => Variant::Transition,
},
identifier: Identifier::from(function.name()),
future_locations: Vec::new(),
input: function
.inputs()
.iter()
@ -276,25 +272,13 @@ impl FunctionStub {
pub fn from_finalize<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>>(
function: &FunctionCore<N, Instruction, Command>,
name: Symbol,
key_name: Symbol,
program: Symbol,
) -> Self {
Self {
annotations: Vec::new(),
variant: Variant::AsyncFunction,
identifier: Identifier::new(name, Default::default()),
future_locations: function
.finalize_logic()
.unwrap()
.inputs()
.iter()
.filter_map(|input| match input.finalize_type() {
FinalizeType::Future(val) => Some(Location::new(
Some(Identifier::from(val.program_id().name()).name),
Symbol::intern(&format!("finalize/{}", val.resource())),
)),
_ => None,
})
.collect(),
identifier: Identifier::new(key_name, Default::default()),
input: function
.finalize_logic()
.unwrap()
@ -306,21 +290,19 @@ impl FunctionStub {
identifier: Identifier::new(Symbol::intern(&format!("arg{}", index + 1)), Default::default()),
mode: Mode::None,
type_: match input.finalize_type() {
PlaintextFinalizeType(val) => Type::from_snarkvm(val, name),
FutureFinalizeType(_) => Type::Future(Default::default()),
PlaintextFinalizeType(val) => Type::from_snarkvm(val, key_name),
FutureFinalizeType(val) => Type::Future(FutureType::new(Vec::new(), Some(Location::new(
Some(Identifier::from(val.program_id().name()).name),
Symbol::intern(&format!("finalize/{}", val.resource()))),
))),
},
span: Default::default(),
id: Default::default(),
})
})
.collect_vec(),
output: vec![Output::Internal(FunctionOutput {
mode: Mode::None,
type_: Type::Future(FutureType { inputs: Vec::new() }),
span: Default::default(),
id: 0,
})],
output_type: Type::Future(FutureType { inputs: Vec::new() }),
output: Vec::new(),
output_type: Type::Unit,
span: Default::default(),
id: 0,
}
@ -361,7 +343,6 @@ impl FunctionStub {
annotations: Vec::new(),
variant: Variant::Function,
identifier: Identifier::from(closure.name()),
future_locations: Vec::new(),
input: closure
.inputs()
.iter()
@ -396,7 +377,6 @@ impl From<Function> for FunctionStub {
annotations: function.annotations,
variant: function.variant,
identifier: function.identifier,
future_locations: Vec::new(),
input: function.input,
output: function.output,
output_type: function.output_type,

View File

@ -86,7 +86,7 @@ impl<'a> CodeGenerator<'a> {
.map(|(_, function)| {
if function.variant != Variant::AsyncFunction {
// Set the `is_transition_function` flag.
self.is_transition_function = matches!(function.variant, Variant::Transition);
self.is_transition_function = function.variant.is_transition();
let mut function_string = self.visit_function(function);

View File

@ -16,31 +16,7 @@
use crate::StaticSingleAssigner;
use leo_ast::{
AccessExpression,
ArrayAccess,
ArrayExpression,
AssociatedFunction,
BinaryExpression,
CallExpression,
CastExpression,
Composite,
Expression,
ExpressionConsumer,
Identifier,
Literal,
Location,
LocatorExpression,
MemberAccess,
Statement,
StructExpression,
StructVariableInitializer,
TernaryExpression,
TupleAccess,
TupleExpression,
UnaryExpression,
UnitExpression,
};
use leo_ast::{AccessExpression, ArrayAccess, ArrayExpression, AssociatedFunction, BinaryExpression, CallExpression, CastExpression, Composite, Expression, ExpressionConsumer, Identifier, Literal, Location, LocatorExpression, MemberAccess, MethodCall, Statement, StructExpression, StructVariableInitializer, TernaryExpression, TupleAccess, TupleExpression, UnaryExpression, UnitExpression};
use leo_span::{sym, Symbol};
use indexmap::IndexMap;

View File

@ -751,6 +751,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
))
.unwrap()
.clone(),
Some(Location::new(input.program, ident.name))
));
ret = match ret.clone() {
Tuple(tup) => Tuple(TupleType::new(
@ -797,7 +798,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
self.scope_state.has_called_finalize = true;
// Update ret to reflect fully inferred future type.
ret = Type::Future(FutureType::new(inferred_finalize_inputs));
ret = Type::Future(FutureType::new(inferred_finalize_inputs, Some(Location::new(input.program, ident.name))));
}
// Set call location so that definition statement knows where future comes from.
self.scope_state.call_location = Some(Location::new(input.program, ident.name));

View File

@ -91,18 +91,16 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Create future stubs.
if input.variant == Variant::AsyncFunction {
let finalize_input_map = &mut self.finalize_input_types;
let mut future_stubs = input.future_locations.clone();
let resolved_inputs: Vec<Type> = input
.input
.iter()
.map(|input_mode| {
match input_mode {
Internal(function_input) => match &function_input.type_ {
Future(_) => {
Future(f) => {
// Since we traverse stubs in post-order, we can assume that the corresponding finalize stub has already been traversed.
Future(FutureType::new(
finalize_input_map.get(&future_stubs.remove(0)).unwrap().clone(),
))
finalize_input_map.get(&f.location.clone().unwrap()).unwrap().clone(), f.location.clone()))
}
_ => function_input.clone().type_,
},
@ -110,7 +108,6 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
}
})
.collect();
assert!(future_stubs.is_empty(), "Disassembler produced malformed stub.");
finalize_input_map
.insert(Location::new(self.scope_state.program_name, input.identifier.name), resolved_inputs);
@ -164,7 +161,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
let mut transition_count = 0;
for (_, function) in input.functions.iter() {
self.visit_function(function);
if matches!(function.variant, Variant::Transition) {
if function.variant.is_transition() {
transition_count += 1;
}
}

View File

@ -398,7 +398,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Fully type the expected return value.
if self.scope_state.variant == Some(Variant::AsyncTransition) && self.scope_state.has_called_finalize {
let inferred_future_type = match self.finalize_input_types.get(&func.unwrap().finalize.clone().unwrap()) {
Some(types) => Future(FutureType::new(types.clone())),
Some(types) => Future(FutureType::new(types.clone(), Some(Location::new(self.scope_state.program_name, parent)))),
None => {
return self.emit_err(TypeCheckerError::async_transition_missing_future_to_return(input.span()));
}

View File

@ -1323,7 +1323,7 @@ impl<'a> TypeChecker<'a> {
// Check that the input parameter is not a record.
else if let Type::Composite(struct_) = input_var.type_() {
// Note that this unwrap is safe, as the type is defined.
if !matches!(function.variant, Variant::Transition)
if !function.variant.is_transition()
&& self
.symbol_table
.borrow()
@ -1378,7 +1378,7 @@ impl<'a> TypeChecker<'a> {
Output::External(external) => {
// If the function is not a transition function, then it cannot output a record.
// Note that an external output must always be a record.
if !matches!(function.variant, Variant::Transition) {
if !function.variant.is_transition() {
self.emit_err(TypeCheckerError::function_cannot_input_or_output_a_record(external.span()));
}
}
@ -1387,7 +1387,7 @@ impl<'a> TypeChecker<'a> {
if self.assert_type_is_valid(&function_output.type_, function_output.span) {
// If the function is not a transition function, then it cannot output a record.
if let Type::Composite(struct_) = function_output.type_.clone() {
if !matches!(function.variant, Variant::Transition)
if !function.variant.is_transition()
&& self
.symbol_table
.borrow()

View File

@ -52,7 +52,7 @@ impl ScopeState {
has_return: false,
is_return: false,
program_name: None,
is_stub: false,
is_stub: true,
futures: IndexMap::new(),
has_called_finalize: false,
is_conditional: false,

View File

@ -71,11 +71,11 @@ pub fn disassemble<N: Network, Instruction: InstructionTrait<N>, Command: Comman
.iter()
.filter_map(|(id, function)| match function.finalize_logic() {
Some(_f) => {
let name = Symbol::intern(&format!(
let key_name = Symbol::intern(&format!(
"finalize/{}",
Symbol::intern(&Identifier::from(id).name.to_string())
));
Some((name, FunctionStub::from_finalize(function, name)))
Some((key_name, FunctionStub::from_finalize(function, key_name, program_id.name.name)))
}
None => None,
})