Skip to content

Commit 7a89da3

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 f40a70d commit 7a89da3

14 files changed

+281
-57
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 100 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
777777
// use the object lifetime defaulting
778778
// rules. So e.g., `Box<dyn Debug>` becomes
779779
// `Box<dyn Debug + 'static>`.
780-
self.resolve_object_lifetime_default(&*lifetime)
780+
self.resolve_object_lifetime_default(&*lifetime);
781781
}
782782
LifetimeKind::Infer => {
783783
// If the user writes `'_`, we use the *ordinary* elision
@@ -796,7 +796,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
796796
hir::TyKind::Ref(lifetime_ref, ref mt) => {
797797
self.visit_lifetime(lifetime_ref);
798798
let scope = Scope::ObjectLifetimeDefault {
799-
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
799+
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).copied(),
800800
s: self.scope,
801801
};
802802
self.with(scope, |this| this.visit_ty_unambig(mt.ty));
@@ -884,11 +884,35 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
884884
}
885885
}
886886

887+
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) {
888+
match qpath {
889+
hir::QPath::Resolved(maybe_qself, path) => {
890+
if let Some(qself) = maybe_qself {
891+
// FIXME: Actually determine the ambient object lifetime defaults for the self ty!
892+
let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope };
893+
self.with(scope, |this| this.visit_ty_unambig(qself));
894+
}
895+
self.visit_path(path, id);
896+
}
897+
hir::QPath::TypeRelative(qself, segment) => {
898+
// Resolving object lifetime defaults for type-relative paths requires full
899+
// type-dependent resolution as performed by HIR ty lowering whose results
900+
// we don't have access to (and we'd results for both FnCtxts and ItemCtxts).
901+
// FIXME: Figure out if there's a feasible way to obtain the map of
902+
// type-dependent definitions.
903+
let scope = Scope::ObjectLifetimeDefault { lifetime: None, s: self.scope };
904+
self.with(scope, |this| {
905+
this.visit_ty_unambig(qself);
906+
this.visit_path_segment(segment)
907+
});
908+
}
909+
}
910+
}
911+
887912
fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) {
888-
for (i, segment) in path.segments.iter().enumerate() {
889-
let depth = path.segments.len() - i - 1;
913+
for (index, segment) in path.segments.iter().enumerate() {
890914
if let Some(args) = segment.args {
891-
self.visit_segment_args(path.res, depth, args);
915+
self.visit_segment_args(path, index, args);
892916
}
893917
}
894918
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
@@ -1617,55 +1641,72 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16171641
#[instrument(level = "debug", skip(self))]
16181642
fn visit_segment_args(
16191643
&mut self,
1620-
res: Res,
1621-
depth: usize,
1644+
path: &hir::Path<'tcx>,
1645+
index: usize,
16221646
generic_args: &'tcx hir::GenericArgs<'tcx>,
16231647
) {
16241648
if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
16251649
self.visit_fn_like_elision(inputs, Some(output), false);
16261650
return;
16271651
}
16281652

1653+
// Let's first resolve all lifetime arguments because we need their resolution
1654+
// for computing the ambient object lifetime defaults.
16291655
for arg in generic_args.args {
16301656
if let hir::GenericArg::Lifetime(lt) = arg {
16311657
self.visit_lifetime(lt);
16321658
}
16331659
}
16341660

1635-
// Figure out if this is a type/trait segment,
1636-
// which requires object lifetime defaults.
1637-
let type_def_id = match res {
1638-
Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)),
1639-
Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)),
1640-
Res::Def(
1641-
DefKind::Struct
1642-
| DefKind::Union
1643-
| DefKind::Enum
1644-
| DefKind::TyAlias
1645-
| DefKind::Trait,
1646-
def_id,
1647-
) if depth == 0 => Some(def_id),
1661+
// Figure out if this is an "eligible generic container" that brings along ambient object
1662+
// lifetime defaults for trait object types contained in any of the type arguments passed to
1663+
// it (any inner generic containers will of course end up shadowing that the default).
1664+
let depth = path.segments.len() - index - 1;
1665+
let container = match (path.res, depth) {
1666+
(Res::Def(DefKind::AssocTy, def_id), 1) => {
1667+
Some((self.tcx.parent(def_id), &path.segments[..=index]))
1668+
}
1669+
(Res::Def(DefKind::Variant, def_id), 0) => {
1670+
Some((self.tcx.parent(def_id), path.segments))
1671+
}
1672+
// FIXME(trait_alias): Arguably, trait aliases are eligible generic containers.
1673+
(
1674+
Res::Def(
1675+
DefKind::Struct
1676+
| DefKind::Union
1677+
| DefKind::Enum
1678+
| DefKind::TyAlias
1679+
| DefKind::Trait
1680+
| DefKind::AssocTy,
1681+
def_id,
1682+
),
1683+
0,
1684+
) => Some((def_id, path.segments)),
1685+
// Note: We don't need to care about definition kinds that may have generics if they
1686+
// can only ever appear in positions where we can perform type inference (i.e., bodies).
1687+
// FIXME(mgca): @fmease thinks that under (m)GCA we now also need to care about e.g.,
1688+
// type-level Consts (GCI) and AssocConsts (maybe also Fns, AssocFns) here
1689+
// since they appear outside of bodies (once the feature is more complete).
16481690
_ => None,
16491691
};
16501692

1651-
debug!(?type_def_id);
1693+
debug!(?container);
16521694

1653-
// Compute a vector of defaults, one for each type parameter,
1654-
// per the rules given in RFCs 599 and 1156. Example:
1695+
// Compute a vector of ambient object lifetime defaults, one for each type parameter,
1696+
// per the rules initially given in RFCs 599 and 1156. Example:
16551697
//
16561698
// ```rust
1657-
// struct Foo<'a, T: 'a, U> { }
1699+
// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U);
16581700
// ```
16591701
//
16601702
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
16611703
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
16621704
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
16631705
// such bound).
16641706
//
1665-
// Therefore, we would compute `object_lifetime_defaults` to a
1666-
// vector like `['x, 'static]`. Note that the vector only
1667-
// includes type parameters.
1668-
let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| {
1707+
// Therefore, we would compute a vector like `['x, 'static]`.
1708+
// Note that the vector only includes type parameters.
1709+
let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segments)| {
16691710
let in_body = {
16701711
let mut scope = self.scope;
16711712
loop {
@@ -1689,9 +1730,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16891730
let rbv = &self.rbv;
16901731
let generics = self.tcx.generics_of(def_id);
16911732

1692-
// `type_def_id` points to an item, so there is nothing to inherit generics from.
1693-
debug_assert_eq!(generics.parent_count, 0);
1694-
16951733
let set_to_region = |set: ObjectLifetimeDefault| match set {
16961734
ObjectLifetimeDefault::Empty => {
16971735
if in_body {
@@ -1702,12 +1740,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17021740
}
17031741
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
17041742
ObjectLifetimeDefault::Param(param_def_id) => {
1705-
// This index can be used with `generic_args` since `parent_count == 0`.
1706-
let index = generics.param_def_id_to_index[&param_def_id] as usize;
1707-
generic_args.args.get(index).and_then(|arg| match arg {
1708-
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1709-
_ => None,
1710-
})
1743+
fn param_to_depth_and_index(
1744+
generics: &ty::Generics,
1745+
tcx: TyCtxt<'_>,
1746+
def_id: DefId,
1747+
) -> (usize, usize) {
1748+
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1749+
let has_self = generics.parent.is_none() && generics.has_self;
1750+
(0, index as usize - generics.parent_count - has_self as usize)
1751+
} else if let Some(parent) = generics.parent {
1752+
let parent = tcx.generics_of(parent);
1753+
let (depth, index) = param_to_depth_and_index(parent, tcx, def_id);
1754+
(depth + 1, index)
1755+
} else {
1756+
unreachable!()
1757+
}
1758+
}
1759+
1760+
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1761+
segments[segments.len() - depth - 1]
1762+
.args
1763+
.and_then(|args| args.args.get(index))
1764+
.and_then(|arg| match arg {
1765+
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1766+
_ => None,
1767+
})
17111768
}
17121769
ObjectLifetimeDefault::Ambiguous => None,
17131770
};
@@ -1737,6 +1794,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17371794
let mut i = 0;
17381795
for arg in generic_args.args {
17391796
match arg {
1797+
// We've already visited all lifetime arguments at the start.
17401798
GenericArg::Lifetime(_) => {}
17411799
GenericArg::Type(ty) => {
17421800
if let Some(&lt) = object_lifetime_defaults.get(i) {
@@ -1811,11 +1869,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18111869
// `for<'a> for<'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
18121870
if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation
18131871
{
1814-
let bound_vars = if let Some(type_def_id) = type_def_id
1815-
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
1872+
let bound_vars = if let Some((container_def_id, _)) = container
1873+
&& self.tcx.def_kind(container_def_id) == DefKind::Trait
18161874
&& let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars(
18171875
self.tcx,
1818-
type_def_id,
1876+
container_def_id,
18191877
constraint.ident,
18201878
ty::AssocTag::Fn,
18211879
) {
@@ -1844,10 +1902,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18441902
this.visit_assoc_item_constraint(constraint)
18451903
});
18461904
});
1847-
} else if let Some(type_def_id) = type_def_id {
1905+
} else if let Some((container_def_id, _)) = container {
18481906
let bound_vars = BoundVarContext::supertrait_hrtb_vars(
18491907
self.tcx,
1850-
type_def_id,
1908+
container_def_id,
18511909
constraint.ident,
18521910
ty::AssocTag::Type,
18531911
)

src/librustdoc/clean/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,9 @@ impl<'tcx> ContainerTy<'_, 'tcx> {
19681968
match self {
19691969
Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
19701970
Self::Regular { ty: container, args, arg: index } => {
1971+
// FIXME(fmease): rustc now also computes ambient object lifetime defaults for
1972+
// `AssocTy`s. Re-elide these, too!
1973+
19711974
let (DefKind::Struct
19721975
| DefKind::Union
19731976
| 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.edition2015.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:37: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:44:19
@@ -310,5 +301,5 @@ LL | fn foo<F>(_: F) where F: Fn() -> _ {}
310301

311302
error: aborting due to 30 previous errors; 1 warning emitted
312303

313-
Some errors have detailed explanations: E0121, E0223, E0740.
304+
Some errors have detailed explanations: E0121, E0223, E0228, E0740.
314305
For more information about an error, try `rustc --explain E0121`.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ type G = dyn 'static + (Send)::AssocTy;
3535
// This is actually a legal path with fn-like generic arguments in the middle!
3636
// Recovery should not apply in this context.
3737
type H = Fn(u8) -> (u8)::Output;
38-
//[edition2015]~^ ERROR ambiguous associated type
38+
//[edition2021]~^ ERROR expected a type, found a trait
39+
//[edition2015]~^^ ERROR the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
3940
//[edition2015]~| WARN trait objects without an explicit `dyn` are deprecated
4041
//[edition2015]~| WARN this is accepted in the current edition
41-
//[edition2021]~^^^^ ERROR expected a type, found a trait
4242

4343
macro_rules! ty {
4444
($ty: ty) => ($ty::AssocTy);
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)