summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src')
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs2
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs64
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs306
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs18
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs16
-rw-r--r--compiler/rustc_borrowck/src/lib.rs44
-rw-r--r--compiler/rustc_borrowck/src/nll.rs6
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs8
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs3
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs9
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs23
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs7
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs19
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs90
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs9
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs48
19 files changed, 431 insertions, 260 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 0b44beeb0..5248a649c 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -71,7 +71,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self.kind {
mir::BorrowKind::Shared => "",
- mir::BorrowKind::Shallow => "shallow ",
+ mir::BorrowKind::Fake => "fake ",
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
// FIXME: differentiate `TwoPhaseBorrow`
mir::BorrowKind::Mut {
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index b719a610e..95db93742 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -49,7 +49,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
// cross suspension points so this behavior is unproblematic.
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
- PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) |
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
// contain dangling references.
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index fe4a45b38..ee352e911 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1025,7 +1025,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
}
- (BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
+ (BorrowKind::Mut { .. }, BorrowKind::Fake) => {
if let Some(immutable_section_description) =
self.classify_immutable_section(issued_borrow.assigned_place)
{
@@ -1117,11 +1117,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
}
- (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
- | (
- BorrowKind::Shallow,
- BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
- ) => unreachable!(),
+ (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake)
+ | (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => {
+ unreachable!()
+ }
};
if issued_spans == borrow_spans {
@@ -2130,21 +2129,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
/// We could expand the analysis to suggest hoising all of the relevant parts of
/// the users' code to make the code compile, but that could be too much.
- struct NestedStatementVisitor {
+ /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
+ /// which is a special case since it's generated by the compiler.
+ struct NestedStatementVisitor<'tcx> {
span: Span,
current: usize,
found: usize,
+ prop_expr: Option<&'tcx hir::Expr<'tcx>>,
}
- impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
- fn visit_block(&mut self, block: &hir::Block<'tcx>) {
+ impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
+ fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
self.current += 1;
walk_block(self, block);
self.current -= 1;
}
- fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if self.span == expr.span.source_callsite() {
self.found = self.current;
+ if self.prop_expr.is_none() {
+ self.prop_expr = Some(expr);
+ }
}
walk_expr(self, expr);
}
@@ -2162,22 +2167,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span: proper_span,
current: 0,
found: 0,
+ prop_expr: None,
};
visitor.visit_stmt(stmt);
+
+ let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
+ let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
+
+ let is_format_arguments_item =
+ if let Some(expr_ty) = expr_ty
+ && let ty::Adt(adt, _) = expr_ty.kind() {
+ self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
+ } else {
+ false
+ };
+
if visitor.found == 0
&& stmt.span.contains(proper_span)
&& let Some(p) = sm.span_to_margin(stmt.span)
&& let Ok(s) = sm.span_to_snippet(proper_span)
{
- let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
- err.multipart_suggestion_verbose(
- msg,
- vec![
- (stmt.span.shrink_to_lo(), addition),
- (proper_span, "binding".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
+ if !is_format_arguments_item {
+ let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
+ err.multipart_suggestion_verbose(
+ msg,
+ vec![
+ (stmt.span.shrink_to_lo(), addition),
+ (proper_span, "binding".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used");
+ err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
+ }
suggested = true;
break;
}
@@ -2620,7 +2643,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let loan_span = loan_spans.args_or_use();
let descr_place = self.describe_any_place(place.as_ref());
- if loan.kind == BorrowKind::Shallow {
+ if loan.kind == BorrowKind::Fake {
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
let mut err = self.cannot_mutate_in_immutable_section(
span,
@@ -2804,6 +2827,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => kind,
},
place_ty.projection_ty(tcx, elem),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 099e07e88..8d4028de9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,7 +13,7 @@ use rustc_index::IndexSlice;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
- AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
+ AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
};
@@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let terminator = self.body[location.block].terminator();
debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
if let TerminatorKind::Call {
- func: Operand::Constant(box Constant { literal, .. }),
+ func: Operand::Constant(box ConstOperand { const_, .. }),
args,
..
} = &terminator.kind
{
- if let ty::FnDef(id, _) = *literal.ty().kind() {
+ if let ty::FnDef(id, _) = *const_.ty().kind() {
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
let closure = match args.first() {
@@ -242,6 +242,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (),
+ ProjectionElem::Subtype(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -322,7 +323,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
- ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
+ ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
+ PlaceTy::from_ty(*ty)
+ }
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
@@ -628,7 +631,7 @@ impl UseSpans<'_> {
err.subdiagnostic(match kind {
Some(kd) => match kd {
rustc_middle::mir::BorrowKind::Shared
- | rustc_middle::mir::BorrowKind::Shallow => {
+ | rustc_middle::mir::BorrowKind::Fake => {
CaptureVarKind::Immut { kind_span: capture_kind_span }
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index d62541daf..8ca57383e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,9 +1,10 @@
+use hir::ExprKind;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -158,6 +159,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
[
..,
ProjectionElem::Index(_)
+ | ProjectionElem::Subtype(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
@@ -225,17 +227,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
if suggest {
borrow_spans.var_subdiag(
- None,
- &mut err,
- Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
- |_kind, var_span| {
- let place = self.describe_any_place(access_place.as_ref());
- crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
- place,
- var_span,
- }
- },
- );
+ None,
+ &mut err,
+ Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
+ |_kind, var_span| {
+ let place = self.describe_any_place(access_place.as_ref());
+ crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
+ place,
+ var_span,
+ }
+ },
+ );
}
borrow_span
}
@@ -262,11 +264,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} => {
err.span_label(span, format!("cannot {act}"));
- if let Some(span) = get_mut_span_in_struct_field(
- self.infcx.tcx,
- Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
- *field,
- ) {
+ let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx);
+ if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) {
err.span_suggestion_verbose(
span,
"consider changing this to be mutable",
@@ -373,12 +372,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_label(span, format!("cannot {act}"));
}
if suggest {
- err.span_suggestion_verbose(
- local_decl.source_info.span.shrink_to_lo(),
- "consider changing this to be mutable",
- "mut ",
- Applicability::MachineApplicable,
- );
+ self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
let tcx = self.infcx.tcx;
if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
@@ -494,6 +488,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
),
);
+ self.suggest_using_iter_mut(&mut err);
self.suggest_make_local_mut(&mut err, local, name);
}
_ => {
@@ -713,6 +708,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
)
}
+ fn construct_mut_suggestion_for_local_binding_patterns(
+ &self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ local: Local,
+ ) {
+ let local_decl = &self.body.local_decls[local];
+ debug!("local_decl: {:?}", local_decl);
+ let pat_span = match *local_decl.local_info() {
+ LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+ opt_ty_info: _,
+ opt_match_place: _,
+ pat_span,
+ })) => pat_span,
+ _ => local_decl.source_info.span,
+ };
+
+ struct BindingFinder {
+ span: Span,
+ hir_id: Option<hir::HirId>,
+ }
+
+ impl<'tcx> Visitor<'tcx> for BindingFinder {
+ fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+ if let hir::StmtKind::Local(local) = s.kind {
+ if local.pat.span == self.span {
+ self.hir_id = Some(local.hir_id);
+ }
+ }
+ hir::intravisit::walk_stmt(self, s);
+ }
+ }
+
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = if let Some(local_def_id) = def_id.as_local()
+ && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id)
+ {
+ let body = hir_map.body(body_id);
+ let mut v = BindingFinder {
+ span: pat_span,
+ hir_id: None,
+ };
+ v.visit_body(body);
+ v.hir_id
+ } else {
+ None
+ };
+
+ // With ref-binding patterns, the mutability suggestion has to apply to
+ // the binding, not the reference (which would be a type error):
+ //
+ // `let &b = a;` -> `let &(mut b) = a;`
+ if let Some(hir_id) = hir_id
+ && let Some(hir::Node::Local(hir::Local {
+ pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
+ ..
+ })) = hir_map.find(hir_id)
+ && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
+ {
+ err.span_suggestion(
+ pat_span,
+ "consider changing this to be mutable",
+ format!("&(mut {name})"),
+ Applicability::MachineApplicable,
+ );
+ return;
+ }
+
+ err.span_suggestion_verbose(
+ local_decl.source_info.span.shrink_to_lo(),
+ "consider changing this to be mutable",
+ "mut ",
+ Applicability::MachineApplicable,
+ );
+ }
+
// point to span of upvar making closure call require mutable borrow
fn show_mutating_upvar(
&self,
@@ -781,83 +853,88 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Attempt to search similar mutable associated items for suggestion.
// In the future, attempt in all path but initially for RHS of for_loop
- fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic) {
+ fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) {
use hir::{
- Expr,
- ExprKind::{Block, Call, DropTemps, Match, MethodCall},
+ BorrowKind, Expr,
+ ExprKind::{AddrOf, Block, Call, MethodCall},
};
let hir_map = self.infcx.tcx.hir();
- if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id()) {
- if let Block(
- hir::Block {
- expr:
- Some(Expr {
- kind:
- DropTemps(Expr {
- kind:
- Match(
- Expr {
- kind:
- Call(
- _,
- [
- Expr {
- kind:
- MethodCall(path_segment, _, _, span),
- hir_id,
- ..
- },
- ..,
- ],
- ),
- ..
- },
- ..,
- ),
- ..
- }),
- ..
- }),
- ..
- },
- _,
- ) = hir_map.body(body_id).value.kind
- {
- let opt_suggestions = self
- .infcx
- .tcx
- .typeck(path_segment.hir_id.owner.def_id)
- .type_dependent_def_id(*hir_id)
- .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
- .map(|def_id| self.infcx.tcx.associated_items(def_id))
- .map(|assoc_items| {
- assoc_items
- .in_definition_order()
- .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
- .filter(|&ident| {
- let original_method_ident = path_segment.ident;
- original_method_ident != ident
- && ident
- .as_str()
- .starts_with(&original_method_ident.name.to_string())
- })
- .map(|ident| format!("{ident}()"))
- .peekable()
- });
+ struct Finder<'tcx> {
+ span: Span,
+ expr: Option<&'tcx Expr<'tcx>>,
+ }
- if let Some(mut suggestions) = opt_suggestions
- && suggestions.peek().is_some()
- {
- err.span_suggestions(
- *span,
- "use mutable method",
- suggestions,
- Applicability::MaybeIncorrect,
- );
+ impl<'tcx> Visitor<'tcx> for Finder<'tcx> {
+ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
+ if e.span == self.span && self.expr.is_none() {
+ self.expr = Some(e);
}
+ hir::intravisit::walk_expr(self, e);
}
- };
+ }
+ if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
+ && let Block(block, _) = hir_map.body(body_id).value.kind
+ {
+ // `span` corresponds to the expression being iterated, find the `for`-loop desugared
+ // expression with that span in order to identify potential fixes when encountering a
+ // read-only iterator that should be mutable.
+ let mut v = Finder {
+ span,
+ expr: None,
+ };
+ v.visit_block(block);
+ if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind {
+ match expr.kind {
+ MethodCall(path_segment, _, _, span) => {
+ // We have `for _ in iter.read_only_iter()`, try to
+ // suggest `for _ in iter.mutable_iter()` instead.
+ let opt_suggestions = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner.def_id)
+ .type_dependent_def_id(expr.hir_id)
+ .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+ .map(|def_id| self.infcx.tcx.associated_items(def_id))
+ .map(|assoc_items| {
+ assoc_items
+ .in_definition_order()
+ .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
+ .filter(|&ident| {
+ let original_method_ident = path_segment.ident;
+ original_method_ident != ident
+ && ident.as_str().starts_with(
+ &original_method_ident.name.to_string(),
+ )
+ })
+ .map(|ident| format!("{ident}()"))
+ .peekable()
+ });
+
+ if let Some(mut suggestions) = opt_suggestions
+ && suggestions.peek().is_some()
+ {
+ err.span_suggestions(
+ span,
+ "use mutable method",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ AddrOf(BorrowKind::Ref, Mutability::Not, expr) => {
+ // We have `for _ in &i`, suggest `for _ in &mut i`.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "use a mutable iterator instead",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ _ => {}
+ }
+ }
+ }
}
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
@@ -951,6 +1028,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
+ fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) {
+ let source = self.body.source;
+ let hir = self.infcx.tcx.hir();
+ if let InstanceDef::Item(def_id) = source.instance
+ && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id)
+ && let ExprKind::Closure(closure) = kind && closure.movability == None
+ && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) {
+ let mut cur_expr = expr;
+ while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
+ if path_segment.ident.name == sym::iter {
+ // check `_ty` has `iter_mut` method
+ let res = self
+ .infcx
+ .tcx
+ .typeck(path_segment.hir_id.owner.def_id)
+ .type_dependent_def_id(cur_expr.hir_id)
+ .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+ .map(|def_id| self.infcx.tcx.associated_items(def_id))
+ .map(|assoc_items| {
+ assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
+ });
+
+ if let Some(mut res) = res && res.peek().is_some() {
+ err.span_suggestion_verbose(
+ path_segment.ident.span,
+ "you may want to use `iter_mut` here",
+ "iter_mut",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ break;
+ } else {
+ cur_expr = recv;
+ }
+ }
+ }
+ }
+
fn suggest_make_local_mut(
&self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
@@ -1003,9 +1118,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
// on for loops, RHS points to the iterator part
Some(DesugaringKind::ForLoop) => {
- self.suggest_similar_mut_method_for_for_loop(err);
+ let span = opt_assignment_rhs_span.unwrap();
+ self.suggest_similar_mut_method_for_for_loop(err, span);
err.span_label(
- opt_assignment_rhs_span.unwrap(),
+ span,
format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
);
None
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 2ea399789..27072a60f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -245,7 +245,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; };
diag.span_note(
*trait_span,
- format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")
+ "due to current limitations in the borrow checker, this implies a `'static` lifetime"
);
let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; };
let Def(_, trait_res_defid) = trait_ref.path.res else { return; };
@@ -277,7 +277,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if suggestions.len() > 0 {
suggestions.dedup();
diag.multipart_suggestion_verbose(
- format!("consider restricting the type parameter to the `'static` lifetime"),
+ "consider restricting the type parameter to the `'static` lifetime",
suggestions,
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 337af89b2..55d581b3a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -27,7 +27,7 @@ pub(crate) struct RegionName {
/// This helps to print the right kinds of diagnostics.
#[derive(Debug, Clone)]
pub(crate) enum RegionNameSource {
- /// A bound (not free) region that was substituted at the def site (not an HRTB).
+ /// A bound (not free) region that was instantiated at the def site (not an HRTB).
NamedEarlyBoundRegion(Span),
/// A free region that the user has a name (`'a`) for.
NamedFreeRegion(Span),
@@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
if free_region.bound_region.is_named() {
// A named region that is actually named.
Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
- } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
+ } else if tcx.asyncness(self.mir_hir_id().owner).is_async() {
// If we spuriously thought that the region is named, we should let the
// system generate a true name for error messages. Currently this can
// happen if we have an elided name in an async fn for example: the
@@ -354,7 +354,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
})
}
- ty::BoundRegionKind::BrAnon(..) => None,
+ ty::BoundRegionKind::BrAnon => None,
},
ty::ReLateBound(..)
@@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
span: Span,
counter: usize,
) -> RegionNameHighlight {
- let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
- highlight.highlighting_region_vid(needle_fr, counter);
+ let mut highlight = RegionHighlightMode::default();
+ highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
let type_name =
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
@@ -516,7 +516,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// be the same as those of the ADT.
// FIXME: We should be able to do something similar to
// match_adt_and_segment in this case.
- Res::Def(DefKind::TyAlias { .. }, _) => (),
+ Res::Def(DefKind::TyAlias, _) => (),
_ => {
if let Some(last_segment) = path.segments.last() {
if let Some(highlight) = self.match_adt_and_segment(
@@ -619,7 +619,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// programs, so we need to use delay_span_bug here. See #82126.
self.infcx.tcx.sess.delay_span_bug(
hir_arg.span(),
- format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
+ format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
);
}
}
@@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
return None;
}
- let mut highlight = RegionHighlightMode::new(tcx);
- highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
+ let mut highlight = RegionHighlightMode::default();
+ highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
let type_name =
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index df5e383ad..2faf1a529 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -159,7 +159,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
self.mutate_place(location, *resume_arg, Deep);
}
- TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
+ TerminatorKind::UnwindResume
+ | TerminatorKind::Return
+ | TerminatorKind::GeneratorDrop => {
// Invalidate all borrows of local places
let borrow_set = self.borrow_set;
let start = self.location_table.start_index(location);
@@ -200,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
}
TerminatorKind::Goto { target: _ }
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Unreachable
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
@@ -251,8 +253,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
let access_kind = match bk {
- BorrowKind::Shallow => {
- (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
+ BorrowKind::Fake => {
+ (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Mut { .. } => {
@@ -374,8 +376,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
// have already taken the reservation
}
- (Read(_), BorrowKind::Shallow | BorrowKind::Shared)
- | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
+ (Read(_), BorrowKind::Fake | BorrowKind::Shared)
+ | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
// Reads don't invalidate shared or shallow borrows
}
@@ -420,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
- BorrowKind::Shared | BorrowKind::Shallow => false,
+ BorrowKind::Shared | BorrowKind::Fake => false,
BorrowKind::Mut { .. } => true,
});
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index efe525c22..1d17df8b7 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -11,7 +11,7 @@
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#[macro_use]
extern crate rustc_middle;
@@ -603,7 +603,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
fn visit_statement_before_primary_effect(
&mut self,
- _results: &R,
+ _results: &mut R,
flow_state: &Flows<'cx, 'tcx>,
stmt: &'cx Statement<'tcx>,
location: Location,
@@ -673,7 +673,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
fn visit_terminator_before_primary_effect(
&mut self,
- _results: &R,
+ _results: &mut R,
flow_state: &Flows<'cx, 'tcx>,
term: &'cx Terminator<'tcx>,
loc: Location,
@@ -770,9 +770,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
}
TerminatorKind::Goto { target: _ }
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Unreachable
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::Return
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
@@ -784,7 +784,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
fn visit_terminator_after_primary_effect(
&mut self,
- _results: &R,
+ _results: &mut R,
flow_state: &Flows<'cx, 'tcx>,
term: &'cx Terminator<'tcx>,
loc: Location,
@@ -803,7 +803,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
}
}
- TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
+ TerminatorKind::UnwindResume
+ | TerminatorKind::Return
+ | TerminatorKind::GeneratorDrop => {
// Returning from the function implicitly kills storage for all locals and statics.
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
@@ -815,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
}
}
- TerminatorKind::Terminate
+ TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Assert { .. }
| TerminatorKind::Call { .. }
| TerminatorKind::Drop { .. }
@@ -835,7 +837,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ArtificialField {
ArrayLength,
- ShallowBorrow,
+ FakeBorrow,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -1074,18 +1076,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Control::Continue
}
- (Read(_), BorrowKind::Shared | BorrowKind::Shallow)
- | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
+ (Read(_), BorrowKind::Shared | BorrowKind::Fake)
+ | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => {
Control::Continue
}
- (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
+ (Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => {
// This used to be a future compatibility warning (to be
// disallowed on NLL). See rust-lang/rust#56254
Control::Continue
}
- (Write(WriteKind::Move), BorrowKind::Shallow) => {
+ (Write(WriteKind::Move), BorrowKind::Fake) => {
// Handled by initialization checks.
Control::Continue
}
@@ -1193,8 +1195,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
let access_kind = match bk {
- BorrowKind::Shallow => {
- (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
+ BorrowKind::Fake => {
+ (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
}
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
BorrowKind::Mut { .. } => {
@@ -1215,7 +1217,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
flow_state,
);
- let action = if bk == BorrowKind::Shallow {
+ let action = if bk == BorrowKind::Fake {
InitializationRequiringAction::MatchOn
} else {
InitializationRequiringAction::Borrow
@@ -1567,7 +1569,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// only mutable borrows should be 2-phase
assert!(match borrow.kind {
- BorrowKind::Shared | BorrowKind::Shallow => false,
+ BorrowKind::Shared | BorrowKind::Fake => false,
BorrowKind::Mut { .. } => true,
});
@@ -1801,6 +1803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
for (place_base, elem) in place.iter_projections().rev() {
match elem {
ProjectionElem::Index(_/*operand*/) |
+ ProjectionElem::Subtype(_) |
ProjectionElem::OpaqueCast(_) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
@@ -2000,14 +2003,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
- | WriteKind::MutableBorrow(BorrowKind::Shallow),
+ | WriteKind::MutableBorrow(BorrowKind::Fake),
)
| Write(
WriteKind::Move
| WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
- | WriteKind::MutableBorrow(BorrowKind::Shallow),
+ | WriteKind::MutableBorrow(BorrowKind::Fake),
) => {
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
&& !self.has_buffered_errors()
@@ -2031,7 +2034,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return false;
}
Read(
- ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow)
+ ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake)
| ReadKind::Copy,
) => {
// Access authorized
@@ -2189,6 +2192,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::Subtype(..)
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 679a19710..3f60f5aca 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::{
Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
START_BLOCK,
};
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
use rustc_span::symbol::sym;
use std::env;
@@ -441,7 +442,10 @@ fn for_each_region_constraint<'tcx>(
let subject = match req.subject {
ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"),
ClosureOutlivesSubject::Ty(ty) => {
- format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)))
+ with_no_trimmed_paths!(format!(
+ "{}",
+ ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))
+ ))
}
};
with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?;
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index c02f6f3b6..777ebf0d4 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -204,7 +204,7 @@ fn place_components_conflict<'tcx>(
match (elem, &base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
- | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
+ | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
// The array length is like additional fields on the
// type; it does not overlap any existing data there.
// Furthermore, if cannot actually be a prefix of any
@@ -249,6 +249,7 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _)
+ | (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
@@ -272,10 +273,10 @@ fn place_components_conflict<'tcx>(
// If the second example, where we did, then we still know
// that the borrow can access a *part* of our place that
// our access cares about, so we still have a conflict.
- if borrow_kind == BorrowKind::Shallow
+ if borrow_kind == BorrowKind::Fake
&& borrow_place.projection.len() < access_place.projection.len()
{
- debug!("borrow_conflicts_with_place: shallow borrow");
+ debug!("borrow_conflicts_with_place: fake borrow");
false
} else {
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
@@ -508,6 +509,7 @@ fn place_projection_conflict<'tcx>(
| ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subtype(_)
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 6f2813498..e9c9709bd 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -89,6 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
cursor = cursor_base;
continue 'cursor;
}
+ ProjectionElem::Subtype(..) => {
+ panic!("Subtype projection is not allowed before borrow check")
+ }
ProjectionElem::Deref => {
// (handled below)
}
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b8cd94e54..852935676 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -2249,7 +2249,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
- self.universe_causes[&universe].clone()
+ // Query canonicalization can create local superuniverses (for example in
+ // `InferCtx::query_response_instantiation_guess`), but they don't have an associated
+ // `UniverseInfo` explaining why they were created.
+ // This can cause ICEs if these causes are accessed in diagnostics, for example in issue
+ // #114907 where this happens via liveness and dropck outlives results.
+ // Therefore, we return a default value in case that happens, which should at worst emit a
+ // suboptimal error, instead of the ICE.
+ self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other())
}
/// Tries to find the terminator of the loop in which the region 'r' resides.
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 4c69ea843..5d6f5cc89 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -4,11 +4,10 @@ use crate::BorrowckInferCtxt;
use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::Constant;
-use rustc_middle::mir::{Body, Location, Promoted};
+use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_span::{Span, Symbol};
+use rustc_span::Symbol;
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
@@ -30,20 +29,14 @@ pub fn renumber_mir<'tcx>(
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
-pub(crate) enum BoundRegionInfo {
- Name(Symbol),
- Span(Span),
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum RegionCtxt {
Location(Location),
TyContext(TyContext),
Free(Symbol),
- Bound(BoundRegionInfo),
- LateBound(BoundRegionInfo),
+ Bound(Symbol),
+ LateBound(Symbol),
Existential(Option<Symbol>),
- Placeholder(BoundRegionInfo),
+ Placeholder(Symbol),
Unknown,
}
@@ -117,9 +110,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
- let literal = constant.literal;
- constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
+ fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
+ let const_ = constant.const_;
+ constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
debug!("constant: {:#?}", constant);
}
}
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index d1d8cfa74..ca3ccf439 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -452,3 +452,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
#[note(borrowck_ty_no_impl_copy)]
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
}
+
+#[derive(Diagnostic)]
+#[diag(borrowck_simd_shuffle_last_const)]
+pub(crate) struct SimdShuffleLastConst {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 16f5e68a0..b7adc314f 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -9,7 +9,7 @@ use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use rustc_trait_selection::traits::ObligationCause;
-use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
+use crate::diagnostics::ToUniverseInfo;
use super::{Locations, NormalizeLocation, TypeChecker};
@@ -46,13 +46,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.push_region_constraints(locations, category, data);
}
+ // If the query has created new universes and errors are going to be emitted, register the
+ // cause of these new universes for improved diagnostics.
let universe = self.infcx.universe();
-
- if old_universe != universe {
- let universe_info = match error_info {
- Some(error_info) => error_info.to_universe_info(old_universe),
- None => UniverseInfo::other(),
- };
+ if old_universe != universe && let Some(error_info) = error_info {
+ let universe_info = error_info.to_universe_info(old_universe);
for u in (old_universe + 1)..=universe {
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
}
@@ -69,15 +67,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- let old_universe = self.infcx.universe();
-
let (instantiated, _) =
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
-
- for u in (old_universe + 1)..=self.infcx.universe() {
- self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
- }
-
instantiated
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 50d875dfa..1f383e533 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -50,7 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
-use crate::session_diagnostics::MoveUnsized;
+use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst};
use crate::{
borrow_set::BorrowSet,
constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -163,10 +163,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
debug!(?normalized_inputs_and_output);
- for u in ty::UniverseIndex::ROOT..=infcx.universe() {
- constraints.universe_causes.insert(u, UniverseInfo::other());
- }
-
let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
@@ -306,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
self.sanitize_place(place, location, context);
}
- fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+ fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
debug!(?constant, ?location, "visit_constant");
self.super_constant(constant, location);
- let ty = self.sanitize_type(constant, constant.literal.ty());
+ let ty = self.sanitize_type(constant, constant.const_.ty());
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
let live_region_vid =
@@ -332,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
if let Some(annotation_index) = constant.user_ty {
if let Err(terr) = self.cx.relate_type_and_user_type(
- constant.literal.ty(),
+ constant.const_.ty(),
ty::Variance::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
locations,
@@ -344,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
constant,
"bad constant user type {:?} vs {:?}: {:?}",
annotation,
- constant.literal.ty(),
+ constant.const_.ty(),
terr,
);
}
} else {
let tcx = self.tcx();
- let maybe_uneval = match constant.literal {
- ConstantKind::Ty(ct) => match ct.kind() {
+ let maybe_uneval = match constant.const_ {
+ Const::Ty(ct) => match ct.kind() {
ty::ConstKind::Unevaluated(_) => {
- bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
+ bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
}
_ => None,
},
- ConstantKind::Unevaluated(uv, _) => Some(uv),
+ Const::Unevaluated(uv, _) => Some(uv),
_ => None,
};
@@ -388,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
check_err(self, promoted_body, ty, promoted_ty);
} else {
self.cx.ascribe_user_type(
- constant.literal.ty(),
+ constant.const_.ty(),
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
locations.span(&self.cx.body),
);
@@ -396,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
- let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
+ let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty;
if let Err(terr) = self.cx.eq_types(
literal_ty,
@@ -408,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
}
- if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() {
+ if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
self.cx.normalize_and_prove_instantiated_predicates(
def_id,
@@ -720,6 +716,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
+ ProjectionElem::Subtype(_) => {
+ bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
+ }
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
@@ -749,7 +748,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
PlaceContext::MutatingUse(_) => ty::Invariant,
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
PlaceContext::NonMutatingUse(
- Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf
+ Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | AddressOf
| Projection,
) => ty::Covariant,
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
@@ -1011,7 +1010,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
- // OK to use the identity substitutions for each opaque type key, since
+ // OK to use the identity arguments for each opaque type key, since
// we remap opaques from HIR typeck back to their definition params.
let opaques: Vec<_> = self
.infcx
@@ -1333,8 +1332,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!("terminator kind: {:?}", term.kind);
match &term.kind {
TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindResume
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Return
| TerminatorKind::GeneratorDrop
| TerminatorKind::Unreachable
@@ -1371,14 +1370,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
- use crate::renumber::{BoundRegionInfo, RegionCtxt};
+ use crate::renumber::RegionCtxt;
let region_ctxt_fn = || {
let reg_info = match br.kind {
- ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
- ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
- ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
- ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
+ ty::BoundRegionKind::BrAnon => sym::anon,
+ ty::BoundRegionKind::BrNamed(_, name) => name,
+ ty::BoundRegionKind::BrEnv => sym::env,
};
RegionCtxt::LateBound(reg_info)
@@ -1430,7 +1428,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.add_element(region_vid, term_location);
}
- self.check_call_inputs(body, term, &sig, args, term_location, *call_source);
+ self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source);
}
TerminatorKind::Assert { cond, msg, .. } => {
self.check_operand(cond, term_location);
@@ -1550,25 +1548,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))]
fn check_call_inputs(
&mut self,
body: &Body<'tcx>,
term: &Terminator<'tcx>,
+ func: &Operand<'tcx>,
sig: &ty::FnSig<'tcx>,
args: &[Operand<'tcx>],
term_location: Location,
call_source: CallSource,
) {
- debug!("check_call_inputs({:?}, {:?})", sig, args);
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
- let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
- Some(func.ty(body, self.infcx.tcx))
- } else {
- None
- };
+ let func_ty = func.ty(body, self.infcx.tcx);
+ if let ty::FnDef(def_id, _) = *func_ty.kind() {
+ if self.tcx().is_intrinsic(def_id) {
+ match self.tcx().item_name(def_id) {
+ sym::simd_shuffle => {
+ if !matches!(args[2], Operand::Constant(_)) {
+ self.tcx()
+ .sess
+ .emit_err(SimdShuffleLastConst { span: term.source_info.span });
+ }
+ }
+ _ => {}
+ }
+ }
+ }
debug!(?func_ty);
for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
@@ -1576,7 +1585,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if call_source.from_hir_call() {
- ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
+ ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty)))
} else {
ConstraintCategory::Boring
};
@@ -1608,12 +1617,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.assert_iscleanup(body, block_data, *target, is_cleanup);
}
}
- TerminatorKind::Resume => {
+ TerminatorKind::UnwindResume => {
if !is_cleanup {
span_mirbug!(self, block_data, "resume on non-cleanup block!")
}
}
- TerminatorKind::Terminate => {
+ TerminatorKind::UnwindTerminate(_) => {
if !is_cleanup {
span_mirbug!(self, block_data, "abort on non-cleanup block!")
}
@@ -1697,7 +1706,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
span_mirbug!(self, ctxt, "unwind on cleanup block")
}
}
- UnwindAction::Unreachable | UnwindAction::Terminate => (),
+ UnwindAction::Unreachable | UnwindAction::Terminate(_) => (),
}
}
@@ -1794,9 +1803,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
debug!(?op, ?location, "check_operand");
if let Operand::Constant(constant) = op {
- let maybe_uneval = match constant.literal {
- ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
- ConstantKind::Unevaluated(uv, _) => Some(uv),
+ let maybe_uneval = match constant.const_ {
+ Const::Val(..) | Const::Ty(_) => None,
+ Const::Unevaluated(uv, _) => Some(uv),
};
if let Some(uv) = maybe_uneval {
@@ -2557,6 +2566,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| ProjectionElem::Subslice { .. } => {
// other field access
}
+ ProjectionElem::Subtype(_) => {
+ bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
+ }
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index e0c629562..c1f82e19c 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -11,7 +11,7 @@ use rustc_span::{Span, Symbol};
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
-use crate::renumber::{BoundRegionInfo, RegionCtxt};
+use crate::renumber::RegionCtxt;
use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@@ -126,10 +126,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
.placeholder_region(self.type_checker.infcx, placeholder);
let reg_info = match placeholder.bound.kind {
- ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span),
- ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon),
- ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name),
- ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
+ ty::BoundRegionKind::BrAnon => sym::anon,
+ ty::BoundRegionKind::BrNamed(_, name) => name,
+ ty::BoundRegionKind::BrEnv => sym::env,
};
if cfg!(debug_assertions) {
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 56945f43f..af437f36b 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -21,13 +21,14 @@ use rustc_hir::BodyOwnerKind;
use rustc_index::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_span::symbol::{kw, sym};
use rustc_span::Symbol;
use std::iter;
-use crate::renumber::{BoundRegionInfo, RegionCtxt};
+use crate::renumber::RegionCtxt;
use crate::BorrowckInferCtxt;
#[derive(Debug)]
@@ -332,10 +333,16 @@ impl<'tcx> UniversalRegions<'tcx> {
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
match self.defining_ty {
DefiningTy::Closure(def_id, args) => {
+ let v = with_no_trimmed_paths!(
+ args[tcx.generics_of(def_id).parent_count..]
+ .iter()
+ .map(|arg| arg.to_string())
+ .collect::<Vec<_>>()
+ );
err.note(format!(
- "defining type: {} with closure args {:#?}",
+ "defining type: {} with closure args [\n {},\n]",
tcx.def_path_str_with_args(def_id, args),
- &args[tcx.generics_of(def_id).parent_count..],
+ v.join(",\n "),
));
// FIXME: It'd be nice to print the late-bound regions
@@ -348,10 +355,16 @@ impl<'tcx> UniversalRegions<'tcx> {
});
}
DefiningTy::Generator(def_id, args, _) => {
+ let v = with_no_trimmed_paths!(
+ args[tcx.generics_of(def_id).parent_count..]
+ .iter()
+ .map(|arg| arg.to_string())
+ .collect::<Vec<_>>()
+ );
err.note(format!(
- "defining type: {} with generator args {:#?}",
+ "defining type: {} with generator args [\n {},\n]",
tcx.def_path_str_with_args(def_id, args),
- &args[tcx.generics_of(def_id).parent_count..],
+ v.join(",\n "),
));
// FIXME: As above, we'd like to print out the region
@@ -433,9 +446,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
- self.infcx.next_nll_region_var(FR, || {
- RegionCtxt::LateBound(BoundRegionInfo::Name(name))
- })
+ self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@@ -467,9 +478,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
- self.infcx.next_nll_region_var(FR, || {
- RegionCtxt::LateBound(BoundRegionInfo::Name(name))
- })
+ self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@@ -567,7 +576,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
}
}
- BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
+ BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
if self.mir_def.to_def_id() == typeck_root_def_id {
let args =
@@ -630,10 +639,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
};
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
- let subst_mapping =
- iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
+ let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var()));
- UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static }
+ UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static }
}
fn compute_inputs_and_output(
@@ -783,7 +791,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
_ => sym::anon,
};
- self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name)))
+ self.next_nll_region_var(origin, || RegionCtxt::Bound(name))
};
indices.insert_late_bound_region(liberated_region, region_vid.as_var());
@@ -813,9 +821,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
- self.next_nll_region_var(FR, || {
- RegionCtxt::LateBound(BoundRegionInfo::Name(name))
- })
+ self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
debug!(?region_vid);
@@ -835,9 +841,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
if !indices.indices.contains_key(&r) {
let region_vid = {
let name = r.get_name_or_anon();
- self.next_nll_region_var(FR, || {
- RegionCtxt::LateBound(BoundRegionInfo::Name(name))
- })
+ self.next_nll_region_var(FR, || RegionCtxt::LateBound(name))
};
indices.insert_late_bound_region(r, region_vid.as_var());