Skip to content

Commit cb043b9

Browse files
committed
Propagate the object lifetime default of GAT's own params
Notably, this excludes the self ty.
1 parent 97c966b commit cb043b9

10 files changed

+181
-27
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -887,11 +887,34 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
887887
}
888888
}
889889

890+
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) {
891+
match qpath {
892+
hir::QPath::Resolved(maybe_qself, path) => {
893+
if let Some(qself) = maybe_qself {
894+
// FIXME: Actually properly determine the OLD for the self ty!
895+
let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope };
896+
self.with(scope, |this| this.visit_ty_unambig(qself));
897+
}
898+
self.visit_path(path, id);
899+
}
900+
hir::QPath::TypeRelative(qself, segment) => {
901+
// Resolving object lifetime defaults for type-relative paths requires type-dependent
902+
// resolution which we don't do here.
903+
// FIXME: How feasible would it be to track type-dependent defs here in RBVs?
904+
let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope };
905+
self.with(scope, |this| {
906+
this.visit_ty_unambig(qself);
907+
this.visit_path_segment(segment)
908+
});
909+
}
910+
hir::QPath::LangItem(..) => {}
911+
}
912+
}
913+
890914
fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) {
891-
for (i, segment) in path.segments.iter().enumerate() {
892-
let depth = path.segments.len() - i - 1;
915+
for (index, segment) in path.segments.iter().enumerate() {
893916
if let Some(args) = segment.args {
894-
self.visit_segment_args(path.res, depth, args);
917+
self.visit_segment_args(path, index, args);
895918
}
896919
}
897920
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
@@ -1611,8 +1634,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16111634
#[instrument(level = "debug", skip(self))]
16121635
fn visit_segment_args(
16131636
&mut self,
1614-
res: Res,
1615-
depth: usize,
1637+
path: &hir::Path<'tcx>,
1638+
index: usize,
16161639
generic_args: &'tcx hir::GenericArgs<'tcx>,
16171640
) {
16181641
if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
@@ -1626,19 +1649,23 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16261649
}
16271650
}
16281651

1629-
// Figure out if this is a type/trait segment,
1630-
// which requires object lifetime defaults.
1631-
let type_def_id = match res {
1632-
Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)),
1633-
Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)),
1634-
Res::Def(
1635-
DefKind::Struct
1636-
| DefKind::Union
1637-
| DefKind::Enum
1638-
| DefKind::TyAlias
1639-
| DefKind::Trait,
1640-
def_id,
1641-
) if depth == 0 => Some(def_id),
1652+
// Figure out if this is a type/trait segment, which requires object lifetime defaults.
1653+
let depth = path.segments.len() - index - 1;
1654+
let type_def_id = match (path.res, depth) {
1655+
(Res::Def(DefKind::AssocTy, def_id), 1) => Some(self.tcx.parent(def_id)),
1656+
(Res::Def(DefKind::Variant, def_id), 0) => Some(self.tcx.parent(def_id)),
1657+
(
1658+
Res::Def(
1659+
DefKind::Struct
1660+
| DefKind::Union
1661+
| DefKind::Enum
1662+
| DefKind::TyAlias
1663+
| DefKind::Trait
1664+
| DefKind::AssocTy,
1665+
def_id,
1666+
),
1667+
0,
1668+
) => Some(def_id),
16421669
_ => None,
16431670
};
16441671

@@ -1683,9 +1710,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16831710
let rbv = &self.rbv;
16841711
let generics = self.tcx.generics_of(def_id);
16851712

1686-
// `type_def_id` points to an item, so there is nothing to inherit generics from.
1687-
debug_assert_eq!(generics.parent_count, 0);
1688-
16891713
let set_to_region = |set: ObjectLifetimeDefault| match set {
16901714
ObjectLifetimeDefault::Empty => {
16911715
if in_body {
@@ -1696,12 +1720,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16961720
}
16971721
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
16981722
ObjectLifetimeDefault::Param(param_def_id) => {
1699-
// This index can be used with `generic_args` since `parent_count == 0`.
1700-
let index = generics.param_def_id_to_index[&param_def_id] as usize;
1701-
generic_args.args.get(index).and_then(|arg| match arg {
1702-
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1703-
_ => None,
1704-
})
1723+
fn param_to_depth_and_index(
1724+
generics: &ty::Generics,
1725+
tcx: TyCtxt<'_>,
1726+
def_id: DefId,
1727+
) -> (usize, usize) {
1728+
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1729+
let has_self = generics.parent.is_none() && generics.has_self;
1730+
(0, index as usize - generics.parent_count - has_self as usize)
1731+
} else if let Some(parent) = generics.parent {
1732+
let parent = tcx.generics_of(parent);
1733+
let (index, depth) = param_to_depth_and_index(parent, tcx, def_id);
1734+
(depth + 1, index)
1735+
} else {
1736+
unreachable!()
1737+
}
1738+
}
1739+
1740+
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1741+
path.segments[path.segments.len() - depth - 1]
1742+
.args
1743+
.and_then(|args| args.args.get(index))
1744+
.and_then(|arg| match arg {
1745+
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1746+
_ => None,
1747+
})
17051748
}
17061749
ObjectLifetimeDefault::Ambiguous => None,
17071750
};

src/librustdoc/clean/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,8 @@ impl<'tcx> ContainerTy<'_, 'tcx> {
20212021
match self {
20222022
Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
20232023
Self::Regular { ty: container, args, arg: index } => {
2024+
// FIXME: Update this to handle AssocTys.
2025+
20242026
let (DefKind::Struct
20252027
| DefKind::Union
20262028
| DefKind::Enum
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// FIXME: Explainer.
2+
//@ known-bug: unknown
3+
4+
trait Outer { type Ty; }
5+
trait Inner {}
6+
7+
impl<'a> Outer for dyn Inner + 'a { type Ty = &'a (); }
8+
9+
fn f<'r>(x: &'r <dyn Inner + 'static as Outer>::Ty) { g(x) }
10+
// FIXME: Should infer `+ 'static`:
11+
fn g<'r>(x: &'r <dyn Inner as Outer>::Ty) {}
12+
13+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
2+
--> $DIR/object-lifetime-default-assoc-ty-self-ty-static.rs:11:18
3+
|
4+
LL | fn g<'r>(x: &'r <dyn Inner as Outer>::Ty) {}
5+
| ^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0228`.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// FIXME: Explainer
2+
//@ known-bug: unknown
3+
4+
trait Outer<'a>: 'a { type Ty; }
5+
trait Inner {}
6+
7+
impl<'a> Outer<'a> for dyn Inner + 'a { type Ty = &'a (); }
8+
9+
fn f<'r>(x: <dyn Inner + 'r as Outer<'r>>::Ty) { g(x) }
10+
// FIXME: Should infer `+ 'r`:
11+
fn g<'r>(x: <dyn Inner as Outer<'r>>::Ty) {}
12+
13+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
2+
--> $DIR/object-lifetime-default-assoc-ty-self-ty.rs:11:14
3+
|
4+
LL | fn g<'r>(x: <dyn Inner as Outer<'r>>::Ty) {}
5+
| ^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0228`.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Properly deduce the object lifetime default in generic associated type (GAT) *paths*.
2+
// issue: <https://github.com/rust-lang/rust/issues/115379>
3+
//@ check-pass
4+
5+
mod own { // the object lifetime default comes from the own generics
6+
trait Outer {
7+
type Ty<'a, T: ?Sized + 'a>;
8+
}
9+
impl Outer for () {
10+
type Ty<'a, T: ?Sized + 'a> = &'a T;
11+
}
12+
trait Inner {}
13+
14+
fn f<'r>(x: <() as Outer>::Ty<'r, dyn Inner + 'r>) { g(x) }
15+
fn g<'r>(_: <() as Outer>::Ty<'r, dyn Inner>) {}
16+
}
17+
18+
mod parent { // the object lifetime default comes from the parent generics
19+
trait Outer<'a> {
20+
type Ty<T: ?Sized + 'a>;
21+
}
22+
impl<'a> Outer<'a> for () {
23+
type Ty<T: ?Sized + 'a> = &'a T;
24+
}
25+
trait Inner {}
26+
27+
fn f<'r>(x: <() as Outer<'r>>::Ty<dyn Inner + 'r>) { g(x) }
28+
fn g<'r>(_: <() as Outer<'r>>::Ty<dyn Inner>) {}
29+
}
30+
31+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// FIXME: Explainer
2+
3+
trait Outer { type Ty<'a, T: 'a + ?Sized>; }
4+
trait Inner {}
5+
6+
fn f<'r, T: Outer>(x: T::Ty<'r, dyn Inner>) {}
7+
//~^ ERROR lifetime bound for this object type cannot be deduced from context
8+
9+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
2+
--> $DIR/object-lifetime-default-gat-type-relative.rs:6:33
3+
|
4+
LL | fn f<'r, T: Outer>(x: T::Ty<'r, dyn Inner>) {}
5+
| ^^^^^^^^^
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0228`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// FIXME: Explainer (used to fail: "inderminate" due to an off by one :^))
2+
//@ check-pass
3+
4+
trait Inner {}
5+
trait Outer<'a, T: 'a + ?Sized> {}
6+
7+
fn bound0<'r, T>() where T: Outer<'r, dyn Inner + 'r> { bound1::<'r, T>() }
8+
fn bound1<'r, T>() where T: Outer<'r, dyn Inner> {}
9+
10+
fn dyn0<'r>(x: Box<dyn Outer<'r, dyn Inner + 'r>>) { dyn1(x) }
11+
fn dyn1<'r>(_: Box<dyn Outer<'r, dyn Inner>>) {}
12+
13+
fn impl0<'r>(x: impl Outer<'r, dyn Inner + 'r>) { impl1(x) }
14+
fn impl1<'r>(_: impl Outer<'r, dyn Inner>) {}
15+
16+
fn main() {}

0 commit comments

Comments
 (0)