simplify check_unique

This commit is contained in:
Ali MJ Al-Nasrawy 2024-03-22 08:02:12 +00:00
parent 6b6ed2ea28
commit 7c6876f9a9
10 changed files with 52 additions and 250 deletions

View File

@ -9,7 +9,6 @@ use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_macros::extension;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::RegionVid;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{GenericArgKind, GenericArgs};
use rustc_span::Span;
@ -23,73 +22,6 @@ use crate::universal_regions::RegionClassification;
use super::RegionInferenceContext;
impl<'tcx> RegionInferenceContext<'tcx> {
fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
let scc = self.constraint_sccs.scc(vid);
self.scc_values
.universal_regions_outlived_by(scc)
.find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?))
}
fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> {
let region = arg.as_region()?;
if let ty::RePlaceholder(..) = region.kind() {
None
} else {
Some(self.to_region_vid(region))
}
}
/// Check that all opaque types have the same region parameters if they have the same
/// non-region parameters. This is necessary because within the new solver we perform various query operations
/// modulo regions, and thus could unsoundly select some impls that don't hold.
fn check_unique(
&self,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) {
for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() {
for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) {
if a.def_id != b.def_id {
continue;
}
// Non-lifetime params differ -> ok
if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) {
continue;
}
trace!(?a, ?b);
for (a, b) in a.args.iter().zip(b.args) {
trace!(?a, ?b);
let Some(r1) = self.generic_arg_to_region(a) else {
continue;
};
let Some(r2) = self.generic_arg_to_region(b) else {
continue;
};
if self.eval_equal(r1, r2) {
continue;
}
// Ignore non-universal regions because they result in an error eventually.
// FIXME(aliemjay): This logic will be rewritten in a later commit.
let Some(r1) = self.universal_name(r1) else {
continue;
};
let Some(r2) = self.universal_name(r2) else {
continue;
};
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
arg: r1.into(),
prev: r2.into(),
span: a_ty.span,
prev_span: b_ty.span,
});
}
}
}
}
/// Resolve any opaque types that were encountered while borrow checking
/// this item. This is then used to get the type in the `type_of` query.
///
@ -139,9 +71,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
self.check_unique(infcx, &opaque_ty_decls);
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
FxIndexMap::default();
for (opaque_type_key, concrete_type) in opaque_ty_decls {
debug!(?opaque_type_key, ?concrete_type);
@ -228,6 +160,29 @@ impl<'tcx> RegionInferenceContext<'tcx> {
OpaqueHiddenType { ty, span: concrete_type.span },
);
}
// Check that all opaque types have the same region parameters if they have the same
// non-region parameters. This is necessary because within the new solver we perform
// various query operations modulo regions, and thus could unsoundly select some impls
// that don't hold.
if !ty.references_error()
&& let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
infcx.tcx.erase_regions(opaque_type_key),
(opaque_type_key, concrete_type.span),
)
&& let Some((arg1, arg2)) = std::iter::zip(
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
)
.find(|(arg1, arg2)| arg1 != arg2)
{
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
arg: arg1,
prev: arg2,
span: prev_span,
prev_span: concrete_type.span,
});
}
}
result
}

View File

@ -1,5 +1,5 @@
error[E0792]: expected generic lifetime parameter, found `'_`
--> $DIR/defining-use-captured-non-universal-region.rs:15:18
--> $DIR/defining-use-captured-non-universal-region.rs:14:18
|
LL | fn foo<'a>() -> impl Sized + 'a {
| -- this generic parameter must be used with a generic lifetime parameter

View File

@ -8,8 +8,7 @@
fn foo<'a>() -> impl Sized + 'a {
#[cfg(statik)]
let i: i32 = foo::<'static>();
//[statik]~^ ERROR opaque type used twice with different lifetimes
//[statik]~| ERROR opaque type used twice with different lifetimes
//[statik]~^ ERROR expected generic lifetime parameter, found `'static`
#[cfg(infer)]
let i: i32 = foo::<'_>();

View File

@ -1,33 +1,12 @@
error: opaque type used twice with different lifetimes
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^ lifetime `'static` used here
...
LL | i
| - lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
error[E0792]: expected generic lifetime parameter, found `'static`
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | fn foo<'a>() -> impl Sized + 'a {
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
LL | #[cfg(statik)]
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^ lifetime `'static` used here
...
LL | i
| - lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
|
LL | let i: i32 = foo::<'static>();
| ^^^^^^^^^^^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 2 previous errors
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0792`.

View File

@ -12,7 +12,7 @@ mod statik {
// invalid defining use: Opaque<'static> := ()
fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
let _: () = foo(Lt::<'static>::None);
//~^ ERROR opaque type used twice with different lifetimes
//~^ ERROR expected generic lifetime parameter, found `'static`
}
}
@ -31,7 +31,7 @@ mod equal {
// because of the use of equal lifetimes in args
fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
//~^ ERROR opaque type used twice with different lifetimes
//~^ ERROR non-defining opaque type use in defining scope
}
}

View File

@ -1,17 +1,8 @@
error: opaque type used twice with different lifetimes
--> $DIR/non-defining-use-lifetimes.rs:14:16
|
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
| ______________________________________________-
LL | | let _: () = foo(Lt::<'static>::None);
| | ^^ lifetime `'static` used here
LL | |
LL | | }
| |_____- lifetime `'a` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
error[E0792]: expected generic lifetime parameter, found `'static`
--> $DIR/non-defining-use-lifetimes.rs:14:16
|
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
LL | let _: () = foo(Lt::<'static>::None);
| ^^
@ -23,22 +14,17 @@ LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
LL | let _: () = foo(Lt::<'_>::None);
| ^^
error: opaque type used twice with different lifetimes
--> $DIR/non-defining-use-lifetimes.rs:33:16
|
LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
| __________________________________________________________________-
LL | | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
| | ^^ lifetime `'a` used here
LL | |
LL | | }
| |_____- lifetime `'b` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
error: non-defining opaque type use in defining scope
--> $DIR/non-defining-use-lifetimes.rs:33:16
|
LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
| ^^
|
note: lifetime used multiple times
--> $DIR/non-defining-use-lifetimes.rs:32:58
|
LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
| ^^ ^^
error: aborting due to 3 previous errors

View File

@ -5,7 +5,6 @@ type Foo<'a> = impl Sized;
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> (Foo<'a>, Foo<'b>) {
(x, y)
//~^ ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
}
type Bar<'a, 'b> = impl std::fmt::Debug;
@ -13,9 +12,6 @@ type Bar<'a, 'b> = impl std::fmt::Debug;
fn bar<'x, 'y>(i: &'x i32, j: &'y i32) -> (Bar<'x, 'y>, Bar<'y, 'x>) {
(i, j)
//~^ ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
}
fn main() {

View File

@ -14,23 +14,7 @@ LL | (x, y)
| ^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/lifetime_mismatch.rs:6:5
|
LL | (x, y)
| ^^^^^^
| |
| lifetime `'a` used here
| lifetime `'b` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/lifetime_mismatch.rs:6:5
|
LL | (x, y)
| ^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: opaque type used twice with different lifetimes
--> $DIR/lifetime_mismatch.rs:14:5
--> $DIR/lifetime_mismatch.rs:13:5
|
LL | (i, j)
| ^^^^^^
@ -39,57 +23,10 @@ LL | (i, j)
| lifetime `'y` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/lifetime_mismatch.rs:14:5
--> $DIR/lifetime_mismatch.rs:13:5
|
LL | (i, j)
| ^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
| |
| lifetime `'y` used here
| lifetime `'x` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
| |
| lifetime `'x` used here
| lifetime `'y` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: opaque type used twice with different lifetimes
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
| |
| lifetime `'y` used here
| lifetime `'x` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/lifetime_mismatch.rs:14:5
|
LL | (i, j)
| ^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 6 previous errors
error: aborting due to 2 previous errors

View File

@ -3,11 +3,8 @@
type Foo<'a, 'b> = impl std::fmt::Debug;
fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
(i, i)
(i, j)
//~^ ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
//~| ERROR opaque type used twice with different lifetimes
}
fn main() {}

View File

@ -1,7 +1,7 @@
error: opaque type used twice with different lifetimes
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
LL | (i, j)
| ^^^^^^
| |
| lifetime `'x` used here
@ -10,55 +10,8 @@ LL | (i, i)
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
LL | (i, j)
| ^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
| |
| lifetime `'y` used here
| lifetime `'x` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
error: opaque type used twice with different lifetimes
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
| |
| lifetime `'x` used here
| lifetime `'y` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: opaque type used twice with different lifetimes
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
| |
| lifetime `'y` used here
| lifetime `'x` previously used here
|
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
|
LL | (i, i)
| ^^^^^^
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 4 previous errors
error: aborting due to 1 previous error