diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 15b2a5ef2e213..a873e04756d06 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -24,7 +24,6 @@ use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_ use tracing::{debug, instrument}; use crate::MirBorrowckCtxt; -use crate::region_infer::values::RegionElement; use crate::session_diagnostics::{ HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError, }; @@ -49,11 +48,12 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } } + /// Report an error where an element erroneously made its way into `placeholder`. pub(crate) fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, - error_element: RegionElement, + error_element: Option, cause: ObligationCause<'tcx>, ) { match *self { @@ -153,10 +153,17 @@ pub(crate) trait TypeOpInfo<'tcx> { &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, - error_element: RegionElement, + error_element: Option, cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; + + // FIXME: this logic is convoluted and strange, and + // we should probably just use the placeholders we get + // as arguments! However, upstream error reporting code + // needs adaptations for that to work (this universe is + // neither the assigned one, nor the calculated one but + // some base-shifted one for some reason?). let base_universe = self.base_universe(); debug!(?base_universe); @@ -172,20 +179,16 @@ pub(crate) trait TypeOpInfo<'tcx> { ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound }, ); - let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) = - error_element - { - let adjusted_universe = - error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32()); + // FIXME: one day this should just be error_element, but see above about the adjusted universes. At that point, this method can probably be removed entirely. + let error_region = error_element.and_then(|e| { + let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32()); adjusted_universe.map(|adjusted| { ty::Region::new_placeholder( tcx, - ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound }, + ty::Placeholder { universe: adjusted.into(), bound: e.bound }, ) }) - } else { - None - }; + }); debug!(?placeholder_region); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 05826bea66bf8..75bc44e2bb688 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -29,7 +29,6 @@ use tracing::{debug, instrument, trace}; use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource}; use crate::nll::ConstraintDescription; -use crate::region_infer::values::RegionElement; use crate::region_infer::{BlameConstraint, TypeTest}; use crate::session_diagnostics::{ FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, @@ -104,15 +103,9 @@ pub(crate) enum RegionErrorKind<'tcx> { /// A generic bound failure for a type test (`T: 'a`). TypeTestError { type_test: TypeTest<'tcx> }, - /// Higher-ranked subtyping error. - BoundUniversalRegionError { - /// The placeholder free region. - longer_fr: RegionVid, - /// The region element that erroneously must be outlived by `longer_fr`. - error_element: RegionElement, - /// The placeholder region. - placeholder: ty::PlaceholderRegion, - }, + /// 'p outlives 'r, which does not hold. 'p is always a placeholder + /// and 'r is some other region. + PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid }, /// Any other lifetime error. RegionError { @@ -205,60 +198,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let tcx = self.infcx.tcx; // find generic associated types in the given region 'lower_bound' - let gat_id_and_generics = self + let scc = self.regioncx.constraint_sccs().scc(lower_bound); + let Some(gat_hir_id) = self .regioncx - .placeholders_contained_in(lower_bound) - .map(|placeholder| { - if let Some(id) = placeholder.bound.kind.get_id() - && let Some(placeholder_id) = id.as_local() - && let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id) - && let Some(generics_impl) = - tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics() - { - Some((gat_hir_id, generics_impl)) - } else { - None - } - }) - .collect::>(); - debug!(?gat_id_and_generics); + .placeholder_representative(scc) + .and_then(|placeholder| placeholder.bound.kind.get_id()) + .and_then(|id| id.as_local()) + .map(|local| self.infcx.tcx.local_def_id_to_hir_id(local)) + else { + return; + }; // Look for the where-bound which introduces the placeholder. // As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>` // and `T: for<'a> Trait`<'a>. let mut hrtb_bounds = vec![]; - gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| { - for pred in generics.predicates { - let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) = - pred.kind - else { - continue; - }; - if bound_generic_params - .iter() - .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) - .is_some() - { - for bound in *bounds { - hrtb_bounds.push(bound); - } - } else { - for bound in *bounds { - if let Trait(trait_bound) = bound { - if trait_bound - .bound_generic_params - .iter() - .rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) - .is_some() - { - hrtb_bounds.push(bound); - return; - } - } - } + + // FIXME(amandasystems) we can probably flatten this. + for pred in self + .infcx + .tcx + .parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id)) + .generics() + .map(|gen_impl| gen_impl.predicates) + .into_iter() + .flatten() + { + let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) = + pred.kind + else { + continue; + }; + if bound_generic_params + .iter() + .rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id) + .is_some() + { + for bound in *bounds { + hrtb_bounds.push(bound); } } - }); + } debug!(?hrtb_bounds); let mut suggestions = vec![]; @@ -361,28 +341,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - RegionErrorKind::BoundUniversalRegionError { + RegionErrorKind::PlaceholderOutlivesIllegalRegion { longer_fr, - placeholder, - error_element, + illegally_outlived_r, } => { - let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); - - // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let cause = self - .regioncx - .best_blame_constraint( - longer_fr, - NllRegionVariableOrigin::Placeholder(placeholder), - error_vid, - ) - .0 - .cause; - - let universe = placeholder.universe; - let universe_info = self.regioncx.universe_info(universe); - - universe_info.report_erroneous_element(self, placeholder, error_element, cause); + self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r) } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index d23ecf6c70796..4ebf969a794cd 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -1,6 +1,8 @@ //! Logic for lowering higher-kinded outlives constraints //! (with placeholders and universes) and turn them into regular //! outlives constraints. +use std::cmp; + use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::scc; @@ -13,8 +15,8 @@ use tracing::{debug, trace}; use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet}; use crate::consumers::OutlivesConstraint; -use crate::diagnostics::UniverseInfo; -use crate::region_infer::values::{LivenessValues, PlaceholderIndices}; +use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; +use crate::region_infer::values::LivenessValues; use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest}; use crate::ty::VarianceDiagInfo; use crate::type_check::free_region_relations::UniversalRegionRelations; @@ -22,17 +24,63 @@ use crate::type_check::{Locations, MirTypeckRegionConstraints}; use crate::universal_regions::UniversalRegions; use crate::{BorrowckInferCtxt, NllRegionVariableOrigin}; +pub(crate) trait RegionSccs { + fn representative(&self, scc: ConstraintSccIndex) -> RegionVid; + fn reachable_placeholders(&self, _scc: ConstraintSccIndex) -> Option { + None + } + /// The largest universe this SCC can name. It's the smallest + /// largest nameable universe of any reachable region, or + /// `max_nameable(r) = min (max_nameable(r') for r' reachable from r)` + fn max_nameable_universe(&self, _scc: ConstraintSccIndex) -> UniverseIndex { + UniverseIndex::ROOT + } + fn max_placeholder_universe_reached(&self, _scc: ConstraintSccIndex) -> UniverseIndex { + UniverseIndex::ROOT + } +} + +impl RegionSccs for IndexVec { + fn representative(&self, scc: ConstraintSccIndex) -> RegionVid { + self[scc].representative.rvid() + } + + fn reachable_placeholders(&self, scc: ConstraintSccIndex) -> Option { + self[scc].reachable_placeholders + } + + fn max_nameable_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { + // Note that this is stricter than it might need to be! + self[scc].min_max_nameable_universe + } + + fn max_placeholder_universe_reached(&self, scc: ConstraintSccIndex) -> UniverseIndex { + self[scc].reachable_placeholders.map(|p| p.max_universe.u).unwrap_or(UniverseIndex::ROOT) + } +} + +impl RegionSccs for IndexVec { + fn representative(&self, scc: ConstraintSccIndex) -> RegionVid { + self[scc].rvid() + } +} + +impl FromRegionDefinition for Representative { + fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { + Representative::new(rvid, definition) + } +} + /// A set of outlives constraints after rewriting to remove /// higher-kinded constraints. pub(crate) struct LoweredConstraints<'tcx> { pub(crate) constraint_sccs: Sccs, pub(crate) definitions: Frozen>>, - pub(crate) scc_annotations: IndexVec, + pub(crate) scc_annotations: Box, pub(crate) outlives_constraints: Frozen>, pub(crate) type_tests: Vec>, pub(crate) liveness_constraints: LivenessValues, pub(crate) universe_causes: FxIndexMap>, - pub(crate) placeholder_indices: PlaceholderIndices, } impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { @@ -41,78 +89,73 @@ impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { } } +trait FromRegionDefinition { + fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self; +} + /// A Visitor for SCC annotation construction. pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { pub(crate) scc_to_annotation: IndexVec, definitions: &'d IndexVec>, } - -impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { - fn new(&self, element: RegionVid) -> RegionTracker { - RegionTracker::new(element, &self.definitions[element]) +impl scc::Annotations + for SccAnnotations<'_, '_, A> +{ + fn new(&self, element: RegionVid) -> A { + A::new(element, &self.definitions[element]) } - fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { + fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: A) { let idx = self.scc_to_annotation.push(annotation); assert!(idx == scc); } - type Ann = RegionTracker; + type Ann = A; type SccIdx = ConstraintSccIndex; } #[derive(Copy, Debug, Clone, PartialEq, Eq)] -enum PlaceholderReachability { - /// This SCC reaches no placeholders. - NoPlaceholders, - /// This SCC reaches at least one placeholder. - Placeholders { - /// The largest-universed placeholder we can reach - max_universe: (UniverseIndex, RegionVid), - - /// The placeholder with the smallest ID - min_placeholder: RegionVid, - - /// The placeholder with the largest ID - max_placeholder: RegionVid, - }, +pub(crate) struct PlaceholderReachability { + /// The largest-universed placeholder we can reach + max_universe: RegionWithUniverse, + + /// The placeholder with the smallest ID + pub(crate) min_placeholder: RegionVid, + + /// The placeholder with the largest ID + pub(crate) max_placeholder: RegionVid, } impl PlaceholderReachability { /// Merge the reachable placeholders of two graph components. - fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability { - use PlaceholderReachability::*; - match (self, other) { - (NoPlaceholders, NoPlaceholders) => NoPlaceholders, - (NoPlaceholders, p @ Placeholders { .. }) - | (p @ Placeholders { .. }, NoPlaceholders) => p, - ( - Placeholders { - min_placeholder: min_pl, - max_placeholder: max_pl, - max_universe: max_u, - }, - Placeholders { min_placeholder, max_placeholder, max_universe }, - ) => Placeholders { - min_placeholder: min_pl.min(min_placeholder), - max_placeholder: max_pl.max(max_placeholder), - max_universe: max_u.max(max_universe), - }, - } + fn merge(&mut self, other: &PlaceholderReachability) { + self.max_universe = self.max_universe.max(other.max_universe); + self.min_placeholder = self.min_placeholder.min(other.min_placeholder); + self.max_placeholder = self.max_placeholder.max(other.max_placeholder); } +} + +/// A region with its universe, ordered fist by largest unverse, then +/// by smallest region (reverse region id order). +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +struct RegionWithUniverse { + u: UniverseIndex, + r: RegionVid, +} - fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> { - match self { - Self::NoPlaceholders => None, - Self::Placeholders { max_universe, .. } => Some(*max_universe), +impl Ord for RegionWithUniverse { + fn cmp(&self, other: &Self) -> cmp::Ordering { + if self.u.cmp(&other.u) == cmp::Ordering::Equal { + self.r.cmp(&other.r).reverse() + } else { + self.u.cmp(&other.u) } } +} - /// If we have reached placeholders, determine if they can - /// be named from this universe. - fn can_be_named_by(&self, from: UniverseIndex) -> bool { - self.max_universe() - .is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe)) +impl PartialOrd for RegionWithUniverse { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } @@ -120,82 +163,81 @@ impl PlaceholderReachability { /// the values of its elements. This annotates a single SCC. #[derive(Copy, Debug, Clone)] pub(crate) struct RegionTracker { - reachable_placeholders: PlaceholderReachability, + pub(crate) reachable_placeholders: Option, + + /// The smallest max nameable universe of all + /// regions reachable from this SCC. + min_max_nameable_universe: UniverseIndex, - /// The largest universe nameable from this SCC. - /// It is the smallest nameable universes of all - /// existential regions reachable from it. Small Rvids are preferred. - max_nameable_universe: (UniverseIndex, RegionVid), + /// The worst-nameable (highest univers'd) placeholder region in this SCC. + is_placeholder: Option, + + /// The worst-naming (min univers'd) existential region we reach. + worst_existential: Option<(UniverseIndex, RegionVid)>, /// The representative Region Variable Id for this SCC. pub(crate) representative: Representative, } -impl RegionTracker { - pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { - let reachable_placeholders = - if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) { - PlaceholderReachability::Placeholders { - max_universe: (definition.universe, rvid), +impl FromRegionDefinition for RegionTracker { + fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { + use NllRegionVariableOrigin::*; + + let min_max_nameable_universe = definition.universe; + let representative = Representative::new(rvid, definition); + let universe_and_rvid = RegionWithUniverse { r: rvid, u: definition.universe }; + + match definition.origin { + FreeRegion => Self { + reachable_placeholders: None, + min_max_nameable_universe, + is_placeholder: None, + worst_existential: None, + representative, + }, + Placeholder(_) => Self { + reachable_placeholders: Some(PlaceholderReachability { + max_universe: universe_and_rvid, min_placeholder: rvid, max_placeholder: rvid, - } - } else { - PlaceholderReachability::NoPlaceholders - }; - - Self { - reachable_placeholders, - max_nameable_universe: (definition.universe, rvid), - representative: Representative::new(rvid, definition), - } - } - - /// The largest universe this SCC can name. It's the smallest - /// largest nameable universe of any reachable region, or - /// `max_nameable(r) = min (max_nameable(r') for r' reachable from r)` - pub(crate) fn max_nameable_universe(self) -> UniverseIndex { - self.max_nameable_universe.0 - } - - pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex { - if let Some((universe, _)) = self.reachable_placeholders.max_universe() { - universe - } else { - UniverseIndex::ROOT + }), + min_max_nameable_universe, + is_placeholder: Some(universe_and_rvid), + worst_existential: None, + representative, + }, + Existential { .. } => Self { + reachable_placeholders: None, + min_max_nameable_universe, + is_placeholder: None, + worst_existential: Some((definition.universe, rvid)), + representative, + }, } } - - /// Determine if we can name all the placeholders in `other`. - pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool { - other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0) - } - - /// If this SCC reaches a placeholder it can't name, return it. - fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> { - self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| { - !self.max_nameable_universe().can_name(placeholder_universe) - }) - } } impl scc::Annotation for RegionTracker { - fn merge_scc(self, other: Self) -> Self { + fn update_scc(&mut self, other: &Self) { trace!("{:?} << {:?}", self.representative, other.representative); - - Self { - representative: self.representative.min(other.representative), - max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe), - reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders), - } + self.representative.update_scc(&other.representative); + self.is_placeholder = self.is_placeholder.max(other.is_placeholder); + self.update_reachable(other); // SCC membership implies reachability. } - fn merge_reached(self, other: Self) -> Self { - Self { - max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe), - reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders), - representative: self.representative, - } + #[inline(always)] + fn update_reachable(&mut self, other: &Self) { + self.worst_existential = self + .worst_existential + .xor(other.worst_existential) + .or_else(|| self.worst_existential.min(other.worst_existential)); + self.min_max_nameable_universe = + self.min_max_nameable_universe.min(other.min_max_nameable_universe); + match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) { + (None, None) | (Some(_), None) => (), + (None, Some(theirs)) => self.reachable_placeholders = Some(*theirs), + (Some(ours), Some(theirs)) => ours.merge(theirs), + }; } } @@ -228,7 +270,7 @@ pub(super) fn region_definitions<'tcx>( // Add external names from universal regions in fun function definitions. // FIXME: this two-step method is annoying, but I don't know how to avoid it. for (external_name, variable) in universal_regions.named_universal_regions_iter() { - debug!("region {:?} has external name {:?}", variable, external_name); + trace!("region {:?} has external name {:?}", variable, external_name); definitions[variable].external_name = Some(external_name); } (Frozen::freeze(definitions), has_placeholders) @@ -266,17 +308,17 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( constraints: MirTypeckRegionConstraints<'tcx>, universal_region_relations: &Frozen>, infcx: &BorrowckInferCtxt<'tcx>, + errors_buffer: &mut RegionErrors<'tcx>, ) -> LoweredConstraints<'tcx> { let universal_regions = &universal_region_relations.universal_regions; let (definitions, has_placeholders) = region_definitions(infcx, universal_regions); let MirTypeckRegionConstraints { - placeholder_indices, - placeholder_index_to_region: _, liveness_constraints, mut outlives_constraints, universe_causes, type_tests, + placeholder_to_region: _, } = constraints; let fr_static = universal_regions.fr_static; @@ -289,33 +331,40 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( ) }; - let mut scc_annotations = SccAnnotations::init(&definitions); - let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); - - // This code structure is a bit convoluted because it allows for a planned - // future change where the early return here has a different type of annotation - // that does much less work. if !has_placeholders { debug!("No placeholder regions found; skipping rewriting logic!"); + // We skip the extra logic and only record representatives. + let mut scc_annotations: SccAnnotations<'_, '_, Representative> = + SccAnnotations::init(&definitions); + let constraint_sccs = ConstraintSccs::new_with_annotation( + &outlives_constraints + .graph(definitions.len()) + .region_graph(&outlives_constraints, fr_static), + &mut scc_annotations, + ); + return LoweredConstraints { type_tests, constraint_sccs, - scc_annotations: scc_annotations.scc_to_annotation, + scc_annotations: Box::new(scc_annotations.scc_to_annotation), definitions, outlives_constraints: Frozen::freeze(outlives_constraints), liveness_constraints, universe_causes, - placeholder_indices, }; } debug!("Placeholders present; activating placeholder handling logic!"); + let mut scc_annotations = SccAnnotations::init(&definitions); + let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); let added_constraints = rewrite_placeholder_outlives( &constraint_sccs, &scc_annotations, fr_static, &mut outlives_constraints, + errors_buffer, + &definitions, ); let (constraint_sccs, scc_annotations) = if added_constraints { @@ -335,12 +384,11 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( LoweredConstraints { constraint_sccs, definitions, - scc_annotations, + scc_annotations: Box::new(scc_annotations), outlives_constraints: Frozen::freeze(outlives_constraints), type_tests, liveness_constraints, universe_causes, - placeholder_indices, } } @@ -349,6 +397,8 @@ pub(crate) fn rewrite_placeholder_outlives<'tcx>( annotations: &SccAnnotations<'_, '_, RegionTracker>, fr_static: RegionVid, outlives_constraints: &mut OutlivesConstraintSet<'tcx>, + errors_buffer: &mut RegionErrors<'tcx>, + definitions: &IndexVec>, ) -> bool { // Changed to `true` if we added any constraints and need to // recompute SCCs. @@ -366,47 +416,91 @@ pub(crate) fn rewrite_placeholder_outlives<'tcx>( let annotation = annotations[scc]; - let Some((max_u, max_u_rvid)) = annotation.unnameable_placeholder() else { + let Some(PlaceholderReachability { min_placeholder, max_placeholder, max_universe }) = + annotation.reachable_placeholders + else { + trace!("No placeholders reached from {scc:?}"); continue; }; + if let Some(us) = annotation.is_placeholder + && min_placeholder != max_placeholder + { + let illegally_outlived_r = + if min_placeholder == us.r { max_placeholder } else { min_placeholder }; + debug!("Placeholder {us:?} outlives placeholder {illegally_outlived_r:?}"); + errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion { + longer_fr: us.r, + illegally_outlived_r, + }); + // FIXME: investigate if it's an actual improvement to drop early here + // and stop reporting errors for this SCC since we are guaranteed to + // have at least one. + } + + if annotation.min_max_nameable_universe.can_name(max_universe.u) { + trace!("All placeholders nameable from {scc:?}!"); + continue; + } + debug!( - "Placeholder universe {max_u:?} is too large for its SCC, represented by {:?}", + "Placeholder {max_universe:?} unnameable from {scc:?} represented by {:?}", annotation.representative ); - // We only add one `r: 'static` constraint per SCC, where `r` is the SCC representative. - // That constraint is annotated with some placeholder `unnameable` where - // `unnameable` is unnameable from `r` and there is a path in the constraint graph - // between them. - // - // There is one exception; if some other region in this SCC can't name `'r`, then - // we pick the region with the smallest universe in the SCC, so that a path can - // always start in `'r` to find a motivation that isn't cyclic. - let blame_to = if annotation.representative.rvid() == max_u_rvid { - // Assertion: the region that lowered our universe is an existential one and we are a placeholder! - - // The SCC's representative is not nameable from some region - // that ends up in the SCC. - let small_universed_rvid = annotation.max_nameable_universe.1; - debug!( - "{small_universed_rvid:?} lowered our universe to {:?}", - annotation.max_nameable_universe() - ); - small_universed_rvid - } else { - // `max_u_rvid` is not nameable by the SCC's representative. - max_u_rvid + // Figure out if we had our universe lowered by an existential + // that cannot name us, a placeholder. This is an error. + if let Some((ex_u, ex_r)) = annotation.worst_existential + && let Some(pl) = annotation.is_placeholder + && ex_u.cannot_name(pl.u) + { + debug!("{pl:?} outlives existential {ex_r:?} that cannot name it!"); + // Prefer the representative region if it's also unnameable. + let longer_fr = if let Representative::Placeholder(p) = annotation.representative + && ex_u.cannot_name(definitions[p].universe) + { + p + } else { + pl.r + }; + errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion { + longer_fr, + illegally_outlived_r: ex_r, + }); + // FIXME: we could `continue` here since there is no point in adding + // 'r: 'static for this SCC now that it's already outlived an + // existential it shouldn't, but we do anyway for compatibility with + // earlier versions' output. }; + let representative_rvid = annotation.representative.rvid(); + + if representative_rvid == max_universe.r { + assert!(matches!(annotation.representative, Representative::Placeholder(_))); + // The unnameable placeholder *is* the representative. + // If this SCC is represented by a placeholder `p` which cannot be named, + // from its own SCC, `p` must have at some point reached a/an: + // - existential region that could not name it (the `if` above) + // - free region that lowered its universe (will flag an error in region + // inference since `p` isn't empty) + // - another placeholder (will flag an error above, but will reach here). + // + // To avoid adding the invalid constraint "`'p: 'static` due to `'p` being + // unnameable from the SCC represented by `'p`", we nope out early here + // at no risk of soundness issues since at this point all paths lead + // to an error. + continue; + } + // This SCC outlives a placeholder it can't name and must outlive 'static. + // FIXME: if we can extract a useful blame span here, future error // reporting and constraint search can be simplified. added_constraints = true; outlives_constraints.push(OutlivesConstraint { - sup: annotation.representative.rvid(), + sup: representative_rvid, sub: fr_static, - category: ConstraintCategory::OutlivesUnnameablePlaceholder(blame_to), + category: ConstraintCategory::OutlivesUnnameablePlaceholder(max_universe.r), locations: Locations::All(rustc_span::DUMMY_SP), span: rustc_span::DUMMY_SP, variance_info: VarianceDiagInfo::None, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 20411fcc16fbb..b52bf212eb503 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2691,6 +2691,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) } } + + /// Report that `longer_fr: error_vid`, which doesn't hold, + /// where `longer_fr` is a placeholder. + fn report_erroneous_rvid_reaches_placeholder( + &mut self, + longer_fr: RegionVid, + error_vid: RegionVid, + ) { + use NllRegionVariableOrigin::*; + + let origin_longer = self.regioncx.definitions[longer_fr].origin; + + // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. + let cause = + self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid).0.cause; + + let Placeholder(placeholder) = origin_longer else { + bug!("Expected {longer_fr:?} to come from placeholder!"); + }; + + // FIXME: Is throwing away the existential region really the best here? + let error_region = match self.regioncx.definitions[error_vid].origin { + FreeRegion | Existential { .. } => None, + Placeholder(other_placeholder) => Some(other_placeholder), + }; + + // FIXME these methods should have better names, and also probably not be this generic. + // FIXME note that we *throw away* the error element here! We probably want to + // thread it through the computation further down and use it, but there currently isn't + // anything there to receive it. + self.regioncx.universe_info(placeholder.universe).report_erroneous_element( + self, + placeholder, + error_region, + cause, + ); + } } /// The degree of overlap between 2 places for borrow-checking. diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 5537d90e297aa..a07d819495d2a 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -95,6 +95,7 @@ pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>( constraints.clone(), &universal_region_relations, infcx, + &mut RegionErrors::new(infcx.tcx), ); let mut regioncx = RegionInferenceContext::new( &infcx, @@ -126,12 +127,17 @@ pub(crate) fn compute_regions<'tcx>( let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output()) || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); + let mut placeholder_errors = RegionErrors::new(infcx.tcx); + let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints( constraints, &universal_region_relations, infcx, + &mut placeholder_errors, ); + debug!("Placeholder errors: {placeholder_errors:?}"); + // If requested, emit legacy polonius facts. polonius::legacy::emit_facts( &mut polonius_facts, @@ -179,9 +185,18 @@ pub(crate) fn compute_regions<'tcx>( }); // Solve the region constraints. - let (closure_region_requirements, nll_errors) = + let (closure_region_requirements, region_inference_errors) = regioncx.solve(infcx, body, polonius_output.clone()); + let nll_errors = if region_inference_errors.is_empty() { + // Only flag the higher-kinded bounds errors if there are no borrowck errors. + debug!("No region inference errors, using placeholder errors: {placeholder_errors:?}"); + placeholder_errors + } else { + debug!("Errors already reported, skipping these: {placeholder_errors:?}"); + region_inference_errors + }; + NllOutput { regioncx, polonius_input: polonius_facts.map(Box::new), diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e98c60e633805..d9c32641483e3 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::graph::scc::{self, Sccs}; use rustc_errors::Diag; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::IndexVec; @@ -26,7 +26,7 @@ use crate::constraints::graph::NormalConstraintGraph; use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet}; use crate::dataflow::BorrowIndex; use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo}; -use crate::handle_placeholders::{LoweredConstraints, RegionTracker}; +use crate::handle_placeholders::{LoweredConstraints, RegionSccs, RegionTracker}; use crate::polonius::LiveLoans; use crate::polonius::legacy::PoloniusOutput; use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex}; @@ -74,6 +74,14 @@ impl Representative { } } +impl scc::Annotation for Representative { + fn update_scc(&mut self, other: &Self) { + *self = (*self).min(*other); + } + + fn update_reachable(&mut self, _other: &Self) {} +} + pub(crate) type ConstraintSccs = Sccs; pub struct RegionInferenceContext<'tcx> { @@ -102,7 +110,7 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: ConstraintSccs, - scc_annotations: IndexVec, + scc_annotations: Box, /// Map universe indexes to information on why we created it. universe_causes: FxIndexMap>, @@ -303,14 +311,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { outlives_constraints, scc_annotations, type_tests, - liveness_constraints, + mut liveness_constraints, universe_causes, - placeholder_indices, } = lowered_constraints; debug!("universal_regions: {:#?}", universal_region_relations.universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); - debug!("placeholder_indices: {:#?}", placeholder_indices); debug!("type tests: {:#?}", type_tests); let constraint_graph = Frozen::freeze(outlives_constraints.graph(definitions.len())); @@ -319,15 +325,29 @@ 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()); for region in liveness_constraints.regions() { let scc = constraint_sccs.scc(region); scc_values.merge_liveness(scc, region, &liveness_constraints); } - let mut result = Self { + for variable in definitions.indices() { + if let NllRegionVariableOrigin::FreeRegion = definitions[variable].origin { + // For each free, universally quantified region X: + + let scc = constraint_sccs.scc(variable); + + // Add all nodes in the CFG to liveness constraints + liveness_constraints.add_all_points(variable); + scc_values.add_all_points(scc); + + // Add `end(X)` into the set for X. + scc_values.add_element(scc, variable); + } + } + + Self { definitions, liveness_constraints, constraints: outlives_constraints, @@ -338,90 +358,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_values, type_tests, universal_region_relations, - }; - - result.init_free_and_bound_regions(); - - result - } - - /// Initializes the region variables for each universally - /// quantified region (lifetime parameter). The first N variables - /// always correspond to the regions appearing in the function - /// signature (both named and anonymous) and where-clauses. This - /// function iterates over those regions and initializes them with - /// minimum values. - /// - /// For example: - /// ```ignore (illustrative) - /// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ } - /// ``` - /// would initialize two variables like so: - /// ```ignore (illustrative) - /// R0 = { CFG, R0 } // 'a - /// R1 = { CFG, R0, R1 } // 'b - /// ``` - /// Here, R0 represents `'a`, and it contains (a) the entire CFG - /// and (b) any universally quantified regions that it outlives, - /// which in this case is just itself. R1 (`'b`) in contrast also - /// outlives `'a` and hence contains R0 and R1. - /// - /// This bit of logic also handles invalid universe relations - /// for higher-kinded types. - /// - /// We Walk each SCC `A` and `B` such that `A: B` - /// and ensure that universe(A) can see universe(B). - /// - /// This serves to enforce the 'empty/placeholder' hierarchy - /// (described in more detail on `RegionKind`): - /// - /// ```ignore (illustrative) - /// static -----+ - /// | | - /// empty(U0) placeholder(U1) - /// | / - /// empty(U1) - /// ``` - /// - /// In particular, imagine we have variables R0 in U0 and R1 - /// created in U1, and constraints like this; - /// - /// ```ignore (illustrative) - /// R1: !1 // R1 outlives the placeholder in U1 - /// R1: R0 // R1 outlives R0 - /// ``` - /// - /// Here, we wish for R1 to be `'static`, because it - /// cannot outlive `placeholder(U1)` and `empty(U0)` any other way. - /// - /// Thanks to this loop, what happens is that the `R1: R0` - /// constraint has lowered the universe of `R1` to `U0`, which in turn - /// means that the `R1: !1` constraint here will cause - /// `R1` to become `'static`. - fn init_free_and_bound_regions(&mut self) { - for variable in self.definitions.indices() { - let scc = self.constraint_sccs.scc(variable); - - match self.definitions[variable].origin { - NllRegionVariableOrigin::FreeRegion => { - // For each free, universally quantified region X: - - // Add all nodes in the CFG to liveness constraints - self.liveness_constraints.add_all_points(variable); - self.scc_values.add_all_points(scc); - - // Add `end(X)` into the set for X. - self.scc_values.add_element(scc, variable); - } - - NllRegionVariableOrigin::Placeholder(placeholder) => { - self.scc_values.add_element(scc, placeholder); - } - - NllRegionVariableOrigin::Existential { .. } => { - // For existential, regions, nothing to do. - } - } } } @@ -478,14 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_values.region_value_str(scc) } - pub(crate) fn placeholders_contained_in( - &self, - r: RegionVid, - ) -> impl Iterator { - let scc = self.constraint_sccs.scc(r); - self.scc_values.placeholders_contained_in(scc) - } - /// Performs region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. @@ -579,7 +507,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_a: ConstraintSccIndex, scc_b: ConstraintSccIndex, ) -> bool { - self.scc_annotations[scc_a].can_name_all_placeholders(self.scc_annotations[scc_b]) + self.scc_annotations + .max_nameable_universe(scc_a) + .can_name(self.scc_annotations.max_placeholder_universe_reached(scc_b)) } /// Once regions have been propagated, this method is used to see @@ -691,8 +621,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // It doesn't matter *what* universe because the promoted `T` will // always be in the root universe. - if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() { - debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p); + if !self.scc_annotations.max_placeholder_universe_reached(r_scc).is_root() { + debug!("encountered placeholder in higher universe, requiring 'static"); let static_r = self.universal_regions().fr_static; propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject, @@ -1169,7 +1099,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The largest universe of any region nameable from this SCC. fn max_nameable_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.scc_annotations[scc].max_nameable_universe() + self.scc_annotations.max_nameable_universe(scc) } /// Checks the final value for the free region `fr` to see if it @@ -1322,16 +1252,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If we have some bound universal region `'a`, then the only // elements it can contain is itself -- we don't know anything // else about it! - if let Some(error_element) = self - .scc_values - .elements_contained_in(longer_fr_scc) - .find(|e| *e != RegionElement::PlaceholderRegion(placeholder)) - { + if let Some(error_element) = self.scc_values.elements_contained_in(longer_fr_scc).next() { // Stop after the first error, it gets too noisy otherwise, and does not provide more information. - errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { + let illegally_outlived_r = match error_element { + RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), + RegionElement::RootUniversalRegion(r) => r, + }; + errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion { longer_fr, - error_element, - placeholder, + illegally_outlived_r, }); } else { debug!("check_bound_universal_region: all bounds satisfied"); @@ -1519,29 +1448,40 @@ impl<'tcx> RegionInferenceContext<'tcx> { }, true).unwrap().1 } - /// Get the region outlived by `longer_fr` and live at `element`. - pub(crate) fn region_from_element( + /// Get the region definition of `r`. + pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { + &self.definitions[r] + } + + /// If the representative of an SCC is a placeholder, return + /// its originating `PlaceholderRegion`. + pub(crate) fn placeholder_representative( &self, - longer_fr: RegionVid, - element: &RegionElement, - ) -> RegionVid { - match *element { - RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l), - RegionElement::RootUniversalRegion(r) => r, - RegionElement::PlaceholderRegion(error_placeholder) => self - .definitions - .iter_enumerated() - .find_map(|(r, definition)| match definition.origin { - NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), - _ => None, - }) - .unwrap(), + scc: ConstraintSccIndex, + ) -> Option { + if let NllRegionVariableOrigin::Placeholder(p) = + self.definitions[self.scc_annotations.representative(scc)].origin + { + Some(p) + } else { + None } } - /// Get the region definition of `r`. - pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> { - &self.definitions[r] + /// If this SCC contains precisely one placeholder, return it. + pub(crate) fn reaches_single_placeholder( + &self, + scc: ConstraintSccIndex, + ) -> Option { + let ps = self.scc_annotations.reachable_placeholders(scc)?; + + if let NllRegionVariableOrigin::Placeholder(p) = self.definitions[ps.min_placeholder].origin + && ps.min_placeholder == ps.max_placeholder + { + Some(p) + } else { + None + } } /// Check if the SCC of `r` contains `upper`. @@ -1567,7 +1507,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { from_region_origin: NllRegionVariableOrigin, to_region: RegionVid, ) -> (BlameConstraint<'tcx>, Vec>) { - assert!(from_region != to_region, "Trying to blame a region for itself!"); + if from_region == to_region { + bug!("Trying to blame {from_region:?} for itself!"); + } let path = self.constraint_path_between_regions(from_region, to_region).unwrap(); @@ -1841,7 +1783,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// they *must* be equal (though not having the same repr does not /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { - self.scc_annotations[scc].representative.rvid() + self.scc_annotations.representative(scc) } pub(crate) fn liveness_constraints(&self) -> &LivenessValues { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 0c4a82f3d2f36..f48846ef6a6fe 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -618,15 +618,17 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Special handling of higher-ranked regions. if !self.max_nameable_universe(scc).is_root() { - match self.scc_values.placeholders_contained_in(scc).enumerate().last() { + // FIXME: consider if `self.placeholder_representative(scc)` is enough here. + // That will simplify the logic quite a bit, but won't work if the placeholder + // isn't *in* `scc` but rather was *reached from* `scc`, presumably because + // `scc` is some transient boring region that's essentially a placeholder + // under a different name. + return match self.reaches_single_placeholder(scc) { // If the region contains a single placeholder then they're equal. - Some((0, placeholder)) => { - return ty::Region::new_placeholder(tcx, placeholder); - } - + Some(placeholder) => ty::Region::new_placeholder(tcx, placeholder), // Fallback: this will produce a cryptic error message. - _ => return region, - } + _ => region, + }; } // Find something that we can name diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs index 90b15cbdd2cc8..9fd2c45fcb072 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs @@ -8,7 +8,8 @@ use rustc_mir_dataflow::points::DenseLocationMap; use crate::BorrowckInferCtxt; use crate::constraints::ConstraintSccIndex; -use crate::handle_placeholders::{SccAnnotations, region_definitions}; +use crate::diagnostics::RegionErrors; +use crate::handle_placeholders::{RegionSccs, SccAnnotations, region_definitions}; use crate::region_infer::reverse_sccs::ReverseSccGraph; use crate::region_infer::values::RegionValues; use crate::region_infer::{ @@ -64,6 +65,8 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { &scc_annotations, universal_regions.fr_static, &mut outlives_constraints, + &mut RegionErrors::new(infcx.tcx), + &definitions, ); if added_constraints { @@ -74,10 +77,8 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { let scc_annotations = scc_annotations.scc_to_annotation; // Unlike the `RegionInferenceContext`, we only care about free regions - // and fully ignore liveness and placeholders. - let placeholder_indices = Default::default(); - let mut scc_values = - RegionValues::new(location_map, universal_regions.len(), placeholder_indices); + // and fully ignore liveness. + let mut scc_values = RegionValues::new(location_map, universal_regions.len()); for variable in definitions.indices() { let scc = constraint_sccs.scc(variable); match definitions[variable].origin { @@ -109,7 +110,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { &self, scc: ConstraintSccIndex, ) -> UniverseIndex { - self.scc_annotations[scc].max_placeholder_universe_reached() + self.scc_annotations.max_placeholder_universe_reached(scc) } pub(super) fn universal_regions(&self) -> &UniversalRegions<'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index eb611fa34757f..8fd58a81c35ea 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,24 +1,18 @@ use std::fmt::Debug; use std::rc::Rc; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_index::Idx; use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::{IntervalSet, SparseIntervalMatrix}; use rustc_middle::mir::{BasicBlock, Location}; -use rustc_middle::ty::{self, RegionVid}; +use rustc_middle::ty::RegionVid; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; use tracing::debug; use crate::BorrowIndex; use crate::polonius::LiveLoans; -rustc_index::newtype_index! { - /// A single integer representing a `ty::Placeholder`. - #[debug_format = "PlaceholderIndex({})"] - pub(crate) struct PlaceholderIndex {} -} - /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. #[derive(Debug, Clone, PartialEq)] @@ -29,10 +23,6 @@ pub(crate) enum RegionElement { /// A universally quantified region from the root universe (e.g., /// a lifetime parameter). RootUniversalRegion(RegionVid), - - /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` - /// type). - PlaceholderRegion(ty::PlaceholderRegion), } /// Records the CFG locations where each region is live. When we initially compute liveness, we use @@ -191,38 +181,6 @@ impl LivenessValues { } } -/// Maps from `ty::PlaceholderRegion` values that are used in the rest of -/// rustc to the internal `PlaceholderIndex` values that are used in -/// NLL. -#[derive(Debug, Default)] -#[derive(Clone)] // FIXME(#146079) -pub(crate) struct PlaceholderIndices { - indices: FxIndexSet, -} - -impl PlaceholderIndices { - /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion` - pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - let (index, _) = self.indices.insert_full(placeholder); - index.into() - } - - pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { - self.indices.get_index_of(&placeholder).unwrap().into() - } - - pub(crate) fn lookup_placeholder( - &self, - placeholder: PlaceholderIndex, - ) -> ty::PlaceholderRegion { - self.indices[placeholder.index()] - } - - pub(crate) fn len(&self) -> usize { - self.indices.len() - } -} - /// Stores the full values for a set of regions (in contrast to /// `LivenessValues`, which only stores those points in the where a /// region is live). The full value for a region may contain points in @@ -243,32 +201,20 @@ impl PlaceholderIndices { /// it would also contain various points from within the function. pub(crate) struct RegionValues { location_map: Rc, - placeholder_indices: PlaceholderIndices, points: SparseIntervalMatrix, free_regions: SparseBitMatrix, - - /// Placeholders represent bound regions -- so something like `'a` - /// in `for<'a> fn(&'a u32)`. - placeholders: SparseBitMatrix, } impl RegionValues { /// Creates a new set of "region values" that tracks causal information. /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. - pub(crate) fn new( - location_map: Rc, - num_universal_regions: usize, - placeholder_indices: PlaceholderIndices, - ) -> Self { + pub(crate) fn new(location_map: Rc, num_universal_regions: usize) -> Self { let num_points = location_map.num_points(); - let num_placeholders = placeholder_indices.len(); Self { location_map, points: SparseIntervalMatrix::new(num_points), - placeholder_indices, free_regions: SparseBitMatrix::new(num_universal_regions), - placeholders: SparseBitMatrix::new(num_placeholders), } } @@ -287,9 +233,7 @@ impl RegionValues { /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to: /// r_from`). pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool { - self.points.union_rows(r_from, r_to) - | self.free_regions.union_rows(r_from, r_to) - | self.placeholders.union_rows(r_from, r_to) + self.points.union_rows(r_from, r_to) | self.free_regions.union_rows(r_from, r_to) } /// Returns `true` if the region `r` contains the given element. @@ -355,29 +299,11 @@ impl RegionValues { self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) } - /// Returns all the elements contained in a given region's value. - pub(crate) fn placeholders_contained_in( - &self, - r: N, - ) -> impl Iterator { - self.placeholders - .row(r) - .into_iter() - .flat_map(|set| set.iter()) - .map(move |p| self.placeholder_indices.lookup_placeholder(p)) - } - /// Returns all the elements contained in a given region's value. pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator { - let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); - - let free_regions_iter = - self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion); - - let placeholder_universes_iter = - self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion); - - points_iter.chain(free_regions_iter).chain(placeholder_universes_iter) + self.locations_outlived_by(r) + .map(RegionElement::Location) + .chain(self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion)) } /// Returns a "pretty" string value of the region. Meant for debugging. @@ -414,18 +340,6 @@ impl ToElementIndex for RegionVid { } } -impl ToElementIndex for ty::PlaceholderRegion { - fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.insert(row, index) - } - - fn contained_in_row(self, values: &RegionValues, row: N) -> bool { - let index = values.placeholder_indices.lookup_index(self); - values.placeholders.contains(row, index) - } -} - /// For debugging purposes, returns a pretty-printed string of the given points. pub(crate) fn pretty_print_points( location_map: &DenseLocationMap, @@ -485,17 +399,6 @@ fn pretty_print_region_elements(elements: impl IntoIterator { - if let Some((location1, location2)) = open_location { - push_sep(&mut result); - push_location_range(&mut result, location1, location2); - open_location = None; - } - - push_sep(&mut result); - result.push_str(&format!("{placeholder:?}")); - } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5f86e8646c03f..b4685d641565c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -5,13 +5,13 @@ use std::{fmt, iter, mem}; use rustc_abi::FieldIdx; use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexSlice; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; @@ -45,7 +45,7 @@ use crate::diagnostics::UniverseInfo; use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; use crate::polonius::{PoloniusContext, PoloniusLivenessContext}; use crate::region_infer::TypeTest; -use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; +use crate::region_infer::values::LivenessValues; use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; @@ -108,12 +108,11 @@ pub(crate) fn type_check<'tcx>( location_map: Rc, ) -> MirTypeckResults<'tcx> { let mut constraints = MirTypeckRegionConstraints { - placeholder_indices: PlaceholderIndices::default(), - placeholder_index_to_region: IndexVec::default(), liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&location_map)), outlives_constraints: OutlivesConstraintSet::default(), type_tests: Vec::default(), universe_causes: FxIndexMap::default(), + placeholder_to_region: Default::default(), }; let CreateResult { @@ -253,20 +252,6 @@ pub(crate) struct MirTypeckResults<'tcx> { /// program to be considered well-typed. #[derive(Clone)] // FIXME(#146079) pub(crate) struct MirTypeckRegionConstraints<'tcx> { - /// Maps from a `ty::Placeholder` to the corresponding - /// `PlaceholderIndex` bit that we will use for it. - /// - /// To keep everything in sync, do not insert this set - /// directly. Instead, use the `placeholder_region` helper. - pub(crate) placeholder_indices: PlaceholderIndices, - - /// Each time we add a placeholder to `placeholder_indices`, we - /// also create a corresponding "representative" region vid for - /// that wraps it. This vector tracks those. This way, when we - /// convert the same `ty::RePlaceholder(p)` twice, we can map to - /// the same underlying `RegionVid`. - pub(crate) placeholder_index_to_region: IndexVec>, - /// In general, the type-checker is not responsible for enforcing /// liveness constraints; this job falls to the region inferencer, /// which performs a liveness analysis. However, in some limited @@ -281,6 +266,11 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { pub(crate) universe_causes: FxIndexMap>, pub(crate) type_tests: Vec>, + + /// For each placeholder we create a corresponding representative region vid. + /// This map tracks those. This way, when we convert the same `ty::RePlaceholder(p)` + /// twice, we can map to the same underlying `RegionVid`. + pub(crate) placeholder_to_region: FxHashMap>, } impl<'tcx> MirTypeckRegionConstraints<'tcx> { @@ -291,16 +281,10 @@ impl<'tcx> MirTypeckRegionConstraints<'tcx> { infcx: &InferCtxt<'tcx>, placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { - let placeholder_index = self.placeholder_indices.insert(placeholder); - match self.placeholder_index_to_region.get(placeholder_index) { - Some(&v) => v, - None => { - let origin = NllRegionVariableOrigin::Placeholder(placeholder); - let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); - self.placeholder_index_to_region.push(region); - region - } - } + *self.placeholder_to_region.entry(placeholder).or_insert_with(|| { + let origin = NllRegionVariableOrigin::Placeholder(placeholder); + infcx.next_nll_region_var_in_universe(origin, placeholder.universe) + }) } } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 1882e6e835a4e..33b5cddf425a5 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -27,26 +27,18 @@ mod tests; /// the max/min element of the SCC, or all of the above. /// /// Concretely, the both merge operations must commute, e.g. where `merge` -/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)` +/// is `update_scc` and `update_reached`: `a.merge(b) == b.merge(a)` /// /// In general, what you want is probably always min/max according /// to some ordering, potentially with side constraints (min x such /// that P holds). pub trait Annotation: Debug + Copy { /// Merge two existing annotations into one during - /// path compression.o - fn merge_scc(self, other: Self) -> Self; + /// path compression. + fn update_scc(&mut self, other: &Self); /// Merge a successor into this annotation. - fn merge_reached(self, other: Self) -> Self; - - fn update_scc(&mut self, other: Self) { - *self = self.merge_scc(other) - } - - fn update_reachable(&mut self, other: Self) { - *self = self.merge_reached(other) - } + fn update_reachable(&mut self, other: &Self); } /// An accumulator for annotations. @@ -70,12 +62,8 @@ impl Annotations for NoAnnotations { /// The empty annotation, which does nothing. impl Annotation for () { - fn merge_reached(self, _other: Self) -> Self { - () - } - fn merge_scc(self, _other: Self) -> Self { - () - } + fn update_reachable(&mut self, _other: &Self) {} + fn update_scc(&mut self, _other: &Self) {} } /// Strongly connected components (SCC) of a graph. The type `N` is @@ -614,7 +602,7 @@ where *min_depth = successor_min_depth; *min_cycle_root = successor_node; } - current_component_annotation.update_scc(successor_annotation); + current_component_annotation.update_scc(&successor_annotation); } // The starting node `node` is succeeded by a fully identified SCC // which is now added to the set under `scc_index`. @@ -629,7 +617,7 @@ where // the `successors_stack` for later. trace!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); - current_component_annotation.update_reachable(successor_annotation); + current_component_annotation.update_reachable(&successor_annotation); } // `node` has no more (direct) successors; search recursively. None => { diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 8f04baf51f355..4626861c3e00b 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -32,12 +32,12 @@ impl Maxes { } impl Annotation for MaxReached { - fn merge_scc(self, other: Self) -> Self { - Self(std::cmp::max(other.0, self.0)) + fn update_scc(&mut self, other: &Self) { + self.0 = self.0.max(other.0); } - fn merge_reached(self, other: Self) -> Self { - Self(std::cmp::max(other.0, self.0)) + fn update_reachable(&mut self, other: &Self) { + self.0 = self.0.max(other.0); } } @@ -75,13 +75,12 @@ impl Annotations for MinMaxes { } impl Annotation for MinMaxIn { - fn merge_scc(self, other: Self) -> Self { - Self { min: std::cmp::min(self.min, other.min), max: std::cmp::max(self.max, other.max) } + fn update_scc(&mut self, other: &Self) { + self.min = self.min.min(other.min); + self.max = self.max.max(other.max); } - fn merge_reached(self, _other: Self) -> Self { - self - } + fn update_reachable(&mut self, _other: &Self) {} } #[test] diff --git a/tests/ui/associated-types/associated-types-eq-hr.stderr b/tests/ui/associated-types/associated-types-eq-hr.stderr index 3a70189dd9f94..68a2cbaac4756 100644 --- a/tests/ui/associated-types/associated-types-eq-hr.stderr +++ b/tests/ui/associated-types/associated-types-eq-hr.stderr @@ -61,26 +61,6 @@ LL | tuple_one::(); = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `TheTrait` is not general enough - --> $DIR/associated-types-eq-hr.rs:96:5 - | -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough - | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `TheTrait` is not general enough - --> $DIR/associated-types-eq-hr.rs:96:5 - | -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough - | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:104:5 | @@ -90,16 +70,6 @@ LL | tuple_two::(); = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error: implementation of `TheTrait` is not general enough - --> $DIR/associated-types-eq-hr.rs:104:5 - | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough - | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0308]: mismatched types --> $DIR/associated-types-eq-hr.rs:104:5 | @@ -114,21 +84,6 @@ note: the lifetime requirement is introduced here LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, | ^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/associated-types-eq-hr.rs:104:5 - | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected reference `&'x _` - found reference `&'y _` -note: the lifetime requirement is introduced here - --> $DIR/associated-types-eq-hr.rs:66:53 - | -LL | T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>, - | ^^^^^^^^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: implementation of `TheTrait` is not general enough --> $DIR/associated-types-eq-hr.rs:116:5 | @@ -138,17 +93,7 @@ LL | tuple_four::(); = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error: implementation of `TheTrait` is not general enough - --> $DIR/associated-types-eq-hr.rs:116:5 - | -LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough - | - = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0271, E0308. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr index d5560bf892032..72657c837b37a 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.no_assumptions.stderr @@ -9,17 +9,5 @@ LL | | }); = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` -error: implementation of `FnOnce` is not general enough - --> $DIR/drop-tracking-unresolved-typeck-results.rs:102:5 - | -LL | / send(async { -LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await -LL | | }); - | |______^ implementation of `FnOnce` is not general enough - | - = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr index b298a3bf2153a..e38735faab4b2 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-1.no_assumptions.stderr @@ -15,24 +15,6 @@ LL | | } = note: no two async blocks, even if identical, have the same type = help: consider pinning your async block and casting it to a trait object -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-1.rs:37:5 - | -LL | / async { -LL | | let _y = &(); -LL | | let _x = filter(FilterMap { -LL | | f: || async move { *_y }, -... | -LL | | drop(_x); -LL | | } - | |_____^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-1.rs:40:19: 40:29}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr index 6fcf1b1eac176..b93b6f73f07c6 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-10.assumptions.stderr @@ -7,15 +7,5 @@ LL | Box::new(async move { get_foo(x).await }) = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` -error: implementation of `Foo` is not general enough - --> $DIR/higher-ranked-auto-trait-10.rs:32:5 - | -LL | Box::new(async move { get_foo(x).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... - = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr index 6fcf1b1eac176..b93b6f73f07c6 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-10.no_assumptions.stderr @@ -7,15 +7,5 @@ LL | Box::new(async move { get_foo(x).await }) = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` -error: implementation of `Foo` is not general enough - --> $DIR/higher-ranked-auto-trait-10.rs:32:5 - | -LL | Box::new(async move { get_foo(x).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`... - = note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr index f69218740dcca..5a9ac7476f2a4 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.assumptions.stderr @@ -4,7 +4,7 @@ error: implementation of `Getter` is not general enough LL | assert_send(my_send_async_method(struct_with_lifetime, data)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: `Getter<'_>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'1>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough @@ -13,29 +13,9 @@ error: implementation of `Getter` is not general enough LL | assert_send(my_send_async_method(struct_with_lifetime, data)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: `Getter<'_>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'1>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Getter` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough - | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `Getter` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough - | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr index cfbdaa8ad4beb..5a9ac7476f2a4 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr @@ -4,7 +4,7 @@ error: implementation of `Getter` is not general enough LL | assert_send(my_send_async_method(struct_with_lifetime, data)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: `Getter<'_>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'1>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` error: implementation of `Getter` is not general enough @@ -13,48 +13,9 @@ error: implementation of `Getter` is not general enough LL | assert_send(my_send_async_method(struct_with_lifetime, data)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... + = note: `Getter<'_>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'1>>`, for any two lifetimes `'0` and `'1`... = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `Callable` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough - | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... - = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` - -error: implementation of `Getter` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough - | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `Getter` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Getter` is not general enough - | - = note: `Getter<'1>` would have to be implemented for the type `GetterImpl<'0, ConstructableImpl<'_>>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `Callable` is not general enough - --> $DIR/higher-ranked-auto-trait-13.rs:65:5 - | -LL | assert_send(my_send_async_method(struct_with_lifetime, data)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough - | - = note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`... - = note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr index b4f3570d9f2da..fed8e92e59be8 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-15.no_assumptions.stderr @@ -7,15 +7,5 @@ LL | require_send(future); = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&Vec,)>` -error: implementation of `FnOnce` is not general enough - --> $DIR/higher-ranked-auto-trait-15.rs:20:5 - | -LL | require_send(future); - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'0 Vec) -> std::slice::Iter<'_, i32>` must implement `FnOnce<(&'1 Vec,)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&Vec,)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr index 152900ca1ae9e..3f2278c714025 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-17.no_assumptions.stderr @@ -11,19 +11,5 @@ LL | | } = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `FnOnce<(&(),)>` -error: implementation of `FnOnce` is not general enough - --> $DIR/higher-ranked-auto-trait-17.rs:12:5 - | -LL | / async move { -LL | | let iter = Adaptor::new(a.iter().map(|_: &()| {})); -LL | | std::future::pending::<()>().await; -LL | | drop(iter); -LL | | } - | |_____^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'0 ())` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr index d1c88101618ae..813dc8ed26d0a 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr @@ -9,18 +9,6 @@ LL | Box::new(async { new(|| async { f().await }).await }) = note: no two async blocks, even if identical, have the same type = help: consider pinning your async block and casting it to a trait object -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-6.rs:16:5 - | -LL | Box::new(async { new(|| async { f().await }).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr index bb43636492409..1ce37253fd501 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.no_assumptions.stderr @@ -12,20 +12,5 @@ LL | | }); = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` -error: implementation of `Send` is not general enough - --> $DIR/issue-110963-early.rs:17:5 - | -LL | / spawn(async move { -LL | | let mut hc = hc; -LL | | if !hc.check().await { -LL | | log_health_check_failure().await; -LL | | } -LL | | }); - | |______^ implementation of `Send` is not general enough - | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr index 887cb14a76935..33a18be5ff929 100644 --- a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr +++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr @@ -16,27 +16,11 @@ error: higher-ranked subtype error LL | match foo() { | ^^^^^ -error: higher-ranked subtype error - --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15 - | -LL | match foo() { - | ^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: higher-ranked subtype error --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 | LL | Subtype::Bar => (), | ^^^^^^^^^^^^ -error: higher-ranked subtype error - --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 - | -LL | Subtype::Bar => (), - | ^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/coroutine/auto-trait-regions.rs b/tests/ui/coroutine/auto-trait-regions.rs index 736555b31bbd1..fae9a3788502c 100644 --- a/tests/ui/coroutine/auto-trait-regions.rs +++ b/tests/ui/coroutine/auto-trait-regions.rs @@ -20,6 +20,19 @@ impl<'a> Foo for &'a OnlyFooIfRef {} fn assert_foo(f: T) {} +fn other_assertion() { + // Disallow impls which relates lifetimes in the coroutine interior + let generator = #[coroutine] move || { + let a = A(&mut true, &mut true, No); + //~^ ERROR borrow may still be in use when coroutine yields + //~| ERROR borrow may still be in use when coroutine yields + yield; + assert_foo(a); + }; + assert_foo(generator); + //~^ ERROR not general enough +} + fn main() { // Make sure 'static is erased for coroutine interiors so we can't match it in trait selection let x: &'static _ = &OnlyFooIfStaticRef(No); @@ -39,15 +52,4 @@ fn main() { assert_foo(x); }; assert_foo(generator); // ok - - // Disallow impls which relates lifetimes in the coroutine interior - let generator = #[coroutine] move || { - let a = A(&mut true, &mut true, No); - //~^ ERROR borrow may still be in use when coroutine yields - //~| ERROR borrow may still be in use when coroutine yields - yield; - assert_foo(a); - }; - assert_foo(generator); - //~^ ERROR not general enough } diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index beb689d868d46..1976163ed56b6 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr @@ -1,5 +1,5 @@ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/auto-trait-regions.rs:45:19 + --> $DIR/auto-trait-regions.rs:26:19 | LL | let generator = #[coroutine] move || { | ------- within this coroutine @@ -15,7 +15,7 @@ LL | let generator = #[coroutine] static move || { | ++++++ error[E0626]: borrow may still be in use when coroutine yields - --> $DIR/auto-trait-regions.rs:45:30 + --> $DIR/auto-trait-regions.rs:26:30 | LL | let generator = #[coroutine] move || { | ------- within this coroutine @@ -31,22 +31,22 @@ LL | let generator = #[coroutine] static move || { | ++++++ error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:31:5 + --> $DIR/auto-trait-regions.rs:32:5 | LL | assert_foo(generator); | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... - = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` + = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... + = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` error: implementation of `Foo` is not general enough - --> $DIR/auto-trait-regions.rs:51:5 + --> $DIR/auto-trait-regions.rs:44:5 | LL | assert_foo(generator); | ^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | - = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`... - = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2` + = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`... + = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef` error: aborting due to 4 previous errors diff --git a/tests/ui/generic-associated-types/extended/lending_iterator.stderr b/tests/ui/generic-associated-types/extended/lending_iterator.stderr index 7af95dc96a10a..84f5ed07bda59 100644 --- a/tests/ui/generic-associated-types/extended/lending_iterator.stderr +++ b/tests/ui/generic-associated-types/extended/lending_iterator.stderr @@ -12,12 +12,6 @@ error: `Self` does not live long enough | LL | >::from_iter(self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: due to a current limitation of the type system, this implies a `'static` lifetime - --> $DIR/lending_iterator.rs:4:21 - | -LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/higher-ranked-lifetime-equality.stderr b/tests/ui/higher-ranked/higher-ranked-lifetime-equality.stderr index 8c0d66bb0bc1f..50b6d49ee4c0b 100644 --- a/tests/ui/higher-ranked/higher-ranked-lifetime-equality.stderr +++ b/tests/ui/higher-ranked/higher-ranked-lifetime-equality.stderr @@ -7,16 +7,6 @@ LL | let foo: Foo = foo; = note: expected struct `my_api::Foo fn(&'a (), &'b ())>` found struct `my_api::Foo fn(&'a (), &'a ())>` -error[E0308]: mismatched types - --> $DIR/higher-ranked-lifetime-equality.rs:34:25 - | -LL | let foo: Foo = foo; - | ^^^ one type is more general than the other - | - = note: expected struct `my_api::Foo fn(&'a (), &'b ())>` - found struct `my_api::Foo fn(&'a (), &'a ())>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 48703186cc634..10ad14967ae54 100644 --- a/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/tests/ui/higher-ranked/subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -12,21 +12,6 @@ LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0308]: mismatched types - --> $DIR/hr-subtype.rs:54:13 - | -LL | gimme::<$t1>(None::<$t2>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other -... -LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), -LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } - | |__________________________________- in this macro invocation - | - = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` - found enum `Option fn(Inv<'a>, Inv<'a>)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr index 69c58c5919e11..37f2128dd6424 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-conflate-regions.stderr @@ -7,15 +7,5 @@ LL | fn b() { want_foo2::(); } = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` -error: implementation of `Foo` is not general enough - --> $DIR/hrtb-conflate-regions.rs:27:10 - | -LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough - | - = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index a15f400fc2a76..8c7ab2e2a6e59 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -91,6 +91,12 @@ LL | impl Qux<'_> for () {} | ^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `()`, found `&'a ()` +error: lifetime may not live long enough + --> $DIR/nested-rpit-hrtb.rs:49:93 + | +LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} + | -- lifetime `'b` defined here ^^ opaque type requires that `'b` must outlive `'static` + error: implementation of `Bar` is not general enough --> $DIR/nested-rpit-hrtb.rs:49:93 | @@ -114,7 +120,7 @@ LL | impl Qux<'_> for () {} | ^^^^^^^^^^^^^^^^^^^ = help: for that trait implementation, expected `()`, found `&'a ()` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0261, E0277, E0657. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/lub-glb/old-lub-glb-object.stderr b/tests/ui/lub-glb/old-lub-glb-object.stderr index c476d6f692b7b..19cc1567770c5 100644 --- a/tests/ui/lub-glb/old-lub-glb-object.stderr +++ b/tests/ui/lub-glb/old-lub-glb-object.stderr @@ -7,16 +7,6 @@ LL | _ => y, = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` -error[E0308]: mismatched types - --> $DIR/old-lub-glb-object.rs:9:14 - | -LL | _ => y, - | ^ one type is more general than the other - | - = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` - found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr b/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr index 9a88ce8756c89..28113ac15db8c 100644 --- a/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr +++ b/tests/ui/nll/relate_tys/hr-fn-aau-eq-abu.stderr @@ -7,16 +7,6 @@ LL | let a: Cell fn(&'a u32, &'b u32)> = make_cell_aa(); = note: expected struct `Cell fn(&'a _, &'b _)>` found struct `Cell fn(&'a _, &'a _)>` -error[E0308]: mismatched types - --> $DIR/hr-fn-aau-eq-abu.rs:18:53 - | -LL | let a: Cell fn(&'a u32, &'b u32)> = make_cell_aa(); - | ^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected struct `Cell fn(&'a _, &'b _)>` - found struct `Cell fn(&'a _, &'a _)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr index e5885ea35a71e..3f81b9306b9f1 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.current.stderr @@ -7,16 +7,6 @@ LL | x = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` found existential trait ref `for<'a> Supertrait<'a, 'a>` -error[E0308]: mismatched types - --> $DIR/higher-ranked-upcasting-ub.rs:22:5 - | -LL | x - | ^ one type is more general than the other - | - = note: expected existential trait ref `for<'a, 'b> Supertrait<'a, 'b>` - found existential trait ref `for<'a> Supertrait<'a, 'a>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs index 98ca30ca391f7..203768b7a8792 100644 --- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs +++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs @@ -21,8 +21,7 @@ impl<'a> Subtrait<'a, 'a> for () {} fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> { x //[current]~^ ERROR mismatched types - //[current]~| ERROR mismatched types - //[next]~^^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied + //[next]~^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied } fn transmute<'a, 'b>(x: &'a str) -> &'b str {