Take RPITITs inherit the assumed_wf_types of their parent fn

This commit is contained in:
Michael Goulet 2023-07-14 18:37:12 +00:00
parent 03a57254b5
commit 349a2372ed
6 changed files with 57 additions and 100 deletions

View file

@ -284,6 +284,17 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
};
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, def_id, span, method_sig);
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) {
for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) {
check_associated_item(
tcx,
assoc_ty_def_id.expect_local(),
tcx.def_span(assoc_ty_def_id),
None,
);
}
}
}
/// Require that the user writes where clauses on GATs for the implicit
@ -1466,13 +1477,6 @@ fn check_fn_or_method<'tcx>(
check_where_clauses(wfcx, span, def_id);
check_return_position_impl_trait_in_trait_bounds(
wfcx,
def_id,
sig.output(),
hir_decl.output.span(),
);
if sig.abi == Abi::RustCall {
let span = tcx.def_span(def_id);
let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
@ -1507,87 +1511,6 @@ fn check_fn_or_method<'tcx>(
}
}
/// Basically `check_associated_type_bounds`, but separated for now and should be
/// deduplicated when RPITITs get lowered into real associated items.
#[tracing::instrument(level = "trace", skip(wfcx))]
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
fn_def_id: LocalDefId,
fn_output: Ty<'tcx>,
span: Span,
) {
let tcx = wfcx.tcx();
let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else {
return;
};
if assoc_item.container != ty::AssocItemContainer::TraitContainer {
return;
}
fn_output.visit_with(&mut ImplTraitInTraitFinder {
wfcx,
fn_def_id,
depth: ty::INNERMOST,
seen: FxHashSet::default(),
});
}
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering
// strategy, we can't just call `check_associated_item` on the new RPITITs,
// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail.
// That's because we need to check that the bounds of the RPITIT hold using
// the special args that we create during opaque type lowering, otherwise we're
// getting a bunch of early bound and free regions mixed up... Haven't looked too
// deep into this, though.
struct ImplTraitInTraitFinder<'a, 'tcx> {
wfcx: &'a WfCheckingCtxt<'a, 'tcx>,
fn_def_id: LocalDefId,
depth: ty::DebruijnIndex,
seen: FxHashSet<DefId>,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
type BreakTy = !;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> {
let tcx = self.wfcx.tcx();
if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
&& self.seen.insert(unshifted_opaque_ty.def_id)
&& let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
&& let origin = tcx.opaque_type_origin(opaque_def_id)
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin
&& source == self.fn_def_id
{
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
match re.kind() {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
r => bug!("unexpected region: {r:?}"),
}
});
for (bound, bound_span) in tcx
.explicit_item_bounds(opaque_ty.def_id)
.iter_instantiated_copied(tcx, opaque_ty.args)
{
let bound = self.wfcx.normalize(bound_span, None, bound);
self.wfcx.register_obligations(traits::wf::predicate_obligations(
self.wfcx.infcx,
self.wfcx.param_env,
self.wfcx.body_def_id,
bound.as_predicate(),
bound_span,
));
// Set the debruijn index back to innermost here, since we already eagerly
// shifted the args that we use to generate these bounds. This is unfortunately
// subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`,
// but that function doesn't actually need to normalize the bound it's visiting
// (whereas we have to do so here)...
let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST);
bound.visit_with(self);
self.depth = old_depth;
}
}
ty.super_visit_with(self)
}
}
const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
of the previous types except `Self`)";

View file

@ -1,6 +1,8 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::middle::resolve_bound_vars as rbv;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
@ -42,6 +44,41 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
let mut impl_spans = impl_spans(tcx, def_id);
tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
}
DefKind::AssocTy if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = tcx.opt_rpitit_info(def_id.to_def_id()) => {
let hir::OpaqueTy { lifetime_mapping, .. } =
*tcx.hir().expect_item(opaque_def_id.expect_local()).expect_opaque_ty();
let mut mapping = FxHashMap::default();
let generics = tcx.generics_of(def_id);
for &(lifetime, new_early_bound_def_id) in lifetime_mapping {
if let Some(rbv::ResolvedArg::LateBound(_, _, def_id)) =
tcx.named_bound_var(lifetime.hir_id)
{
let name = tcx.hir().name(lifetime.hir_id);
let index = generics
.param_def_id_to_index(tcx, new_early_bound_def_id.to_def_id())
.unwrap();
mapping.insert(
ty::Region::new_free(
tcx,
fn_def_id,
ty::BoundRegionKind::BrNamed(def_id, name),
),
ty::Region::new_early_bound(
tcx,
ty::EarlyBoundRegion {
def_id: new_early_bound_def_id.to_def_id(),
index,
name,
},
),
);
}
}
let a = tcx.fold_regions(tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), |re, _| {
if let Some(re) = mapping.get(&re) { *re } else { re }
});
tcx.arena.alloc_from_iter(a)
}
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
DefKind::TyAlias => ty::List::empty(),

View file

@ -8,6 +8,7 @@
#![feature(assert_matches)]
#![feature(iterator_try_collect)]
#![feature(let_chains)]
#![feature(if_let_guard)]
#![feature(never_type)]
#![feature(box_patterns)]
#![recursion_limit = "256"]

View file

@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^
|
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
--> $DIR/async-generics-and-bounds.rs:12:18
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^
| ^
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
--> $DIR/async-generics-and-bounds.rs:12:28
|
@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
--> $DIR/async-generics-and-bounds.rs:12:18
|
LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
| ^^^^^
| ^
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
--> $DIR/async-generics-and-bounds.rs:12:28
|

View file

@ -4,11 +4,11 @@ error[E0311]: the parameter type `U` may not live long enough
LL | async fn foo(&self) -> &(T, U);
| ^^^^^^^
|
note: the parameter type `U` must be valid for the anonymous lifetime defined here...
note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
--> $DIR/async-generics.rs:9:18
|
LL | async fn foo(&self) -> &(T, U);
| ^^^^^
| ^
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
--> $DIR/async-generics.rs:9:28
|
@ -21,11 +21,11 @@ error[E0311]: the parameter type `T` may not live long enough
LL | async fn foo(&self) -> &(T, U);
| ^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
--> $DIR/async-generics.rs:9:18
|
LL | async fn foo(&self) -> &(T, U);
| ^^^^^
| ^
note: ...so that the reference type `&(T, U)` does not outlive the data it points at
--> $DIR/async-generics.rs:9:28
|

View file

@ -47,10 +47,6 @@ note: required by a bound in `NeedsDisplay`
|
LL | struct NeedsDisplay<T: Display>(T);
| ^^^^^^^ required by this bound in `NeedsDisplay`
help: consider restricting type parameter `T`
|
LL | fn nya4<T: std::fmt::Display>() -> impl Wf<NeedsDisplay<T>>;
| +++++++++++++++++++
error: aborting due to 4 previous errors