diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:41 +0000 |
commit | 4f9fe856a25ab29345b90e7725509e9ee38a37be (patch) | |
tree | e4ffd8a9374cae7b21f7cbfb352927e0e074aff6 /compiler/rustc_borrowck | |
parent | Adding upstream version 1.68.2+dfsg1. (diff) | |
download | rustc-upstream/1.69.0+dfsg1.tar.xz rustc-upstream/1.69.0+dfsg1.zip |
Adding upstream version 1.69.0+dfsg1.upstream/1.69.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_borrowck')
30 files changed, 1102 insertions, 582 deletions
diff --git a/compiler/rustc_borrowck/locales/en-US.ftl b/compiler/rustc_borrowck/locales/en-US.ftl new file mode 100644 index 000000000..a3b6b5e81 --- /dev/null +++ b/compiler/rustc_borrowck/locales/en-US.ftl @@ -0,0 +1,129 @@ +borrowck_move_unsized = + cannot move a value of type `{$ty}` + .label = the size of `{$ty}` cannot be statically determined + +borrowck_higher_ranked_lifetime_error = + higher-ranked lifetime error + +borrowck_could_not_prove = + could not prove `{$predicate}` + +borrowck_could_not_normalize = + could not normalize `{$value}` + +borrowck_higher_ranked_subtype_error = + higher-ranked subtype error + +borrowck_generic_does_not_live_long_enough = + `{$kind}` does not live long enough + +borrowck_move_borrowed = + cannot move out of `{$desc}` because it is borrowed + +borrowck_var_does_not_need_mut = + variable does not need to be mutable + .suggestion = remove this `mut` + +borrowck_var_cannot_escape_closure = + captured variable cannot escape `FnMut` closure body + .note = `FnMut` closures only have access to their captured variables while they are executing... + .cannot_escape = ...therefore, they cannot allow references to captured variables to escape + +borrowck_var_here_defined = variable defined here + +borrowck_var_here_captured = variable captured here + +borrowck_closure_inferred_mut = inferred to be a `FnMut` closure + +borrowck_returned_closure_escaped = + returns a closure that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_async_block_escaped = + returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_ref_escaped = + returns a reference to a captured variable which escapes the closure body + +borrowck_lifetime_constraints_error = + lifetime may not live long enough + +borrowck_returned_lifetime_wrong = + {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` + +borrowck_returned_lifetime_short = + {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` + +borrowck_used_impl_require_static = + the used `impl` has a `'static` requirement + +borrowck_capture_kind_label = + capture is {$kind_desc} because of use here + +borrowck_var_borrow_by_use_place_in_generator = + borrow occurs due to use of {$place} in closure in generator + +borrowck_var_borrow_by_use_place_in_closure = + borrow occurs due to use of {$place} in closure + +borrowck_var_borrow_by_use_place = + borrow occurs due to use of {$place} + +borrowck_borrow_due_to_use_generator = + borrow occurs due to use in generator + +borrowck_use_due_to_use_generator = + use occurs due to use in generator + +borrowck_assign_due_to_use_generator = + assign occurs due to use in generator + +borrowck_assign_part_due_to_use_generator = + assign to part occurs due to use in generator + +borrowck_borrow_due_to_use_closure = + borrow occurs due to use in closure + +borrowck_use_due_to_use_closure = + use occurs due to use in closure + +borrowck_assign_due_to_use_closure = + assignment occurs due to use in closure + +borrowck_assign_part_due_to_use_closure = + assignment to part occurs due to use in closure + +borrowck_capture_immute = + capture is immutable because of use here + +borrowck_capture_mut = + capture is mutable because of use here + +borrowck_capture_move = + capture is moved because of use here + +borrowck_var_move_by_use_place_in_generator = + move occurs due to use of {$place} in generator + +borrowck_var_move_by_use_place_in_closure = + move occurs due to use of {$place} in closure + +borrowck_cannot_move_when_borrowed = + cannot move out of {$place -> + [value] value + *[other] {$place} + } because it is borrowed + .label = borrow of {$borrow_place -> + [value] value + *[other] {$borrow_place} + } occurs here + .move_label = move out of {$value_place -> + [value] value + *[other] {$value_place} + } occurs here + +borrowck_opaque_type_non_generic_param = + expected generic {$kind} parameter, found `{$ty}` + .label = {STREQ($ty, "'static") -> + [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type + *[other] this generic parameter must be used with a generic {$kind} parameter + } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index a4943d112..2bbb9618d 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -37,7 +37,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc)); + err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc)); err.span_label(span, format!("use of borrowed {}", borrow_desc)); err } @@ -250,8 +250,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { desc, ); - err.span_label(borrow_span, format!("borrow of {} occurs here", desc)); - err.span_label(span, format!("assignment to borrowed {} occurs here", desc)); + err.span_label(borrow_span, format!("{} is borrowed here", desc)); + err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc)); err } diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 11b31c3f1..1427f5cb3 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; use crate::{ borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid, @@ -165,7 +165,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { /// `location`. fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location) where - T: TypeVisitable<'tcx>, + T: TypeVisitable<TyCtxt<'tcx>>, { debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location); diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 1f0b8adea..f370c0216 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -17,7 +17,7 @@ pub(crate) mod graph; /// constraints of the form `R1: R2`. Each constraint is identified by /// a unique `OutlivesConstraintIndex` and you can index into the set /// (`constraint_set[i]`) to access the constraint details. -#[derive(Clone, Default)] +#[derive(Clone, Debug, Default)] pub(crate) struct OutlivesConstraintSet<'tcx> { outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>, } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 8c4885770..2821677c5 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -393,6 +393,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) | mir::StatementKind::Intrinsic(..) + | mir::StatementKind::ConstEvalCounter | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 1550958ab..68205fa45 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -106,7 +106,7 @@ impl<'tcx> ToUniverseInfo<'tcx> } } -impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx> +impl<'tcx, T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx> ToUniverseInfo<'tcx> for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>> { fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { @@ -180,20 +180,20 @@ trait TypeOpInfo<'tcx> { return; }; - let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder { name: placeholder.name, universe: adjusted_universe.into(), - })); + }); let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = error_element { let adjusted_universe = error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); adjusted_universe.map(|adjusted| { - tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + tcx.mk_re_placeholder(ty::Placeholder { name: error_placeholder.name, universe: adjusted.into(), - })) + }) }) } else { None @@ -258,7 +258,7 @@ struct NormalizeQuery<'tcx, T> { impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T> where - T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx, + T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx, { fn fallback_error( &self, @@ -390,7 +390,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, ®ion_constraints, |vid| ocx.infcx.region_var_origin(vid), - |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))), + |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_re_var(vid)), ) } @@ -411,7 +411,7 @@ fn try_extract_error_from_region_constraints<'tcx>( } // FIXME: Should this check the universe of the var? Constraint::VarSubReg(vid, sup) if sup == placeholder_region => { - Some((infcx.tcx.mk_region(ty::ReVar(vid)), cause.clone())) + Some((infcx.tcx.mk_re_var(vid), cause.clone())) } _ => None, } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index e5a36259f..cb97699d7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; @@ -236,10 +236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = used_place.ty(self.body, self.infcx.tcx).ty; let needs_note = match ty.kind() { ty::Closure(id, _) => { - let tables = self.infcx.tcx.typeck(id.expect_local()); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local()); - - tables.closure_kind_origins().get(hir_id).is_none() + self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none() } _ => true, }; @@ -766,7 +763,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); let cause = ObligationCause::new( span, - self.mir_hir_id(), + self.mir_def_id(), rustc_infer::traits::ObligationCauseCode::MiscObligation, ); let errors = rustc_trait_selection::traits::fully_solve_bound( @@ -803,6 +800,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { predicates .iter() .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)), + None, ); } } @@ -1185,11 +1183,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return None; }; debug!("checking call args for uses of inner_param: {:?}", args); - if args.contains(&Operand::Move(inner_param)) { - Some((loc, term)) - } else { - None - } + args.contains(&Operand::Move(inner_param)).then_some((loc, term)) }) else { debug!("no uses of inner_param found as a by-move call arg"); return; @@ -1497,7 +1491,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { assert!(root_place.projection.is_empty()); let proper_span = self.body.local_decls[root_place.local].source_info.span; - let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection); + let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection); if self.access_place_error_reported.contains(&( Place { local: root_place.local, projection: root_place_projection }, @@ -1673,7 +1667,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("`{}` would have to be valid for `{}`...", name, region_name), ); - let fn_hir_id = self.mir_hir_id(); err.span_label( drop_span, format!( @@ -1681,19 +1674,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name, self.infcx .tcx - .hir() - .opt_name(fn_hir_id) + .opt_item_name(self.mir_def_id().to_def_id()) .map(|name| format!("function `{}`", name)) .unwrap_or_else(|| { - match &self - .infcx - .tcx - .typeck(self.mir_def_id()) - .node_type(fn_hir_id) - .kind() - { - ty::Closure(..) => "enclosing closure", - ty::Generator(..) => "enclosing generator", + match &self.infcx.tcx.def_kind(self.mir_def_id()) { + DefKind::Closure => "enclosing closure", + DefKind::Generator => "enclosing generator", kind => bug!("expected closure or generator, found {:?}", kind), } .to_string() @@ -1736,7 +1722,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.local_names, &mut err, "", - None, + Some(borrow_span), None, ); } @@ -2138,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { let tcx = self.infcx.tcx; - let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id()); + let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); let mut err = borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); @@ -2595,11 +2581,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if is_closure { None } else { - let ty = self.infcx.tcx.type_of(self.mir_def_id()); + let ty = self.infcx.tcx.type_of(self.mir_def_id()).subst_identity(); match ty.kind() { ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( self.mir_def_id(), - self.infcx.tcx.fn_sig(self.mir_def_id()), + self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(), ), _ => None, } @@ -2645,6 +2631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { operands, ) = rvalue { + let def_id = def_id.expect_local(); for operand in operands { let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else { continue; @@ -2667,7 +2654,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // into a place then we should annotate the closure in // case it ends up being assigned into the return place. annotated_closure = - self.annotate_fn_sig(*def_id, substs.as_closure().sig()); + self.annotate_fn_sig(def_id, substs.as_closure().sig()); debug!( "annotate_argument_and_return_for_borrow: \ annotated_closure={:?} assigned_from_local={:?} \ diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 209574709..19855075c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,6 +1,8 @@ //! Print diagnostics to explain why values are borrowed. use rustc_errors::{Applicability, Diagnostic}; +use rustc_hir as hir; +use rustc_hir::intravisit::Visitor; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ @@ -11,6 +13,7 @@ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; +use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ @@ -63,6 +66,36 @@ impl<'tcx> BorrowExplanation<'tcx> { borrow_span: Option<Span>, multiple_borrow_span: Option<(Span, Span)>, ) { + if let Some(span) = borrow_span { + let def_id = body.source.def_id(); + if let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(body_id) = node.body_id() + { + let body = tcx.hir().body(body_id); + let mut expr_finder = FindExprBySpan::new(span); + expr_finder.visit_expr(body.value); + if let Some(mut expr) = expr_finder.result { + while let hir::ExprKind::AddrOf(_, _, inner) + | hir::ExprKind::Unary(hir::UnOp::Deref, inner) + | hir::ExprKind::Field(inner, _) + | hir::ExprKind::MethodCall(_, inner, _, _) + | hir::ExprKind::Index(inner, _) = &expr.kind + { + expr = inner; + } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind + && let [hir::PathSegment { ident, args: None, .. }] = p.segments + && let hir::def::Res::Local(hir_id) = p.res + && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id) + { + err.span_label( + pat.span, + &format!("binding `{ident}` declared here"), + ); + } + } + } + } match *self { BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1b40b7143..a99fd594a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -115,11 +115,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.span_note( *span, &format!( @@ -139,11 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(target) = target { if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - - if let Some((span, hir_place)) = - self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) - { + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { diag.span_note( *span, &format!( @@ -373,14 +365,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // We know the field exists so it's safe to call operator[] and `unwrap` here. let def_id = def_id.expect_local(); - let var_id = self - .infcx - .tcx - .typeck(def_id) - .closure_min_captures_flattened(def_id) - .nth(field.index()) - .unwrap() - .get_root_variable(); + let var_id = + self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable(); Some(self.infcx.tcx.hir().name(var_id).to_string()) } @@ -817,6 +803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind { debug!("move_spans: def_id={:?} places={:?}", def_id, places); + let def_id = def_id.expect_local(); if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(def_id, moved_place, places) { @@ -945,6 +932,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { box AggregateKind::Generator(def_id, _, _) => (def_id, true), _ => continue, }; + let def_id = def_id.expect_local(); debug!( "borrow_spans: def_id={:?} is_generator={:?} places={:?}", @@ -985,7 +973,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr { for (captured_place, place) in - self.infcx.tcx.typeck(def_id).closure_min_captures_flattened(def_id).zip(places) + self.infcx.tcx.closure_captures(def_id).iter().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) @@ -1064,7 +1052,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - CallKind::Normal { self_arg, desugaring, method_did } => { + CallKind::Normal { self_arg, desugaring, method_did, method_substs } => { let self_arg = self_arg.unwrap(); let tcx = self.infcx.tcx; if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { @@ -1128,17 +1116,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "{place_name} {partially_str}moved due to this method call{loop_message}", ), ); + let infcx = tcx.infer_ctxt().build(); + // Erase and shadow everything that could be passed to the new infcx. let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); + let method_substs = tcx.erase_regions(method_substs); + if let ty::Adt(def, substs) = ty.kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() - && let self_ty = infcx.replace_bound_vars_with_fresh_vars( + && let self_ty = infcx.instantiate_binder_with_fresh_vars( fn_call_span, LateBoundRegionConversionTime::FnCall, - tcx.fn_sig(method_did).input(0), + tcx.fn_sig(method_did).subst(tcx, method_substs).input(0), ) - && infcx.can_eq(self.param_env, ty, self_ty).is_ok() + && infcx.can_eq(self.param_env, ty, self_ty) { err.span_suggestion_verbose( fn_call_span.shrink_to_lo(), @@ -1176,13 +1168,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } let parent_did = tcx.parent(method_did); - let parent_self_ty = (tcx.def_kind(parent_did) - == rustc_hir::def::DefKind::Impl) - .then_some(parent_did) - .and_then(|did| match tcx.type_of(did).kind() { - ty::Adt(def, ..) => Some(def.did()), - _ => None, - }); + let parent_self_ty = + matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. }) + .then_some(parent_did) + .and_then(|did| match tcx.type_of(did).subst_identity().kind() { + ty::Adt(def, ..) => Some(def.did()), + _ => None, + }); let is_option_or_result = parent_self_ty.map_or(false, |def_id| { matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 6db3c858a..5e4c7292e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -448,7 +448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); - use_spans.args_span_label(err, format!("move out of {place_desc} occurs here")); + use_spans.args_span_label(err, format!("{place_desc} is moved here")); } } } @@ -467,7 +467,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), "consider borrowing here", - "&".to_string(), + '&', Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 45b15c2c5..328ac880d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { err.span_help(source_info.span, "try removing `&mut` here"); } - } else if decl.mutability == Mutability::Not { + } else if decl.mutability.is_not() { if matches!( decl.local_info, Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( @@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_suggestion_verbose( local_decl.source_info.span.shrink_to_lo(), "consider changing this to be mutable", - "mut ".to_string(), + "mut ", Applicability::MachineApplicable, ); let tcx = self.infcx.tcx; @@ -606,12 +606,63 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } Some((false, err_label_span, message)) => { - err.span_label( - err_label_span, - &format!( - "consider changing this binding's type to be: `{message}`" - ), - ); + 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 = hir_map.local_def_id_to_hir_id(def_id.expect_local()); + let node = hir_map.find(hir_id); + let hir_id = if let Some(hir::Node::Item(item)) = node + && let hir::ItemKind::Fn(.., body_id) = item.kind + { + let body = hir_map.body(body_id); + let mut v = BindingFinder { + span: err_label_span, + hir_id: None, + }; + v.visit_body(body); + v.hir_id + } else { + None + }; + if let Some(hir_id) = hir_id + && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) + { + let (changing, span, sugg) = match local.ty { + Some(ty) => ("changing", ty.span, message), + None => ( + "specifying", + local.pat.span.shrink_to_hi(), + format!(": {message}"), + ), + }; + err.span_suggestion_verbose( + span, + &format!("consider {changing} this binding's type"), + sugg, + Applicability::HasPlaceholders, + ); + } else { + err.span_label( + err_label_span, + &format!( + "consider changing this binding's type to be: `{message}`" + ), + ); + } } None => {} } @@ -850,10 +901,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err: &mut Diagnostic, ) { let tables = tcx.typeck(closure_local_def_id); - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id); - if let Some((span, closure_kind_origin)) = - &tables.closure_kind_origins().get(closure_hir_id) - { + if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) { let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); let root_hir_id = upvar_id.var_path.hir_id; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 187861ba1..ffe82b46c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -415,7 +415,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// - /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. + /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`. pub(crate) fn report_region_error( &mut self, fr: RegionVid, @@ -575,7 +575,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() { - output_ty = self.infcx.tcx.type_of(def_id) + output_ty = self.infcx.tcx.type_of(def_id).subst_identity() }; debug!("report_fnmut_error: output_ty={:?}", output_ty); @@ -583,10 +583,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let err = FnMutError { span: *span, ty_err: match output_ty.kind() { - ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span }, ty::Generator(def, ..) if self.infcx.tcx.generator_is_async(*def) => { FnMutReturnTypeErr::ReturnAsyncBlock { span: *span } } + _ if output_ty.contains_closure() => { + FnMutReturnTypeErr::ReturnClosure { span: *span } + } _ => FnMutReturnTypeErr::ReturnRef { span: *span }, }, }; @@ -658,10 +660,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { errci.outlived_fr, ); - let (_, escapes_from) = self - .infcx - .tcx - .article_and_description(self.regioncx.universal_regions().defining_ty.def_id()); + let escapes_from = + self.infcx.tcx.def_descr(self.regioncx.universal_regions().defining_ty.def_id()); // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. @@ -755,8 +755,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. } = errci; - let (_, mir_def_name) = - self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id()); + let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id()); let err = LifetimeOutliveErr { span: *span }; let mut diag = self.infcx.tcx.sess.create_err(err); @@ -813,17 +812,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if *outlived_f != ty::ReStatic { return; } + let suitable_region = self.infcx.tcx.is_suitable_region(f); + let Some(suitable_region) = suitable_region else { return; }; - let fn_returns = self - .infcx - .tcx - .is_suitable_region(f) - .map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id)) - .unwrap_or_default(); - - if fn_returns.is_empty() { - return; - } + let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id); let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) { param @@ -839,15 +831,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; let captures = format!("captures data from {arg}"); - return nice_region_error::suggest_new_region_bound( - self.infcx.tcx, - diag, - fn_returns, - lifetime.to_string(), - Some(arg), - captures, - Some((param.param_ty_span, param.param_ty.to_string())), - self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id), + if !fn_returns.is_empty() { + nice_region_error::suggest_new_region_bound( + self.infcx.tcx, + diag, + fn_returns, + lifetime.to_string(), + Some(arg), + captures, + Some((param.param_ty_span, param.param_ty.to_string())), + Some(suitable_region.def_id), + ); + return; + } + + let Some((alias_tys, alias_span)) = self + .infcx + .tcx + .return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; }; + + // in case the return type of the method is a type alias + let mut spans_suggs: Vec<_> = Vec::new(); + for alias_ty in alias_tys { + if alias_ty.span.desugaring_kind().is_some() { + // Skip `async` desugaring `impl Future`. + () + } + if let TyKind::TraitObject(_, lt, _) = alias_ty.kind { + spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string())); + } + } + spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string())); + diag.multipart_suggestion_verbose( + &format!( + "to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias" + ), + spans_suggs, + Applicability::MaybeIncorrect, ); } } @@ -873,7 +893,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!(?fn_did, ?substs); // Only suggest this on function calls, not closures - let ty = tcx.type_of(fn_did); + let ty = tcx.type_of(fn_did).subst_identity(); debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); if let ty::Closure(_, _) = ty.kind() { return; @@ -929,7 +949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement", + "calling this method introduces the `impl`'s `'static` requirement", ); err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( @@ -976,7 +996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) { let map = self.infcx.tcx.hir(); let body_id = map.body_owned_by(self.mir_def_id()); - let expr = &map.body(body_id).value; + let expr = &map.body(body_id).value.peel_blocks(); let mut closure_span = None::<rustc_span::Span>; match expr.kind { hir::ExprKind::MethodCall(.., args, _) => { @@ -991,20 +1011,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } } - hir::ExprKind::Block(blk, _) => { - if let Some(expr) = blk.expr { - // only when the block is a closure - if let hir::ExprKind::Closure(hir::Closure { - capture_clause: hir::CaptureBy::Ref, - body, - .. - }) = expr.kind - { - let body = map.body(*body); - if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) { - closure_span = Some(expr.span.shrink_to_lo()); - } - } + hir::ExprKind::Closure(hir::Closure { + capture_clause: hir::CaptureBy::Ref, + body, + .. + }) => { + let body = map.body(*body); + if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) { + closure_span = Some(expr.span.shrink_to_lo()); } } _ => {} diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 9233287cf..f6881a2e5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -187,6 +187,12 @@ impl Display for RegionName { } } +impl rustc_errors::IntoDiagnosticArg for RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId { self.body.source.def_id().expect_local() @@ -274,17 +280,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { debug!("give_region_a_name: error_region = {:?}", error_region); match *error_region { - ty::ReEarlyBound(ebr) => { - if ebr.has_name() { - let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); - Some(RegionName { - name: ebr.name, - source: RegionNameSource::NamedEarlyBoundRegion(span), - }) - } else { - None - } - } + ty::ReEarlyBound(ebr) => ebr.has_name().then(|| { + let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); + RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) } + }), ty::ReStatic => { Some(RegionName { name: kw::StaticLifetime, source: RegionNameSource::Static }) @@ -337,11 +336,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let note = match closure_kind_ty.to_opt_closure_kind() { Some(ty::ClosureKind::Fn) => { "closure implements `Fn`, so references to captured variables \ - can't escape the closure" + can't escape the closure" } Some(ty::ClosureKind::FnMut) => { "closure implements `FnMut`, so references to captured variables \ - can't escape the closure" + can't escape the closure" } Some(ty::ClosureKind::FnOnce) => { bug!("BrEnv in a `FnOnce` closure"); @@ -358,7 +357,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::BoundRegionKind::BrAnon(..) => None, }, - ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None, + ty::ReLateBound(..) + | ty::ReVar(..) + | ty::RePlaceholder(..) + | ty::ReErased + | ty::ReError(_) => None, } } @@ -842,12 +845,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let tcx = self.infcx.tcx; let region_parent = tcx.parent(region.def_id); - if tcx.def_kind(region_parent) != DefKind::Impl { + let DefKind::Impl { .. } = tcx.def_kind(region_parent) else { return None; - } + }; - let found = tcx - .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region)); + let found = tcx.any_free_region_meets(&tcx.type_of(region_parent).subst_identity(), |r| { + *r == ty::ReEarlyBound(region) + }); Some(RegionName { name: self.synthesize_region_name(), diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 6fd929005..6217676d5 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -91,7 +91,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { LocalMutationIsAllowed::Yes, ); } - StatementKind::Nop + StatementKind::ConstEvalCounter + | StatementKind::Nop | StatementKind::Retag { .. } | StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 73ea7314b..0f591460e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1,6 +1,7 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. #![allow(rustc::potential_query_instability)] +#![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(let_chains)] #![feature(min_specialization)] @@ -20,12 +21,15 @@ extern crate tracing; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::{Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; use rustc_index::vec::IndexVec; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{ + DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, +}; +use rustc_macros::fluent_messages; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, @@ -43,6 +47,7 @@ use smallvec::SmallVec; use std::cell::OnceCell; use std::cell::RefCell; use std::collections::BTreeMap; +use std::ops::Deref; use std::rc::Rc; use rustc_mir_dataflow::impls::{ @@ -94,6 +99,9 @@ use nll::{PoloniusOutput, ToRegionVid}; use place_ext::PlaceExt; use places_conflict::{places_conflict, PlaceConflictBias}; use region_infer::RegionInferenceContext; +use renumber::RegionCtxt; + +fluent_messages! { "../locales/en-US.ftl" } // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] @@ -167,10 +175,10 @@ fn do_mir_borrowck<'tcx>( return_body_with_facts: bool, ) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) { let def = input_body.source.with_opt_param().as_local().unwrap(); - debug!(?def); let tcx = infcx.tcx; + let infcx = BorrowckInferCtxt::new(infcx); let param_env = tcx.param_env(def.did); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); @@ -194,14 +202,14 @@ fn do_mir_borrowck<'tcx>( let mut errors = error::BorrowckErrors::new(infcx.tcx); // Gather the upvars of a closure, if any. - let tables = tcx.typeck_opt_const_arg(def); - if let Some(e) = tables.tainted_by_errors { + if let Some(e) = input_body.tainted_by_errors { infcx.set_tainted_by_errors(e); errors.set_tainted_by_errors(e); } - let upvars: Vec<_> = tables - .closure_min_captures_flattened(def.did) - .map(|captured_place| { + let upvars: Vec<_> = tcx + .closure_captures(def.did) + .iter() + .map(|&captured_place| { let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue => false, @@ -218,7 +226,7 @@ fn do_mir_borrowck<'tcx>( let mut body_owned = input_body.clone(); let mut promoted = input_promoted.clone(); let free_regions = - nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted); + nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes let location_table_owned = LocationTable::new(body); @@ -256,7 +264,7 @@ fn do_mir_borrowck<'tcx>( opt_closure_req, nll_errors, } = nll::compute_regions( - infcx, + &infcx, free_regions, body, &promoted, @@ -271,12 +279,12 @@ fn do_mir_borrowck<'tcx>( // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. - nll::dump_mir_results(infcx, &body, ®ioncx, &opt_closure_req); + nll::dump_mir_results(&infcx, &body, ®ioncx, &opt_closure_req); // We also have a `#[rustc_regions]` annotation that causes us to dump // information. nll::dump_annotation( - infcx, + &infcx, &body, ®ioncx, &opt_closure_req, @@ -320,7 +328,7 @@ fn do_mir_borrowck<'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { - infcx, + infcx: &infcx, param_env, body: promoted_body, move_data: &move_data, @@ -349,7 +357,7 @@ fn do_mir_borrowck<'tcx>( } let mut mbcx = MirBorrowckCtxt { - infcx, + infcx: &infcx, param_env, body, move_data: &mdpe.move_data, @@ -481,8 +489,84 @@ pub struct BodyWithBorrowckFacts<'tcx> { pub location_table: LocationTable, } +pub struct BorrowckInferCtxt<'cx, 'tcx> { + pub(crate) infcx: &'cx InferCtxt<'tcx>, + pub(crate) reg_var_to_origin: RefCell<FxHashMap<ty::RegionVid, RegionCtxt>>, +} + +impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { + pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { + BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } + } + + pub(crate) fn next_region_var<F>( + &self, + origin: RegionVariableOrigin, + get_ctxt_fn: F, + ) -> ty::Region<'tcx> + where + F: Fn() -> RegionCtxt, + { + let next_region = self.infcx.next_region_var(origin); + let vid = next_region + .as_var() + .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + + if cfg!(debug_assertions) { + debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); + let ctxt = get_ctxt_fn(); + let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(vid, ctxt); + + // This only makes sense if not called in a canonicalization context. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + next_region + } + + #[instrument(skip(self, get_ctxt_fn), level = "debug")] + pub(crate) fn next_nll_region_var<F>( + &self, + origin: NllRegionVariableOrigin, + get_ctxt_fn: F, + ) -> ty::Region<'tcx> + where + F: Fn() -> RegionCtxt, + { + let next_region = self.infcx.next_nll_region_var(origin.clone()); + let vid = next_region + .as_var() + .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); + + if cfg!(debug_assertions) { + debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); + let ctxt = get_ctxt_fn(); + let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(vid, ctxt); + + // This only makes sense if not called in a canonicalization context. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + next_region + } +} + +impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> { + type Target = InferCtxt<'tcx>; + + fn deref(&self) -> &'cx Self::Target { + self.infcx + } +} + struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, @@ -609,7 +693,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx StatementKind::AscribeUserType(..) // Doesn't have any language semantics | StatementKind::Coverage(..) - // Does not actually affect borrowck + // These do not actually affect borrowck + | StatementKind::ConstEvalCounter | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( @@ -1277,6 +1362,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // in order to populate our used_mut set. match **aggregate_kind { AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => { + let def_id = def_id.expect_local(); let BorrowCheckResult { used_mut_upvars, .. } = self.infcx.tcx.mir_borrowck(def_id); debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index b2d92d0db..96228338a 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -5,16 +5,14 @@ use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; -use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid}; +use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt}; use rustc_span::symbol::sym; use std::env; -use std::fmt::Debug; use std::io; use std::path::PathBuf; use std::rc::Rc; @@ -37,7 +35,7 @@ use crate::{ renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, - Upvar, + BorrowckInferCtxt, Upvar, }; pub type PoloniusOutput = Output<RustcFacts>; @@ -58,7 +56,7 @@ pub(crate) struct NllOutput<'tcx> { /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec<Promoted, Body<'tcx>>, @@ -157,7 +155,7 @@ fn populate_polonius_move_facts( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexVec<Promoted, Body<'tcx>>, @@ -259,6 +257,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( ); let mut regioncx = RegionInferenceContext::new( + infcx, var_origins, universal_regions, placeholder_indices, @@ -322,10 +321,10 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } pub(super) fn dump_mir_results<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, + closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, ) { if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) { return; @@ -340,9 +339,11 @@ pub(super) fn dump_mir_results<'tcx>( if let Some(closure_region_requirements) = closure_region_requirements { writeln!(out, "| Free Region Constraints")?; - for_each_region_constraint(closure_region_requirements, &mut |msg| { - writeln!(out, "| {}", msg) - })?; + for_each_region_constraint( + infcx.tcx, + closure_region_requirements, + &mut |msg| writeln!(out, "| {}", msg), + )?; writeln!(out, "|")?; } } @@ -369,11 +370,13 @@ pub(super) fn dump_mir_results<'tcx>( }; } +#[allow(rustc::diagnostic_outside_of_impl)] +#[allow(rustc::untranslatable_diagnostic)] pub(super) fn dump_annotation<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, + closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { @@ -403,7 +406,7 @@ pub(super) fn dump_annotation<'tcx>( // Dump the region constraints we are imposing *between* those // newly created variables. - for_each_region_constraint(closure_region_requirements, &mut |msg| { + for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| { err.note(msg); Ok(()) }) @@ -424,16 +427,19 @@ pub(super) fn dump_annotation<'tcx>( errors.buffer_non_error_diag(err); } -fn for_each_region_constraint( - closure_region_requirements: &ClosureRegionRequirements<'_>, +fn for_each_region_constraint<'tcx>( + tcx: TyCtxt<'tcx>, + closure_region_requirements: &ClosureRegionRequirements<'tcx>, with_msg: &mut dyn FnMut(&str) -> io::Result<()>, ) -> io::Result<()> { for req in &closure_region_requirements.outlives_requirements { - let subject: &dyn Debug = match &req.subject { - ClosureOutlivesSubject::Region(subject) => subject, - ClosureOutlivesSubject::Ty(ty) => ty, + let subject = match req.subject { + ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject), + ClosureOutlivesSubject::Ty(ty) => { + format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) + } }; - with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?; + with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?; } Ok(()) } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 238172ea3..e6195de40 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -7,18 +7,18 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diagnostic; use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; use rustc_infer::infer::outlives::test_type_match; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::{ - Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind, + Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy, + ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, + TerminatorKind, }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; use crate::{ @@ -35,6 +35,7 @@ use crate::{ }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, + BorrowckInferCtxt, }; mod dump_mir; @@ -244,6 +245,70 @@ pub enum ExtraConstraintInfo { PlaceholderFromPredicate(Span), } +#[instrument(skip(infcx, sccs), level = "debug")] +fn sccs_info<'cx, 'tcx>( + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>, +) { + use crate::renumber::RegionCtxt; + + let var_to_origin = infcx.reg_var_to_origin.borrow(); + + let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>(); + var_to_origin_sorted.sort_by(|a, b| a.0.cmp(&b.0)); + let mut debug_str = "region variables to origins:\n".to_string(); + for (reg_var, origin) in var_to_origin_sorted.into_iter() { + debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); + } + debug!(debug_str); + + let num_components = sccs.scc_data().ranges().len(); + let mut components = vec![FxHashSet::default(); num_components]; + + for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() { + let reg_var = ty::RegionVid::from_usize(reg_var_idx); + let origin = var_to_origin.get(®_var).unwrap_or_else(|| &RegionCtxt::Unknown); + components[scc_idx.as_usize()].insert((reg_var, *origin)); + } + + let mut components_str = "strongly connected components:".to_string(); + for (scc_idx, reg_vars_origins) in components.iter().enumerate() { + let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>(); + components_str.push_str(&format!( + "{:?}: {:?})", + ConstraintSccIndex::from_usize(scc_idx), + regions_info, + )) + } + debug!(components_str); + + // calculate the best representative for each component + let components_representatives = components + .into_iter() + .enumerate() + .map(|(scc_idx, region_ctxts)| { + let repr = region_ctxts + .into_iter() + .map(|reg_var_origin| reg_var_origin.1) + .max_by(|x, y| x.preference_value().cmp(&y.preference_value())) + .unwrap(); + + (ConstraintSccIndex::from_usize(scc_idx), repr) + }) + .collect::<FxHashMap<_, _>>(); + + let mut scc_node_to_edges = FxHashMap::default(); + for (scc_idx, repr) in components_representatives.iter() { + let edges_range = sccs.scc_data().ranges()[*scc_idx].clone(); + let edges = &sccs.scc_data().all_successors()[edges_range]; + let edge_representatives = + edges.iter().map(|scc_idx| components_representatives[scc_idx]).collect::<Vec<_>>(); + scc_node_to_edges.insert((scc_idx, repr), edge_representatives); + } + + debug!("SCC edges {:#?}", scc_node_to_edges); +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Creates a new region inference context with a total of /// `num_region_variables` valid inference variables; the first N @@ -252,7 +317,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// The `outlives_constraints` and `type_tests` are an initial set /// of constraints produced by the MIR type check. - pub(crate) fn new( + pub(crate) fn new<'cx>( + _infcx: &BorrowckInferCtxt<'cx, 'tcx>, var_infos: VarInfos, universal_regions: Rc<UniversalRegions<'tcx>>, placeholder_indices: Rc<PlaceholderIndices>, @@ -264,6 +330,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues<RegionVid>, elements: &Rc<RegionValueElements>, ) -> Self { + debug!("universal_regions: {:#?}", universal_regions); + debug!("outlives constraints: {:#?}", outlives_constraints); + debug!("placeholder_indices: {:#?}", placeholder_indices); + debug!("type tests: {:#?}", type_tests); + // Create a RegionDefinition for each inference variable. let definitions: IndexVec<_, _> = var_infos .iter() @@ -275,6 +346,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let fr_static = universal_regions.fr_static; let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); + if cfg!(debug_assertions) { + sccs_info(_infcx, constraint_sccs.clone()); + } + let mut scc_values = RegionValues::new(elements, universal_regions.len(), &placeholder_indices); @@ -747,20 +822,33 @@ impl<'tcx> RegionInferenceContext<'tcx> { } debug!(?choice_regions, "after ub"); - // If we ruled everything out, we're done. - if choice_regions.is_empty() { - return false; - } - - // Otherwise, we need to find the minimum remaining choice, if - // any, and take that. - debug!("choice_regions remaining are {:#?}", choice_regions); - let Some(&min_choice) = choice_regions.iter().find(|&r1| { + // At this point we can pick any member of `choice_regions`, but to avoid potential + // non-determinism we will pick the *unique minimum* choice. + // + // Because universal regions are only partially ordered (i.e, not every two regions are + // comparable), we will ignore any region that doesn't compare to all others when picking + // the minimum choice. + // For example, consider `choice_regions = ['static, 'a, 'b, 'c, 'd, 'e]`, where + // `'static: 'a, 'static: 'b, 'a: 'c, 'b: 'c, 'c: 'd, 'c: 'e`. + // `['d, 'e]` are ignored because they do not compare - the same goes for `['a, 'b]`. + let totally_ordered_subset = choice_regions.iter().copied().filter(|&r1| { choice_regions.iter().all(|&r2| { - self.universal_region_relations.outlives(r2, *r1) + self.universal_region_relations.outlives(r1, r2) + || self.universal_region_relations.outlives(r2, r1) }) + }); + // Now we're left with `['static, 'c]`. Pick `'c` as the minimum! + let Some(min_choice) = totally_ordered_subset.reduce(|r1, r2| { + let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); + let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); + match (r1_outlives_r2, r2_outlives_r1) { + (true, true) => r1.min(r2), + (true, false) => r2, + (false, true) => r1, + (false, false) => bug!("incomparable regions in total order"), + } }) else { - debug!("no choice region outlived by all others"); + debug!("no unique minimum choice"); return false; }; @@ -802,7 +890,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// from a universe it can't name; at present, the only way for /// this to be true is if `scc` outlives `'static`. This is /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b`>` that might then allow us to approximate + /// like `for<'a: 'b>` that might then allow us to approximate /// `'a` with `'b` and not `'static`. But it will have to do for /// now. fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { @@ -997,18 +1085,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { true } - /// When we promote a type test `T: 'r`, we have to convert the - /// type `T` into something we can store in a query result (so - /// something allocated for `'tcx`). This is problematic if `ty` - /// contains regions. During the course of NLL region checking, we - /// will have replaced all of those regions with fresh inference - /// variables. To create a test subject, we want to replace those - /// inference variables with some region from the closure - /// signature -- this is not always possible, so this is a - /// fallible process. Presuming we do find a suitable region, we - /// will use it's *external name*, which will be a `RegionKind` - /// variant that can be used in query responses such as - /// `ReEarlyBound`. + /// When we promote a type test `T: 'r`, we have to replace all region + /// variables in the type `T` with an equal universal region from the + /// closure signature. + /// This is not always possible, so this is a fallible process. #[instrument(level = "debug", skip(self, infcx))] fn try_promote_type_test_subject( &self, @@ -1017,91 +1097,63 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option<ClosureOutlivesSubject<'tcx>> { let tcx = infcx.tcx; + // Opaque types' substs may include useless lifetimes. + // We will replace them with ReStatic. + struct OpaqueFolder<'tcx> { + tcx: TyCtxt<'tcx>, + } + impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + use ty::TypeSuperFoldable as _; + let tcx = self.tcx; + let &ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = t.kind() else { + return t.super_fold_with(self); + }; + let substs = + std::iter::zip(substs, tcx.variances_of(def_id)).map(|(arg, v)| { + match (arg.unpack(), v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => { + tcx.lifetimes.re_static.into() + } + _ => arg.fold_with(self), + } + }); + tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs)) + } + } + + let ty = ty.fold_with(&mut OpaqueFolder { tcx }); + let ty = tcx.fold_regions(ty, |r, _depth| { - let region_vid = self.to_region_vid(r); + let r_vid = self.to_region_vid(r); + let r_scc = self.constraint_sccs.scc(r_vid); // The challenge if this. We have some region variable `r` // whose value is a set of CFG points and universal // regions. We want to find if that set is *equivalent* to // any of the named regions found in the closure. - // - // To do so, we compute the - // `non_local_universal_upper_bound`. This will be a - // non-local, universal region that is greater than `r`. - // However, it might not be *contained* within `r`, so - // then we further check whether this bound is contained - // in `r`. If so, we can say that `r` is equivalent to the - // bound. - // - // Let's work through a few examples. For these, imagine - // that we have 3 non-local regions (I'll denote them as - // `'static`, `'a`, and `'b`, though of course in the code - // they would be represented with indices) where: - // - // - `'static: 'a` - // - `'static: 'b` - // - // First, let's assume that `r` is some existential - // variable with an inferred value `{'a, 'static}` (plus - // some CFG nodes). In this case, the non-local upper - // bound is `'static`, since that outlives `'a`. `'static` - // is also a member of `r` and hence we consider `r` - // equivalent to `'static` (and replace it with - // `'static`). - // - // Now let's consider the inferred value `{'a, 'b}`. This - // means `r` is effectively `'a | 'b`. I'm not sure if - // this can come about, actually, but assuming it did, we - // would get a non-local upper bound of `'static`. Since - // `'static` is not contained in `r`, we would fail to - // find an equivalent. - let upper_bound = self.non_local_universal_upper_bound(region_vid); - if self.region_contains(region_vid, upper_bound) { - self.definitions[upper_bound].external_name.unwrap_or(r) - } else { - // In the case of a failure, use a `ReVar` result. This will - // cause the `needs_infer` later on to return `None`. - r - } + // To do so, we simply check every candidate `u_r` for equality. + self.scc_values + .universal_regions_outlived_by(r_scc) + .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r)) + .find(|&u_r| self.eval_equal(u_r, r_vid)) + .map(|u_r| tcx.mk_re_var(u_r)) + // In the case of a failure, use `ReErased`. We will eventually + // return `None` in this case. + .unwrap_or(tcx.lifetimes.re_erased) }); debug!("try_promote_type_test_subject: folded ty = {:?}", ty); - // `needs_infer` will only be true if we failed to promote some region. - if ty.needs_infer() { + // This will be true if we failed to promote some region. + if ty.has_erased_regions() { return None; } - Some(ClosureOutlivesSubject::Ty(ty)) - } - - /// Given some universal or existential region `r`, finds a - /// non-local, universal region `r+` that outlives `r` at entry to (and - /// exit from) the closure. In the worst case, this will be - /// `'static`. - /// - /// This is used for two purposes. First, if we are propagated - /// some requirement `T: r`, we can use this method to enlarge `r` - /// to something we can encode for our creator (which only knows - /// about non-local, universal regions). It is also used when - /// encoding `T` as part of `try_promote_type_test_subject` (see - /// that fn for details). - /// - /// This is based on the result `'y` of `universal_upper_bound`, - /// except that it converts further takes the non-local upper - /// bound of `'y`, so that the final result is non-local. - fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); - - let lub = self.universal_upper_bound(r); - - // Grow further to get smallest universal region known to - // creator. - let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub); - - debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub); - - non_local_lub + Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty))) } /// Returns a universally quantified region that outlives the @@ -1279,13 +1331,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// we use this kind of hacky solution. fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { tcx.fold_regions(value, |r, _db| { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; - tcx.mk_region(ty::ReVar(repr)) + tcx.mk_re_var(repr) }) } @@ -1707,7 +1759,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // If not, report an error. - let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); + let member_region = infcx.tcx.mk_re_var(member_region_vid); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { span: m_c.definition_span, hidden_ty: m_c.hidden_ty, @@ -2022,7 +2074,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|constraint| BlameConstraint { category: constraint.category, from_closure: constraint.from_closure, - cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()), + cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()), variance_info: constraint.variance_info, outlives_constraint: *constraint, }) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index db5a67a8b..c550e37c6 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,12 +1,13 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::vec_map::VecMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -91,11 +92,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } None => { subst_regions.push(vid); - infcx.tcx.sess.delay_span_bug( + infcx.tcx.mk_re_error_with_message( concrete_type.span, "opaque type with non-universal region substs", - ); - infcx.tcx.lifetimes.re_static + ) } } }; @@ -150,13 +150,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { // once we convert the generic parameters to those of the opaque type. if let Some(prev) = result.get_mut(&opaque_type_key.def_id) { if prev.ty != ty { - if !ty.references_error() { + let guar = ty.error_reported().err().unwrap_or_else(|| { prev.report_mismatch( &OpaqueHiddenType { ty, span: concrete_type.span }, infcx.tcx, - ); - } - prev.ty = infcx.tcx.ty_error(); + ) + }); + prev.ty = infcx.tcx.ty_error(guar); } // Pick a better span if there is one. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. @@ -179,7 +179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// region names in error messages. pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { tcx.fold_regions(ty, |region, _| match *region { ty::ReVar(vid) => { @@ -248,20 +248,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { origin: OpaqueTyOrigin, ) -> Ty<'tcx> { if let Some(e) = self.tainted_by_errors() { - return self.tcx.ty_error_with_guaranteed(e); + return self.tcx.ty_error(e); } let definition_ty = instantiated_ty .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; - if !check_opaque_type_parameter_valid( + if let Err(guar) = check_opaque_type_parameter_valid( self.tcx, opaque_type_key, origin, instantiated_ty.span, ) { - return self.tcx.ty_error(); + return self.tcx.ty_error(guar); } // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` @@ -273,9 +273,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // This logic duplicates most of `check_opaque_meets_bounds`. // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id); // HACK This bubble is required for this tests to pass: - // type-alias-impl-trait/issue-67844-nested-opaque.rs + // nested-return-type2-tait2.rs + // nested-return-type2-tait3.rs let infcx = self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); let ocx = ObligationCtxt::new(&infcx); @@ -290,7 +290,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // the bounds that the function supplies. let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs); if let Err(err) = ocx.eq( - &ObligationCause::misc(instantiated_ty.span, body_id), + &ObligationCause::misc(instantiated_ty.span, def_id), param_env, opaque_ty, definition_ty, @@ -298,7 +298,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { infcx .err_ctxt() .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), + &ObligationCause::misc(instantiated_ty.span, def_id), opaque_ty, definition_ty, err, @@ -309,7 +309,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { ocx.register_obligation(Obligation::misc( infcx.tcx, instantiated_ty.span, - body_id, + def_id, param_env, predicate, )); @@ -326,7 +326,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { definition_ty } else { let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); - self.tcx.ty_error_with_guaranteed(reported) + self.tcx.ty_error(reported) } } } @@ -336,7 +336,7 @@ fn check_opaque_type_parameter_valid( opaque_type_key: OpaqueTypeKey<'_>, origin: OpaqueTyOrigin, span: Span, -) -> bool { +) -> Result<(), ErrorGuaranteed> { match origin { // No need to check return position impl trait (RPIT) // because for type and const parameters they are correct @@ -359,7 +359,7 @@ fn check_opaque_type_parameter_valid( // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. // // which would error here on all of the `'static` args. - OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true, + OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()), // Check these OpaqueTyOrigin::TyAlias => {} } @@ -368,18 +368,6 @@ fn check_opaque_type_parameter_valid( for (i, arg) in opaque_type_key.substs.iter().enumerate() { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if lt.is_static() => { - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_label( - tcx.def_span(opaque_generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - return false; - } GenericArgKind::Lifetime(lt) => { matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } @@ -392,13 +380,13 @@ fn check_opaque_type_parameter_valid( // Prevent `fn foo() -> Foo<u32>` from being defining. let opaque_param = opaque_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); - tcx.sess.emit_err(NonGenericOpaqueTypeParam { + + return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam { ty: arg, kind, span, param_span: tcx.def_span(opaque_param.def_id), - }); - return false; + })); } } @@ -409,12 +397,13 @@ fn check_opaque_type_parameter_valid( .into_iter() .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) .collect(); - tcx.sess + return Err(tcx + .sess .struct_span_err(span, "non-defining opaque type use in defining scope") .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - return false; + .emit()); } } - true + + Ok(()) } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c3dfeedc2..8132800f1 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -181,12 +181,13 @@ impl<N: Idx> LivenessValues<N> { /// Maps from `ty::PlaceholderRegion` values that are used in the rest of /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. -#[derive(Default)] +#[derive(Debug, Default)] pub(crate) struct PlaceholderIndices { indices: FxIndexSet<ty::PlaceholderRegion>, } impl PlaceholderIndices { + /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion` pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { let (index, _) = self.indices.insert_full(placeholder); index.into() @@ -234,7 +235,7 @@ pub(crate) struct RegionValues<N: Idx> { free_regions: SparseBitMatrix<N, RegionVid>, /// Placeholders represent bound regions -- so something like `'a` - /// in for<'a> fn(&'a u32)`. + /// in `for<'a> fn(&'a u32)`. placeholders: SparseBitMatrix<N, PlaceholderIndex>, } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 084754830..016f6f78d 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,18 +1,20 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +use crate::BorrowckInferCtxt; use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +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::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_span::{Span, Symbol}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec<Promoted, Body<'tcx>>, ) { @@ -29,27 +31,68 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. -#[instrument(skip(infcx), level = "debug")] -pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T +#[instrument(skip(infcx, get_ctxt_fn), level = "debug")] +pub(crate) fn renumber_regions<'tcx, T, F>( + infcx: &BorrowckInferCtxt<'_, 'tcx>, + value: T, + get_ctxt_fn: F, +) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, + F: Fn() -> RegionCtxt, { infcx.tcx.fold_regions(value, |_region, _depth| { let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - infcx.next_nll_region_var(origin) + infcx.next_nll_region_var(origin, || get_ctxt_fn()) }) } +#[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), + Existential(Option<Symbol>), + Placeholder(BoundRegionInfo), + Unknown, +} + +impl RegionCtxt { + /// Used to determine the representative of a component in the strongly connected + /// constraint graph + pub(crate) fn preference_value(self) -> usize { + let _anon = Symbol::intern("anon"); + + match self { + RegionCtxt::Unknown => 1, + RegionCtxt::Existential(None) => 2, + RegionCtxt::Existential(Some(_anon)) | RegionCtxt::Free(_anon) => 2, + RegionCtxt::Location(_) => 3, + RegionCtxt::TyContext(_) => 4, + _ => 5, + } + } +} + struct NllVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, } impl<'a, 'tcx> NllVisitor<'a, 'tcx> { - fn renumber_regions<T>(&mut self, value: T) -> T + fn renumber_regions<T, F>(&mut self, value: T, region_ctxt_fn: F) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, + F: Fn() -> RegionCtxt, { - renumber_regions(self.infcx, value) + renumber_regions(self.infcx, value, region_ctxt_fn) } } @@ -60,14 +103,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - *ty = self.renumber_regions(*ty); + *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context)); debug!(?ty); } #[instrument(skip(self), level = "debug")] fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { - *substs = self.renumber_regions(*substs); + *substs = self.renumber_regions(*substs, || RegionCtxt::Location(location)); debug!(?substs); } @@ -75,7 +118,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { let old_region = *region; - *region = self.renumber_regions(old_region); + *region = self.renumber_regions(old_region, || RegionCtxt::Location(location)); debug!(?region); } @@ -83,7 +126,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'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); + constant.literal = self.renumber_regions(literal, || 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 23acf1592..a36789290 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,4 +1,4 @@ -use rustc_errors::{IntoDiagnosticArg, MultiSpan}; +use rustc_errors::MultiSpan; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; @@ -55,7 +55,7 @@ pub(crate) struct VarNeedNotMut { #[derive(Diagnostic)] #[diag(borrowck_var_cannot_escape_closure)] #[note] -#[note(cannot_escape)] +#[note(borrowck_cannot_escape)] pub(crate) struct FnMutError { #[primary_span] pub span: Span, @@ -128,18 +128,6 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> { }, } -impl IntoDiagnosticArg for &RegionName { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() - } -} - -impl IntoDiagnosticArg for RegionName { - fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { - format!("{}", self).into_diagnostic_arg() - } -} - #[derive(Subdiagnostic)] pub(crate) enum RequireStaticErr { #[note(borrowck_used_impl_require_static)] @@ -235,7 +223,7 @@ pub(crate) struct MoveBorrow<'a> { pub borrow_place: &'a str, pub value_place: &'a str, #[primary_span] - #[label(move_label)] + #[label(borrowck_move_label)] pub span: Span, #[label] pub borrow_span: Span, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 11729e2c8..b27d5d205 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -2,7 +2,7 @@ use std::fmt; use rustc_infer::infer::{canonical::Canonical, InferOk}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; @@ -66,7 +66,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { canonical: &Canonical<'tcx, T>, ) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { let old_universe = self.infcx.universe(); @@ -117,7 +117,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn prove_predicates( &mut self, - predicates: impl IntoIterator<Item = impl ToPredicate<'tcx> + std::fmt::Debug>, + predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, ) { @@ -181,9 +181,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_ty: ty::UserType<'tcx>, span: Span, ) { - // FIXME: Ideally MIR types are normalized, but this is not always true. - let mir_ty = self.normalize(mir_ty, Locations::All(span)); - self.fully_perform_op( Locations::All(span), ConstraintCategory::Boring, @@ -217,7 +214,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } + // FIXME: Ideally MIR types are normalized, but this is not always true. let mir_ty = self.normalize(mir_ty, Locations::All(span)); + let cause = ObligationCause::dummy_with_span(span); let param_env = self.param_env; let op = |infcx: &'_ _| { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index e15d1b99a..a93561350 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,8 +6,8 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; use crate::{ @@ -83,16 +83,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } self.constraints.member_constraints = tmp; - for (predicate, constraint_category) in outlives { - // At the moment, we never generate any "higher-ranked" - // region constraints like `for<'a> 'a: 'b`. At some point - // when we move to universes, we will, and this assertion - // will start to fail. - let predicate = predicate.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", predicate,); - }); - - self.convert(predicate, *constraint_category); + for &(predicate, constraint_category) in outlives { + self.convert(predicate, constraint_category); } } @@ -124,7 +116,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let outlived_region = closure_mapping[outlives_requirement.outlived_free_region]; let subject = match outlives_requirement.subject { ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(), - ClosureOutlivesSubject::Ty(ty) => ty.into(), + ClosureOutlivesSubject::Ty(subject_ty) => { + subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into() + } }; self.category = outlives_requirement.category; @@ -179,7 +173,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { /// /// FIXME: This should get removed once higher ranked region obligations /// are dealt with during trait solving. - fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { + fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T { if value.has_placeholders() { self.tcx.fold_regions(value, |r, _| match *r { ty::RePlaceholder(placeholder) => { diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 82ff86247..4004966c4 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,6 +8,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -92,31 +93,6 @@ impl UniversalRegionRelations<'_> { res } - /// Returns the "postdominating" bound of the set of - /// `non_local_upper_bounds` for the given region. - pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { - let upper_bounds = self.non_local_upper_bounds(fr); - - // In case we find more than one, reduce to one for - // convenience. This is to prevent us from generating more - // complex constraints, but it will cause spurious errors. - let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds); - - debug!("non_local_bound: post_dom={:?}", post_dom); - - post_dom - .and_then(|post_dom| { - // If the mutual immediate postdom is not local, then - // there is no non-local result we can return. - if !self.universal_regions.is_local_free_region(post_dom) { - Some(post_dom) - } else { - None - } - }) - .unwrap_or(self.universal_regions.fr_static) - } - /// Finds a "lower bound" for `fr` that is not local. In other /// words, returns the largest (*) known region `fr1` that (a) is /// outlived by `fr` and (b) is not local. @@ -217,8 +193,27 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.inverse_outlives.add(fr_b, fr_a); } + #[instrument(level = "debug", skip(self))] pub(crate) fn create(mut self) -> CreateResult<'tcx> { let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id()); + + // Insert the facts we know from the predicates. Why? Why not. + let param_env = self.param_env; + self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); + + // - outlives is reflexive, so `'r: 'r` for every region `'r` + // - `'static: 'r` for every region `'r` + // - `'r: 'fn_body` for every (other) universally quantified + // region `'r`, all of which are provided by our caller + let fr_static = self.universal_regions.fr_static; + let fr_fn_body = self.universal_regions.fr_fn_body; + for fr in self.universal_regions.universal_regions() { + debug!("build: relating free region {:?} to itself and to 'static", fr); + self.relate_universal_regions(fr, fr); + self.relate_universal_regions(fr_static, fr); + self.relate_universal_regions(fr, fr_fn_body); + } + let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -236,78 +231,59 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // the `relations` is built. let mut normalized_inputs_and_output = Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); - let constraint_sets: Vec<_> = unnormalized_input_output_tys - .flat_map(|ty| { - debug!("build: input_or_output={:?}", ty); - // We add implied bounds from both the unnormalized and normalized ty. - // See issue #87748 - let constraints_implied1 = self.add_implied_bounds(ty); - let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self - .param_env - .and(type_op::normalize::Normalize::new(ty)) - .fully_perform(self.infcx) - .unwrap_or_else(|_| { - let reported = self - .infcx - .tcx - .sess - .delay_span_bug(span, &format!("failed to normalize {:?}", ty)); - TypeOpOutput { - output: self.infcx.tcx.ty_error_with_guaranteed(reported), - constraints: None, - error_info: None, - } - }); - // Note: we need this in examples like - // ``` - // trait Foo { - // type Bar; - // fn foo(&self) -> &Self::Bar; - // } - // impl Foo for () { - // type Bar = (); - // fn foo(&self) -> &() {} - // } - // ``` - // Both &Self::Bar and &() are WF - let constraints_implied2 = - if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; - normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2) - }) - .collect(); + let mut constraints = vec![]; + for ty in unnormalized_input_output_tys { + debug!("build: input_or_output={:?}", ty); + // We add implied bounds from both the unnormalized and normalized ty. + // See issue #87748 + let constraints_unnorm = self.add_implied_bounds(ty); + if let Some(c) = constraints_unnorm { + constraints.push(c) + } + let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self + .param_env + .and(type_op::normalize::Normalize::new(ty)) + .fully_perform(self.infcx) + .unwrap_or_else(|_| { + let guar = self + .infcx + .tcx + .sess + .delay_span_bug(span, &format!("failed to normalize {:?}", ty)); + TypeOpOutput { + output: self.infcx.tcx.ty_error(guar), + constraints: None, + error_info: None, + } + }); + if let Some(c) = constraints_normalize { + constraints.push(c) + } - // Insert the facts we know from the predicates. Why? Why not. - let param_env = self.param_env; - self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); + // Note: we need this in examples like + // ``` + // trait Foo { + // type Bar; + // fn foo(&self) -> &Self::Bar; + // } + // impl Foo for () { + // type Bar = (); + // fn foo(&self) ->&() {} + // } + // ``` + // Both &Self::Bar and &() are WF + if ty != norm_ty { + let constraints_norm = self.add_implied_bounds(norm_ty); + if let Some(c) = constraints_norm { + constraints.push(c) + } + } - // Finally: - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - let fr_static = self.universal_regions.fr_static; - let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions() { - debug!("build: relating free region {:?} to itself and to 'static", fr); - self.relate_universal_regions(fr, fr); - self.relate_universal_regions(fr_static, fr); - self.relate_universal_regions(fr, fr_fn_body); + normalized_inputs_and_output.push(norm_ty); } - for data in &constraint_sets { - constraint_conversion::ConstraintConversion::new( - self.infcx, - &self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - Locations::All(span), - span, - ConstraintCategory::Internal, - &mut self.constraints, - ) - .convert_all(data); + for c in constraints { + self.push_region_constraints(c, span); } CreateResult { @@ -321,6 +297,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } } + #[instrument(skip(self, data), level = "debug")] + fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) { + debug!("constraints generated: {:#?}", data); + + constraint_conversion::ConstraintConversion::new( + self.infcx, + &self.universal_regions, + &self.region_bound_pairs, + self.implicit_region_bound, + self.param_env, + Locations::All(span), + span, + ConstraintCategory::Internal, + &mut self.constraints, + ) + .convert_all(data); + } + /// Update the type of a single local, which should represent /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come @@ -332,6 +326,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .fully_perform(self.infcx) .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); + debug!(?bounds, ?constraints); self.add_outlives_bounds(bounds); constraints } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index fa9ea769a..717020ea5 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -26,11 +26,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if !self.tcx().is_closure(mir_def_id.to_def_id()) { return; } - let Some(user_provided_poly_sig) = - self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id) - else { - return; - }; + let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); // Instantiate the canonicalized variables from user-provided signature // (e.g., the `_` in the code above) with fresh variables. @@ -38,7 +34,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // so that they represent the view from "inside" the closure. let user_provided_sig = self .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig); - let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars( + let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( body.span, LateBoundRegionConversionTime::FnCall, user_provided_sig, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index d5c401ae1..a411aec51 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -50,13 +50,11 @@ pub(super) fn generate<'mir, 'tcx>( compute_relevant_live_locals(typeck.tcx(), &free_regions, &body); let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx()); - let polonius_drop_used = if facts_enabled { + let polonius_drop_used = facts_enabled.then(|| { let mut drop_used = Vec::new(); polonius::populate_access_facts(typeck, body, location_table, move_data, &mut drop_used); - Some(drop_used) - } else { - None - }; + drop_used + }); trace::trace( typeck, diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 3ff5d188a..473c05963 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,7 +3,7 @@ use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; -use rustc_middle::ty::{Ty, TypeVisitable}; +use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -477,7 +477,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// points `live_at`. fn add_use_live_facts_for( &mut self, - value: impl TypeVisitable<'tcx>, + value: impl TypeVisitable<TyCtxt<'tcx>>, live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); @@ -542,7 +542,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { fn make_all_regions_live( elements: &RegionValueElements, typeck: &mut TypeChecker<'_, 'tcx>, - value: impl TypeVisitable<'tcx>, + value: impl TypeVisitable<TyCtxt<'tcx>>, live_at: &IntervalSet<PointIndex>, ) { debug!("make_all_regions_live(value={:?})", value); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 81bd4c2a7..a49da3da6 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,7 +30,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; -use rustc_middle::ty::visit::TypeVisitable; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, @@ -64,7 +64,7 @@ use crate::{ region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, - Upvar, + BorrowckInferCtxt, Upvar, }; macro_rules! span_mirbug { @@ -123,7 +123,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map pub(crate) fn type_check<'mir, 'tcx>( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexVec<Promoted, Body<'tcx>>, @@ -137,7 +137,7 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars: &[Upvar<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); + let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), @@ -239,7 +239,7 @@ pub(crate) fn type_check<'mir, 'tcx>( decl.hidden_type.span, &format!("could not resolve {:#?}", hidden_type.ty.kind()), ); - hidden_type.ty = infcx.tcx.ty_error_with_guaranteed(reported); + hidden_type.ty = infcx.tcx.ty_error(reported); } (opaque_type_key, (hidden_type, decl.origin)) @@ -402,7 +402,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); + let unnormalized_ty = tcx.type_of(static_def_id).subst_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; @@ -529,12 +529,12 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { for elem in place.projection.iter() { if place_ty.variant_index.is_none() { - if place_ty.ty.references_error() { + if let Err(guar) = place_ty.ty.error_reported() { assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().ty_error()); + return PlaceTy::from_ty(self.tcx().ty_error(guar)); } } - place_ty = self.sanitize_projection(place_ty, elem, place, location); + place_ty = self.sanitize_projection(place_ty, elem, place, location, context); } if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { @@ -630,12 +630,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn sanitize_projection( &mut self, base: PlaceTy<'tcx>, pi: PlaceElem<'tcx>, place: &Place<'tcx>, location: Location, + context: PlaceContext, ) -> PlaceTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); @@ -713,8 +715,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { match self.field_ty(place, base, field, location) { Ok(ty) => { let ty = self.cx.normalize(ty, location); - if let Err(terr) = self.cx.eq_types( + debug!(?fty, ?ty); + + if let Err(terr) = self.cx.relate_types( ty, + self.get_ambient_variance(context), fty, location.to_locations(), ConstraintCategory::Boring, @@ -743,9 +748,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let ty = self.sanitize_type(place, ty); let ty = self.cx.normalize(ty, location); self.cx - .eq_types( - base.ty, + .relate_types( ty, + self.get_ambient_variance(context), + base.ty, location.to_locations(), ConstraintCategory::TypeAnnotation, ) @@ -757,7 +763,22 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn error(&mut self) -> Ty<'tcx> { self.errors_reported = true; - self.tcx().ty_error() + self.tcx().ty_error_misc() + } + + fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance { + use rustc_middle::mir::visit::NonMutatingUseContext::*; + use rustc_middle::mir::visit::NonUseContext::*; + + match context { + PlaceContext::MutatingUse(_) => ty::Invariant, + PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, + PlaceContext::NonMutatingUse( + Inspect | Copy | Move | SharedBorrow | ShallowBorrow | UniqueBorrow | AddressOf + | Projection, + ) => ty::Covariant, + PlaceContext::NonUse(AscribeUserTy) => ty::Covariant, + } } fn field_ty( @@ -845,7 +866,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -910,6 +931,8 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { } impl<'tcx> MirTypeckRegionConstraints<'tcx> { + /// Creates a `Region` for a given `PlaceholderRegion`, or returns the + /// region that corresponds to a previously created one. fn placeholder_region( &mut self, infcx: &InferCtxt<'tcx>, @@ -996,7 +1019,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'tcx>, + infcx: &'a BorrowckInferCtxt<'a, 'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -1258,6 +1281,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | StatementKind::StorageDead(..) | StatementKind::Retag { .. } | StatementKind::Coverage(..) + | StatementKind::ConstEvalCounter | StatementKind::Nop => {} StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") @@ -1332,11 +1356,34 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; let (sig, map) = tcx.replace_late_bound_regions(sig, |br| { - self.infcx.next_region_var(LateBoundRegion( - term.source_info.span, - br.kind, - LateBoundRegionConversionTime::FnCall, - )) + use crate::renumber::{BoundRegionInfo, RegionCtxt}; + use rustc_span::Symbol; + + let region_ctxt_fn = || { + let reg_info = match br.kind { + ty::BoundRegionKind::BrAnon(_, Some(span)) => { + BoundRegionInfo::Span(span) + } + ty::BoundRegionKind::BrAnon(..) => { + BoundRegionInfo::Name(Symbol::intern("anon")) + } + ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), + ty::BoundRegionKind::BrEnv => { + BoundRegionInfo::Name(Symbol::intern("env")) + } + }; + + RegionCtxt::LateBound(reg_info) + }; + + self.infcx.next_region_var( + LateBoundRegion( + term.source_info.span, + br.kind, + LateBoundRegionConversionTime::FnCall, + ), + region_ctxt_fn, + ) }); debug!(?sig); // IMPORTANT: We have to prove well formed for the function signature before @@ -1483,7 +1530,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } None => { - if !sig.output().is_privately_uninhabited(self.tcx(), self.param_env) { + // The signature in this call can reference region variables, + // so erase them before calling a query. + let output_ty = self.tcx().erase_regions(sig.output()); + if !output_ty.is_privately_uninhabited(self.tcx(), self.param_env) { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } } @@ -1776,7 +1826,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // than 1. // If the length is larger than 1, the repeat expression will need to copy the // element, so we require the `Copy` trait. - if len.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + if len.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) { match operand { Operand::Copy(..) | Operand::Constant(..) => { // These are always okay: direct use of a const, or a value that can evidently be copied. @@ -2027,7 +2077,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; - if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not { + if ty_to_mut.is_mut() && ty_mut.is_not() { span_mirbug!( self, rvalue, @@ -2532,7 +2582,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, substs) | AggregateKind::Generator(def_id, substs, _) => { - (def_id.to_def_id(), self.prove_closure_bounds(tcx, def_id, substs, location)) + (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)) } AggregateKind::Array(_) | AggregateKind::Tuple => { @@ -2583,7 +2633,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { DefKind::InlineConst => substs.as_inline_const().parent_substs(), other => bug!("unexpected item {:?}", other), }; - let parent_substs = tcx.mk_substs(parent_substs.iter()); + let parent_substs = tcx.mk_substs(parent_substs); assert_eq!(typeck_root_substs.len(), parent_substs.len()); if let Err(_) = self.eq_substs( diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b2702eafd..d96372fb9 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,14 +1,15 @@ -use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; +use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; +use crate::renumber::{BoundRegionInfo, RegionCtxt}; use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -100,23 +101,65 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> universe } - fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + #[instrument(skip(self), level = "debug")] + fn next_existential_region_var( + &mut self, + from_forall: bool, + _name: Option<Symbol>, + ) -> ty::Region<'tcx> { let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.type_checker.infcx.next_nll_region_var(origin) + + let reg_var = + self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(_name)); + + reg_var } + #[instrument(skip(self), level = "debug")] fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.type_checker + let reg = self + .type_checker .borrowck_context .constraints - .placeholder_region(self.type_checker.infcx, placeholder) + .placeholder_region(self.type_checker.infcx, placeholder); + + let reg_info = match placeholder.name { + ty::BoundRegionKind::BrAnon(_, Some(span)) => BoundRegionInfo::Span(span), + ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(Symbol::intern("anon")), + ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), + ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(Symbol::intern("env")), + }; + + let reg_var = + reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); + assert!(matches!(prev, None)); + + reg } + #[instrument(skip(self), level = "debug")] fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.type_checker.infcx.next_nll_region_var_in_universe( + let reg = self.type_checker.infcx.next_nll_region_var_in_universe( NllRegionVariableOrigin::Existential { from_forall: false }, universe, - ) + ); + + let reg_var = + reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); + + if cfg!(debug_assertions) { + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); + + // It only makes sense to track region vars in non-canonicalization contexts. If this + // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` + // or modify how we track nll region vars for that map. + assert!(matches!(prev, None)); + } + + reg } fn push_outlives( @@ -140,10 +183,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> ); } - fn normalization() -> NormalizationStrategy { - NormalizationStrategy::Eager - } - fn forbid_inference_vars() -> bool { true } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 5b4d99682..15d7613a8 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -18,17 +18,20 @@ use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyOwnerKind, HirId}; +use rustc_hir::BodyOwnerKind; use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt, }; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_span::Symbol; use std::iter; use crate::nll::ToRegionVid; +use crate::renumber::{BoundRegionInfo, RegionCtxt}; +use crate::BorrowckInferCtxt; #[derive(Debug)] pub struct UniversalRegions<'tcx> { @@ -162,11 +165,14 @@ struct UniversalRegionIndices<'tcx> { /// `ty::Region` to the internal `RegionVid` we are using. This is /// used because trait matching and type-checking will feed us /// region constraints that reference those regions and we need to - /// be able to map them our internal `RegionVid`. This is + /// be able to map them to our internal `RegionVid`. This is /// basically equivalent to an `InternalSubsts`, except that it also /// contains an entry for `ReStatic` -- it might be nice to just /// use a substs, and then handle `ReStatic` another way. indices: FxHashMap<ty::Region<'tcx>, RegionVid>, + + /// The vid assigned to `'static`. Used only for diagnostics. + pub fr_static: RegionVid, } #[derive(Debug, PartialEq)] @@ -221,13 +227,11 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &InferCtxt<'tcx>, + infcx: &BorrowckInferCtxt<'_, 'tcx>, mir_def: ty::WithOptConstParam<LocalDefId>, param_env: ty::ParamEnv<'tcx>, ) -> Self { - let tcx = infcx.tcx; - let mir_hir_id = tcx.hir().local_def_id_to_hir_id(mir_def.did); - UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build() + UniversalRegionsBuilder { infcx, mir_def, param_env }.build() } /// Given a reference to a closure type, extracts all the values @@ -382,9 +386,8 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, + infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, mir_def: ty::WithOptConstParam<LocalDefId>, - mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, } @@ -400,7 +403,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(FIRST_GLOBAL_INDEX, self.infcx.num_region_vars()); // Create the "global" region that is always free in all contexts: 'static. - let fr_static = self.infcx.next_nll_region_var(FR).to_region_vid(); + let fr_static = self + .infcx + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("static"))) + .to_region_vid(); // We've now added all the global regions. The next ones we // add will be external. @@ -432,7 +438,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.infcx.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.infcx.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -460,7 +476,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.infcx.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.infcx.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -472,28 +498,32 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // C-variadic fns also have a `VaList` input that's not listed in the signature // (as it's created inside the body itself, not passed in from outside). if let DefiningTy::FnDef(def_id, _) = defining_ty { - if self.infcx.tcx.fn_sig(def_id).c_variadic() { + if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { let va_list_did = self.infcx.tcx.require_lang_item( LangItem::VaList, Some(self.infcx.tcx.def_span(self.mir_def.did)), ); - let region = self - .infcx - .tcx - .mk_region(ty::ReVar(self.infcx.next_nll_region_var(FR).to_region_vid())); - let va_list_ty = self + + let reg_vid = self .infcx - .tcx - .bound_type_of(va_list_did) - .subst(self.infcx.tcx, &[region.into()]); + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) + .to_region_vid(); + + let region = self.infcx.tcx.mk_re_var(reg_vid); + let va_list_ty = + self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); - unnormalized_input_tys = self.infcx.tcx.mk_type_list( + unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter( unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)), ); } } - let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid(); + let fr_fn_body = self + .infcx + .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body"))) + .to_region_vid(); + let num_universals = self.infcx.num_region_vars(); debug!("build: global regions = {}..{}", FIRST_GLOBAL_INDEX, first_extern_index); @@ -527,12 +557,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { match tcx.hir().body_owner_kind(self.mir_def.did) { BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id { - tcx.type_of(typeck_root_def_id) - } else { - let tables = tcx.typeck(self.mir_def.did); - tables.node_type(self.mir_hir_id) - }; + let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity(); debug!("defining_ty (pre-replacement): {:?}", defining_ty); @@ -561,7 +586,18 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs); DefiningTy::Const(self.mir_def.did.to_def_id(), substs) } else { - let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id); + // FIXME this line creates a dependency between borrowck and typeck. + // + // This is required for `AscribeUserType` canonical query, which will call + // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes + // into borrowck, which is ICE #78174. + // + // As a workaround, inline consts have an additional generic param (`ty` + // below), so that `type_of(inline_const_def_id).substs(substs)` uses the + // proper type with NLL infer vars. + let ty = tcx + .typeck(self.mir_def.did) + .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did)); let substs = InlineConstSubsts::new( tcx, InlineConstSubstsParts { parent_substs: identity_substs, ty }, @@ -609,7 +645,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let subst_mapping = iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid())); - UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() } + UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static } } fn compute_inputs_and_output( @@ -623,7 +659,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(self.mir_def.did.to_def_id(), def_id); let closure_sig = substs.as_closure().sig(); let inputs_and_output = closure_sig.inputs_and_output(); - let bound_vars = tcx.mk_bound_variable_kinds( + let bound_vars = tcx.mk_bound_variable_kinds_from_iter( inputs_and_output .bound_vars() .iter() @@ -633,7 +669,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); + let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); // The "inputs" of the closure in the @@ -647,7 +683,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { }; ty::Binder::bind_with_vars( - tcx.mk_type_list( + tcx.mk_type_list_from_iter( iter::once(closure_ty).chain(inputs).chain(iter::once(output)), ), bound_vars, @@ -660,12 +696,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let output = substs.as_generator().return_ty(); let generator_ty = tcx.mk_generator(def_id, substs, movability); let inputs_and_output = - self.infcx.tcx.intern_type_list(&[generator_ty, resume_ty, output]); + self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]); ty::Binder::dummy(inputs_and_output) } DefiningTy::FnDef(def_id, _) => { - let sig = tcx.fn_sig(def_id); + let sig = tcx.fn_sig(def_id).subst_identity(); let sig = indices.fold_to_region_vids(tcx, sig); sig.inputs_and_output() } @@ -674,15 +710,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // For a constant body, there are no inputs, and one // "output" (the type of the constant). assert_eq!(self.mir_def.did.to_def_id(), def_id); - let ty = tcx.type_of(self.mir_def.def_id_for_type_of()); + let ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity(); let ty = indices.fold_to_region_vids(tcx, ty); - ty::Binder::dummy(tcx.intern_type_list(&[ty])) + ty::Binder::dummy(tcx.mk_type_list(&[ty])) } DefiningTy::InlineConst(def_id, substs) => { assert_eq!(self.mir_def.did.to_def_id(), def_id); let ty = substs.as_inline_const().ty(); - ty::Binder::dummy(tcx.intern_type_list(&[ty])) + ty::Binder::dummy(tcx.mk_type_list(&[ty])) } } } @@ -695,7 +731,7 @@ trait InferCtxtExt<'tcx> { value: T, ) -> T where - T: TypeFoldable<'tcx>; + T: TypeFoldable<TyCtxt<'tcx>>; fn replace_bound_regions_with_nll_infer_vars<T>( &self, @@ -705,7 +741,7 @@ trait InferCtxtExt<'tcx> { indices: &mut UniversalRegionIndices<'tcx>, ) -> T where - T: TypeFoldable<'tcx>; + T: TypeFoldable<TyCtxt<'tcx>>; fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope( &self, @@ -720,16 +756,27 @@ trait InferCtxtExt<'tcx> { ); } -impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { +impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { + #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars<T>( &self, origin: NllRegionVariableOrigin, value: T, ) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { - self.tcx.fold_regions(value, |_region, _depth| self.next_nll_region_var(origin)) + self.infcx.tcx.fold_regions(value, |region, _depth| { + let name = match region.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + debug!(?region, ?name); + + let reg_var = self.next_nll_region_var(origin, || RegionCtxt::Free(name)); + + reg_var + }) } #[instrument(level = "debug", skip(self, indices))] @@ -741,15 +788,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { indices: &mut UniversalRegionIndices<'tcx>, ) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); - let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: all_outlive_scope.to_def_id(), - bound_region: br.kind, - })); - let region_vid = self.next_nll_region_var(origin); + let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind); + let region_vid = { + let name = match br.kind.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name))) + }; + indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid()); debug!(?liberated_region, ?region_vid); region_vid @@ -775,7 +827,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.next_nll_region_var(FR); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.to_region_vid()); } @@ -791,8 +853,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| { debug!(?r); if !indices.indices.contains_key(&r) { - let region_vid = self.next_nll_region_var(FR); - debug!(?region_vid); + let region_vid = { + let name = match r.get_name() { + Some(name) => name, + _ => Symbol::intern("anon"), + }; + + self.next_nll_region_var(FR, || { + RegionCtxt::LateBound(BoundRegionInfo::Name(name)) + }) + }; + indices.insert_late_bound_region(r, region_vid.to_region_vid()); } }); @@ -821,6 +892,11 @@ impl<'tcx> UniversalRegionIndices<'tcx> { pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { if let ty::ReVar(..) = *r { r.to_region_vid() + } else if r.is_error() { + // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the + // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if + // errors are being emitted and 2) it leaves the happy path unaffected. + self.fr_static } else { *self .indices @@ -833,9 +909,9 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// returned by `to_region_vid`. pub fn fold_to_region_vids<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T where - T: TypeFoldable<'tcx>, + T: TypeFoldable<TyCtxt<'tcx>>, { - tcx.fold_regions(value, |region, _| tcx.mk_region(ty::ReVar(self.to_region_vid(region)))) + tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region))) } } @@ -875,8 +951,7 @@ fn for_each_late_bound_region_in_item<'tcx>( for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) { let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; }; - let liberated_region = tcx - .mk_region(ty::ReFree(ty::FreeRegion { scope: mir_def_id.to_def_id(), bound_region })); + let liberated_region = tcx.mk_re_free(mir_def_id.to_def_id(), bound_region); f(liberated_region); } } |