@@ -3,6 +3,7 @@ use std::iter;
3
3
use std:: ops:: ControlFlow ;
4
4
5
5
use crate :: clauses:: ClauseBuilder ;
6
+ use crate :: clauses:: super_traits:: super_traits;
6
7
use crate :: rust_ir:: AdtKind ;
7
8
use crate :: { Interner , RustIrDatabase , TraitRef , WellKnownTrait } ;
8
9
use chalk_ir:: {
@@ -204,7 +205,20 @@ pub fn add_unsize_program_clauses<I: Interner>(
204
205
let principal_a = principal_id ( db, bounds_a) ;
205
206
let principal_b = principal_id ( db, bounds_b) ;
206
207
207
- let auto_trait_ids_a: Vec < _ > = auto_trait_ids ( db, bounds_a) . collect ( ) ;
208
+ // Include super traits in a list of auto traits for A,
209
+ // to allow `dyn Trait -> dyn Trait + X` if `Trait: X`.
210
+ let auto_trait_ids_a: Vec < _ > = auto_trait_ids ( db, bounds_a)
211
+ . chain ( principal_a. into_iter ( ) . flat_map ( |principal_a| {
212
+ super_traits ( db, principal_a)
213
+ . into_value_and_skipped_binders ( )
214
+ . 0
215
+ . 0
216
+ . into_iter ( )
217
+ . map ( |x| x. skip_binders ( ) . trait_id )
218
+ . filter ( |& x| db. trait_datum ( x) . is_auto_trait ( ) )
219
+ } ) )
220
+ . collect ( ) ;
221
+
208
222
let auto_trait_ids_b: Vec < _ > = auto_trait_ids ( db, bounds_b) . collect ( ) ;
209
223
210
224
let may_apply = principal_a == principal_b
@@ -234,7 +248,7 @@ pub fn add_unsize_program_clauses<I: Interner>(
234
248
// ------------------
235
249
236
250
// Construct a new trait object type by taking the source ty,
237
- // filtering out auto traits of source that are not present in target
251
+ // replacing auto traits of source with those of target,
238
252
// and changing source lifetime to target lifetime.
239
253
//
240
254
// In order for the coercion to be valid, this new type
@@ -243,17 +257,33 @@ pub fn add_unsize_program_clauses<I: Interner>(
243
257
bounds : bounds_a. map_ref ( |bounds| {
244
258
QuantifiedWhereClauses :: from_iter (
245
259
interner,
246
- bounds. iter ( interner) . filter ( |bound| {
247
- let trait_id = match bound. trait_id ( ) {
248
- Some ( id) => id,
249
- None => return true ,
250
- } ;
251
-
252
- if auto_trait_ids_a. iter ( ) . all ( |& id_a| id_a != trait_id) {
253
- return true ;
254
- }
255
- auto_trait_ids_b. iter ( ) . any ( |& id_b| id_b == trait_id)
256
- } ) ,
260
+ bounds
261
+ . iter ( interner)
262
+ . cloned ( )
263
+ . filter_map ( |bound| {
264
+ let Some ( trait_id) = bound. trait_id ( ) else {
265
+ // Keep non-"implements" bounds as-is
266
+ return Some ( bound) ;
267
+ } ;
268
+
269
+ // Auto traits are already checked above, ignore them
270
+ // (we'll use the ones from B below)
271
+ if db. trait_datum ( trait_id) . is_auto_trait ( ) {
272
+ return None ;
273
+ }
274
+
275
+ // The only "implements" bound that is not an auto trait, is the principal
276
+ assert_eq ! ( Some ( trait_id) , principal_a) ;
277
+ Some ( bound)
278
+ } )
279
+ // Add auto traits from B (again, they are already checked above).
280
+ . chain ( bounds_b. skip_binders ( ) . iter ( interner) . cloned ( ) . filter (
281
+ |bound| {
282
+ bound. trait_id ( ) . is_some_and ( |trait_id| {
283
+ db. trait_datum ( trait_id) . is_auto_trait ( )
284
+ } )
285
+ } ,
286
+ ) ) ,
257
287
)
258
288
} ) ,
259
289
lifetime : lifetime_b. clone ( ) ,
0 commit comments