diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f0baa20648cd2..03d5ed889ca1b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -439,6 +439,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { outlives_suggestion: &mut OutlivesSuggestionBuilder, ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); + assert!(self.regioncx.universal_regions().is_universal_region(fr)); + assert!(self.regioncx.universal_regions().is_universal_region(outlived_fr)); let (blame_constraint, path) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 9349b46ec5b0c..568599ba68a64 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -265,6 +265,12 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { .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) + }) + .or_else(|| { + Some(RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::Static, + }) }); if let Some(new_name) = new_name { diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 35264bd1a7075..20a1ec7e50823 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -11,8 +11,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::IndexSlice; use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; use rustc_middle::mir::{ - Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file, - dump_enabled, dump_mir, + Body, ClosureRequirements, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; @@ -43,7 +42,7 @@ pub(crate) struct NllOutput<'tcx> { pub opaque_type_values: FxIndexMap>, pub polonius_input: Option>, pub polonius_output: Option>, - pub opt_closure_req: Option>, + pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, /// When using `-Zpolonius=next`: the localized typeck and liveness constraints. @@ -171,7 +170,7 @@ pub(crate) fn compute_regions<'a, 'tcx>( }); // Solve the region constraints. - let (closure_region_requirements, nll_errors) = + let (closure_outlives_requirements, nll_errors) = regioncx.solve(infcx, body, polonius_output.clone()); if let Some(guar) = nll_errors.has_errors() { @@ -179,14 +178,36 @@ pub(crate) fn compute_regions<'a, 'tcx>( infcx.set_tainted_by_errors(guar); } - let remapped_opaque_tys = regioncx.infer_opaque_types(infcx, opaque_type_values); + let (opaque_type_values, opt_closure_req) = if infcx.tcx.is_typeck_child(body.source.def_id()) { + let opaque_types = regioncx.propagate_opaque_types(infcx, opaque_type_values); + let num_external_vids = regioncx.universal_regions().num_global_and_external_regions(); + let closure_requirements = ClosureRequirements { + num_external_vids, + num_existential_external_regions: regioncx + .universal_regions() + .existential_external_regions + .len(), + outlives_requirements: closure_outlives_requirements.unwrap(), + opaque_types, + }; + if closure_requirements.outlives_requirements.is_empty() + && closure_requirements.opaque_types.is_empty() + { + (Default::default(), None) + } else { + (Default::default(), Some(closure_requirements)) + } + } else { + assert!(closure_outlives_requirements.is_none()); + (regioncx.infer_opaque_types(infcx, opaque_type_values), None) + }; NllOutput { regioncx, - opaque_type_values: remapped_opaque_tys, + opaque_type_values, polonius_input: polonius_facts.map(Box::new), polonius_output, - opt_closure_req: closure_region_requirements, + opt_closure_req, nll_errors, localized_outlives_constraints, } @@ -205,7 +226,7 @@ pub(super) fn dump_nll_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, + closure_requirements: &Option>, borrow_set: &BorrowSet<'tcx>, ) { let tcx = infcx.tcx; @@ -229,7 +250,7 @@ pub(super) fn dump_nll_mir<'tcx>( &0, body, |pass_where, out| { - emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) + emit_nll_mir(tcx, regioncx, closure_requirements, borrow_set, pass_where, out) }, options, ); @@ -251,7 +272,7 @@ pub(super) fn dump_nll_mir<'tcx>( pub(crate) fn emit_nll_mir<'tcx>( tcx: TyCtxt<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, + closure_requirements: &Option>, borrow_set: &BorrowSet<'tcx>, pass_where: PassWhere, out: &mut dyn io::Write, @@ -262,9 +283,9 @@ pub(crate) fn emit_nll_mir<'tcx>( regioncx.dump_mir(tcx, out)?; writeln!(out, "|")?; - if let Some(closure_region_requirements) = closure_region_requirements { + if let Some(closure_requirements) = closure_requirements { writeln!(out, "| Free Region Constraints")?; - for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| { + for_each_region_constraint(tcx, closure_requirements, &mut |msg| { writeln!(out, "| {msg}") })?; writeln!(out, "|")?; @@ -298,7 +319,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( infcx: &'infcx BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, + closure_requirements: &Option>, opaque_type_values: &FxIndexMap>, diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, ) { @@ -316,19 +337,16 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( // better. let def_span = tcx.def_span(body.source.def_id()); - let mut err = if let Some(closure_region_requirements) = closure_region_requirements { + let mut err = if let Some(closure_requirements) = closure_requirements { let mut err = infcx.dcx().struct_span_note(def_span, "external requirements"); regioncx.annotate(tcx, &mut err); - err.note(format!( - "number of external vids: {}", - closure_region_requirements.num_external_vids - )); + err.note(format!("number of external vids: {}", closure_requirements.num_external_vids)); // Dump the region constraints we are imposing *between* those // newly created variables. - for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| { + for_each_region_constraint(tcx, closure_requirements, &mut |msg| { err.note(msg); Ok(()) }) @@ -351,20 +369,26 @@ pub(super) fn dump_annotation<'tcx, 'infcx>( fn for_each_region_constraint<'tcx>( tcx: TyCtxt<'tcx>, - closure_region_requirements: &ClosureRegionRequirements<'tcx>, + closure_requirements: &ClosureRequirements<'tcx>, with_msg: &mut dyn FnMut(String) -> io::Result<()>, ) -> io::Result<()> { - for req in &closure_region_requirements.outlives_requirements { - let subject = match req.subject { - ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"), - ClosureOutlivesSubject::Ty(ty) => { - with_no_trimmed_paths!(format!( - "{}", - ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) - )) - } - }; - with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; + for req in &closure_requirements.outlives_requirements { + let subject = with_no_trimmed_paths!(format!( + "{:?}", + req.subject.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) + )); + // TODO + with_msg(format!( + "where {}: {:?}", + subject, + req.outlived_free_region.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) + ))?; + } + + for data in &closure_requirements.opaque_types { + // TODO + let (key, hidden_ty) = data.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)); + with_msg(format!("where {key:?} = {hidden_ty:?}"))?; } Ok(()) } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index a6d8014903440..101a5281b924e 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -1,7 +1,7 @@ use std::io; use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; -use rustc_middle::mir::{Body, ClosureRegionRequirements, PassWhere}; +use rustc_middle::mir::{Body, ClosureRequirements, PassWhere}; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirIncludeSpans; @@ -19,7 +19,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( regioncx: &RegionInferenceContext<'tcx>, borrow_set: &BorrowSet<'tcx>, localized_outlives_constraints: Option, - closure_region_requirements: &Option>, + closure_requirements: &Option>, ) { let tcx = infcx.tcx; if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { @@ -49,7 +49,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( emit_polonius_mir( tcx, regioncx, - closure_region_requirements, + closure_requirements, borrow_set, &localized_outlives_constraints, pass_where, @@ -64,7 +64,7 @@ pub(crate) fn dump_polonius_mir<'tcx>( fn emit_polonius_mir<'tcx>( tcx: TyCtxt<'tcx>, regioncx: &RegionInferenceContext<'tcx>, - closure_region_requirements: &Option>, + closure_requirements: &Option>, borrow_set: &BorrowSet<'tcx>, localized_outlives_constraints: &LocalizedOutlivesConstraintSet, pass_where: PassWhere, @@ -74,7 +74,7 @@ fn emit_polonius_mir<'tcx>( crate::nll::emit_nll_mir( tcx, regioncx, - closure_region_requirements, + closure_requirements, borrow_set, pass_where.clone(), out, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index d2268c4779d63..93d06f3ca009e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -13,9 +13,8 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::bug; use rustc_middle::mir::{ - AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, - ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location, - ReturnConstraint, TerminatorKind, + AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ConstraintCategory, + InClosureRequirement, Local, Location, ReturnConstraint, TerminatorKind, }; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::fold::fold_regions; @@ -60,33 +59,36 @@ pub struct RegionTracker { min_reachable_universe: UniverseIndex, /// The representative Region Variable Id for this SCC. We prefer - /// placeholders over existentially quantified variables, otherwise - /// it's the one with the smallest Region Variable ID. + /// free regions over placeholders over existentially quantified variables, + /// otherwise it's the one with the smallest Region Variable ID. pub(crate) representative: RegionVid, - /// Is the current representative a placeholder? - representative_is_placeholder: bool, - - /// Is the current representative existentially quantified? - representative_is_existential: bool, + /// Whether the representative is a placeholder, free region, or existential. + representative_origin: NllRegionVariableOrigin, } impl scc::Annotation for RegionTracker { fn merge_scc(mut self, mut other: Self) -> Self { - // Prefer any placeholder over any existential - if other.representative_is_placeholder && self.representative_is_existential { - other.merge_min_max_seen(&self); - return other; - } + use NllRegionVariableOrigin as VarOrigin; + let choose_self = match (self.representative_origin, other.representative_origin) { + (VarOrigin::FreeRegion, VarOrigin::FreeRegion) + | (VarOrigin::Placeholder(_), VarOrigin::Placeholder(_)) + | (VarOrigin::Existential { .. }, VarOrigin::Existential { .. }) => { + self.representative <= other.representative + } + (VarOrigin::FreeRegion, VarOrigin::Placeholder(_) | VarOrigin::Existential { .. }) + | (VarOrigin::Placeholder(_), VarOrigin::Existential { .. }) => true, + (VarOrigin::Placeholder(_) | VarOrigin::Existential { .. }, VarOrigin::FreeRegion) + | (VarOrigin::Existential { .. }, VarOrigin::Placeholder(_)) => false, + }; - if self.representative_is_placeholder && other.representative_is_existential - || (self.representative <= other.representative) - { + if choose_self { self.merge_min_max_seen(&other); - return self; + self + } else { + other.merge_min_max_seen(&self); + return other; } - other.merge_min_max_seen(&self); - other } fn merge_reached(mut self, other: Self) -> Self { @@ -98,22 +100,18 @@ impl scc::Annotation for RegionTracker { impl RegionTracker { pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { - let (representative_is_placeholder, representative_is_existential) = match definition.origin - { - NllRegionVariableOrigin::FreeRegion => (false, false), - NllRegionVariableOrigin::Placeholder(_) => (true, false), - NllRegionVariableOrigin::Existential { .. } => (false, true), - }; - let placeholder_universe = - if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT }; + if let NllRegionVariableOrigin::Placeholder(_) = definition.origin { + definition.universe + } else { + UniverseIndex::ROOT + }; Self { max_placeholder_universe_reached: placeholder_universe, min_reachable_universe: definition.universe, representative: rvid, - representative_is_placeholder, - representative_is_existential, + representative_origin: definition.origin, } } @@ -436,8 +434,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { sccs_info(infcx, &constraint_sccs); } - let mut scc_values = - RegionValues::new(location_map, universal_regions.len(), placeholder_indices); + let mut scc_values = RegionValues::new( + location_map, + universal_regions.len(), + &universal_regions.existential_external_regions, + placeholder_indices, + ); for region in liveness_constraints.regions() { let scc = constraint_sccs.scc(region); @@ -650,7 +652,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx: &InferCtxt<'tcx>, body: &Body<'tcx>, polonius_output: Option>, - ) -> (Option>, RegionErrors<'tcx>) { + ) -> (Option>>, RegionErrors<'tcx>) { let mir_def_id = body.source.def_id(); self.propagate_constraints(); @@ -673,6 +675,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // constraints were too strong, and if so, emit or propagate those errors. if infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() { self.check_polonius_subset_errors( + infcx, outlives_requirements.as_mut(), &mut errors_buffer, polonius_output @@ -680,7 +683,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .expect("Polonius output is unavailable despite `-Z polonius`"), ); } else { - self.check_universal_regions(outlives_requirements.as_mut(), &mut errors_buffer); + self.check_universal_regions(infcx, outlives_requirements.as_mut(), &mut errors_buffer); } debug!(?errors_buffer); @@ -691,17 +694,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!(?errors_buffer); - let outlives_requirements = outlives_requirements.unwrap_or_default(); - - if outlives_requirements.is_empty() { - (None, errors_buffer) - } else { - let num_external_vids = self.universal_regions().num_global_and_external_regions(); - ( - Some(ClosureRegionRequirements { num_external_vids, outlives_requirements }), - errors_buffer, - ) - } + (outlives_requirements, errors_buffer) } /// Propagate the region constraints: this will grow the values @@ -1000,7 +993,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { let static_r = self.universal_regions().fr_static; propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, - outlived_free_region: static_r, + outlived_free_region: InClosureRequirement::bind( + infcx.tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + ty::Region::new_var(infcx.tcx, static_r), + ), blame_span, category: ConstraintCategory::Boring, }); @@ -1030,7 +1028,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { let requirement = ClosureOutlivesRequirement { subject, - outlived_free_region: upper_bound, + outlived_free_region: InClosureRequirement::bind( + infcx.tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + ty::Region::new_var(infcx.tcx, upper_bound), + ), blame_span, category: ConstraintCategory::Boring, }; @@ -1055,7 +1058,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>, - ) -> Option> { + ) -> Option>> { let tcx = infcx.tcx; let mut failed = false; let ty = fold_regions(tcx, ty, |r, _depth| { @@ -1087,7 +1090,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { return None; } - Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty))) + Some(InClosureRequirement::bind( + tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + ty.into(), + )) } /// Like `universal_upper_bound`, but returns an approximation more suitable @@ -1330,6 +1338,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_universal_regions( &self, + infcx: &InferCtxt<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { @@ -1341,6 +1350,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. self.check_universal_region( + infcx, fr, &mut propagated_outlives_requirements, errors_buffer, @@ -1381,6 +1391,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// report them as errors. fn check_polonius_subset_errors( &self, + infcx: &InferCtxt<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, polonius_output: &PoloniusOutput, @@ -1427,6 +1438,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let propagated = self.try_propagate_universal_region_error( + infcx, longer_fr.into(), shorter_fr.into(), &mut propagated_outlives_requirements, @@ -1474,13 +1486,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. - #[instrument(skip(self, propagated_outlives_requirements, errors_buffer), level = "debug")] + #[instrument( + skip(self, infcx, propagated_outlives_requirements, errors_buffer), + level = "debug" + )] fn check_universal_region( &self, + infcx: &InferCtxt<'tcx>, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { + assert!(self.universal_regions().is_universal_region(longer_fr)); let longer_fr_scc = self.constraint_sccs.scc(longer_fr); // Because this free region must be in the ROOT universe, we @@ -1494,8 +1511,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Note that the representative will be a universal region if there is // one in this SCC, so we will always check the representative here. let representative = self.scc_representative(longer_fr_scc); + assert!(self.universal_regions().is_universal_region(representative)); if representative != longer_fr { if let RegionRelationCheckResult::Error = self.check_universal_region_relation( + infcx, longer_fr, representative, propagated_outlives_requirements, @@ -1514,7 +1533,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // (because `fr` includes `end(o)`). let mut error_reported = false; for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) { + assert!(self.universal_regions().is_universal_region(shorter_fr)); if let RegionRelationCheckResult::Error = self.check_universal_region_relation( + infcx, longer_fr, shorter_fr, propagated_outlives_requirements, @@ -1537,8 +1558,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Checks that we can prove that `longer_fr: shorter_fr`. If we can't we attempt to propagate /// the constraint outward (e.g. to a closure environment), but if that fails, there is an /// error. + #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements), ret)] fn check_universal_region_relation( &self, + infcx: &InferCtxt<'tcx>, longer_fr: RegionVid, shorter_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, @@ -1554,6 +1577,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. self.try_propagate_universal_region_error( + infcx, longer_fr, shorter_fr, propagated_outlives_requirements, @@ -1565,6 +1589,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// creator. If we cannot, then the caller should report an error to the user. fn try_propagate_universal_region_error( &self, + infcx: &InferCtxt<'tcx>, longer_fr: RegionVid, shorter_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, @@ -1595,8 +1620,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { for fr in shorter_fr_plus { // Push the constraint `fr-: shorter_fr+` propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, + subject: InClosureRequirement::bind( + infcx.tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + ty::Region::new_var(infcx.tcx, fr_minus).into(), + ), + outlived_free_region: InClosureRequirement::bind( + infcx.tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + ty::Region::new_var(infcx.tcx, fr), + ), blame_span: blame_span_category.1.span, category: blame_span_category.0, }); @@ -1702,11 +1737,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { fr2: RegionVid, ) -> bool { debug!("provides_universal_region(r={:?}, fr1={:?}, fr2={:?})", r, fr1, fr2); - let result = { - r == fr2 || { - fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r) - } - }; + let result = r == fr2 + || (fr2 == self.universal_regions().fr_static && self.cannot_name_placeholder(fr1, r)); debug!("provides_universal_region: result = {:?}", result); result } @@ -1778,6 +1810,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Check if we reached the region we were looking for. If so, // we can reconstruct the path that led to it and return it. if target_test(r) { + debug!("found target"); let mut result = vec![]; let mut p = r; loop { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7c484327e3118..51f1bd864cd0c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -3,6 +3,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _}; use rustc_macros::extension; +use rustc_middle::mir::InClosureRequirement; use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ @@ -18,6 +19,53 @@ use crate::session_diagnostics::{LifetimeMismatchOpaqueParam, NonGenericOpaqueTy use crate::universal_regions::RegionClassification; impl<'tcx> RegionInferenceContext<'tcx> { + pub(crate) fn propagate_opaque_types( + &self, + infcx: &InferCtxt<'tcx>, + opaque_ty_decls: FxIndexMap, OpaqueHiddenType<'tcx>>, + ) -> Vec, OpaqueHiddenType<'tcx>)>> { + let mut propagated_decls = Vec::new(); + for (opaque_type_key, concrete_type) in opaque_ty_decls { + let mut guar = None; + let propagated = fold_regions(infcx.tcx, (opaque_type_key, concrete_type), |r, _| { + // Use the SCC representative instead of directly using `region`. + // See [rustc-dev-guide chapter] § "Strict lifetime equality". + let scc = self.constraint_sccs.scc(r.as_var()); + let vid = self.scc_representative(scc); + self.universal_regions() + .universal_regions_iter() + .filter(|&ur| { + match self.universal_regions().region_classification(ur).unwrap() { + RegionClassification::Global | RegionClassification::External { .. } => true, + RegionClassification::Local => false, + } + }) + .find(|&ur| self.universal_region_relations.equal(vid, ur)) + .or_else(|| self.universal_regions().existential_external_regions.contains(&vid).then(|| vid)) + .map(|ur| ty::Region::new_var(infcx.tcx, ur)) + .unwrap_or_else(|| { + ty::Region::new_error( + infcx.tcx, + *guar.get_or_insert_with(|| { + infcx.tcx.dcx().span_err( + concrete_type.span, + format!("defining opaque type with local region in closure: {opaque_type_key:?} {concrete_type:?}"), + ) + }), + ) + }) + }); + + propagated_decls.push(InClosureRequirement::bind( + infcx.tcx, + self.universal_regions().num_global_and_external_regions(), + &self.universal_regions().existential_external_regions, + propagated, + )); + } + propagated_decls + } + /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. /// @@ -91,13 +139,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { NllRegionVariableOrigin::FreeRegion => self .universal_regions() .universal_regions_iter() - .filter(|&ur| { - // See [rustc-dev-guide chapter] § "Closure restrictions". - !matches!( - self.universal_regions().region_classification(ur), - Some(RegionClassification::External) - ) - }) .find(|&ur| self.universal_region_relations.equal(vid, ur)) .map(|ur| self.definitions[ur].external_name.unwrap()), NllRegionVariableOrigin::Placeholder(placeholder) => { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index f1bcb353dc61c..9c9cd504196e7 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -243,7 +243,10 @@ pub(crate) struct RegionValues { location_map: Rc, placeholder_indices: PlaceholderIndices, points: SparseIntervalMatrix, - free_regions: SparseBitMatrix, + free_regions: SparseBitMatrix, + // TODO + num_universal_regions: usize, + existential_external_regions: FxIndexSet, /// Placeholders represent bound regions -- so something like `'a` /// in `for<'a> fn(&'a u32)`. @@ -257,6 +260,7 @@ impl RegionValues { pub(crate) fn new( location_map: Rc, num_universal_regions: usize, + existential_external_regions: &FxIndexSet, placeholder_indices: PlaceholderIndices, ) -> Self { let num_points = location_map.num_points(); @@ -265,7 +269,11 @@ impl RegionValues { location_map, points: SparseIntervalMatrix::new(num_points), placeholder_indices, - free_regions: SparseBitMatrix::new(num_universal_regions), + free_regions: SparseBitMatrix::new( + num_universal_regions + existential_external_regions.len(), + ), + num_universal_regions, + existential_external_regions: existential_external_regions.clone(), placeholders: SparseBitMatrix::new(num_placeholders), } } @@ -353,7 +361,16 @@ impl RegionValues { &'a self, r: N, ) -> impl Iterator + 'a { - self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) + self.free_regions.row(r).into_iter().flat_map(|set| set.iter()).map(|idx| { + if idx < self.num_universal_regions { + RegionVid::from_usize(idx) + } else { + *self + .existential_external_regions + .get_index(idx - self.num_universal_regions) + .unwrap() + } + }) } /// Returns all the elements contained in a given region's value. @@ -410,11 +427,25 @@ impl ToElementIndex for Location { impl ToElementIndex for RegionVid { fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - values.free_regions.insert(row, self) + let idx = if self.as_usize() < values.num_universal_regions { + self.as_usize() + } else { + values.num_universal_regions + + values.existential_external_regions.get_index_of(&self).unwrap() + }; + + values.free_regions.insert(row, idx) } fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - values.free_regions.contains(row, self) + let idx = if self.as_usize() < values.num_universal_regions { + self.as_usize() + } else { + values.num_universal_regions + + values.existential_external_regions.get_index_of(&self).unwrap() + }; + + values.free_regions.contains(row, idx) } } diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 4b7f53213886e..5c0c727258b86 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -5,11 +5,14 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::bug; -use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; +use rustc_middle::mir::{ClosureRequirements, ConstraintCategory}; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, +}; use rustc_span::Span; use rustc_trait_selection::traits::ScrubbedTraitError; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; @@ -90,17 +93,24 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(crate) fn apply_closure_requirements( &mut self, - closure_requirements: &ClosureRegionRequirements<'tcx>, + closure_requirements: &ClosureRequirements<'tcx>, closure_def_id: DefId, closure_args: ty::GenericArgsRef<'tcx>, - ) { + ) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { + let ClosureRequirements { + num_external_vids, + num_existential_external_regions, + outlives_requirements, + opaque_types, + } = closure_requirements; // Extract the values of the free regions in `closure_args` // into a vector. These are the regions that we will be // relating to one another. let closure_mapping = &UniversalRegions::closure_mapping( - self.tcx, + self.infcx, closure_args, - closure_requirements.num_external_vids, + *num_external_vids, + *num_existential_external_regions, closure_def_id.expect_local(), ); debug!(?closure_mapping); @@ -108,23 +118,26 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // Create the predicates. let backup = (self.category, self.span, self.from_closure); self.from_closure = true; - for outlives_requirement in &closure_requirements.outlives_requirements { - let outlived_region = closure_mapping[outlives_requirement.outlived_free_region]; - let subject = match outlives_requirement.subject { - ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(), - ClosureOutlivesSubject::Ty(subject_ty) => { - subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into() - } - }; - + for outlives_requirement in outlives_requirements { + let outlived_region = outlives_requirement + .outlived_free_region + .instantiate(self.tcx, |vid| closure_mapping[vid]); + let subject = + outlives_requirement.subject.instantiate(self.tcx, |vid| closure_mapping[vid]); self.category = outlives_requirement.category; self.span = outlives_requirement.blame_span; self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category); } (self.category, self.span, self.from_closure) = backup; + + let mut instantiated_opaque_types = Vec::new(); + for data in opaque_types { + instantiated_opaque_types.push(data.instantiate(self.tcx, |vid| closure_mapping[vid])); + } + instantiated_opaque_types } - fn convert( + pub(super) fn convert( &mut self, predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'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 edf612f4e97a4..edf2dd8622d9f 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -4,7 +4,7 @@ use rustc_hir::def::DefKind; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; -use rustc_infer::infer::{InferCtxt, outlives}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, outlives}; use rustc_infer::traits::ScrubbedTraitError; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::ObligationCause; @@ -22,7 +22,7 @@ use crate::universal_regions::UniversalRegions; #[derive(Debug)] pub(crate) struct UniversalRegionRelations<'tcx> { - pub(crate) universal_regions: UniversalRegions<'tcx>, + pub(crate) universal_regions: Frozen>, /// Stores the outlives relations that are known to hold from the /// implied bounds, in-scope where-clauses, and that sort of @@ -36,6 +36,57 @@ pub(crate) struct UniversalRegionRelations<'tcx> { inverse_outlives: TransitiveRelation, } +pub(crate) struct UniversalRegionRelationsBuilder<'tcx> { + pub(crate) universal_regions: UniversalRegions<'tcx>, + outlives: TransitiveRelationBuilder, + inverse_outlives: TransitiveRelationBuilder, +} + +impl<'tcx> UniversalRegionRelationsBuilder<'tcx> { + /// Records in the `outlives_relation` (and + /// `inverse_outlives_relation`) that `fr_a: fr_b`. + fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { + debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); + self.outlives.add(fr_a, fr_b); + self.inverse_outlives.add(fr_b, fr_a); + } + + pub(crate) fn add_existential_external_region( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> ty::Region<'tcx> { + let external = infcx.next_nll_region_var_in_universe( + NllRegionVariableOrigin::FreeRegion, + ty::UniverseIndex::ROOT, + ); + let external_vid = self.universal_regions.to_region_vid(external); + self.universal_regions.existential_external_regions.insert(external_vid); + external + } + + pub(crate) fn freeze(mut self) -> Frozen> { + // - outlives is reflexive, so `'r: 'r` for every region `'r` + // - `'static: 'r` for every region `'r` + // - `'r: 'fn_body` for every (other) universally quantified + // region `'r`, all of which are provided by our caller + let fr_static = self.universal_regions.fr_static; + let fr_fn_body = self.universal_regions.fr_fn_body; + // TODO + for fr in self.universal_regions.universal_regions_iter().collect::>() { + debug!("build: relating free region {:?} to itself and to 'static", fr); + self.relate_universal_regions(fr, fr); + self.relate_universal_regions(fr_static, fr); + self.relate_universal_regions(fr, fr_fn_body); + } + + Frozen::freeze(UniversalRegionRelations { + universal_regions: Frozen::freeze(self.universal_regions), + outlives: self.outlives.freeze(), + inverse_outlives: self.inverse_outlives.freeze(), + }) + } +} + /// As part of computing the free region relations, we also have to /// normalize the input-output types, which we then need later. So we /// return those. This vector consists of first the input types and @@ -43,7 +94,7 @@ pub(crate) struct UniversalRegionRelations<'tcx> { type NormalizedInputsAndOutput<'tcx> = Vec>; pub(crate) struct CreateResult<'tcx> { - pub(crate) universal_region_relations: Frozen>, + pub(crate) universal_region_relations: UniversalRegionRelationsBuilder<'tcx>, pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, pub(crate) known_type_outlives_obligations: Vec>, pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, @@ -56,15 +107,17 @@ pub(crate) fn create<'tcx>( universal_regions: UniversalRegions<'tcx>, constraints: &mut MirTypeckRegionConstraints<'tcx>, ) -> CreateResult<'tcx> { - UniversalRegionRelationsBuilder { + FreeRegionRelationsBuilder { infcx, param_env, implicit_region_bound, constraints, - universal_regions, + universal_region_relations: UniversalRegionRelationsBuilder { + universal_regions, + outlives: Default::default(), + inverse_outlives: Default::default(), + }, region_bound_pairs: Default::default(), - outlives: Default::default(), - inverse_outlives: Default::default(), } .create() } @@ -180,32 +233,23 @@ impl UniversalRegionRelations<'_> { } } -struct UniversalRegionRelationsBuilder<'a, 'tcx> { +struct FreeRegionRelationsBuilder<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - universal_regions: UniversalRegions<'tcx>, implicit_region_bound: ty::Region<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, // outputs: - outlives: TransitiveRelationBuilder, - inverse_outlives: TransitiveRelationBuilder, + universal_region_relations: UniversalRegionRelationsBuilder<'tcx>, region_bound_pairs: RegionBoundPairs<'tcx>, } -impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } - +impl<'tcx> FreeRegionRelationsBuilder<'_, 'tcx> { #[instrument(level = "debug", skip(self))] pub(crate) fn create(mut self) -> CreateResult<'tcx> { let tcx = self.infcx.tcx; - let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local(); + let defining_ty_def_id = + self.universal_region_relations.universal_regions.defining_ty.def_id().expect_local(); let span = tcx.def_span(defining_ty_def_id); // Insert the `'a: 'b` we know from the predicates. @@ -213,19 +257,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let param_env = self.param_env; self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); - // - outlives is reflexive, so `'r: 'r` for every region `'r` - // - `'static: 'r` for every region `'r` - // - `'r: 'fn_body` for every (other) universally quantified - // region `'r`, all of which are provided by our caller - let fr_static = self.universal_regions.fr_static; - let fr_fn_body = self.universal_regions.fr_fn_body; - for fr in self.universal_regions.universal_regions_iter() { - debug!("build: relating free region {:?} to itself and to 'static", fr); - self.relate_universal_regions(fr, fr); - self.relate_universal_regions(fr_static, fr); - self.relate_universal_regions(fr, fr_fn_body); - } - // Normalize the assumptions we use to borrowck the program. let mut constraints = vec![]; let mut known_type_outlives_obligations = vec![]; @@ -241,11 +272,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } let unnormalized_input_output_tys = self + .universal_region_relations .universal_regions .unnormalized_input_tys .iter() .cloned() - .chain(Some(self.universal_regions.unnormalized_output_ty)); + .chain(Some(self.universal_region_relations.universal_regions.unnormalized_output_ty)); // For each of the input/output types: // - Normalize the type. This will create some region @@ -255,8 +287,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // the `region_bound_pairs` and so forth. // - After this is done, we'll process the constraints, once // the `relations` is built. - let mut normalized_inputs_and_output = - Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1); + let mut normalized_inputs_and_output = Vec::with_capacity( + self.universal_region_relations.universal_regions.unnormalized_input_tys.len() + 1, + ); for ty in unnormalized_input_output_tys { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty. @@ -322,7 +355,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { for c in constraints { constraint_conversion::ConstraintConversion::new( self.infcx, - &self.universal_regions, + &self.universal_region_relations.universal_regions, &self.region_bound_pairs, self.implicit_region_bound, param_env, @@ -336,11 +369,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } CreateResult { - universal_region_relations: Frozen::freeze(UniversalRegionRelations { - universal_regions: self.universal_regions, - outlives: self.outlives.freeze(), - inverse_outlives: self.inverse_outlives.freeze(), - }), + universal_region_relations: self.universal_region_relations, known_type_outlives_obligations, region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, @@ -422,9 +451,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { // The bound says that `r1 <= r2`; we store `r2: r1`. - let r1 = self.universal_regions.to_region_vid(r1); - let r2 = self.universal_regions.to_region_vid(r2); - self.relate_universal_regions(r2, r1); + let r1 = self.universal_region_relations.universal_regions.to_region_vid(r1); + let r2 = self.universal_region_relations.universal_regions.to_region_vid(r2); + self.universal_region_relations.relate_universal_regions(r2, r1); } OutlivesBound::RegionSubParam(r_a, param_b) => { diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 1f2ec168f0322..2c0600356251e 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -48,7 +48,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // FIXME(async_closures): It's kind of wacky that we must apply this // transformation here, since we do the same thing in HIR typeck. // Maybe we could just fix up the canonicalized signature during HIR typeck? - if let DefiningTy::CoroutineClosure(_, args) = self.universal_regions.defining_ty { + if let DefiningTy::CoroutineClosure(_, args) = + self.universal_region_relations.universal_regions.defining_ty + { assert_matches!( self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), Some(hir::CoroutineKind::Desugared( @@ -160,7 +162,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_yield_ty) = body.yield_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - self.universal_regions.yield_ty.unwrap(), + self.universal_region_relations.universal_regions.yield_ty.unwrap(), mir_yield_ty, yield_span, ); @@ -169,7 +171,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(mir_resume_ty) = body.resume_ty() { let yield_span = body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( - self.universal_regions.resume_ty.unwrap(), + self.universal_region_relations.universal_regions.resume_ty.unwrap(), mir_resume_ty, yield_span, ); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 4e0b2a4e29681..ffaea885a2398 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -45,11 +45,11 @@ pub(super) fn generate<'a, 'tcx>( let free_regions = if !typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { regions_that_outlive_free_regions( typeck.infcx.num_region_vars(), - &typeck.universal_regions, + &typeck.universal_region_relations.universal_regions, &typeck.constraints.outlives_constraints, ) } else { - typeck.universal_regions.universal_regions_iter().collect() + typeck.universal_region_relations.universal_regions.universal_regions_iter().collect() }; let (relevant_live_locals, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); @@ -69,7 +69,7 @@ pub(super) fn generate<'a, 'tcx>( record_regular_live_regions( typeck.tcx(), &mut typeck.constraints.liveness_constraints, - &typeck.universal_regions, + &typeck.universal_region_relations.universal_regions, &mut typeck.polonius_context, body, ); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index c564d85616e25..28594e0241cc5 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -551,7 +551,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { self.typeck.tcx(), dropped_local, &kind, - self.typeck.universal_regions, + &self.typeck.universal_region_relations.universal_regions, self.typeck.polonius_facts, ); } @@ -573,7 +573,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { tcx: typeck.tcx(), param_env: typeck.infcx.param_env, op: |r| { - let live_region_vid = typeck.universal_regions.to_region_vid(r); + let live_region_vid = + typeck.universal_region_relations.universal_regions.to_region_vid(r); typeck.constraints.liveness_constraints.add_points(live_region_vid, live_at); }, @@ -583,7 +584,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { if let Some(polonius_context) = typeck.polonius_context { polonius_context.record_live_region_variance( typeck.infcx.tcx, - typeck.universal_regions, + &typeck.universal_region_relations.universal_regions, value, ); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index eca8a688ff4a2..386c543216b7f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use std::{fmt, iter, mem}; +use free_region_relations::UniversalRegionRelationsBuilder; use rustc_abi::FieldIdx; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -18,7 +19,7 @@ use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::{ BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, }; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::traits::{Obligation, ObligationCause, PredicateObligations}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -40,7 +41,9 @@ use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, sym}; -use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; +use rustc_trait_selection::traits::query::type_op::custom::{ + CustomTypeOp, scrape_region_constraints, +}; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument, trace}; @@ -128,7 +131,7 @@ pub(crate) fn type_check<'a, 'tcx>( }; let CreateResult { - universal_region_relations, + mut universal_region_relations, region_bound_pairs, normalized_inputs_and_output, known_type_outlives_obligations, @@ -163,7 +166,7 @@ pub(crate) fn type_check<'a, 'tcx>( known_type_outlives_obligations, implicit_region_bound, reported_errors: Default::default(), - universal_regions: &universal_region_relations.universal_regions, + universal_region_relations: &mut universal_region_relations, location_table, polonius_facts, borrow_set, @@ -182,8 +185,18 @@ pub(crate) fn type_check<'a, 'tcx>( liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data); - let opaque_type_values = - opaque_types::take_opaques_and_register_member_constraints(&mut typeck); + let opaque_type_values = opaque_types::take_opaque_types(&mut typeck); + // Add member constraints in case we're in the typeck root. See + // the comment of `register_member_constraints` for more details. + // + // We don't do so for typeck children, e.g. closures, as we propagate + // the opaque type value to its parent instead and then prove their + // member constraints there. + if !infcx.tcx.is_typeck_child(body.source.def_id()) { + opaque_types::register_member_constraints(&mut typeck, &opaque_type_values); + } else { + opaque_types::force_regions_to_existential_externals(&mut typeck, &opaque_type_values); + } if let Some(polonius_context) = typeck.polonius_context.as_mut() { let num_regions = infcx.num_region_vars(); @@ -193,7 +206,7 @@ pub(crate) fn type_check<'a, 'tcx>( MirTypeckResults { constraints, - universal_region_relations, + universal_region_relations: universal_region_relations.freeze(), opaque_type_values, polonius_context, } @@ -315,7 +328,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let ty = constant.const_.ty(); self.typeck.infcx.tcx.for_each_free_region(&ty, |live_region| { - let live_region_vid = self.typeck.universal_regions.to_region_vid(live_region); + let live_region_vid = + self.typeck.universal_region_relations.universal_regions.to_region_vid(live_region); self.typeck.constraints.liveness_constraints.add_location(live_region_vid, location); }); @@ -559,7 +573,7 @@ struct TypeChecker<'a, 'tcx> { known_type_outlives_obligations: Vec>, implicit_region_bound: ty::Region<'tcx>, reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, - universal_regions: &'a UniversalRegions<'tcx>, + universal_region_relations: &'a mut UniversalRegionRelationsBuilder<'tcx>, location_table: &'a PoloniusLocationTable, polonius_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, @@ -708,7 +722,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let ty::RePlaceholder(placeholder) = r.kind() { self.constraints.placeholder_region(self.infcx, placeholder).as_var() } else { - self.universal_regions.to_region_vid(r) + self.universal_region_relations.universal_regions.to_region_vid(r) } } @@ -747,7 +761,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, - self.universal_regions, + &self.universal_region_relations.universal_regions, &self.region_bound_pairs, self.implicit_region_bound, self.infcx.param_env, @@ -849,7 +863,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } let args = self.infcx.resolve_vars_if_possible(args.args); - let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); + let predicates = self.prove_closure_bounds(def_id, args, Locations::All(span)); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -873,7 +887,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // though. let category = match place.as_local() { Some(RETURN_PLACE) => { - let defining_ty = &self.universal_regions.defining_ty; + let defining_ty = + &self.universal_region_relations.universal_regions.defining_ty; if defining_ty.is_const() { if tcx.is_static(defining_ty.def_id()) { ConstraintCategory::UseAsStatic @@ -1122,7 +1137,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // output) types in the signature must be live, since // all the inputs that fed into it were live. for &late_bound_region in map.values() { - let region_vid = self.universal_regions.to_region_vid(late_bound_region); + let region_vid = self + .universal_region_relations + .universal_regions + .to_region_vid(late_bound_region); self.constraints.liveness_constraints.add_location(region_vid, term_location); } @@ -1212,7 +1230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let category = match destination.as_local() { Some(RETURN_PLACE) => { if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = - self.universal_regions.defining_ty + self.universal_region_relations.universal_regions.defining_ty { if tcx.is_static(def_id) { ConstraintCategory::UseAsStatic @@ -1546,16 +1564,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(uv) = maybe_uneval { if uv.promoted.is_none() { - let tcx = self.tcx(); let def_id = uv.def; - if tcx.def_kind(def_id) == DefKind::InlineConst { + if self.tcx().def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds( - tcx, - def_id, - uv.args, - location.to_locations(), - ); + let predicates = + self.prove_closure_bounds(def_id, uv.args, location.to_locations()); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -2498,12 +2511,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | AggregateKind::CoroutineClosure(def_id, args) | AggregateKind::Coroutine(def_id, args) => ( def_id, - self.prove_closure_bounds( - tcx, - def_id.expect_local(), - args, - location.to_locations(), - ), + self.prove_closure_bounds(def_id.expect_local(), args, location.to_locations()), ), AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => { @@ -2520,15 +2528,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn prove_closure_bounds( &mut self, - tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { + let tcx = self.infcx.tcx; if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { - constraint_conversion::ConstraintConversion::new( + let opaque_types = constraint_conversion::ConstraintConversion::new( self.infcx, - self.universal_regions, + &self.universal_region_relations.universal_regions, &self.region_bound_pairs, self.implicit_region_bound, self.infcx.param_env, @@ -2539,6 +2547,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.constraints, ) .apply_closure_requirements(closure_requirements, def_id.to_def_id(), args); + + for (OpaqueTypeKey { def_id, args }, hidden_ty) in opaque_types { + let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( + Locations::All(hidden_ty.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |ocx| { + let cause = ObligationCause::dummy_with_span(hidden_ty.span); + let alias = ty::AliasTy::new(tcx, def_id.to_def_id(), args).to_ty(tcx); + ocx.eq(&cause, self.infcx.param_env, alias, hidden_ty.ty) + .map_err(|_e| NoSolution) + }, + "opaque_type_map", + ), + ); + } } // Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589. diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs index ad4e006c21ae8..310d4cc6959c2 100644 --- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs +++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs @@ -1,6 +1,7 @@ use std::iter; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{ @@ -9,30 +10,19 @@ use rustc_middle::ty::{ }; use tracing::{debug, trace}; -use super::{MemberConstraintSet, TypeChecker}; +use super::{Locations, TypeChecker, constraint_conversion}; /// Once we're done with typechecking the body, we take all the opaque types /// defined by this function and add their 'member constraints'. -pub(super) fn take_opaques_and_register_member_constraints<'tcx>( +pub(super) fn take_opaque_types<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, ) -> FxIndexMap, OpaqueHiddenType<'tcx>> { let infcx = typeck.infcx; - // Annoying: to invoke `typeck.to_region_vid`, we need access to - // `typeck.constraints`, but we also want to be mutating - // `typeck.member_constraints`. For now, just swap out the value - // we want and replace at the end. - let mut member_constraints = std::mem::take(&mut typeck.constraints.member_constraints); - let opaque_types = infcx + infcx .take_opaque_types() .into_iter() .map(|(opaque_type_key, hidden_type)| { let hidden_type = infcx.resolve_vars_if_possible(hidden_type); - register_member_constraints( - typeck, - &mut member_constraints, - opaque_type_key, - hidden_type, - ); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); if hidden_type.has_non_region_infer() { span_bug!(hidden_type.span, "could not resolve {:?}", hidden_type.ty); @@ -46,10 +36,55 @@ pub(super) fn take_opaques_and_register_member_constraints<'tcx>( (opaque_type_key, hidden_type) }) - .collect(); - assert!(typeck.constraints.member_constraints.is_empty()); - typeck.constraints.member_constraints = member_constraints; - opaque_types + .collect() +} + +pub(super) fn force_regions_to_existential_externals<'tcx>( + typeck: &mut TypeChecker<'_, 'tcx>, + opaque_types: &FxIndexMap, OpaqueHiddenType<'tcx>>, +) { + let infcx = typeck.infcx; + let fr_fn_body = ty::Region::new_var( + infcx.tcx, + typeck.universal_region_relations.universal_regions.fr_fn_body, + ); + let mut existential_external_region_map = FxHashSet::default(); + for (&key, &hidden_ty) in opaque_types { + fold_regions(infcx.tcx, (key, hidden_ty), |r, _| { + if existential_external_region_map.insert(r) { + let external_reg = + typeck.universal_region_relations.add_existential_external_region(infcx); + + let external_vid = typeck.to_region_vid(external_reg); + typeck + .universal_region_relations + .universal_regions + .existential_external_regions + .insert(external_vid); + let mut constraint_conversion = constraint_conversion::ConstraintConversion::new( + infcx, + &typeck.universal_region_relations.universal_regions, + &typeck.region_bound_pairs, + typeck.implicit_region_bound, + infcx.param_env, + &typeck.known_type_outlives_obligations, + Locations::All(hidden_ty.span), + hidden_ty.span, + ConstraintCategory::OpaqueType, + typeck.constraints, + ); + constraint_conversion.convert( + ty::OutlivesPredicate(external_reg.into(), r), + ConstraintCategory::OpaqueType, + ); + constraint_conversion.convert( + ty::OutlivesPredicate(r.into(), external_reg), + ConstraintCategory::OpaqueType, + ); + } + r + }); + } } /// Given the map `opaque_types` containing the opaque @@ -192,56 +227,63 @@ pub(super) fn take_opaques_and_register_member_constraints<'tcx>( /// but this is not necessary, because the opaque type we /// create will be allowed to reference `T`. So we only generate a /// constraint that `'0: 'a`. -fn register_member_constraints<'tcx>( +pub(super) fn register_member_constraints<'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, - member_constraints: &mut MemberConstraintSet<'tcx, ty::RegionVid>, - opaque_type_key: OpaqueTypeKey<'tcx>, - OpaqueHiddenType { span, ty: hidden_ty }: OpaqueHiddenType<'tcx>, + opaque_types: &FxIndexMap, OpaqueHiddenType<'tcx>>, ) { + // Annoying: to invoke `typeck.to_region_vid`, we need access to + // `typeck.constraints`, but we also want to be mutating + // `typeck.member_constraints`. For now, just swap out the value + // we want and replace at the end. + let mut member_constraints = std::mem::take(&mut typeck.constraints.member_constraints); let tcx = typeck.tcx(); - let hidden_ty = typeck.infcx.resolve_vars_if_possible(hidden_ty); - debug!(?hidden_ty); + for (&opaque_type_key, &ty::OpaqueHiddenType { span, ty: hidden_ty }) in opaque_types { + let hidden_ty = typeck.infcx.resolve_vars_if_possible(hidden_ty); + debug!(?hidden_ty); - let variances = tcx.variances_of(opaque_type_key.def_id); - debug!(?variances); + let variances = tcx.variances_of(opaque_type_key.def_id); + debug!(?variances); - // For a case like `impl Foo<'a, 'b>`, we would generate a constraint - // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the - // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`). - // - // `conflict1` and `conflict2` are the two region bounds that we - // detected which were unrelated. They are used for diagnostics. + // For a case like `impl Foo<'a, 'b>`, we would generate a constraint + // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the + // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`). + // + // `conflict1` and `conflict2` are the two region bounds that we + // detected which were unrelated. They are used for diagnostics. - // Create the set of choice regions: each region in the hidden - // type can be equal to any of the region parameters of the - // opaque type definition. - let fr_static = typeck.universal_regions.fr_static; - let choice_regions: Vec<_> = opaque_type_key - .args - .iter() - .enumerate() - .filter(|(i, _)| variances[*i] == ty::Invariant) - .filter_map(|(_, arg)| match arg.unpack() { - GenericArgKind::Lifetime(r) => Some(typeck.to_region_vid(r)), - GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, - }) - .chain(iter::once(fr_static)) - .collect(); + // Create the set of choice regions: each region in the hidden + // type can be equal to any of the region parameters of the + // opaque type definition. + let fr_static = typeck.universal_region_relations.universal_regions.fr_static; + let choice_regions: Vec<_> = opaque_type_key + .args + .iter() + .enumerate() + .filter(|(i, _)| variances[*i] == ty::Invariant) + .filter_map(|(_, arg)| match arg.unpack() { + GenericArgKind::Lifetime(r) => Some(typeck.to_region_vid(r)), + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, + }) + .chain(iter::once(fr_static)) + .collect(); - // FIXME(#42940): This should use the `FreeRegionsVisitor`, but that's - // not currently sound until we have existential regions. - hidden_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - tcx, - op: |r| { - member_constraints.add_member_constraint( - opaque_type_key, - hidden_ty, - span, - typeck.to_region_vid(r), - &choice_regions, - ) - }, - }); + // FIXME(#42940): This should use the `FreeRegionsVisitor`, but that's + // not currently sound until we have existential regions. + hidden_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { + tcx, + op: |r| { + member_constraints.add_member_constraint( + opaque_type_key, + hidden_ty, + span, + typeck.to_region_vid(r), + &choice_regions, + ) + }, + }); + } + assert!(typeck.constraints.member_constraints.is_empty()); + typeck.constraints.member_constraints = member_constraints; } /// Visitor that requires that (almost) all regions in the type visited outlive diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 59e2eee41d3fc..4f8c4d4e1030d 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -286,8 +286,8 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { sub: ty::Region<'tcx>, info: ty::VarianceDiagInfo>, ) { - let sub = self.type_checker.universal_regions.to_region_vid(sub); - let sup = self.type_checker.universal_regions.to_region_vid(sup); + let sub = self.type_checker.universal_region_relations.universal_regions.to_region_vid(sub); + let sup = self.type_checker.universal_region_relations.universal_regions.to_region_vid(sup); self.type_checker.constraints.outlives_constraints.push(OutlivesConstraint { sup, sub, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 26af86c0cdd49..40cb86500f608 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -18,13 +18,13 @@ use std::cell::Cell; use std::iter; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::Diag; use rustc_hir::BodyOwnerKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; -use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_macros::extension; use rustc_middle::ty::fold::{TypeFoldable, fold_regions}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -65,6 +65,8 @@ pub(crate) struct UniversalRegions<'tcx> { /// The total number of universal region variables instantiated. num_universals: usize, + pub existential_external_regions: FxIndexSet, + /// The "defining" type for this function, with all universal /// regions instantiated. For a closure or coroutine, this is the /// closure type, but for a top-level function it's the `FnDef`. @@ -223,7 +225,7 @@ pub(crate) enum RegionClassification { /// /// If we are not analyzing a closure/coroutine/inline-const, /// there are no external lifetimes. - External, + External { is_existential: bool }, /// A **local** lifetime is one about which we know the full set /// of relevant constraints (that is, relationships to other named @@ -254,19 +256,22 @@ impl<'tcx> UniversalRegions<'tcx> { /// Given a reference to a closure type, extracts all the values /// from its free regions and returns a vector with them. This is /// used when the closure's creator checks that the - /// `ClosureRegionRequirements` are met. The requirements from - /// `ClosureRegionRequirements` are expressed in terms of + /// `ClosureRequirements` are met. The requirements from + /// `ClosureRequirements` are expressed in terms of /// `RegionVid` entries that map into the returned vector `V`: so - /// if the `ClosureRegionRequirements` contains something like + /// if the `ClosureRequirements` contains something like /// `'1: '2`, then the caller would impose the constraint that /// `V[1]: V[2]`. pub(crate) fn closure_mapping( - tcx: TyCtxt<'tcx>, + infcx: &InferCtxt<'tcx>, closure_args: GenericArgsRef<'tcx>, expected_num_vars: usize, + num_existential_external_vars: usize, closure_def_id: LocalDefId, ) -> IndexVec> { - let mut region_mapping = IndexVec::with_capacity(expected_num_vars); + let tcx = infcx.tcx; + let mut region_mapping = + IndexVec::with_capacity(expected_num_vars + num_existential_external_vars); region_mapping.push(tcx.lifetimes.re_static); tcx.for_each_free_region(&closure_args, |fr| { region_mapping.push(fr); @@ -282,12 +287,27 @@ impl<'tcx> UniversalRegions<'tcx> { "index vec had unexpected number of variables" ); + for _ in 0..num_existential_external_vars { + region_mapping.push( + infcx.next_nll_region_var(NllRegionVariableOrigin::Existential { + from_forall: false, + }), + ); + } + region_mapping } /// Returns `true` if `r` is a member of this set of universal regions. pub(crate) fn is_universal_region(&self, r: RegionVid) -> bool { - (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) + if (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index()) + || self.existential_external_regions.contains(&r) + { + true + } else { + // println!("{r:?} not contained in {self:?}"); TODO + false + } } /// Classifies `r` as a universal region, returning `None` if this @@ -297,9 +317,11 @@ impl<'tcx> UniversalRegions<'tcx> { if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) { Some(RegionClassification::Global) } else if (self.first_extern_index..self.first_local_index).contains(&index) { - Some(RegionClassification::External) + Some(RegionClassification::External { is_existential: false }) } else if (self.first_local_index..self.num_universals).contains(&index) { Some(RegionClassification::Local) + } else if self.existential_external_regions.contains(&r) { + Some(RegionClassification::External { is_existential: true }) } else { None } @@ -307,8 +329,10 @@ impl<'tcx> UniversalRegions<'tcx> { /// Returns an iterator over all the RegionVids corresponding to /// universally quantified free regions. - pub(crate) fn universal_regions_iter(&self) -> impl Iterator { - (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) + pub(crate) fn universal_regions_iter(&self) -> impl Iterator + '_ { + (FIRST_GLOBAL_INDEX..self.num_universals) + .map(RegionVid::from_usize) + .chain(self.existential_external_regions.iter().copied()) } /// Returns `true` if `r` is classified as a local region. @@ -562,6 +586,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { first_extern_index, first_local_index, num_universals, + existential_external_regions: Default::default(), defining_ty, unnormalized_output_ty: *unnormalized_output_ty, unnormalized_input_tys, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index db5da941f1e7b..1ed9d207b765c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -4,18 +4,19 @@ use std::cell::Cell; use std::fmt::{self, Debug}; use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::{Span, Symbol}; +use rustc_type_ir::fold::TypeFoldable; use smallvec::SmallVec; use super::{ConstValue, SourceInfo}; use crate::ty::fold::fold_regions; -use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; +use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt}; rustc_index::newtype_index! { #[derive(HashStable)] @@ -122,7 +123,7 @@ pub struct BorrowCheckResult<'tcx> { /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. pub concrete_opaque_types: FxIndexMap>, - pub closure_requirements: Option>, + pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[FieldIdx; 8]>, pub tainted_by_errors: Option, } @@ -183,7 +184,7 @@ pub struct ConstQualifs { /// can be extracted from its type and constrained to have the given /// outlives relationship. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ClosureRegionRequirements<'tcx> { +pub struct ClosureRequirements<'tcx> { /// The number of external regions defined on the closure. In our /// example above, it would be 3 -- one for `'static`, then `'1` /// and `'2`. This is just used for a sanity check later on, to @@ -191,9 +192,13 @@ pub struct ClosureRegionRequirements<'tcx> { /// matches. pub num_external_vids: usize, + pub num_existential_external_regions: usize, + /// Requirements between the various free regions defined in /// indices. pub outlives_requirements: Vec>, + + pub opaque_types: Vec, OpaqueHiddenType<'tcx>)>>, } /// Indicates an outlives-constraint between a type or between two @@ -201,10 +206,10 @@ pub struct ClosureRegionRequirements<'tcx> { #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct ClosureOutlivesRequirement<'tcx> { // This region or type ... - pub subject: ClosureOutlivesSubject<'tcx>, + pub subject: InClosureRequirement>, // ... must outlive this one. - pub outlived_free_region: ty::RegionVid, + pub outlived_free_region: InClosureRequirement>, // If not, report an error here ... pub blame_span: Span, @@ -291,39 +296,48 @@ pub enum ClosureOutlivesSubject<'tcx> { /// Subject is a type, typically a type parameter, but could also /// be a projection. Indicates a requirement like `T: 'a` being /// passed to the caller, where the type here is `T`. - Ty(ClosureOutlivesSubjectTy<'tcx>), + Ty(InClosureRequirement>), /// Subject is a free region from the closure. Indicates a requirement /// like `'a: 'b` being passed to the caller; the region here is `'a`. Region(ty::RegionVid), } -/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`]. -/// -/// This abstraction is necessary because the type may include `ReVar` regions, -/// which is what we use internally within NLL code, and they can't be used in -/// a query response. +/// Used for types in `ClosureOutlivesRequirements` which may refer to external +/// regions. This is necessary as they are represented using `ReVar` which must +/// not be used in a query response. /// /// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this /// type is not recognized as a binder for late-bound region. #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] -pub struct ClosureOutlivesSubjectTy<'tcx> { - inner: Ty<'tcx>, +pub struct InClosureRequirement { + inner: T, } -impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { +impl<'tcx, T: TypeFoldable>> InClosureRequirement { /// All regions of `ty` must be of kind `ReVar` and must represent /// universal regions *external* to the closure. - pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - let inner = fold_regions(tcx, ty, |r, depth| match r.kind() { + pub fn bind( + tcx: TyCtxt<'tcx>, + num_external_regions: usize, + existential_mapping: &FxIndexSet, + value: T, + ) -> Self { + let inner = fold_regions(tcx, value, |r, depth| match r.kind() { ty::ReVar(vid) => { + let index = if vid.index() < num_external_regions { + vid.index() + } else { + num_external_regions + existential_mapping.get_index_of(&vid).unwrap() + }; let br = ty::BoundRegion { - var: ty::BoundVar::new(vid.index()), + var: ty::BoundVar::new(index), kind: ty::BoundRegionKind::Anon, }; ty::Region::new_bound(tcx, depth, br) } - _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), + ty::ReError(_) => r, + _ => bug!("unexpected region in closure requirement: {r:?}"), }); Self { inner } @@ -333,12 +347,13 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { self, tcx: TyCtxt<'tcx>, mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>, - ) -> Ty<'tcx> { + ) -> T { fold_regions(tcx, self.inner, |r, depth| match r.kind() { ty::ReBound(debruijn, br) => { debug_assert_eq!(debruijn, depth); map(ty::RegionVid::new(br.var.index())) } + ty::ReError(_) => r, _ => bug!("unexpected region {r:?}"), }) } diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index cbb26b83c79cf..980191c0b60c9 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -114,9 +114,13 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }); + let pointee_ty = self.ty; + let ty = pointee_ty + .builtin_deref(true) + .or_else(|| Some(Ty::new_error(tcx, pointee_ty.error_reported().err()?))) + .unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", self) + }); PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {