/// local place can be mutated.
//
// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
-// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`.
// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
// `is_declared_mutable()`.
// - Take flow state into consideration in `is_assignable()` for local variables.
// Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
- // Special case: you can assign an immutable local variable
- // (e.g., `x = ...`) so long as it has never been initialized
- // before (at this point in the flow).
- if let Some(local) = place_span.0.as_local() {
- if let Mutability::Not = self.body.local_decls[local].mutability {
- // check for reassignments to immutable local variables
- self.check_if_reassignment_to_immutable_state(
- location, local, place_span, flow_state,
- );
- return;
- }
- }
-
- // Otherwise, use the normal access permission rules.
self.access_place(
location,
place_span,
}
}
- fn check_if_reassignment_to_immutable_state(
- &mut self,
- location: Location,
- local: Local,
- place_span: (Place<'tcx>, Span),
- flow_state: &Flows<'cx, 'tcx>,
- ) {
- debug!("check_if_reassignment_to_immutable_state({:?})", local);
-
- // Check if any of the initializations of `local` have happened yet:
- if let Some(init_index) = self.is_local_ever_initialized(local, flow_state) {
- // And, if so, report an error.
- let init = &self.move_data.inits[init_index];
- let span = init.span(&self.body);
- self.report_illegal_reassignment(location, place_span, span, place_span.0);
- }
- }
-
fn check_if_full_path_is_moved(
&mut self,
location: Location,
// partial initialization, do not complain about mutability
// errors except for actual mutation (as opposed to an attempt
// to do a partial initialization).
- let previously_initialized =
- self.is_local_ever_initialized(place.local, flow_state).is_some();
+ let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
// at this point, we have set up the error reporting state.
- if previously_initialized {
- self.report_mutability_error(place, span, the_place_err, error_access, location);
+ if let Some(init_index) = previously_initialized {
+ if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
+ // If this is a mutate access to an immutable local variable with no projections
+ // report the error as an illegal reassignment
+ let init = &self.move_data.inits[init_index];
+ let assigned_span = init.span(&self.body);
+ self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+ } else {
+ self.report_mutability_error(place, span, the_place_err, error_access, location)
+ }
true
} else {
false
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
+ buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
/// Diagnostics to be reported buffer.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
BorrowckErrors {
tcx,
buffered_move_errors: BTreeMap::new(),
+ buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
}
}
}
+ pub fn get_buffered_mut_error(
+ &mut self,
+ span: Span,
+ ) -> Option<(DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)> {
+ self.errors.buffered_mut_errors.remove(&span)
+ }
+
+ pub fn buffer_mut_error(
+ &mut self,
+ span: Span,
+ t: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ count: usize,
+ ) {
+ self.errors.buffered_mut_errors.insert(span, (t, count));
+ }
+
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
diag.buffer(&mut self.errors.buffered);
}
+ for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
+ if count > 10 {
+ diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ }
+ diag.buffer(&mut self.errors.buffered);
+ }
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);