in checker/src/call_visitor.rs [1167:1321]
fn inline_indirectly_called_function(&mut self) {
checked_assume!(self.actual_args.len() == 2);
trace!("self.actual_args {:?}", self.actual_args);
trace!(
"self.actual_argument_types {:?}",
self.actual_argument_types
);
trace!(
"self.function_constant_args {:?}",
self.function_constant_args
);
// Get the function to call (it is either a function pointer or a closure)
let callee = self.actual_args[0].1.clone();
let callee_func_ref = self.block_visitor.get_func_ref(&callee);
// Get the path of the tuple containing the arguments.
let callee_arg_array_path = self.actual_args[1].0.clone();
if let Some(func_ref) = &callee_func_ref {
let def_id = func_ref.def_id.expect("defined when used here");
let func_const = ConstantDomain::Function(func_ref.clone());
// Unpack the type of the second argument, which should be a tuple.
checked_assume!(self.actual_argument_types.len() == 2);
let mut actual_argument_types: Vec<Ty<'tcx>> =
if let TyKind::Tuple(tuple_types) = self.actual_argument_types[1].kind() {
tuple_types.iter().collect()
} else {
assume_unreachable!("expected second type argument to be a tuple type");
};
// Unpack the second argument, which should be a tuple
let mut actual_args: Vec<(Rc<Path>, Rc<AbstractValue>)> = actual_argument_types
.iter()
.enumerate()
.map(|(i, t)| {
let arg_path = Path::new_field(callee_arg_array_path.clone(), i);
let arg_val = self
.block_visitor
.bv
.lookup_path_and_refine_result(arg_path.clone(), *t);
(arg_path, arg_val)
})
.collect();
// Prepend the callee closure/generator/function to the unpacked arguments vector
// if the called function actually expects it.
let tcx = self.block_visitor.bv.tcx;
let callee_ty = self.actual_argument_types[0];
if !callee_ty.is_fn() || tcx.is_closure(def_id) {
actual_args.insert(0, self.actual_args[0].clone());
actual_argument_types.insert(0, callee_ty);
if self.callee_known_name == KnownNames::StdOpsFunctionFnOnceCallOnce
&& self.block_visitor.bv.tcx.is_mir_available(def_id)
{
// call_once consumes it's callee argument. If the callee does not,
// we have to provide it with a reference.
// Sadly, the easiest way to get hold of the type of the first parameter
// of the callee is to look at its MIR body. If there is no body, we wont
// be executing it and the type of the first argument is immaterial, so this
// does not cause problems.
let mir = tcx.optimized_mir(def_id);
if let Some(decl) = mir.local_decls.get(mir::Local::from(1usize)) {
if decl.ty.is_ref() {
let closure_path = self.actual_args[0].0.clone();
let closure_reference = AbstractValue::make_reference(closure_path);
actual_args[0] = (
Path::get_as_path(closure_reference.clone()),
closure_reference,
);
// decl.ty is not type specialized
actual_argument_types[0] =
tcx.mk_mut_ref(tcx.lifetimes.re_static, callee_ty);
}
}
}
}
let function_constant_args = self
.block_visitor
.get_function_constant_args(&actual_args, &actual_argument_types);
// Get the generic argument map for the indirectly called function
let generic_arguments = match callee_ty.kind() {
TyKind::Closure(_, substs) => Some(self.type_visitor().specialize_substs(
substs.as_closure().substs,
&self.type_visitor().generic_argument_map,
)),
TyKind::Generator(_, substs, _) => Some(self.type_visitor().specialize_substs(
substs.as_generator().substs,
&self.type_visitor().generic_argument_map,
)),
TyKind::FnDef(_, substs) | TyKind::Opaque(_, substs) => Some(
self.type_visitor()
.specialize_substs(substs, &self.type_visitor().generic_argument_map),
),
_ => self.block_visitor.bv.cv.substs_cache.get(&def_id).cloned(),
};
let argument_map = if let Some(substs) = generic_arguments {
self.type_visitor().get_generic_arguments_map(
def_id,
substs,
&actual_argument_types,
)
} else {
None
};
// Set up a call visitor
let environment_before_call = self.block_visitor.bv.current_environment.clone();
let mut block_visitor = BlockVisitor::new(self.block_visitor.bv);
let mut indirect_call_visitor = CallVisitor::new(
&mut block_visitor,
def_id,
generic_arguments,
argument_map,
environment_before_call,
func_const,
);
indirect_call_visitor.actual_args = actual_args;
indirect_call_visitor.actual_argument_types = actual_argument_types;
indirect_call_visitor.function_constant_args = &function_constant_args;
indirect_call_visitor.callee_fun_val = callee.clone();
indirect_call_visitor.callee_known_name = KnownNames::None;
indirect_call_visitor.destination = self.destination;
let summary = indirect_call_visitor.get_function_summary();
if let Some(summary) = summary {
if summary.is_computed {
indirect_call_visitor.transfer_and_refine_into_current_environment(&summary);
}
if summary.is_incomplete
&& self
.block_visitor
.bv
.already_reported_errors_for_call_to
.insert(callee)
{
let saved_callee_def_id = self.callee_def_id;
self.callee_def_id = def_id;
self.report_incomplete_summary();
self.callee_def_id = saved_callee_def_id;
}
return;
}
}
if self
.block_visitor
.bv
.already_reported_errors_for_call_to
.insert(callee.clone())
{
debug!("unknown callee {:?}", callee);
self.block_visitor.report_missing_summary();
}
}