Skip to content

Deeply check well-formedness of return-position impl Trait in trait #109545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 72 additions & 33 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,42 +1544,81 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
span: Span,
) {
let tcx = wfcx.tcx();
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
{
// 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 substs 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.
for arg in fn_output.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
// RPITITs are always eagerly normalized into opaques, so always look for an
// opaque here.
&& let ty::Alias(ty::Opaque, opaque_ty) = ty.kind()
&& let Some(opaque_def_id) = opaque_ty.def_id.as_local()
&& let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
&& source == fn_def_id
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 substs 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 opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
&& source == self.fn_def_id
{
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| {
if let ty::ReLateBound(index, bv) = re.kind() {
if depth != ty::INNERMOST {
return tcx.mk_re_error_with_message(
DUMMY_SP,
"we shouldn't walk non-predicate binders with `impl Trait`...",
);
}
tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
} else {
re
}
});
for (bound, bound_span) in tcx
.bound_explicit_item_bounds(opaque_ty.def_id)
.subst_iter_copied(tcx, opaque_ty.substs)
{
let span = tcx.def_span(opaque_ty.def_id);
let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs);
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
wfcx.param_env,
wfcx.body_def_id,
normalized_bound,
bound_span,
)
});
wfcx.register_obligations(wf_obligations);
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,
bound_span,
));
// Set the debruijn index back to innermost here, since we already eagerly
// shifted the substs 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)
}
}

Expand Down
20 changes: 15 additions & 5 deletions tests/ui/impl-trait/in-trait/wf-bounds.current.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:11:22
--> $DIR/wf-bounds.rs:13:22
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -9,7 +9,7 @@ note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:14:23
--> $DIR/wf-bounds.rs:16:23
|
LL | fn nya2() -> impl Wf<[u8]>;
| ^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -18,13 +18,23 @@ LL | fn nya2() -> impl Wf<[u8]>;
note: required by a bound in `Wf`
--> $DIR/wf-bounds.rs:8:10
|
LL | trait Wf<T> {}
LL | trait Wf<T> {
| ^ required by this bound in `Wf`
help: consider relaxing the implicit `Sized` restriction
|
LL | trait Wf<T: ?Sized> {}
LL | trait Wf<T: ?Sized> {
| ++++++++

error: aborting due to 2 previous errors
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:19:44
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
20 changes: 15 additions & 5 deletions tests/ui/impl-trait/in-trait/wf-bounds.next.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:11:22
--> $DIR/wf-bounds.rs:13:22
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -9,7 +9,7 @@ note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:14:23
--> $DIR/wf-bounds.rs:16:23
|
LL | fn nya2() -> impl Wf<[u8]>;
| ^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -18,13 +18,23 @@ LL | fn nya2() -> impl Wf<[u8]>;
note: required by a bound in `Wf`
--> $DIR/wf-bounds.rs:8:10
|
LL | trait Wf<T> {}
LL | trait Wf<T> {
| ^ required by this bound in `Wf`
help: consider relaxing the implicit `Sized` restriction
|
LL | trait Wf<T: ?Sized> {}
LL | trait Wf<T: ?Sized> {
| ++++++++

error: aborting due to 2 previous errors
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:19:44
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
7 changes: 6 additions & 1 deletion tests/ui/impl-trait/in-trait/wf-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
#![feature(return_position_impl_trait_in_trait)]
#![allow(incomplete_features)]

trait Wf<T> {}
trait Wf<T> {
type Output;
}

trait Uwu {
fn nya() -> impl Wf<Vec<[u8]>>;
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time

fn nya2() -> impl Wf<[u8]>;
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time

fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
}

fn main() {}