fn promote_reference()

in checker/src/body_visitor.rs [908:1057]


    fn promote_reference(
        &mut self,
        environment: &mut Environment,
        result_rustc_type: Ty<'tcx>,
        promoted_root: &Rc<Path>,
        local_path: &Rc<Path>,
    ) {
        let target_type = self.type_visitor().get_dereferenced_type(result_rustc_type);
        if target_type.is_unit() {
            return;
        }
        if ExpressionType::from(target_type.kind()).is_primitive() {
            // Kind of weird, but seems to be generated for debugging support.
            // Move the value into a path, so that we can drop the reference to the soon to be dead local.
            let target_value = self
                .exit_environment
                .as_ref()
                .unwrap()
                .value_map
                .get(local_path)
                .unwrap_or_else(|| {
                    panic!(
                        "expect reference target to have a value {:?} in env {:?}",
                        local_path, self.exit_environment
                    )
                });
            let value_path = Path::get_as_path(target_value.clone());
            let promoted_value = AbstractValue::make_from(Expression::Reference(value_path), 1);
            environment.strong_update_value_at(promoted_root.clone(), promoted_value);
        } else if let TyKind::Ref(_, t, _) = target_type.kind() {
            // Promoting a reference to a reference.
            let eight: Rc<AbstractValue> = self.get_u128_const_val(8);
            let (_, heap_root) = self.get_new_heap_block(eight.clone(), eight, false, target_type);
            let layout_path = Path::new_layout(heap_root.clone());
            let layout_value = self
                .current_environment
                .value_at(&layout_path)
                .expect("new heap block should have a layout");
            environment.strong_update_value_at(layout_path, layout_value.clone());
            let exit_env_map = self.exit_environment.as_ref().unwrap().value_map.clone();
            if !exit_env_map.contains_key(local_path) {
                self.promote_reference(
                    environment,
                    *t,
                    &Path::new_field(heap_root.clone(), 0),
                    &Path::new_field(local_path.clone(), 0),
                );
                self.promote_reference(
                    environment,
                    self.tcx.types.usize,
                    &Path::new_length(heap_root),
                    &Path::new_length(local_path.clone()),
                );
            } else {
                let target_value = exit_env_map
                    .get(local_path)
                    .expect("expect reference target to have a value");
                environment.strong_update_value_at(heap_root.clone(), target_value.clone());
                if let Expression::Reference(path) = &target_value.expression {
                    match &path.value {
                        PathEnum::LocalVariable { .. } => {
                            self.promote_reference(environment, target_type, &heap_root, path)
                        }
                        PathEnum::Computed { value } => {
                            environment.strong_update_value_at(path.clone(), value.clone());
                            if target_type.is_slice() {
                                let len_path = Path::new_length(path.clone());
                                if let Some(len_val) = exit_env_map.get(&len_path) {
                                    environment.strong_update_value_at(len_path, len_val.clone());
                                }
                            }
                        }
                        _ => {}
                    }
                }
                let promoted_value = AbstractValue::make_from(Expression::Reference(heap_root), 1);
                environment.strong_update_value_at(promoted_root.clone(), promoted_value);
            }
        } else if let TyKind::Str = target_type.kind() {
            // Promoting a string constant
            let exit_env_map = &self.exit_environment.as_ref().unwrap().value_map;
            let target_value = exit_env_map
                .get(local_path)
                .expect("expect reference target to have a value");
            environment.strong_update_value_at(promoted_root.clone(), target_value.clone());
            if let Expression::Reference(str_path) = &target_value.expression {
                if let PathEnum::Computed { value } = &str_path.value {
                    environment.strong_update_value_at(str_path.clone(), value.clone());
                    let len_path = Path::new_length(str_path.clone());
                    if let Some(len_val) = exit_env_map.get(&len_path) {
                        environment.strong_update_value_at(len_path, len_val.clone());
                    }
                }
            }
        } else {
            // A composite value needs to get to get promoted to the heap
            // in order to propagate it via function summaries.
            let byte_size = self.type_visitor().get_type_size(target_type);
            let byte_size_value = self.get_u128_const_val(byte_size as u128);
            let elem_size = self
                .type_visitor()
                .get_type_size(self.type_visitor().get_element_type(target_type));
            let alignment: Rc<AbstractValue> = Rc::new(
                (match elem_size {
                    0 => 1,
                    1 | 2 | 4 | 8 => elem_size,
                    _ => 8,
                } as u128)
                    .into(),
            );
            let (_, heap_root) =
                self.get_new_heap_block(byte_size_value, alignment, false, target_type);
            let layout_path = Path::new_layout(heap_root.clone());
            let layout_value = self
                .current_environment
                .value_at(&layout_path)
                .expect("new heap block should have a layout");
            environment.strong_update_value_at(layout_path, layout_value.clone());
            for (path, value) in self
                .exit_environment
                .as_ref()
                .unwrap()
                .value_map
                .iter()
                .filter(|(p, _)| (*p) == local_path || p.is_rooted_by(local_path))
            {
                let renamed_path = path.replace_root(local_path, heap_root.clone());
                environment.strong_update_value_at(renamed_path, value.clone());
            }

            let thin_pointer_to_heap = AbstractValue::make_reference(heap_root);
            if self.type_visitor().is_slice_pointer(target_type.kind()) {
                let promoted_thin_pointer_path = Path::new_field(promoted_root.clone(), 0);
                environment
                    .strong_update_value_at(promoted_thin_pointer_path, thin_pointer_to_heap);
                let length_value = self
                    .exit_environment
                    .as_ref()
                    .unwrap()
                    .value_map
                    .get(&Path::new_length(local_path.clone()))
                    .unwrap_or_else(|| assume_unreachable!("promoted constant slice source is expected to have a length value, see source at {:?}", self.current_span))
                    .clone();
                let length_path = Path::new_length(promoted_root.clone());
                environment.strong_update_value_at(length_path, length_value);
            } else {
                environment.strong_update_value_at(promoted_root.clone(), thin_pointer_to_heap);
            }
        }
    }