Auto merge of #121123 - compiler-errors:item-assumptions, r=oli-obk

Split an item bounds and an item's super predicates

This is the moral equivalent of #107614, but instead for predicates this applies to **item bounds**. This PR splits out the item bounds (i.e. *all* predicates that are assumed to hold for the alias) from the item *super predicates*, which are the subset of item bounds which share the same self type as the alias.

## Why?

Much like #107614, there are places in the compiler where we *only* care about super-predicates, and considering predicates that possibly don't have anything to do with the alias is problematic. This includes things like closure signature inference (which is at its core searching for `Self: Fn(..)` style bounds), but also lints like `#[must_use]`, error reporting for aliases, computing type outlives predicates.

Even in cases where considering all of the `item_bounds` doesn't lead to bugs, unnecessarily considering irrelevant bounds does lead to a regression (#121121) due to doing extra work in the solver.

## Example 1 - Trait Aliases

This is best explored via an example:

```
type TAIT<T> = impl TraitAlias<T>;

trait TraitAlias<T> = A + B where T: C;
```

The item bounds list for `Tait<T>` will include:
* `Tait<T>: A`
* `Tait<T>: B`
* `T: C`

While `item_super_predicates` query will include just the first two predicates.

Side-note: You may wonder why `T: C` is included in the item bounds for `TAIT`? This is because when we elaborate `TraitAlias<T>`, we will also elaborate all the predicates on the trait.

## Example 2 - Associated Type Bounds

```
type TAIT<T> = impl Iterator<Item: A>;
```

The `item_bounds` list for `TAIT<T>` will include:
* `Tait<T>: Iterator`
* `<Tait<T> as Iterator>::Item: A`

But the `item_super_predicates` will just include the first bound, since that's the only bound that is relevant to the *alias* itself.

## So what

This leads to some diagnostics duplication just like #107614, but none of it will be user-facing. We only see it in the UI test suite because we explicitly disable diagnostic deduplication.

Regarding naming, I went with `super_predicates` kind of arbitrarily; this can easily be changed, but I'd consider better names as long as we don't block this PR in perpetuity.
This commit is contained in:
bors 2024-03-21 06:12:24 +00:00
commit e8794ff541
2 changed files with 5 additions and 5 deletions

View File

@ -64,7 +64,7 @@ fn check_fn(
} }
let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner()); let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
let preds = cx.tcx.explicit_item_bounds(def_id); let preds = cx.tcx.explicit_item_super_predicates(def_id);
let mut is_future = false; let mut is_future = false;
for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) { for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
if let Some(trait_pred) = p.as_trait_clause() { if let Some(trait_pred) = p.as_trait_clause() {

View File

@ -96,7 +96,7 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
return false; return false;
} }
for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).instantiate_identity_iter_copied() {
match predicate.kind().skip_binder() { match predicate.kind().skip_binder() {
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
// and check substitutions to find `U`. // and check substitutions to find `U`.
@ -328,7 +328,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
}, },
ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() {
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
return true; return true;
@ -729,7 +729,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds( ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds(
cx, cx,
ty, ty,
cx.tcx.item_bounds(def_id).iter_instantiated(cx.tcx, args), cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args),
cx.tcx.opt_parent(def_id), cx.tcx.opt_parent(def_id),
), ),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@ -807,7 +807,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
for (pred, _) in cx for (pred, _) in cx
.tcx .tcx
.explicit_item_bounds(ty.def_id) .explicit_item_super_predicates(ty.def_id)
.iter_instantiated_copied(cx.tcx, ty.args) .iter_instantiated_copied(cx.tcx, ty.args)
{ {
match pred.kind().skip_binder() { match pred.kind().skip_binder() {