From a725436c292c8a2b379b9b1d328af88585ab9a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 30 Aug 2023 13:51:09 +0000 Subject: [PATCH 1/5] return default `UniverseInfo` cause in `RegionInferenceContext` Query canonicalization can create local super-universes without causes, creating ICEs when accessed during diagnostics. --- compiler/rustc_borrowck/src/region_infer/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b8cd94e542242..1049e7a8bbe35 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -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. From f3a1bae88c617330b8956818da3cea256336c1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 30 Aug 2023 14:10:52 +0000 Subject: [PATCH 2/5] add test for issue 114907 --- .../missing-universe-cause-issue-114907.rs | 40 ++++++++++ ...missing-universe-cause-issue-114907.stderr | 79 +++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 tests/ui/nll/missing-universe-cause-issue-114907.rs create mode 100644 tests/ui/nll/missing-universe-cause-issue-114907.stderr diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.rs b/tests/ui/nll/missing-universe-cause-issue-114907.rs new file mode 100644 index 0000000000000..94acdccfcf254 --- /dev/null +++ b/tests/ui/nll/missing-universe-cause-issue-114907.rs @@ -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); +impl Role for HandshakeCallback { + type Inner = (); +} + +struct Handshake { + _inner: Option, +} +impl Drop for Handshake { + fn drop(&mut self) {} +} + +fn accept(_: C) -> Handshake> { + 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 +} diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr new file mode 100644 index 0000000000000..c3dd4257a7366 --- /dev/null +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -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) -> Handshake> { + | ^^^^^^^^^^^ +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 { + | ^^^^ +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`. From 407695132c64ce6dfb3d96b820c7f23b7f989601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 31 Aug 2023 11:10:54 +0000 Subject: [PATCH 3/5] remove dummy UniverseInfo causes from type checker `instantiate_canonical_with_fresh_inference_vars` This was backfilling causes for the new universes that can be created by the InferCtxt. We don't need to do that anymore: `other()` is the default when there is no registered universe cause. --- compiler/rustc_borrowck/src/type_check/canonical.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 16f5e68a06f55..b1ccaaae17c34 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -69,15 +69,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: TypeFoldable>, { - 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 } From ae963b560fba006d1ff7f9ca0ca95e660d36ef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 31 Aug 2023 11:16:35 +0000 Subject: [PATCH 4/5] remove dummy UniverseInfo causes from type checker `type_check` This was pre-filling causes for universes that could already exist in the InferCtxt. We don't need to do that anymore: `other()` is the default when there is no registered universe cause. --- compiler/rustc_borrowck/src/type_check/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3004291c3e75e..28286243e82f7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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, From 10ef8d9bf7b9acb921b335b48b9b7a3294fe178b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 31 Aug 2023 11:41:58 +0000 Subject: [PATCH 5/5] remove dummy UniverseInfo causes from type checker `fully_perform_op` This was backfilling causes for new universes that may have been created by an op, when there was no error info to use for improved diagnostics. We don't need to do that anymore: `other()` is the default when there is no registered universe cause. --- compiler/rustc_borrowck/src/type_check/canonical.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index b1ccaaae17c34..b7adc314f07b9 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -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}; @@ -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()); }