Skip to content

Commit

Permalink
Auto merge of #115384 - lqd:default-universe-info, r=matthewjasper
Browse files Browse the repository at this point in the history
Work around ICE in diagnostics for local super-universes missing `UniverseInfo`s

In issue #114907, canonicalization of liveness dropck-outlives results (IIUC) encounters universes absent from the original query.  Some local universes [are created](https://github.com/lqd/rust/blob/f3a1bae88c617330b8956818da3cea256336c1cf/compiler/rustc_infer/src/infer/canonical/query_response.rs#L417-L425) for the mapping, but importantly, they won't have associated causes.

These missing `UniverseInfo`s can be [needed](https://github.com/lqd/rust/blob/f3a1bae88c617330b8956818da3cea256336c1cf/compiler/rustc_borrowck/src/diagnostics/region_errors.rs#L376) during diagnostics, [causing the `IndexMap: key not found` ICE](https://github.com/lqd/rust/blob/d55522aad87c5605d7edd5dd4b37926e8b446117/compiler/rustc_borrowck/src/region_infer/mod.rs#L2252) seen in the issue.

This PR works around this by returning the suboptimal catch-all cause, to avoid the ICE. It does results in suboptimal diagnostics right now, but it's better than an ICE.

r? `@matthewjasper.`

Let me know if there's a good easy-ish way to fix this, but I believe that for some of these erroneous cases and diagnostics, that inference/canonicalization/higher-ranked subtyping/etc may not behave exactly the same with the new trait solver? If that's the case then it'd probably be best to wait a bit more to do the correct fix.

Fixes #114907.

cc `@aliemjay`
  • Loading branch information
bors committed Aug 31, 2023
2 parents b30b535 + 10ef8d9 commit 4b71f03
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 19 deletions.
9 changes: 8 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2249,7 +2249,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}

pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
self.universe_causes[&universe].clone()
// Query canonicalization can create local superuniverses (for example in
// `InferCtx::query_response_substitution_guess`), but they don't have an associated
// `UniverseInfo` explaining why they were created.
// This can cause ICEs if these causes are accessed in diagnostics, for example in issue
// #114907 where this happens via liveness and dropck outlives results.
// Therefore, we return a default value in case that happens, which should at worst emit a
// suboptimal error, instead of the ICE.
self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other())
}

/// Tries to find the terminator of the loop in which the region 'r' resides.
Expand Down
19 changes: 5 additions & 14 deletions compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use rustc_trait_selection::traits::ObligationCause;

use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
use crate::diagnostics::ToUniverseInfo;

use super::{Locations, NormalizeLocation, TypeChecker};

Expand Down Expand Up @@ -46,13 +46,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.push_region_constraints(locations, category, data);
}

// If the query has created new universes and errors are going to be emitted, register the
// cause of these new universes for improved diagnostics.
let universe = self.infcx.universe();

if old_universe != universe {
let universe_info = match error_info {
Some(error_info) => error_info.to_universe_info(old_universe),
None => UniverseInfo::other(),
};
if old_universe != universe && let Some(error_info) = error_info {
let universe_info = error_info.to_universe_info(old_universe);
for u in (old_universe + 1)..=universe {
self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
}
Expand All @@ -69,15 +67,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
let old_universe = self.infcx.universe();

let (instantiated, _) =
self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);

for u in (old_universe + 1)..=self.infcx.universe() {
self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
}

instantiated
}

Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,6 @@ pub(crate) fn type_check<'mir, 'tcx>(

debug!(?normalized_inputs_and_output);

for u in ty::UniverseIndex::ROOT..=infcx.universe() {
constraints.universe_causes.insert(u, UniverseInfo::other());
}

let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
Expand Down
40 changes: 40 additions & 0 deletions tests/ui/nll/missing-universe-cause-issue-114907.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// This is a non-regression test for issue #114907 where an ICE happened because of missing
// `UniverseInfo`s accessed during diagnostics.
//
// A couple notes:
// - the `FnOnce` bounds need an arg that is a reference
// - a custom `Drop` is needed somewhere in the type that `accept` returns, to create universes
// during liveness and dropck outlives computation

// check-fail

trait Role {
type Inner;
}

struct HandshakeCallback<C>(C);
impl<C: FnOnce(&())> Role for HandshakeCallback<C> {
type Inner = ();
}

struct Handshake<R: Role> {
_inner: Option<R::Inner>,
}
impl<R: Role> Drop for Handshake<R> {
fn drop(&mut self) {}
}

fn accept<C: FnOnce(&())>(_: C) -> Handshake<HandshakeCallback<C>> {
todo!()
}

fn main() {
let callback = |_| {};
accept(callback);
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR higher-ranked subtype error
//~| ERROR higher-ranked subtype error
}
79 changes: 79 additions & 0 deletions tests/ui/nll/missing-universe-cause-issue-114907.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
error[E0308]: mismatched types
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> FnOnce<(&'a (),)>`
found trait `FnOnce<(&(),)>`
note: this closure does not fulfill the lifetime requirements
--> $DIR/missing-universe-cause-issue-114907.rs:32:20
|
LL | let callback = |_| {};
| ^^^
note: the lifetime requirement is introduced here
--> $DIR/missing-universe-cause-issue-114907.rs:27:14
|
LL | fn accept<C: FnOnce(&())>(_: C) -> Handshake<HandshakeCallback<C>> {
| ^^^^^^^^^^^
help: consider specifying the type of the closure parameters
|
LL | let callback = |_: &_| {};
| ~~~~~~~

error: implementation of `FnOnce` is not general enough
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 ())` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`

error[E0308]: mismatched types
--> $DIR/missing-universe-cause-issue-114907.rs:33:5
|
LL | accept(callback);
| ^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'a> FnOnce<(&'a (),)>`
found trait `FnOnce<(&(),)>`
note: this closure does not fulfill the lifetime requirements
--> $DIR/missing-universe-cause-issue-114907.rs:32:20
|
LL | let callback = |_| {};
| ^^^
note: the lifetime requirement is introduced here
--> $DIR/missing-universe-cause-issue-114907.rs:20:21
|
LL | struct Handshake<R: Role> {
| ^^^^
help: consider specifying the type of the closure parameters
|
LL | let callback = |_: &_| {};
| ~~~~~~~

error: higher-ranked subtype error
--> $DIR/missing-universe-cause-issue-114907.rs:33:21
|
LL | accept(callback);
| ^

error: higher-ranked subtype error
--> $DIR/missing-universe-cause-issue-114907.rs:33:21
|
LL | accept(callback);
| ^

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 4b71f03

Please sign in to comment.