Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 551f51f

Browse files
committed
Propagate the object lifetime defaults of GAT's own params
Notably, this excludes the self ty. This automatically fixes object lifetime defaulting for trait refs, too. These used to be broken because the index calculation for going from middle generic args back to HIR ones didn't take into account the implicit self ty param present of traits.
1 parent b8c54d6 commit 551f51f

14 files changed

+257
-56
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
780780
// use the object lifetime defaulting
781781
// rules. So e.g., `Box<dyn Debug>` becomes
782782
// `Box<dyn Debug + 'static>`.
783-
self.resolve_object_lifetime_default(&*lifetime)
783+
self.resolve_object_lifetime_default(&*lifetime);
784784
}
785785
LifetimeKind::Infer => {
786786
// If the user writes `'_`, we use the *ordinary* elision
@@ -799,7 +799,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
799799
hir::TyKind::Ref(lifetime_ref, ref mt) => {
800800
self.visit_lifetime(lifetime_ref);
801801
let scope = Scope::ObjectLifetimeDefault {
802-
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
802+
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).copied(),
803803
s: self.scope,
804804
};
805805
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
@@ -887,11 +887,36 @@ 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 determine the ambient object lifetime defaults 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 full
902+
// type-dependent resolution as performed by HIR ty lowering whose results
903+
// we don't have access to (and we'd results for both FnCtxts and ItemCtxts).
904+
// FIXME: Figure out if there's a feasible way to obtain the map of
905+
// type-dependent definitions.
906+
let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope };
907+
self.with(scope, |this| {
908+
this.visit_ty_unambig(qself);
909+
this.visit_path_segment(segment)
910+
});
911+
}
912+
hir::QPath::LangItem(..) => {}
913+
}
914+
}
915+
890916
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;
917+
for (index, segment) in path.segments.iter().enumerate() {
893918
if let Some(args) = segment.args {
894-
self.visit_segment_args(path.res, depth, args);
919+
self.visit_segment_args(path, index, args);
895920
}
896921
}
897922
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
@@ -1611,55 +1636,72 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16111636
#[instrument(level = "debug", skip(self))]
16121637
fn visit_segment_args(
16131638
&mut self,
1614-
res: Res,
1615-
depth: usize,
1639+
path: &hir::Path<'tcx>,
1640+
index: usize,
16161641
generic_args: &'tcx hir::GenericArgs<'tcx>,
16171642
) {
16181643
if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
16191644
self.visit_fn_like_elision(inputs, Some(output), false);
16201645
return;
16211646
}
16221647

1648+
// Let's first resolve all lifetime arguments because we need their resolution
1649+
// for computing the ambient object lifetime defaults.
16231650
for arg in generic_args.args {
16241651
if let hir::GenericArg::Lifetime(lt) = arg {
16251652
self.visit_lifetime(lt);
16261653
}
16271654
}
16281655

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),
1656+
// Figure out if this is an "eligible generic container" that brings along ambient object
1657+
// lifetime defaults for trait object types contained in any of the type arguments passed to
1658+
// it (any inner generic containers will of course end up shadowing that the default).
1659+
let depth = path.segments.len() - index - 1;
1660+
let container = match (path.res, depth) {
1661+
(Res::Def(DefKind::AssocTy, def_id), 1) => {
1662+
Some((self.tcx.parent(def_id), &path.segments[..=index]))
1663+
}
1664+
(Res::Def(DefKind::Variant, def_id), 0) => {
1665+
Some((self.tcx.parent(def_id), path.segments))
1666+
}
1667+
// FIXME(trait_alias): Arguably, trait aliases are eligible generic containers.
1668+
(
1669+
Res::Def(
1670+
DefKind::Struct
1671+
| DefKind::Union
1672+
| DefKind::Enum
1673+
| DefKind::TyAlias
1674+
| DefKind::Trait
1675+
| DefKind::AssocTy,
1676+
def_id,
1677+
),
1678+
0,
1679+
) => Some((def_id, path.segments)),
1680+
// Note: We don't need to care about definitions kinds that can have generics if they
1681+
// can only ever appear in positions where we can perform type inference (i.e., bodies).
1682+
// FIXME(mgca): @fmease thinks that under (m)GCA we now also need to care about e.g.,
1683+
// type-level Consts (GCI) and AssocConsts (maybe also Fns, AssocFns) here
1684+
// since they appear outside of bodies (once the feature is more complete).
16421685
_ => None,
16431686
};
16441687

1645-
debug!(?type_def_id);
1688+
debug!(?container);
16461689

1647-
// Compute a vector of defaults, one for each type parameter,
1648-
// per the rules given in RFCs 599 and 1156. Example:
1690+
// Compute a vector of ambient object lifetime defaults, one for each type parameter,
1691+
// per the rules initially given in RFCs 599 and 1156. Example:
16491692
//
16501693
// ```rust
1651-
// struct Foo<'a, T: 'a, U> { }
1694+
// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U);
16521695
// ```
16531696
//
16541697
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
16551698
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
16561699
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
16571700
// such bound).
16581701
//
1659-
// Therefore, we would compute `object_lifetime_defaults` to a
1660-
// vector like `['x, 'static]`. Note that the vector only
1661-
// includes type parameters.
1662-
let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| {
1702+
// Therefore, we would compute a vector like `['x, 'static]`.
1703+
// Note that the vector only includes type parameters.
1704+
let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segments)| {
16631705
let in_body = {
16641706
let mut scope = self.scope;
16651707
loop {
@@ -1683,9 +1725,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16831725
let rbv = &self.rbv;
16841726
let generics = self.tcx.generics_of(def_id);
16851727

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-
16891728
let set_to_region = |set: ObjectLifetimeDefault| match set {
16901729
ObjectLifetimeDefault::Empty => {
16911730
if in_body {
@@ -1696,12 +1735,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16961735
}
16971736
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
16981737
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-
})
1738+
fn param_to_depth_and_index(
1739+
generics: &ty::Generics,
1740+
tcx: TyCtxt<'_>,
1741+
def_id: DefId,
1742+
) -> (usize, usize) {
1743+
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1744+
let has_self = generics.parent.is_none() && generics.has_self;
1745+
(0, index as usize - generics.parent_count - has_self as usize)
1746+
} else if let Some(parent) = generics.parent {
1747+
let parent = tcx.generics_of(parent);
1748+
let (index, depth) = param_to_depth_and_index(parent, tcx, def_id);
1749+
(depth + 1, index)
1750+
} else {
1751+
unreachable!()
1752+
}
1753+
}
1754+
1755+
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1756+
segments[segments.len() - depth - 1]
1757+
.args
1758+
.and_then(|args| args.args.get(index))
1759+
.and_then(|arg| match arg {
1760+
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1761+
_ => None,
1762+
})
17051763
}
17061764
ObjectLifetimeDefault::Ambiguous => None,
17071765
};
@@ -1731,6 +1789,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17311789
let mut i = 0;
17321790
for arg in generic_args.args {
17331791
match arg {
1792+
// We've already visited all lifetime arguments at the start.
17341793
GenericArg::Lifetime(_) => {}
17351794
GenericArg::Type(ty) => {
17361795
if let Some(&lt) = object_lifetime_defaults.get(i) {
@@ -1805,11 +1864,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18051864
// `for<'a> for<'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
18061865
if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation
18071866
{
1808-
let bound_vars = if let Some(type_def_id) = type_def_id
1809-
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
1867+
let bound_vars = if let Some((container_def_id, _)) = container
1868+
&& self.tcx.def_kind(container_def_id) == DefKind::Trait
18101869
&& let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
18111870
self.tcx,
1812-
type_def_id,
1871+
container_def_id,
18131872
constraint.ident,
18141873
ty::AssocTag::Fn,
18151874
) {
@@ -1838,10 +1897,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18381897
this.visit_assoc_item_constraint(constraint)
18391898
});
18401899
});
1841-
} else if let Some(type_def_id) = type_def_id {
1900+
} else if let Some((container_def_id, _)) = container {
18421901
let bound_vars = BoundVarContext::supertrait_hrtb_vars(
18431902
self.tcx,
1844-
type_def_id,
1903+
container_def_id,
18451904
constraint.ident,
18461905
ty::AssocTag::Type,
18471906
)

src/librustdoc/clean/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,9 @@ impl<'tcx> ContainerTy<'_, 'tcx> {
19941994
match self {
19951995
Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
19961996
Self::Regular { ty: container, args, arg: index } => {
1997+
// FIXME(fmease): rustc now also computes ambient object lifetime defaults for
1998+
// `AssocTy`s. Re-elide these, too!
1999+
19972000
let (DefKind::Struct
19982001
| DefKind::Union
19992002
| DefKind::Enum

tests/ui/deriving/issue-89188-gat-hrtb.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//@ check-pass
1+
// FIXME(fmease): I've regressed this one since we now reject TypeRelative paths as too complex.
2+
//@ known-bug: unknown
23

34
trait CallWithShim: Sized {
45
type Shim<'s>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
2+
--> $DIR/issue-89188-gat-hrtb.rs:27:56
3+
|
4+
LL | &'s mut T::Shim<dyn for<'t> Fn(&'s mut T::Shim<dyn for<'u> Trait<'s, 't, 'u>>)>,
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
8+
--> $DIR/issue-89188-gat-hrtb.rs:27:56
9+
|
10+
LL | &'s mut T::Shim<dyn for<'t> Fn(&'s mut T::Shim<dyn for<'u> Trait<'s, 't, 'u>>)>,
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
|
13+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14+
15+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
16+
--> $DIR/issue-89188-gat-hrtb.rs:27:56
17+
|
18+
LL | &'s mut T::Shim<dyn for<'t> Fn(&'s mut T::Shim<dyn for<'u> Trait<'s, 't, 'u>>)>,
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
|
21+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
22+
23+
error: aborting due to 3 previous errors
24+
25+
For more information about this error, try `rustc --explain E0228`.

tests/ui/did_you_mean/bad-assoc-ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type G = dyn 'static + (Send)::AssocTy;
3131
// This is actually a legal path with fn-like generic arguments in the middle!
3232
// Recovery should not apply in this context.
3333
type H = Fn(u8) -> (u8)::Output;
34-
//~^ ERROR ambiguous associated type
34+
//~^ ERROR the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
3535
//~| WARN trait objects without an explicit `dyn` are deprecated
3636
//~| WARN this is accepted in the current edition
3737

tests/ui/did_you_mean/bad-assoc-ty.stderr

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -193,20 +193,11 @@ help: if this is a dyn-compatible trait, use `dyn`
193193
LL | type H = <dyn Fn(u8) -> (u8)>::Output;
194194
| ++++ +
195195

196-
error[E0223]: ambiguous associated type
196+
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
197197
--> $DIR/bad-assoc-ty.rs:33:10
198198
|
199199
LL | type H = Fn(u8) -> (u8)::Output;
200-
| ^^^^^^^^^^^^^^^^^^^^^^
201-
|
202-
help: use fully-qualified syntax
203-
|
204-
LL - type H = Fn(u8) -> (u8)::Output;
205-
LL + type H = <(dyn Fn(u8) -> u8 + 'static) as BitOr>::Output;
206-
|
207-
LL - type H = Fn(u8) -> (u8)::Output;
208-
LL + type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output;
209-
|
200+
| ^^^^^^^^^^^^^^
210201

211202
error[E0223]: ambiguous associated type
212203
--> $DIR/bad-assoc-ty.rs:39:19
@@ -354,5 +345,5 @@ LL + trait P<F, T> where F: Fn() -> T {
354345

355346
error: aborting due to 29 previous errors; 1 warning emitted
356347

357-
Some errors have detailed explanations: E0121, E0223, E0740.
348+
Some errors have detailed explanations: E0121, E0223, E0228, E0740.
358349
For more information about an error, try `rustc --explain E0121`.
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+
// FIXME: Deduce `dyn Inner + 'static` from absence of any bounds on self ty param of trait `Outer`.
10+
fn f<'r>(x: &'r <dyn Inner as Outer>::Ty) { g(x) }
11+
fn g<'r>(x: &'r <dyn Inner + 'static 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:10:18
3+
|
4+
LL | fn f<'r>(x: &'r <dyn Inner as Outer>::Ty) { g(x) }
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: Deduce `dyn Inner + 'r` from bound `'a` on self ty param of trait `Outer`.
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`.

0 commit comments

Comments
 (0)