Skip to content

Commit a0c12b4

Browse files
committed
Propagate the object lifetime default to the self ty of resolved projections
1 parent 0d034e1 commit a0c12b4

File tree

6 files changed

+183
-166
lines changed

6 files changed

+183
-166
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 173 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
77
//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
88
9+
use std::assert_matches::assert_matches;
910
use std::cell::RefCell;
1011
use std::fmt;
1112
use std::ops::ControlFlow;
@@ -890,12 +891,28 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
890891
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: HirId, _: Span) {
891892
match qpath {
892893
hir::QPath::Resolved(maybe_qself, path) => {
894+
// Visit the path before the self type since computing the ambient object lifetime default
895+
// for the latter requires all lifetime arguments of the trait ref to be already resolved.
896+
self.visit_path(path, id);
893897
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));
898+
let container = match path.res {
899+
Res::Def(DefKind::AssocTy, def_id) => Some((
900+
self.tcx.parent(def_id),
901+
&path.segments[..path.segments.len() - 1],
902+
)),
903+
_ => None,
904+
};
905+
let object_lifetime_defaults =
906+
container.map_or(Vec::new(), |(def_id, segs)| {
907+
self.compute_ambient_object_lifetime_defaults(def_id, segs)
908+
});
909+
if let Some(&lt) = object_lifetime_defaults.get(0) {
910+
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
911+
self.with(scope, |this| this.visit_ty_unambig(qself));
912+
} else {
913+
self.visit_ty_unambig(qself);
914+
}
897915
}
898-
self.visit_path(path, id);
899916
}
900917
hir::QPath::TypeRelative(qself, segment) => {
901918
// Resolving object lifetime defaults for type-relative paths requires full
@@ -1060,51 +1077,53 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
10601077
}
10611078

10621079
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
1063-
let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else {
1064-
bug!("expected GenericParam for object_lifetime_default");
1080+
// Scan the bounds and where-clauses on parameters to extract bounds of the form `T: 'a`
1081+
// so as to determine the `ObjectLifetimeDefault` for each type parameter.
1082+
1083+
let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) {
1084+
hir::Node::GenericParam(param) => match param.source {
1085+
hir::GenericParamSource::Generics => {
1086+
assert_matches!(param.kind, GenericParamKind::Type { .. });
1087+
(tcx.hir_get_generics(tcx.local_parent(param_def_id)).unwrap(), &[][..])
1088+
}
1089+
hir::GenericParamSource::Binder => return ObjectLifetimeDefault::Empty,
1090+
},
1091+
// For Self ty params
1092+
hir::Node::Item(&hir::Item {
1093+
kind: hir::ItemKind::Trait(_, _, _, generics, bounds, _),
1094+
..
1095+
}) => (generics, bounds),
1096+
_ => bug!("`object_lifetime_default` must only be called on type parameters"),
10651097
};
1066-
match param.source {
1067-
hir::GenericParamSource::Generics => {
1068-
let parent_def_id = tcx.local_parent(param_def_id);
1069-
let generics = tcx.hir_get_generics(parent_def_id).unwrap();
1070-
1071-
// Scan the bounds and where-clauses on parameters to extract bounds
1072-
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
1073-
// for each type parameter.
1074-
match param.kind {
1075-
GenericParamKind::Type { .. } => {
1076-
let mut set = Set1::Empty;
1077-
1078-
// Look for `type: ...` where clauses.
1079-
for bound in generics.bounds_for_param(param_def_id) {
1080-
// Ignore `for<'a> type: ...` as they can change what
1081-
// lifetimes mean (although we could "just" handle it).
1082-
if !bound.bound_generic_params.is_empty() {
1083-
continue;
1084-
}
10851098

1086-
for bound in bound.bounds {
1087-
if let hir::GenericBound::Outlives(lifetime) = bound {
1088-
set.insert(lifetime.kind);
1089-
}
1090-
}
1091-
}
1099+
let mut set = Set1::Empty;
10921100

1093-
match set {
1094-
Set1::Empty => ObjectLifetimeDefault::Empty,
1095-
Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
1096-
Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
1097-
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
1098-
}
1099-
_ => ObjectLifetimeDefault::Ambiguous,
1100-
}
1101-
}
1102-
_ => {
1103-
bug!("object_lifetime_default must only be called on a type parameter")
1104-
}
1101+
let mut add_outlives_bounds = |bounds: &[hir::GenericBound<'_>]| {
1102+
for bound in bounds {
1103+
if let hir::GenericBound::Outlives(lifetime) = bound {
1104+
set.insert(lifetime.kind);
11051105
}
11061106
}
1107-
hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty,
1107+
};
1108+
1109+
add_outlives_bounds(bounds);
1110+
1111+
// Look for `Type: ...` where clauses.
1112+
for bound in generics.bounds_for_param(param_def_id) {
1113+
// Ignore `for<'a> Type: ...` as they can change what
1114+
// lifetimes mean (although we could "just" handle it).
1115+
if bound.bound_generic_params.is_empty() {
1116+
add_outlives_bounds(&bound.bounds);
1117+
}
1118+
}
1119+
1120+
match set {
1121+
Set1::Empty => ObjectLifetimeDefault::Empty,
1122+
Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
1123+
Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
1124+
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
1125+
}
1126+
_ => ObjectLifetimeDefault::Ambiguous,
11081127
}
11091128
}
11101129

@@ -1684,106 +1703,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16841703

16851704
debug!(?container);
16861705

1687-
// Compute a vector of ambient object lifetime defaults, one for each type parameter,
1688-
// per the rules initially given in RFCs 599 and 1156. Example:
1689-
//
1690-
// ```rust
1691-
// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U);
1692-
// ```
1693-
//
1694-
// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
1695-
// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
1696-
// and `dyn Baz` to `dyn Baz + 'static` (because there is no
1697-
// such bound).
1698-
//
1699-
// Therefore, we would compute a vector like `['x, 'static]`.
1700-
// Note that the vector only includes type parameters.
1701-
let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segments)| {
1702-
let in_body = {
1703-
let mut scope = self.scope;
1704-
loop {
1705-
match *scope {
1706-
Scope::Root { .. } => break false,
1707-
1708-
Scope::Body { .. } => break true,
1709-
1710-
Scope::Binder { s, .. }
1711-
| Scope::ObjectLifetimeDefault { s, .. }
1712-
| Scope::Opaque { s, .. }
1713-
| Scope::Supertrait { s, .. }
1714-
| Scope::TraitRefBoundary { s, .. }
1715-
| Scope::LateBoundary { s, .. } => {
1716-
scope = s;
1717-
}
1718-
}
1719-
}
1720-
};
1721-
1722-
let rbv = &self.rbv;
1723-
let generics = self.tcx.generics_of(def_id);
1724-
1725-
let set_to_region = |set: ObjectLifetimeDefault| match set {
1726-
ObjectLifetimeDefault::Empty => {
1727-
if in_body {
1728-
None
1729-
} else {
1730-
Some(ResolvedArg::StaticLifetime)
1731-
}
1732-
}
1733-
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
1734-
ObjectLifetimeDefault::Param(param_def_id) => {
1735-
fn param_to_depth_and_index(
1736-
generics: &ty::Generics,
1737-
tcx: TyCtxt<'_>,
1738-
def_id: DefId,
1739-
) -> (usize, usize) {
1740-
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1741-
let has_self = generics.parent.is_none() && generics.has_self;
1742-
(0, index as usize - generics.parent_count - has_self as usize)
1743-
} else if let Some(parent) = generics.parent {
1744-
let parent = tcx.generics_of(parent);
1745-
let (depth, index) = param_to_depth_and_index(parent, tcx, def_id);
1746-
(depth + 1, index)
1747-
} else {
1748-
unreachable!()
1749-
}
1750-
}
1751-
1752-
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1753-
segments[segments.len() - depth - 1]
1754-
.args
1755-
.and_then(|args| args.args.get(index))
1756-
.and_then(|arg| match arg {
1757-
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1758-
_ => None,
1759-
})
1760-
}
1761-
ObjectLifetimeDefault::Ambiguous => None,
1762-
};
1763-
generics
1764-
.own_params
1765-
.iter()
1766-
.filter_map(|param| {
1767-
match self.tcx.def_kind(param.def_id) {
1768-
// Generic consts don't impose any constraints.
1769-
//
1770-
// We still store a dummy value here to allow generic parameters
1771-
// in an arbitrary order.
1772-
DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
1773-
DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)),
1774-
// We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter
1775-
// works. Ignore it because it can't have a meaningful lifetime default.
1776-
DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None,
1777-
dk => bug!("unexpected def_kind {:?}", dk),
1778-
}
1779-
})
1780-
.map(set_to_region)
1781-
.collect()
1706+
let object_lifetime_defaults = container.map_or_else(Vec::new, |(def_id, segs)| {
1707+
self.compute_ambient_object_lifetime_defaults(def_id, segs)
17821708
});
17831709

17841710
debug!(?object_lifetime_defaults);
17851711

1786-
let mut i = 0;
1712+
let has_self = container
1713+
.map(|(def_id, _)| self.tcx.generics_of(def_id))
1714+
.is_some_and(|generics| generics.parent.is_none() && generics.has_self);
1715+
let mut i = has_self as usize;
17871716
for arg in generic_args.args {
17881717
match arg {
17891718
// We've already visited all lifetime arguments at the start.
@@ -1915,6 +1844,110 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19151844
}
19161845
}
19171846

1847+
/// Compute a vector of ambient object lifetime defaults, one for each type parameter,
1848+
/// per the rules initially given in RFCs 599 and 1156.
1849+
///
1850+
/// # Example
1851+
///
1852+
/// ```ignore (illustrative)
1853+
/// struct Foo<'a, T: 'a + ?Sized, U: ?Sized>(&'a T, &'a U);
1854+
/// ```
1855+
///
1856+
/// If you have `Foo<'x, dyn Bar, dyn Baz>`, we want to default
1857+
/// `dyn Bar` to `dyn Bar + 'x` (because of the `T: 'a` bound)
1858+
/// and `dyn Baz` to `dyn Baz + 'static` (because there is no
1859+
/// such bound).
1860+
///
1861+
/// Therefore, we would compute a vector like `['x, 'static]`.
1862+
/// Note that the vector only includes type parameters.
1863+
fn compute_ambient_object_lifetime_defaults(
1864+
&self,
1865+
def_id: DefId,
1866+
segments: &[hir::PathSegment<'_>],
1867+
) -> Vec<Option<ResolvedArg>> {
1868+
let in_body = {
1869+
let mut scope = self.scope;
1870+
loop {
1871+
match *scope {
1872+
Scope::Root { .. } => break false,
1873+
1874+
Scope::Body { .. } => break true,
1875+
1876+
Scope::Binder { s, .. }
1877+
| Scope::ObjectLifetimeDefault { s, .. }
1878+
| Scope::Opaque { s, .. }
1879+
| Scope::Supertrait { s, .. }
1880+
| Scope::TraitRefBoundary { s, .. }
1881+
| Scope::LateBoundary { s, .. } => {
1882+
scope = s;
1883+
}
1884+
}
1885+
}
1886+
};
1887+
1888+
let generics = self.tcx.generics_of(def_id);
1889+
1890+
let set_to_region = |set: ObjectLifetimeDefault| match set {
1891+
ObjectLifetimeDefault::Empty => {
1892+
if in_body {
1893+
None
1894+
} else {
1895+
Some(ResolvedArg::StaticLifetime)
1896+
}
1897+
}
1898+
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
1899+
ObjectLifetimeDefault::Param(param_def_id) => {
1900+
fn param_to_depth_and_index(
1901+
generics: &ty::Generics,
1902+
tcx: TyCtxt<'_>,
1903+
def_id: DefId,
1904+
) -> (usize, usize) {
1905+
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1906+
let has_self = generics.parent.is_none() && generics.has_self;
1907+
(0, index as usize - generics.parent_count - has_self as usize)
1908+
} else if let Some(parent) = generics.parent {
1909+
let parent = tcx.generics_of(parent);
1910+
let (depth, index) = param_to_depth_and_index(parent, tcx, def_id);
1911+
(depth + 1, index)
1912+
} else {
1913+
unreachable!()
1914+
}
1915+
}
1916+
1917+
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1918+
segments[segments.len() - depth - 1]
1919+
.args
1920+
.and_then(|args| args.args.get(index))
1921+
.and_then(|arg| match arg {
1922+
GenericArg::Lifetime(lt) => self.rbv.defs.get(&lt.hir_id.local_id).copied(),
1923+
_ => None,
1924+
})
1925+
}
1926+
ObjectLifetimeDefault::Ambiguous => None,
1927+
};
1928+
generics
1929+
.own_params
1930+
.iter()
1931+
.filter_map(|param| {
1932+
match self.tcx.def_kind(param.def_id) {
1933+
// Generic consts don't impose any constraints.
1934+
//
1935+
// We still store a dummy value here to allow generic parameters
1936+
// in an arbitrary order.
1937+
DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
1938+
// `Self` type params share the `DefId` of the corresp. trait.
1939+
DefKind::TyParam | DefKind::Trait => {
1940+
Some(self.tcx.object_lifetime_default(param.def_id))
1941+
}
1942+
// `Self` type params of trait aliases may show up here, ignore them.
1943+
DefKind::LifetimeParam | DefKind::TraitAlias => None,
1944+
dk => bug!("unexpected def_kind {:?}", dk),
1945+
}
1946+
})
1947+
.map(set_to_region)
1948+
.collect()
1949+
}
1950+
19181951
/// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the
19191952
/// associated type name and starting trait.
19201953
/// For example, imagine we have

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14761476
if let Some(name) = tcx.intrinsic(def_id) {
14771477
record!(self.tables.intrinsic[def_id] <- name);
14781478
}
1479-
if let DefKind::TyParam = def_kind {
1479+
if let DefKind::TyParam | DefKind::Trait = def_kind {
14801480
let default = self.tcx.object_lifetime_default(def_id);
14811481
record!(self.tables.object_lifetime_default[def_id] <- default);
14821482
}

tests/ui/object-lifetime/object-lifetime-default-assoc-ty-self-ty-static.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// FIXME: Explainer.
2-
//@ known-bug: unknown
1+
// Check that we correctly deduce object lifetime defaults inside self types of qualified paths.
2+
//@ check-pass
33

44
trait Outer { type Ty; }
55
trait Inner {}
66

77
impl<'a> Outer for dyn Inner + 'a { type Ty = &'a (); }
88

9-
// FIXME: Deduce `dyn Inner + 'static` from absence of any bounds on self ty param of trait `Outer`.
9+
// We deduce `dyn Inner + 'static` from absence of any bounds on self ty param of trait `Outer`.
1010
fn f<'r>(x: &'r <dyn Inner as Outer>::Ty) { g(x) }
1111
fn g<'r>(x: &'r <dyn Inner + 'static as Outer>::Ty) {}
1212

tests/ui/object-lifetime/object-lifetime-default-assoc-ty-self-ty-static.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)