use super::DestructuringVisitor;
use leo_ast::{
ArrayAccess,
Expression,
ExpressionReconstructor,
Identifier,
IntegerType,
Literal,
Node as _,
Statement,
TernaryExpression,
TupleAccess,
TupleExpression,
Type,
};
use itertools::izip;
impl ExpressionReconstructor for DestructuringVisitor<'_> {
type AdditionalOutput = Vec<Statement>;
fn reconstruct_tuple_access(&mut self, input: TupleAccess) -> (Expression, Self::AdditionalOutput) {
let Expression::Identifier(identifier) = &input.tuple else {
panic!("SSA guarantees that subexpressions are identifiers or literals.");
};
match self.tuples.get(&identifier.name).and_then(|tuple_names| tuple_names.get(input.index.value())) {
Some(id) => ((*id).into(), Default::default()),
None => {
if !matches!(self.state.type_table.get(&identifier.id), Some(Type::Future(_))) {
panic!("Type checking guarantees that all tuple accesses are declared and indices are valid.");
}
let expr = ArrayAccess {
array: (*identifier).into(),
index: Literal::integer(IntegerType::U32, input.index.to_string(), input.span, Default::default())
.into(),
span: input.span,
id: input.id,
}
.into();
(expr, Default::default())
}
}
}
fn reconstruct_ternary(&mut self, mut input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
let (if_true, mut statements) = self.reconstruct_expression_tuple(std::mem::take(&mut input.if_true));
let (if_false, statements2) = self.reconstruct_expression_tuple(std::mem::take(&mut input.if_false));
statements.extend(statements2);
match (if_true, if_false) {
(Expression::Tuple(tuple_true), Expression::Tuple(tuple_false)) => {
let Some(Type::Tuple(tuple_type)) = self.state.type_table.get(&tuple_true.id()) else {
panic!("Should have tuple type");
};
let cond = if let Expression::Identifier(..) = input.condition {
input.condition
} else {
let place = Identifier::new(
self.state.assigner.unique_symbol("cond", "$$"),
self.state.node_builder.next_id(),
);
let definition = self.state.assigner.simple_definition(
place,
input.condition,
self.state.node_builder.next_id(),
);
statements.push(definition);
self.state.type_table.insert(place.id(), Type::Boolean);
Expression::Identifier(place)
};
let mut elements = Vec::with_capacity(tuple_true.elements.len());
for (i, (lhs, rhs, ty)) in
izip!(tuple_true.elements, tuple_false.elements, tuple_type.elements()).enumerate()
{
let identifier = Identifier::new(
self.state.assigner.unique_symbol(format_args!("ternary_{i}"), "$$"),
self.state.node_builder.next_id(),
);
let expression: Expression = TernaryExpression {
condition: cond.clone(),
if_true: lhs,
if_false: rhs,
span: Default::default(),
id: self.state.node_builder.next_id(),
}
.into();
self.state.type_table.insert(identifier.id(), ty.clone());
self.state.type_table.insert(expression.id(), ty.clone());
let definition = self.state.assigner.simple_definition(
identifier,
expression,
self.state.node_builder.next_id(),
);
statements.push(definition);
elements.push(identifier.into());
}
let expr: Expression =
TupleExpression { elements, span: Default::default(), id: self.state.node_builder.next_id() }
.into();
self.state.type_table.insert(expr.id(), Type::Tuple(tuple_type.clone()));
(expr, statements)
}
(if_true, if_false) => {
(TernaryExpression { if_true, if_false, ..input }.into(), statements)
}
}
}
}