fn try_to_devirtualize()

in checker/src/call_visitor.rs [185:288]


    fn try_to_devirtualize(&mut self) {
        let tcx = self.block_visitor.bv.tcx;
        if self
            .block_visitor
            .bv
            .tcx
            .is_mir_available(self.callee_def_id)
            && !utils::is_trait_method(self.callee_def_id, tcx)
        {
            return;
        }
        if let Some(gen_args) = self.callee_generic_arguments {
            // The parameter environment of the caller provides a resolution context for the callee.
            let param_env = rustc_middle::ty::ParamEnv::reveal_all();
            trace!(
                "devirtualize resolving def_id {:?}: {:?}",
                self.callee_def_id,
                tcx.type_of(self.callee_def_id)
            );
            trace!("devirtualize resolving func_ref {:?}", self.callee_func_ref,);
            trace!("gen_args {:?}", gen_args);
            if let Some(arg0_ty) = gen_args.types().next() {
                if matches!(arg0_ty.kind(), TyKind::Dynamic(..)) {
                    // Instance::resolve panics if it can't find a vtable entry for the given def_id
                    // It is hard to figure out exactly when this will be the case, but it does
                    // happen in a case where the first generic argument type is Dynamic.
                    return;
                }
            }
            let abi = tcx.type_of(self.callee_def_id).fn_sig(tcx).abi();
            let resolved_instance = if abi == rustc_target::spec::abi::Abi::Rust {
                Some(rustc_middle::ty::Instance::resolve(
                    tcx,
                    param_env,
                    self.callee_def_id,
                    gen_args,
                ))
            } else {
                None
            };
            if let Some(Ok(Some(instance))) = resolved_instance {
                let resolved_def_id = instance.def.def_id();
                let tcx = tcx;
                let has_mir = tcx.is_mir_available(resolved_def_id);
                if !has_mir && self.callee_known_name == KnownNames::StdCloneClone {
                    return;
                }
                self.callee_def_id = resolved_def_id;
                let resolved_ty = tcx.type_of(resolved_def_id);
                let resolved_map = self.type_visitor().get_generic_arguments_map(
                    resolved_def_id,
                    instance.substs,
                    &[],
                );
                let specialized_resolved_ty = self
                    .type_visitor()
                    .specialize_generic_argument_type(resolved_ty, &resolved_map);
                trace!(
                    "devirtualize resolved def_id {:?}: {:?}",
                    resolved_def_id,
                    specialized_resolved_ty
                );
                let func_const = self
                    .block_visitor
                    .visit_function_reference(
                        resolved_def_id,
                        specialized_resolved_ty,
                        Some(instance.substs),
                    )
                    .clone();
                self.callee_func_ref = if let ConstantDomain::Function(fr) = &func_const {
                    self.callee_known_name = fr.known_name;
                    Some(fr.clone())
                } else {
                    None
                };
                self.callee_fun_val = Rc::new(func_const.into());
                self.callee_generic_arguments = Some(instance.substs);
                self.callee_generic_argument_map = self.type_visitor().get_generic_arguments_map(
                    resolved_def_id,
                    instance.substs,
                    &self.actual_argument_types,
                );
                if has_mir && specialized_resolved_ty.is_closure() {
                    let mir = tcx.optimized_mir(resolved_def_id);
                    if self.actual_argument_types.len() + 1 == mir.arg_count {
                        // When the closure has no captured variables, the first argument is just the function pointer.
                        // Sadly, MIR omits this argument (because the call is via a trait), so we have to add it here.
                        self.actual_args
                            .insert(0, (Path::new_parameter(1), self.callee_fun_val.clone()));
                        self.actual_argument_types.insert(
                            0,
                            tcx.mk_mut_ref(tcx.lifetimes.re_static, specialized_resolved_ty),
                        );
                    }
                }
            } else {
                debug!(
                    "could not resolve function {:?}, {:?}, {:?}",
                    self.callee_def_id, param_env, gen_args,
                )
            }
        }
    }