fn inline_indirectly_called_function()

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();
        }
    }