diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index 6be90994015f3..d23ecf6c70796 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -344,7 +344,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( } } -fn rewrite_placeholder_outlives<'tcx>( +pub(crate) fn rewrite_placeholder_outlives<'tcx>( sccs: &Sccs, annotations: &SccAnnotations<'_, '_, RegionTracker>, fr_static: RegionVid, diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs index 667fc440ac002..a2e2b61ae2d35 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/member_constraints.rs @@ -39,7 +39,7 @@ pub(super) fn apply_member_constraints<'tcx>( debug!(?member_constraints); for scc_a in rcx.constraint_sccs.all_sccs() { debug!(?scc_a); - // Start by adding the region values required by outlives constraints. This + // Start by adding the region values required by outlives constraints. This // matches how we compute the final region values in `fn compute_regions`. // // We need to do this here to get a lower bound when applying member constraints. @@ -64,6 +64,7 @@ fn apply_member_constraint<'tcx>( // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. if !rcx.max_placeholder_universe_reached(member).is_root() { + debug!("member region reached non root universe, bailing"); return; } 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 8d89f3e0d8700..0abd95b44b1cd 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -253,6 +253,10 @@ fn collect_defining_uses<'tcx>( } } else { errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err)); + debug!( + "collect_defining_uses: InvalidOpaqueTypeArgs for {:?} := {:?}", + non_nll_opaque_type_key, hidden_type + ); } continue; } @@ -286,26 +290,31 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( let tcx = infcx.tcx; let mut decls_modulo_regions: FxIndexMap, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); - for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses { + for this_use @ &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses { // After applying member constraints, we now map all regions in the hidden type // to the `arg_regions` of this defining use. In case a region in the hidden type // ended up not being equal to any such region, we error. - let hidden_type = - match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) { - Ok(hidden_type) => hidden_type, - Err(r) => { - errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion { - hidden_type, - opaque_type_key, - member_region: ty::Region::new_var(tcx, r), - }); - let guar = tcx.dcx().span_delayed_bug( - hidden_type.span, - "opaque type with non-universal region args", - ); - ty::OpaqueHiddenType::new_error(tcx, guar) - } - }; + let hidden_type = match hidden_type + .try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) + { + Ok(hidden_type) => hidden_type, + Err(r) => { + errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion { + hidden_type, + opaque_type_key, + member_region: ty::Region::new_var(tcx, r), + }); + debug!( + "compute_definition_site_hidden_types_from_defining_use: UnexpectedHiddenRegion for {:?}", + this_use, + ); + let guar = tcx.dcx().span_delayed_bug( + hidden_type.span, + "opaque type with non-universal region args", + ); + ty::OpaqueHiddenType::new_error(tcx, guar) + } + }; // Now that we mapped the member regions to their final value, // map the arguments of the opaque type key back to the parameters 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 88326e4eebfc2..90b15cbdd2cc8 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 @@ -11,7 +11,9 @@ use crate::constraints::ConstraintSccIndex; use crate::handle_placeholders::{SccAnnotations, region_definitions}; use crate::region_infer::reverse_sccs::ReverseSccGraph; use crate::region_infer::values::RegionValues; -use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker, Representative}; +use crate::region_infer::{ + ConstraintSccs, OutlivesConstraintSet, RegionDefinition, RegionTracker, Representative, +}; use crate::type_check::MirTypeckRegionConstraints; use crate::type_check::free_region_relations::UniversalRegionRelations; use crate::universal_regions::UniversalRegions; @@ -39,16 +41,36 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { location_map: Rc, constraints: &MirTypeckRegionConstraints<'tcx>, ) -> RegionCtxt<'a, 'tcx> { + let mut outlives_constraints = constraints.outlives_constraints.clone(); let universal_regions = &universal_region_relations.universal_regions; let (definitions, _has_placeholders) = region_definitions(infcx, universal_regions); + + let compute_sccs = + |outlives_constraints: &OutlivesConstraintSet<'tcx>, + annotations: &mut SccAnnotations<'_, 'tcx, RegionTracker>| { + ConstraintSccs::new_with_annotation( + &outlives_constraints + .graph(definitions.len()) + .region_graph(outlives_constraints, universal_regions.fr_static), + annotations, + ) + }; + let mut scc_annotations = SccAnnotations::init(&definitions); - let constraint_sccs = ConstraintSccs::new_with_annotation( - &constraints - .outlives_constraints - .graph(definitions.len()) - .region_graph(&constraints.outlives_constraints, universal_regions.fr_static), - &mut scc_annotations, + let mut constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); + + let added_constraints = crate::handle_placeholders::rewrite_placeholder_outlives( + &constraint_sccs, + &scc_annotations, + universal_regions.fr_static, + &mut outlives_constraints, ); + + if added_constraints { + scc_annotations = SccAnnotations::init(&definitions); + constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations); + } + let scc_annotations = scc_annotations.scc_to_annotation; // Unlike the `RegionInferenceContext`, we only care about free regions diff --git a/tests/ui/impl-trait/member-constraints/placeholders_lift_to_static.rs b/tests/ui/impl-trait/member-constraints/placeholders_lift_to_static.rs new file mode 100644 index 0000000000000..f2b332de5ebe5 --- /dev/null +++ b/tests/ui/impl-trait/member-constraints/placeholders_lift_to_static.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// We have some `RPIT` with an item bound of `for<'a> Outlives<'a>`. We +// infer a hidden type of `&'?x i32` where `'?x` is required to outlive +// some placeholder `'!a` due to the `for<'a> Outlives<'a>` item bound. +// +// We previously did not write constraints of the form `'?x: '!a` into +// `'?x: 'static`. This caused member constraints to bail and not consider +// `'?x` to be constrained to an arg region. + +pub trait Outlives<'a> {} +impl<'a, T: 'a> Outlives<'a> for T {} + +pub fn foo() -> impl for<'a> Outlives<'a> { + let x: &'static i32 = &1; + x +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index f4ff13d6c20f9..11d79bcff7371 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -48,7 +48,6 @@ fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = im // This should resolve. fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} //~^ ERROR implementation of `Bar` is not general enough -//~| ERROR lifetime may not live long enough // This should resolve. fn two_htrb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Qux<'b>> {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 93cd7bd788f45..2e95ef370c7fd 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:57:77 + --> $DIR/nested-rpit-hrtb.rs:56:77 | LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Siz | ++++ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:65:82 + --> $DIR/nested-rpit-hrtb.rs:64:82 | LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -87,12 +87,6 @@ LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc but trait `Qux<'_>` is implemented 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 | @@ -103,7 +97,7 @@ LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied - --> $DIR/nested-rpit-hrtb.rs:61:64 + --> $DIR/nested-rpit-hrtb.rs:60:64 | LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()` @@ -112,7 +106,7 @@ LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> but trait `Qux<'_>` is implemented for `()` = help: for that trait implementation, expected `()`, found `&'a ()` -error: aborting due to 10 previous errors +error: aborting due to 9 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/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr index 0edbd7b44ef1c..629570b602ed6 100644 --- a/tests/ui/nll/ice-106874.stderr +++ b/tests/ui/nll/ice-106874.stderr @@ -17,6 +17,20 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + error: implementation of `FnOnce` is not general enough --> $DIR/ice-106874.rs:8:7 | @@ -75,17 +89,5 @@ LL | A(B(C::new(D::new(move |st| f(st))))) = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: higher-ranked subtype error - --> $DIR/ice-106874.rs:8:7 - | -LL | A(B(C::new(D::new(move |st| f(st))))) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: higher-ranked subtype error - --> $DIR/ice-106874.rs:8:41 - | -LL | A(B(C::new(D::new(move |st| f(st))))) - | ^ - error: aborting due to 10 previous errors