//! immutable "borrow kind" (see `ty::BorrowKind` for details) and then
//! "escalating" the kind as needed. The borrow kind proceeds according to
//! the following lattice:
-//!
-//! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
-//!
+//! ```ignore (not-rust)
+//! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
+//! ```
//! So, for example, if we see an assignment `x = 5` to an upvar `x`, we
//! will promote its borrow kind to mutable borrow. If we see an `&mut x`
//! we'll do the same. Naturally, this applies not just to the upvar, but
use super::FnCtxt;
use crate::expr_use_visitor as euv;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
};
use rustc_session::lint;
use rustc_span::sym;
-use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol};
+use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_data_structures::stable_map::FxHashMap;
/// the existing min_capture map that is stored in TypeckResults.
///
/// Eg:
- /// ```rust,no_run
+ /// ```
+ /// #[derive(Debug)]
/// struct Point { x: i32, y: i32 }
///
- /// let s: String; // hir_id_s
- /// let mut p: Point; // his_id_p
+ /// let s = String::from("s"); // hir_id_s
+ /// let mut p = Point { x: 2, y: -2 }; // his_id_p
/// let c = || {
- /// println!("{s}"); // L1
+ /// println!("{s:?}"); // L1
/// p.x += 10; // L2
/// println!("{}" , p.y); // L3
- /// println!("{p}"); // L4
+ /// println!("{p:?}"); // L4
/// drop(s); // L5
/// };
/// ```
///
/// InferBorrowKind results in a structure like this:
///
- /// ```text
+ /// ```ignore (illustrative)
/// {
/// Place(base: hir_id_s, projections: [], ....) -> {
/// capture_kind_expr: hir_id_L5,
/// path_expr_id: hir_id_L4,
/// capture_kind: ByValue
/// },
+ /// }
/// ```
///
/// After the min capture analysis, we get:
- /// ```text
+ /// ```ignore (illustrative)
/// {
/// hir_id_s -> [
/// Place(base: hir_id_s, projections: [], ....) -> {
/// capture_kind: ByValue
/// },
/// ],
+ /// }
/// ```
fn compute_min_captures(
&self,
diagnostics_builder.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
&diagnostic_msg,
- format!("\n{}{};", indent, migration_string),
+ format!("\n{indent}{migration_string};"),
Applicability::MachineApplicable,
);
} else if line1.starts_with('{') {
diagnostics_builder.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
&diagnostic_msg,
- format!(" {};", migration_string),
+ format!(" {migration_string};"),
Applicability::MachineApplicable,
);
} else {
diagnostics_builder.multipart_suggestion(
&diagnostic_msg,
vec![
- (closure_body_span.shrink_to_lo(), format!("{{ {}; ", migration_string)),
+ (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
(closure_body_span.shrink_to_hi(), " }".to_string()),
],
Applicability::MachineApplicable
reasons.auto_traits.extend(auto_trait_reasons);
reasons.drop_order = drop_order;
+ // `auto_trait_reasons` are in hashset order, so sort them to put the
+ // diagnostics we emit later in a cross-platform-consistent order.
+ reasons.auto_traits.sort_unstable();
+
reasons
}
/// - Ty(place): Type of place
/// - `(a, b)`: Represents the function parameters `base_path_ty` and `captured_by_move_projs`
/// respectively.
- /// ```
+ /// ```ignore (illustrative)
/// (Ty(w), [ &[p, x], &[c] ])
- /// |
- /// ----------------------------
- /// | |
- /// v v
+ /// // |
+ /// // ----------------------------
+ /// // | |
+ /// // v v
/// (Ty(w.p), [ &[x] ]) (Ty(w.c), [ &[] ]) // I(1)
- /// | |
- /// v v
+ /// // | |
+ /// // v v
/// (Ty(w.p), [ &[x] ]) false
- /// |
- /// |
- /// -------------------------------
- /// | |
- /// v v
+ /// // |
+ /// // |
+ /// // -------------------------------
+ /// // | |
+ /// // v v
/// (Ty((w.p).x), [ &[] ]) (Ty((w.p).y), []) // IMP 2
- /// | |
- /// v v
+ /// // | |
+ /// // v v
/// false NeedsSignificantDrop(Ty(w.p.y))
- /// |
- /// v
+ /// // |
+ /// // v
/// true
/// ```
///
///
/// Consider another example:
///
- /// ```rust
+ /// ```ignore (pseudo-rust)
/// struct X;
/// impl Drop for X {}
///
self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:");
for (place, capture_info) in capture_information {
let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
- let output_str = format!("Capturing {}", capture_str);
+ let output_str = format!("Capturing {capture_str}");
let span =
capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
let capture_str =
construct_capture_info_string(self.tcx, place, capture_info);
- let output_str = format!("Min Capture {}", capture_str);
+ let output_str = format!("Min Capture {capture_str}");
if capture.info.path_expr_id != capture.info.capture_kind_expr_id {
let path_span = capture_info
/// s.str2 via a MutableBorrow
///
/// ```rust,no_run
- /// struct SomeStruct { str1: String, str2: String }
+ /// struct SomeStruct { str1: String, str2: String };
///
/// // Assume that the HirId for the variable definition is `V1`
- /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") }
+ /// let mut s = SomeStruct { str1: format!("s1"), str2: format!("s2") };
///
/// let fix_s = |new_s2| {
/// // Assume that the HirId for the expression `s.str1` is `E1`
- /// println!("Updating SomeStruct with str1=", s.str1);
+ /// println!("Updating SomeStruct with str1={0}", s.str1);
/// // Assume that the HirId for the expression `*s.str2` is `E2`
/// s.str2 = new_s2;
/// };
///
/// For closure `fix_s`, (at a high level) the map contains
///
- /// ```
+ /// ```ignore (illustrative)
/// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow }
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
/// ```
projections_str.push_str(proj.as_str());
}
- format!("{}[{}]", variable_name, projections_str)
+ format!("{variable_name}[{projections_str}]")
}
fn construct_capture_kind_reason_string<'tcx>(
ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
};
- format!("{} captured as {} here", place_str, capture_kind_str)
+ format!("{place_str} captured as {capture_kind_str} here")
}
fn construct_path_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
let place_str = construct_place_string(tcx, place);
- format!("{} used here", place_str)
+ format!("{place_str} used here")
}
fn construct_capture_info_string<'tcx>(
ty::UpvarCapture::ByValue => "ByValue".into(),
ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
};
- format!("{} -> {}", place_str, capture_kind_str)
+ format!("{place_str} -> {capture_kind_str}")
}
fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
.collect::<Vec<_>>();
let migration_ref_concat =
- need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", ");
+ need_migrations_variables.iter().map(|v| format!("&{v}")).collect::<Vec<_>>().join(", ");
let migration_string = if 1 == need_migrations.len() {
- format!("let _ = {}", migration_ref_concat)
+ format!("let _ = {migration_ref_concat}")
} else {
- format!("let _ = ({})", migration_ref_concat)
+ format!("let _ = ({migration_ref_concat})")
};
let migrated_variables_concat =
- need_migrations_variables.iter().map(|v| format!("`{}`", v)).collect::<Vec<_>>().join(", ");
+ need_migrations_variables.iter().map(|v| format!("`{v}`")).collect::<Vec<_>>().join(", ");
(migration_string, migrated_variables_concat)
}
/// Consider the following example
/// ```rust,no_run
/// struct Point { x: i32, y: i32 }
-/// let mut p: Point { x: 10, y: 10 };
+/// let mut p = Point { x: 10, y: 10 };
///
/// let c = || {
/// p.x += 10;
///
/// Reason we only drop the last deref is because of the following edge case:
///
-/// ```rust
+/// ```
+/// # struct A { field_of_a: Box<i32> }
+/// # struct B {}
+/// # struct C<'a>(&'a i32);
/// struct MyStruct<'a> {
/// a: &'static A,
/// b: B,
/// }
///
/// fn foo<'a, 'b>(m: &'a MyStruct<'b>) -> impl FnMut() + 'static {
-/// let c = || drop(&*m.a.field_of_a);
+/// || drop(&*m.a.field_of_a)
/// // Here we really do want to capture `*m.a` because that outlives `'static`
///
/// // If we capture `m`, then the closure no longer outlives `'static'