diff options
Diffstat (limited to 'compiler/rustc_borrowck')
26 files changed, 643 insertions, 809 deletions
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index fbf628e86..87c113f3e 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [lib] -doctest = false [dependencies] either = "1.5.0" diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 144fd15fc..f185e402f 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -14,8 +14,8 @@ use crate::{ places_conflict, region_infer::values::LivenessValues, }; -pub(super) fn generate_constraints<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +pub(super) fn generate_constraints<'tcx>( + infcx: &InferCtxt<'tcx>, liveness_constraints: &mut LivenessValues<RegionVid>, all_facts: &mut Option<AllFacts>, location_table: &LocationTable, @@ -37,8 +37,8 @@ pub(super) fn generate_constraints<'cx, 'tcx>( } /// 'cg = the duration of the constraint generation process itself. -struct ConstraintGeneration<'cg, 'cx, 'tcx> { - infcx: &'cg InferCtxt<'cx, 'tcx>, +struct ConstraintGeneration<'cg, 'tcx> { + infcx: &'cg InferCtxt<'tcx>, all_facts: &'cg mut Option<AllFacts>, location_table: &'cg LocationTable, liveness_constraints: &'cg mut LivenessValues<RegionVid>, @@ -46,7 +46,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> { body: &'cg Body<'tcx>, } -impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, '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); } @@ -156,7 +156,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { } } -impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { +impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { /// Some variable with type `live_ty` is "regular live" at /// `location` -- i.e., it may be used later. This means that all /// regions appearing in the type `live_ty` must be live at diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index efc17a173..b162095f8 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -31,9 +31,8 @@ pub fn get_body_with_borrowck_facts<'tcx>( def: ty::WithOptConstParam<LocalDefId>, ) -> BodyWithBorrowckFacts<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() - }) + let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build(); + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index b1def1892..02071ed6b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -56,7 +56,7 @@ impl<'tcx> UniverseInfo<'tcx> { ) { match self.0 { UniverseInfoInner::RelateTys { expected, found } => { - let err = mbcx.infcx.report_mismatched_types( + let err = mbcx.infcx.err_ctxt().report_mismatched_types( &cause, expected, found, @@ -238,20 +238,11 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> { placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -288,37 +279,24 @@ where placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - cause, - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = + rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -349,21 +327,11 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { - mbcx.infcx.tcx.infer_ctxt().enter_with_canonical( - cause.span, - &self.canonical_query, - |ref infcx, key, _| { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) - .ok()?; - try_extract_error_from_fulfill_cx( - fulfill_cx, - infcx, - placeholder_region, - error_region, - ) - }, - ) + let (ref infcx, key, _) = + mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query); + let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?; + try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) } } @@ -407,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> { #[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { @@ -427,7 +395,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( } fn try_extract_error_from_region_constraints<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option<ty::Region<'tcx>>, region_constraints: &RegionConstraintData<'tcx>, @@ -449,42 +417,38 @@ fn try_extract_error_from_region_constraints<'tcx>( })?; debug!(?sub_region, "cause = {:#?}", cause); - let nice_error = match (error_region, *sub_region) { - (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::SubSupConflict( - vid, - region_var_origin(vid), - cause.clone(), - error_region, - cause.clone(), - placeholder_region, - vec![], - ), - ), - (Some(error_region), _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region), + let error = match (error_region, *sub_region) { + (Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict( + vid, + region_var_origin(vid), + cause.clone(), + error_region, + cause.clone(), + placeholder_region, + vec![], ), + (Some(error_region), _) => { + RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region) + } // Note universe here is wrong... - (None, ty::ReVar(vid)) => NiceRegionError::new( - infcx, - RegionResolutionError::UpperBoundUniverseConflict( - vid, - region_var_origin(vid), - universe_of_region(vid), - cause.clone(), - placeholder_region, - ), - ), - (None, _) => NiceRegionError::new( - infcx, - RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region), + (None, ty::ReVar(vid)) => RegionResolutionError::UpperBoundUniverseConflict( + vid, + region_var_origin(vid), + universe_of_region(vid), + cause.clone(), + placeholder_region, ), + (None, _) => { + RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region) + } }; - nice_error.try_report_from_nll().or_else(|| { + NiceRegionError::new(&infcx.err_ctxt(), error).try_report_from_nll().or_else(|| { if let SubregionOrigin::Subtype(trace) = cause { - Some(infcx.report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch)) + Some( + infcx + .err_ctxt() + .report_and_explain_type_error(*trace, TypeError::RegionsPlaceholderMismatch), + ) } else { None } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f2204c242..583bc2e28 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::{ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty}; +use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -198,7 +198,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span, move_spans, *moved_place, - Some(used_place), partially_str, loop_message, move_msg, @@ -369,6 +368,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] }; visitor.visit_body(&body); + let mut show_assign_sugg = false; let isnt_initialized = if let InitializationRequiringAction::PartialAssignment | InitializationRequiringAction::Assignment = desired_action { @@ -396,6 +396,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .count() == 0 { + show_assign_sugg = true; "isn't initialized" } else { "is possibly-uninitialized" @@ -446,10 +447,84 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } + err.span_label(decl_span, "binding declared here but left uninitialized"); + if show_assign_sugg { + struct LetVisitor { + decl_span: Span, + sugg_span: Option<Span>, + } + + impl<'v> Visitor<'v> for LetVisitor { + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + if self.sugg_span.is_some() { + return; + } + if let hir::StmtKind::Local(hir::Local { + span, ty, init: None, .. + }) = &ex.kind && span.contains(self.decl_span) { + self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); + } + hir::intravisit::walk_stmt(self, ex); + } + } + + let mut visitor = LetVisitor { decl_span, sugg_span: None }; + visitor.visit_body(&body); + if let Some(span) = visitor.sugg_span { + self.suggest_assign_value(&mut err, moved_place, span); + } + } err } + fn suggest_assign_value( + &self, + err: &mut Diagnostic, + moved_place: PlaceRef<'tcx>, + sugg_span: Span, + ) { + let ty = moved_place.ty(self.body, self.infcx.tcx).ty; + debug!("ty: {:?}, kind: {:?}", ty, ty.kind()); + + let tcx = self.infcx.tcx; + let implements_default = |ty, param_env| { + let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { + return false; + }; + // Regions are already solved, so we must use a fresh InferCtxt, + // but the type has region variables, so erase those. + tcx.infer_ctxt() + .build() + .type_implements_trait( + default_trait, + tcx.erase_regions(ty), + ty::List::empty(), + param_env, + ) + .must_apply_modulo_regions() + }; + + let assign_value = match ty.kind() { + ty::Bool => "false", + ty::Float(_) => "0.0", + ty::Int(_) | ty::Uint(_) => "0", + ty::Never | ty::Error(_) => "", + ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]", + ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()", + _ => "todo!()", + }; + + if !assign_value.is_empty() { + err.span_suggestion_verbose( + sugg_span.shrink_to_hi(), + format!("consider assigning a value"), + format!(" = {}", assign_value), + Applicability::MaybeIncorrect, + ); + } + } + fn suggest_borrow_fn_like( &self, err: &mut Diagnostic, @@ -537,41 +612,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .and_then(|def_id| tcx.hir().get_generics(def_id)) else { return; }; // Try to find predicates on *generic params* that would allow copying `ty` - let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| { - let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx); + let infcx = tcx.infer_ctxt().build(); + let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx); - let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); - let cause = ObligationCause::new( - span, - self.mir_hir_id(), - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); - fulfill_cx.register_bound( - &infcx, - self.param_env, - // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), - copy_did, - cause, - ); - // Select all, including ambiguous predicates - let errors = fulfill_cx.select_all_or_error(&infcx); - - // Only emit suggestion if all required predicates are on generic - errors - .into_iter() - .map(|err| match err.obligation.predicate.kind().skip_binder() { - PredicateKind::Trait(predicate) => match predicate.self_ty().kind() { - ty::Param(param_ty) => Ok(( - generics.type_param(param_ty, tcx), - predicate.trait_ref.print_only_trait_path().to_string(), - )), - _ => Err(()), - }, + let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); + let cause = ObligationCause::new( + span, + self.mir_hir_id(), + rustc_infer::traits::ObligationCauseCode::MiscObligation, + ); + fulfill_cx.register_bound( + &infcx, + self.param_env, + // Erase any region vids from the type, which may not be resolved + infcx.tcx.erase_regions(ty), + copy_did, + cause, + ); + // Select all, including ambiguous predicates + let errors = fulfill_cx.select_all_or_error(&infcx); + + // Only emit suggestion if all required predicates are on generic + let predicates: Result<Vec<_>, _> = errors + .into_iter() + .map(|err| match err.obligation.predicate.kind().skip_binder() { + PredicateKind::Trait(predicate) => match predicate.self_ty().kind() { + ty::Param(param_ty) => Ok(( + generics.type_param(param_ty, tcx), + predicate.trait_ref.print_only_trait_path().to_string(), + )), _ => Err(()), - }) - .collect() - }); + }, + _ => Err(()), + }) + .collect(); if let Ok(predicates) = predicates { suggest_constraining_type_params( @@ -2146,7 +2220,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } StorageDeadOrDrop::Destructor(_) => kind, }, - ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { + ProjectionElem::OpaqueCast { .. } + | ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) => { match place_ty.ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1c01e78ab..582d683dd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,8 +1,5 @@ //! Print diagnostics to explain why values are borrowed. -use std::collections::VecDeque; - -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic}; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; @@ -359,19 +356,37 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_region_vid = borrow.region; debug!(?borrow_region_vid); - let region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); + let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location); debug!(?region_sub); - match find_use::find(body, regioncx, tcx, region_sub, location) { + let mut use_location = location; + let mut use_in_later_iteration_of_loop = false; + + if region_sub == borrow_region_vid { + // When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is + // issued is the same location that invalidates the reference), this is likely a loop iteration + // - in this case, try using the loop terminator location in `find_sub_region_live_at`. + if let Some(loop_terminator_location) = + regioncx.find_loop_terminator_location(borrow.region, body) + { + region_sub = self + .regioncx + .find_sub_region_live_at(borrow_region_vid, loop_terminator_location); + debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub); + use_location = loop_terminator_location; + use_in_later_iteration_of_loop = true; + } + } + + match find_use::find(body, regioncx, tcx, region_sub, use_location) { Some(Cause::LiveVar(local, location)) => { let span = body.source_info(location).span; let spans = self .move_spans(Place::from(local).as_ref(), location) .or_else(|| self.borrow_spans(span, location)); - let borrow_location = location; - if self.is_use_in_later_iteration_of_loop(borrow_location, location) { - let later_use = self.later_use_kind(borrow, spans, location); + if use_in_later_iteration_of_loop { + let later_use = self.later_use_kind(borrow, spans, use_location); BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) } else { // Check if the location represents a `FakeRead`, and adapt the error @@ -425,131 +440,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - /// true if `borrow_location` can reach `use_location` by going through a loop and - /// `use_location` is also inside of that loop - fn is_use_in_later_iteration_of_loop( - &self, - borrow_location: Location, - use_location: Location, - ) -> bool { - let back_edge = self.reach_through_backedge(borrow_location, use_location); - back_edge.map_or(false, |back_edge| self.can_reach_head_of_loop(use_location, back_edge)) - } - - /// Returns the outmost back edge if `from` location can reach `to` location passing through - /// that back edge - fn reach_through_backedge(&self, from: Location, to: Location) -> Option<Location> { - let mut visited_locations = FxHashSet::default(); - let mut pending_locations = VecDeque::new(); - visited_locations.insert(from); - pending_locations.push_back(from); - debug!("reach_through_backedge: from={:?} to={:?}", from, to,); - - let mut outmost_back_edge = None; - while let Some(location) = pending_locations.pop_front() { - debug!( - "reach_through_backedge: location={:?} outmost_back_edge={:?} - pending_locations={:?} visited_locations={:?}", - location, outmost_back_edge, pending_locations, visited_locations - ); - - if location == to && outmost_back_edge.is_some() { - // We've managed to reach the use location - debug!("reach_through_backedge: found!"); - return outmost_back_edge; - } - - let block = &self.body.basic_blocks[location.block]; - - if location.statement_index < block.statements.len() { - let successor = location.successor_within_block(); - if visited_locations.insert(successor) { - pending_locations.push_back(successor); - } - } else { - pending_locations.extend( - block - .terminator() - .successors() - .map(|bb| Location { statement_index: 0, block: bb }) - .filter(|s| visited_locations.insert(*s)) - .map(|s| { - if self.is_back_edge(location, s) { - match outmost_back_edge { - None => { - outmost_back_edge = Some(location); - } - - Some(back_edge) - if location.dominates(back_edge, &self.dominators) => - { - outmost_back_edge = Some(location); - } - - Some(_) => {} - } - } - - s - }), - ); - } - } - - None - } - - /// true if `from` location can reach `loop_head` location and `loop_head` dominates all the - /// intermediate nodes - fn can_reach_head_of_loop(&self, from: Location, loop_head: Location) -> bool { - self.find_loop_head_dfs(from, loop_head, &mut FxHashSet::default()) - } - - fn find_loop_head_dfs( - &self, - from: Location, - loop_head: Location, - visited_locations: &mut FxHashSet<Location>, - ) -> bool { - visited_locations.insert(from); - - if from == loop_head { - return true; - } - - if loop_head.dominates(from, &self.dominators) { - let block = &self.body.basic_blocks[from.block]; - - if from.statement_index < block.statements.len() { - let successor = from.successor_within_block(); - - if !visited_locations.contains(&successor) - && self.find_loop_head_dfs(successor, loop_head, visited_locations) - { - return true; - } - } else { - for bb in block.terminator().successors() { - let successor = Location { statement_index: 0, block: bb }; - - if !visited_locations.contains(&successor) - && self.find_loop_head_dfs(successor, loop_head, visited_locations) - { - return true; - } - } - } - } - - false - } - - /// True if an edge `source -> target` is a backedge -- in other words, if the target - /// dominates the source. - fn is_back_edge(&self, source: Location, target: Location) -> bool { - target.dominates(source, &self.dominators) - } - /// Determine how the borrow was later used. /// First span returned points to the location of the conflicting use /// Second span if `Some` is returned in the case of closures and points diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 683084cf0..534d9ecae 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -237,6 +237,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), + ProjectionElem::OpaqueCast(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -317,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), + ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; @@ -970,7 +972,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span: Span, move_spans: UseSpans<'tcx>, moved_place: Place<'tcx>, - used_place: Option<PlaceRef<'tcx>>, partially_str: &str, loop_message: &str, move_msg: &str, @@ -1024,7 +1025,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, self.infcx.tcx).ty; let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { - Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| { + Some(def_id) => { + let infcx = self.infcx.tcx.infer_ctxt().build(); type_known_to_meet_bound_modulo_regions( &infcx, self.param_env, @@ -1035,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id, DUMMY_SP, ) - }), + } _ => false, }; if suggest { @@ -1058,9 +1060,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_name, partially_str, loop_message ), ); - // If we have a `&mut` ref, we need to reborrow. - if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place - .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind()) + // If the moved place was a `&mut` ref, then we can + // suggest to reborrow it where it was moved, so it + // will still be valid by the time we get to the usage. + if let ty::Ref(_, _, hir::Mutability::Mut) = + moved_place.ty(self.body, self.infcx.tcx).ty.kind() { // If we are in a loop this will be suggested later. if !is_loop_move { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 8d4c38d3a..5a47f4567 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(use_spans) = use_spans { self.explain_captures( - &mut err, span, span, use_spans, move_place, None, "", "", "", false, true, + &mut err, span, span, use_spans, move_place, "", "", "", false, true, ); } err diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 6b5014fa9..8ad40c0aa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .., ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), ], @@ -931,7 +932,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let opt_suggestions = self .infcx .tcx - .typeck(path_segment.hir_id.owner) + .typeck(path_segment.hir_id.owner.def_id) .type_dependent_def_id(*hir_id) .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) .map(|def_id| self.infcx.tcx.associated_items(def_id)) @@ -1031,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if look_at_return && hir.get_return_block(closure_id).is_some() { // ...otherwise we are probably in the tail expression of the function, point at the // return type. - match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) { + match hir.get_by_def_id(hir.get_parent_item(fn_call_id).def_id) { hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) | hir::Node::TraitItem(hir::TraitItem { ident, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 34be2874f..15230718d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(lower_bound_region) = lower_bound_region { let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx); let origin = RelateParamBound(type_test_span, generic_ty, None); - self.buffer_error(self.infcx.construct_generic_bound_failure( + self.buffer_error(self.infcx.err_ctxt().construct_generic_bound_failure( self.body.source.def_id().expect_local(), type_test_span, Some(origin), @@ -281,7 +281,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; match tcx.hir().get_if_local(def_id) { Some(Node::ImplItem(impl_item)) => { - match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) { + match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id) + { Some(Node::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. @@ -291,7 +292,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } Some(Node::TraitItem(trait_item)) => { let trait_did = tcx.hir().get_parent_item(trait_item.hir_id()); - match tcx.hir().find_by_def_id(trait_did) { + match tcx.hir().find_by_def_id(trait_did.def_id) { Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { // The method being called is defined in the `trait`, but the `'static` // obligation comes from the `impl`. Find that `impl` so that we can point @@ -340,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// - /// ```compile_fail,E0312 + /// ```compile_fail /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// @@ -364,7 +365,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); + let infer_err = self.infcx.err_ctxt(); + let nice = NiceRegionError::new_from_span(&infer_err, cause.span, o, f); if let Some(diag) = nice.try_report_from_nll() { self.buffer_error(diag); return; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 6c1eaa809..c044dbaba 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -251,7 +251,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)); + .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)); if let Some(ref value) = value { self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); @@ -707,7 +708,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { hir::AsyncGeneratorKind::Block => " of async block", hir::AsyncGeneratorKind::Closure => " of async closure", hir::AsyncGeneratorKind::Fn => { - let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id)); + let parent_item = + hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id); let output = &parent_item .fn_decl() .expect("generator lowered from async fn should be in fn") @@ -863,20 +865,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }; let tcx = self.infcx.tcx; - let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?; - if tcx.parent(region.def_id) != body_parent_did - || tcx.def_kind(body_parent_did) != DefKind::Impl - { + let region_parent = tcx.parent(region.def_id); + if tcx.def_kind(region_parent) != DefKind::Impl { return None; } - let mut found = false; - tcx.fold_regions(tcx.type_of(body_parent_did), |r: ty::Region<'tcx>, _| { - if *r == ty::ReEarlyBound(region) { - found = true; - } - r - }); + let found = tcx + .any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region)); Some(RegionName { name: self.synthesize_region_name(), @@ -889,4 +884,92 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ), }) } + + fn give_name_if_anonymous_region_appears_in_arg_position_impl_trait( + &self, + fr: RegionVid, + ) -> Option<RegionName> { + let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else { + return None; + }; + if region.has_name() { + return None; + }; + + let predicates = self + .infcx + .tcx + .predicates_of(self.body.source.def_id()) + .instantiate_identity(self.infcx.tcx) + .predicates; + + if let Some(upvar_index) = self + .regioncx + .universal_regions() + .defining_ty + .upvar_tys() + .position(|ty| self.any_param_predicate_mentions(&predicates, ty, region)) + { + let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( + self.infcx.tcx, + &self.upvars, + upvar_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name), + }) + } else if let Some(arg_index) = self + .regioncx + .universal_regions() + .unnormalized_input_tys + .iter() + .position(|ty| self.any_param_predicate_mentions(&predicates, *ty, region)) + { + let (arg_name, arg_span) = self.regioncx.get_argument_name_and_span_for_region( + self.body, + &self.local_names, + arg_index, + ); + let region_name = self.synthesize_region_name(); + + Some(RegionName { + name: region_name, + source: RegionNameSource::AnonRegionFromArgument( + RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()), + ), + }) + } else { + None + } + } + + fn any_param_predicate_mentions( + &self, + predicates: &[ty::Predicate<'tcx>], + ty: Ty<'tcx>, + region: ty::EarlyBoundRegion, + ) -> bool { + let tcx = self.infcx.tcx; + ty.walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Param(_) = ty.kind() + { + predicates.iter().any(|pred| { + match pred.kind().skip_binder() { + ty::PredicateKind::Trait(data) if data.self_ty() == ty => {} + ty::PredicateKind::Projection(data) if data.projection_ty.self_ty() == ty => {} + _ => return false, + } + tcx.any_free_region_meets(pred, |r| { + *r == ty::ReEarlyBound(region) + }) + }) + } else { + false + } + }) + } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 86da87d06..abfe253d4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,7 +3,6 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] @@ -132,14 +131,11 @@ fn mir_borrowck<'tcx>( debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner; - let opt_closure_req = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner)) - .enter(|infcx| { - let input_body: &Body<'_> = &input_body.borrow(); - let promoted: &IndexVec<_, _> = &promoted.borrow(); - do_mir_borrowck(&infcx, input_body, promoted, false).0 - }); + let infcx = + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); + let input_body: &Body<'_> = &input_body.borrow(); + let promoted: &IndexVec<_, _> = &promoted.borrow(); + let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0; debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -151,8 +147,8 @@ fn mir_borrowck<'tcx>( /// region ids on which the borrow checking was performed together with Polonius /// facts. #[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")] -fn do_mir_borrowck<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +fn do_mir_borrowck<'tcx>( + infcx: &InferCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexVec<Promoted, Body<'tcx>>, return_body_with_facts: bool, @@ -475,7 +471,7 @@ pub struct BodyWithBorrowckFacts<'tcx> { } struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, @@ -1781,6 +1777,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | + ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => @@ -2172,6 +2169,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 12b2481cc..08fdd28eb 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -55,8 +55,8 @@ pub(crate) struct NllOutput<'tcx> { /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] -pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, +pub(crate) fn replace_regions_in_mir<'tcx>( + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec<Promoted, Body<'tcx>>, @@ -155,7 +155,7 @@ fn populate_polonius_move_facts( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &InferCtxt<'cx, 'tcx>, + infcx: &InferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexVec<Promoted, Body<'tcx>>, @@ -318,8 +318,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } } -pub(super) fn dump_mir_results<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub(super) fn dump_mir_results<'tcx>( + infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, @@ -368,8 +368,8 @@ pub(super) fn dump_mir_results<'a, 'tcx>( }; } -pub(super) fn dump_annotation<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, +pub(super) fn dump_annotation<'tcx>( + infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 6e5a96bee..0e71efd6f 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -250,6 +250,7 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) + | (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -317,6 +318,17 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF"); Overlap::EqualOrDisjoint } + (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => { + if v1 == v2 { + // same type - recur. + debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE"); + Overlap::EqualOrDisjoint + } else { + // Different types. Disjoint! + debug!("place_element_conflict: DISJOINT-OPAQUE"); + Overlap::Disjoint + } + } (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => { if f1 == f2 { // same field (e.g., `a.y` vs. `a.y`) - recur. @@ -520,6 +532,7 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), _, diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index bdf2becb7..2b50cbac9 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } + | ProjectionElem::OpaqueCast { .. } | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => { cursor = cursor_base; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 244e6e342..8b63294fb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, - ConstraintCategory, Local, Location, ReturnConstraint, + ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind, }; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCauseCode; @@ -565,7 +565,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] pub(super) fn solve( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, polonius_output: Option<Rc<PoloniusOutput>>, @@ -835,7 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 'a`. See `TypeTest` for more details. fn check_type_tests( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, @@ -923,7 +923,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))] fn try_promote_type_test( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, type_test: &TypeTest<'tcx>, @@ -1036,7 +1036,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx))] fn try_promote_type_test_subject( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option<ClosureOutlivesSubject<'tcx>> { let tcx = infcx.tcx; @@ -1212,7 +1212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// `point`. fn eval_verify_bound( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, generic_ty: Ty<'tcx>, @@ -1262,7 +1262,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn eval_if_eq( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, generic_ty: Ty<'tcx>, lower_bound: RegionVid, @@ -1398,7 +1398,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// whether any of the constraints were too strong. In particular, /// we want to check for a case where a universally quantified /// region exceeded its bounds. Consider: - /// ```compile_fail,E0312 + /// ```compile_fail /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// In this case, returning `x` requires `&'a u32 <: &'b u32` @@ -1451,7 +1451,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// <https://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/> /// /// In the canonical example - /// ```compile_fail,E0312 + /// ```compile_fail /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a @@ -1718,7 +1718,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_member_constraints( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, errors_buffer: &mut RegionErrors<'tcx>, ) { let member_constraints = self.member_constraints.clone(); @@ -2236,6 +2236,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { self.universe_causes[&universe].clone() } + + /// Tries to find the terminator of the loop in which the region 'r' resides. + /// Returns the location of the terminator if found. + pub(crate) fn find_loop_terminator_location( + &self, + r: RegionVid, + body: &Body<'_>, + ) -> Option<Location> { + let scc = self.constraint_sccs.scc(r.to_region_vid()); + let locations = self.scc_values.locations_outlived_by(scc); + for location in locations { + let bb = &body[location.block]; + if let Some(terminator) = &bb.terminator { + // terminator of a loop should be TerminatorKind::FalseUnwind + if let TerminatorKind::FalseUnwind { .. } = terminator.kind { + return Some(location); + } + } + } + None + } } impl<'tcx> RegionDefinition<'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 9d088642f..465f353aa 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -2,22 +2,18 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine}; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; -use crate::session_diagnostics::ConstNotUsedTraitAlias; - use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -63,7 +59,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> { let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new(); @@ -194,7 +190,7 @@ pub trait InferCtxtExt<'tcx> { ) -> Ty<'tcx>; } -impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type @@ -229,31 +225,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return self.tcx.ty_error(); } - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - - // Use substs to build up a reverse map from regions to their - // identity mappings. This is necessary because of `impl - // Trait` lifetimes are computed by replacing existing - // lifetimes with 'static and remapping only those used in the - // `impl Trait` return type, resulting in the parameters - // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); - debug!(?id_substs); - let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); - debug!("map = {:#?}", map); - - // Convert the type from the function into a type valid outside - // the function, by replacing invalid regions with 'static, - // after producing an error for each of them. - let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new( - self.tcx, - opaque_type_key, - map, - instantiated_ty.ty, - instantiated_ty.span, - )); - debug!(?definition_ty); + let definition_ty = instantiated_ty + .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin) + .ty; if !check_opaque_type_parameter_valid( self.tcx, @@ -266,72 +240,70 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - if let OpaqueTyOrigin::TyAlias = origin { - // 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 - self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter( - move |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())) - .to_predicate(infcx.tcx); - let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + 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); + 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 + let infcx = + self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); + // 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())) + .to_predicate(infcx.tcx); + let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - // Require that the hidden type actually fulfills all the bounds of the opaque type, even without - // the bounds that the function supplies. - match infcx.register_hidden_type( - OpaqueTypeKey { def_id, substs: id_substs }, - ObligationCause::misc(instantiated_ty.span, body_id), - param_env, + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_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); + match infcx + .at(&ObligationCause::misc(instantiated_ty.span, body_id), param_env) + .eq(opaque_ty, definition_ty) + { + Ok(infer_ok) => { + for obligation in infer_ok.obligations { + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + } + Err(err) => { + infcx + .err_ctxt() + .report_mismatched_types( + &ObligationCause::misc(instantiated_ty.span, body_id), + opaque_ty, definition_ty, - origin, - ) { - Ok(infer_ok) => { - for obligation in infer_ok.obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - } - Err(err) => { - infcx - .report_mismatched_types( - &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id.to_def_id(), id_substs), - definition_ty, - err, - ) - .emit(); - } - } + err, + ) + .emit(); + } + } - fulfillment_cx.register_predicate_obligation( - &infcx, - Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), - ); + fulfillment_cx.register_predicate_obligation( + &infcx, + Obligation::misc(instantiated_ty.span, body_id, param_env, predicate), + ); - // Check that all obligations are satisfied by the implementation's - // version. - let errors = fulfillment_cx.select_all_or_error(&infcx); + // Check that all obligations are satisfied by the implementation's + // version. + let errors = fulfillment_cx.select_all_or_error(&infcx); - // This is still required for many(half of the tests in ui/type-alias-impl-trait) - // tests to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + // This is still required for many(half of the tests in ui/type-alias-impl-trait) + // tests to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - if errors.is_empty() { - definition_ty - } else { - infcx.report_fulfillment_errors(&errors, None, false); - self.tcx.ty_error() - } - }, - ) - } else { + if errors.is_empty() { definition_ty + } else { + infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); + self.tcx.ty_error() } } } @@ -427,221 +399,3 @@ fn check_opaque_type_parameter_valid( } true } - -struct ReverseMapper<'tcx> { - tcx: TyCtxt<'tcx>, - - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - do_not_error: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option<Ty<'tcx>>, - - /// Span of function being checked. - span: Span, -} - -impl<'tcx> ReverseMapper<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - hidden_ty: Ty<'tcx>, - span: Span, - ) -> Self { - Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span } - } - - fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.do_not_error); - self.do_not_error = true; - let kind = kind.fold_with(self); - self.do_not_error = false; - kind - } - - fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.do_not_error); - kind.fold_with(self) - } -} - -impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - #[instrument(skip(self), level = "debug")] - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - // Ignore bound regions and `'static` regions that appear in the - // type, we only need to remap regions that reference lifetimes - // from the function declaration. - // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | ty::ReStatic => return r, - - // If regions have been erased (by writeback), don't try to unerase - // them. - ty::ReErased => return r, - - // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) => {} - - ty::RePlaceholder(_) | ty::ReVar(_) => { - // All of the regions in the type should either have been - // erased by writeback, or mapped back to named regions by - // borrow checking. - bug!("unexpected region kind in opaque type: {:?}", r); - } - } - - let generics = self.tcx().generics_of(self.key.def_id); - match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(GenericArgKind::Lifetime(r1)) => r1, - Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.do_not_error => self.tcx.lifetimes.re_static, - None if generics.parent.is_some() => { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - self.tcx.def_span(self.key.def_id), - hidden_ty, - r, - self.key, - ) - .emit(); - } - self.tcx.lifetimes.re_static - } - None => { - self.tcx - .sess - .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( - self.span, - format!( - "lifetime `{}` is part of concrete type but not used in \ - parameter list of the `impl Trait` type alias", - r - ), - ) - .emit(); - - self.tcx().lifetimes.re_static - } - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_closure(def_id, substs) - } - - ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_generator(def_id, substs, movability) - } - - ty::Param(param) => { - // Look it up in the substitution list. - match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the - // opaque type. - Some(GenericArgKind::Type(t1)) => t1, - Some(u) => panic!("type mapped to unexpected kind: {:?}", u), - None => { - debug!(?param, ?self.map); - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "type parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ty - ), - ) - .emit(); - - self.tcx().ty_error() - } - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - trace!("checking const {:?}", ct); - // Find a const parameter - match ct.kind() { - ty::ConstKind::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the - // opaque type. - Some(GenericArgKind::Const(c1)) => c1, - Some(u) => panic!("const mapped to unexpected kind: {:?}", u), - None => { - self.tcx.sess.emit_err(ConstNotUsedTraitAlias { - ct: ct.to_string(), - span: self.span, - }); - - self.tcx().const_error(ct.ty()) - } - } - } - - _ => ct, - } - } -} diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 63b2088f7..f30237690 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,8 +1,8 @@ use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::mir::visit::{MutVisitor, TyContext}; +use rustc_middle::mir::Constant; use rustc_middle::mir::{Body, Location, Promoted}; -use rustc_middle::mir::{Constant, ConstantKind}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec<Promoted, Body<'tcx>>, ) { @@ -28,7 +28,7 @@ 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 +pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { @@ -38,23 +38,8 @@ where }) } -// FIXME(valtrees): This function is necessary because `fold_regions` -// panics for mir constants in the visitor. -// -// Once `visit_mir_constant` is removed we can also remove this function -// and just use `renumber_regions`. -fn renumber_regions_in_mir_constant<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - value: ConstantKind<'tcx>, -) -> ConstantKind<'tcx> { - infcx.tcx.super_fold_regions(value, |_region, _depth| { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; - infcx.next_nll_region_var(origin) - }) -} - struct NllVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, } impl<'a, 'tcx> NllVisitor<'a, 'tcx> { @@ -64,13 +49,6 @@ impl<'a, 'tcx> NllVisitor<'a, 'tcx> { { renumber_regions(self.infcx, value) } - - fn renumber_regions_in_mir_constant( - &mut self, - value: ConstantKind<'tcx>, - ) -> ConstantKind<'tcx> { - renumber_regions_in_mir_constant(self.infcx, value) - } } impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { @@ -103,7 +81,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_in_mir_constant(literal); + constant.literal = self.renumber_regions(literal); debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 5d750c6ca..cff3089c3 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,12 +1,12 @@ use rustc_errors::{IntoDiagnosticArg, MultiSpan}; -use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; use crate::diagnostics::RegionName; -#[derive(SessionDiagnostic)] -#[diag(borrowck::move_unsized, code = "E0161")] +#[derive(Diagnostic)] +#[diag(borrowck_move_unsized, code = "E0161")] pub(crate) struct MoveUnsized<'tcx> { pub ty: Ty<'tcx>, #[primary_span] @@ -14,8 +14,8 @@ pub(crate) struct MoveUnsized<'tcx> { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(borrowck::higher_ranked_lifetime_error)] +#[derive(Diagnostic)] +#[diag(borrowck_higher_ranked_lifetime_error)] pub(crate) struct HigherRankedLifetimeError { #[subdiagnostic] pub cause: Option<HigherRankedErrorCause>, @@ -23,23 +23,23 @@ pub(crate) struct HigherRankedLifetimeError { pub span: Span, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub(crate) enum HigherRankedErrorCause { - #[note(borrowck::could_not_prove)] + #[note(borrowck_could_not_prove)] CouldNotProve { predicate: String }, - #[note(borrowck::could_not_normalize)] + #[note(borrowck_could_not_normalize)] CouldNotNormalize { value: String }, } -#[derive(SessionDiagnostic)] -#[diag(borrowck::higher_ranked_subtype_error)] +#[derive(Diagnostic)] +#[diag(borrowck_higher_ranked_subtype_error)] pub(crate) struct HigherRankedSubtypeError { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(borrowck::generic_does_not_live_long_enough)] +#[derive(Diagnostic)] +#[diag(borrowck_generic_does_not_live_long_enough)] pub(crate) struct GenericDoesNotLiveLongEnough { pub kind: String, #[primary_span] @@ -47,24 +47,15 @@ pub(crate) struct GenericDoesNotLiveLongEnough { } #[derive(LintDiagnostic)] -#[diag(borrowck::var_does_not_need_mut)] +#[diag(borrowck_var_does_not_need_mut)] pub(crate) struct VarNeedNotMut { #[suggestion_short(applicability = "machine-applicable", code = "")] pub span: Span, } - -#[derive(SessionDiagnostic)] -#[diag(borrowck::const_not_used_in_type_alias)] -pub(crate) struct ConstNotUsedTraitAlias { - pub ct: String, - #[primary_span] - pub span: Span, -} - -#[derive(SessionDiagnostic)] -#[diag(borrowck::var_cannot_escape_closure)] +#[derive(Diagnostic)] +#[diag(borrowck_var_cannot_escape_closure)] #[note] -#[note(borrowck::cannot_escape)] +#[note(cannot_escape)] pub(crate) struct FnMutError { #[primary_span] pub span: Span, @@ -72,54 +63,54 @@ pub(crate) struct FnMutError { pub ty_err: FnMutReturnTypeErr, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub(crate) enum VarHereDenote { - #[label(borrowck::var_here_captured)] + #[label(borrowck_var_here_captured)] Captured { #[primary_span] span: Span, }, - #[label(borrowck::var_here_defined)] + #[label(borrowck_var_here_defined)] Defined { #[primary_span] span: Span, }, - #[label(borrowck::closure_inferred_mut)] + #[label(borrowck_closure_inferred_mut)] FnMutInferred { #[primary_span] span: Span, }, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub(crate) enum FnMutReturnTypeErr { - #[label(borrowck::returned_closure_escaped)] + #[label(borrowck_returned_closure_escaped)] ReturnClosure { #[primary_span] span: Span, }, - #[label(borrowck::returned_async_block_escaped)] + #[label(borrowck_returned_async_block_escaped)] ReturnAsyncBlock { #[primary_span] span: Span, }, - #[label(borrowck::returned_ref_escaped)] + #[label(borrowck_returned_ref_escaped)] ReturnRef { #[primary_span] span: Span, }, } -#[derive(SessionDiagnostic)] -#[diag(borrowck::lifetime_constraints_error)] +#[derive(Diagnostic)] +#[diag(borrowck_lifetime_constraints_error)] pub(crate) struct LifetimeOutliveErr { #[primary_span] pub span: Span, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub(crate) enum LifetimeReturnCategoryErr<'a> { - #[label(borrowck::returned_lifetime_wrong)] + #[label(borrowck_returned_lifetime_wrong)] WrongReturn { #[primary_span] span: Span, @@ -127,7 +118,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> { outlived_fr_name: RegionName, fr_name: &'a RegionName, }, - #[label(borrowck::returned_lifetime_short)] + #[label(borrowck_returned_lifetime_short)] ShortReturn { #[primary_span] span: Span, @@ -149,9 +140,9 @@ impl IntoDiagnosticArg for RegionName { } } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub(crate) enum RequireStaticErr { - #[note(borrowck::used_impl_require_static)] + #[note(borrowck_used_impl_require_static)] UsedImpl { #[primary_span] multi_span: MultiSpan, diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 9271a2f4d..a581726a1 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -52,11 +52,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(error_info) => error_info.to_universe_info(old_universe), None => UniverseInfo::other(), }; - for u in old_universe..universe { - self.borrowck_context - .constraints - .universe_causes - .insert(u + 1, universe_info.clone()); + for u in (old_universe + 1)..=universe { + self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); } } @@ -71,15 +68,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: TypeFoldable<'tcx>, { + let old_universe = self.infcx.universe(); + let (instantiated, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - for u in 0..canonical.max_universe.as_u32() { - let info = UniverseInfo::other(); - self.borrowck_context - .constraints - .universe_causes - .insert(ty::UniverseIndex::from_u32(u), info); + for u in (old_universe + 1)..=self.infcx.universe() { + self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other()); } instantiated diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 71eae0583..d5bfc2f52 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -19,7 +19,7 @@ use crate::{ }; pub(crate) struct ConstraintConversion<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, tcx: TyCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, /// Each RBP `GK: 'a` is assumed to be true. These encode @@ -43,7 +43,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> { impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { pub(crate) fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, 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 f1b1c33a1..029095926 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,7 +8,6 @@ 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::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -48,7 +47,7 @@ pub(crate) struct CreateResult<'tcx> { } pub(crate) fn create<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, implicit_region_bound: ty::Region<'tcx>, universal_regions: &Rc<UniversalRegions<'tcx>>, @@ -197,7 +196,7 @@ impl UniversalRegionRelations<'_> { } struct UniversalRegionRelationsBuilder<'this, 'tcx> { - infcx: &'this InferCtxt<'this, 'tcx>, + infcx: &'this InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, universal_regions: Rc<UniversalRegions<'tcx>>, implicit_region_bound: ty::Region<'tcx>, @@ -219,6 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } pub(crate) fn create(mut self) -> CreateResult<'tcx> { + let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id()); let unnormalized_input_output_tys = self .universal_regions .unnormalized_input_tys @@ -250,7 +250,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.infcx .tcx .sess - .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty)); + .delay_span_bug(span, &format!("failed to normalize {:?}", ty)); TypeOpOutput { output: self.infcx.tcx.ty_error(), constraints: None, @@ -301,8 +301,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { &self.region_bound_pairs, self.implicit_region_bound, self.param_env, - Locations::All(DUMMY_SP), - DUMMY_SP, + Locations::All(span), + span, ConstraintCategory::Internal, &mut self.constraints, ) @@ -362,6 +362,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { self.region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a)); } + + OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => { + self.region_bound_pairs + .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a)); + } } } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 4431a2e8e..a66ddd27d 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -7,16 +7,11 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use crate::type_check::constraint_conversion::ConstraintConversion; use rustc_index::vec::Idx; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; -use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; -use rustc_trait_selection::traits::query::Fallible; -use type_op::TypeOpOutput; use crate::universal_regions::UniversalRegions; @@ -185,7 +180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - #[instrument(skip(self, span), level = "debug")] + #[instrument(skip(self), level = "debug")] fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { if let Err(_) = self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) @@ -194,13 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd // like to normalize *before* inserting into `local_decls`, but // doing so ends up causing some other trouble. - let b = match self.normalize_and_add_constraints(b) { - Ok(n) => n, - Err(_) => { - debug!("equate_inputs_and_outputs: NoSolution"); - b - } - }; + let b = self.normalize(b, Locations::All(span)); // Note: if we have to introduce new placeholders during normalization above, then we won't have // added those universes to the universe info, which we would want in `relate_tys`. @@ -218,28 +207,4 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } - - pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> { - let TypeOpOutput { output: norm_ty, constraints, .. } = - self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?; - - debug!("{:?} normalized to {:?}", t, norm_ty); - - for data in constraints { - ConstraintConversion::new( - self.infcx, - &self.borrowck_context.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - Locations::All(DUMMY_SP), - DUMMY_SP, - ConstraintCategory::Internal, - &mut self.borrowck_context.constraints, - ) - .convert_all(&*data); - } - - Ok(norm_ty) - } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3713ec3f5..3c1c3ab45 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexVec<Promoted, Body<'tcx>>, @@ -138,8 +138,6 @@ pub(crate) fn type_check<'mir, 'tcx>( use_polonius: bool, ) -> MirTypeckResults<'tcx> { let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body)); - let mut universe_causes = FxHashMap::default(); - universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other()); let mut constraints = MirTypeckRegionConstraints { placeholder_indices: PlaceholderIndices::default(), placeholder_index_to_region: IndexVec::default(), @@ -148,7 +146,7 @@ pub(crate) fn type_check<'mir, 'tcx>( member_constraints: MemberConstraintSet::default(), closure_bounds_mapping: Default::default(), type_tests: Vec::default(), - universe_causes, + universe_causes: FxHashMap::default(), }; let CreateResult { @@ -165,9 +163,8 @@ pub(crate) fn type_check<'mir, 'tcx>( debug!(?normalized_inputs_and_output); - for u in ty::UniverseIndex::ROOT..infcx.universe() { - let info = UniverseInfo::other(); - constraints.universe_causes.insert(u, info); + for u in ty::UniverseIndex::ROOT..=infcx.universe() { + constraints.universe_causes.insert(u, UniverseInfo::other()); } let mut borrowck_context = BorrowCheckContext { @@ -236,7 +233,7 @@ pub(crate) fn type_check<'mir, 'tcx>( .unwrap(); let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); - if hidden_type.has_infer_types_or_consts() { + if hidden_type.has_non_region_infer() { infcx.tcx.sess.delay_span_bug( decl.hidden_type.span, &format!("could not resolve {:#?}", hidden_type.ty.kind()), @@ -428,12 +425,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { + // const_trait_impl: use a non-const param env when checking that a FnDef type is well formed. + // this is because the well-formedness of the function does not need to be proved to have `const` + // impls for trait bounds. let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); + let prev = self.cx.param_env; + self.cx.param_env = prev.without_const(); self.cx.normalize_and_prove_instantiated_predicates( def_id, instantiated_predicates, locations, ); + self.cx.param_env = prev; } } } @@ -581,6 +584,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // modify their locations. let all_facts = &mut None; let mut constraints = Default::default(); + let mut type_tests = Default::default(); let mut closure_bounds = Default::default(); let mut liveness_constraints = LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); @@ -592,6 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { &mut this.cx.borrowck_context.constraints.outlives_constraints, &mut constraints, ); + mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests); mem::swap( &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, &mut closure_bounds, @@ -616,6 +621,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { swap_constraints(self); let locations = location.to_locations(); + + // Use location of promoted const in collected constraints + for type_test in type_tests.iter() { + let mut type_test = type_test.clone(); + type_test.locations = locations; + self.cx.borrowck_context.constraints.type_tests.push(type_test) + } for constraint in constraints.outlives().iter() { let mut constraint = constraint.clone(); constraint.locations = locations; @@ -764,6 +776,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } PlaceTy::from_ty(fty) } + ProjectionElem::OpaqueCast(ty) => { + let ty = self.sanitize_type(place, ty); + let ty = self.cx.normalize(ty, location); + self.cx + .eq_types( + base.ty, + ty, + location.to_locations(), + ConstraintCategory::TypeAnnotation, + ) + .unwrap(); + PlaceTy::from_ty(ty) + } } } @@ -857,7 +882,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<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -927,7 +952,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { impl<'tcx> MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); @@ -1011,7 +1036,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'a, 'tcx>, + infcx: &'a InferCtxt<'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -1170,10 +1195,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx, self.param_env, proj, - |this, field, ()| { + |this, field, _| { let ty = this.field_ty(tcx, field); self.normalize(ty, locations) }, + |_, _| unreachable!(), ); curr_projected_ty = projected_ty; } @@ -1604,7 +1630,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if from_hir_call { - ConstraintCategory::CallArgument(func_ty) + ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) } else { ConstraintCategory::Boring }; @@ -1757,7 +1783,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx.at(span), self.param_env) { + if !erased_ty.is_sized(tcx, self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough @@ -2189,25 +2215,104 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } - - CastKind::Misc => { + CastKind::IntToInt => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); - // Misc casts are either between floats and ints, or one ptr type to another. match (cast_ty_from, cast_ty_to) { - ( - Some(CastTy::Int(_) | CastTy::Float), - Some(CastTy::Int(_) | CastTy::Float), - ) - | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (), + (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => (), _ => { span_mirbug!( self, rvalue, - "Invalid Misc cast {:?} -> {:?}", + "Invalid IntToInt cast {:?} -> {:?}", ty_from, - ty, + ty + ) + } + } + } + CastKind::IntToFloat => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Int(_)), Some(CastTy::Float)) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid IntToFloat cast {:?} -> {:?}", + ty_from, + ty + ) + } + } + } + CastKind::FloatToInt => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Float), Some(CastTy::Int(_))) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid FloatToInt cast {:?} -> {:?}", + ty_from, + ty + ) + } + } + } + CastKind::FloatToFloat => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Float), Some(CastTy::Float)) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid FloatToFloat cast {:?} -> {:?}", + ty_from, + ty + ) + } + } + } + CastKind::FnPtrToPtr => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid FnPtrToPtr cast {:?} -> {:?}", + ty_from, + ty + ) + } + } + } + CastKind::PtrToPtr => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (), + _ => { + span_mirbug!( + self, + rvalue, + "Invalid PtrToPtr cast {:?} -> {:?}", + ty_from, + ty ) } } @@ -2503,6 +2608,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } ProjectionElem::Field(..) | ProjectionElem::Downcast(..) + | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -2723,7 +2829,7 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { /// constraints in our `InferCtxt` type ErrorInfo = InstantiateOpaqueType<'tcx>; - fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { let (mut output, region_constraints) = scrape_region_constraints(infcx, || { Ok(InferOk { value: (), obligations: self.obligations.clone() }) })?; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c97a6a1a6..4f2dc263b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::TypeRelation; @@ -155,27 +155,16 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> true } - fn register_opaque_type( + fn register_opaque_type_obligations( &mut self, - a: Ty<'tcx>, - b: Ty<'tcx>, - a_is_expected: bool, + obligations: PredicateObligations<'tcx>, ) -> Result<(), TypeError<'tcx>> { - let param_env = self.param_env(); - let span = self.span(); - let def_id = self.type_checker.body.source.def_id().expect_local(); - let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id); - let cause = ObligationCause::misc(span, body_id); self.type_checker .fully_perform_op( self.locations, self.category, InstantiateOpaqueType { - obligations: self - .type_checker - .infcx - .handle_opaque_type(a, b, a_is_expected, &cause, param_env)? - .obligations, + obligations, // These fields are filled in during execution of the operation base_universe: None, region_constraints: None, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 8cf9ed53d..2beb5e0ab 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -22,8 +22,8 @@ use rustc_hir::{BodyOwnerKind, HirId}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{InternalSubsts, SubstsRef}; use std::iter; use crate::nll::ToRegionVid; @@ -219,7 +219,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, mir_def: ty::WithOptConstParam<LocalDefId>, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -382,7 +382,7 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, mir_def: ty::WithOptConstParam<LocalDefId>, mir_hir_id: HirId, param_env: ty::ParamEnv<'tcx>, @@ -414,7 +414,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id()); - // If this is is a 'root' body (not a closure/generator/inline const), then + // If this is a 'root' body (not a closure/generator/inline const), then // there are no extern regions, so the local regions start at the same // position as the (empty) sub-list of extern regions let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id { @@ -699,7 +699,7 @@ trait InferCtxtExt<'tcx> { ); } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { fn replace_free_regions_with_nll_infer_vars<T>( &self, origin: NllRegionVariableOrigin, |