Auto merge of #116891 - aliemjay:opaque-region-infer-rework-2, r=compiler-errors,oli-obk
rework opaque type region inference User-facing changes are documented in [this comment](https://github.com/rust-lang/rust/pull/116891#issuecomment-1973774412). The design document is in [this comment](https://github.com/rust-lang/rust/pull/116891#issuecomment-1836900102). --- \- Fix Ice in check_unique; ICE -> Error; fixes #122782. \- Ignore uncaptured lifetime args; ICE -> Pass; fixes #111906, fixes #110623, fixes #109059, fixes #122307 \- Except equal parameters from the uniqueness check; Pass -> Error; fixes #113916. \- Check RPITs for invalid args; Pass -> Error; fixes #111935; ICE -> Error; fixes #110726. \- Rework opaque types region inference; Pass -> Error; fixes #113971, fixes #112841. \- Reject external lifetimes as invalid args; Pass -> Error; fixes #105498. r? `@ghost`
This commit is contained in:
commit
551abd65be
40 changed files with 883 additions and 349 deletions
|
@ -95,9 +95,11 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// visible from this index.
|
||||
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
|
||||
|
||||
/// 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<RegionVid, RegionDefinition<'tcx>>,
|
||||
) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
|
||||
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);
|
||||
let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, 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);
|
||||
// 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
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
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;
|
||||
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;
|
||||
|
@ -18,76 +17,19 @@ use rustc_trait_selection::traits::ObligationCtxt;
|
|||
|
||||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||
use crate::session_diagnostics::NonGenericOpaqueTypeParam;
|
||||
use crate::universal_regions::RegionClassification;
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
self.scc_values
|
||||
.universal_regions_outlived_by(scc)
|
||||
.find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?))
|
||||
}
|
||||
|
||||
fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> {
|
||||
let region = arg.as_region()?;
|
||||
|
||||
if let ty::RePlaceholder(..) = region.kind() {
|
||||
None
|
||||
} else {
|
||||
Some(self.to_region_vid(region))
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that all opaque types have the same region parameters if they have the same
|
||||
/// non-region parameters. This is necessary because within the new solver we perform various query operations
|
||||
/// modulo regions, and thus could unsoundly select some impls that don't hold.
|
||||
fn check_unique(
|
||||
&self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
) {
|
||||
for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() {
|
||||
for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) {
|
||||
if a.def_id != b.def_id {
|
||||
continue;
|
||||
}
|
||||
// Non-lifetime params differ -> ok
|
||||
if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) {
|
||||
continue;
|
||||
}
|
||||
trace!(?a, ?b);
|
||||
for (a, b) in a.args.iter().zip(b.args) {
|
||||
trace!(?a, ?b);
|
||||
let Some(r1) = self.generic_arg_to_region(a) else {
|
||||
continue;
|
||||
};
|
||||
let Some(r2) = self.generic_arg_to_region(b) else {
|
||||
continue;
|
||||
};
|
||||
if self.eval_equal(r1, r2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
|
||||
arg: self.universal_name(r1).unwrap().into(),
|
||||
prev: self.universal_name(r2).unwrap().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.
|
||||
///
|
||||
/// 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>`
|
||||
|
@ -95,118 +37,102 @@ 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,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
|
||||
self.check_unique(infcx, &opaque_ty_decls);
|
||||
|
||||
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
|
||||
|
||||
let member_constraints: FxIndexMap<_, _> = self
|
||||
.member_constraints
|
||||
.all_indices()
|
||||
.map(|ci| (self.member_constraints[ci].key, ci))
|
||||
.collect();
|
||||
debug!(?member_constraints);
|
||||
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
|
||||
FxIndexMap::default();
|
||||
|
||||
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 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",
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// 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_args = infcx.tcx.fold_regions(args, |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)
|
||||
});
|
||||
debug!(?universal_args);
|
||||
debug!(?arg_regions);
|
||||
|
||||
// Deduplicate the set of regions while keeping the chosen order.
|
||||
let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>();
|
||||
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,
|
||||
});
|
||||
debug!(?universal_concrete_type);
|
||||
let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
|
||||
vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)];
|
||||
|
||||
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,
|
||||
);
|
||||
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| {
|
||||
// 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))
|
||||
}
|
||||
NllRegionVariableOrigin::Existential { .. } => None,
|
||||
}
|
||||
.unwrap_or_else(|| {
|
||||
ty::Region::new_error_with_message(
|
||||
infcx.tcx,
|
||||
concrete_type.span,
|
||||
"opaque type with non-universal region args",
|
||||
)
|
||||
});
|
||||
|
||||
arg_regions.push((vid, named));
|
||||
named
|
||||
});
|
||||
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 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<X, Y>` mapped to `(X, Y)`
|
||||
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
|
||||
|
@ -234,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
|
||||
}
|
||||
|
@ -422,42 +371,46 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
/// 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>,
|
||||
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 parent_generics = tcx.generics_of(parent);
|
||||
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();
|
||||
|
||||
// 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 => {
|
||||
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(_)),
|
||||
};
|
||||
|
||||
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<u32>` 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();
|
||||
|
||||
if let Err(guar) = opaque_env.param_is_error(i) {
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
||||
ty: arg,
|
||||
kind,
|
||||
|
@ -469,10 +422,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)]
|
||||
|
@ -486,3 +439,91 @@ fn check_opaque_type_parameter_valid(
|
|||
|
||||
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<ty::GenericArgsRef<'tcx>>,
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RegionVid> {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -833,6 +833,38 @@ pub struct OpaqueTypeKey<'tcx> {
|
|||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeKey<'tcx> {
|
||||
pub fn iter_captured_args(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> {
|
||||
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
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||
--> $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
|
||||
...
|
||||
LL | let i: i32 = foo::<'_>();
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
|
@ -0,0 +1,22 @@
|
|||
// This was an ICE. See #110726.
|
||||
|
||||
//@ 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 expected generic lifetime parameter, found `'static`
|
||||
|
||||
#[cfg(infer)]
|
||||
let i: i32 = foo::<'_>();
|
||||
//[infer]~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
|
||||
#[cfg(fixed)]
|
||||
let i: i32 = foo::<'a>();
|
||||
|
||||
i
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,12 @@
|
|||
error[E0792]: expected generic lifetime parameter, found `'static`
|
||||
--> $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
|
||||
LL | #[cfg(statik)]
|
||||
LL | let i: i32 = foo::<'static>();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
|
@ -0,0 +1,74 @@
|
|||
// issue: #110623
|
||||
//@ check-pass
|
||||
|
||||
use std::{collections::BTreeMap, num::ParseIntError, str::FromStr};
|
||||
|
||||
enum FileSystem {
|
||||
File(usize),
|
||||
Directory(BTreeMap<String, FileSystem>),
|
||||
}
|
||||
|
||||
impl FromStr for FileSystem {
|
||||
type Err = ParseIntError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<FileSystem> {
|
||||
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<Item = &'a str> + 'a,
|
||||
) -> Option<impl Iterator<Item = &'a str> + '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() {}
|
|
@ -0,0 +1,13 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(adt_const_params)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Bar<const FOO: &'static str> {}
|
||||
impl Bar<"asdf"> for () {}
|
||||
|
||||
fn foo<const FOO: &'static str>() -> impl Bar<"asdf"> {
|
||||
()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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() {}
|
|
@ -1,4 +1,4 @@
|
|||
error: {foo<DefId(..)_'a/#0>::{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<i32>) -> impl Fn() + 'static {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: {foo<DefId(..)_'a/#0>::{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<i32>) -> impl Fn() + 'static {
|
||||
|
|
|
@ -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<i32>) -> 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
|
||||
|| ()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
||||
For more information about this error, try `rustc --explain E0261`.
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0261, E0792.
|
||||
For more information about an error, try `rustc --explain E0261`.
|
||||
|
|
|
@ -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 {}
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
37
tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs
Normal file
37
tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// issue: #111935
|
||||
|
||||
#![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 expected generic lifetime parameter, found `'static`
|
||||
}
|
||||
}
|
||||
|
||||
mod infer {
|
||||
use super::*;
|
||||
// invalid defining use: Opaque<'_> := ()
|
||||
fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
|
||||
let _: () = foo(Lt::<'_>::None);
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
}
|
||||
}
|
||||
|
||||
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 non-defining opaque type use in defining scope
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
31
tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr
Normal file
31
tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr
Normal file
|
@ -0,0 +1,31 @@
|
|||
error[E0792]: expected generic lifetime parameter, found `'static`
|
||||
--> $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
|
||||
LL | let _: () = foo(Lt::<'static>::None);
|
||||
| ^^
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||
--> $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
|
||||
LL | let _: () = foo(Lt::<'_>::None);
|
||||
| ^^
|
||||
|
||||
error: non-defining opaque type use in defining scope
|
||||
--> $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:31:58
|
||||
|
|
||||
LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
|
||||
| ^^ ^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
|
@ -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() {}
|
|
@ -8,12 +8,24 @@ impl<T> Equate for T { type Proj = T; }
|
|||
trait Indirect { type Ty; }
|
||||
impl<A, B: Equate<Proj = A>> 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() {}
|
||||
|
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -0,0 +1,37 @@
|
|||
// issue: #112841
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait Trait<'a, 'b> {}
|
||||
impl<T> 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() {}
|
|
@ -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`.
|
52
tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs
Normal file
52
tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
trait Trait<'a, 'b> {}
|
||||
impl<T> 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() {}
|
|
@ -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`.
|
|
@ -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`.
|
38
tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs
Normal file
38
tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs
Normal file
|
@ -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<T> Captures<'_> for T {}
|
||||
|
||||
fn ensure_outlives<'a, X: 'a>(_: X) {}
|
||||
fn relate<X>(_: X, _: X) {}
|
||||
|
||||
type Opaque<'a> = impl Copy + Captures<'a>;
|
||||
|
||||
fn test<'x>(_: Opaque<'x>) {
|
||||
let opaque = None::<Opaque<'_>>; // let's call this lifetime '?1
|
||||
|
||||
#[cfg(basic)]
|
||||
let hidden = None::<u8>;
|
||||
|
||||
#[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() {}
|
|
@ -13,6 +13,7 @@ type FutNothing<'a> = impl 'a + Future<Output = ()>;
|
|||
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: F)
|
||||
|
|
|
@ -6,6 +6,26 @@ LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
|
|||
|
|
||||
= note: `FutNothing` must be used in combination with a concrete type within the same module
|
||||
|
||||
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:22:1
|
||||
|
|
||||
LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
|
||||
| -- this generic parameter must be used with a generic lifetime parameter
|
||||
...
|
||||
LL | / {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: concrete type differs from previous defining opaque type use
|
||||
--> $DIR/hkl_forbidden4.rs:13:1
|
||||
|
|
||||
|
@ -18,17 +38,6 @@ note: previous use here
|
|||
LL | call(operation).await
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'any`
|
||||
--> $DIR/hkl_forbidden4.rs:21:1
|
||||
|
|
||||
LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
|
||||
| -- this generic parameter must be used with a generic lifetime parameter
|
||||
...
|
||||
LL | / {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -14,23 +14,7 @@ LL | (x, y)
|
|||
| ^^^^^^
|
||||
|
||||
error: opaque type used twice with different lifetimes
|
||||
--> $DIR/lifetime_mismatch.rs:6:5
|
||||
|
|
||||
LL | (x, y)
|
||||
| ^^^^^^
|
||||
| |
|
||||
| lifetime `'a` used here
|
||||
| lifetime `'b` previously used here
|
||||
|
|
||||
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||
--> $DIR/lifetime_mismatch.rs:6:5
|
||||
|
|
||||
LL | (x, y)
|
||||
| ^^^^^^
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: opaque type used twice with different lifetimes
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
--> $DIR/lifetime_mismatch.rs:13:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
|
@ -39,57 +23,10 @@ LL | (i, j)
|
|||
| lifetime `'y` previously used here
|
||||
|
|
||||
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
--> $DIR/lifetime_mismatch.rs:13:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
|
||||
error: opaque type used twice with different lifetimes
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
| |
|
||||
| lifetime `'y` used here
|
||||
| lifetime `'x` previously used here
|
||||
|
|
||||
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
|
||||
error: opaque type used twice with different lifetimes
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
| |
|
||||
| lifetime `'x` used here
|
||||
| lifetime `'y` previously used here
|
||||
|
|
||||
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: opaque type used twice with different lifetimes
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
| |
|
||||
| lifetime `'y` used here
|
||||
| lifetime `'x` previously used here
|
||||
|
|
||||
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
|
||||
--> $DIR/lifetime_mismatch.rs:14:5
|
||||
|
|
||||
LL | (i, j)
|
||||
| ^^^^^^
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
16
tests/ui/type-alias-impl-trait/param_mismatch4.rs
Normal file
16
tests/ui/type-alias-impl-trait/param_mismatch4.rs
Normal file
|
@ -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() {}
|
12
tests/ui/type-alias-impl-trait/param_mismatch4.stderr
Normal file
12
tests/ui/type-alias-impl-trait/param_mismatch4.stderr
Normal file
|
@ -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`.
|
Loading…
Add table
Reference in a new issue