Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 66abdf7

Browse files
committedOct 23, 2023
Auto merge of #116891 - aliemjay:opaque-region-infer-rework-2, r=<try>
rework opaque type region inference fixes #113971 Pass -> Error fixes #111906 ICE -> Pass fixes #110623 == fixes #109059 == fixes #112841 Pass -> Error fixes #110726 ICE->Error fixes #111935 Pass -> Error fixes #113916 == r? `@ghost`
2 parents aec4741 + 350b33e commit 66abdf7

26 files changed

+713
-123
lines changed
 

‎compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ pub struct RegionInferenceContext<'tcx> {
9797
/// visible from this index.
9898
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
9999

100-
/// Contains a "representative" from each SCC. This will be the
101-
/// minimal RegionVid belonging to that universe. It is used as a
102-
/// kind of hacky way to manage checking outlives relationships,
100+
/// Contains the "representative" region of each SCC.
101+
/// It is defined as the one with the minimal RegionVid, favoring
102+
/// free regions, then placeholders, then existential regions.
103+
///
104+
/// It is a hacky way to manage checking regions for equality,
103105
/// since we can 'canonicalize' each region to the representative
104106
/// of its SCC and be sure that -- if they have the same repr --
105107
/// they *must* be equal (though not having the same repr does not
@@ -487,22 +489,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
487489
scc_universes
488490
}
489491

490-
/// For each SCC, we compute a unique `RegionVid` (in fact, the
491-
/// minimal one that belongs to the SCC). See
492+
/// For each SCC, we compute a unique `RegionVid`. See
492493
/// `scc_representatives` field of `RegionInferenceContext` for
493494
/// more details.
494495
fn compute_scc_representatives(
495496
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
496497
definitions: &IndexSlice<RegionVid, RegionDefinition<'tcx>>,
497498
) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
498499
let num_sccs = constraints_scc.num_sccs();
499-
let next_region_vid = definitions.next_index();
500-
let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs);
501-
502-
for region_vid in definitions.indices() {
503-
let scc = constraints_scc.scc(region_vid);
504-
let prev_min = scc_representatives[scc];
505-
scc_representatives[scc] = region_vid.min(prev_min);
500+
let mut scc_representatives = IndexVec::from_elem_n(ty::RegionVid::MAX, num_sccs);
501+
502+
for (vid, def) in definitions.iter_enumerated() {
503+
use NllRegionVariableOrigin as VarOrigin;
504+
let scc = constraints_scc.scc(vid);
505+
let repr = &mut scc_representatives[scc];
506+
if *repr == ty::RegionVid::MAX {
507+
*repr = vid;
508+
} else if matches!(def.origin, VarOrigin::Placeholder(_))
509+
&& matches!(definitions[*repr].origin, VarOrigin::Existential { .. })
510+
{
511+
*repr = vid;
512+
}
506513
}
507514

508515
scc_representatives

‎compiler/rustc_borrowck/src/region_infer/opaque_types.rs

Lines changed: 132 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
1+
use rustc_data_structures::fx::FxIndexMap;
22
use rustc_errors::ErrorGuaranteed;
33
use rustc_hir::def::DefKind;
44
use rustc_hir::def_id::LocalDefId;
55
use rustc_hir::OpaqueTyOrigin;
6-
use rustc_infer::infer::InferCtxt;
76
use rustc_infer::infer::TyCtxtInferExt as _;
7+
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
88
use rustc_infer::traits::{Obligation, ObligationCause};
99
use rustc_middle::traits::DefiningAnchor;
1010
use rustc_middle::ty::visit::TypeVisitableExt;
@@ -66,85 +66,60 @@ impl<'tcx> RegionInferenceContext<'tcx> {
6666
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
6767
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
6868

69-
let member_constraints: FxIndexMap<_, _> = self
70-
.member_constraints
71-
.all_indices()
72-
.map(|ci| (self.member_constraints[ci].key, ci))
73-
.collect();
74-
debug!(?member_constraints);
75-
7669
for (opaque_type_key, concrete_type) in opaque_ty_decls {
77-
let args = opaque_type_key.args;
78-
debug!(?concrete_type, ?args);
70+
debug!(?opaque_type_key, ?concrete_type);
7971

80-
let mut subst_regions = vec![self.universal_regions.fr_static];
72+
let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> =
73+
vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)];
8174

82-
let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
83-
trace!(?vid);
84-
let scc = self.constraint_sccs.scc(vid);
85-
trace!(?scc);
86-
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
87-
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
88-
}) {
89-
Some(region) => {
90-
let vid = self.universal_regions.to_region_vid(region);
91-
subst_regions.push(vid);
92-
region
75+
let opaque_type_key =
76+
opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| {
77+
let scc = self.constraint_sccs.scc(self.to_region_vid(region));
78+
let vid = self.scc_representatives[scc];
79+
let named = match self.definitions[vid].origin {
80+
NllRegionVariableOrigin::FreeRegion => self
81+
.universal_regions
82+
.universal_regions()
83+
.filter(|&ur| {
84+
use crate::universal_regions::RegionClassification as Class;
85+
matches!(
86+
self.universal_regions.region_classification(ur),
87+
Some(Class::Global | Class::Local)
88+
)
89+
})
90+
.filter(|&ur| ur != self.universal_regions.fr_fn_body)
91+
.find(|&ur| self.universal_region_relations.equal(vid, ur))
92+
.map(|ur| self.definitions[ur].external_name.unwrap()),
93+
NllRegionVariableOrigin::Placeholder(placeholder) => {
94+
Some(ty::Region::new_placeholder(infcx.tcx, placeholder))
95+
}
96+
NllRegionVariableOrigin::Existential { .. } => None,
9397
}
94-
None => {
95-
subst_regions.push(vid);
98+
.unwrap_or_else(|| {
9699
ty::Region::new_error_with_message(
97100
infcx.tcx,
98101
concrete_type.span,
99102
"opaque type with non-universal region args",
100103
)
101-
}
102-
}
103-
};
104+
});
104105

105-
// Start by inserting universal regions from the member_constraint choice regions.
106-
// This will ensure they get precedence when folding the regions in the concrete type.
107-
if let Some(&ci) = member_constraints.get(&opaque_type_key) {
108-
for &vid in self.member_constraints.choice_regions(ci) {
109-
to_universal_region(vid, &mut subst_regions);
110-
}
111-
}
112-
debug!(?subst_regions);
113-
114-
// Next, insert universal regions from args, so we can translate regions that appear
115-
// in them but are not subject to member constraints, for instance closure args.
116-
let universal_args = infcx.tcx.fold_regions(args, |region, _| {
117-
if let ty::RePlaceholder(..) = region.kind() {
118-
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the args.
119-
return region;
120-
}
106+
arg_regions.push((vid, named));
107+
named
108+
});
109+
debug!(?opaque_type_key, ?arg_regions);
110+
111+
let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| {
121112
let vid = self.to_region_vid(region);
122-
to_universal_region(vid, &mut subst_regions)
113+
arg_regions
114+
.iter()
115+
.find(|&&(ur_vid, _)| self.eval_equal(vid, ur_vid))
116+
.map(|&(_, ur_name)| ur_name)
117+
.unwrap_or(infcx.tcx.lifetimes.re_erased)
123118
});
124-
debug!(?universal_args);
125-
debug!(?subst_regions);
126-
127-
// Deduplicate the set of regions while keeping the chosen order.
128-
let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
129-
debug!(?subst_regions);
130-
131-
let universal_concrete_type =
132-
infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
133-
ty::ReVar(vid) => subst_regions
134-
.iter()
135-
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
136-
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
137-
.unwrap_or(infcx.tcx.lifetimes.re_erased),
138-
_ => region,
139-
});
140-
debug!(?universal_concrete_type);
119+
debug!(?concrete_type);
141120

142-
let opaque_type_key =
143-
OpaqueTypeKey { def_id: opaque_type_key.def_id, args: universal_args };
144-
let ty = infcx.infer_opaque_definition_from_instantiation(
145-
opaque_type_key,
146-
universal_concrete_type,
147-
);
121+
let ty =
122+
infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
148123
// Sometimes two opaque types are the same only after we remap the generic parameters
149124
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
150125
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -365,38 +340,33 @@ fn check_opaque_type_well_formed<'tcx>(
365340
}
366341
}
367342

368-
fn check_opaque_type_parameter_valid(
369-
tcx: TyCtxt<'_>,
370-
opaque_type_key: OpaqueTypeKey<'_>,
343+
fn check_opaque_type_parameter_valid<'tcx>(
344+
tcx: TyCtxt<'tcx>,
345+
opaque_type_key: OpaqueTypeKey<'tcx>,
371346
span: Span,
372347
) -> Result<(), ErrorGuaranteed> {
373-
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
374-
let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
375-
OpaqueTyOrigin::TyAlias { .. } => true,
376-
OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
377-
};
378-
348+
let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
379349
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
380350
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
381-
for (i, arg) in opaque_type_key.args.iter().enumerate() {
351+
for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
382352
if let Err(guar) = arg.error_reported() {
383353
return Err(guar);
384354
}
385355

386356
let arg_is_param = match arg.unpack() {
387357
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
388-
GenericArgKind::Lifetime(lt) if is_ty_alias => {
358+
GenericArgKind::Lifetime(lt) => {
389359
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
360+
|| (lt.is_static() && opaque_env.param_equal_static(i))
390361
}
391-
// FIXME(#113916): we can't currently check for unique lifetime params,
392-
// see that issue for more. We will also have to ignore unused lifetime
393-
// params for RPIT, but that's comparatively trivial ✨
394-
GenericArgKind::Lifetime(_) => continue,
395362
GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
396363
};
397364

398365
if arg_is_param {
399-
seen_params.entry(arg).or_default().push(i);
366+
let seen_where = seen_params.entry(arg).or_default();
367+
if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
368+
seen_where.push(i);
369+
}
400370
} else {
401371
// Prevent `fn foo() -> Foo<u32>` from being defining.
402372
let opaque_param = opaque_generics.param_at(i, tcx);
@@ -428,3 +398,81 @@ fn check_opaque_type_parameter_valid(
428398

429399
Ok(())
430400
}
401+
402+
struct LazyOpaqueTyEnv<'tcx> {
403+
tcx: TyCtxt<'tcx>,
404+
def_id: LocalDefId,
405+
canonical_args: std::cell::Cell<Option<ty::GenericArgsRef<'tcx>>>,
406+
}
407+
408+
impl<'tcx> LazyOpaqueTyEnv<'tcx> {
409+
pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
410+
Self { tcx, def_id, canonical_args: std::cell::Cell::new(None) }
411+
}
412+
413+
pub fn param_equal_static(&self, param_index: usize) -> bool {
414+
self.get_canonical_args()[param_index].expect_region().is_static()
415+
}
416+
417+
pub fn params_equal(&self, param1: usize, param2: usize) -> bool {
418+
let canonical_args = self.get_canonical_args();
419+
canonical_args[param1] == canonical_args[param2]
420+
}
421+
422+
fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
423+
use rustc_hir as hir;
424+
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
425+
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
426+
427+
if let Some(canonical_args) = self.canonical_args.get() {
428+
return canonical_args;
429+
}
430+
431+
let &Self { tcx, def_id, .. } = self;
432+
let origin = tcx.opaque_type_origin(def_id);
433+
let defining_use_anchor = match origin {
434+
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
435+
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
436+
};
437+
let param_env = tcx.param_env(defining_use_anchor);
438+
439+
let infcx = tcx.infer_ctxt().build();
440+
let ocx = ObligationCtxt::new(&infcx);
441+
442+
let args = match origin {
443+
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
444+
GenericArgs::identity_for_item(tcx, parent).extend_to(
445+
tcx,
446+
def_id.to_def_id(),
447+
|param, _| {
448+
tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into()
449+
},
450+
)
451+
}
452+
hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
453+
};
454+
455+
let wf_tys = ocx.assumed_wf_types(param_env, defining_use_anchor).unwrap_or_else(|_| {
456+
tcx.sess.delay_span_bug(tcx.def_span(def_id), "error getting implied bounds");
457+
Default::default()
458+
});
459+
let implied_bounds = infcx.implied_bounds_tys(param_env, defining_use_anchor, wf_tys);
460+
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
461+
462+
let mut seen = vec![tcx.lifetimes.re_static];
463+
let canonical_args = tcx.fold_regions(args, |r1, _| {
464+
if let Some(&r2) = seen.iter().find(|&&r2| {
465+
let free_regions = outlives_env.free_region_map();
466+
free_regions.sub_free_regions(tcx, r1, r2)
467+
&& free_regions.sub_free_regions(tcx, r2, r1)
468+
}) {
469+
r2
470+
} else {
471+
seen.push(r1);
472+
r1
473+
}
474+
});
475+
self.canonical_args.set(Some(canonical_args));
476+
canonical_args
477+
}
478+
}

‎compiler/rustc_borrowck/src/type_check/free_region_relations.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ impl UniversalRegionRelations<'_> {
159159
self.outlives.contains(fr1, fr2)
160160
}
161161

162+
/// Returns `true` if fr1 is known to equal fr2.
163+
///
164+
/// This will only ever be true for universally quantified regions.
165+
pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
166+
self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1)
167+
}
168+
162169
/// Returns a vector of free regions `x` such that `fr1: x` is
163170
/// known to hold.
164171
pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {

‎compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,22 @@ pub(crate) fn type_check<'mir, 'tcx>(
243243
hidden_type.ty = Ty::new_error(infcx.tcx, reported);
244244
}
245245

246+
// Convert all regions to nll vars.
247+
let (opaque_type_key, hidden_type) =
248+
infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| {
249+
match region.kind() {
250+
ty::ReVar(_) => region,
251+
ty::RePlaceholder(placeholder) => checker
252+
.borrowck_context
253+
.constraints
254+
.placeholder_region(infcx, placeholder),
255+
_ => ty::Region::new_var(
256+
infcx.tcx,
257+
checker.borrowck_context.universal_regions.to_region_vid(region),
258+
),
259+
}
260+
});
261+
246262
(opaque_type_key, hidden_type)
247263
})
248264
.collect();

‎compiler/rustc_middle/src/ty/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,38 @@ pub struct OpaqueTypeKey<'tcx> {
15041504
pub args: GenericArgsRef<'tcx>,
15051505
}
15061506

1507+
impl<'tcx> OpaqueTypeKey<'tcx> {
1508+
pub fn fold_captured_lifetime_args(
1509+
self,
1510+
tcx: TyCtxt<'tcx>,
1511+
mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>,
1512+
) -> Self {
1513+
let Self { def_id, args } = self;
1514+
let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| {
1515+
match (arg.unpack(), v) {
1516+
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
1517+
(ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(),
1518+
_ => arg,
1519+
}
1520+
});
1521+
let args = tcx.mk_args_from_iter(args);
1522+
Self { def_id, args }
1523+
}
1524+
1525+
pub fn iter_captured_args(
1526+
self,
1527+
tcx: TyCtxt<'tcx>,
1528+
) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> {
1529+
std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map(
1530+
|(i, (arg, v))| match (arg.unpack(), v) {
1531+
(_, ty::Invariant) => Some((i, arg)),
1532+
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None,
1533+
_ => bug!("unexpected opaque type arg variance"),
1534+
},
1535+
)
1536+
}
1537+
}
1538+
15071539
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
15081540
pub struct OpaqueHiddenType<'tcx> {
15091541
/// The span of this particular definition of the opaque type. So
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0792]: expected generic lifetime parameter, found `'_`
2+
--> $DIR/defining-use-captured-non-universal-region.rs:14:18
3+
|
4+
LL | fn foo<'a>() -> impl Sized + 'a {
5+
| -- this generic parameter must be used with a generic lifetime parameter
6+
...
7+
LL | let i: i32 = foo::<'_>();
8+
| ^^^^^^^^^^^
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// This was an ICE. See #110726.
2+
3+
// revisions: statik infer fixed
4+
//[fixed] check-pass
5+
//[statik] check-fail
6+
#![allow(unconditional_recursion)]
7+
8+
fn foo<'a>() -> impl Sized + 'a {
9+
#[cfg(statik)]
10+
let i: i32 = foo::<'static>();
11+
//[statik]~^ ERROR expected generic lifetime parameter, found `'static`
12+
13+
#[cfg(infer)]
14+
let i: i32 = foo::<'_>();
15+
//[infer]~^ ERROR expected generic lifetime parameter, found `'_`
16+
17+
#[cfg(fixed)]
18+
let i: i32 = foo::<'a>();
19+
20+
i
21+
}
22+
23+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0792]: expected generic lifetime parameter, found `'static`
2+
--> $DIR/defining-use-captured-non-universal-region.rs:10:18
3+
|
4+
LL | fn foo<'a>() -> impl Sized + 'a {
5+
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
6+
LL | #[cfg(statik)]
7+
LL | let i: i32 = foo::<'static>();
8+
| ^^^^^^^^^^^^^^^^
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// issue: #110623
2+
// check-pass
3+
4+
use std::{collections::BTreeMap, num::ParseIntError, str::FromStr};
5+
6+
enum FileSystem {
7+
File(usize),
8+
Directory(BTreeMap<String, FileSystem>),
9+
}
10+
11+
impl FromStr for FileSystem {
12+
type Err = ParseIntError;
13+
14+
fn from_str(s: &str) -> Result<Self, Self::Err> {
15+
if s.starts_with("dir") {
16+
Ok(Self::new_dir())
17+
} else {
18+
Ok(Self::File(s.split_whitespace().next().unwrap().parse()?))
19+
}
20+
}
21+
}
22+
23+
impl FileSystem {
24+
fn new_dir() -> FileSystem {
25+
FileSystem::Directory(BTreeMap::new())
26+
}
27+
28+
fn insert(&mut self, name: String, other: FileSystem) -> Option<FileSystem> {
29+
match self {
30+
FileSystem::File(_) => panic!("can only insert into directory!"),
31+
FileSystem::Directory(tree) => tree.insert(name, other),
32+
}
33+
}
34+
35+
// Recursively build a tree from commands. This uses (abuses?)
36+
// the fact that `cd /` only appears at the start and that
37+
// subsequent `cd`s can only move ONE level to use the recursion
38+
// stack as the filesystem stack
39+
fn build<'a>(
40+
&mut self,
41+
mut commands: impl Iterator<Item = &'a str> + 'a,
42+
) -> Option<impl Iterator<Item = &'a str> + 'a> {
43+
let cmd = commands.next()?;
44+
let mut elements = cmd.lines();
45+
match elements.next().map(str::trim) {
46+
Some("cd /") | None => self.build(commands),
47+
Some("cd ..") => {
48+
// return to higher scope
49+
Some(commands)
50+
}
51+
Some("ls") => {
52+
for item in elements {
53+
let name = item.split_whitespace().last().unwrap();
54+
let prior = self.insert(name.to_string(), item.parse().unwrap());
55+
debug_assert!(prior.is_none());
56+
}
57+
// continue on
58+
self.build(commands)
59+
}
60+
Some(other_cd) => {
61+
let name = other_cd
62+
.trim()
63+
.strip_prefix("cd ")
64+
.expect("expected a cd command");
65+
let mut directory = FileSystem::new_dir();
66+
let further_commands = directory.build(commands);
67+
self.insert(name.to_string(), directory);
68+
self.build(further_commands?) // THIS LINE FAILS TO COMPILE
69+
}
70+
}
71+
}
72+
}
73+
74+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
#![feature(adt_const_params)]
4+
#![allow(incomplete_features)]
5+
6+
trait Bar<const FOO: &'static str> {}
7+
impl Bar<"asdf"> for () {}
8+
9+
fn foo<const FOO: &'static str>() -> impl Bar<"asdf"> {
10+
()
11+
}
12+
13+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// issue: #111906
2+
// check-pass
3+
4+
#![allow(unconditional_recursion)]
5+
6+
fn foo<'a: 'a>() -> impl Sized {
7+
let _: () = foo::<'a>();
8+
loop {}
9+
}
10+
11+
fn bar<'a: 'a>() -> impl Sized + 'a {
12+
let _: *mut &'a () = bar::<'a>();
13+
loop {}
14+
}
15+
16+
fn main() {}

‎tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
use std::fmt::Debug;
33

44
fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
5-
//~^ ERROR cannot resolve opaque type
6-
75
|x| x
8-
//~^ ERROR concrete type differs from previous defining opaque type use
6+
//~^ ERROR expected generic lifetime parameter, found `'_`
97
}
108

119
fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) {
Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
1-
error: concrete type differs from previous defining opaque type use
2-
--> $DIR/impl-fn-predefined-lifetimes.rs:7:9
3-
|
4-
LL | |x| x
5-
| ^ expected `impl Debug + '_`, got `&u8`
6-
|
7-
note: previous use here
8-
--> $DIR/impl-fn-predefined-lifetimes.rs:7:5
9-
|
10-
LL | |x| x
11-
| ^^^^^
12-
13-
error[E0720]: cannot resolve opaque type
14-
--> $DIR/impl-fn-predefined-lifetimes.rs:4:35
1+
error[E0792]: expected generic lifetime parameter, found `'_`
2+
--> $DIR/impl-fn-predefined-lifetimes.rs:5:9
153
|
164
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
17-
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
5+
| -- this generic parameter must be used with a generic lifetime parameter
6+
LL | |x| x
7+
| ^
188

19-
error: aborting due to 2 previous errors
9+
error: aborting due to previous error
2010

21-
For more information about this error, try `rustc --explain E0720`.
11+
For more information about this error, try `rustc --explain E0792`.

‎tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ trait Foo {
55
fn bar<'other: 'a>() -> impl Sized + 'a {}
66
//~^ ERROR use of undeclared lifetime name `'a`
77
//~| ERROR use of undeclared lifetime name `'a`
8+
//~| ERROR expected generic lifetime parameter, found `'static`
89
}
910

1011
fn main() {}

‎tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ help: consider introducing lifetime `'a` here
2828
LL | trait Foo<'a> {
2929
| ++++
3030

31-
error: aborting due to 2 previous errors
31+
error[E0792]: expected generic lifetime parameter, found `'static`
32+
--> $DIR/bad-item-bound-within-rpitit-2.rs:5:45
33+
|
34+
LL | fn bar<'other: 'a>() -> impl Sized + 'a {}
35+
| ------ ^^
36+
| |
37+
| cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
38+
39+
error: aborting due to 3 previous errors
3240

33-
For more information about this error, try `rustc --explain E0261`.
41+
Some errors have detailed explanations: E0261, E0792.
42+
For more information about an error, try `rustc --explain E0261`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// issue: #111935
2+
3+
#![allow(unconditional_recursion)]
4+
5+
// Lt indirection is necessary to make the lifetime of the function late-bound,
6+
// in order to bypass some other bugs.
7+
type Lt<'lt> = Option<*mut &'lt ()>;
8+
9+
mod statik {
10+
use super::*;
11+
// invalid defining use: Opaque<'static> := ()
12+
fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
13+
let _: () = foo(Lt::<'static>::None);
14+
//~^ ERROR expected generic lifetime parameter, found `'static`
15+
}
16+
}
17+
18+
mod infer {
19+
use super::*;
20+
// invalid defining use: Opaque<'_> := ()
21+
fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
22+
let _: () = foo(Lt::<'_>::None);
23+
//~^ ERROR expected generic lifetime parameter, found `'_`
24+
}
25+
}
26+
27+
mod equal {
28+
use super::*;
29+
// invalid defining use: Opaque<'a, 'a> := ()
30+
// because of the use of equal lifetimes in args
31+
fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
32+
let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
33+
//~^ ERROR non-defining opaque type use in defining scope
34+
}
35+
}
36+
37+
fn main() {}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0792]: expected generic lifetime parameter, found `'static`
2+
--> $DIR/non-defining-use-lifetimes.rs:13:16
3+
|
4+
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
5+
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
6+
LL | let _: () = foo(Lt::<'static>::None);
7+
| ^^
8+
9+
error[E0792]: expected generic lifetime parameter, found `'_`
10+
--> $DIR/non-defining-use-lifetimes.rs:22:16
11+
|
12+
LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a {
13+
| -- this generic parameter must be used with a generic lifetime parameter
14+
LL | let _: () = foo(Lt::<'_>::None);
15+
| ^^
16+
17+
error: non-defining opaque type use in defining scope
18+
--> $DIR/non-defining-use-lifetimes.rs:32:16
19+
|
20+
LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None);
21+
| ^^
22+
|
23+
note: lifetime used multiple times
24+
--> $DIR/non-defining-use-lifetimes.rs:31:58
25+
|
26+
LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b {
27+
| ^^ ^^
28+
29+
error: aborting due to 3 previous errors
30+
31+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// User type annotation in fn bodies is a a valid defining site for opaque types.
22
// check-pass
3+
34
#![feature(type_alias_impl_trait)]
45

56
trait Equate { type Proj; }
@@ -8,12 +9,24 @@ impl<T> Equate for T { type Proj = T; }
89
trait Indirect { type Ty; }
910
impl<A, B: Equate<Proj = A>> Indirect for (A, B) { type Ty = (); }
1011

11-
type Opq = impl Sized;
12-
fn define_1(_: Opq) {
13-
let _ = None::<<(Opq, u8) as Indirect>::Ty>;
12+
mod basic {
13+
use super::*;
14+
type Opq = impl Sized;
15+
fn define_1(_: Opq) {
16+
let _ = None::<<(Opq, u8) as Indirect>::Ty>;
17+
}
18+
fn define_2() -> Opq {
19+
0u8
20+
}
1421
}
15-
fn define_2() -> Opq {
16-
0u8
22+
23+
// `Opq<'a> == &'b u8` shouldn't be an error because `'a == 'b`.
24+
mod lifetime {
25+
use super::*;
26+
type Opq<'a> = impl Sized + 'a;
27+
fn define<'a: 'b, 'b: 'a>(_: Opq<'a>) {
28+
let _ = None::<<(Opq<'a>, &'b u8) as Indirect>::Ty>;
29+
}
1730
}
1831

1932
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
mod case1 {
4+
type Opaque<'x> = impl Sized + 'x;
5+
fn foo<'s>() -> Opaque<'s> {
6+
let _ = || { let _: Opaque<'s> = (); };
7+
//~^ ERROR expected generic lifetime parameter, found `'_`
8+
}
9+
}
10+
11+
mod case2 {
12+
type Opaque<'x> = impl Sized + 'x;
13+
fn foo<'s>() -> Opaque<'s> {
14+
let _ = || -> Opaque<'s> {};
15+
//~^ ERROR expected generic lifetime parameter, found `'_`
16+
}
17+
}
18+
19+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0792]: expected generic lifetime parameter, found `'_`
2+
--> $DIR/defined-in-closure-external-lifetime.rs:6:29
3+
|
4+
LL | type Opaque<'x> = impl Sized + 'x;
5+
| -- this generic parameter must be used with a generic lifetime parameter
6+
LL | fn foo<'s>() -> Opaque<'s> {
7+
LL | let _ = || { let _: Opaque<'s> = (); };
8+
| ^^^^^^^^^^
9+
10+
error[E0792]: expected generic lifetime parameter, found `'_`
11+
--> $DIR/defined-in-closure-external-lifetime.rs:14:34
12+
|
13+
LL | type Opaque<'x> = impl Sized + 'x;
14+
| -- this generic parameter must be used with a generic lifetime parameter
15+
LL | fn foo<'s>() -> Opaque<'s> {
16+
LL | let _ = || -> Opaque<'s> {};
17+
| ^^
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// issue: #112841
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait Trait<'a, 'b> {}
6+
impl<T> Trait<'_, '_> for T {}
7+
8+
mod mod1 {
9+
type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
10+
fn test<'a>() -> Opaque<'a, 'a> {}
11+
//~^ ERROR non-defining opaque type use in defining scope
12+
//~| ERROR non-defining opaque type use in defining scope
13+
}
14+
15+
mod mod2 {
16+
type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
17+
fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {}
18+
//~^ ERROR non-defining opaque type use in defining scope
19+
}
20+
21+
mod mod3 {
22+
type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
23+
fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a }
24+
//~^ ERROR non-defining opaque type use in defining scope
25+
}
26+
27+
// This is similar to the previous cases in that 'a is equal to 'static,
28+
// which is is some sense an implicit parameter to `Opaque`.
29+
// For example, given a defining use `Opaque<'a> := &'a ()`,
30+
// it is ambiguous whether `Opaque<'a> := &'a ()` or `Opaque<'a> := &'static ()`
31+
mod mod4 {
32+
type Opaque<'a> = impl super::Trait<'a, 'a>;
33+
fn test<'a: 'static>() -> Opaque<'a> {}
34+
//~^ ERROR expected generic lifetime parameter, found `'static`
35+
}
36+
37+
fn main() {}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: non-defining opaque type use in defining scope
2+
--> $DIR/equal-lifetime-params-not-ok.rs:10:22
3+
|
4+
LL | fn test<'a>() -> Opaque<'a, 'a> {}
5+
| ^^^^^^^^^^^^^^ generic argument `'a` used twice
6+
|
7+
note: for this opaque type
8+
--> $DIR/equal-lifetime-params-not-ok.rs:9:27
9+
|
10+
LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: non-defining opaque type use in defining scope
14+
--> $DIR/equal-lifetime-params-not-ok.rs:10:37
15+
|
16+
LL | fn test<'a>() -> Opaque<'a, 'a> {}
17+
| ^^
18+
|
19+
note: lifetime used multiple times
20+
--> $DIR/equal-lifetime-params-not-ok.rs:9:17
21+
|
22+
LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
23+
| ^^ ^^
24+
25+
error: non-defining opaque type use in defining scope
26+
--> $DIR/equal-lifetime-params-not-ok.rs:17:49
27+
|
28+
LL | fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {}
29+
| ^^
30+
|
31+
note: lifetime used multiple times
32+
--> $DIR/equal-lifetime-params-not-ok.rs:16:17
33+
|
34+
LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
35+
| ^^ ^^
36+
37+
error: non-defining opaque type use in defining scope
38+
--> $DIR/equal-lifetime-params-not-ok.rs:23:61
39+
|
40+
LL | fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a }
41+
| ^
42+
|
43+
note: lifetime used multiple times
44+
--> $DIR/equal-lifetime-params-not-ok.rs:22:17
45+
|
46+
LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>;
47+
| ^^ ^^
48+
49+
error[E0792]: expected generic lifetime parameter, found `'static`
50+
--> $DIR/equal-lifetime-params-not-ok.rs:33:42
51+
|
52+
LL | type Opaque<'a> = impl super::Trait<'a, 'a>;
53+
| -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
54+
LL | fn test<'a: 'static>() -> Opaque<'a> {}
55+
| ^^
56+
57+
error: aborting due to 5 previous errors
58+
59+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// FIXME: description
2+
// issue: #113916
3+
// check-pass
4+
5+
#![feature(type_alias_impl_trait)]
6+
#![feature(impl_trait_in_assoc_type)]
7+
8+
trait Trait<'a, 'b> {}
9+
impl<T> Trait<'_, '_> for T {}
10+
11+
mod equal_params {
12+
type Opaque<'a: 'b, 'b: 'a> = impl super::Trait<'a, 'b>;
13+
fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {
14+
let _ = None::<&'a &'b &'a ()>;
15+
0u8
16+
}
17+
}
18+
19+
mod equal_static {
20+
type Opaque<'a: 'static> = impl Sized + 'a;
21+
fn test<'a: 'static>() -> Opaque<'a> {
22+
let _ = None::<&'static &'a ()>;
23+
0u8
24+
}
25+
}
26+
27+
mod implied_bounds {
28+
trait Traitor {
29+
type Assoc;
30+
fn define(self) -> Self::Assoc;
31+
}
32+
33+
impl<'a> Traitor for &'static &'a () {
34+
type Assoc = impl Sized + 'a;
35+
fn define(self) -> Self::Assoc {
36+
let _ = None::<&'static &'a ()>;
37+
0u8
38+
}
39+
}
40+
41+
impl<'a, 'b> Traitor for (&'a &'b (), &'b &'a ()) {
42+
type Assoc = impl Sized + 'a + 'b;
43+
fn define(self) -> Self::Assoc {
44+
let _ = None::<(&'a &'b (), &'b &'a ())>;
45+
0u8
46+
}
47+
}
48+
}
49+
50+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0792]: expected generic lifetime parameter, found `'_`
2+
--> $DIR/generic-not-strictly-equal.rs:33:5
3+
|
4+
LL | type Opaque<'a> = impl Copy + Captures<'a>;
5+
| -- this generic parameter must be used with a generic lifetime parameter
6+
...
7+
LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8
8+
| ^^^^^^^^^^^^^^^^^^^^^^
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0792`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0700]: hidden type for `Opaque<'x>` captures lifetime that does not appear in bounds
2+
--> $DIR/generic-not-strictly-equal.rs:33:5
3+
|
4+
LL | type Opaque<'a> = impl Copy + Captures<'a>;
5+
| ------------------------ opaque type defined here
6+
LL |
7+
LL | fn test<'x>(_: Opaque<'x>) {
8+
| -- hidden type `&'x u8` captures the lifetime `'x` as defined here
9+
...
10+
LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0700`.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// `Opaque<'?1> := u8` is not a valid defining use here.
2+
//
3+
// Due to fundamental limitations of the member constraints algorithm,
4+
// we require '?1 to be *equal* to some universal region.
5+
//
6+
// While '?1 is eventually inferred to be equal to 'x because of the constraint '?1: 'x,
7+
// we don't consider them equal in the strict sense because they lack the bidirectional outlives
8+
// constraints ['?1: 'x, 'x: '?1]. In NLL terms, they are not part of the same SCC.
9+
//
10+
// See #113971 for details.
11+
12+
// revisions: basic member_constraints
13+
#![feature(type_alias_impl_trait)]
14+
15+
trait Captures<'a> {}
16+
impl<T> Captures<'_> for T {}
17+
18+
fn ensure_outlives<'a, X: 'a>(_: X) {}
19+
fn relate<X>(_: X, _: X) {}
20+
21+
type Opaque<'a> = impl Copy + Captures<'a>;
22+
23+
fn test<'x>(_: Opaque<'x>) {
24+
let opaque = None::<Opaque<'_>>; // let's call this lifetime '?1
25+
26+
#[cfg(basic)]
27+
let hidden = None::<u8>;
28+
29+
#[cfg(member_constraints)]
30+
let hidden = None::<&'x u8>;
31+
32+
ensure_outlives::<'x>(opaque); // outlives constraint: '?1: 'x
33+
relate(opaque, hidden); // defining use: Opaque<'?1> := u8
34+
//[basic]~^ ERROR expected generic lifetime parameter, found `'_`
35+
//[member_constraints]~^^ ERROR captures lifetime that does not appear in bounds
36+
}
37+
38+
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.