Skip to content

Commit da2a772

Browse files
committed
move TypeOutlives normalization out of region checking
1 parent 3f808f2 commit da2a772

3 files changed

Lines changed: 136 additions & 21 deletions

File tree

compiler/rustc_trait_selection/src/regions.rs

Lines changed: 102 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,105 @@
1+
use rustc_data_structures::fx::FxHashSet;
12
use rustc_hir::def_id::LocalDefId;
23
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
3-
use rustc_infer::infer::{InferCtxt, RegionResolutionError};
4+
use rustc_infer::infer::{
5+
InferCtxt, RegionResolutionError, SubregionOrigin, TypeOutlivesConstraint,
6+
};
47
use rustc_macros::extension;
58
use rustc_middle::traits::ObligationCause;
6-
use rustc_middle::traits::query::NoSolution;
79
use rustc_middle::ty::{self, Ty, elaborate};
810

911
use crate::traits::ScrubbedTraitError;
1012
use crate::traits::outlives_bounds::InferCtxtExt;
1113

14+
fn normalize_higher_ranked_assumptions<'tcx>(
15+
infcx: &InferCtxt<'tcx>,
16+
param_env: ty::ParamEnv<'tcx>,
17+
) -> FxHashSet<ty::ArgOutlivesPredicate<'tcx>> {
18+
let assumptions = infcx.take_registered_region_assumptions();
19+
if !infcx.next_trait_solver() {
20+
return elaborate::elaborate_outlives_assumptions(infcx.tcx, assumptions);
21+
}
22+
23+
let mut normalized_assumptions = vec![];
24+
let mut seen_assumptions = FxHashSet::default();
25+
26+
for assumption in assumptions {
27+
if !seen_assumptions.insert(assumption) {
28+
continue;
29+
}
30+
31+
let assumption = infcx.resolve_vars_if_possible(assumption);
32+
let outlives = ty::Binder::dummy(assumption);
33+
let ty::OutlivesPredicate(kind, region) =
34+
match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
35+
infcx.at(&ObligationCause::dummy(), param_env),
36+
outlives,
37+
) {
38+
Ok(assumption) => assumption,
39+
Err(_) => {
40+
infcx.dcx().delayed_bug(format!(
41+
"could not normalize higher-ranked assumption `{assumption}`"
42+
));
43+
outlives
44+
}
45+
}
46+
.no_bound_vars()
47+
.expect("started with no bound vars, should end with no bound vars");
48+
49+
normalized_assumptions.push(ty::OutlivesPredicate(kind, region));
50+
}
51+
52+
for assumption in infcx.take_registered_region_assumptions() {
53+
if seen_assumptions.insert(assumption) {
54+
normalized_assumptions.push(assumption);
55+
}
56+
}
57+
58+
elaborate::elaborate_outlives_assumptions(infcx.tcx, normalized_assumptions)
59+
}
60+
61+
fn normalize_registered_region_obligations<'tcx>(
62+
infcx: &InferCtxt<'tcx>,
63+
param_env: ty::ParamEnv<'tcx>,
64+
) -> Result<(), (ty::PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
65+
if !infcx.next_trait_solver() {
66+
return Ok(());
67+
}
68+
69+
let obligations = infcx.take_registered_region_obligations();
70+
let mut seen_outputs = FxHashSet::default();
71+
let mut normalized_obligations = vec![];
72+
73+
for TypeOutlivesConstraint { sup_type, sub_region, origin } in obligations {
74+
let outlives = infcx.resolve_vars_if_possible(ty::Binder::dummy(ty::OutlivesPredicate(
75+
sup_type, sub_region,
76+
)));
77+
let ty::OutlivesPredicate(sup_type, sub_region) = crate::solve::deeply_normalize(
78+
infcx.at(&ObligationCause::dummy_with_span(origin.span()), param_env),
79+
outlives,
80+
)
81+
.map_err(|_: Vec<ScrubbedTraitError<'tcx>>| (outlives, origin.clone()))?
82+
.no_bound_vars()
83+
.expect("started with no bound vars, should end with no bound vars");
84+
85+
if seen_outputs.insert((sup_type, sub_region)) {
86+
normalized_obligations.push(TypeOutlivesConstraint { sup_type, sub_region, origin });
87+
}
88+
}
89+
90+
for obligation in infcx.take_registered_region_obligations() {
91+
if seen_outputs.insert((obligation.sup_type, obligation.sub_region)) {
92+
normalized_obligations.push(obligation);
93+
}
94+
}
95+
96+
for obligation in normalized_obligations {
97+
infcx.register_type_outlives_constraint_inner(obligation);
98+
}
99+
100+
Ok(())
101+
}
102+
12103
#[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)]
13104
impl<'tcx> OutlivesEnvironment<'tcx> {
14105
fn new(
@@ -46,10 +137,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
46137
}
47138
}
48139

49-
// FIXME(-Znext-trait-solver): Normalize these.
50-
let higher_ranked_assumptions = infcx.take_registered_region_assumptions();
51-
let higher_ranked_assumptions =
52-
elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions);
140+
let higher_ranked_assumptions = normalize_higher_ranked_assumptions(infcx, param_env);
53141

54142
// FIXME: This needs to be modified so that we normalize the known type
55143
// outlives obligations then elaborate them into their region/type components.
@@ -98,21 +186,14 @@ impl<'tcx> InferCtxt<'tcx> {
98186
&self,
99187
outlives_env: &OutlivesEnvironment<'tcx>,
100188
) -> Vec<RegionResolutionError<'tcx>> {
101-
self.resolve_regions_with_normalize(&outlives_env, |ty, origin| {
102-
let ty = self.resolve_vars_if_possible(ty);
103-
104-
if self.next_trait_solver() {
105-
crate::solve::deeply_normalize(
106-
self.at(
107-
&ObligationCause::dummy_with_span(origin.span()),
108-
outlives_env.param_env,
109-
),
110-
ty,
111-
)
112-
.map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
113-
} else {
114-
Ok(ty)
115-
}
189+
if let Err((outlives, origin)) =
190+
normalize_registered_region_obligations(self, outlives_env.param_env)
191+
{
192+
return vec![RegionResolutionError::CannotNormalize(outlives, origin)];
193+
}
194+
195+
self.resolve_regions_with_normalize(outlives_env, |outlives, _| {
196+
Ok(self.resolve_vars_if_possible(outlives))
116197
})
117198
}
118199
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ compile-flags: -Znext-solver=globally
2+
3+
trait X<'a> {
4+
type U: ?Sized;
5+
}
6+
7+
impl X<'_> for u32
8+
where
9+
for<'b> <Self as X<'b>>::U: 'a,
10+
//~^ ERROR use of undeclared lifetime name `'a`
11+
{
12+
type U = str;
13+
}
14+
15+
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0261]: use of undeclared lifetime name `'a`
2+
--> $DIR/undeclared-lifetime-no-ice-issue-151461.rs:9:33
3+
|
4+
LL | for<'b> <Self as X<'b>>::U: 'a,
5+
| ^^ undeclared lifetime
6+
|
7+
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
8+
help: consider making the bound lifetime-generic with a new `'a` lifetime
9+
|
10+
LL | for<'a, 'b> <Self as X<'b>>::U: 'a,
11+
| +++
12+
help: consider introducing lifetime `'a` here
13+
|
14+
LL | impl<'a> X<'_> for u32
15+
| ++++
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0261`.

0 commit comments

Comments
 (0)