@@ -4,7 +4,7 @@ use std::iter;
4
4
5
5
use super :: assembly:: { self , Candidate , CandidateSource } ;
6
6
use super :: infcx_ext:: InferCtxtExt ;
7
- use super :: { Certainty , EvalCtxt , Goal , QueryResult } ;
7
+ use super :: { CanonicalResponse , Certainty , EvalCtxt , Goal , QueryResult } ;
8
8
use rustc_hir:: def_id:: DefId ;
9
9
use rustc_infer:: infer:: InferCtxt ;
10
10
use rustc_infer:: traits:: query:: NoSolution ;
@@ -253,57 +253,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
253
253
ecx. infcx . probe ( |_| {
254
254
match ( a_ty. kind ( ) , b_ty. kind ( ) ) {
255
255
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
256
- (
257
- & ty:: Dynamic ( a_data, a_region, ty:: Dyn ) ,
258
- & ty:: Dynamic ( b_data, b_region, ty:: Dyn ) ,
259
- ) => {
260
- // All of a's auto traits need to be in b's auto traits.
261
- let auto_traits_compatible = b_data
262
- . auto_traits ( )
263
- . all ( |b| a_data. auto_traits ( ) . any ( |a| a == b) ) ;
264
- if !auto_traits_compatible {
265
- return Err ( NoSolution ) ;
266
- }
267
-
268
- // If the principal def ids match (or are both none), then we're not doing
269
- // trait upcasting. We're just removing auto traits (or shortening the lifetime).
270
- if a_data. principal_def_id ( ) == b_data. principal_def_id ( ) {
271
- // Require that all of the trait predicates from A match B, except for
272
- // the auto traits. We do this by constructing a new A type with B's
273
- // auto traits, and equating these types.
274
- let new_a_data = a_data
275
- . iter ( )
276
- . filter ( |a| {
277
- matches ! (
278
- a. skip_binder( ) ,
279
- ty:: ExistentialPredicate :: Trait ( _) | ty:: ExistentialPredicate :: Projection ( _)
280
- )
281
- } )
282
- . chain (
283
- b_data
284
- . auto_traits ( )
285
- . map ( ty:: ExistentialPredicate :: AutoTrait )
286
- . map ( ty:: Binder :: dummy) ,
287
- ) ;
288
- let new_a_data = tcx. mk_poly_existential_predicates ( new_a_data) ;
289
- let new_a_ty = tcx. mk_dynamic ( new_a_data, b_region, ty:: Dyn ) ;
290
-
291
- // We also require that A's lifetime outlives B's lifetime.
292
- let mut nested_obligations = ecx. infcx . eq ( goal. param_env , new_a_ty, b_ty) ?;
293
- nested_obligations. push ( goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region, b_region) ) ) ) ;
294
-
295
- ecx. evaluate_all_and_make_canonical_response ( nested_obligations)
296
- } else if let Some ( a_principal) = a_data. principal ( )
297
- && let Some ( b_principal) = b_data. principal ( )
298
- && supertraits ( tcx, a_principal. with_self_ty ( tcx, a_ty) )
299
- . any ( |trait_ref| trait_ref. def_id ( ) == b_principal. def_id ( ) )
300
- {
301
- // FIXME: Intentionally ignoring `need_migrate_deref_output_trait_object` here for now.
302
- // Confirm upcasting candidate
303
- todo ! ( )
304
- } else {
305
- Err ( NoSolution )
306
- }
256
+ ( & ty:: Dynamic ( _, _, ty:: Dyn ) , & ty:: Dynamic ( _, _, ty:: Dyn ) ) => {
257
+ // Dyn upcasting is handled separately, since due to upcasting,
258
+ // when there are two supertraits that differ by substs, we
259
+ // may return more than one query response.
260
+ return Err ( NoSolution ) ;
307
261
}
308
262
// `T` -> `dyn Trait` unsizing
309
263
( _, & ty:: Dynamic ( data, region, ty:: Dyn ) ) => {
@@ -332,10 +286,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
332
286
ty:: Binder :: dummy ( tcx. mk_trait_ref ( sized_def_id, [ a_ty] ) ) ,
333
287
) ,
334
288
// The type must outlive the lifetime of the `dyn` we're unsizing into.
335
- goal. with (
336
- tcx,
337
- ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_ty, region) ) ,
338
- ) ,
289
+ goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_ty, region) ) ) ,
339
290
] )
340
291
. collect ( ) ;
341
292
@@ -413,6 +364,81 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
413
364
}
414
365
} )
415
366
}
367
+
368
+ fn consider_builtin_dyn_unsize_candidates (
369
+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
370
+ goal : Goal < ' tcx , Self > ,
371
+ ) -> Vec < CanonicalResponse < ' tcx > > {
372
+ let tcx = ecx. tcx ( ) ;
373
+
374
+ let a_ty = goal. predicate . self_ty ( ) ;
375
+ let b_ty = goal. predicate . trait_ref . substs . type_at ( 1 ) ;
376
+ let ty:: Dynamic ( a_data, a_region, ty:: Dyn ) = * a_ty. kind ( ) else {
377
+ return vec ! [ ] ;
378
+ } ;
379
+ let ty:: Dynamic ( b_data, b_region, ty:: Dyn ) = * b_ty. kind ( ) else {
380
+ return vec ! [ ] ;
381
+ } ;
382
+
383
+ // All of a's auto traits need to be in b's auto traits.
384
+ let auto_traits_compatible =
385
+ b_data. auto_traits ( ) . all ( |b| a_data. auto_traits ( ) . any ( |a| a == b) ) ;
386
+ if !auto_traits_compatible {
387
+ return vec ! [ ] ;
388
+ }
389
+
390
+ let mut responses = vec ! [ ] ;
391
+ let mut unsize_dyn_to_principal = |principal : Option < ty:: PolyExistentialTraitRef < ' tcx > > | {
392
+ let _ = ecx. infcx . probe ( |_| -> Result < ( ) , NoSolution > {
393
+ // Require that all of the trait predicates from A match B, except for
394
+ // the auto traits. We do this by constructing a new A type with B's
395
+ // auto traits, and equating these types.
396
+ let new_a_data = principal
397
+ . into_iter ( )
398
+ . map ( |trait_ref| trait_ref. map_bound ( ty:: ExistentialPredicate :: Trait ) )
399
+ . chain ( a_data. iter ( ) . filter ( |a| {
400
+ matches ! ( a. skip_binder( ) , ty:: ExistentialPredicate :: Projection ( _) )
401
+ } ) )
402
+ . chain (
403
+ b_data
404
+ . auto_traits ( )
405
+ . map ( ty:: ExistentialPredicate :: AutoTrait )
406
+ . map ( ty:: Binder :: dummy) ,
407
+ ) ;
408
+ let new_a_data = tcx. mk_poly_existential_predicates ( new_a_data) ;
409
+ let new_a_ty = tcx. mk_dynamic ( new_a_data, b_region, ty:: Dyn ) ;
410
+
411
+ // We also require that A's lifetime outlives B's lifetime.
412
+ let mut nested_obligations = ecx. infcx . eq ( goal. param_env , new_a_ty, b_ty) ?;
413
+ nested_obligations. push (
414
+ goal. with ( tcx, ty:: Binder :: dummy ( ty:: OutlivesPredicate ( a_region, b_region) ) ) ,
415
+ ) ;
416
+
417
+ responses. push ( ecx. evaluate_all_and_make_canonical_response ( nested_obligations) ?) ;
418
+
419
+ Ok ( ( ) )
420
+ } ) ;
421
+ } ;
422
+
423
+ // If the principal def ids match (or are both none), then we're not doing
424
+ // trait upcasting. We're just removing auto traits (or shortening the lifetime).
425
+ if a_data. principal_def_id ( ) == b_data. principal_def_id ( ) {
426
+ unsize_dyn_to_principal ( a_data. principal ( ) ) ;
427
+ } else if let Some ( a_principal) = a_data. principal ( )
428
+ && let Some ( b_principal) = b_data. principal ( )
429
+ {
430
+ for super_trait_ref in supertraits ( tcx, a_principal. with_self_ty ( tcx, a_ty) ) {
431
+ if super_trait_ref. def_id ( ) != b_principal. def_id ( ) {
432
+ continue ;
433
+ }
434
+ let erased_trait_ref = super_trait_ref
435
+ . map_bound ( |trait_ref| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) ) ;
436
+ unsize_dyn_to_principal ( Some ( erased_trait_ref) ) ;
437
+ }
438
+ }
439
+
440
+ responses
441
+ }
416
442
}
417
443
418
444
impl < ' tcx > EvalCtxt < ' _ , ' tcx > {
0 commit comments