use crate::hir::{HirCallExpr, HirExpr, HirStmt, LocalId};
use super::super::{AstLowerError, AstLowerer};
use crate::ast::common::{AstCallKind, AstCallStmt, AstExpr, AstStmt};
impl<'a> AstLowerer<'a> {
pub(in crate::ast::build) fn try_lower_forwarded_multiret_call_stmt(
&mut self,
proto_index: usize,
stmts: &[HirStmt],
index: usize,
) -> Result<Option<(AstStmt, usize)>, AstLowerError> {
let Some(HirStmt::LocalDecl(local_decl)) = stmts.get(index) else {
return Ok(None);
};
let [binding] = local_decl.bindings.as_slice() else {
return Ok(None);
};
let [HirExpr::Call(source_call)] = local_decl.values.as_slice() else {
return Ok(None);
};
if !source_call.multiret {
return Ok(None);
}
let Some(HirStmt::CallStmt(call_stmt)) = stmts.get(index + 1) else {
return Ok(None);
};
if super::super::analysis::count_local_uses_in_stmts(&stmts[(index + 1)..], *binding) != 1
|| !call_stmt_uses_local_as_final_arg_only(&call_stmt.call, *binding)
{
return Ok(None);
}
let mut forwarded_call = call_stmt.call.clone();
let Some(last_arg) = forwarded_call.args.last_mut() else {
return Ok(None);
};
*last_arg = HirExpr::Call(Box::new((**source_call).clone()));
Ok(Some((
AstStmt::CallStmt(Box::new(AstCallStmt {
call: self.lower_call(proto_index, &forwarded_call)?,
})),
2,
)))
}
pub(in crate::ast::build) fn try_lower_single_value_final_call_arg_stmt(
&mut self,
proto_index: usize,
stmts: &[HirStmt],
index: usize,
) -> Result<Option<(AstStmt, usize)>, AstLowerError> {
let Some(HirStmt::CallStmt(call_stmt)) = stmts.get(index) else {
return Ok(None);
};
let Some(HirExpr::Call(arg_call)) = call_stmt.call.args.last() else {
return Ok(None);
};
if arg_call.multiret {
return Ok(None);
}
let mut lowered_call = self.lower_call(proto_index, &call_stmt.call)?;
let lowered_last_arg = AstExpr::SingleValue(Box::new(
self.lower_expr(
proto_index,
call_stmt
.call
.args
.last()
.expect("checked above, final arg must exist"),
)?,
));
match &mut lowered_call {
AstCallKind::Call(call) => {
let last_arg = call
.args
.last_mut()
.expect("final arg must still exist after lower_call");
*last_arg = lowered_last_arg;
}
AstCallKind::MethodCall(call) => {
let last_arg = call
.args
.last_mut()
.expect("final arg must still exist after lower_call");
*last_arg = lowered_last_arg;
}
}
Ok(Some((
AstStmt::CallStmt(Box::new(AstCallStmt { call: lowered_call })),
1,
)))
}
}
fn call_stmt_uses_local_as_final_arg_only(call: &HirCallExpr, local: LocalId) -> bool {
matches!(
call.args.last(),
Some(HirExpr::LocalRef(last_local)) if *last_local == local
) && super::super::analysis::count_local_uses_in_call(call, local) == 1
}