Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b969b83

Browse files
committed
Auto merge of #113704 - compiler-errors:rpitit-assumed-wf-inherit, r=spastorino
Make RPITITs inherit the `assumed_wf_types` of their parent method ... and then move the RPITIT well-formedness check to just use the regular logic of wfchecking an associated type. --- We need to inherit the `assumed_wf_types` of the RPITIT's parent function in order for the given code to be considered well-formed: ```rust trait Foo { fn bar<'a, T>(_: &'a T) -> impl Iterator<Output = &'a T>; } ``` Since for `&'a T` to be WF, we need `T: 'a`. In order for this to work for late-bound lifetimes, we need to do some additional mapping of any late-bound lifetimes captured by these assumed wf types. This is because within the body of the function (and thus in the `assumed_wf_types`), they're represented as `ReFree` variants of the original late-bound lifetimes declared in the function's generics, but in the RPITIT's GAT, they're represented as "reified" `ReEarlyBound` vars (duplicated during opaque type lowering). Luckily, the mapping between these two is already [stored in the opaque](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.OpaqueTy.html#structfield.lifetime_mapping). Fixes #113796
2 parents 32303b2 + 744e770 commit b969b83

File tree

13 files changed

+151
-117
lines changed

13 files changed

+151
-117
lines changed

‎compiler/rustc_hir_analysis/src/check/wfcheck.rs‎

Lines changed: 11 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,17 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
284284
};
285285
check_object_unsafe_self_trait_by_name(tcx, trait_item);
286286
check_associated_item(tcx, def_id, span, method_sig);
287+
288+
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
289+
for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) {
290+
check_associated_item(
291+
tcx,
292+
assoc_ty_def_id.expect_local(),
293+
tcx.def_span(assoc_ty_def_id),
294+
None,
295+
);
296+
}
297+
}
287298
}
288299

289300
/// Require that the user writes where clauses on GATs for the implicit
@@ -1466,13 +1477,6 @@ fn check_fn_or_method<'tcx>(
14661477

14671478
check_where_clauses(wfcx, span, def_id);
14681479

1469-
check_return_position_impl_trait_in_trait_bounds(
1470-
wfcx,
1471-
def_id,
1472-
sig.output(),
1473-
hir_decl.output.span(),
1474-
);
1475-
14761480
if sig.abi == Abi::RustCall {
14771481
let span = tcx.def_span(def_id);
14781482
let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
@@ -1507,87 +1511,6 @@ fn check_fn_or_method<'tcx>(
15071511
}
15081512
}
15091513

1510-
/// Basically `check_associated_type_bounds`, but separated for now and should be
1511-
/// deduplicated when RPITITs get lowered into real associated items.
1512-
#[tracing::instrument(level = "trace", skip(wfcx))]
1513-
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
1514-
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1515-
fn_def_id: LocalDefId,
1516-
fn_output: Ty<'tcx>,
1517-
span: Span,
1518-
) {
1519-
let tcx = wfcx.tcx();
1520-
let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else {
1521-
return;
1522-
};
1523-
if assoc_item.container != ty::AssocItemContainer::TraitContainer {
1524-
return;
1525-
}
1526-
fn_output.visit_with(&mut ImplTraitInTraitFinder {
1527-
wfcx,
1528-
fn_def_id,
1529-
depth: ty::INNERMOST,
1530-
seen: FxHashSet::default(),
1531-
});
1532-
}
1533-
1534-
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
1535-
// strategy, we can't just call `check_associated_item` on the new RPITITs,
1536-
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
1537-
// That's because we need to check that the bounds of the RPITIT hold using
1538-
// the special args that we create during opaque type lowering, otherwise we're
1539-
// getting a bunch of early bound and free regions mixed up... Haven't looked too
1540-
// deep into this, though.
1541-
struct ImplTraitInTraitFinder<'a, 'tcx> {
1542-
wfcx: &'a WfCheckingCtxt<'a, 'tcx>,
1543-
fn_def_id: LocalDefId,
1544-
depth: ty::DebruijnIndex,
1545-
seen: FxHashSet<DefId>,
1546-
}
1547-
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
1548-
type BreakTy = !;
1549-
1550-
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> {
1551-
let tcx = self.wfcx.tcx();
1552-
if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
1553-
&& self.seen.insert(unshifted_opaque_ty.def_id)
1554-
&& let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
1555-
&& let origin = tcx.opaque_type_origin(opaque_def_id)
1556-
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin
1557-
&& source == self.fn_def_id
1558-
{
1559-
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
1560-
match re.kind() {
1561-
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
1562-
r => bug!("unexpected region: {r:?}"),
1563-
}
1564-
});
1565-
for (bound, bound_span) in tcx
1566-
.explicit_item_bounds(opaque_ty.def_id)
1567-
.iter_instantiated_copied(tcx, opaque_ty.args)
1568-
{
1569-
let bound = self.wfcx.normalize(bound_span, None, bound);
1570-
self.wfcx.register_obligations(traits::wf::predicate_obligations(
1571-
self.wfcx.infcx,
1572-
self.wfcx.param_env,
1573-
self.wfcx.body_def_id,
1574-
bound.as_predicate(),
1575-
bound_span,
1576-
));
1577-
// Set the debruijn index back to innermost here, since we already eagerly
1578-
// shifted the args that we use to generate these bounds. This is unfortunately
1579-
// subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`,
1580-
// but that function doesn't actually need to normalize the bound it's visiting
1581-
// (whereas we have to do so here)...
1582-
let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST);
1583-
bound.visit_with(self);
1584-
self.depth = old_depth;
1585-
}
1586-
}
1587-
ty.super_visit_with(self)
1588-
}
1589-
}
1590-
15911514
const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
15921515
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
15931516
of the previous types except `Self`)";

‎compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ provide! { tcx, def_id, other, cdata,
246246
debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
247247
cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
248248
}
249+
assumed_wf_types_for_rpitit => { table }
249250
collect_return_position_impl_trait_in_trait_tys => {
250251
Ok(cdata
251252
.root

‎compiler/rustc_metadata/src/rmeta/encoder.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
15601560
}
15611561
if let Some(rpitit_info) = item.opt_rpitit_info {
15621562
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
1563+
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
1564+
record_array!(
1565+
self.tables.assumed_wf_types_for_rpitit[def_id]
1566+
<- self.tcx.assumed_wf_types_for_rpitit(def_id)
1567+
);
1568+
}
15631569
}
15641570
}
15651571

‎compiler/rustc_metadata/src/rmeta/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ define_tables! {
457457
trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
458458
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
459459
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
460+
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
460461
}
461462

462463
#[derive(TyEncodable, TyDecodable)]

‎compiler/rustc_middle/src/query/mod.rs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,13 @@ rustc_queries! {
885885
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
886886
}
887887

888+
/// We need to store the assumed_wf_types for an RPITIT so that impls of foreign
889+
/// traits with return-position impl trait in traits can inherit the right wf types.
890+
query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] {
891+
desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
892+
separate_provide_extern
893+
}
894+
888895
/// Computes the signature of the function.
889896
query fn_sig(key: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
890897
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }

‎compiler/rustc_ty_utils/src/implied_bounds.rs‎

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
use rustc_data_structures::fx::FxHashMap;
12
use rustc_hir as hir;
23
use rustc_hir::def::DefKind;
34
use rustc_hir::def_id::LocalDefId;
5+
use rustc_middle::middle::resolve_bound_vars as rbv;
46
use rustc_middle::query::Providers;
57
use rustc_middle::ty::{self, Ty, TyCtxt};
68
use rustc_span::Span;
79
use std::iter;
810

911
pub fn provide(providers: &mut Providers) {
10-
*providers = Providers { assumed_wf_types, ..*providers };
12+
*providers = Providers {
13+
assumed_wf_types,
14+
assumed_wf_types_for_rpitit: |tcx, def_id| {
15+
assert!(tcx.is_impl_trait_in_trait(def_id.to_def_id()));
16+
tcx.assumed_wf_types(def_id)
17+
},
18+
..*providers
19+
};
1120
}
1221

1322
fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
@@ -42,6 +51,81 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
4251
let mut impl_spans = impl_spans(tcx, def_id);
4352
tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
4453
}
54+
DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => match data {
55+
ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id } => {
56+
let hir::OpaqueTy { lifetime_mapping, .. } =
57+
*tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty();
58+
// We need to remap all of the late-bound lifetimes in theassumed wf types
59+
// of the fn (which are represented as ReFree) to the early-bound lifetimes
60+
// of the RPITIT (which are represented by ReEarlyBound owned by the opaque).
61+
// Luckily, this is very easy to do because we already have that mapping
62+
// stored in the HIR of this RPITIT.
63+
//
64+
// Side-note: We don't really need to do this remapping for early-bound
65+
// lifetimes because they're already "linked" by the bidirectional outlives
66+
// predicates we insert in the `explicit_predicates_of` query for RPITITs.
67+
let mut mapping = FxHashMap::default();
68+
let generics = tcx.generics_of(def_id);
69+
for &(lifetime, new_early_bound_def_id) in
70+
lifetime_mapping.expect("expected lifetime mapping for RPITIT")
71+
{
72+
if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) =
73+
tcx.named_bound_var(lifetime.hir_id)
74+
{
75+
let name = tcx.hir().name(lifetime.hir_id);
76+
let index = generics
77+
.param_def_id_to_index(tcx, new_early_bound_def_id.to_def_id())
78+
.unwrap();
79+
mapping.insert(
80+
ty::Region::new_free(
81+
tcx,
82+
fn_def_id,
83+
ty::BoundRegionKind::BrNamed(def_id, name),
84+
),
85+
ty::Region::new_early_bound(
86+
tcx,
87+
ty::EarlyBoundRegion {
88+
def_id: new_early_bound_def_id.to_def_id(),
89+
index,
90+
name,
91+
},
92+
),
93+
);
94+
}
95+
}
96+
// FIXME: This could use a real folder, I guess.
97+
let remapped_wf_tys = tcx.fold_regions(
98+
tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(),
99+
|region, _| {
100+
// If `region` is a `ReFree` that is captured by the
101+
// opaque, remap it to its corresponding the early-
102+
// bound region.
103+
if let Some(remapped_region) = mapping.get(&region) {
104+
*remapped_region
105+
} else {
106+
region
107+
}
108+
},
109+
);
110+
tcx.arena.alloc_from_iter(remapped_wf_tys)
111+
}
112+
// Assumed wf types for RPITITs in an impl just inherit (and instantiate)
113+
// the assumed wf types of the trait's RPITIT GAT.
114+
ty::ImplTraitInTraitData::Impl { .. } => {
115+
let impl_def_id = tcx.local_parent(def_id);
116+
let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap();
117+
let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
118+
tcx,
119+
impl_def_id.to_def_id(),
120+
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args,
121+
);
122+
tcx.arena.alloc_from_iter(
123+
ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id))
124+
.iter_instantiated_copied(tcx, args)
125+
.chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()),
126+
)
127+
}
128+
},
45129
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
46130
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
47131
DefKind::TyAlias => ty::List::empty(),

‎compiler/rustc_ty_utils/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#![feature(assert_matches)]
99
#![feature(iterator_try_collect)]
1010
#![feature(let_chains)]
11+
#![feature(if_let_guard)]
1112
#![feature(never_type)]
1213
#![feature(box_patterns)]
1314
#![recursion_limit = "256"]

‎tests/ui/async-await/in-trait/async-generics-and-bounds.stderr‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
44
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
55
| ^^^^^^^
66
|
7-
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
7+
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
88
--> $DIR/async-generics-and-bounds.rs:12:18
99
|
1010
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
11-
| ^^^^^
11+
| ^
1212
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
1313
--> $DIR/async-generics-and-bounds.rs:12:28
1414
|
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
2121
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
2222
| ^^^^^^^
2323
|
24-
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
24+
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
2525
--> $DIR/async-generics-and-bounds.rs:12:18
2626
|
2727
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
28-
| ^^^^^
28+
| ^
2929
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
3030
--> $DIR/async-generics-and-bounds.rs:12:28
3131
|

‎tests/ui/async-await/in-trait/async-generics.stderr‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
44
LL | async fn foo(&self) -> &(T, U);
55
| ^^^^^^^
66
|
7-
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
7+
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
88
--> $DIR/async-generics.rs:9:18
99
|
1010
LL | async fn foo(&self) -> &(T, U);
11-
| ^^^^^
11+
| ^
1212
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
1313
--> $DIR/async-generics.rs:9:28
1414
|
@@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
2121
LL | async fn foo(&self) -> &(T, U);
2222
| ^^^^^^^
2323
|
24-
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
24+
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
2525
--> $DIR/async-generics.rs:9:18
2626
|
2727
LL | async fn foo(&self) -> &(T, U);
28-
| ^^^^^
28+
| ^
2929
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
3030
--> $DIR/async-generics.rs:9:28
3131
|
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
// edition: 2021
3+
// issue: 113796
4+
5+
#![feature(async_fn_in_trait)]
6+
7+
trait AsyncLendingIterator {
8+
type Item<'a>
9+
where
10+
Self: 'a;
11+
12+
async fn next(&mut self) -> Option<Self::Item<'_>>;
13+
}
14+
15+
struct Lend<I>(I);
16+
impl<I> AsyncLendingIterator for Lend<I> {
17+
type Item<'a> = &'a I
18+
where
19+
Self: 'a;
20+
21+
// Checking that the synthetic `<Self as AsyncLendingIterator>::next()` GAT
22+
// is well-formed requires being able to assume the WF types of `next`.
23+
24+
async fn next(&mut self) -> Option<Self::Item<'_>> {
25+
todo!()
26+
}
27+
}
28+
29+
fn main() {}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /