fn copy_field_bits()

in checker/src/body_visitor.rs [1948:2086]


    fn copy_field_bits(
        &mut self,
        source_fields: Vec<(Rc<Path>, Ty<'tcx>)>,
        target_fields: Vec<(Rc<Path>, Ty<'tcx>)>,
    ) {
        let source_len = source_fields.len();
        let mut source_field_index = 0;
        let mut copied_source_bits = 0;
        for (target_path, target_type) in target_fields.into_iter() {
            let target_type = self.type_visitor().specialize_generic_argument_type(
                target_type,
                &self.type_visitor().generic_argument_map,
            );
            if source_field_index >= source_len {
                let warning = self.cv.session.struct_span_warn(
                    self.current_span,
                    "The union is not fully initialized by this assignment",
                );
                self.emit_diagnostic(warning);
                break;
            }
            let (source_path, source_type) = &source_fields[source_field_index];
            let source_type = self.type_visitor().specialize_generic_argument_type(
                *source_type,
                &self.type_visitor().generic_argument_map,
            );
            let source_path = source_path.canonicalize(&self.current_environment);
            if let PathEnum::QualifiedPath {
                qualifier,
                selector,
                ..
            } = &source_path.value
            {
                if **selector == PathSelector::Field(0) {
                    if let PathEnum::Computed { value } = &qualifier.value {
                        if let Expression::CompileTimeConstant(ConstantDomain::Str(s)) =
                            &value.expression
                        {
                            // The value is a string literal. See if the target might treat it as &[u8].
                            if let TyKind::RawPtr(TypeAndMut { ty, .. }) = target_type.kind() {
                                if let TyKind::Uint(UintTy::U8) = ty.kind() {
                                    let thin_ptr_deref = Path::new_deref(
                                        source_path.clone(),
                                        ExpressionType::NonPrimitive,
                                    )
                                    .canonicalize(&self.current_environment);
                                    for (i, ch) in s.as_bytes().iter().enumerate() {
                                        let index = Rc::new((i as u128).into());
                                        let ch_const: Rc<AbstractValue> =
                                            Rc::new((*ch as u128).into());
                                        let path = Path::new_index(thin_ptr_deref.clone(), index);
                                        self.current_environment
                                            .strong_update_value_at(path, ch_const);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            let mut val = self.lookup_path_and_refine_result(source_path.clone(), source_type);
            if copied_source_bits > 0 {
                // discard the lower order bits from val since they have already been copied to a previous target field
                val = val.unsigned_shift_right(copied_source_bits);
            }
            let source_expression_type = ExpressionType::from(source_type.kind());
            let source_bits = ExpressionType::from(source_type.kind()).bit_length();
            let target_expression_type = ExpressionType::from(target_type.kind());
            let mut target_bits_to_write = target_expression_type.bit_length();
            if source_bits == target_bits_to_write
                && copied_source_bits == 0
                && target_expression_type == val.expression.infer_type()
            {
                self.current_environment
                    .strong_update_value_at(target_path, val);
                source_field_index += 1;
            } else if source_bits - copied_source_bits >= target_bits_to_write {
                // target field can be completely assigned from bits of source field value
                if source_bits - copied_source_bits > target_bits_to_write {
                    // discard higher order bits since they wont fit into the target field
                    val = val.unsigned_modulo(target_bits_to_write);
                }
                if source_expression_type != target_expression_type {
                    val = val.transmute(target_expression_type);
                }
                self.current_environment
                    .strong_update_value_at(target_path, val);
                copied_source_bits += target_bits_to_write;
                if copied_source_bits == source_bits {
                    source_field_index += 1;
                    copied_source_bits = 0;
                }
            } else {
                // target field needs bits from multiple source fields
                let mut written_target_bits = source_bits - copied_source_bits;
                target_bits_to_write -= written_target_bits;
                val = val.unsigned_modulo(written_target_bits);
                loop {
                    // Get another field
                    source_field_index += 1;
                    if source_field_index >= source_len {
                        let warning = self.cv.session.struct_span_warn(
                            self.current_span,
                            "The union is not fully initialized by this assignment",
                        );
                        self.emit_diagnostic(warning);
                        break;
                    }
                    let (source_path, source_type) = &source_fields[source_field_index];
                    let source_path = source_path.canonicalize(&self.current_environment);
                    let source_bits = ExpressionType::from(source_type.kind()).bit_length();
                    let mut next_val =
                        self.lookup_path_and_refine_result(source_path.clone(), *source_type);
                    // discard higher order bits that wont fit into the target field
                    next_val = next_val.unsigned_modulo(target_bits_to_write);
                    // shift next value to the left, making space for val in the lower order bits
                    next_val = next_val.unsigned_shift_left(written_target_bits);
                    // update val to include next_val (in its higher order bits, thanks to the shift left above)
                    val = next_val.addition(val);
                    if source_bits >= target_bits_to_write {
                        // We are done with this target field
                        self.current_environment.strong_update_value_at(
                            target_path.clone(),
                            val.transmute(target_expression_type),
                        );
                        if source_bits == target_bits_to_write {
                            copied_source_bits = 0;
                            source_field_index += 1;
                        } else {
                            copied_source_bits = target_bits_to_write;
                        }
                        break;
                    }
                    target_bits_to_write -= source_bits;
                    written_target_bits += source_bits;
                }
            }
        }
    }