Skip to content

Commit 102434c

Browse files
committed
Introduce fn eligible_container & rename depth to rev seg index
1 parent a137dac commit 102434c

2 files changed

Lines changed: 142 additions & 54 deletions

File tree

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 137 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -909,20 +909,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
909909
// already resolved.
910910
self.visit_path(path, id);
911911
if let Some(qself) = maybe_qself {
912-
// Read more about containers in fn `visit_path_segment_args`.
913-
let container = match path.res {
914-
Res::Def(DefKind::AssocTy, def_id) => Some((
915-
self.tcx.parent(def_id),
916-
&path.segments[..path.segments.len() - 1],
917-
)),
918-
_ => None,
919-
};
912+
let container =
913+
self.eligible_container(path, RevSegIdx(1).reverse(path.segments));
914+
920915
let object_lifetime_defaults =
921916
container.map_or(Vec::new(), |(def_id, segs)| {
922917
let generics = self.tcx.generics_of(def_id);
923918
self.compute_object_lifetime_defaults(generics, segs)
924919
});
925-
if let Some(&lt) = object_lifetime_defaults.get(0) {
920+
921+
if let Some(&lt) = object_lifetime_defaults.first() {
926922
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
927923
self.with(scope, |this| this.visit_ty_unambig(qself));
928924
} else {
@@ -952,7 +948,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
952948
fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) {
953949
for (index, segment) in path.segments.iter().enumerate() {
954950
if let Some(args) = segment.args {
955-
self.visit_path_segment_args(args, index, path);
951+
self.visit_path_segment_args(args, SegIdx(index), path);
956952
}
957953
}
958954
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
@@ -1723,7 +1719,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17231719
fn visit_path_segment_args(
17241720
&mut self,
17251721
generic_args: &'tcx hir::GenericArgs<'tcx>,
1726-
index: usize,
1722+
seg_idx: SegIdx,
17271723
path: &hir::Path<'tcx>,
17281724
) {
17291725
if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() {
@@ -1739,35 +1735,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17391735
}
17401736
}
17411737

1742-
// Figure out if this is an eligible container that induces lifetime defaults for
1743-
// trait object types contained in any of the type arguments passed to it
1744-
// (any inner containers will of course end up shadowing that default).
1745-
//
1746-
// FIXME(mgca, #151649): Assoc (and free?) consts should also qualify.
1747-
// FIXME(return_type_notation, #151662): Assoc fns should also qualify.
1748-
let depth = path.segments.len() - index - 1;
1749-
let container = match path.res {
1750-
Res::Def(DefKind::AssocTy | DefKind::Variant, def_id) if depth == 1 => {
1751-
Some((self.tcx.parent(def_id), &path.segments[..=index]))
1752-
}
1753-
Res::Def(DefKind::Variant, def_id) if depth == 0 => {
1754-
Some((self.tcx.parent(def_id), path.segments))
1755-
}
1756-
Res::Def(
1757-
DefKind::Struct
1758-
| DefKind::Union
1759-
| DefKind::Enum
1760-
| DefKind::TyAlias
1761-
| DefKind::Trait
1762-
| DefKind::TraitAlias
1763-
| DefKind::AssocTy,
1764-
def_id,
1765-
) if depth == 0 => Some((def_id, path.segments)),
1766-
// Note: We don't need to care about definition kinds that may have generics if they
1767-
// can only ever appear in positions where we can perform type inference (i.e., bodies).
1768-
_ => None,
1769-
};
1770-
1738+
let container = self.eligible_container(path, seg_idx);
17711739
debug!(?container);
17721740

17731741
let (has_self, object_lifetime_defaults) = container
@@ -1922,6 +1890,90 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19221890
}
19231891
}
19241892

1893+
/// Return the eligible container for the path segment given by the index if applicable.
1894+
///
1895+
/// Such a container induces lifetime defaults for trait object types contained
1896+
/// in any of the type arguments passed to it (any inner containers will of course
1897+
/// end up shadowing that default).
1898+
fn eligible_container<'b>(
1899+
&self,
1900+
path: &'b hir::Path<'tcx>,
1901+
seg_idx: SegIdx,
1902+
) -> Option<(DefId, &'b [hir::PathSegment<'tcx>])> {
1903+
let RevSegIdx(rev_seg_idx) = seg_idx.reverse(path.segments);
1904+
let SegIdx(seg_idx) = seg_idx;
1905+
1906+
// NOTE: We don't need to care about definition kinds that may have generics if they
1907+
// can only ever appear in positions where we can perform type inference (i.e., bodies).
1908+
1909+
// FIXME(mgca, #151649): Type-level free/assoc consts, const&fn ctors should also qualify.
1910+
// FIXME(return_type_notation, #151662): Assoc fns should also qualify.
1911+
1912+
let (kind, def_id) = match path.res {
1913+
Res::Def(kind, def_id) => (kind, def_id),
1914+
Res::PrimTy(..)
1915+
| Res::SelfTyParam { .. }
1916+
| Res::SelfTyAlias { .. }
1917+
| Res::SelfCtor(_)
1918+
| Res::Local(_)
1919+
| Res::ToolMod
1920+
| Res::OpenMod(_)
1921+
| Res::NonMacroAttr(_)
1922+
| Res::Err => return None, // see NOTE above!
1923+
};
1924+
1925+
match kind {
1926+
DefKind::AssocTy => match rev_seg_idx {
1927+
0 => Some((def_id, path.segments)),
1928+
// We're looking at the trait ref of an assoc type projection.
1929+
// E.g., the `TraitRef<…>` in `<… as path::to::TraitRef<…>>::AssocTy<…>`.
1930+
1 => Some((self.tcx.parent(def_id), &path.segments[..=seg_idx])),
1931+
_ => None,
1932+
},
1933+
DefKind::Variant => match rev_seg_idx {
1934+
// We're looking at the `Variant::<…>` in `path::to::Variant::<…> { … }`.
1935+
// Even if it's the variant segment that has the generic args and not the
1936+
// enum segment, it's the enum that has the corresponding generic params.
1937+
0 => Some((self.tcx.parent(def_id), path.segments)),
1938+
// We're looking at the `Enum::<…>` in `path::to::Enum::<…>::Variant { … }`.
1939+
1 => Some((self.tcx.parent(def_id), &path.segments[..=seg_idx])),
1940+
_ => None,
1941+
},
1942+
DefKind::Enum
1943+
| DefKind::Struct
1944+
| DefKind::Trait
1945+
| DefKind::TraitAlias
1946+
| DefKind::TyAlias
1947+
| DefKind::Union => match rev_seg_idx {
1948+
0 => Some((def_id, path.segments)),
1949+
_ => None,
1950+
},
1951+
DefKind::AnonConst
1952+
| DefKind::AssocConst { .. }
1953+
| DefKind::AssocFn
1954+
| DefKind::Closure
1955+
| DefKind::Const { .. }
1956+
| DefKind::ConstParam
1957+
| DefKind::Ctor(..)
1958+
| DefKind::ExternCrate
1959+
| DefKind::Field
1960+
| DefKind::Fn
1961+
| DefKind::ForeignMod
1962+
| DefKind::ForeignTy
1963+
| DefKind::GlobalAsm
1964+
| DefKind::Impl { .. }
1965+
| DefKind::InlineConst
1966+
| DefKind::LifetimeParam
1967+
| DefKind::Macro(_)
1968+
| DefKind::Mod
1969+
| DefKind::OpaqueTy
1970+
| DefKind::Static { .. }
1971+
| DefKind::SyntheticCoroutineBody
1972+
| DefKind::TyParam
1973+
| DefKind::Use => None, // see NOTE above!
1974+
}
1975+
}
1976+
19251977
/// Compute a list of trait object lifetime defaults, one for each type parameter,
19261978
/// per the rules initially given in RFCs [599] and [1156]. Example:
19271979
///
@@ -1973,31 +2025,38 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19732025
}
19742026
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
19752027
ObjectLifetimeDefault::Param(param_def_id) => {
1976-
fn param_to_depth_and_index(
2028+
struct ArgIdx(usize);
2029+
2030+
fn resolve_param(
2031+
param_def_id: DefId,
19772032
generics: &ty::Generics,
19782033
tcx: TyCtxt<'_>,
1979-
def_id: DefId,
1980-
) -> (usize, usize) {
1981-
if let Some(&index) = generics.param_def_id_to_index.get(&def_id) {
2034+
) -> (RevSegIdx, ArgIdx) {
2035+
if let Some(&index) = generics.param_def_id_to_index.get(&param_def_id) {
19822036
let has_self = generics.has_own_self();
1983-
(0, index as usize - generics.parent_count - has_self as usize)
2037+
let index = index as usize - generics.parent_count - has_self as usize;
2038+
(RevSegIdx(0), ArgIdx(index))
19842039
} else if let Some(parent) = generics.parent {
1985-
let parent = tcx.generics_of(parent);
1986-
let (depth, index) = param_to_depth_and_index(parent, tcx, def_id);
1987-
(depth + 1, index)
2040+
let parent_generics = tcx.generics_of(parent);
2041+
let (RevSegIdx(rev_seg_idx), arg_idx) =
2042+
resolve_param(param_def_id, parent_generics, tcx);
2043+
(RevSegIdx(rev_seg_idx + 1), arg_idx)
19882044
} else {
19892045
unreachable!()
19902046
}
19912047
}
19922048

1993-
let (depth, index) = param_to_depth_and_index(generics, self.tcx, param_def_id);
1994-
segments[segments.len() - depth - 1]
1995-
.args
1996-
.and_then(|args| args.args.get(index))
1997-
.and_then(|arg| match arg {
2049+
let (rev_seg_idx, ArgIdx(arg_idx)) =
2050+
resolve_param(param_def_id, generics, self.tcx);
2051+
2052+
let SegIdx(seg_idx) = rev_seg_idx.reverse(segments);
2053+
2054+
segments[seg_idx].args.and_then(|args| args.args.get(arg_idx)).and_then(|arg| {
2055+
match arg {
19982056
GenericArg::Lifetime(lt) => self.rbv.defs.get(&lt.hir_id.local_id).copied(),
19992057
_ => None,
2000-
})
2058+
}
2059+
})
20012060
}
20022061
ObjectLifetimeDefault::Ambiguous => None,
20032062
};
@@ -2673,3 +2732,27 @@ fn deny_non_region_late_bound(
26732732
*arg = ResolvedArg::Error(guar);
26742733
}
26752734
}
2735+
2736+
/// A path segment index.
2737+
#[derive(Clone, Copy, Debug)]
2738+
struct SegIdx(usize);
2739+
2740+
impl SegIdx {
2741+
fn reverse(self, segments: &[hir::PathSegment<'_>]) -> RevSegIdx {
2742+
let SegIdx(seg_idx) = self;
2743+
RevSegIdx(segments.len() - seg_idx - 1)
2744+
}
2745+
}
2746+
2747+
/// A reversed path segment index.
2748+
///
2749+
/// E.g., for qualified path `<() as path::to::TraitRef<…>>::AssocTy<…>` the mapping from reversed
2750+
/// index to path segment would look like 3 ↦ `path`, 2 ↦ `to`, 1 ↦ `TraitRef<…>`, 0 ↦ `AssocTy<…>`.
2751+
struct RevSegIdx(usize);
2752+
2753+
impl RevSegIdx {
2754+
fn reverse(self, segments: &[hir::PathSegment<'_>]) -> SegIdx {
2755+
let RevSegIdx(rev_seg_idx) = self;
2756+
SegIdx(segments.len() - rev_seg_idx - 1)
2757+
}
2758+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ fn f<'r>(x: <dyn Inner + 'r as Outer<'r>>::Ty) { /*check*/ g(x) }
1616
// We deduce `dyn Inner + 'r` from bound `'a` on self ty param of trait `Outer`.
1717
fn g<'r>(x: <dyn Inner as Outer<'r>>::Ty) {}
1818

19+
fn h<'r>(x: <dyn Inner + 'r as Outer<'r>>::Ty) { /*check*/ i(x) }
20+
// Just like the case directly above, we elaborate `dyn Inner` to `dyn Inner + 'r`.
21+
// What's different is the extra segment (`self`) that once threw off RBV in a dev version.
22+
fn i<'r>(x: <dyn Inner as self::Outer<'r>>::Ty) {}
23+
1924
fn main() {}

0 commit comments

Comments
 (0)