Skip to content

Commit a054be7

Browse files
authored
Rollup merge of #140684 - compiler-errors:unnecessary-assoc, r=lcnr
Only include `dyn Trait<Assoc = ...>` associated type bounds for `Self: Sized` associated types if they are provided Since #136458, we began filtering out associated types with `Self: Sized` bounds when constructing the list of associated type bounds to put into our `dyn Trait` types. For example, given: ```rust trait Trait { type Assoc where Self: Sized; } ``` After #136458, even if a user writes `dyn Trait<Assoc = ()>`, the lowered ty would have an empty projection list, and thus be equivalent to `dyn Trait`. However, this has the side effect of no longer constraining any types in the RHS of `Assoc = ...`, not implying any WF implied bounds, and not requiring that they hold when unsizing. After this PR, we include these bounds, but (still) do not require that they are provided. If the are not provided, they are skipped from the projections list. This results in `dyn Trait` types that have differing numbers of projection bounds. This will lead to re-introducing type mismatches e.g. between `dyn Trait` and `dyn Trait<Assoc = ()>`. However, this is expected and doesn't suffer from any of the deduplication unsoundness from before #136458. We may want to begin to ignore thse bounds in the future by bumping `unused_associated_type_bounds` to an FCW. I don't want to tangle that up into the fix that was originally intended in #136458, so I'm doing a "fix-forward" in this PR and deferring thinking about this for the future. Fixes #140645 r? lcnr
2 parents 32e3207 + 3799d84 commit a054be7

File tree

5 files changed

+73
-11
lines changed

5 files changed

+73
-11
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
172172

173173
let principal_trait = regular_traits.into_iter().next();
174174

175-
let mut needed_associated_types = vec![];
175+
// A stable ordering of associated types from the principal trait and all its
176+
// supertraits. We use this to ensure that different substitutions of a trait
177+
// don't result in `dyn Trait` types with different projections lists, which
178+
// can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
179+
// We achieve a stable ordering by walking over the unsubstituted principal
180+
// trait ref.
181+
let mut ordered_associated_types = vec![];
182+
176183
if let Some((principal_trait, ref spans)) = principal_trait {
177184
let principal_trait = principal_trait.map_bound(|trait_pred| {
178185
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
@@ -197,16 +204,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
197204
// FIXME(negative_bounds): Handle this correctly...
198205
let trait_ref =
199206
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
200-
needed_associated_types.extend(
207+
ordered_associated_types.extend(
201208
tcx.associated_items(pred.trait_ref.def_id)
202209
.in_definition_order()
203210
// We only care about associated types.
204211
.filter(|item| item.is_type())
205212
// No RPITITs -- they're not dyn-compatible for now.
206213
.filter(|item| !item.is_impl_trait_in_trait())
207-
// If the associated type has a `where Self: Sized` bound,
208-
// we do not need to constrain the associated type.
209-
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
210214
.map(|item| (item.def_id, trait_ref)),
211215
);
212216
}
@@ -278,14 +282,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
278282
}
279283
}
280284

285+
// We compute the list of projection bounds taking the ordered associated types,
286+
// and check if there was an entry in the collected `projection_bounds`. Those
287+
// are computed by first taking the user-written associated types, then elaborating
288+
// the principal trait ref, and only using those if there was no user-written.
289+
// See note below about how we handle missing associated types with `Self: Sized`,
290+
// which are not required to be provided, but are still used if they are provided.
281291
let mut missing_assoc_types = FxIndexSet::default();
282-
let projection_bounds: Vec<_> = needed_associated_types
292+
let projection_bounds: Vec<_> = ordered_associated_types
283293
.into_iter()
284294
.filter_map(|key| {
285295
if let Some(assoc) = projection_bounds.get(&key) {
286296
Some(*assoc)
287297
} else {
288-
missing_assoc_types.insert(key);
298+
// If the associated type has a `where Self: Sized` bound, then
299+
// we do not need to provide the associated type. This results in
300+
// a `dyn Trait` type that has a different number of projection
301+
// bounds, which may lead to type mismatches.
302+
if !tcx.generics_require_sized_self(key.0) {
303+
missing_assoc_types.insert(key);
304+
}
289305
None
290306
}
291307
})

compiler/rustc_middle/src/ty/sty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,10 @@ impl<'tcx> Ty<'tcx> {
723723
repr: DynKind,
724724
) -> Ty<'tcx> {
725725
if cfg!(debug_assertions) {
726-
let projection_count = obj.projection_bounds().count();
726+
let projection_count = obj
727+
.projection_bounds()
728+
.filter(|item| !tcx.generics_require_sized_self(item.item_def_id()))
729+
.count();
727730
let expected_count: usize = obj
728731
.principal_def_id()
729732
.into_iter()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ check-pass
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/140645>.
4+
// Test that we lower impossible-to-satisfy associated type bounds, which
5+
// may for example constrain impl parameters.
6+
7+
pub trait Other {}
8+
9+
pub trait Trait {
10+
type Assoc
11+
where
12+
Self: Sized;
13+
}
14+
15+
impl Other for dyn Trait {}
16+
// `dyn Trait<Assoc = ()>` is a different "nominal type" than `dyn Trait`.
17+
impl Other for dyn Trait<Assoc = ()> {}
18+
//~^ WARN unnecessary associated type bound for dyn-incompatible associated type
19+
20+
// I hope it's clear that `dyn Trait` (w/o `Assoc`) wouldn't match this impl.
21+
impl<T> dyn Trait<Assoc = T> {}
22+
//~^ WARN unnecessary associated type bound for dyn-incompatible associated type
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
warning: unnecessary associated type bound for dyn-incompatible associated type
2+
--> $DIR/constrain-via-unnecessary-bound.rs:17:26
3+
|
4+
LL | impl Other for dyn Trait<Assoc = ()> {}
5+
| ^^^^^^^^^^ help: remove this bound
6+
|
7+
= note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
8+
= note: `#[warn(unused_associated_type_bounds)]` on by default
9+
10+
warning: unnecessary associated type bound for dyn-incompatible associated type
11+
--> $DIR/constrain-via-unnecessary-bound.rs:21:19
12+
|
13+
LL | impl<T> dyn Trait<Assoc = T> {}
14+
| ^^^^^^^^^ help: remove this bound
15+
|
16+
= note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
17+
18+
warning: 2 warnings emitted
19+

tests/ui/traits/object/pretty.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ error[E0308]: mismatched types
154154
--> $DIR/pretty.rs:41:56
155155
|
156156
LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
157-
| - ^ expected `()`, found `&dyn HasGat<u8>`
157+
| - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
158158
| |
159-
| help: try adding a return type: `-> &dyn HasGat<u8>`
159+
| help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
160160
|
161161
= note: expected unit type `()`
162-
found reference `&dyn HasGat<u8>`
162+
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
163163

164164
error: aborting due to 14 previous errors; 1 warning emitted
165165

0 commit comments

Comments
 (0)