From 92f40b8059096c8cc868c1116a31a6d2eea8bc71 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Thu, 21 Mar 2024 03:04:49 +0000 Subject: [PATCH 01/12] fix ICE in check_unique --- .../src/region_infer/opaque_types.rs | 13 +++++++++++-- .../ui/type-alias-impl-trait/param_mismatch4.rs | 16 ++++++++++++++++ .../type-alias-impl-trait/param_mismatch4.stderr | 12 ++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/param_mismatch4.rs create mode 100644 tests/ui/type-alias-impl-trait/param_mismatch4.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d5875a226fe02..49f7242cd8349 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -69,9 +69,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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: self.universal_name(r1).unwrap().into(), - prev: self.universal_name(r2).unwrap().into(), + arg: r1.into(), + prev: r2.into(), span: a_ty.span, prev_span: b_ty.span, }); diff --git a/tests/ui/type-alias-impl-trait/param_mismatch4.rs b/tests/ui/type-alias-impl-trait/param_mismatch4.rs new file mode 100644 index 0000000000000..e072f3ab8e05b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/param_mismatch4.rs @@ -0,0 +1,16 @@ +//! This test checks that when checking for opaque types that +//! only differ in lifetimes, we handle the case of non-generic +//! regions correctly. +#![feature(type_alias_impl_trait)] + +type Opq<'a> = impl Sized; + +// Two defining uses: Opq<'{empty}> and Opq<'a>. +// This used to ICE. +// issue: #122782 +fn build<'a>() -> Opq<'a> { + let _: Opq<'_> = (); + //~^ ERROR expected generic lifetime parameter, found `'_` +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/param_mismatch4.stderr b/tests/ui/type-alias-impl-trait/param_mismatch4.stderr new file mode 100644 index 0000000000000..d3fdea25a3dc4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/param_mismatch4.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/param_mismatch4.rs:12:12 + | +LL | type Opq<'a> = impl Sized; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let _: Opq<'_> = (); + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. From 4e1999d3870c7be9a4addcfcf4fd5db9d29b7d1c Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 18 Mar 2024 08:33:24 +0000 Subject: [PATCH 02/12] ignore uncaptured lifetimes when checking opaques --- .../src/region_infer/opaque_types.rs | 23 +++--- compiler/rustc_middle/src/ty/mod.rs | 32 ++++++++ ...g-use-uncaptured-non-universal-region-2.rs | 74 +++++++++++++++++++ ...g-use-uncaptured-non-universal-region-3.rs | 13 ++++ ...ing-use-uncaptured-non-universal-region.rs | 16 ++++ ...erased-regions-in-hidden-ty.current.stderr | 2 +- .../erased-regions-in-hidden-ty.next.stderr | 2 +- .../impl-trait/erased-regions-in-hidden-ty.rs | 2 +- ...ariant-duplicate-lifetime-unconstrained.rs | 18 +++++ .../escaping-bound-var.rs | 4 + .../escaping-bound-var.stderr | 14 +++- 11 files changed, 183 insertions(+), 17 deletions(-) create mode 100644 tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs create mode 100644 tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs create mode 100644 tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs create mode 100644 tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 49f7242cd8349..4958e2c1ade43 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -179,7 +179,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Next, insert universal regions from args, so we can translate regions that appear // in them but are not subject to member constraints, for instance closure args. - let universal_args = infcx.tcx.fold_regions(args, |region, _| { + let universal_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { if let ty::RePlaceholder(..) = region.kind() { // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args. return region; @@ -187,6 +187,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let vid = self.to_region_vid(region); to_universal_region(vid, &mut arg_regions) }); + let universal_args = universal_key.args; debug!(?universal_args); debug!(?arg_regions); @@ -431,23 +432,21 @@ fn check_opaque_type_well_formed<'tcx>( } } -fn check_opaque_type_parameter_valid( - tcx: TyCtxt<'_>, - opaque_type_key: OpaqueTypeKey<'_>, +fn check_opaque_type_parameter_valid<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, ) -> Result<(), ErrorGuaranteed> { let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); - let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin { + let (_parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin { OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true), OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false), }; - let parent_generics = tcx.generics_of(parent); + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); - // Only check the parent generics, which will ignore any of the - // duplicated lifetime args that come from reifying late-bounds. - for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() { + for (i, arg) in opaque_type_key.iter_captured_args(tcx) { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) if is_ty_alias => { @@ -464,7 +463,7 @@ fn check_opaque_type_parameter_valid( seen_params.entry(arg).or_default().push(i); } else { // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = parent_generics.param_at(i, tcx); + let opaque_param = opaque_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { @@ -478,10 +477,10 @@ fn check_opaque_type_parameter_valid( for (_, indices) in seen_params { if indices.len() > 1 { - let descr = parent_generics.param_at(indices[0], tcx).kind.descr(); + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); let spans: Vec<_> = indices .into_iter() - .map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id)) + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) .collect(); #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ce53ccc8cd7a..0be1a1ab39d69 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -832,6 +832,38 @@ pub struct OpaqueTypeKey<'tcx> { pub args: GenericArgsRef<'tcx>, } +impl<'tcx> OpaqueTypeKey<'tcx> { + pub fn iter_captured_args( + self, + tcx: TyCtxt<'tcx>, + ) -> impl Iterator)> { + std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map( + |(i, (arg, v))| match (arg.unpack(), v) { + (_, ty::Invariant) => Some((i, arg)), + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, + _ => bug!("unexpected opaque type arg variance"), + }, + ) + } + + pub fn fold_captured_lifetime_args( + self, + tcx: TyCtxt<'tcx>, + mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>, + ) -> Self { + let Self { def_id, args } = self; + let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { + match (arg.unpack(), v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), + _ => arg, + } + }); + let args = tcx.mk_args_from_iter(args); + Self { def_id, args } + } +} + #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs new file mode 100644 index 0000000000000..56e099c28d219 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs @@ -0,0 +1,74 @@ +// issue: #110623 +//@ check-pass + +use std::{collections::BTreeMap, num::ParseIntError, str::FromStr}; + +enum FileSystem { + File(usize), + Directory(BTreeMap), +} + +impl FromStr for FileSystem { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result { + if s.starts_with("dir") { + Ok(Self::new_dir()) + } else { + Ok(Self::File(s.split_whitespace().next().unwrap().parse()?)) + } + } +} + +impl FileSystem { + fn new_dir() -> FileSystem { + FileSystem::Directory(BTreeMap::new()) + } + + fn insert(&mut self, name: String, other: FileSystem) -> Option { + match self { + FileSystem::File(_) => panic!("can only insert into directory!"), + FileSystem::Directory(tree) => tree.insert(name, other), + } + } + + // Recursively build a tree from commands. This uses (abuses?) + // the fact that `cd /` only appears at the start and that + // subsequent `cd`s can only move ONE level to use the recursion + // stack as the filesystem stack + fn build<'a>( + &mut self, + mut commands: impl Iterator + 'a, + ) -> Option + 'a> { + let cmd = commands.next()?; + let mut elements = cmd.lines(); + match elements.next().map(str::trim) { + Some("cd /") | None => self.build(commands), + Some("cd ..") => { + // return to higher scope + Some(commands) + } + Some("ls") => { + for item in elements { + let name = item.split_whitespace().last().unwrap(); + let prior = self.insert(name.to_string(), item.parse().unwrap()); + debug_assert!(prior.is_none()); + } + // continue on + self.build(commands) + } + Some(other_cd) => { + let name = other_cd + .trim() + .strip_prefix("cd ") + .expect("expected a cd command"); + let mut directory = FileSystem::new_dir(); + let further_commands = directory.build(commands); + self.insert(name.to_string(), directory); + self.build(further_commands?) // THIS LINE FAILS TO COMPILE + } + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs new file mode 100644 index 0000000000000..a6dcad3face0a --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar<"asdf"> for () {} + +fn foo() -> impl Bar<"asdf"> { + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs new file mode 100644 index 0000000000000..f90ff51c651aa --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs @@ -0,0 +1,16 @@ +// issue: #111906 +//@ check-pass + +#![allow(unconditional_recursion)] + +fn foo<'a: 'a>() -> impl Sized { + let _: () = foo::<'a>(); + loop {} +} + +fn bar<'a: 'a>() -> impl Sized + 'a { + let _: *mut &'a () = bar::<'a>(); + loop {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr index 1d648162113f3..78ef8ec404c9b 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr @@ -1,4 +1,4 @@ -error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo<'{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:12:36 | LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr index 1d648162113f3..78ef8ec404c9b 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr @@ -1,4 +1,4 @@ -error: {foo::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo<'{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:12:36 | LL | fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs index 9d71685f179e4..e60f1badcae0f 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs @@ -10,7 +10,7 @@ // Make sure that the compiler can handle `ReErased` in the hidden type of an opaque. fn foo<'a: 'a>(x: &'a Vec) -> impl Fn() + 'static { - //~^ ERROR 'a/#0>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} + //~^ ERROR '{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} // Can't write whole type because of lack of path sanitization || () } diff --git a/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs b/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs new file mode 100644 index 0000000000000..3b83b2e544b01 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs @@ -0,0 +1,18 @@ +// The defining use below has an unconstrained lifetime argument. +// Opaque<'{empty}, 'a> := (); +// Make sure we accept it because the lifetime parameter in such position is +// irrelevant - it is an artifact of how we internally represent opaque +// generics. +// See issue #122307 for details. + +//@ check-pass +#![feature(type_alias_impl_trait)] +#![allow(unconditional_recursion)] + +type Opaque<'a> = impl Sized + 'a; + +fn test<'a>() -> Opaque<'a> { + let _: () = test::<'a>(); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index 1ff200680be5e..4abd6b75ae6bd 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -17,6 +17,10 @@ impl Test<'_> for () {} fn constrain() -> Foo { () + //~^ ERROR expected generic lifetime parameter, found `'static` + // FIXME(aliemjay): Undesirable error message appears because error regions + // are converterted internally into `'?0` which corresponds to `'static` + // This should be fixed in a later commit. } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index 09f6fba79cfdf..b903b9f915146 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -10,6 +10,16 @@ note: lifetime declared here LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; | ^^ -error: aborting due to 1 previous error +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/escaping-bound-var.rs:19:5 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +... +LL | () + | ^^ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0657`. +Some errors have detailed explanations: E0657, E0792. +For more information about an error, try `rustc --explain E0657`. From 4ecdf5ff00a9af18160bc7214cbcb8a6a1e01d10 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sat, 21 Oct 2023 16:28:51 +0000 Subject: [PATCH 03/12] except equal parameters from the uniqueness check --- .../src/region_infer/opaque_types.rs | 98 ++++++++++++++++++- tests/ui/error-codes/E0657.rs | 2 + tests/ui/error-codes/E0657.stderr | 27 ++++- .../rpit/non-defining-use-lifetimes.rs | 38 +++++++ .../rpit/non-defining-use-lifetimes.stderr | 36 +++++++ .../equal-lifetime-params-ok.rs | 50 ++++++++++ 6 files changed, 246 insertions(+), 5 deletions(-) create mode 100644 tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs create mode 100644 tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr create mode 100644 tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4958e2c1ade43..0474dd18d4555 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -432,6 +432,10 @@ fn check_opaque_type_well_formed<'tcx>( } } +/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. +/// +/// [rustc-dev-guide chapter]: +/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html fn check_opaque_type_parameter_valid<'tcx>( tcx: TyCtxt<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, @@ -444,6 +448,7 @@ fn check_opaque_type_parameter_valid<'tcx>( }; let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); for (i, arg) in opaque_type_key.iter_captured_args(tcx) { @@ -451,6 +456,7 @@ fn check_opaque_type_parameter_valid<'tcx>( GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) if is_ty_alias => { matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) + || (lt.is_static() && opaque_env.param_equal_static(i)) } // FIXME(#113916): we can't currently check for unique lifetime params, // see that issue for more. We will also have to ignore unused lifetime @@ -460,7 +466,13 @@ fn check_opaque_type_parameter_valid<'tcx>( }; if arg_is_param { - seen_params.entry(arg).or_default().push(i); + // Register if the same lifetime appears multiple times in the generic args. + // There is an exception when the opaque type *requires* the lifetimes to be equal. + // See [rustc-dev-guide chapter] § "An exception to uniqueness rule". + let seen_where = seen_params.entry(arg).or_default(); + if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) { + seen_where.push(i); + } } else { // Prevent `fn foo() -> Foo` from being defining. let opaque_param = opaque_generics.param_at(i, tcx); @@ -494,3 +506,87 @@ fn check_opaque_type_parameter_valid<'tcx>( Ok(()) } + +/// Computes if an opaque type requires a lifetime parameter to be equal to +/// another one or to the `'static` lifetime. +/// These requirements are derived from the explicit and implied bounds. +struct LazyOpaqueTyEnv<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + + /// Equal parameters will have the same name. Computed Lazily. + /// Example: + /// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;` + /// Identity args: `['a, 'b, 'c]` + /// Canonical args: `['static, 'b, 'b]` + canonical_args: std::cell::OnceCell>, +} + +impl<'tcx> LazyOpaqueTyEnv<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() } + } + + pub fn param_equal_static(&self, param_index: usize) -> bool { + self.get_canonical_args()[param_index].expect_region().is_static() + } + + pub fn params_equal(&self, param1: usize, param2: usize) -> bool { + let canonical_args = self.get_canonical_args(); + canonical_args[param1] == canonical_args[param2] + } + + fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { + use rustc_hir as hir; + use rustc_infer::infer::outlives::env::OutlivesEnvironment; + use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; + + if let Some(&canonical_args) = self.canonical_args.get() { + return canonical_args; + } + + let &Self { tcx, def_id, .. } = self; + let origin = tcx.opaque_type_origin(def_id); + let parent = match origin { + hir::OpaqueTyOrigin::FnReturn(parent) + | hir::OpaqueTyOrigin::AsyncFn(parent) + | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, + }; + let param_env = tcx.param_env(parent); + let args = GenericArgs::identity_for_item(tcx, parent).extend_to( + tcx, + def_id.to_def_id(), + |param, _| { + tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into() + }, + ); + + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + + let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { + tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds"); + Default::default() + }); + let implied_bounds = infcx.implied_bounds_tys(param_env, parent, &wf_tys); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + + let mut seen = vec![tcx.lifetimes.re_static]; + let canonical_args = tcx.fold_regions(args, |r1, _| { + if r1.is_error() { + r1 + } else if let Some(&r2) = seen.iter().find(|&&r2| { + let free_regions = outlives_env.free_region_map(); + free_regions.sub_free_regions(tcx, r1, r2) + && free_regions.sub_free_regions(tcx, r2, r1) + }) { + r2 + } else { + seen.push(r1); + r1 + } + }); + self.canonical_args.set(canonical_args).unwrap(); + canonical_args + } +} diff --git a/tests/ui/error-codes/E0657.rs b/tests/ui/error-codes/E0657.rs index 212c1d9e581a2..d70c0b334fa84 100644 --- a/tests/ui/error-codes/E0657.rs +++ b/tests/ui/error-codes/E0657.rs @@ -11,6 +11,7 @@ fn free_fn_capture_hrtb_in_impl_trait() //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type { Box::new(()) + //~^ ERROR expected generic lifetime parameter, found `'static` } struct Foo; @@ -20,6 +21,7 @@ impl Foo { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type { Box::new(()) + //~^ ERROR expected generic lifetime parameter, found `'static` } } diff --git a/tests/ui/error-codes/E0657.stderr b/tests/ui/error-codes/E0657.stderr index c539007cdcf19..28b989aa429da 100644 --- a/tests/ui/error-codes/E0657.stderr +++ b/tests/ui/error-codes/E0657.stderr @@ -10,18 +10,37 @@ note: lifetime declared here LL | -> Box Id>> | ^^ +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/E0657.rs:13:5 + | +LL | -> Box Id>> + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +... +LL | Box::new(()) + | ^^^^^^^^^^^^ + error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - --> $DIR/E0657.rs:19:35 + --> $DIR/E0657.rs:20:35 | LL | -> Box Id>> | ^^ | note: lifetime declared here - --> $DIR/E0657.rs:19:20 + --> $DIR/E0657.rs:20:20 | LL | -> Box Id>> | ^^ -error: aborting due to 2 previous errors +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/E0657.rs:23:9 + | +LL | -> Box Id>> + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +... +LL | Box::new(()) + | ^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0657`. +Some errors have detailed explanations: E0657, E0792. +For more information about an error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs new file mode 100644 index 0000000000000..aa60ec27e00a3 --- /dev/null +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs @@ -0,0 +1,38 @@ +// issue: #111935 +// FIXME(aliemjay): outdated due to "once modulo regions" restriction. +// FIXME(aliemjay): mod `infer` should fail. + +#![allow(unconditional_recursion)] + +// Lt indirection is necessary to make the lifetime of the function late-bound, +// in order to bypass some other bugs. +type Lt<'lt> = Option<*mut &'lt ()>; + +mod statik { + use super::*; + // 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 + } +} + +mod infer { + use super::*; + // invalid defining use: Opaque<'_> := () + fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + let _: () = foo(Lt::<'_>::None); + } +} + +mod equal { + use super::*; + // invalid defining use: Opaque<'a, 'a> := () + // 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 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr new file mode 100644 index 0000000000000..fe6bf71abdbd3 --- /dev/null +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr @@ -0,0 +1,36 @@ +error: opaque type used twice with different lifetimes + --> $DIR/non-defining-use-lifetimes.rs:15: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 + --> $DIR/non-defining-use-lifetimes.rs:15:16 + | +LL | let _: () = foo(Lt::<'static>::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 + --> $DIR/non-defining-use-lifetimes.rs:33:16 + | +LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None); + | ^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs new file mode 100644 index 0000000000000..6e3f72a1ebe44 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs @@ -0,0 +1,50 @@ +// FIXME: description +// issue: #113916 +//@ check-pass + +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +mod equal_params { + type Opaque<'a: 'b, 'b: 'a> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> { + let _ = None::<&'a &'b &'a ()>; + 0u8 + } +} + +mod equal_static { + type Opaque<'a: 'static> = impl Sized + 'a; + fn test<'a: 'static>() -> Opaque<'a> { + let _ = None::<&'static &'a ()>; + 0u8 + } +} + +mod implied_bounds { + trait Traitor { + type Assoc; + fn define(self) -> Self::Assoc; + } + + impl<'a> Traitor for &'static &'a () { + type Assoc = impl Sized + 'a; + fn define(self) -> Self::Assoc { + let _ = None::<&'static &'a ()>; + 0u8 + } + } + + impl<'a, 'b> Traitor for (&'a &'b (), &'b &'a ()) { + type Assoc = impl Sized + 'a + 'b; + fn define(self) -> Self::Assoc { + let _ = None::<(&'a &'b (), &'b &'a ())>; + 0u8 + } + } +} + +fn main() {} From c337825d6dae4b2ada4b358b95aa6ee730a49677 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Tue, 19 Mar 2024 19:23:47 +0000 Subject: [PATCH 04/12] ignore error params --- .../src/region_infer/opaque_types.rs | 8 ++++++ tests/ui/error-codes/E0657.rs | 2 -- tests/ui/error-codes/E0657.stderr | 27 +++---------------- .../escaping-bound-var.rs | 4 --- .../escaping-bound-var.stderr | 14 ++-------- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 0474dd18d4555..84bacabc14eea 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -478,6 +478,10 @@ fn check_opaque_type_parameter_valid<'tcx>( let opaque_param = opaque_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); + if let Err(guar) = opaque_env.param_is_error(i) { + return Err(guar); + } + return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { ty: arg, kind, @@ -536,6 +540,10 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { canonical_args[param1] == canonical_args[param2] } + pub fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> { + self.get_canonical_args()[param_index].error_reported() + } + fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; diff --git a/tests/ui/error-codes/E0657.rs b/tests/ui/error-codes/E0657.rs index d70c0b334fa84..212c1d9e581a2 100644 --- a/tests/ui/error-codes/E0657.rs +++ b/tests/ui/error-codes/E0657.rs @@ -11,7 +11,6 @@ fn free_fn_capture_hrtb_in_impl_trait() //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type { Box::new(()) - //~^ ERROR expected generic lifetime parameter, found `'static` } struct Foo; @@ -21,7 +20,6 @@ impl Foo { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type { Box::new(()) - //~^ ERROR expected generic lifetime parameter, found `'static` } } diff --git a/tests/ui/error-codes/E0657.stderr b/tests/ui/error-codes/E0657.stderr index 28b989aa429da..c539007cdcf19 100644 --- a/tests/ui/error-codes/E0657.stderr +++ b/tests/ui/error-codes/E0657.stderr @@ -10,37 +10,18 @@ note: lifetime declared here LL | -> Box Id>> | ^^ -error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/E0657.rs:13:5 - | -LL | -> Box Id>> - | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type -... -LL | Box::new(()) - | ^^^^^^^^^^^^ - error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - --> $DIR/E0657.rs:20:35 + --> $DIR/E0657.rs:19:35 | LL | -> Box Id>> | ^^ | note: lifetime declared here - --> $DIR/E0657.rs:20:20 + --> $DIR/E0657.rs:19:20 | LL | -> Box Id>> | ^^ -error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/E0657.rs:23:9 - | -LL | -> Box Id>> - | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type -... -LL | Box::new(()) - | ^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0657, E0792. -For more information about an error, try `rustc --explain E0657`. +For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index 4abd6b75ae6bd..1ff200680be5e 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -17,10 +17,6 @@ impl Test<'_> for () {} fn constrain() -> Foo { () - //~^ ERROR expected generic lifetime parameter, found `'static` - // FIXME(aliemjay): Undesirable error message appears because error regions - // are converterted internally into `'?0` which corresponds to `'static` - // This should be fixed in a later commit. } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index b903b9f915146..09f6fba79cfdf 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -10,16 +10,6 @@ note: lifetime declared here LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; | ^^ -error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/escaping-bound-var.rs:19:5 - | -LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; - | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type -... -LL | () - | ^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0657, E0792. -For more information about an error, try `rustc --explain E0657`. +For more information about this error, try `rustc --explain E0657`. From ce91e46a1e9ad5126df1128068113d6f2d618827 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Mon, 18 Mar 2024 16:03:18 +0000 Subject: [PATCH 05/12] check RPITs for invalid args --- .../src/region_infer/opaque_types.rs | 12 +------ ...captured-non-universal-region.infer.stderr | 12 +++++++ ...ining-use-captured-non-universal-region.rs | 24 ++++++++++++++ ...aptured-non-universal-region.statik.stderr | 33 +++++++++++++++++++ .../impl-fn-predefined-lifetimes.rs | 4 +-- .../impl-fn-predefined-lifetimes.stderr | 24 ++++---------- .../bad-item-bound-within-rpitit-2.rs | 1 + .../bad-item-bound-within-rpitit-2.stderr | 13 ++++++-- tests/ui/impl-trait/rpit/early_bound.rs | 1 + tests/ui/impl-trait/rpit/early_bound.stderr | 12 ++++++- .../rpit/non-defining-use-lifetimes.rs | 2 +- .../rpit/non-defining-use-lifetimes.stderr | 15 +++++++-- .../type-alias-impl-trait/hkl_forbidden4.rs | 1 + .../hkl_forbidden4.stderr | 27 ++++++++++----- 14 files changed, 134 insertions(+), 47 deletions(-) create mode 100644 tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr create mode 100644 tests/ui/impl-trait/defining-use-captured-non-universal-region.rs create mode 100644 tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 84bacabc14eea..dbf55db6e6b40 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -441,12 +441,6 @@ fn check_opaque_type_parameter_valid<'tcx>( opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, ) -> Result<(), ErrorGuaranteed> { - let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); - let (_parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin { - OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true), - OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false), - }; - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); @@ -454,14 +448,10 @@ fn check_opaque_type_parameter_valid<'tcx>( for (i, arg) in opaque_type_key.iter_captured_args(tcx) { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if is_ty_alias => { + GenericArgKind::Lifetime(lt) => { matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) || (lt.is_static() && opaque_env.param_equal_static(i)) } - // FIXME(#113916): we can't currently check for unique lifetime params, - // see that issue for more. We will also have to ignore unused lifetime - // params for RPIT, but that's comparatively trivial ✨ - GenericArgKind::Lifetime(_) => continue, GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), }; diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr new file mode 100644 index 0000000000000..ec062abb2fc6f --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defining-use-captured-non-universal-region.rs:15:18 + | +LL | fn foo<'a>() -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let i: i32 = foo::<'_>(); + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs new file mode 100644 index 0000000000000..4f72333e65e89 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs @@ -0,0 +1,24 @@ +// This was an ICE. See #110726. +// FIXME(aliemjay): outdated due to "once modulo regions" restriction. + +//@ revisions: statik infer fixed +//@ [fixed] check-pass +#![allow(unconditional_recursion)] + +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 + + #[cfg(infer)] + let i: i32 = foo::<'_>(); + //[infer]~^ ERROR expected generic lifetime parameter, found `'_` + + #[cfg(fixed)] + let i: i32 = foo::<'a>(); + + i +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr new file mode 100644 index 0000000000000..b44f9ca69442a --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr @@ -0,0 +1,33 @@ +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>(); + | ^^^^^^^^^^^^^^^^ + +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 + diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs index 1577866237544..199cbbf4fcc9b 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -2,10 +2,8 @@ use std::fmt::Debug; fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - //~^ ERROR cannot resolve opaque type - |x| x - //~^ ERROR concrete type differs from previous defining opaque type use + //~^ ERROR expected generic lifetime parameter, found `'_` } fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) { diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index c19420bbb0ceb..6064b09ef0927 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -1,21 +1,11 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/impl-fn-predefined-lifetimes.rs:7:9 - | -LL | |x| x - | ^ expected `impl Debug + '_`, got `&u8` - | -note: previous use here - --> $DIR/impl-fn-predefined-lifetimes.rs:7:5 - | -LL | |x| x - | ^^^^^ - -error[E0720]: cannot resolve opaque type - --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/impl-fn-predefined-lifetimes.rs:5:9 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ cannot resolve opaque type + | -- this generic parameter must be used with a generic lifetime parameter +LL | |x| x + | ^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs index 41d5f0f64498d..5b3a4eb53ff15 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs @@ -5,6 +5,7 @@ trait Foo { fn bar<'other: 'a>() -> impl Sized + 'a {} //~^ ERROR use of undeclared lifetime name `'a` //~| ERROR use of undeclared lifetime name `'a` + //~| ERROR expected generic lifetime parameter, found `'static` } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr index b0832eb33ca74..8975578dabd84 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr @@ -28,6 +28,15 @@ help: consider introducing lifetime `'a` here LL | trait Foo<'a> { | ++++ -error: aborting due to 2 previous errors +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/bad-item-bound-within-rpitit-2.rs:5:45 + | +LL | fn bar<'other: 'a>() -> impl Sized + 'a {} + | ------ ^^ + | | + | cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0792. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/rpit/early_bound.rs b/tests/ui/impl-trait/rpit/early_bound.rs index 6dda687929c4d..005bcea59f243 100644 --- a/tests/ui/impl-trait/rpit/early_bound.rs +++ b/tests/ui/impl-trait/rpit/early_bound.rs @@ -5,6 +5,7 @@ fn test<'a: 'a>(n: bool) -> impl Sized + 'a { let true = n else { loop {} }; let _ = || { let _ = identity::<&'a ()>(test(false)); + //~^ ERROR expected generic lifetime parameter, found `'_` }; loop {} } diff --git a/tests/ui/impl-trait/rpit/early_bound.stderr b/tests/ui/impl-trait/rpit/early_bound.stderr index 780dea4e284ee..b0c7bd4199cc2 100644 --- a/tests/ui/impl-trait/rpit/early_bound.stderr +++ b/tests/ui/impl-trait/rpit/early_bound.stderr @@ -1,3 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/early_bound.rs:7:17 + | +LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let _ = identity::<&'a ()>(test(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: concrete type differs from previous defining opaque type use --> $DIR/early_bound.rs:3:29 | @@ -10,5 +19,6 @@ note: previous use here LL | let _ = identity::<&'a ()>(test(false)); | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs index aa60ec27e00a3..923b194d48384 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs @@ -1,6 +1,5 @@ // issue: #111935 // FIXME(aliemjay): outdated due to "once modulo regions" restriction. -// FIXME(aliemjay): mod `infer` should fail. #![allow(unconditional_recursion)] @@ -22,6 +21,7 @@ mod infer { // invalid defining use: Opaque<'_> := () fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { let _: () = foo(Lt::<'_>::None); + //~^ ERROR expected generic lifetime parameter, found `'_` } } diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr index fe6bf71abdbd3..e0122d32abe55 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr @@ -1,5 +1,5 @@ error: opaque type used twice with different lifetimes - --> $DIR/non-defining-use-lifetimes.rs:15:16 + --> $DIR/non-defining-use-lifetimes.rs:14:16 | LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { | ______________________________________________- @@ -10,11 +10,19 @@ 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 - --> $DIR/non-defining-use-lifetimes.rs:15:16 + --> $DIR/non-defining-use-lifetimes.rs:14:16 | LL | let _: () = foo(Lt::<'static>::None); | ^^ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/non-defining-use-lifetimes.rs:23:16 + | +LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +LL | let _: () = foo(Lt::<'_>::None); + | ^^ + error: opaque type used twice with different lifetimes --> $DIR/non-defining-use-lifetimes.rs:33:16 | @@ -32,5 +40,6 @@ note: if all non-lifetime generic parameters are the same, but the lifetime para LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None); | ^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs index ef9fe604ea783..3b54fb7ea999f 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs @@ -13,6 +13,7 @@ type FutNothing<'a> = impl 'a + Future; async fn operation(_: &mut ()) -> () { //~^ ERROR: concrete type differs from previous call(operation).await + //~^ ERROR: expected generic lifetime parameter, found `'any` } async fn call(_f: F) diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr index cd4982b24809a..c41ed0642a46c 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -6,20 +6,17 @@ LL | type FutNothing<'a> = impl 'a + Future; | = note: `FutNothing` must be used in combination with a concrete type within the same module -error: concrete type differs from previous defining opaque type use - --> $DIR/hkl_forbidden4.rs:13:1 - | -LL | async fn operation(_: &mut ()) -> () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}` - | -note: previous use here +error[E0792]: expected generic lifetime parameter, found `'any` --> $DIR/hkl_forbidden4.rs:15:5 | +LL | async fn operation(_: &mut ()) -> () { + | - this generic parameter must be used with a generic lifetime parameter +LL | LL | call(operation).await | ^^^^^^^^^^^^^^^ error[E0792]: expected generic lifetime parameter, found `'any` - --> $DIR/hkl_forbidden4.rs:21:1 + --> $DIR/hkl_forbidden4.rs:22:1 | LL | type FutNothing<'a> = impl 'a + Future; | -- this generic parameter must be used with a generic lifetime parameter @@ -29,6 +26,18 @@ LL | | LL | | } | |_^ -error: aborting due to 3 previous errors +error: concrete type differs from previous defining opaque type use + --> $DIR/hkl_forbidden4.rs:13:1 + | +LL | async fn operation(_: &mut ()) -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}` + | +note: previous use here + --> $DIR/hkl_forbidden4.rs:15:5 + | +LL | call(operation).await + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0792`. From 15c7e59c05d14be214ded1f8fe703bfb0c14ffa0 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 18 Oct 2023 09:04:13 +0000 Subject: [PATCH 06/12] favor placeholders over existentials when choosing SCC representatives ... even when the existential has the least RegionVid. universal regions (of root universe) > placeholders > existentials The previous behavior, that chooses the minimal RegionVid index, naturally prefers universal regions over others because they always have the least RegionVids, but there was no guranteed ordering between placeholders and existentials. --- .../rustc_borrowck/src/region_infer/mod.rs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 54c516c960c1f..599f7dd18c3ea 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -95,9 +95,11 @@ pub struct RegionInferenceContext<'tcx> { /// visible from this index. scc_universes: IndexVec, - /// Contains a "representative" from each SCC. This will be the - /// minimal RegionVid belonging to that universe. It is used as a - /// kind of hacky way to manage checking outlives relationships, + /// Contains the "representative" region of each SCC. + /// It is defined as the one with the minimal RegionVid, favoring + /// free regions, then placeholders, then existential regions. + /// + /// It is a hacky way to manage checking regions for equality, /// since we can 'canonicalize' each region to the representative /// of its SCC and be sure that -- if they have the same repr -- /// they *must* be equal (though not having the same repr does not @@ -481,8 +483,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_universes } - /// For each SCC, we compute a unique `RegionVid` (in fact, the - /// minimal one that belongs to the SCC). See + /// For each SCC, we compute a unique `RegionVid`. See the /// `scc_representatives` field of `RegionInferenceContext` for /// more details. fn compute_scc_representatives( @@ -490,13 +491,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { definitions: &IndexSlice>, ) -> IndexVec { let num_sccs = constraints_scc.num_sccs(); - let next_region_vid = definitions.next_index(); - let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs); - - for region_vid in definitions.indices() { - let scc = constraints_scc.scc(region_vid); - let prev_min = scc_representatives[scc]; - scc_representatives[scc] = region_vid.min(prev_min); + let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs); + + // Iterate over all RegionVids *in-order* and pick the least RegionVid as the + // representative of its SCC. This naturally prefers free regions over others. + for (vid, def) in definitions.iter_enumerated() { + let repr = &mut scc_representatives[constraints_scc.scc(vid)]; + if *repr == ty::RegionVid::MAX { + *repr = vid; + } else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_)) + && matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. }) + { + // Pick placeholders over existentials even if they have a greater RegionVid. + *repr = vid; + } } scc_representatives From 08c8caa5244b91ab7bda3bbc383f66ae07f3cc93 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 18 Oct 2023 09:33:57 +0000 Subject: [PATCH 07/12] convert all named regions in opaque types to nll vars Do it in typeck before entering region inference routines particularly because we will no longer be able to convert placeholders. --- compiler/rustc_borrowck/src/type_check/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a206aac0467f4..b72dccb2ebd0d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -229,6 +229,22 @@ pub(crate) fn type_check<'mir, 'tcx>( ); } + // Convert all regions to nll vars. + let (opaque_type_key, hidden_type) = + infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| { + match region.kind() { + ty::ReVar(_) => region, + ty::RePlaceholder(placeholder) => checker + .borrowck_context + .constraints + .placeholder_region(infcx, placeholder), + _ => ty::Region::new_var( + infcx.tcx, + checker.borrowck_context.universal_regions.to_region_vid(region), + ), + } + }); + (opaque_type_key, hidden_type) }) .collect(); From f4940e4d22006e902989bbe41ad0484d549495f5 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Wed, 18 Oct 2023 13:56:15 +0000 Subject: [PATCH 08/12] rework opaque types region inference --- .../src/region_infer/opaque_types.rs | 152 ++++++++---------- .../src/type_check/free_region_relations.rs | 7 + .../defined-by-user-annotation.rs | 22 ++- .../equal-lifetime-params-not-ok.rs | 37 +++++ .../equal-lifetime-params-not-ok.stderr | 59 +++++++ .../generic-not-strictly-equal.basic.stderr | 12 ++ ...t-strictly-equal.member_constraints.stderr | 15 ++ .../generic-not-strictly-equal.rs | 38 +++++ 8 files changed, 250 insertions(+), 92 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs create mode 100644 tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr create mode 100644 tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr create mode 100644 tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr create mode 100644 tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index dbf55db6e6b40..7fbf4fbf08589 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,10 +1,10 @@ -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; @@ -95,8 +95,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. /// This is lowered to give HIR something like /// - /// type f<'a>::_Return<'_a> = impl Sized + '_a; - /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } + /// type f<'a>::_Return<'_x> = impl Sized + '_x; + /// fn f<'a>(x: &'a i32) -> f<'a>::_Return<'a> { x } /// /// When checking the return type record the type from the return and the /// type used in the return value. In this case they might be `_Return<'1>` @@ -104,30 +104,34 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Once we to this method, we have completed region inference and want to /// call `infer_opaque_definition_from_instantiation` to get the inferred - /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` + /// type of `_Return<'_x>`. `infer_opaque_definition_from_instantiation` /// compares lifetimes directly, so we need to map the inference variables /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`. /// - /// First we map all the lifetimes in the concrete type to an equal - /// universal region that occurs in the concrete type's args, in this case - /// this would result in `&'1 i32`. We only consider regions in the args + /// First we map the regions in the the generic parameters `_Return<'1>` to + /// their `external_name` giving `_Return<'a>`. This step is a bit involved. + /// See the [rustc-dev-guide chapter] for more info. + /// + /// Then we map all the lifetimes in the concrete type to an equal + /// universal region that occurs in the opaque type's args, in this case + /// this would result in `&'a i32`. We only consider regions in the args /// in case there is an equal region that does not. For example, this should /// be allowed: /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` /// - /// Then we map the regions in both the type and the generic parameters to their - /// `external_name` giving `concrete_type = &'a i32`, - /// `args = ['static, 'a]`. This will then allow - /// `infer_opaque_definition_from_instantiation` to determine that - /// `_Return<'_a> = &'_a i32`. + /// This will then allow `infer_opaque_definition_from_instantiation` to + /// determine that `_Return<'_x> = &'_x i32`. /// /// There's a slight complication around closures. Given /// `fn f<'a: 'a>() { || {} }` the closure's type is something like /// `f::<'a>::{{closure}}`. The region parameter from f is essentially /// ignored by type checking so ends up being inferred to an empty region. /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, - /// which has no `external_name` in which case we use `'empty` as the + /// which has no `external_name` in which case we use `'{erased}` as the /// region to pass to `infer_opaque_definition_from_instantiation`. + /// + /// [rustc-dev-guide chapter]: + /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, @@ -138,85 +142,59 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut result: FxIndexMap> = FxIndexMap::default(); - let member_constraints: FxIndexMap<_, _> = self - .member_constraints - .all_indices() - .map(|ci| (self.member_constraints[ci].key, ci)) - .collect(); - debug!(?member_constraints); - for (opaque_type_key, concrete_type) in opaque_ty_decls { - let args = opaque_type_key.args; - debug!(?concrete_type, ?args); + debug!(?opaque_type_key, ?concrete_type); - let mut arg_regions = vec![self.universal_regions.fr_static]; + let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = + vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; - let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid) - { - Some(region) => { - let vid = self.universal_regions.to_region_vid(region); - arg_regions.push(vid); - region - } - None => { - arg_regions.push(vid); - ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "opaque type with non-universal region args", - ) - } - }; + let opaque_type_key = + opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { + // Use the SCC representative instead of directly using `region`. + // See [rustc-dev-guide chapter] § "Strict lifetime equality". + let scc = self.constraint_sccs.scc(region.as_var()); + let vid = self.scc_representatives[scc]; + let named = match self.definitions[vid].origin { + // Iterate over all universal regions in a consistent order and find the + // *first* equal region. This makes sure that equal lifetimes will have + // the same name and simplifies subsequent handling. + // See [rustc-dev-guide chapter] § "Semantic lifetime equality". + NllRegionVariableOrigin::FreeRegion => self + .universal_regions + .universal_regions() + .filter(|&ur| self.universal_region_relations.equal(vid, ur)) + // FIXME(aliemjay): universal regions with no `external_name` + // are extenal closure regions, which should be rejected eventually. + .find_map(|ur| self.definitions[ur].external_name), + NllRegionVariableOrigin::Placeholder(placeholder) => { + Some(ty::Region::new_placeholder(infcx.tcx, placeholder)) + } + NllRegionVariableOrigin::Existential { .. } => None, + } + .unwrap_or_else(|| { + ty::Region::new_error_with_message( + infcx.tcx, + concrete_type.span, + "opaque type with non-universal region args", + ) + }); - // Start by inserting universal regions from the member_constraint choice regions. - // This will ensure they get precedence when folding the regions in the concrete type. - if let Some(&ci) = member_constraints.get(&opaque_type_key) { - for &vid in self.member_constraints.choice_regions(ci) { - to_universal_region(vid, &mut arg_regions); - } - } - debug!(?arg_regions); - - // Next, insert universal regions from args, so we can translate regions that appear - // in them but are not subject to member constraints, for instance closure args. - let universal_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { - if let ty::RePlaceholder(..) = region.kind() { - // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args. - return region; - } - let vid = self.to_region_vid(region); - to_universal_region(vid, &mut arg_regions) - }); - let universal_args = universal_key.args; - debug!(?universal_args); - debug!(?arg_regions); - - // Deduplicate the set of regions while keeping the chosen order. - let arg_regions = arg_regions.into_iter().collect::>(); - debug!(?arg_regions); - - let universal_concrete_type = - infcx.tcx.fold_regions(concrete_type, |region, _| match *region { - ty::ReVar(vid) => arg_regions - .iter() - .find(|ur_vid| self.eval_equal(vid, **ur_vid)) - .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_erased), - ty::RePlaceholder(_) => ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "hidden type contains placeholders, we don't support higher kinded opaques yet", - ), - _ => region, + arg_regions.push((vid, named)); + named }); - debug!(?universal_concrete_type); + debug!(?opaque_type_key, ?arg_regions); + + let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| { + arg_regions + .iter() + .find(|&&(arg_vid, _)| self.eval_equal(region.as_var(), arg_vid)) + .map(|&(_, arg_named)| arg_named) + .unwrap_or(infcx.tcx.lifetimes.re_erased) + }); + debug!(?concrete_type); - let opaque_type_key = - OpaqueTypeKey { def_id: opaque_type_key.def_id, args: universal_args }; - let ty = infcx.infer_opaque_definition_from_instantiation( - opaque_type_key, - universal_concrete_type, - ); + let ty = + infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType` mapped to `(X, Y)` // and `OpaqueType` mapped to `(Y, X)`, and those are the same, but we only know that diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 86d20599a2a88..7553e3ee04fb4 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -164,6 +164,13 @@ impl UniversalRegionRelations<'_> { self.outlives.contains(fr1, fr2) } + /// Returns `true` if fr1 is known to equal fr2. + /// + /// This will only ever be true for universally quantified regions. + pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1) + } + /// Returns a vector of free regions `x` such that `fr1: x` is /// known to hold. pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec { diff --git a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs index d97a3010a17a0..0e1d44e7bb3a3 100644 --- a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs +++ b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs @@ -8,12 +8,24 @@ impl Equate for T { type Proj = T; } trait Indirect { type Ty; } impl> Indirect for (A, B) { type Ty = (); } -type Opq = impl Sized; -fn define_1(_: Opq) { - let _ = None::<<(Opq, u8) as Indirect>::Ty>; +mod basic { + use super::*; + type Opq = impl Sized; + fn define_1(_: Opq) { + let _ = None::<<(Opq, u8) as Indirect>::Ty>; + } + fn define_2() -> Opq { + 0u8 + } } -fn define_2() -> Opq { - 0u8 + +// `Opq<'a> == &'b u8` shouldn't be an error because `'a == 'b`. +mod lifetime { + use super::*; + type Opq<'a> = impl Sized + 'a; + fn define<'a: 'b, 'b: 'a>(_: Opq<'a>) { + let _ = None::<<(Opq<'a>, &'b u8) as Indirect>::Ty>; + } } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs new file mode 100644 index 0000000000000..59ba2694a7643 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs @@ -0,0 +1,37 @@ +// issue: #112841 + +#![feature(type_alias_impl_trait)] + +trait Trait<'a, 'b> {} +impl Trait<'_, '_> for T {} + +mod mod1 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a>() -> Opaque<'a, 'a> {} + //~^ ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope +} + +mod mod2 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {} + //~^ ERROR non-defining opaque type use in defining scope +} + +mod mod3 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a } + //~^ ERROR non-defining opaque type use in defining scope +} + +// This is similar to the previous cases in that 'a is equal to 'static, +// which is is some sense an implicit parameter to `Opaque`. +// For example, given a defining use `Opaque<'a> := &'a ()`, +// it is ambiguous whether `Opaque<'a> := &'a ()` or `Opaque<'a> := &'static ()` +mod mod4 { + type Opaque<'a> = impl super::Trait<'a, 'a>; + fn test<'a: 'static>() -> Opaque<'a> {} + //~^ ERROR expected generic lifetime parameter, found `'static` +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr new file mode 100644 index 0000000000000..b08bc8b826873 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr @@ -0,0 +1,59 @@ +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:10:22 + | +LL | fn test<'a>() -> Opaque<'a, 'a> {} + | ^^^^^^^^^^^^^^ generic argument `'a` used twice + | +note: for this opaque type + --> $DIR/equal-lifetime-params-not-ok.rs:9:27 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:10:37 + | +LL | fn test<'a>() -> Opaque<'a, 'a> {} + | ^^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:9:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:17:49 + | +LL | fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {} + | ^^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:16:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:23:61 + | +LL | fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a } + | ^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:22:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/equal-lifetime-params-not-ok.rs:33:42 + | +LL | type Opaque<'a> = impl super::Trait<'a, 'a>; + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +LL | fn test<'a: 'static>() -> Opaque<'a> {} + | ^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr new file mode 100644 index 0000000000000..e5f86c8c19355 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/generic-not-strictly-equal.rs:33:5 + | +LL | type Opaque<'a> = impl Copy + Captures<'a>; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr new file mode 100644 index 0000000000000..693af69d6fab9 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `Opaque<'x>` captures lifetime that does not appear in bounds + --> $DIR/generic-not-strictly-equal.rs:33:5 + | +LL | type Opaque<'a> = impl Copy + Captures<'a>; + | ------------------------ opaque type defined here +LL | +LL | fn test<'x>(_: Opaque<'x>) { + | -- hidden type `&'x u8` captures the lifetime `'x` as defined here +... +LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs new file mode 100644 index 0000000000000..a059fd3b8227e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs @@ -0,0 +1,38 @@ +// `Opaque<'?1> := u8` is not a valid defining use here. +// +// Due to fundamental limitations of the member constraints algorithm, +// we require '?1 to be *equal* to some universal region. +// +// While '?1 is eventually inferred to be equal to 'x because of the constraint '?1: 'x, +// we don't consider them equal in the strict sense because they lack the bidirectional outlives +// constraints ['?1: 'x, 'x: '?1]. In NLL terms, they are not part of the same SCC. +// +// See #113971 for details. + +//@ revisions: basic member_constraints +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +fn ensure_outlives<'a, X: 'a>(_: X) {} +fn relate(_: X, _: X) {} + +type Opaque<'a> = impl Copy + Captures<'a>; + +fn test<'x>(_: Opaque<'x>) { + let opaque = None::>; // let's call this lifetime '?1 + + #[cfg(basic)] + let hidden = None::; + + #[cfg(member_constraints)] + let hidden = None::<&'x u8>; + + ensure_outlives::<'x>(opaque); // outlives constraint: '?1: 'x + relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + //[basic]~^ ERROR expected generic lifetime parameter, found `'_` + //[member_constraints]~^^ ERROR captures lifetime that does not appear in bounds +} + +fn main() {} From 6b6ed2ea28e591ccae99048f226f98abfcd2e087 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Thu, 19 Oct 2023 10:42:25 +0000 Subject: [PATCH 09/12] reject external lifetimes as invalid arguments --- .../src/region_infer/opaque_types.rs | 14 +++++++++---- .../defined-in-closure-external-lifetime.rs | 19 +++++++++++++++++ ...efined-in-closure-external-lifetime.stderr | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs create mode 100644 tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7fbf4fbf08589..8a03d59b71019 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -18,6 +18,7 @@ use rustc_trait_selection::traits::ObligationCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::session_diagnostics::NonGenericOpaqueTypeParam; +use crate::universal_regions::RegionClassification; use super::RegionInferenceContext; @@ -162,10 +163,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { NllRegionVariableOrigin::FreeRegion => self .universal_regions .universal_regions() - .filter(|&ur| self.universal_region_relations.equal(vid, ur)) - // FIXME(aliemjay): universal regions with no `external_name` - // are extenal closure regions, which should be rejected eventually. - .find_map(|ur| self.definitions[ur].external_name), + .filter(|&ur| { + // See [rustc-dev-guide chapter] § "Closure restrictions". + !matches!( + self.universal_regions.region_classification(ur), + Some(RegionClassification::External) + ) + }) + .find(|&ur| self.universal_region_relations.equal(vid, ur)) + .map(|ur| self.definitions[ur].external_name.unwrap()), NllRegionVariableOrigin::Placeholder(placeholder) => { Some(ty::Region::new_placeholder(infcx.tcx, placeholder)) } diff --git a/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs new file mode 100644 index 0000000000000..9101e4385b3d3 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +mod case1 { + type Opaque<'x> = impl Sized + 'x; + fn foo<'s>() -> Opaque<'s> { + let _ = || { let _: Opaque<'s> = (); }; + //~^ ERROR expected generic lifetime parameter, found `'_` + } +} + +mod case2 { + type Opaque<'x> = impl Sized + 'x; + fn foo<'s>() -> Opaque<'s> { + let _ = || -> Opaque<'s> {}; + //~^ ERROR expected generic lifetime parameter, found `'_` + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr new file mode 100644 index 0000000000000..a8fd1f691dd40 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr @@ -0,0 +1,21 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defined-in-closure-external-lifetime.rs:6:29 + | +LL | type Opaque<'x> = impl Sized + 'x; + | -- this generic parameter must be used with a generic lifetime parameter +LL | fn foo<'s>() -> Opaque<'s> { +LL | let _ = || { let _: Opaque<'s> = (); }; + | ^^^^^^^^^^ + +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defined-in-closure-external-lifetime.rs:14:34 + | +LL | type Opaque<'x> = impl Sized + 'x; + | -- this generic parameter must be used with a generic lifetime parameter +LL | fn foo<'s>() -> Opaque<'s> { +LL | let _ = || -> Opaque<'s> {}; + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0792`. From 7c6876f9a9fe400e29430cb47cc11e71c13bb875 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Fri, 22 Mar 2024 08:02:12 +0000 Subject: [PATCH 10/12] simplify check_unique --- .../src/region_infer/opaque_types.rs | 95 +++++-------------- ...captured-non-universal-region.infer.stderr | 2 +- ...ining-use-captured-non-universal-region.rs | 3 +- ...aptured-non-universal-region.statik.stderr | 33 ++----- .../rpit/non-defining-use-lifetimes.rs | 4 +- .../rpit/non-defining-use-lifetimes.stderr | 34 ++----- .../lifetime_mismatch.rs | 4 - .../lifetime_mismatch.stderr | 69 +------------- .../multiple-def-uses-in-one-fn-lifetimes.rs | 5 +- ...ltiple-def-uses-in-one-fn-lifetimes.stderr | 53 +---------- 10 files changed, 52 insertions(+), 250 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 8a03d59b71019..63b8044581747 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -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> { - 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 { - 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, 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, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap> { - self.check_unique(infcx, &opaque_ty_decls); - let mut result: FxIndexMap> = FxIndexMap::default(); + let mut decls_modulo_regions: FxIndexMap, (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 } diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr index ec062abb2fc6f..2cb82bf771c44 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr @@ -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 diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs index 4f72333e65e89..2d54804f1fa62 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs @@ -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::<'_>(); diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr index b44f9ca69442a..0d9b7df225771 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr @@ -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 - --> $DIR/defining-use-captured-non-universal-region.rs:10:18 - | -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 +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>(); | ^^^^^^^^^^^^^^^^ - = 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`. diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs index 923b194d48384..cad41d2f2edff 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs @@ -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 } } diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr index e0122d32abe55..7ef96a2e59575 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr @@ -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 diff --git a/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs b/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs index 9ec585d93f58d..45a55050c4435 100644 --- a/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs +++ b/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs @@ -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() { diff --git a/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr b/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr index 7f54f47d27d0c..4f7b0f1740765 100644 --- a/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr +++ b/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr @@ -14,53 +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 - | -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) - | ^^^^^^ - -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 + --> $DIR/lifetime_mismatch.rs:13:5 | LL | (i, j) | ^^^^^^ @@ -69,27 +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 - | -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 + --> $DIR/lifetime_mismatch.rs:13: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 diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs index 5bec38c5e5b2f..580fb58ef8388 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs @@ -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() {} diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr index 0ccb3e2221d83..b2b9e604a6b69 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr @@ -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 From fb35156bb567417121e8e93ebd93a0fd13bce732 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Thu, 28 Mar 2024 06:07:50 +0000 Subject: [PATCH 11/12] fixup except equal params from --- tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs index 6e3f72a1ebe44..0ce85a4d6cbe1 100644 --- a/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs @@ -1,4 +1,6 @@ -// FIXME: description +// Normally we do not allow equal lifetimes in opaque type generic args at +// their defining sites. An exception to this rule, however, is when the bounds +// of the opaque type *require* the lifetimes to be equal. // issue: #113916 //@ check-pass From 59c217fed2bc74f3685bf3461674f6b3c7e113c3 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Thu, 28 Mar 2024 06:11:09 +0000 Subject: [PATCH 12/12] remove test FIXME re once-module-region --- ...efining-use-captured-non-universal-region.infer.stderr | 2 +- .../defining-use-captured-non-universal-region.rs | 1 - ...fining-use-captured-non-universal-region.statik.stderr | 2 +- tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs | 1 - .../ui/impl-trait/rpit/non-defining-use-lifetimes.stderr | 8 ++++---- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr index 2cb82bf771c44..ded9a92d8e8c4 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr @@ -1,5 +1,5 @@ error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/defining-use-captured-non-universal-region.rs:14:18 + --> $DIR/defining-use-captured-non-universal-region.rs:13:18 | LL | fn foo<'a>() -> impl Sized + 'a { | -- this generic parameter must be used with a generic lifetime parameter diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs index 2d54804f1fa62..e18302dc061a3 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs @@ -1,5 +1,4 @@ // This was an ICE. See #110726. -// FIXME(aliemjay): outdated due to "once modulo regions" restriction. //@ revisions: statik infer fixed //@ [fixed] check-pass diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr index 0d9b7df225771..43beb29f9ec46 100644 --- a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr @@ -1,5 +1,5 @@ error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/defining-use-captured-non-universal-region.rs:10:18 + --> $DIR/defining-use-captured-non-universal-region.rs:9: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 diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs index cad41d2f2edff..5e04e6b091adc 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs @@ -1,5 +1,4 @@ // issue: #111935 -// FIXME(aliemjay): outdated due to "once modulo regions" restriction. #![allow(unconditional_recursion)] diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr index 7ef96a2e59575..d2a224601fbe6 100644 --- a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr @@ -1,5 +1,5 @@ error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/non-defining-use-lifetimes.rs:14:16 + --> $DIR/non-defining-use-lifetimes.rs:13: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 @@ -7,7 +7,7 @@ LL | let _: () = foo(Lt::<'static>::None); | ^^ error[E0792]: expected generic lifetime parameter, found `'_` - --> $DIR/non-defining-use-lifetimes.rs:23:16 + --> $DIR/non-defining-use-lifetimes.rs:22:16 | LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { | -- this generic parameter must be used with a generic lifetime parameter @@ -15,13 +15,13 @@ LL | let _: () = foo(Lt::<'_>::None); | ^^ error: non-defining opaque type use in defining scope - --> $DIR/non-defining-use-lifetimes.rs:33:16 + --> $DIR/non-defining-use-lifetimes.rs:32:16 | LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None); | ^^ | note: lifetime used multiple times - --> $DIR/non-defining-use-lifetimes.rs:32:58 + --> $DIR/non-defining-use-lifetimes.rs:31:58 | LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b { | ^^ ^^