Skip to content

Commit d2dd153

Browse files
authored
Unrolled build for rust-lang#132047
Rollup merge of rust-lang#132047 - compiler-errors:rbv-rtn-cleanup, r=cjgillot Robustify and genericize return-type-notation resolution in `resolve_bound_vars` rust-lang#129629 implemented return-type-notation (RTN) in its path form, like `where T::method(..): Bound`. As part of lowering, we must record the late-bound vars for the where clause introduced by the method (namely, its early- and late-bound lifetime arguments, since `where T::method(..)` turns into a higher-ranked where clause over all of the lifetimes according to [RFC 3654](https://rust-lang.github.io/rfcs/3654-return-type-notation.html#converting-to-higher-ranked-trait-bounds)). However, this logic was only looking at the where clauses of the parent item that the `T::method(..)` bound was written on, and not any parent items. This PR generalizes that logic to look at the parent item (i.e. the outer impl or trait) instead and fixes a (debug only) assertion as an effect. This logic is also more general and likely easier to adapt to more interesting (though likely very far off) cases like non-lifetime binder `for<T: Trait> T::method(..): Send` bounds. Tracking: - rust-lang#109417
2 parents 8ac313b + 0f5759a commit d2dd153

File tree

3 files changed

+143
-35
lines changed

3 files changed

+143
-35
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+110-35
Original file line numberDiff line numberDiff line change
@@ -2060,48 +2060,37 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
20602060
};
20612061
match path.res {
20622062
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => {
2063-
// Get the generics of this type's hir owner. This is *different*
2064-
// from the generics of the parameter's definition, since we want
2065-
// to be able to resolve an RTN path on a nested body (e.g. method
2066-
// inside an impl) using the where clauses on the method.
2067-
// FIXME(return_type_notation): Think of some better way of doing this.
2068-
let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics()
2069-
else {
2070-
return;
2071-
};
2072-
2073-
// Look for the first bound that contains an associated type that
2074-
// matches the segment that we're looking for. We ignore any subsequent
2075-
// bounds since we'll be emitting a hard error in HIR lowering, so this
2076-
// is purely speculative.
2077-
let one_bound = generics.predicates.iter().find_map(|predicate| {
2078-
let hir::WherePredicateKind::BoundPredicate(predicate) = predicate.kind
2079-
else {
2080-
return None;
2081-
};
2082-
let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
2083-
predicate.bounded_ty.kind
2084-
else {
2085-
return None;
2086-
};
2087-
if bounded_path.res != path.res {
2088-
return None;
2089-
}
2090-
predicate.bounds.iter().find_map(|bound| {
2091-
let hir::GenericBound::Trait(trait_) = bound else {
2092-
return None;
2093-
};
2063+
let mut bounds =
2064+
self.for_each_trait_bound_on_res(path.res).filter_map(|trait_def_id| {
20942065
BoundVarContext::supertrait_hrtb_vars(
20952066
self.tcx,
2096-
trait_.trait_ref.trait_def_id()?,
2067+
trait_def_id,
20972068
item_segment.ident,
20982069
ty::AssocKind::Fn,
20992070
)
2100-
})
2101-
});
2102-
let Some((bound_vars, assoc_item)) = one_bound else {
2071+
});
2072+
2073+
let Some((bound_vars, assoc_item)) = bounds.next() else {
2074+
// This will error in HIR lowering.
2075+
self.tcx
2076+
.dcx()
2077+
.span_delayed_bug(path.span, "no resolution for RTN path");
21032078
return;
21042079
};
2080+
2081+
// Don't bail if we have identical bounds, which may be collected from
2082+
// something like `T: Bound + Bound`, or via elaborating supertraits.
2083+
for (second_vars, second_assoc_item) in bounds {
2084+
if second_vars != bound_vars || second_assoc_item != assoc_item {
2085+
// This will error in HIR lowering.
2086+
self.tcx.dcx().span_delayed_bug(
2087+
path.span,
2088+
"ambiguous resolution for RTN path",
2089+
);
2090+
return;
2091+
}
2092+
}
2093+
21052094
(bound_vars, assoc_item.def_id, item_segment)
21062095
}
21072096
// If we have a self type alias (in an impl), try to resolve an
@@ -2167,6 +2156,92 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
21672156
existing_bound_vars.extend(bound_vars);
21682157
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
21692158
}
2159+
2160+
/// Walk the generics of the item for a trait bound whose self type
2161+
/// corresponds to the expected res, and return the trait def id.
2162+
fn for_each_trait_bound_on_res(
2163+
&self,
2164+
expected_res: Res,
2165+
) -> impl Iterator<Item = DefId> + use<'tcx, '_> {
2166+
std::iter::from_coroutine(
2167+
#[coroutine]
2168+
move || {
2169+
let mut scope = self.scope;
2170+
loop {
2171+
let hir_id = match *scope {
2172+
Scope::Binder { hir_id, .. } => Some(hir_id),
2173+
Scope::Root { opt_parent_item: Some(parent_def_id) } => {
2174+
Some(self.tcx.local_def_id_to_hir_id(parent_def_id))
2175+
}
2176+
Scope::Body { .. }
2177+
| Scope::ObjectLifetimeDefault { .. }
2178+
| Scope::Supertrait { .. }
2179+
| Scope::TraitRefBoundary { .. }
2180+
| Scope::LateBoundary { .. }
2181+
| Scope::Opaque { .. }
2182+
| Scope::Root { opt_parent_item: None } => None,
2183+
};
2184+
2185+
if let Some(hir_id) = hir_id {
2186+
let node = self.tcx.hir_node(hir_id);
2187+
// If this is a `Self` bound in a trait, yield the trait itself.
2188+
// Specifically, we don't need to look at any supertraits since
2189+
// we already do that in `BoundVarContext::supertrait_hrtb_vars`.
2190+
if let Res::SelfTyParam { trait_: _ } = expected_res
2191+
&& let hir::Node::Item(item) = node
2192+
&& let hir::ItemKind::Trait(..) = item.kind
2193+
{
2194+
// Yield the trait's def id. Supertraits will be
2195+
// elaborated from that.
2196+
yield item.owner_id.def_id.to_def_id();
2197+
} else if let Some(generics) = node.generics() {
2198+
for pred in generics.predicates {
2199+
let hir::WherePredicateKind::BoundPredicate(pred) = pred.kind
2200+
else {
2201+
continue;
2202+
};
2203+
let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
2204+
pred.bounded_ty.kind
2205+
else {
2206+
continue;
2207+
};
2208+
// Match the expected res.
2209+
if bounded_path.res != expected_res {
2210+
continue;
2211+
}
2212+
for pred in pred.bounds {
2213+
match pred {
2214+
hir::GenericBound::Trait(poly_trait_ref) => {
2215+
if let Some(def_id) =
2216+
poly_trait_ref.trait_ref.trait_def_id()
2217+
{
2218+
yield def_id;
2219+
}
2220+
}
2221+
hir::GenericBound::Outlives(_)
2222+
| hir::GenericBound::Use(_, _) => {}
2223+
}
2224+
}
2225+
}
2226+
}
2227+
}
2228+
2229+
match *scope {
2230+
Scope::Binder { s, .. }
2231+
| Scope::Body { s, .. }
2232+
| Scope::ObjectLifetimeDefault { s, .. }
2233+
| Scope::Supertrait { s, .. }
2234+
| Scope::TraitRefBoundary { s }
2235+
| Scope::LateBoundary { s, .. }
2236+
| Scope::Opaque { s, .. } => {
2237+
scope = s;
2238+
}
2239+
Scope::Root { .. } => break,
2240+
}
2241+
}
2242+
},
2243+
)
2244+
}
21702245
}
21712246

21722247
/// Detects late-bound lifetimes and inserts them into

compiler/rustc_hir_analysis/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ This API is completely unstable and subject to change.
6262
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
6363
#![doc(rust_logo)]
6464
#![feature(assert_matches)]
65+
#![feature(coroutines)]
6566
#![feature(if_let_guard)]
67+
#![feature(iter_from_coroutine)]
6668
#![feature(iter_intersperse)]
6769
#![feature(let_chains)]
6870
#![feature(never_type)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//@ check-pass
2+
3+
#![feature(return_type_notation)]
4+
5+
trait Trait {
6+
fn method(&self) -> impl Sized;
7+
}
8+
9+
impl Trait for () {
10+
fn method(&self) -> impl Sized {}
11+
}
12+
13+
struct Struct<T>(T);
14+
15+
// This test used to fail a debug assertion since we weren't resolving the item
16+
// for `T::method(..)` correctly, leading to two bound vars being given the
17+
// index 0. The solution is to look at both generics of `test` and its parent impl.
18+
19+
impl<T> Struct<T>
20+
where
21+
T: Trait,
22+
{
23+
fn test()
24+
where
25+
T::method(..): Send
26+
{}
27+
}
28+
29+
fn main() {
30+
Struct::<()>::test();
31+
}

0 commit comments

Comments
 (0)