Skip to content
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

Make RPITITs assume/require their parent method's predicates #113215

Merged
merged 4 commits into from
Jul 4, 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
19 changes: 16 additions & 3 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,26 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
use rustc_hir::*;

match tcx.opt_rpitit_info(def_id.to_def_id()) {
Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
Some(ImplTraitInTraitData::Trait { opaque_def_id, fn_def_id }) => {
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else {
bug!("unexpected {opaque_ty_node:?}")
};

let mut predicates = Vec::new();

// RPITITs should inherit the predicates of their parent. This is
// both to ensure that the RPITITs are only instantiated when the
// parent predicates would hold, and also so that the param-env
// inherits these predicates as assumptions.
let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
predicates.extend(
tcx.explicit_predicates_of(fn_def_id).instantiate_own(tcx, identity_substs),
);

// We also install bidirectional outlives predicates for the RPITIT
// to keep the duplicates lifetimes from opaque lowering in sync.
compute_bidirectional_outlives_predicates(
tcx,
def_id,
Expand All @@ -89,12 +101,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen

Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
let assoc_item = tcx.associated_item(def_id);
let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap());
let trait_assoc_predicates =
tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap());

let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
let impl_def_id = tcx.parent(fn_def_id);
let impl_trait_ref_substs =
tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs;
tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity().substs;

let impl_assoc_substs =
impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,9 @@ fn foo(&self) -> Self::T { String::new() }
let Some(hir_id) = body_owner_def_id.as_local() else {
return false;
};
let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id);
let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(hir_id) else {
return false;
};
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
// `expected` and point at it.
let parent_id = tcx.hir().get_parent_item(hir_id);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,10 +1151,10 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
let assoc_item = tcx.associated_item(def_id);
match assoc_item.container {
ty::AssocItemContainer::ImplContainer => true,
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) always encode RPITITs,
// since we need to be able to "project" from an RPITIT associated item
// to an opaque when installing the default projection predicates in
// default trait methods with RPITITs.
// Always encode RPITITs, since we need to be able to project
// from an RPITIT associated item to an opaque when installing
// the default projection predicates in default trait methods
// with RPITITs.
ty::AssocItemContainer::TraitContainer => {
assoc_item.defaultness(tcx).has_value() || assoc_item.opt_rpitit_info.is_some()
}
Expand Down
19 changes: 1 addition & 18 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, EarlyBinder, ImplTraitInTraitData, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
self, EarlyBinder, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use rustc_session::config::TraitSolver;
use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
Expand Down Expand Up @@ -120,22 +119,6 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
let ty::InstantiatedPredicates { mut predicates, .. } =
tcx.predicates_of(def_id).instantiate_identity(tcx);

// When computing the param_env of an RPITIT, use predicates of the containing function,
// *except* for the additional assumption that the RPITIT normalizes to the trait method's
// default opaque type. This is needed to properly check the item bounds of the assoc
// type hold (`check_type_bounds`), since that method already installs a similar projection
// bound, so they will conflict.
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should
// at least be making sure that the generics in RPITITs and their parent fn don't
// get out of alignment, or else we do actually need to substitute these predicates.
if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. })
| Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id)
{
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Should not need to add the predicates
// from the parent fn to our assumptions
predicates.extend(tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates);
}

// Finally, we have to normalize the bounds in the environment, in
// case they contain any associated type projections. This process
// can yield errors if the put in illegal associated types, like
Expand Down
6 changes: 1 addition & 5 deletions tests/ui/impl-trait/in-trait/issue-102140.next.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ LL | MyTrait::foo(&self)
| |
| required by a bound introduced by this call
|
help: consider removing the leading `&`-reference
|
LL - MyTrait::foo(&self)
LL + MyTrait::foo(self)
|
Comment on lines -9 to -13
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why exactly this suggestion changed, but if you look below, the new "help: the trait MyTrait is implemented for Outer" is actually emitted instead, so I don't really consider this to be a regression.

Also this suggestion isn't even right, I think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and even removing & doesn't help in any way.

= help: the trait `MyTrait` is implemented for `Outer`

error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
--> $DIR/issue-102140.rs:26:9
Expand Down
27 changes: 22 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:13:22
--> $DIR/wf-bounds.rs:17:22
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -9,14 +9,14 @@ 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:16:23
--> $DIR/wf-bounds.rs:20:23
|
LL | fn nya2() -> impl Wf<[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 `Wf`
--> $DIR/wf-bounds.rs:8:10
--> $DIR/wf-bounds.rs:10:10
|
LL | trait Wf<T> {
| ^ required by this bound in `Wf`
Expand All @@ -26,7 +26,7 @@ LL | trait Wf<T: ?Sized> {
| ++++++++

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:19:44
--> $DIR/wf-bounds.rs:23:44
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -35,6 +35,23 @@ LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error: aborting due to 3 previous errors
error[E0277]: `T` doesn't implement `std::fmt::Display`
--> $DIR/wf-bounds.rs:26:26
|
LL | fn nya4<T>() -> impl Wf<NeedsDisplay<T>>;
| ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `NeedsDisplay`
--> $DIR/wf-bounds.rs:14:24
|
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

For more information about this error, try `rustc --explain E0277`.
27 changes: 22 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:13:22
--> $DIR/wf-bounds.rs:17:22
|
LL | fn nya() -> impl Wf<Vec<[u8]>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -9,14 +9,14 @@ 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:16:23
--> $DIR/wf-bounds.rs:20:23
|
LL | fn nya2() -> impl Wf<[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 `Wf`
--> $DIR/wf-bounds.rs:8:10
--> $DIR/wf-bounds.rs:10:10
|
LL | trait Wf<T> {
| ^ required by this bound in `Wf`
Expand All @@ -26,7 +26,7 @@ LL | trait Wf<T: ?Sized> {
| ++++++++

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/wf-bounds.rs:19:44
--> $DIR/wf-bounds.rs:23:44
|
LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -35,6 +35,23 @@ LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>;
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error: aborting due to 3 previous errors
error[E0277]: `T` doesn't implement `std::fmt::Display`
--> $DIR/wf-bounds.rs:26:26
|
LL | fn nya4<T>() -> impl Wf<NeedsDisplay<T>>;
| ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `NeedsDisplay`
--> $DIR/wf-bounds.rs:14:24
|
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

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

use std::fmt::Display;

trait Wf<T> {
type Output;
}

struct NeedsDisplay<T: Display>(T);

trait Uwu {
fn nya() -> impl Wf<Vec<[u8]>>;
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
Expand All @@ -18,6 +22,9 @@ trait Uwu {

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

fn nya4<T>() -> impl Wf<NeedsDisplay<T>>;
//~^ ERROR `T` doesn't implement `std::fmt::Display`
}

fn main() {}