Skip to content

Commit 8498c5f

Browse files
committed
Auto merge of #65232 - nikomatsakis:lazy-norm-anon-const-push-2, r=matthewjasper
replace the leak check with universes, take 2 This PR is an attempt to revive the "universe-based region check", which is an important step towards lazy normalization. Unlike before, we also modify the definition of `'empty` so that it is indexed by a universe. This sidesteps some of the surprising effects we saw before -- at the core, we no longer think that `exists<'a> { forall<'b> { 'b: 'a } }` is solveable. The new region lattice looks like this: ``` static ----------+-----...------+ (greatest) | | | early-bound and | | free regions | | | | | scope regions | | | | | empty(root) placeholder(U1) | | / | | / placeholder(Un) empty(U1) -- / | / ... / | / empty(Un) -------- (smallest) ``` This PR has three effects: * It changes a fair number of error messages, I think for the better. * It fixes a number of bugs. The old algorithm was too conservative and caused us to reject legal subtypings. * It also causes two regressions (things that used to compile, but now do not). * `coherence-subtyping.rs` gets an additional error. This is expected. * `issue-57639.rs` regresses as before, for the reasons covered in #57639. Both of the regressions stem from the same underlying property: without the leak check, the instantaneous "subtype" check is not able to tell whether higher-ranked subtyping will succeed or not. In both cases, we might be able to fix the problem by doing a 'leak-check like change' at some later point (e.g., as part of coherence). This is a draft PR because: * I didn't finish ripping out the leak-check completely. * We might want to consider a crater run before landing this. * We might want some kind of design meeting to cover the overall strategy. * I just remembered I never finished 100% integrating this into the canonicalization code. * I should also review what happens in NLL region checking -- it probably still has a notion of bottom (empty set). r? @matthewjasper
2 parents a29424a + 4b3c66d commit 8498c5f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+613
-207
lines changed

src/librustc/ich/impls_ty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
6363
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
6464
mem::discriminant(self).hash_stable(hcx, hasher);
6565
match *self {
66-
ty::ReErased | ty::ReStatic | ty::ReEmpty => {
66+
ty::ReErased | ty::ReStatic => {
6767
// No variant fields to hash for these ...
6868
}
69+
ty::ReEmpty(universe) => {
70+
universe.hash_stable(hcx, hasher);
71+
}
6972
ty::ReLateBound(db, ty::BrAnon(i)) => {
7073
db.hash_stable(hcx, hasher);
7174
i.hash_stable(hcx, hasher);

src/librustc/infer/canonical/canonicalizer.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,29 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
167167
r: ty::Region<'tcx>,
168168
) -> ty::Region<'tcx> {
169169
match r {
170-
ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
170+
ty::ReFree(_)
171+
| ty::ReErased
172+
| ty::ReStatic
173+
| ty::ReEmpty(ty::UniverseIndex::ROOT)
174+
| ty::ReEarlyBound(..) => r,
175+
171176
ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
172177
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) },
173178
r,
174179
),
180+
175181
ty::ReVar(vid) => {
176182
let universe = canonicalizer.region_var_universe(*vid);
177183
canonicalizer.canonical_var_for_region(
178184
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
179185
r,
180186
)
181187
}
188+
189+
ty::ReEmpty(ui) => {
190+
bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME
191+
}
192+
182193
_ => {
183194
// Other than `'static` or `'empty`, the query
184195
// response should be executing in a fully
@@ -213,7 +224,7 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
213224
r: ty::Region<'tcx>,
214225
) -> ty::Region<'tcx> {
215226
match r {
216-
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReEmpty | ty::ReStatic => r,
227+
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
217228
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
218229
_ => {
219230
// We only expect region names that the user can type.
@@ -320,8 +331,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
320331
| ty::ReEarlyBound(..)
321332
| ty::ReFree(_)
322333
| ty::ReScope(_)
334+
| ty::ReEmpty(_)
323335
| ty::RePlaceholder(..)
324-
| ty::ReEmpty
325336
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
326337

327338
ty::ReClosureBound(..) => {

src/librustc/infer/combine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
577577

578578
ty::RePlaceholder(..)
579579
| ty::ReVar(..)
580-
| ty::ReEmpty
580+
| ty::ReEmpty(_)
581581
| ty::ReStatic
582582
| ty::ReScope(..)
583583
| ty::ReEarlyBound(..)

src/librustc/infer/error_reporting/mod.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ pub(super) fn note_and_explain_region(
138138
msg_span_from_free_region(tcx, region)
139139
}
140140

141-
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
141+
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),
142+
143+
// uh oh, hope no user ever sees THIS
144+
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
142145

143146
ty::RePlaceholder(_) => (format!("any other region"), None),
144147

@@ -181,7 +184,8 @@ fn msg_span_from_free_region(
181184
msg_span_from_early_bound_and_free_regions(tcx, region)
182185
}
183186
ty::ReStatic => ("the static lifetime".to_owned(), None),
184-
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
187+
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
188+
ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
185189
_ => bug!("{:?}", region),
186190
}
187191
}
@@ -375,6 +379,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
375379
}
376380
}
377381

382+
RegionResolutionError::UpperBoundUniverseConflict(
383+
_,
384+
_,
385+
var_universe,
386+
sup_origin,
387+
sup_r,
388+
) => {
389+
assert!(sup_r.is_placeholder());
390+
391+
// Make a dummy value for the "sub region" --
392+
// this is the initial value of the
393+
// placeholder. In practice, we expect more
394+
// tailored errors that don't really use this
395+
// value.
396+
let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe));
397+
398+
self.report_placeholder_failure(
399+
region_scope_tree,
400+
sup_origin,
401+
sub_r,
402+
sup_r,
403+
)
404+
.emit();
405+
}
406+
378407
RegionResolutionError::MemberConstraintFailure {
379408
opaque_type_def_id,
380409
hidden_ty,
@@ -429,6 +458,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
429458
RegionResolutionError::GenericBoundFailure(..) => true,
430459
RegionResolutionError::ConcreteFailure(..)
431460
| RegionResolutionError::SubSupConflict(..)
461+
| RegionResolutionError::UpperBoundUniverseConflict(..)
432462
| RegionResolutionError::MemberConstraintFailure { .. } => false,
433463
};
434464

@@ -443,6 +473,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
443473
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
444474
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
445475
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
476+
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
446477
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
447478
});
448479
errors

src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
4545
///
4646
/// It will later be extended to trait objects.
4747
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
48-
let (span, sub, sup) = self.regions();
48+
let (span, sub, sup) = self.regions()?;
4949

5050
// Determine whether the sub and sup consist of both anonymous (elided) regions.
5151
let anon_reg_sup = self.tcx().is_suitable_region(sup)?;

src/librustc/infer/error_reporting/nice_region_error/mod.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ mod util;
1717

1818
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
1919
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
20-
match *error {
21-
ConcreteFailure(..) | SubSupConflict(..) => {}
22-
_ => return false, // inapplicable
23-
}
24-
2520
if let Some(tables) = self.in_progress_tables {
2621
let tables = tables.borrow();
2722
NiceRegionError::new(self, error.clone(), Some(&tables)).try_report().is_some()
@@ -79,13 +74,14 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
7974
.or_else(|| self.try_report_impl_not_conforming_to_trait())
8075
}
8176

82-
pub fn regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
77+
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
8378
match (&self.error, self.regions) {
84-
(Some(ConcreteFailure(origin, sub, sup)), None) => (origin.span(), sub, sup),
85-
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => (origin.span(), sub, sup),
86-
(None, Some((span, sub, sup))) => (span, sub, sup),
87-
(Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"),
88-
_ => panic!("trying to report on an incorrect lifetime failure"),
79+
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
80+
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
81+
Some((origin.span(), sub, sup))
82+
}
83+
(None, Some((span, sub, sup))) => Some((span, sub, sup)),
84+
_ => None,
8985
}
9086
}
9187
}

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
99
/// When given a `ConcreteFailure` for a function with parameters containing a named region and
1010
/// an anonymous region, emit an descriptive diagnostic error.
1111
pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
12-
let (span, sub, sup) = self.regions();
12+
let (span, sub, sup) = self.regions()?;
1313

1414
debug!(
1515
"try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",

src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs

+19
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ impl NiceRegionError<'me, 'tcx> {
107107
found.substs,
108108
)),
109109

110+
Some(RegionResolutionError::UpperBoundUniverseConflict(
111+
vid,
112+
_,
113+
_,
114+
SubregionOrigin::Subtype(box TypeTrace {
115+
cause,
116+
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
117+
}),
118+
sup_placeholder @ ty::RePlaceholder(_),
119+
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
120+
Some(self.tcx().mk_region(ty::ReVar(*vid))),
121+
cause,
122+
None,
123+
Some(*sup_placeholder),
124+
expected.def_id,
125+
expected.substs,
126+
found.substs,
127+
)),
128+
110129
Some(RegionResolutionError::ConcreteFailure(
111130
SubregionOrigin::Subtype(box TypeTrace {
112131
cause,

src/librustc/infer/freshen.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
130130
| ty::ReScope(_)
131131
| ty::ReVar(_)
132132
| ty::RePlaceholder(..)
133-
| ty::ReEmpty
133+
| ty::ReEmpty(_)
134134
| ty::ReErased => {
135135
// replace all free regions with 'erased
136136
self.tcx().lifetimes.re_erased

src/librustc/infer/higher_ranked/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
128128
placeholder_map: &PlaceholderMap<'tcx>,
129129
snapshot: &CombinedSnapshot<'_, 'tcx>,
130130
) -> RelateResult<'tcx, ()> {
131+
// If the user gave `-Zno-leak-check`, or we have been
132+
// configured to skip the leak check, then skip the leak check
133+
// completely. The leak check is deprecated. Any legitimate
134+
// subtyping errors that it would have caught will now be
135+
// caught later on, during region checking. However, we
136+
// continue to use it for a transition period.
137+
if self.tcx.sess.opts.debugging_opts.no_leak_check || self.skip_leak_check.get() {
138+
return Ok(());
139+
}
140+
131141
self.borrow_region_constraints().leak_check(
132142
self.tcx,
133143
overly_polymorphic,

0 commit comments

Comments
 (0)