compiler/rustc_borrowck/src/diagnostics/mod.rs RUST 1,667 lines View on github.com → Search inside
1//! Borrow checker diagnostics.23use std::collections::BTreeMap;45use rustc_abi::{FieldIdx, VariantIdx};6use rustc_data_structures::fx::FxIndexMap;7use rustc_errors::formatting::DiagMessageAddArg;8use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg};9use rustc_hir::attrs::lang_items::LangItem;10use rustc_hir::def::{CtorKind, Namespace};11use rustc_hir::{12    self as hir, CoroutineKind, GenericBound, WhereBoundPredicate, WherePredicateKind,13};14use rustc_index::{IndexSlice, IndexVec};15use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};16use rustc_infer::traits::SelectionError;17use rustc_middle::mir::{18    AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,19    LocalKind, Location, Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement,20    StatementKind, Terminator, TerminatorKind, VarDebugInfoContents, find_self_call,21};22use rustc_middle::ty::print::{Print, with_no_trimmed_paths};23use rustc_middle::ty::{self, Ty, TyCtxt};24use rustc_middle::{bug, span_bug};25use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};26use rustc_span::def_id::LocalDefId;27use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym};28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;29use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};30use rustc_trait_selection::infer::InferCtxtExt;31use rustc_trait_selection::traits::{32    FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,33};34use tracing::debug;3536use super::MirBorrowckCtxt;37use super::borrow_set::BorrowData;38use crate::LocalMutationIsAllowed;39use crate::constraints::OutlivesConstraint;40use crate::nll::ConstraintDescription;41use crate::session_diagnostics::{42    CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,43    CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,44};4546mod find_all_local_uses;47mod find_use;48mod outlives_suggestion;49mod region_name;50mod var_name;5152mod bound_region_errors;53mod conflict_errors;54mod explain_borrow;55mod move_errors;56mod mutability_errors;57mod opaque_types;58mod region_errors;5960pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};61pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError};62pub(crate) use mutability_errors::AccessKind;63pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;64pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};65pub(crate) use region_name::{RegionName, RegionNameSource};66pub(crate) use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;6768pub(super) struct DescribePlaceOpt {69    including_downcast: bool,7071    /// Enable/Disable tuple fields.72    /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`73    including_tuple_field: bool,74}7576pub(super) struct IncludingTupleField(pub(super) bool);7778pub(crate) enum BufferedDiag<'diag> {79    Error(Diag<'diag>),80    NonError(Diag<'diag, ()>),81}8283impl<'diag> BufferedDiag<'diag> {84    fn sort_span(&self) -> Span {85        match self {86            BufferedDiag::Error(diag) => diag.sort_span,87            BufferedDiag::NonError(diag) => diag.sort_span,88        }89    }90}9192#[derive(Default)]93pub(crate) struct BorrowckDiagnosticsBuffer<'diag, 'tcx> {94    /// This field keeps track of move errors that are to be reported for given move indices.95    ///96    /// There are situations where many errors can be reported for a single move out (see97    /// #53807) and we want only the best of those errors.98    ///99    /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the100    /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of101    /// the `Place` of the previous most diagnostic. This happens instead of buffering the102    /// error. Once all move errors have been reported, any diagnostics in this map are added103    /// to the buffer to be emitted.104    ///105    /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary106    /// when errors in the map are being re-added to the error buffer so that errors with the107    /// same primary span come out in a consistent order.108    buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'diag>)>,109110    buffered_mut_errors: FxIndexMap<Span, (Diag<'diag>, usize)>,111112    /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.113    buffered_diags: Vec<BufferedDiag<'diag>>,114}115116impl<'diag, 'tcx> BorrowckDiagnosticsBuffer<'diag, 'tcx> {117    pub(crate) fn buffer_non_error(&mut self, diag: Diag<'diag, ()>) {118        self.buffered_diags.push(BufferedDiag::NonError(diag));119    }120    pub(crate) fn buffer_error(&mut self, diag: Diag<'diag>) {121        self.buffered_diags.push(BufferedDiag::Error(diag));122    }123124    pub(crate) fn emit_errors(&mut self) {125        // Buffer any move errors that we collected and de-duplicated.126        for (_, (_, diag)) in std::mem::take(&mut self.buffered_move_errors) {127            // We have already set tainted for this error, so just buffer it.128            self.buffer_error(diag);129        }130        for (_, (mut diag, count)) in std::mem::take(&mut self.buffered_mut_errors) {131            if count > 10 {132                diag.note(format!("...and {} other attempted mutable borrows", count - 10));133            }134            self.buffer_error(diag);135        }136137        if !self.buffered_diags.is_empty() {138            self.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());139            for buffered_diag in self.buffered_diags.drain(..) {140                match buffered_diag {141                    BufferedDiag::Error(diag) => {142                        diag.emit();143                    }144                    BufferedDiag::NonError(diag) => diag.emit(),145                }146            }147        }148    }149}150151impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {152    pub(crate) fn buffer_error(&mut self, diag: Diag<'_>) {153        self.diags_buffer.buffer_error(diag.with_dcx(self.dcx()));154    }155156    pub(crate) fn buffer_non_error(&mut self, diag: Diag<'_, ()>) {157        self.diags_buffer.buffer_non_error(diag.with_dcx(self.dcx()));158    }159160    pub(crate) fn buffer_move_error(161        &mut self,162        move_out_indices: Vec<MoveOutIndex>,163        place_and_err: (PlaceRef<'tcx>, Diag<'diag>),164    ) -> bool {165        if let Some((_, diag)) =166            self.diags_buffer.buffered_move_errors.insert(move_out_indices, place_and_err)167        {168            // Cancel the old diagnostic so we don't ICE169            diag.cancel();170            false171        } else {172            true173        }174    }175176    pub(crate) fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'diag>, usize)> {177        // FIXME(#120456) - is `swap_remove` correct?178        self.diags_buffer.buffered_mut_errors.swap_remove(&span)179    }180181    pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'diag>, count: usize) {182        self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));183    }184185    pub(crate) fn has_buffered_diags(&self) -> bool {186        self.diags_buffer.buffered_diags.is_empty()187    }188189    pub(crate) fn has_move_error(190        &self,191        move_out_indices: &[MoveOutIndex],192    ) -> Option<&(PlaceRef<'tcx>, Diag<'diag>)> {193        self.diags_buffer.buffered_move_errors.get(move_out_indices)194    }195196    /// Uses `body.var_debug_info` to find the symbol197    fn local_name(&self, index: Local) -> Option<Symbol> {198        *self.local_names().get(index)?199    }200201    fn local_names(&self) -> &IndexSlice<Local, Option<Symbol>> {202        self.local_names.get_or_init(|| {203            let mut local_names = IndexVec::from_elem(None, &self.body.local_decls);204            for var_debug_info in &self.body.var_debug_info {205                if let VarDebugInfoContents::Place(place) = var_debug_info.value {206                    if let Some(local) = place.as_local() {207                        if let Some(prev_name) = local_names[local]208                            && var_debug_info.name != prev_name209                        {210                            span_bug!(211                                var_debug_info.source_info.span,212                                "local {:?} has many names (`{}` vs `{}`)",213                                local,214                                prev_name,215                                var_debug_info.name216                            );217                        }218                        local_names[local] = Some(var_debug_info.name);219                    }220                }221            }222            local_names223        })224    }225}226227impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {228    /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure229    /// is moved after being invoked.230    ///231    /// ```text232    /// note: closure cannot be invoked more than once because it moves the variable `dict` out of233    ///       its environment234    ///   --> $DIR/issue-42065.rs:16:29235    ///    |236    /// LL |         for (key, value) in dict {237    ///    |                             ^^^^238    /// ```239    pub(super) fn add_moved_or_invoked_closure_note(240        &self,241        location: Location,242        place: PlaceRef<'tcx>,243        diag: &mut Diag<'_>,244    ) -> bool {245        debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);246        let mut target = place.local_or_deref_local();247        for stmt in &self.body[location.block].statements[location.statement_index..] {248            debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);249            if let StatementKind::Assign((into, Rvalue::Use(from, _))) = &stmt.kind {250                debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);251                match from {252                    Operand::Copy(place) | Operand::Move(place)253                        if target == place.local_or_deref_local() =>254                    {255                        target = into.local_or_deref_local()256                    }257                    _ => {}258                }259            }260        }261262        // Check if we are attempting to call a closure after it has been invoked.263        let terminator = self.body[location.block].terminator();264        debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);265        if let TerminatorKind::Call {266            func: Operand::Constant(ConstOperand { const_, .. }),267            args,268            ..269        } = &terminator.kind270            && let ty::FnDef(id, _) = *const_.ty().kind()271        {272            debug!("add_moved_or_invoked_closure_note: id={:?}", id);273            if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {274                let closure = match args.first() {275                    Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. })276                        if target == place.local_or_deref_local() =>277                    {278                        place.local_or_deref_local().unwrap()279                    }280                    _ => return false,281                };282283                debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);284                if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {285                    let did = did.expect_local();286                    if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {287                        diag.subdiagnostic(OnClosureNote::InvokedTwice {288                            place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),289                            span: *span,290                        });291                        return true;292                    }293                }294            }295        }296297        // Check if we are just moving a closure after it has been invoked.298        if let Some(target) = target299            && let ty::Closure(did, _) = self.body.local_decls[target].ty.kind()300        {301            let did = did.expect_local();302            if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {303                diag.subdiagnostic(OnClosureNote::MovedTwice {304                    place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),305                    span: *span,306                });307                return true;308            }309        }310        false311    }312313    /// End-user visible description of `place` if one can be found.314    /// If the place is a temporary for instance, `"value"` will be returned.315    pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {316        match self.describe_place(place_ref) {317            Some(mut descr) => {318                // Surround descr with `backticks`.319                descr.reserve(2);320                descr.insert(0, '`');321                descr.push('`');322                descr323            }324            None => "value".to_string(),325        }326    }327328    /// End-user visible description of `place` if one can be found.329    /// If the place is a temporary for instance, `None` will be returned.330    pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {331        self.describe_place_with_options(332            place_ref,333            DescribePlaceOpt { including_downcast: false, including_tuple_field: true },334        )335    }336337    /// End-user visible description of `place` if one can be found. If the place is a temporary338    /// for instance, `None` will be returned.339    /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is340    /// `Downcast` and `IncludingDowncast` is true341    pub(super) fn describe_place_with_options(342        &self,343        place: PlaceRef<'tcx>,344        opt: DescribePlaceOpt,345    ) -> Option<String> {346        let local = place.local;347        if self.body.local_decls[local]348            .source_info349            .span350            .in_external_macro(self.infcx.tcx.sess.source_map())351        {352            return None;353        }354355        let mut autoderef_index = None;356        let mut buf = String::new();357        let mut ok = self.append_local_to_string(local, &mut buf);358359        for (index, elem) in place.projection.into_iter().enumerate() {360            match elem {361                ProjectionElem::Deref => {362                    if index == 0 {363                        if self.body.local_decls[local].is_ref_for_guard() {364                            continue;365                        }366                        if let LocalInfo::StaticRef { def_id, .. } =367                            *self.body.local_decls[local].local_info()368                        {369                            buf.push_str(self.infcx.tcx.item_name(def_id).as_str());370                            ok = Ok(());371                            continue;372                        }373                    }374                    if let Some(field) = self.is_upvar_field_projection(PlaceRef {375                        local,376                        projection: place.projection.split_at(index + 1).0,377                    }) {378                        let var_index = field.index();379                        buf = self.upvars[var_index].to_string(self.infcx.tcx);380                        ok = Ok(());381                        if !self.upvars[var_index].is_by_ref() {382                            buf.insert(0, '*');383                        }384                    } else {385                        if autoderef_index.is_none() {386                            autoderef_index = match place.projection.iter().rposition(|elem| {387                                !matches!(388                                    elem,389                                    ProjectionElem::Deref | ProjectionElem::Downcast(..)390                                )391                            }) {392                                Some(index) => Some(index + 1),393                                None => Some(0),394                            };395                        }396                        if index >= autoderef_index.unwrap() {397                            buf.insert(0, '*');398                        }399                    }400                }401                ProjectionElem::Downcast(..) if opt.including_downcast => return None,402                ProjectionElem::Downcast(..) => (),403                ProjectionElem::OpaqueCast(..) => (),404                ProjectionElem::UnwrapUnsafeBinder(_) => (),405                ProjectionElem::Field(field, _ty) => {406                    // FIXME(project-rfc_2229#36): print capture precisely here.407                    if let Some(field) = self.is_upvar_field_projection(PlaceRef {408                        local,409                        projection: place.projection.split_at(index + 1).0,410                    }) {411                        buf = self.upvars[field.index()].to_string(self.infcx.tcx);412                        ok = Ok(());413                    } else {414                        let field_name = self.describe_field(415                            PlaceRef { local, projection: place.projection.split_at(index).0 },416                            *field,417                            IncludingTupleField(opt.including_tuple_field),418                        );419                        if let Some(field_name_str) = field_name {420                            buf.push('.');421                            buf.push_str(&field_name_str);422                        }423                    }424                }425                ProjectionElem::Index(index) => {426                    buf.push('[');427                    if self.append_local_to_string(*index, &mut buf).is_err() {428                        buf.push('_');429                    }430                    buf.push(']');431                }432                ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {433                    // Since it isn't possible to borrow an element on a particular index and434                    // then use another while the borrow is held, don't output indices details435                    // to avoid confusing the end-user436                    buf.push_str("[..]");437                }438            }439        }440        ok.ok().map(|_| buf)441    }442443    fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {444        for elem in place.projection.into_iter() {445            match elem {446                ProjectionElem::Downcast(Some(name), _) => {447                    return Some(*name);448                }449                _ => {}450            }451        }452        None453    }454455    /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have456    /// a name, or its name was generated by the compiler, then `Err` is returned457    fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {458        let decl = &self.body.local_decls[local];459        match self.local_name(local) {460            Some(name) if !decl.from_compiler_desugaring() => {461                buf.push_str(name.as_str());462                Ok(())463            }464            _ => Err(()),465        }466    }467468    /// End-user visible description of the `field`nth field of `base`469    fn describe_field(470        &self,471        place: PlaceRef<'tcx>,472        field: FieldIdx,473        including_tuple_field: IncludingTupleField,474    ) -> Option<String> {475        let place_ty = match place {476            PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),477            PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {478                ProjectionElem::Deref479                | ProjectionElem::Index(..)480                | ProjectionElem::ConstantIndex { .. }481                | ProjectionElem::Subslice { .. } => {482                    PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)483                }484                ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),485                ProjectionElem::OpaqueCast(ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => {486                    PlaceTy::from_ty(*ty)487                }488                ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),489            },490        };491        self.describe_field_from_ty(492            place_ty.ty,493            field,494            place_ty.variant_index,495            including_tuple_field,496        )497    }498499    /// End-user visible description of the `field_index`nth field of `ty`500    fn describe_field_from_ty(501        &self,502        ty: Ty<'_>,503        field: FieldIdx,504        variant_index: Option<VariantIdx>,505        including_tuple_field: IncludingTupleField,506    ) -> Option<String> {507        if let Some(boxed_ty) = ty.boxed_ty() {508            // If the type is a box, the field is described from the boxed type509            self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field)510        } else {511            match *ty.kind() {512                ty::Adt(def, _) => {513                    let variant = if let Some(idx) = variant_index {514                        assert!(def.is_enum());515                        def.variant(idx)516                    } else {517                        def.non_enum_variant()518                    };519                    if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {520                        return None;521                    }522                    Some(variant.fields[field].name.to_string())523                }524                ty::Tuple(_) => Some(field.index().to_string()),525                ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {526                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)527                }528                ty::Array(ty, _) | ty::Slice(ty) => {529                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)530                }531                ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {532                    // We won't be borrowck'ing here if the closure came from another crate,533                    // so it's safe to call `expect_local`.534                    //535                    // We know the field exists so it's safe to call operator[] and `unwrap` here.536                    let def_id = def_id.expect_local();537                    let var_id =538                        self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();539540                    Some(self.infcx.tcx.hir_name(var_id).to_string())541                }542                _ => {543                    // This can happen for field accesses on `Box<T>`: the field is544                    // described from the boxed type, which may have no named fields545                    Some(field.index().to_string())546                }547            }548        }549    }550551    pub(super) fn borrowed_content_source(552        &self,553        deref_base: PlaceRef<'tcx>,554    ) -> BorrowedContentSource<'tcx> {555        let tcx = self.infcx.tcx;556557        // Look up the provided place and work out the move path index for it,558        // we'll use this to check whether it was originally from an overloaded559        // operator.560        match self.move_data.rev_lookup.find(deref_base) {561            LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {562                debug!("borrowed_content_source: mpi={:?}", mpi);563564                for i in &self.move_data.init_path_map[mpi] {565                    let init = &self.move_data.inits[*i];566                    debug!("borrowed_content_source: init={:?}", init);567                    // We're only interested in statements that initialized a value, not the568                    // initializations from arguments.569                    let InitLocation::Statement(loc) = init.location else { continue };570571                    let bbd = &self.body[loc.block];572                    let is_terminator = bbd.statements.len() == loc.statement_index;573                    debug!(574                        "borrowed_content_source: loc={:?} is_terminator={:?}",575                        loc, is_terminator,576                    );577                    if !is_terminator {578                        continue;579                    } else if let Some(Terminator {580                        kind:581                            TerminatorKind::Call {582                                func,583                                call_source: CallSource::OverloadedOperator,584                                ..585                            },586                        ..587                    }) = &bbd.terminator588                    {589                        if let Some(source) =590                            BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)591                        {592                            return source;593                        }594                    }595                }596            }597            // Base is a `static` so won't be from an overloaded operator598            _ => (),599        };600601        // If we didn't find an overloaded deref or index, then assume it's a602        // built in deref and check the type of the base.603        let base_ty = deref_base.ty(self.body, tcx).ty;604        if base_ty.is_raw_ptr() {605            BorrowedContentSource::DerefRawPointer606        } else if base_ty.is_mutable_ptr() {607            BorrowedContentSource::DerefMutableRef608        } else if base_ty.is_ref() {609            BorrowedContentSource::DerefSharedRef610        } else {611            // Custom type implementing `Deref` (e.g. `MyBox<T>`, `Rc<T>`, `Arc<T>`)612            // that wasn't detected via the MIR init trace above. This can happen613            // when the deref base is initialized by a regular statement rather than614            // a `TerminatorKind::Call` with `CallSource::OverloadedOperator`.615            BorrowedContentSource::OverloadedDeref(base_ty)616        }617    }618619    /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime620    /// name where required.621    pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {622        let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);623624        // We need to add synthesized lifetimes where appropriate. We do625        // this by hooking into the pretty printer and telling it to label the626        // lifetimes without names with the value `'0`.627        if let ty::Ref(region, ..) = ty.kind() {628            match region.kind() {629                ty::ReBound(_, ty::BoundRegion { kind: br, .. })630                | ty::RePlaceholder(ty::PlaceholderRegion {631                    bound: ty::BoundRegion { kind: br, .. },632                    ..633                }) => p.region_highlight_mode.highlighting_bound_region(br, counter),634                _ => {}635            }636        }637638        ty.print(&mut p).unwrap();639        p.into_buffer()640    }641642    /// Returns the name of the provided `Ty` (that must be a reference)'s region with a643    /// synthesized lifetime name where required.644    pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {645        let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);646647        let region = if let ty::Ref(region, ..) = ty.kind() {648            match region.kind() {649                ty::ReBound(_, ty::BoundRegion { kind: br, .. })650                | ty::RePlaceholder(ty::PlaceholderRegion {651                    bound: ty::BoundRegion { kind: br, .. },652                    ..653                }) => p.region_highlight_mode.highlighting_bound_region(br, counter),654                _ => {}655            }656            region657        } else {658            bug!("ty for annotation of borrow region is not a reference");659        };660661        region.print(&mut p).unwrap();662        p.into_buffer()663    }664665    /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates666    /// implicitly introduce an "outlives `'static`" constraint.667    ///668    /// This is very similar to `fn suggest_static_lifetime_for_gat_from_hrtb` which handles this669    /// note for failed type tests instead of outlives errors.670    fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(671        &self,672        diag: &mut Diag<'_, G>,673        path: &[OutlivesConstraint<'tcx>],674    ) {675        let tcx = self.infcx.tcx;676        let Some((gat_hir_id, generics)) = path.iter().find_map(|constraint| {677            let outlived = constraint.sub;678            if let Some(origin) = self.regioncx.definitions.get(outlived)679                && let NllRegionVariableOrigin::Placeholder(placeholder) = origin.origin680                && let Some(id) = placeholder.bound.kind.get_id()681                && let Some(placeholder_id) = id.as_local()682                && let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)683                && let Some(generics_impl) =684                    tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()685            {686                Some((gat_hir_id, generics_impl))687            } else {688                None689            }690        }) else {691            return;692        };693694        // Look for the where-bound which introduces the placeholder.695        // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>`696        // and `T: for<'a> Trait`<'a>.697        for pred in generics.predicates {698            let WherePredicateKind::BoundPredicate(WhereBoundPredicate {699                bound_generic_params,700                bounds,701                ..702            }) = pred.kind703            else {704                continue;705            };706            if bound_generic_params707                .iter()708                .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)709                .is_some()710            {711                diag.span_note(pred.span, LIMITATION_NOTE);712                return;713            }714            for bound in bounds.iter() {715                if let GenericBound::Trait(bound) = bound {716                    if bound717                        .bound_generic_params718                        .iter()719                        .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)720                        .is_some()721                    {722                        diag.span_note(bound.span, LIMITATION_NOTE);723                        return;724                    }725                }726            }727        }728    }729730    /// Add a label to region errors and borrow explanations when outlives constraints arise from731    /// proving a type implements `Sized` or `Copy`.732    fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(733        &self,734        err: &mut Diag<'_, G>,735        blamed_category: ConstraintCategory<'tcx>,736        path: &[OutlivesConstraint<'tcx>],737    ) {738        for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {739            if sought_category != blamed_category740                && let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)741            {742                let label = format!(743                    "requirement occurs due to {}",744                    sought_category.description().trim_end()745                );746                err.span_label(sought_constraint.span, label);747            }748        }749    }750}751752/// The span(s) associated to a use of a place.753#[derive(Copy, Clone, PartialEq, Eq, Debug)]754pub(super) enum UseSpans<'tcx> {755    /// The access is caused by capturing a variable for a closure.756    ClosureUse {757        /// This is true if the captured variable was from a coroutine.758        closure_kind: hir::ClosureKind,759        /// The span of the args of the closure, including the `move` keyword if760        /// it's present.761        args_span: Span,762        /// The span of the use resulting in capture kind763        /// Check `ty::CaptureInfo` for more details764        capture_kind_span: Span,765        /// The span of the use resulting in the captured path766        /// Check `ty::CaptureInfo` for more details767        path_span: Span,768    },769    /// The access is caused by using a variable as the receiver of a method770    /// that takes 'self'771    FnSelfUse {772        /// The span of the variable being moved773        var_span: Span,774        /// The span of the method call on the variable775        fn_call_span: Span,776        /// The definition span of the method being called777        fn_span: Span,778        kind: CallKind<'tcx>,779    },780    /// This access is caused by a `match` or `if let` pattern.781    PatUse(Span),782    /// This access has a single span associated to it: common case.783    OtherUse(Span),784}785786impl UseSpans<'_> {787    pub(super) fn args_or_use(self) -> Span {788        match self {789            UseSpans::ClosureUse { args_span: span, .. }790            | UseSpans::PatUse(span)791            | UseSpans::OtherUse(span) => span,792            UseSpans::FnSelfUse { var_span, .. } => var_span,793        }794    }795796    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`797    pub(super) fn var_or_use_path_span(self) -> Span {798        match self {799            UseSpans::ClosureUse { path_span: span, .. }800            | UseSpans::PatUse(span)801            | UseSpans::OtherUse(span) => span,802            UseSpans::FnSelfUse { var_span, .. } => var_span,803        }804    }805806    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`807    pub(super) fn var_or_use(self) -> Span {808        match self {809            UseSpans::ClosureUse { capture_kind_span: span, .. }810            | UseSpans::PatUse(span)811            | UseSpans::OtherUse(span) => span,812            UseSpans::FnSelfUse { var_span, .. } => var_span,813        }814    }815816    // FIXME(coroutines): Make this just return the `ClosureKind` directly?817    pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {818        match self {819            UseSpans::ClosureUse {820                closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),821                ..822            } => Some(coroutine_kind),823            _ => None,824        }825    }826827    /// Add a span label to the arguments of the closure, if it exists.828    pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {829        if let UseSpans::ClosureUse { args_span, .. } = self {830            err.subdiagnostic(f(args_span));831        }832    }833834    /// Add a span label to the use of the captured variable, if it exists.835    /// only adds label to the `path_span`836    pub(super) fn var_path_only_subdiag(837        self,838        err: &mut Diag<'_>,839        action: crate::InitializationRequiringAction,840    ) {841        use CaptureVarPathUseCause::*;842843        use crate::InitializationRequiringAction::*;844        if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {845            match closure_kind {846                hir::ClosureKind::Coroutine(_) => {847                    err.subdiagnostic(match action {848                        Borrow => BorrowInCoroutine { path_span },849                        MatchOn | Use => UseInCoroutine { path_span },850                        Assignment => AssignInCoroutine { path_span },851                        PartialAssignment => AssignPartInCoroutine { path_span },852                    });853                }854                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {855                    err.subdiagnostic(match action {856                        Borrow => BorrowInClosure { path_span },857                        MatchOn | Use => UseInClosure { path_span },858                        Assignment => AssignInClosure { path_span },859                        PartialAssignment => AssignPartInClosure { path_span },860                    });861                }862            }863        }864    }865866    /// Add a subdiagnostic to the use of the captured variable, if it exists.867    pub(super) fn var_subdiag(868        self,869        err: &mut Diag<'_>,870        kind: Option<rustc_middle::mir::BorrowKind>,871        f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,872    ) {873        if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {874            if capture_kind_span != path_span {875                err.subdiagnostic(match kind {876                    Some(kd) => match kd {877                        rustc_middle::mir::BorrowKind::Shared878                        | rustc_middle::mir::BorrowKind::Fake(_) => {879                            CaptureVarKind::Immut { kind_span: capture_kind_span }880                        }881882                        rustc_middle::mir::BorrowKind::Mut { .. } => {883                            CaptureVarKind::Mut { kind_span: capture_kind_span }884                        }885                    },886                    None => CaptureVarKind::Move { kind_span: capture_kind_span },887                });888            };889            let diag = f(closure_kind, path_span);890            err.subdiagnostic(diag);891        }892    }893894    /// Returns `false` if this place is not used in a closure.895    pub(super) fn for_closure(&self) -> bool {896        match *self {897            UseSpans::ClosureUse { closure_kind, .. } => {898                matches!(closure_kind, hir::ClosureKind::Closure)899            }900            _ => false,901        }902    }903904    /// Returns `false` if this place is not used in a coroutine.905    pub(super) fn for_coroutine(&self) -> bool {906        match *self {907            // FIXME(coroutines): Do we want this to apply to synthetic coroutines?908            UseSpans::ClosureUse { closure_kind, .. } => {909                matches!(closure_kind, hir::ClosureKind::Coroutine(..))910            }911            _ => false,912        }913    }914915    pub(super) fn or_else<F>(self, if_other: F) -> Self916    where917        F: FnOnce() -> Self,918    {919        match self {920            closure @ UseSpans::ClosureUse { .. } => closure,921            UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),922            fn_self @ UseSpans::FnSelfUse { .. } => fn_self,923        }924    }925}926927pub(super) enum BorrowedContentSource<'tcx> {928    DerefRawPointer,929    DerefMutableRef,930    DerefSharedRef,931    OverloadedDeref(Ty<'tcx>),932    OverloadedIndex(Ty<'tcx>),933}934935impl<'tcx> BorrowedContentSource<'tcx> {936    pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {937        match *self {938            BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),939            BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),940            BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),941            BorrowedContentSource::OverloadedDeref(ty) => ty942                .ty_adt_def()943                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {944                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),945                    _ => None,946                })947                .unwrap_or_else(|| format!("dereference of `{ty}`")),948            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),949        }950    }951952    pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {953        match *self {954            BorrowedContentSource::DerefRawPointer => Some("raw pointer"),955            BorrowedContentSource::DerefSharedRef => Some("shared reference"),956            BorrowedContentSource::DerefMutableRef => Some("mutable reference"),957            // Overloaded deref and index operators should be evaluated into a958            // temporary. So we don't need a description here.959            BorrowedContentSource::OverloadedDeref(_)960            | BorrowedContentSource::OverloadedIndex(_) => None,961        }962    }963964    pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {965        match *self {966            BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),967            BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),968            BorrowedContentSource::DerefMutableRef => {969                bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")970            }971            BorrowedContentSource::OverloadedDeref(ty) => ty972                .ty_adt_def()973                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {974                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),975                    _ => None,976                })977                .unwrap_or_else(|| format!("dereference of `{ty}`")),978            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),979        }980    }981982    fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {983        match *func.kind() {984            ty::FnDef(def_id, args) => {985                let trait_id = tcx.trait_of_assoc(def_id)?;986987                let args = args.no_bound_vars().unwrap();988989                if tcx.is_lang_item(trait_id, LangItem::Deref)990                    || tcx.is_lang_item(trait_id, LangItem::DerefMut)991                {992                    Some(BorrowedContentSource::OverloadedDeref(args.type_at(0)))993                } else if tcx.is_lang_item(trait_id, LangItem::Index)994                    || tcx.is_lang_item(trait_id, LangItem::IndexMut)995                {996                    Some(BorrowedContentSource::OverloadedIndex(args.type_at(0)))997                } else {998                    None999                }1000            }1001            _ => None,1002        }1003    }1004}10051006/// Helper struct for `explain_captures`.1007struct CapturedMessageOpt {1008    is_partial_move: bool,1009    is_loop_message: bool,1010    is_move_msg: bool,1011    is_loop_move: bool,1012    has_suggest_reborrow: bool,1013    maybe_reinitialized_locations_is_empty: bool,1014}10151016/// Tracks whether [`MirBorrowckCtxt::explain_captures`] emitted a clone1017/// suggestion, so callers can avoid emitting redundant suggestions downstream.1018#[derive(Copy, Clone, PartialEq, Eq)]1019pub(super) enum CloneSuggestion {1020    Emitted,1021    NotEmitted,1022}10231024impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {1025    /// Finds the spans associated to a move or copy of move_place at location.1026    pub(super) fn move_spans(1027        &self,1028        moved_place: PlaceRef<'tcx>, // Could also be an upvar.1029        location: Location,1030    ) -> UseSpans<'tcx> {1031        use self::UseSpans::*;10321033        let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {1034            return OtherUse(self.body.source_info(location).span);1035        };10361037        debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);1038        if let StatementKind::Assign((_, Rvalue::Aggregate(kind, places))) = &stmt.kind1039            && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind1040        {1041            debug!("move_spans: def_id={:?} places={:?}", def_id, places);1042            let def_id = def_id.expect_local();1043            if let Some((args_span, closure_kind, capture_kind_span, path_span)) =1044                self.closure_span(def_id, moved_place, places)1045            {1046                return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };1047            }1048        }10491050        // StatementKind::FakeRead only contains a def_id if they are introduced as a result1051        // of pattern matching within a closure.1052        if let StatementKind::FakeRead((cause, place)) = stmt.kind {1053            match cause {1054                FakeReadCause::ForMatchedPlace(Some(closure_def_id))1055                | FakeReadCause::ForLet(Some(closure_def_id)) => {1056                    debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);1057                    let places = &[Operand::Move(place)];1058                    if let Some((args_span, closure_kind, capture_kind_span, path_span)) =1059                        self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))1060                    {1061                        return ClosureUse {1062                            closure_kind,1063                            args_span,1064                            capture_kind_span,1065                            path_span,1066                        };1067                    }1068                }1069                _ => {}1070            }1071        }10721073        let normal_ret =1074            if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {1075                PatUse(stmt.source_info.span)1076            } else {1077                OtherUse(stmt.source_info.span)1078            };10791080        // We are trying to find MIR of the form:1081        // ```1082        // _temp = _moved_val;1083        // ...1084        // FnSelfCall(_temp, ...)1085        // ```1086        //1087        // where `_moved_val` is the place we generated the move error for,1088        // `_temp` is some other local, and `FnSelfCall` is a function1089        // that has a `self` parameter.10901091        let target_temp = match stmt.kind {1092            StatementKind::Assign((temp, _)) if temp.as_local().is_some() => {1093                temp.as_local().unwrap()1094            }1095            _ => return normal_ret,1096        };10971098        debug!("move_spans: target_temp = {:?}", target_temp);10991100        if let Some(Terminator {1101            kind: TerminatorKind::Call { fn_span, call_source, .. }, ..1102        }) = &self.body[location.block].terminator1103        {1104            let Some((method_did, method_args)) =1105                find_self_call(self.infcx.tcx, self.body, target_temp, location.block)1106            else {1107                return normal_ret;1108            };11091110            let kind = call_kind(1111                self.infcx.tcx,1112                self.infcx.typing_env(self.infcx.param_env),1113                method_did,1114                method_args,1115                *fn_span,1116                call_source.from_hir_call(),1117                self.infcx.tcx.fn_arg_idents(method_did)[0],1118            );11191120            return FnSelfUse {1121                var_span: stmt.source_info.span,1122                fn_call_span: *fn_span,1123                fn_span: self.infcx.tcx.def_span(method_did),1124                kind,1125            };1126        }11271128        normal_ret1129    }11301131    /// Finds the span of arguments of a closure (within `maybe_closure_span`)1132    /// and its usage of the local assigned at `location`.1133    /// This is done by searching in statements succeeding `location`1134    /// and originating from `maybe_closure_span`.1135    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {1136        use self::UseSpans::*;1137        debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);11381139        let Some(Statement { kind: StatementKind::Assign((place, _)), .. }) =1140            self.body[location.block].statements.get(location.statement_index)1141        else {1142            return OtherUse(use_span);1143        };1144        let Some(target) = place.as_local() else { return OtherUse(use_span) };11451146        if self.body.local_kind(target) != LocalKind::Temp {1147            // operands are always temporaries.1148            return OtherUse(use_span);1149        }11501151        // drop and replace might have moved the assignment to the next block1152        let maybe_additional_statement =1153            if let TerminatorKind::Drop { target: drop_target, .. } =1154                self.body[location.block].terminator().kind1155            {1156                self.body[drop_target].statements.first()1157            } else {1158                None1159            };11601161        let statements =1162            self.body[location.block].statements[location.statement_index + 1..].iter();11631164        for stmt in statements.chain(maybe_additional_statement) {1165            if let StatementKind::Assign((_, Rvalue::Aggregate(kind, places))) = &stmt.kind {1166                let (&def_id, is_coroutine) = match kind {1167                    AggregateKind::Closure(def_id, _) => (def_id, false),1168                    AggregateKind::Coroutine(def_id, _) => (def_id, true),1169                    _ => continue,1170                };1171                let def_id = def_id.expect_local();11721173                debug!(1174                    "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",1175                    def_id, is_coroutine, places1176                );1177                if let Some((args_span, closure_kind, capture_kind_span, path_span)) =1178                    self.closure_span(def_id, Place::from(target).as_ref(), places)1179                {1180                    return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };1181                } else {1182                    return OtherUse(use_span);1183                }1184            }11851186            if use_span != stmt.source_info.span {1187                break;1188            }1189        }11901191        OtherUse(use_span)1192    }11931194    /// Finds the spans of a captured place within a closure or coroutine.1195    /// The first span is the location of the use resulting in the capture kind of the capture1196    /// The second span is the location the use resulting in the captured path of the capture1197    fn closure_span(1198        &self,1199        def_id: LocalDefId,1200        target_place: PlaceRef<'tcx>,1201        places: &IndexSlice<FieldIdx, Operand<'tcx>>,1202    ) -> Option<(Span, hir::ClosureKind, Span, Span)> {1203        debug!(1204            "closure_span: def_id={:?} target_place={:?} places={:?}",1205            def_id, target_place, places1206        );1207        let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);1208        let expr = &self.infcx.tcx.hir_expect_expr(hir_id).kind;1209        debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);1210        if let &hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {1211            for (captured_place, place) in1212                self.infcx.tcx.closure_captures(def_id).iter().zip(places)1213            {1214                match place {1215                    Operand::Copy(place) | Operand::Move(place)1216                        if target_place == place.as_ref() =>1217                    {1218                        debug!("closure_span: found captured local {:?}", place);1219                        return Some((1220                            fn_decl_span,1221                            kind,1222                            captured_place.get_capture_kind_span(self.infcx.tcx),1223                            captured_place.get_path_span(self.infcx.tcx),1224                        ));1225                    }1226                    _ => {}1227                }1228            }1229        }1230        None1231    }12321233    /// Helper to retrieve span(s) of given borrow from the current MIR1234    /// representation1235    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {1236        let span = self.body.source_info(borrow.reserve_location).span;1237        self.borrow_spans(span, borrow.reserve_location)1238    }12391240    fn explain_captures(1241        &mut self,1242        err: &mut Diag<'_>,1243        span: Span,1244        move_span: Span,1245        move_spans: UseSpans<'tcx>,1246        moved_place: Place<'tcx>,1247        msg_opt: CapturedMessageOpt,1248    ) -> CloneSuggestion {1249        let CapturedMessageOpt {1250            is_partial_move: is_partial,1251            is_loop_message,1252            is_move_msg,1253            is_loop_move,1254            has_suggest_reborrow,1255            maybe_reinitialized_locations_is_empty,1256        } = msg_opt;1257        let mut suggested_cloning = false;1258        if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {1259            let place_name = self1260                .describe_place(moved_place.as_ref())1261                .map(|n| format!("`{n}`"))1262                .unwrap_or_else(|| "value".to_owned());1263            match kind {1264                CallKind::FnCall { fn_trait_id, self_ty }1265                    if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) =>1266                {1267                    err.subdiagnostic(CaptureReasonLabel::Call {1268                        fn_call_span,1269                        place_name: &place_name,1270                        is_partial,1271                        is_loop_message,1272                    });1273                    // Check if the move occurs on a value because of a call on a closure that comes1274                    // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:1275                    // ```1276                    // error[E0382]: use of moved value: `blk`1277                    //   --> $DIR/once-cant-call-twice-on-heap.rs:8:51278                    //    |1279                    // LL | fn foo<F:FnOnce()>(blk: F) {1280                    //    |                    --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait1281                    // LL | blk();1282                    //    | ----- `blk` moved due to this call1283                    // LL | blk();1284                    //    | ^^^ value used here after move1285                    //    |1286                    // note: `FnOnce` closures can only be called once1287                    //   --> $DIR/once-cant-call-twice-on-heap.rs:6:101288                    //    |1289                    // LL | fn foo<F:FnOnce()>(blk: F) {1290                    //    |        ^^^^^^^^ `F` is made to be an `FnOnce` closure here1291                    // LL | blk();1292                    //    | ----- this value implements `FnOnce`, which causes it to be moved when called1293                    // ```1294                    if let ty::Param(param_ty) = *self_ty.kind()1295                        && let generics = self.infcx.tcx.generics_of(self.mir_def_id())1296                        && let param = generics.type_param(param_ty, self.infcx.tcx)1297                        && let Some(hir_generics) = self.infcx.tcx.hir_get_generics(1298                            self.infcx.tcx.typeck_root_def_id_local(self.mir_def_id()),1299                        )1300                        && let spans = hir_generics1301                            .predicates1302                            .iter()1303                            .filter_map(|pred| match pred.kind {1304                                hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),1305                                _ => None,1306                            })1307                            .filter(|pred| {1308                                if let Some((id, _)) = pred.bounded_ty.as_generic_param() {1309                                    id == param.def_id1310                                } else {1311                                    false1312                                }1313                            })1314                            .flat_map(|pred| pred.bounds)1315                            .filter_map(|bound| {1316                                if let Some(trait_ref) = bound.trait_ref()1317                                    && let Some(trait_def_id) = trait_ref.trait_def_id()1318                                    && trait_def_id == fn_trait_id1319                                {1320                                    Some(bound.span())1321                                } else {1322                                    None1323                                }1324                            })1325                            .collect::<Vec<Span>>()1326                        && !spans.is_empty()1327                    {1328                        let mut span: MultiSpan = spans.clone().into();1329                        let msg = msg!("`{$ty}` is made to be an `FnOnce` closure here")1330                            .arg("ty", param_ty.to_string())1331                            .format();1332                        for sp in spans {1333                            span.push_span_label(sp, msg.clone());1334                        }1335                        span.push_span_label(1336                            fn_call_span,1337                            msg!("this value implements `FnOnce`, which causes it to be moved when called"),1338                        );1339                        err.span_note(span, msg!("`FnOnce` closures can only be called once"));1340                    } else {1341                        err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });1342                    }1343                }1344                CallKind::Operator { self_arg, trait_id, .. } => {1345                    let self_arg = self_arg.unwrap();1346                    err.subdiagnostic(CaptureReasonLabel::OperatorUse {1347                        fn_call_span,1348                        place_name: &place_name,1349                        is_partial,1350                        is_loop_message,1351                    });1352                    if self.fn_self_span_reported.insert(fn_span) {1353                        let lang = self.infcx.tcx.lang_items();1354                        err.subdiagnostic(1355                            if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]1356                                .contains(&Some(trait_id))1357                            {1358                                CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }1359                            } else {1360                                CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }1361                            },1362                        );1363                    }1364                }1365                CallKind::Normal { self_arg, desugaring, method_did, method_args } => {1366                    let self_arg = self_arg.unwrap();1367                    let mut has_sugg = false;1368                    let tcx = self.infcx.tcx;1369                    // Avoid pointing to the same function in multiple different1370                    // error messages.1371                    if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {1372                        self.explain_iterator_advancement_in_for_loop_if_applicable(1373                            err,1374                            span,1375                            &move_spans,1376                        );13771378                        let func = with_no_trimmed_paths!(tcx.def_path_str(method_did));1379                        if let Some((kind, _)) = desugaring {1380                            err.subdiagnostic(CaptureReasonNote::DesugaringFuncTakeSelf {1381                                func,1382                                desugar_name: kind.name(),1383                                place_name: place_name.clone(),1384                                span: self_arg.span,1385                            });1386                        } else {1387                            err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {1388                                func,1389                                place_name: place_name.clone(),1390                                span: self_arg.span,1391                            });1392                        }1393                    }1394                    let parent_did = tcx.parent(method_did);1395                    let parent_self_ty =1396                        matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })1397                            .then_some(parent_did)1398                            .and_then(|did| {1399                                match tcx.type_of(did).instantiate_identity().skip_norm_wip().kind()1400                                {1401                                    ty::Adt(def, ..) => Some(def.did()),1402                                    _ => None,1403                                }1404                            });1405                    let is_option_or_result = parent_self_ty.is_some_and(|def_id| {1406                        matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))1407                    });1408                    if is_option_or_result && maybe_reinitialized_locations_is_empty {1409                        err.subdiagnostic(CaptureReasonLabel::BorrowContent {1410                            var_span: var_span.shrink_to_hi(),1411                        });1412                    }1413                    if let Some((1414                        kind @ (CallDesugaringKind::ForLoopIntoIter1415                        | CallDesugaringKind::ForLoopIntoAsyncIter),1416                        _,1417                    )) = desugaring1418                    {1419                        let ty = moved_place.ty(self.body, tcx).ty;1420                        let def_id = kind.trait_def_id(tcx);1421                        let suggest = type_known_to_meet_bound_modulo_regions(1422                            self.infcx,1423                            self.infcx.param_env,1424                            Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),1425                            def_id,1426                        );1427                        if suggest {1428                            err.subdiagnostic(CaptureReasonSuggest::IterateSlice {1429                                ty,1430                                span: move_span.shrink_to_lo(),1431                            });1432                        }14331434                        match kind {1435                            CallDesugaringKind::ForLoopIntoIter => {1436                                err.subdiagnostic(CaptureReasonLabel::ImplicitCall {1437                                    fn_call_span,1438                                    place_name: &place_name,1439                                    is_partial,1440                                    is_loop_message,1441                                });1442                            }1443                            CallDesugaringKind::ForLoopIntoAsyncIter => {1444                                err.subdiagnostic(CaptureReasonLabel::ImplicitAsyncCall {1445                                    fn_call_span,1446                                    place_name: &place_name,1447                                    is_partial,1448                                    is_loop_message,1449                                });1450                            }1451                            _ => {}1452                        }1453                        // If the moved place was a `&mut` ref, then we can1454                        // suggest to reborrow it where it was moved, so it1455                        // will still be valid by the time we get to the usage.1456                        if let ty::Ref(_, _, hir::Mutability::Mut) =1457                            moved_place.ty(self.body, self.infcx.tcx).ty.kind()1458                        {1459                            // The `&mut *place` reborrow suggestion is `MachineApplicable`, so1460                            // only offer it where `*place` can be borrowed mutably: a value1461                            // captured by an `Fn` closure (held via `&self`) cannot, and the1462                            // suggestion would otherwise fail to compile with E0596.1463                            let reborrow_place = self.infcx.tcx.mk_place_deref(moved_place);1464                            let reborrow_is_valid = self1465                                .is_mutable(reborrow_place.as_ref(), LocalMutationIsAllowed::No)1466                                .is_ok();1467                            // Suggest `reborrow` in other place for following situations:1468                            // 1. If we are in a loop this will be suggested later.1469                            // 2. If the moved value is a mut reference, it is used in a1470                            // generic function and the corresponding arg's type is generic param.1471                            if !is_loop_move && !has_suggest_reborrow && reborrow_is_valid {1472                                self.suggest_reborrow(1473                                    err,1474                                    move_span.shrink_to_lo(),1475                                    moved_place.as_ref(),1476                                );1477                            }1478                        }1479                    } else {1480                        match desugaring {1481                            Some((CallDesugaringKind::Await, _)) => {1482                                err.subdiagnostic(CaptureReasonLabel::Await {1483                                    fn_call_span,1484                                    place_name: &place_name,1485                                    is_partial,1486                                    is_loop_message,1487                                });1488                            }1489                            Some((CallDesugaringKind::QuestionBranch, _)) => {1490                                err.subdiagnostic(CaptureReasonLabel::QuestionMark {1491                                    fn_call_span,1492                                    place_name: &place_name,1493                                    is_partial,1494                                    is_loop_message,1495                                });1496                            }1497                            _ => {1498                                err.subdiagnostic(CaptureReasonLabel::MethodCall {1499                                    fn_call_span,1500                                    place_name: &place_name,1501                                    is_partial,1502                                    is_loop_message,1503                                });1504                            }1505                        }1506                        // Erase and shadow everything that could be passed to the new infcx.1507                        let ty = moved_place.ty(self.body, tcx).ty;15081509                        if let ty::Adt(def, args) = ty.peel_refs().kind()1510                            && tcx.is_lang_item(def.did(), LangItem::Pin)1511                            && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()1512                            && let self_ty = self.infcx.instantiate_binder_with_fresh_vars(1513                                fn_call_span,1514                                BoundRegionConversionTime::FnCall,1515                                tcx.fn_sig(method_did)1516                                    .instantiate(tcx, method_args)1517                                    .skip_norm_wip()1518                                    .input(0),1519                            )1520                            && self.infcx.can_eq(self.infcx.param_env, ty, self_ty)1521                        {1522                            err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {1523                                span: move_span.shrink_to_hi(),1524                            });1525                            has_sugg = true;1526                        }1527                        if let Some(clone_trait) = tcx.lang_items().clone_trait() {1528                            // Check whether the deref is from a custom Deref impl1529                            // (e.g. Rc, Box) or a built-in reference deref.1530                            // For built-in derefs with Clone fully satisfied, we skip1531                            // the UFCS suggestion here and let `suggest_cloning`1532                            // downstream emit a simpler `.clone()` suggestion instead.1533                            let has_overloaded_deref =1534                                moved_place.iter_projections().any(|(place, elem)| {1535                                    matches!(elem, ProjectionElem::Deref)1536                                        && matches!(1537                                            self.borrowed_content_source(place),1538                                            BorrowedContentSource::OverloadedDeref(_)1539                                                | BorrowedContentSource::OverloadedIndex(_)1540                                        )1541                                });15421543                            let has_deref = moved_place1544                                .iter_projections()1545                                .any(|(_, elem)| matches!(elem, ProjectionElem::Deref));15461547                            let sugg = if has_deref {1548                                let (start, end) = if let Some(expr) = self.find_expr(move_span)1549                                    && let Some(_) = self.clone_on_reference(expr)1550                                    && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind1551                                {1552                                    (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))1553                                } else {1554                                    (move_span.shrink_to_lo(), move_span.shrink_to_hi())1555                                };1556                                vec![1557                                    // We use the fully-qualified path because `.clone()` can1558                                    // sometimes choose `<&T as Clone>` instead of `<T as Clone>`1559                                    // when going through auto-deref, so this ensures that doesn't1560                                    // happen, causing suggestions for `.clone().clone()`.1561                                    (start, format!("<{ty} as Clone>::clone(&")),1562                                    (end, ")".to_string()),1563                                ]1564                            } else {1565                                vec![(move_span.shrink_to_hi(), ".clone()".to_string())]1566                            };1567                            if let Some(errors) = self.infcx.type_implements_trait_shallow(1568                                clone_trait,1569                                ty,1570                                self.infcx.param_env,1571                            ) && !has_sugg1572                            {1573                                let skip_for_simple_clone =1574                                    has_deref && !has_overloaded_deref && errors.no_errors();1575                                if !skip_for_simple_clone {1576                                    let msg = match errors.as_slice() {1577                                        [] => "you can `clone` the value and consume it, but \1578                                               this might not be your desired behavior"1579                                            .to_string(),1580                                        [error] => {1581                                            format!(1582                                                "you could `clone` the value and consume it, if \1583                                                 the `{}` trait bound could be satisfied",1584                                                error.obligation.predicate,1585                                            )1586                                        }1587                                        _ => {1588                                            format!(1589                                                "you could `clone` the value and consume it, if \1590                                                 the following trait bounds could be satisfied: \1591                                                 {}",1592                                                listify(1593                                                    errors.as_slice(),1594                                                    |e: &FulfillmentError<'tcx>| format!(1595                                                        "`{}`",1596                                                        e.obligation.predicate1597                                                    )1598                                                )1599                                                .unwrap(),1600                                            )1601                                        }1602                                    };1603                                    err.multipart_suggestion(1604                                        msg,1605                                        sugg,1606                                        Applicability::MaybeIncorrect,1607                                    );16081609                                    suggested_cloning = errors.no_errors();16101611                                    for error in errors {1612                                        if let FulfillmentErrorCode::Select(1613                                            SelectionError::Unimplemented,1614                                        ) = error.code1615                                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(1616                                                pred,1617                                            )) = error.obligation.predicate.kind().skip_binder()1618                                        {1619                                            self.infcx.err_ctxt().suggest_derive(1620                                                &error.obligation,1621                                                err,1622                                                error.obligation.predicate.kind().rebind(pred),1623                                            );1624                                        }1625                                    }1626                                }1627                            }1628                        }1629                    }1630                }1631                // Other desugarings takes &self, which cannot cause a move1632                _ => {}1633            }1634        } else {1635            if move_span != span || is_loop_message {1636                err.subdiagnostic(CaptureReasonLabel::MovedHere {1637                    move_span,1638                    is_partial,1639                    is_move_msg,1640                    is_loop_message,1641                });1642            }1643            // If the move error occurs due to a loop, don't show1644            // another message for the same span1645            if !is_loop_message {1646                move_spans.var_subdiag(err, None, |kind, var_span| match kind {1647                    hir::ClosureKind::Coroutine(_) => {1648                        CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }1649                    }1650                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1651                        CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }1652                    }1653                })1654            }1655        }1656        if suggested_cloning { CloneSuggestion::Emitted } else { CloneSuggestion::NotEmitted }1657    }16581659    /// Skip over locals that begin with an underscore or have no name1660    pub(crate) fn local_excluded_from_unused_mut_lint(&self, index: Local) -> bool {1661        self.local_name(index).is_none_or(|name| name.as_str().starts_with('_'))1662    }1663}16641665const LIMITATION_NOTE: DiagMessage =1666    msg!("due to a current limitation of the type system, this implies a `'static` lifetime");

Code quality findings 67

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if let Some(prev_name) = local_names[local]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
local_names[local] = Some(var_debug_info.name);
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
for stmt in &self.body[location.block].statements[location.statement_index..] {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let terminator = self.body[location.block].terminator();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
place.local_or_deref_local().unwrap()
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
&& let ty::Closure(did, _) = self.body.local_decls[target].ty.kind()
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if self.body.local_decls[local]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if self.body.local_decls[local].is_ref_for_guard() {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
*self.body.local_decls[local].local_info()
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
buf = self.upvars[var_index].to_string(self.infcx.tcx);
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if !self.upvars[var_index].is_by_ref() {
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
if index >= autoderef_index.unwrap() {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
buf = self.upvars[field.index()].to_string(self.infcx.tcx);
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let decl = &self.body.local_decls[local];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
Some(variant.fields[field].name.to_string())
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// We know the field exists so it's safe to call operator[] and `unwrap` here.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
for i in &self.move_data.init_path_map[mpi] {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let init = &self.move_data.inits[*i];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let bbd = &self.body[loc.block];
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
ty.print(&mut p).unwrap();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
region.print(&mut p).unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let args = args.no_bound_vars().unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// Tracks whether [`MirBorrowckCtxt::explain_captures`] emitted a clone
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
temp.as_local().unwrap()
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
}) = &self.body[location.block].terminator
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.infcx.tcx.fn_arg_idents(method_did)[0],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.body[location.block].statements.get(location.statement_index)
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.body[location.block].terminator().kind
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.body[drop_target].statements.first()
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
self.body[location.block].statements[location.statement_index + 1..].iter();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// error[E0382]: use of moved value: `blk`
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let self_arg = self_arg.unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let self_arg = self_arg.unwrap();
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
.unwrap(),
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
self.buffered_diags.push(BufferedDiag::NonError(diag));
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
self.buffered_diags.push(BufferedDiag::Error(diag));
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match from {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let closure = match args.first() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match elem {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match self.local_name(local) {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match region.kind() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match region.kind() {
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use CaptureVarPathUseCause::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::InitializationRequiringAction::*;
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *self {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *self {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *self {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *self {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *self {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *func.kind() {
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use self::UseSpans::*;
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let target_temp = match stmt.kind {
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use self::UseSpans::*;
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let (&def_id, is_coroutine) = match kind {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.filter_map(|pred| match pred.kind {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
let mut span: MultiSpan = spans.clone().into();
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
.arg("ty", param_ty.to_string())
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
span.push_span_label(sp, msg.clone());
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match tcx.type_of(did).instantiate_identity().skip_norm_wip().kind()

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.