/// Whether this value be written or borrowed mutably.
/// Returns the root place if the place passed in is a projection.
Whether this value be written or borrowed mutably.
Returns the root place if the place passed in is a projection.
Whether this value be written or borrowed mutably . Returns the root place if the place passed in is a projection .
fn is_mutable<'d>(
        &self,
        place: &'d Place<'tcx>,
        is_local_mutation_allowed: LocalMutationIsAllowed,
    ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> {
        match *place {
            Place::Local(local) => {
                let local = &self.mir.local_decls[local];
                match local.mutability {
                    Mutability::Not => match is_local_mutation_allowed {
                        LocalMutationIsAllowed::Yes => Ok(RootPlace {
                            place,
                            is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
                        }),
                        LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
                            place,
                            is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
                        }),
                        LocalMutationIsAllowed::No => Err(place),
                    },
                    Mutability::Mut => Ok(RootPlace {
                        place,
                        is_local_mutation_allowed,
                    }),
                }
            }
            // The rules for promotion are made by `qualify_consts`, there wouldn't even be a
            // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
            Place::Promoted(_) => Ok(RootPlace {
                place,
                is_local_mutation_allowed,
            }),
            Place::Static(ref static_) => {
                if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
                    Err(place)
                } else {
                    Ok(RootPlace {
                        place,
                        is_local_mutation_allowed,
                    })
                }
            }
            Place::Projection(ref proj) => {
                match proj.elem {
                    ProjectionElem::Deref => {
                        let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
                        // Check the kind of deref to decide
                        match base_ty.sty {
                            ty::TyRef(_, _, mutbl) => {
                                match mutbl {
                                    // Shared borrowed data is never mutable
                                    hir::MutImmutable => Err(place),
                                    // Mutably borrowed data is mutable, but only if we have a
                                    // unique path to the `&mut`
                                    hir::MutMutable => {
                                        let mode = match place.is_upvar_field_projection(
                                            self.mir, &self.tcx)
                                        {
                                            Some(field)
                                                if {
                                                    self.mir.upvar_decls[field.index()].by_ref
                                                } =>
                                            {
                                                is_local_mutation_allowed
                                            }
                                            _ => LocalMutationIsAllowed::Yes,
                                        };
                                        self.is_mutable(&proj.base, mode)
                                    }
                                }
                            }
                            ty::TyRawPtr(tnm) => {
                                match tnm.mutbl {
                                    // `*const` raw pointers are not mutable
                                    hir::MutImmutable => return Err(place),
                                    // `*mut` raw pointers are always mutable, regardless of
                                    // context. The users have to check by themselves.
                                    hir::MutMutable => {
                                        return Ok(RootPlace {
                                            place,
                                            is_local_mutation_allowed,
                                        });
                                    }
                                }
                            }
                            // `Box<T>` owns its content, so mutable if its location is mutable
                            _ if base_ty.is_box() => {
                                self.is_mutable(&proj.base, is_local_mutation_allowed)
                            }
                            // Deref should only be for reference, pointers or boxes
                            _ => bug!("Deref of unexpected type: {:?}", base_ty),
                        }
                    }
                    // All other projections are owned by their base path, so mutable if
                    // base path is mutable
                    ProjectionElem::Field(..)
                    | ProjectionElem::Index(..)
                    | ProjectionElem::ConstantIndex { .. }
                    | ProjectionElem::Subslice { .. }
                    | ProjectionElem::Downcast(..) => {
                        let upvar_field_projection = place.is_upvar_field_projection(
                            self.mir, &self.tcx);
                        if let Some(field) = upvar_field_projection {
                            let decl = &self.mir.upvar_decls[field.index()];
                            debug!(
                                "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
                                decl, is_local_mutation_allowed, place
                            );
                            match (decl.mutability, is_local_mutation_allowed) {
                                (Mutability::Not, LocalMutationIsAllowed::No)
                                | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => {
                                    Err(place)
                                }
                                (Mutability::Not, LocalMutationIsAllowed::Yes)
                                | (Mutability::Mut, _) => {
                                    // Subtle: this is an upvar
                                    // reference, so it looks like
                                    // `self.foo` -- we want to double
                                    // check that the context `*self`
                                    // is mutable (i.e., this is not a
                                    // `Fn` closure).  But if that
                                    // check succeeds, we want to
                                    // *blame* the mutability on
                                    // `place` (that is,
                                    // `self.foo`). This is used to
                                    // propagate the info about
                                    // whether mutability declarations
                                    // are used outwards, so that we register
                                    // the outer variable as mutable. Otherwise a
                                    // test like this fails to record the `mut`
                                    // as needed:
                                    //
                                    // ```
                                    // fn foo<F: FnOnce()>(_f: F) { }
                                    // fn main() {
                                    //     let var = Vec::new();
                                    //     foo(move || {
                                    //         var.push(1);
                                    //     });
                                    // }
                                    // ```
                                    let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?;
                                    Ok(RootPlace {
                                        place,
                                        is_local_mutation_allowed,
                                    })
                                }
                            }
                        } else {
                            self.is_mutable(&proj.base, is_local_mutation_allowed)
                        }
                    }
                }
            }
        }
    }
fn is_mutable < ' d > ( & self , place : & ' d Place < ' tcx > , is_local_mutation_allowed : LocalMutationIsAllowed , ) -> Result < RootPlace < ' d , ' tcx > , & ' d Place < ' tcx > > { match * place { Place :: Local ( local ) => { let local = & self . mir . local_decls [ local ] ; match local . mutability { Mutability :: Not => match is_local_mutation_allowed { LocalMutationIsAllowed :: Yes => Ok ( RootPlace { place , is_local_mutation_allowed : LocalMutationIsAllowed :: Yes , } ) , LocalMutationIsAllowed :: ExceptUpvars => Ok ( RootPlace { place , is_local_mutation_allowed : LocalMutationIsAllowed :: ExceptUpvars , } ) , LocalMutationIsAllowed :: No => Err ( place ) , } , Mutability :: Mut => Ok ( RootPlace { place , is_local_mutation_allowed , } ) , } } // The rules for promotion are made by `qualify_consts`, there wouldn't even be a // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this Place :: Promoted ( _ ) => Ok ( RootPlace { place , is_local_mutation_allowed , } ) , Place :: Static ( ref static_ ) => { if self . tcx . is_static ( static_ . def_id ) != Some ( hir :: Mutability :: MutMutable ) { Err ( place ) } else { Ok ( RootPlace { place , is_local_mutation_allowed , } ) } } Place :: Projection ( ref proj ) => { match proj . elem { ProjectionElem :: Deref => { let base_ty = proj . base . ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ; // Check the kind of deref to decide match base_ty . sty { ty :: TyRef ( _ , _ , mutbl ) => { match mutbl { // Shared borrowed data is never mutable hir :: MutImmutable => Err ( place ) , // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir :: MutMutable => { let mode = match place . is_upvar_field_projection ( self . mir , & self . tcx ) { Some ( field ) if { self . mir . upvar_decls [ field . index ( ) ] . by_ref } => { is_local_mutation_allowed } _ => LocalMutationIsAllowed :: Yes , } ; self . is_mutable ( & proj . base , mode ) } } } ty :: TyRawPtr ( tnm ) => { match tnm . mutbl { // `*const` raw pointers are not mutable hir :: MutImmutable => return Err ( place ) , // `*mut` raw pointers are always mutable, regardless of // context. The users have to check by themselves. hir :: MutMutable => { return Ok ( RootPlace { place , is_local_mutation_allowed , } ) ; } } } // `Box<T>` owns its content, so mutable if its location is mutable _ if base_ty . is_box ( ) => { self . is_mutable ( & proj . base , is_local_mutation_allowed ) } // Deref should only be for reference, pointers or boxes _ => bug ! ( " " base_ty ) , } } // All other projections are owned by their base path, so mutable if // base path is mutable ProjectionElem :: Field ( .. ) | ProjectionElem :: Index ( .. ) | ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } | ProjectionElem :: Downcast ( .. ) => { let upvar_field_projection = place . is_upvar_field_projection ( self . mir , & self . tcx ) ; if let Some ( field ) = upvar_field_projection { let decl = & self . mir . upvar_decls [ field . index ( ) ] ; debug ! ( " " decl is_local_mutation_allowed place ) ; match ( decl . mutability , is_local_mutation_allowed ) { ( Mutability :: Not , LocalMutationIsAllowed :: No ) | ( Mutability :: Not , LocalMutationIsAllowed :: ExceptUpvars ) => { Err ( place ) } ( Mutability :: Not , LocalMutationIsAllowed :: Yes ) | ( Mutability :: Mut , _ ) => { // Subtle: this is an upvar // reference, so it looks like // `self.foo` -- we want to double // check that the context `*self` // is mutable (i.e., this is not a // `Fn` closure).  But if that // check succeeds, we want to // *blame* the mutability on // `place` (that is, // `self.foo`). This is used to // propagate the info about // whether mutability declarations // are used outwards, so that we register // the outer variable as mutable. Otherwise a // test like this fails to record the `mut` // as needed: // // ``` // fn foo<F: FnOnce()>(_f: F) { } // fn main() { //     let var = Vec::new(); //     foo(move || { //         var.push(1); //     }); // } // ``` let _ = self . is_mutable ( & proj . base , is_local_mutation_allowed ) ? ; Ok ( RootPlace { place , is_local_mutation_allowed , } ) } } } else { self . is_mutable ( & proj . base , is_local_mutation_allowed ) } } } } } }
Whether this value be written or borrowed mutably.
Whether this value be written or borrowed mutably .
&self
place
&'d Place<'tcx>
is_local_mutation_allowed
LocalMutationIsAllowed