Repository: rust-lang/rust
File: compiler/rustc_middle/src/ty/closure.rs (Rust)

Code before:
                        bug!(
                            "Field projection applied to a type other than Adt or Tuple: {:?}.",
                            ty
                        )
                    }
                }
            }
            HirProjectionKind::UnwrapUnsafeBinder => {
                curr_string = format!("unwrap_binder!({curr_string})");
            }
            // Just change the type to the hidden type, so we can actually project.
            HirProjectionKind::OpaqueCast => {}
            proj => bug!("{:?} unexpected because it isn't captured", proj),
        }
        ty = proj.ty;
    }

    curr_string
}

fn typing_env_for_place<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> ty::TypingEnv<'tcx> {
    match place.base {
        HirPlaceBase::Upvar(upvar_id) => {
            ty::TypingEnv::post_analysis(tcx, upvar_id.closure_expr_id)
        }
        _ => ty::TypingEnv::fully_monomorphized(),
    }
}

fn normalize_place_ty<'tcx>(
    tcx: TyCtxt<'tcx>,
    typing_env: ty::TypingEnv<'tcx>,
    ty: Ty<'tcx>,
) -> Ty<'tcx> {
    tcx.normalize_erasing_regions(typing_env, ty)
}

#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable, Hash)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum BorrowKind {
    /// Data must be immutable and is aliasable.
    Immutable,

    /// Data must be immutable but not aliasable. This kind of borrow
    /// cannot currently be expressed by the user and is used only in
    /// implicit closure bindings. It is needed when the closure
    /// is borrowing or mutating a mutable referent, e.g.:
    ///
    /// ```
    /// let mut z = 3;
    /// let x: &mut isize = &mut z;

Review comment (bug):
This is hacky and subtly wrong in two ways.
- even if the type is not from an upvar, we still need the right param_env to normalize
- we use this during MIR build, so it should probably use `TypingMode::Borrowck` or whatever

see https://rustc-dev-guide.rust-lang.org/typing-parameter-envs.html

Code after:
            // Just change the type to the hidden type, so we can actually project.
            HirProjectionKind::OpaqueCast => {}
            proj => bug!("{:?} unexpected because it isn't captured", proj),
        }
    }

    curr_string
}

#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable, Hash)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum BorrowKind {
    /// Data must be immutable and is aliasable.
    Immutable,

    /// Data must be immutable but not aliasable. This kind of borrow
    /// cannot currently be expressed by the user and is used only in
    /// implicit closure bindings. It is needed when the closure
    /// is borrowing or mutating a mutable referent, e.g.:
    ///
    /// ```
    /// let mut z = 3;
    /// let x: &mut isize = &mut z;
    /// let y = || *x += 5;
    /// ```
    ///
    /// If we were to try to translate this closure into a more explicit
    /// form, we'd encounter an error with the code as written:
    ///
    /// ```compile_fail,E0594
    /// struct Env<'a> { x: &'a &'a mut isize }
    /// let mut z = 3;
    /// let x: &mut isize = &mut z;
    /// let y = (&mut Env { x: &x }, fn_ptr);  // Closure is pair of env and fn
    /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
    /// ```
    ///
    /// This is then illegal because you cannot mutate a `&mut` found
    /// in an aliasable location. To solve, you'd have to translate with
    /// an `&mut` borrow:
    ///
    /// ```compile_fail,E0596
    /// struct Env<'a> { x: &'a mut &'a mut isize }
    /// let mut z = 3;
    /// let x: &mut isize = &mut z;
    /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x
    /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
    /// ```
    ///
    /// Now the assignment to `**env.x` is legal, but creating a
    /// mutable pointer to `x` is not because `x` is not mutable. We