diff options
Diffstat (limited to 'compiler/rustc_borrowck')
23 files changed, 476 insertions, 381 deletions
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6be20b097..0b44beeb0 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -72,8 +72,11 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { let kind = match self.kind { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", - mir::BorrowKind::Unique => "uniq ", - mir::BorrowKind::Mut { .. } => "mut ", + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", + // FIXME: differentiate `TwoPhaseBorrow` + mir::BorrowKind::Mut { + kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, + } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index acca1a147..a4e0e773a 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -278,7 +278,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, move_from_desc: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { - struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,) + struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc) } /// Signal an error due to an attempt to move out of the interior diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 2aa09a3f2..743d117e0 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -4,8 +4,8 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::visit::TyContext; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, - SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection, + Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement, + StatementKind, Terminator, TerminatorKind, UserTypeProjection, }; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::visit::TypeVisitable; @@ -49,10 +49,6 @@ struct ConstraintGeneration<'cg, 'tcx> { } impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> { - fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) { - self.super_basic_block_data(bb, data); - } - /// We sometimes have `substs` within an rvalue, or within a /// call. Make them live at the location where they appear. fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) { diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 2daa82aef..1064b44d2 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -59,7 +59,7 @@ macro_rules! impl_visitable { } fn reconstruct_before_statement_effect( - &self, + &mut self, state: &mut Self::FlowState, stmt: &mir::Statement<'tcx>, loc: Location, @@ -69,7 +69,7 @@ macro_rules! impl_visitable { } fn reconstruct_statement_effect( - &self, + &mut self, state: &mut Self::FlowState, stmt: &mir::Statement<'tcx>, loc: Location, @@ -79,7 +79,7 @@ macro_rules! impl_visitable { } fn reconstruct_before_terminator_effect( - &self, + &mut self, state: &mut Self::FlowState, term: &mir::Terminator<'tcx>, loc: Location, @@ -89,7 +89,7 @@ macro_rules! impl_visitable { } fn reconstruct_terminator_effect( - &self, + &mut self, state: &mut Self::FlowState, term: &mir::Terminator<'tcx>, loc: Location, @@ -125,15 +125,9 @@ pub struct Borrows<'a, 'tcx> { borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, } -struct StackEntry { - bb: mir::BasicBlock, - lo: usize, - hi: usize, -} - struct OutOfScopePrecomputer<'a, 'tcx> { visited: BitSet<mir::BasicBlock>, - visit_stack: Vec<StackEntry>, + visit_stack: Vec<mir::BasicBlock>, body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>, borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, @@ -158,29 +152,50 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { borrow_region: RegionVid, first_location: Location, ) { - // We visit one BB at a time. The complication is that we may start in the - // middle of the first BB visited (the one containing `first_location`), in which - // case we may have to later on process the first part of that BB if there - // is a path back to its start. - - // For visited BBs, we record the index of the first statement processed. - // (In fully processed BBs this index is 0.) Note also that we add BBs to - // `visited` once they are added to `stack`, before they are actually - // processed, because this avoids the need to look them up again on - // completion. - self.visited.insert(first_location.block); - let first_block = first_location.block; - let mut first_lo = first_location.statement_index; - let first_hi = self.body[first_block].statements.len(); + let first_bb_data = &self.body.basic_blocks[first_block]; + + // This is the first block, we only want to visit it from the creation of the borrow at + // `first_location`. + let first_lo = first_location.statement_index; + let first_hi = first_bb_data.statements.len(); + + if let Some(kill_stmt) = self.regioncx.first_non_contained_inclusive( + borrow_region, + first_block, + first_lo, + first_hi, + ) { + let kill_location = Location { block: first_block, statement_index: kill_stmt }; + // If region does not contain a point at the location, then add to list and skip + // successor locations. + debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location); + self.borrows_out_of_scope_at_location + .entry(kill_location) + .or_default() + .push(borrow_index); + + // The borrow is already dead, there is no need to visit other blocks. + return; + } - self.visit_stack.push(StackEntry { bb: first_block, lo: first_lo, hi: first_hi }); + // The borrow is not dead. Add successor BBs to the work list, if necessary. + for succ_bb in first_bb_data.terminator().successors() { + if self.visited.insert(succ_bb) { + self.visit_stack.push(succ_bb); + } + } - 'preorder: while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() { + // We may end up visiting `first_block` again. This is not an issue: we know at this point + // that it does not kill the borrow in the `first_lo..=first_hi` range, so checking the + // `0..first_lo` range and the `0..first_hi` range give the same result. + while let Some(block) = self.visit_stack.pop() { + let bb_data = &self.body[block]; + let num_stmts = bb_data.statements.len(); if let Some(kill_stmt) = - self.regioncx.first_non_contained_inclusive(borrow_region, bb, lo, hi) + self.regioncx.first_non_contained_inclusive(borrow_region, block, 0, num_stmts) { - let kill_location = Location { block: bb, statement_index: kill_stmt }; + let kill_location = Location { block, statement_index: kill_stmt }; // If region does not contain a point at the location, then add to list and skip // successor locations. debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location); @@ -188,38 +203,15 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { .entry(kill_location) .or_default() .push(borrow_index); - continue 'preorder; - } - // If we process the first part of the first basic block (i.e. we encounter that block - // for the second time), we no longer have to visit its successors again. - if bb == first_block && hi != first_hi { + // We killed the borrow, so we do not visit this block's successors. continue; } // Add successor BBs to the work list, if necessary. - let bb_data = &self.body[bb]; - debug_assert!(hi == bb_data.statements.len()); for succ_bb in bb_data.terminator().successors() { - if !self.visited.insert(succ_bb) { - if succ_bb == first_block && first_lo > 0 { - // `succ_bb` has been seen before. If it wasn't - // fully processed, add its first part to `stack` - // for processing. - self.visit_stack.push(StackEntry { bb: succ_bb, lo: 0, hi: first_lo - 1 }); - - // And update this entry with 0, to represent the - // whole BB being processed. - first_lo = 0; - } - } else { - // succ_bb hasn't been seen before. Add it to - // `stack` for processing. - self.visit_stack.push(StackEntry { - bb: succ_bb, - lo: 0, - hi: self.body[succ_bb].statements.len(), - }); + if self.visited.insert(succ_bb) { + self.visit_stack.push(succ_bb); } } } @@ -343,7 +335,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; fn before_statement_effect( - &self, + &mut self, trans: &mut impl GenKill<Self::Idx>, _statement: &mir::Statement<'tcx>, location: Location, @@ -352,7 +344,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } fn statement_effect( - &self, + &mut self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, location: Location, @@ -400,7 +392,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } fn before_terminator_effect( - &self, + &mut self, trans: &mut impl GenKill<Self::Idx>, _terminator: &mir::Terminator<'tcx>, location: Location, @@ -409,7 +401,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } fn terminator_effect( - &self, + &mut self, trans: &mut impl GenKill<Self::Idx>, terminator: &mir::Terminator<'tcx>, _location: Location, @@ -426,7 +418,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } fn call_return_effect( - &self, + &mut self, _trans: &mut impl GenKill<Self::Idx>, _block: mir::BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index f41795d60..cfcf31fce 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -180,24 +180,25 @@ trait TypeOpInfo<'tcx> { return; }; - let placeholder_region = tcx.mk_re_placeholder(ty::Placeholder { - universe: adjusted_universe.into(), - bound: placeholder.bound, - }); - - 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_re_placeholder(ty::Placeholder { - universe: adjusted.into(), - bound: error_placeholder.bound, - }) - }) - } else { - None - }; + let placeholder_region = ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, + ); + + 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| { + ty::Region::new_placeholder( + tcx, + ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, + ) + }) + } else { + None + }; debug!(?placeholder_region); @@ -390,7 +391,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_re_var(vid)), + |vid| ocx.infcx.universe_of_region(ty::Region::new_var(ocx.infcx.tcx, vid)), ) } @@ -411,7 +412,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_re_var(vid), cause.clone())) + Some((ty::Region::new_var(infcx.tcx, 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 15d73ed73..c8c8b72b3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,6 +1,5 @@ -use std::iter; - use either::Either; +use hir::PatField; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ @@ -14,9 +13,10 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, + self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_middle::util::CallKind; @@ -27,6 +27,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; +use std::iter; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -677,8 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| { - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() + let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| { + if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && pred.self_ty() == ty { if Some(pred.def_id()) == tcx.lang_items().fn_trait() { @@ -704,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx .explicit_item_bounds(def_id) .subst_iter_copied(tcx, substs) - .find_map(find_fn_kind_from_did), + .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))), ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), @@ -775,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let predicates: Result<Vec<_>, _> = errors .into_iter() .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { match predicate.self_ty().kind() { ty::Param(param_ty) => Ok(( generics.type_param(param_ty, tcx), @@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME: supply non-"" `opt_via` when appropriate let first_borrow_desc; let mut err = match (gen_borrow_kind, issued_borrow.kind) { - (BorrowKind::Shared, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Shared, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "mutable "; self.cannot_reborrow_already_borrowed( span, @@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ) } - (BorrowKind::Mut { .. }, BorrowKind::Shared) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Shared, + ) => { first_borrow_desc = "immutable "; let mut err = self.cannot_reborrow_already_borrowed( span, @@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "first "; let mut err = self.cannot_mutably_borrow_multiply( span, @@ -972,7 +982,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &msg_borrow, None, ); - self.suggest_split_at_mut_if_applicable( + self.suggest_slice_method_if_applicable( &mut err, place, issued_borrow.borrowed_place, @@ -982,15 +992,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { issued_borrow.borrowed_place, &issued_spans, ); + self.explain_iterator_advancement_in_for_loop_if_applicable( + &mut err, + span, + &issued_spans, + ); err } - (BorrowKind::Unique, BorrowKind::Unique) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + ) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1004,7 +1022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(BorrowKind::Unique), + Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { @@ -1038,7 +1056,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - (BorrowKind::Unique, _) => { + (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_one_closure( span, @@ -1052,7 +1070,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Unique) => { + (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1067,7 +1085,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Mut { .. }, BorrowKind::Unique) => { + (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1085,10 +1103,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) | ( BorrowKind::Shallow, - BorrowKind::Mut { .. } - | BorrowKind::Unique - | BorrowKind::Shared - | BorrowKind::Shallow, + BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, ) => unreachable!(), }; @@ -1252,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - fn suggest_split_at_mut_if_applicable( + fn suggest_slice_method_if_applicable( &self, err: &mut Diagnostic, place: Place<'tcx>, @@ -1264,7 +1279,75 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.help( "consider using `.split_at_mut(position)` or similar method to obtain \ two mutable non-overlapping sub-slices", - ); + ) + .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); + } + } + + /// Suggest using `while let` for call `next` on an iterator in a for loop. + /// + /// For example: + /// ```ignore (illustrative) + /// + /// for x in iter { + /// ... + /// iter.next() + /// } + /// ``` + pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable( + &self, + err: &mut Diagnostic, + span: Span, + issued_spans: &UseSpans<'tcx>, + ) { + let issue_span = issued_spans.args_or_use(); + let tcx = self.infcx.tcx; + let hir = tcx.hir(); + + let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return }; + let typeck_results = tcx.typeck(self.mir_def_id()); + + struct ExprFinder<'hir> { + issue_span: Span, + expr_span: Span, + body_expr: Option<&'hir hir::Expr<'hir>>, + loop_bind: Option<Symbol>, + } + impl<'hir> Visitor<'hir> for ExprFinder<'hir> { + fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { + if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind && + let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind && + let hir::ExprKind::Call(path, _args) = call.kind && + let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind && + let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind && + let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path && + let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field && + self.issue_span.source_equal(call.span) { + self.loop_bind = Some(ident.name); + } + + if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind && + body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) { + self.body_expr = Some(ex); + } + + hir::intravisit::walk_expr(self, ex); + } + } + let mut finder = + ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None }; + finder.visit_expr(hir.body(body_id).value); + + if let Some(loop_bind) = finder.loop_bind && + let Some(body_expr) = finder.body_expr && + let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) && + let Some(trait_did) = tcx.trait_of_item(def_id) && + tcx.is_diagnostic_item(sym::Iterator, trait_did) { + err.note(format!( + "a for loop advances the iterator for you, the result is stored in `{}`.", + loop_bind + )); + err.help("if you want to call `next` on a iterator within the loop, consider using `while let`."); } } @@ -1720,18 +1803,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ( Some(name), BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), - ) => self.report_escaping_closure_capture( - borrow_spans, - borrow_span, - &RegionName { - name: self.synthesize_region_name(), - source: RegionNameSource::Static, - }, - ConstraintCategory::CallArgument(None), - var_or_use_span, - &format!("`{}`", name), - "block", - ), + ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self + .report_escaping_closure_capture( + borrow_spans, + borrow_span, + &RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::Static, + }, + ConstraintCategory::CallArgument(None), + var_or_use_span, + &format!("`{}`", name), + "block", + ), ( Some(name), BorrowExplanation::MustBeValidFor { @@ -1744,7 +1828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span, .. }, - ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self + ) if borrow_spans.for_generator() || borrow_spans.for_closure() => self .report_escaping_closure_capture( borrow_spans, borrow_span, @@ -2579,7 +2663,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) { let tcx = self.infcx.tcx; if let ( - Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }), + Some(Terminator { + kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. }, + .. + }), Some((method_did, method_substs)), ) = ( &self.body[loan.reserve_location.block].terminator, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1d430a93a..225c38efb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,10 +6,10 @@ use rustc_hir::intravisit::Visitor; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, - Rvalue, Statement, StatementKind, TerminatorKind, + Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, + Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, }; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; @@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else if self.was_captured_by_trait_object(borrow) { LaterUseKind::TraitCapture } else if location.statement_index == block.statements.len() { - if let TerminatorKind::Call { func, from_hir_call: true, .. } = + if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } = &block.terminator().kind { // Just point to the function, to reduce the chance of overlapping spans. @@ -584,7 +584,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, // If we see an unsized cast, then if it is our data we should check // whether it is being cast to a trait object. - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => { + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::Unsize), + operand, + ty, + ) => { match operand { Operand::Copy(place) | Operand::Move(place) => { if let Some(from) = place.as_local() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 20370e4c6..d292611e6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,8 +13,9 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !is_terminator { continue; } else if let Some(Terminator { - kind: TerminatorKind::Call { func, from_hir_call: false, .. }, + kind: + TerminatorKind::Call { + func, + call_source: CallSource::OverloadedOperator, + .. + }, .. }) = &bbd.terminator { @@ -622,8 +628,7 @@ impl UseSpans<'_> { err.subdiagnostic(match kind { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Unique => { + | rustc_middle::mir::BorrowKind::Shallow => { CaptureVarKind::Immut { kind_span: capture_kind_span } } @@ -839,7 +844,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. + kind: TerminatorKind::Call { fn_span, call_source, .. }, .. }) = &self.body[location.block].terminator { let Some((method_did, method_substs)) = @@ -859,7 +864,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { method_did, method_substs, *fn_span, - *from_hir_call, + call_source.from_hir_call(), Some(self.infcx.tcx.fn_arg_names(method_did)[0]), ); @@ -1045,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(def_id) => type_known_to_meet_bound_modulo_regions( &self.infcx, self.param_env, - tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty), + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty), def_id, ), _ => false, @@ -1141,6 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Avoid pointing to the same function in multiple different // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { + self.explain_iterator_advancement_in_for_loop_if_applicable( + err, + span, + &move_spans, + ); + let func = tcx.def_path_str(method_did); err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { func, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d0e17bf5a..1f2fefadf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -123,13 +123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { item_msg = access_place_desc; debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(is_closure_or_generator( - Place::ty_from( - the_place_err.local, - the_place_err.projection, - self.body, - self.infcx.tcx - ) - .ty + the_place_err.ty(self.body, self.infcx.tcx).ty )); reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { @@ -234,7 +228,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }), + Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { let place = self.describe_any_place(access_place.as_ref()); crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { @@ -300,7 +294,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, mir::Rvalue::Ref( _, - mir::BorrowKind::Mut { allow_two_phase_borrow: false }, + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, _, ), )), @@ -416,12 +410,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, ) = pat.kind { - err.span_suggestion( - upvar_ident.span, - "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), - Applicability::MachineApplicable, - ); + if upvar_ident.name == kw::SelfLower { + for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) { + if let Some(fn_decl) = node.fn_decl() { + if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) { + err.span_suggestion( + upvar_ident.span, + "consider changing this to be mutable", + format!("mut {}", upvar_ident.name), + Applicability::MachineApplicable, + ); + break; + } + } + } + } else { + err.span_suggestion( + upvar_ident.span, + "consider changing this to be mutable", + format!("mut {}", upvar_ident.name), + Applicability::MachineApplicable, + ); + } } let tcx = self.infcx.tcx; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8ec872e20..617c85174 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -508,7 +508,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let generic_arg = substs[param_index as usize]; let identity_substs = InternalSubsts::identity_for_item(self.infcx.tcx, adt.did()); - let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs); + let base_ty = Ty::new_adt(self.infcx.tcx, *adt, identity_substs); let base_generic_arg = identity_substs[param_index as usize]; let adt_desc = adt.descr(); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index f38e1605f..074f37bed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -928,7 +928,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { fn any_param_predicate_mentions( &self, - predicates: &[ty::Predicate<'tcx>], + clauses: &[ty::Clause<'tcx>], ty: Ty<'tcx>, region: ty::EarlyBoundRegion, ) -> bool { @@ -937,10 +937,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Param(_) = ty.kind() { - predicates.iter().any(|pred| { + clauses.iter().any(|pred| { match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {} - ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {} + ty::ClauseKind::Trait(data) if data.self_ty() == ty => {} + ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {} _ => return false, } tcx.any_free_region_meets(pred, |r| { diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index b2ff25ecb..0152d89eb 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(location, func); @@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: mir::MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { } (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => { + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { // Reads don't invalidate shared or shallow borrows } - (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it @@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a53ea100c..97d15cb53 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -29,8 +29,8 @@ use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, - Place, PlaceElem, PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability, + NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; @@ -222,7 +222,7 @@ fn do_mir_borrowck<'tcx>( let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) = match MoveData::gather_moves(&body, tcx, param_env) { - Ok((_, move_data)) => (move_data, Vec::new()), + Ok(move_data) => (move_data, Vec::new()), Err((move_data, move_errors)) => (move_data, move_errors), }; let promoted_errors = promoted @@ -368,7 +368,7 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. mbcx.report_region_errors(nll_errors); - let results = BorrowckResults { + let mut results = BorrowckResults { ever_inits: flow_ever_inits, uninits: flow_uninits, borrows: flow_borrows, @@ -379,7 +379,7 @@ fn do_mir_borrowck<'tcx>( rustc_mir_dataflow::visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &results, + &mut results, &mut mbcx, ); @@ -598,11 +598,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> { // 2. loans made in overlapping scopes do not conflict // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> { +impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> { type FlowState = Flows<'cx, 'tcx>; fn visit_statement_before_primary_effect( &mut self, + _results: &R, flow_state: &Flows<'cx, 'tcx>, stmt: &'cx Statement<'tcx>, location: Location, @@ -672,6 +673,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx fn visit_terminator_before_primary_effect( &mut self, + _results: &R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, @@ -708,7 +710,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _, } => { self.consume_operand(loc, (func, span), flow_state); @@ -782,6 +784,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx fn visit_terminator_after_primary_effect( &mut self, + _results: &R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, @@ -1068,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => Control::Continue, + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + Control::Continue + } (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be @@ -1084,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); @@ -1191,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -1228,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -1562,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( @@ -1956,16 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) - | Write(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) => { - let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Unique => LocalMutationIsAllowed::Yes, - BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), + Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { + let is_local_mutation_allowed = match mut_borrow_kind { + // `ClosureCapture` is used for mutable variable with a immutable binding. + // This is only behaviour difference between `ClosureCapture` and mutable borrows. + MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, + MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { + is_local_mutation_allowed + } }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { @@ -2028,12 +2029,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow( - BorrowKind::Unique - | BorrowKind::Mut { .. } - | BorrowKind::Shared - | BorrowKind::Shallow, - ) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow) | ReadKind::Copy, ) => { // Access authorized diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 889acb3ac..b5014a3f4 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -441,7 +441,7 @@ fn for_each_region_constraint<'tcx>( let subject = match req.subject { ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject), ClosureOutlivesSubject::Ty(ty) => { - format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) + format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) } }; with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index d521d0db2..3d7e8c6eb 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -46,11 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { } } - for (i, elem) in self.projection.iter().enumerate() { - let proj_base = &self.projection[..i]; - + for (i, (proj_base, elem)) in self.iter_projections().enumerate() { if elem == ProjectionElem::Deref { - let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; + let ty = proj_base.ty(body, tcx).ty; match ty.kind() { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { // For references to thread-local statics, we do need diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 25c485b81..1217dcb9c 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -4,7 +4,9 @@ use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; use rustc_hir as hir; -use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; +use rustc_middle::mir::{ + Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, +}; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; use std::iter; @@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>( tcx, body, borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow }, access_place.as_ref(), AccessDepth::Deep, bias, @@ -135,13 +137,11 @@ fn place_components_conflict<'tcx>( } // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - for (i, (borrow_c, &access_c)) in - iter::zip(borrow_place.projection, access_place.projection).enumerate() + for ((borrow_place, borrow_c), &access_c) in + iter::zip(borrow_place.iter_projections(), access_place.projection) { debug!(?borrow_c, ?access_c); - let borrow_proj_base = &borrow_place.projection[..i]; - // Borrow and access path both have more components. // // Examples: @@ -154,15 +154,7 @@ fn place_components_conflict<'tcx>( // check whether the components being borrowed vs // accessed are disjoint (as in the second example, // but not the first). - match place_projection_conflict( - tcx, - body, - borrow_local, - borrow_proj_base, - borrow_c, - access_c, - bias, - ) { + match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) { Overlap::Arbitrary => { // We have encountered different fields of potentially // the same union - the borrow now partially overlaps. @@ -193,8 +185,7 @@ fn place_components_conflict<'tcx>( } if borrow_place.projection.len() > access_place.projection.len() { - for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate() - { + for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) { // Borrow path is longer than the access path. Examples: // // - borrow of `a.b.c`, access to `a.b` @@ -203,8 +194,7 @@ fn place_components_conflict<'tcx>( // our place. This is a conflict if that is a part our // access cares about. - let proj_base = &borrow_place.projection[..access_place.projection.len() + i]; - let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty; + let base_ty = base.ty(body, tcx).ty; match (elem, &base_ty.kind(), access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -308,8 +298,7 @@ fn place_base_conflict(l1: Local, l2: Local) -> Overlap { fn place_projection_conflict<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - pi1_local: Local, - pi1_proj_base: &[PlaceElem<'tcx>], + pi1: PlaceRef<'tcx>, pi1_elem: PlaceElem<'tcx>, pi2_elem: PlaceElem<'tcx>, bias: PlaceConflictBias, @@ -331,7 +320,7 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; + let ty = pi1.ty(body, tcx).ty; if ty.is_union() { // Different fields of a union, we are basically stuck. debug!("place_element_conflict: STUCK-UNION"); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 50b246b14..e45d3a2c8 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1139,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { _ => arg.fold_with(self), } }); - tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs)) + Ty::new_opaque(tcx, def_id, tcx.mk_substs_from_iter(substs)) } } @@ -1158,7 +1158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .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)) + .map(|u_r| ty::Region::new_var(tcx, u_r)) // In the case of a failure, use `ReErased`. We will eventually // return `None` in this case. .unwrap_or(tcx.lifetimes.re_erased) @@ -1355,7 +1355,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let vid = self.to_region_vid(r); let scc = self.constraint_sccs.scc(vid); let repr = self.scc_representatives[scc]; - tcx.mk_re_var(repr) + ty::Region::new_var(tcx, repr) }) } @@ -1779,7 +1779,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // If not, report an error. - let member_region = infcx.tcx.mk_re_var(member_region_vid); + let member_region = ty::Region::new_var(infcx.tcx, member_region_vid); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { span: m_c.definition_span, hidden_ty: m_c.hidden_ty, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7fc89e89a..1a227f2d1 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, - opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); @@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect(); debug!(?member_constraints); - for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { + for (opaque_type_key, concrete_type) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -92,7 +92,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } None => { subst_regions.push(vid); - infcx.tcx.mk_re_error_with_message( + ty::Region::new_error_with_message( + infcx.tcx, concrete_type.span, "opaque type with non-universal region substs", ) @@ -142,7 +143,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { let ty = infcx.infer_opaque_definition_from_instantiation( opaque_type_key, universal_concrete_type, - origin, ); // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` @@ -158,7 +158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) .emit() }); - prev.ty = infcx.tcx.ty_error(guar); + prev.ty = Ty::new_error(infcx.tcx, guar); } // Pick a better span if there is one. // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. @@ -214,7 +214,6 @@ pub trait InferCtxtExt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, ) -> Ty<'tcx>; } @@ -247,99 +246,117 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - origin: OpaqueTyOrigin, ) -> Ty<'tcx> { if let Some(e) = self.tainted_by_errors() { - return self.tcx.ty_error(e); + return Ty::new_error(self.tcx, e); + } + + if let Err(guar) = + check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span) + { + return Ty::new_error(self.tcx, guar); } let definition_ty = instantiated_ty .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false) .ty; - if let Err(guar) = check_opaque_type_parameter_valid( + // `definition_ty` does not live in of the current inference context, + // so lets make sure that we don't accidentally misuse our current `infcx`. + match check_opaque_type_well_formed( self.tcx, - opaque_type_key, - origin, + self.next_trait_solver(), + opaque_type_key.def_id, instantiated_ty.span, + definition_ty, ) { - return self.tcx.ty_error(guar); + Ok(hidden_ty) => hidden_ty, + Err(guar) => Ty::new_error(self.tcx, guar), } + } +} - // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` - // on stable and we'd break that. - let OpaqueTyOrigin::TyAlias { .. } = origin else { - return definition_ty; - }; - let def_id = opaque_type_key.def_id; - // 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); - // HACK This bubble is required for this tests to pass: - // 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); - // Require the hidden type to be well-formed with only the generics of the opaque type. - // Defining use functions may have more bounds than the opaque type, which is ok, as long as the - // hidden type is well formed even without those bounds. - let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into())); - - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); +/// 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. +fn check_opaque_type_well_formed<'tcx>( + tcx: TyCtxt<'tcx>, + next_trait_solver: bool, + def_id: LocalDefId, + definition_span: Span, + definition_ty: Ty<'tcx>, +) -> Result<Ty<'tcx>, ErrorGuaranteed> { + // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` + // on stable and we'd break that. + let opaque_ty_hir = tcx.hir().expect_item(def_id); + let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else { + return Ok(definition_ty); + }; + let param_env = tcx.param_env(def_id); + // HACK This bubble is required for this tests to pass: + // nested-return-type2-tait2.rs + // nested-return-type2-tait3.rs + // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error` + // and prepopulate this `InferCtxt` with known opaque values, rather than + // using the `Bind` anchor here. For now it's fine. + let infcx = tcx + .infer_ctxt() + .with_next_trait_solver(next_trait_solver) + .with_opaque_type_inference(if next_trait_solver { + DefiningAnchor::Bind(def_id) + } else { + DefiningAnchor::Bubble + }) + .build(); + let ocx = ObligationCtxt::new(&infcx); + let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // 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, def_id), - param_env, - opaque_ty, - definition_ty, - ) { + // Require that the hidden type actually fulfills all the bounds of the opaque type, even without + // the bounds that the function supplies. + let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_substs); + ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty) + .map_err(|err| { infcx .err_ctxt() .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, def_id), + &ObligationCause::misc(definition_span, def_id), opaque_ty, definition_ty, err, ) - .emit(); - } + .emit() + })?; - ocx.register_obligation(Obligation::misc( - infcx.tcx, - instantiated_ty.span, - def_id, - param_env, - predicate, - )); + // Require the hidden type to be well-formed with only the generics of the opaque type. + // Defining use functions may have more bounds than the opaque type, which is ok, as long as the + // hidden type is well formed even without those bounds. + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + definition_ty.into(), + ))); + ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate)); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = ocx.select_all_or_error(); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = ocx.select_all_or_error(); - // This is still required for many(half of the tests in ui/type-alias-impl-trait) - // tests to pass - let _ = infcx.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); - self.tcx.ty_error(reported) - } + if errors.is_empty() { + Ok(definition_ty) + } else { + Err(infcx.err_ctxt().report_fulfillment_errors(&errors)) } } fn check_opaque_type_parameter_valid( tcx: TyCtxt<'_>, opaque_type_key: OpaqueTypeKey<'_>, - origin: OpaqueTyOrigin, span: Span, ) -> Result<(), ErrorGuaranteed> { - match origin { + let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); + match opaque_ty_hir.expect_opaque_ty().origin { // No need to check return position impl trait (RPIT) // because for type and const parameters they are correct // by construction: we convert diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f527eee7b..c19fbf20c 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -89,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory<'tcx>, ) { self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }))), + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( + ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }, + ))), locations, category, ); 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 c8ec1257d..f22851d76 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -245,7 +245,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx, span) .unwrap_or_else(|guar| TypeOpOutput { - output: self.infcx.tcx.ty_error(guar), + output: Ty::new_error(self.infcx.tcx, guar), constraints: None, error_info: None, }); diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index a06d4bcc6..eec886b7b 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -124,21 +124,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Return types are a bit more complex. They may contain opaque `impl Trait` types. let mir_output_ty = body.local_decls[RETURN_PLACE].ty; let output_span = body.local_decls[RETURN_PLACE].source_info.span; - if let Err(terr) = self.eq_types( - normalized_output_ty, - mir_output_ty, - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - ) { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - normalized_output_ty, - mir_output_ty, - terr - ); - }; + self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span); } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index dc5121e1a..a15e1065c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -7,7 +7,6 @@ use std::{fmt, iter, mem}; use either::Either; -use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; @@ -28,7 +27,8 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::AssertKind; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitableExt; @@ -50,7 +50,6 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::renumber::RegionCtxt; use crate::session_diagnostics::MoveUnsized; use crate::{ borrow_set::BorrowSet, @@ -139,7 +138,7 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars: &[Upvar<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { - let implicit_region_bound = infcx.tcx.mk_re_var(universal_regions.fr_fn_body); + let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), @@ -188,10 +187,7 @@ pub(crate) fn type_check<'mir, 'tcx>( // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering // predefined opaques in the typeck root. - // FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since - // the HIR typeck map defining usages back to their definition params, - // they won't actually match up with the usages in this body... - if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { checker.register_predefined_opaques_in_new_solver(); } @@ -241,10 +237,10 @@ 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(reported); + hidden_type.ty = Ty::new_error(infcx.tcx, reported); } - (opaque_type_key, (hidden_type, decl.origin)) + (opaque_type_key, hidden_type) }) .collect(); @@ -480,9 +476,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_body(&mut self, body: &Body<'tcx>) { self.sanitize_type(&"return type", body.return_ty()); - for local_decl in &body.local_decls { - self.sanitize_type(local_decl, local_decl.ty); - } + // The types of local_decls are checked above which is called in super_body. self.super_body(body); } } @@ -526,7 +520,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { for elem in place.projection.iter() { if place_ty.variant_index.is_none() { if let Err(guar) = place_ty.ty.error_reported() { - return PlaceTy::from_ty(self.tcx().ty_error(guar)); + return PlaceTy::from_ty(Ty::new_error(self.tcx(), guar)); } } place_ty = self.sanitize_projection(place_ty, elem, place, location, context); @@ -662,7 +656,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceTy::from_ty(match base_ty.kind() { ty::Array(inner, _) => { assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(*inner, to - from) + Ty::new_array(tcx, *inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -755,7 +749,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } fn error(&mut self) -> Ty<'tcx> { - self.tcx().ty_error_misc() + Ty::new_misc_error(self.tcx()) } fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance { @@ -883,8 +877,7 @@ struct BorrowCheckContext<'a, 'tcx> { pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, - pub(crate) opaque_type_values: - FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, } /// A collection of region constraints that must be satisfied for the @@ -1042,16 +1035,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .typeck(self.body.source.def_id().expect_local()) .concrete_opaque_types .iter() - .map(|(&def_id, &hidden_ty)| { - let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id); - (ty::OpaqueTypeKey { def_id, substs }, hidden_ty) - }) + .map(|(k, v)| (*k, *v)) .collect(); let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { - self.infcx.next_nll_region_var( + self.infcx.next_nll_region_var_in_universe( NllRegionVariableOrigin::Existential { from_forall: false }, - || RegionCtxt::Unknown, + ty::UniverseIndex::ROOT, ) }); @@ -1061,15 +1051,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::OpaqueType, CustomTypeOp::new( |ocx| { - for (key, hidden_ty) in renumbered_opaques { - ocx.register_infer_ok_obligations( - ocx.infcx.register_hidden_type_in_new_solver( - key, - param_env, - hidden_ty.ty, - )?, + let mut obligations = Vec::new(); + for (opaque_type_key, hidden_ty) in renumbered_opaques { + let cause = ObligationCause::dummy(); + ocx.infcx.insert_hidden_type( + opaque_type_key, + &cause, + param_env, + hidden_ty.ty, + true, + &mut obligations, + )?; + + ocx.infcx.add_item_bounds_for_hidden_type( + opaque_type_key.def_id.to_def_id(), + opaque_type_key.substs, + cause, + param_env, + hidden_ty.ty, + &mut obligations, ); } + + ocx.register_obligations(obligations); Ok(()) }, "register pre-defined opaques", @@ -1366,7 +1370,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // FIXME: check the values } - TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => { + TerminatorKind::Call { func, args, destination, call_source, target, .. } => { self.check_operand(func, term_location); for arg in args { self.check_operand(arg, term_location); @@ -1415,9 +1419,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // // See #91068 for an example. self.prove_predicates( - sig.inputs_and_output - .iter() - .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))), + sig.inputs_and_output.iter().map(|ty| { + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + ty.into(), + ))) + }), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -1440,7 +1446,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call); + self.check_call_inputs(body, term, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1567,7 +1573,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, - from_hir_call: bool, + call_source: CallSource, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { @@ -1585,7 +1591,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = op_arg.ty(body, self.tcx()); let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if from_hir_call { + let category = if call_source.from_hir_call() { ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) } else { ConstraintCategory::Boring @@ -1846,7 +1852,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let array_ty = rvalue.ty(body.local_decls(), tcx); self.prove_predicate( - ty::PredicateKind::WellFormed(array_ty.into()), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), Locations::Single(location), ConstraintCategory::Boring, ); @@ -1902,7 +1908,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_operand(op, location); match cast_kind { - CastKind::Pointer(PointerCast::ReifyFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like @@ -1912,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // and hence may contain unnormalized results. let fn_sig = self.normalize(fn_sig, location); - let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); + let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig); if let Err(terr) = self.eq_types( *ty, @@ -1931,12 +1937,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { + CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => { let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), }; - let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); + let ty_fn_ptr_from = + Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety)); if let Err(terr) = self.eq_types( *ty, @@ -1955,7 +1962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::UnsafeFnPointer) => { + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer) => { let fn_sig = op.ty(body, tcx).fn_sig(tcx); // The type that we see in the fcx is like @@ -1984,7 +1991,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::Unsize) => { + CastKind::PointerCoercion(PointerCoercion::Unsize) => { let &ty = ty; let trait_ref = ty::TraitRef::from_lang_item( tcx, @@ -2019,10 +2026,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Cast, ); - let outlives_predicate = - tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause( - ty::Clause::TypeOutlives(ty::OutlivesPredicate(self_ty, *region)), - ))); + let outlives_predicate = tcx.mk_predicate(Binder::dummy( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + )), + )); self.prove_predicate( outlives_predicate, location.to_locations(), @@ -2030,7 +2038,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - CastKind::Pointer(PointerCast::MutToConstPointer) => { + CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mut, @@ -2072,7 +2080,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::Pointer(PointerCast::ArrayToPointer) => { + CastKind::PointerCoercion(PointerCoercion::ArrayToPointer) => { let ty_from = op.ty(body, tcx); let opt_ty_elem_mut = match ty_from.kind() { @@ -2495,7 +2503,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { location, borrow_region, borrowed_place ); - let mut cursor = borrowed_place.projection.as_ref(); let tcx = self.infcx.tcx; let field = path_utils::is_upvar_field_projection( tcx, @@ -2509,14 +2516,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring }; - while let [proj_base @ .., elem] = cursor { - cursor = proj_base; - + for (base, elem) in borrowed_place.as_ref().iter_projections().rev() { debug!("add_reborrow_constraint - iteration {:?}", elem); match elem { ProjectionElem::Deref => { - let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty; + let base_ty = base.ty(body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind() { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 56f078f2d..7821b82bf 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -500,7 +500,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { .next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic"))) .as_var(); - let region = self.infcx.tcx.mk_re_var(reg_vid); + let region = ty::Region::new_var(self.infcx.tcx, reg_vid); let va_list_ty = self.infcx.tcx.type_of(va_list_did).subst(self.infcx.tcx, &[region.into()]); @@ -660,7 +660,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv, }; - let env_region = tcx.mk_re_late_bound(ty::INNERMOST, br); + let env_region = ty::Region::new_late_bound(tcx, ty::INNERMOST, br); let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); // The "inputs" of the closure in the @@ -685,7 +685,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { assert_eq!(self.mir_def.to_def_id(), def_id); let resume_ty = substs.as_generator().resume_ty(); let output = substs.as_generator().return_ty(); - let generator_ty = tcx.mk_generator(def_id, substs, movability); + let generator_ty = Ty::new_generator(tcx, def_id, substs, movability); let inputs_and_output = self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]); ty::Binder::dummy(inputs_and_output) @@ -778,7 +778,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { { let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| { debug!(?br); - let liberated_region = self.tcx.mk_re_free(all_outlive_scope.to_def_id(), br.kind); + let liberated_region = + ty::Region::new_free(self.tcx, all_outlive_scope.to_def_id(), br.kind); let region_vid = { let name = match br.kind.get_name() { Some(name) => name, @@ -889,7 +890,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - tcx.fold_regions(value, |region, _| tcx.mk_re_var(self.to_region_vid(region))) + tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region))) } } @@ -929,7 +930,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_re_free(mir_def_id.to_def_id(), bound_region); + let liberated_region = ty::Region::new_free(tcx, mir_def_id.to_def_id(), bound_region); f(liberated_region); } } |