@@ -196,13 +196,25 @@ fn collect_unwrap_info<'tcx>(
196196}
197197
198198/// A HIR visitor delegate that checks if a local variable of type `Option<_>` is mutated,
199- /// unless `Option::as_mut` is called.
199+ /// *except* for if `Option::as_mut` is called.
200+ /// The reason for why we allow that one specifically is that `.as_mut()` cannot change
201+ /// the option to `None`, and that is important because this lint relies on the fact that
202+ /// `is_some` + `unwrap` is equivalent to `if let Some(..) = ..`, which it would not be if
203+ /// the option is changed to None between `is_some` and `unwrap`.
204+ /// (And also `.as_mut()` is a somewhat common method that is still worth linting on.)
200205struct MutationVisitor < ' tcx > {
201206 is_mutated : bool ,
202207 local_id : HirId ,
203208 tcx : TyCtxt < ' tcx > ,
204209}
205210
211+ /// Checks if the parent of the expression pointed at by the given `HirId` is a call to
212+ /// `Option::as_mut`.
213+ ///
214+ /// Used by the mutation visitor to specifically allow `.as_mut()` calls.
215+ /// In particular, the `HirId` that the visitor receives is the id of the local expression
216+ /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
217+ /// expression: that will be where the actual method call is.
206218fn is_option_as_mut_use ( tcx : TyCtxt < ' _ > , expr_id : HirId ) -> bool {
207219 if let Node :: Expr ( mutating_expr) = tcx. hir ( ) . get_parent ( expr_id)
208220 && let ExprKind :: MethodCall ( path, ..) = mutating_expr. kind
@@ -260,7 +272,8 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
260272 vis. walk_expr ( branch) ;
261273
262274 if delegate. is_mutated {
263- // if the variable is mutated, we don't know whether it can be unwrapped:
275+ // if the variable is mutated, we don't know whether it can be unwrapped.
276+ // it might have been changed to `None` in between `is_some` + `unwrap`.
264277 continue ;
265278 }
266279 self . unwrappables . push ( unwrap_info) ;
0 commit comments