Skip to content

Commit d017d59

Browse files
committed
Auto merge of #98109 - nikomatsakis:issue-98095, r=jackh726
fix universes in the NLL type tests In the NLL code, we were not accommodating universes in the `type_test` logic. Fixes #98095. r? `@compiler-errors` This breaks some tests, however, so the purpose of this branch is more explanatory and perhaps to do a crater run.
2 parents fc96600 + e7ed8fe commit d017d59

29 files changed

+735
-267
lines changed

compiler/rustc_borrowck/src/nll.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
299299

300300
// Solve the region constraints.
301301
let (closure_region_requirements, nll_errors) =
302-
regioncx.solve(infcx, &body, polonius_output.clone());
302+
regioncx.solve(infcx, param_env, &body, polonius_output.clone());
303303

304304
if !nll_errors.is_empty() {
305305
// Suppress unhelpful extra errors in `infer_opaque_types`.

compiler/rustc_borrowck/src/region_infer/mod.rs

+81-20
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
1010
use rustc_hir::CRATE_HIR_ID;
1111
use rustc_index::vec::IndexVec;
1212
use rustc_infer::infer::canonical::QueryOutlivesConstraint;
13-
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
13+
use rustc_infer::infer::outlives::test_type_match;
14+
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
1415
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
1516
use rustc_middle::mir::{
1617
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -46,6 +47,7 @@ pub mod values;
4647

4748
pub struct RegionInferenceContext<'tcx> {
4849
pub var_infos: VarInfos,
50+
4951
/// Contains the definition for every region variable. Region
5052
/// variables are identified by their index (`RegionVid`). The
5153
/// definition contains information about where the region came
@@ -559,6 +561,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
559561
pub(super) fn solve(
560562
&mut self,
561563
infcx: &InferCtxt<'_, 'tcx>,
564+
param_env: ty::ParamEnv<'tcx>,
562565
body: &Body<'tcx>,
563566
polonius_output: Option<Rc<PoloniusOutput>>,
564567
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
@@ -574,7 +577,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
574577
// eagerly.
575578
let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
576579

577-
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
580+
self.check_type_tests(
581+
infcx,
582+
param_env,
583+
body,
584+
outlives_requirements.as_mut(),
585+
&mut errors_buffer,
586+
);
578587

579588
// In Polonius mode, the errors about missing universal region relations are in the output
580589
// and need to be emitted or propagated. Otherwise, we need to check whether the
@@ -823,6 +832,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
823832
fn check_type_tests(
824833
&self,
825834
infcx: &InferCtxt<'_, 'tcx>,
835+
param_env: ty::ParamEnv<'tcx>,
826836
body: &Body<'tcx>,
827837
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
828838
errors_buffer: &mut RegionErrors<'tcx>,
@@ -839,7 +849,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
839849

840850
let generic_ty = type_test.generic_kind.to_ty(tcx);
841851
if self.eval_verify_bound(
842-
tcx,
852+
infcx,
853+
param_env,
843854
body,
844855
generic_ty,
845856
type_test.lower_bound,
@@ -851,6 +862,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
851862
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
852863
if self.try_promote_type_test(
853864
infcx,
865+
param_env,
854866
body,
855867
type_test,
856868
propagated_outlives_requirements,
@@ -907,6 +919,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
907919
fn try_promote_type_test(
908920
&self,
909921
infcx: &InferCtxt<'_, 'tcx>,
922+
param_env: ty::ParamEnv<'tcx>,
910923
body: &Body<'tcx>,
911924
type_test: &TypeTest<'tcx>,
912925
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
@@ -938,7 +951,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
938951
// where `ur` is a local bound -- we are sometimes in a
939952
// position to prove things that our caller cannot. See
940953
// #53570 for an example.
941-
if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) {
954+
if self.eval_verify_bound(
955+
infcx,
956+
param_env,
957+
body,
958+
generic_ty,
959+
ur,
960+
&type_test.verify_bound,
961+
) {
942962
continue;
943963
}
944964

@@ -1161,7 +1181,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11611181
/// `point`.
11621182
fn eval_verify_bound(
11631183
&self,
1164-
tcx: TyCtxt<'tcx>,
1184+
infcx: &InferCtxt<'_, 'tcx>,
1185+
param_env: ty::ParamEnv<'tcx>,
11651186
body: &Body<'tcx>,
11661187
generic_ty: Ty<'tcx>,
11671188
lower_bound: RegionVid,
@@ -1170,8 +1191,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11701191
debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
11711192

11721193
match verify_bound {
1173-
VerifyBound::IfEq(test_ty, verify_bound1) => {
1174-
self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
1194+
VerifyBound::IfEq(verify_if_eq_b) => {
1195+
self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
11751196
}
11761197

11771198
VerifyBound::IsEmpty => {
@@ -1185,30 +1206,50 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11851206
}
11861207

11871208
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
1188-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1209+
self.eval_verify_bound(
1210+
infcx,
1211+
param_env,
1212+
body,
1213+
generic_ty,
1214+
lower_bound,
1215+
verify_bound,
1216+
)
11891217
}),
11901218

11911219
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
1192-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1220+
self.eval_verify_bound(
1221+
infcx,
1222+
param_env,
1223+
body,
1224+
generic_ty,
1225+
lower_bound,
1226+
verify_bound,
1227+
)
11931228
}),
11941229
}
11951230
}
11961231

11971232
fn eval_if_eq(
11981233
&self,
1199-
tcx: TyCtxt<'tcx>,
1200-
body: &Body<'tcx>,
1234+
infcx: &InferCtxt<'_, 'tcx>,
1235+
param_env: ty::ParamEnv<'tcx>,
12011236
generic_ty: Ty<'tcx>,
12021237
lower_bound: RegionVid,
1203-
test_ty: Ty<'tcx>,
1204-
verify_bound: &VerifyBound<'tcx>,
1238+
verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
12051239
) -> bool {
1206-
let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
1207-
let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
1208-
if generic_ty_normalized == test_ty_normalized {
1209-
self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
1210-
} else {
1211-
false
1240+
let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
1241+
let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
1242+
match test_type_match::extract_verify_if_eq(
1243+
infcx.tcx,
1244+
param_env,
1245+
&verify_if_eq_b,
1246+
generic_ty,
1247+
) {
1248+
Some(r) => {
1249+
let r_vid = self.to_region_vid(r);
1250+
self.eval_outlives(r_vid, lower_bound)
1251+
}
1252+
None => false,
12121253
}
12131254
}
12141255

@@ -1278,6 +1319,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12781319
let sub_region_scc = self.constraint_sccs.scc(sub_region);
12791320
let sup_region_scc = self.constraint_sccs.scc(sup_region);
12801321

1322+
// If we are checking that `'sup: 'sub`, and `'sub` contains
1323+
// some placeholder that `'sup` cannot name, then this is only
1324+
// true if `'sup` outlives static.
1325+
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
1326+
debug!(
1327+
"eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
1328+
by super `{sup_region_scc:?}`, promoting to static",
1329+
);
1330+
1331+
return self.eval_outlives(sup_region, self.universal_regions.fr_static);
1332+
}
1333+
12811334
// Both the `sub_region` and `sup_region` consist of the union
12821335
// of some number of universal regions (along with the union
12831336
// of various points in the CFG; ignore those points for
@@ -1292,6 +1345,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12921345
});
12931346

12941347
if !universal_outlives {
1348+
debug!(
1349+
"eval_outlives: returning false because sub region contains a universal region not present in super"
1350+
);
12951351
return false;
12961352
}
12971353

@@ -1300,10 +1356,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
13001356

13011357
if self.universal_regions.is_universal_region(sup_region) {
13021358
// Micro-opt: universal regions contain all points.
1359+
debug!(
1360+
"eval_outlives: returning true because super is universal and hence contains all points"
1361+
);
13031362
return true;
13041363
}
13051364

1306-
self.scc_values.contains_points(sup_region_scc, sub_region_scc)
1365+
let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
1366+
debug!("returning {} because of comparison between points in sup/sub", result);
1367+
result
13071368
}
13081369

13091370
/// Once regions have been propagated, this method is used to see

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ use rustc_middle::ty::{Region, RegionVid};
2222
use rustc_span::Span;
2323
use std::fmt;
2424

25+
use super::outlives::test_type_match;
26+
2527
/// This function performs lexical region resolution given a complete
2628
/// set of constraints and variable origins. It performs a fixed-point
2729
/// iteration to find region values which satisfy all constraints,
2830
/// assuming such values can be found. It returns the final values of
2931
/// all the variables as well as a set of errors that must be reported.
3032
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
3133
pub(crate) fn resolve<'tcx>(
34+
param_env: ty::ParamEnv<'tcx>,
3235
region_rels: &RegionRelations<'_, 'tcx>,
3336
var_infos: VarInfos,
3437
data: RegionConstraintData<'tcx>,
3538
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
3639
let mut errors = vec![];
37-
let mut resolver = LexicalResolver { region_rels, var_infos, data };
40+
let mut resolver = LexicalResolver { param_env, region_rels, var_infos, data };
3841
let values = resolver.infer_variable_values(&mut errors);
3942
(values, errors)
4043
}
@@ -100,6 +103,7 @@ struct RegionAndOrigin<'tcx> {
100103
type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
101104

102105
struct LexicalResolver<'cx, 'tcx> {
106+
param_env: ty::ParamEnv<'tcx>,
103107
region_rels: &'cx RegionRelations<'cx, 'tcx>,
104108
var_infos: VarInfos,
105109
data: RegionConstraintData<'tcx>,
@@ -818,9 +822,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
818822
min: ty::Region<'tcx>,
819823
) -> bool {
820824
match bound {
821-
VerifyBound::IfEq(k, b) => {
822-
(var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
823-
&& self.bound_is_met(b, var_values, generic_ty, min)
825+
VerifyBound::IfEq(verify_if_eq_b) => {
826+
let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
827+
match test_type_match::extract_verify_if_eq(
828+
self.tcx(),
829+
self.param_env,
830+
&verify_if_eq_b,
831+
generic_ty,
832+
) {
833+
Some(r) => {
834+
self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
835+
}
836+
837+
None => false,
838+
}
824839
}
825840

826841
VerifyBound::OutlivedBy(r) => {

compiler/rustc_infer/src/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
12901290
&RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map());
12911291

12921292
let (lexical_region_resolutions, errors) =
1293-
lexical_region_resolve::resolve(region_rels, var_infos, data);
1293+
lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
12941294

12951295
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
12961296
assert!(old_value.is_none());

compiler/rustc_infer/src/infer/outlives/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub mod components;
44
pub mod env;
55
pub mod obligations;
6+
pub mod test_type_match;
67
pub mod verify;
78

89
use rustc_middle::traits::query::OutlivesBound;

compiler/rustc_infer/src/infer/outlives/obligations.rs

+27-14
Original file line numberDiff line numberDiff line change
@@ -318,17 +318,13 @@ where
318318
self.delegate.push_verify(origin, generic, region, verify_bound);
319319
}
320320

321+
#[tracing::instrument(level = "debug", skip(self))]
321322
fn projection_must_outlive(
322323
&mut self,
323324
origin: infer::SubregionOrigin<'tcx>,
324325
region: ty::Region<'tcx>,
325326
projection_ty: ty::ProjectionTy<'tcx>,
326327
) {
327-
debug!(
328-
"projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
329-
region, projection_ty, origin
330-
);
331-
332328
// This case is thorny for inference. The fundamental problem is
333329
// that there are many cases where we have choice, and inference
334330
// doesn't like choice (the current region inference in
@@ -363,13 +359,21 @@ where
363359
// #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
364360
// 'a` in the environment but `trait Foo<'b> { type Item: 'b
365361
// }` in the trait definition.
366-
approx_env_bounds.retain(|bound| match *bound.0.kind() {
367-
ty::Projection(projection_ty) => self
368-
.verify_bound
369-
.projection_declared_bounds_from_trait(projection_ty)
370-
.all(|r| r != bound.1),
371-
372-
_ => panic!("expected only projection types from env, not {:?}", bound.0),
362+
approx_env_bounds.retain(|bound_outlives| {
363+
// OK to skip binder because we only manipulate and compare against other
364+
// values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a`
365+
// in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region.
366+
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
367+
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
368+
let bound = bound_outlives.skip_binder();
369+
match *bound.0.kind() {
370+
ty::Projection(projection_ty) => self
371+
.verify_bound
372+
.projection_declared_bounds_from_trait(projection_ty)
373+
.all(|r| r != bound.1),
374+
375+
_ => panic!("expected only projection types from env, not {:?}", bound.0),
376+
}
373377
});
374378

375379
// If declared bounds list is empty, the only applicable rule is
@@ -420,8 +424,16 @@ where
420424
if !trait_bounds.is_empty()
421425
&& trait_bounds[1..]
422426
.iter()
423-
.chain(approx_env_bounds.iter().map(|b| &b.1))
424-
.all(|b| *b == trait_bounds[0])
427+
.map(|r| Some(*r))
428+
.chain(
429+
// NB: The environment may contain `for<'a> T: 'a` style bounds.
430+
// In that case, we don't know if they are equal to the trait bound
431+
// or not (since we don't *know* whether the environment bound even applies),
432+
// so just map to `None` here if there are bound vars, ensuring that
433+
// the call to `all` will fail below.
434+
approx_env_bounds.iter().map(|b| b.map_bound(|b| b.1).no_bound_vars()),
435+
)
436+
.all(|b| b == Some(trait_bounds[0]))
425437
{
426438
let unique_bound = trait_bounds[0];
427439
debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
@@ -437,6 +449,7 @@ where
437449
// even though a satisfactory solution exists.
438450
let generic = GenericKind::Projection(projection_ty);
439451
let verify_bound = self.verify_bound.generic_bound(generic);
452+
debug!("projection_must_outlive: pushing {:?}", verify_bound);
440453
self.delegate.push_verify(origin, generic, region, verify_bound);
441454
}
442455
}

0 commit comments

Comments
 (0)