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

Commit 82134af

Browse files
committed
Propagate the object lifetime default to the self ty of resolved projections
1 parent b9ea182 commit 82134af

File tree

6 files changed

+156
-151
lines changed

6 files changed

+156
-151
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 149 additions & 126 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,26 @@ 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 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));
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)| self.xyzxx(def_id, segs));
907+
if let Some(&lt) = object_lifetime_defaults.get(0) {
908+
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
909+
self.with(scope, |this| this.visit_ty_unambig(qself));
910+
} else {
911+
self.visit_ty_unambig(qself);
912+
}
897913
}
898-
self.visit_path(path, id);
899914
}
900915
hir::QPath::TypeRelative(qself, segment) => {
901916
// Resolving object lifetime defaults for type-relative paths requires type-dependent
@@ -1058,51 +1073,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
10581073
}
10591074

10601075
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
1061-
let hir::Node::GenericParam(param) = tcx.hir_node_by_def_id(param_def_id) else {
1062-
bug!("expected GenericParam for object_lifetime_default");
1076+
// FIXME: Update comments etc.
1077+
1078+
// Scan the bounds and where-clauses on parameters to extract bounds
1079+
// of the form `T: 'a` so as to determine the `ObjectLifetimeDefault`
1080+
// for each type parameter.
1081+
1082+
let (generics, bounds) = match tcx.hir_node_by_def_id(param_def_id) {
1083+
hir::Node::GenericParam(param) => match param.source {
1084+
hir::GenericParamSource::Generics => {
1085+
// FIXME: message
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"),
10631097
};
1064-
match param.source {
1065-
hir::GenericParamSource::Generics => {
1066-
let parent_def_id = tcx.local_parent(param_def_id);
1067-
let generics = tcx.hir_get_generics(parent_def_id).unwrap();
1068-
1069-
// Scan the bounds and where-clauses on parameters to extract bounds
1070-
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
1071-
// for each type parameter.
1072-
match param.kind {
1073-
GenericParamKind::Type { .. } => {
1074-
let mut set = Set1::Empty;
1075-
1076-
// Look for `type: ...` where clauses.
1077-
for bound in generics.bounds_for_param(param_def_id) {
1078-
// Ignore `for<'a> type: ...` as they can change what
1079-
// lifetimes mean (although we could "just" handle it).
1080-
if !bound.bound_generic_params.is_empty() {
1081-
continue;
1082-
}
10831098

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

1091-
match set {
1092-
Set1::Empty => ObjectLifetimeDefault::Empty,
1093-
Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
1094-
Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
1095-
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
1096-
}
1097-
_ => ObjectLifetimeDefault::Ambiguous,
1098-
}
1099-
}
1100-
_ => {
1101-
bug!("object_lifetime_default must only be called on a type parameter")
1102-
}
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.res);
11031105
}
11041106
}
1105-
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,
11061127
}
11071128
}
11081129

@@ -1683,88 +1704,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16831704
// Therefore, we would compute `object_lifetime_defaults` to a
16841705
// vector like `['x, 'static]`. Note that the vector only
16851706
// includes type parameters.
1686-
let object_lifetime_defaults = type_def_id.map_or_else(Vec::new, |def_id| {
1687-
let in_body = {
1688-
let mut scope = self.scope;
1689-
loop {
1690-
match *scope {
1691-
Scope::Root { .. } => break false,
1692-
1693-
Scope::Body { .. } => break true,
1694-
1695-
Scope::Binder { s, .. }
1696-
| Scope::ObjectLifetimeDefault { s, .. }
1697-
| Scope::Opaque { s, .. }
1698-
| Scope::Supertrait { s, .. }
1699-
| Scope::TraitRefBoundary { s, .. }
1700-
| Scope::LateBoundary { s, .. } => {
1701-
scope = s;
1702-
}
1703-
}
1704-
}
1705-
};
1706-
1707-
let rbv = &self.rbv;
1708-
let generics = self.tcx.generics_of(def_id);
1709-
1710-
let set_to_region = |set: ObjectLifetimeDefault| match set {
1711-
ObjectLifetimeDefault::Empty => {
1712-
if in_body {
1713-
None
1714-
} else {
1715-
Some(ResolvedArg::StaticLifetime)
1716-
}
1717-
}
1718-
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
1719-
ObjectLifetimeDefault::Param(param_def_id) => {
1720-
fn param_to_depth_and_index(
1721-
generics: &ty::Generics,
1722-
tcx: TyCtxt<'_>,
1723-
def_id: DefId,
1724-
) -> (usize, usize) {
1725-
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1726-
let has_self = generics.parent.is_none() && generics.has_self;
1727-
(0, index as usize - generics.parent_count - has_self as usize)
1728-
} else if let Some(parent) = generics.parent {
1729-
let parent = tcx.generics_of(parent);
1730-
let (index, depth) = param_to_depth_and_index(parent, tcx, def_id);
1731-
(depth + 1, index)
1732-
} else {
1733-
unreachable!()
1734-
}
1735-
}
1736-
1737-
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1738-
path.segments[path.segments.len() - depth - 1]
1739-
.args
1740-
.and_then(|args| args.args.get(index))
1741-
.and_then(|arg| match arg {
1742-
GenericArg::Lifetime(lt) => rbv.defs.get(&lt.hir_id.local_id).copied(),
1743-
_ => None,
1744-
})
1745-
}
1746-
ObjectLifetimeDefault::Ambiguous => None,
1747-
};
1748-
generics
1749-
.own_params
1750-
.iter()
1751-
.filter_map(|param| {
1752-
match self.tcx.def_kind(param.def_id) {
1753-
// Generic consts don't impose any constraints.
1754-
//
1755-
// We still store a dummy value here to allow generic parameters
1756-
// in an arbitrary order.
1757-
DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
1758-
DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)),
1759-
// We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter
1760-
// works. Ignore it because it can't have a meaningful lifetime default.
1761-
DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None,
1762-
dk => bug!("unexpected def_kind {:?}", dk),
1763-
}
1764-
})
1765-
.map(set_to_region)
1766-
.collect()
1767-
});
1707+
let object_lifetime_defaults =
1708+
type_def_id.map_or_else(Vec::new, |def_id| self.xyzxx(def_id, &path.segments));
17681709

17691710
debug!(?object_lifetime_defaults);
17701711

@@ -1899,6 +1840,88 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18991840
}
19001841
}
19011842

1843+
fn xyzxx(&self, def_id: DefId, segments: &[hir::PathSegment<'_>]) -> Vec<Option<ResolvedArg>> {
1844+
let in_body = {
1845+
let mut scope = self.scope;
1846+
loop {
1847+
match *scope {
1848+
Scope::Root { .. } => break false,
1849+
1850+
Scope::Body { .. } => break true,
1851+
1852+
Scope::Binder { s, .. }
1853+
| Scope::ObjectLifetimeDefault { s, .. }
1854+
| Scope::Opaque { s, .. }
1855+
| Scope::Supertrait { s, .. }
1856+
| Scope::TraitRefBoundary { s, .. }
1857+
| Scope::LateBoundary { s, .. } => {
1858+
scope = s;
1859+
}
1860+
}
1861+
}
1862+
};
1863+
1864+
let generics = self.tcx.generics_of(def_id);
1865+
1866+
let set_to_region = |set: ObjectLifetimeDefault| match set {
1867+
ObjectLifetimeDefault::Empty => {
1868+
if in_body {
1869+
None
1870+
} else {
1871+
Some(ResolvedArg::StaticLifetime)
1872+
}
1873+
}
1874+
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
1875+
ObjectLifetimeDefault::Param(param_def_id) => {
1876+
fn param_to_depth_and_index(
1877+
generics: &ty::Generics,
1878+
tcx: TyCtxt<'_>,
1879+
def_id: DefId,
1880+
) -> (usize, usize) {
1881+
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
1882+
let has_self = generics.parent.is_none() && generics.has_self;
1883+
(0, index as usize - generics.parent_count - has_self as usize)
1884+
} else if let Some(parent) = generics.parent {
1885+
let parent = tcx.generics_of(parent);
1886+
let (index, depth) = param_to_depth_and_index(parent, tcx, def_id);
1887+
(depth + 1, index)
1888+
} else {
1889+
unreachable!()
1890+
}
1891+
}
1892+
1893+
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1894+
segments[segments.len() - depth - 1]
1895+
.args
1896+
.and_then(|args| args.args.get(index))
1897+
.and_then(|arg| match arg {
1898+
GenericArg::Lifetime(lt) => self.rbv.defs.get(&lt.hir_id.local_id).copied(),
1899+
_ => None,
1900+
})
1901+
}
1902+
ObjectLifetimeDefault::Ambiguous => None,
1903+
};
1904+
generics
1905+
.own_params
1906+
.iter()
1907+
.filter_map(|param| {
1908+
match self.tcx.def_kind(param.def_id) {
1909+
// Generic consts don't impose any constraints.
1910+
//
1911+
// We still store a dummy value here to allow generic parameters
1912+
// in an arbitrary order.
1913+
DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty),
1914+
DefKind::TyParam | DefKind::Trait => {
1915+
Some(self.tcx.object_lifetime_default(param.def_id))
1916+
}
1917+
DefKind::LifetimeParam | DefKind::TraitAlias => None,
1918+
dk => bug!("unexpected def_kind {:?}", dk),
1919+
}
1920+
})
1921+
.map(set_to_region)
1922+
.collect()
1923+
}
1924+
19021925
/// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the
19031926
/// associated type name and starting trait.
19041927
/// 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
}
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// FIXME: Explainer.
2-
//@ known-bug: unknown
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-
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) {}
9+
fn f<'r>(x: &'r <dyn Inner as Outer>::Ty) { g(x) }
10+
fn g<'r>(x: &'r <dyn Inner + 'static as Outer>::Ty) {}
1211

1312
fn main() {}

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

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// FIXME: Explainer
2-
//@ known-bug: unknown
2+
//@ check-pass
33

4+
// FIXME: Test both bound and where-clause form
5+
// trait Outer<'a> where Self: 'a { type Ty; }
46
trait Outer<'a>: 'a { type Ty; }
57
trait Inner {}
68

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

911
fn f<'r>(x: <dyn Inner + 'r as Outer<'r>>::Ty) { g(x) }
10-
// FIXME: Should infer `+ 'r`:
1112
fn g<'r>(x: <dyn Inner as Outer<'r>>::Ty) {}
1213

1314
fn main() {}

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

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

0 commit comments

Comments
 (0)