@@ -8,7 +8,7 @@ use std::collections::{hash_map::Entry, HashMap};
8
8
use rustc_hir:: def:: DefKind ;
9
9
use rustc_hir:: def_id:: DefId ;
10
10
use rustc_middle:: traits:: CodegenObligationError ;
11
- use rustc_middle:: ty:: * ;
11
+ use rustc_middle:: ty:: { self , * } ;
12
12
use rustc_trait_selection:: traits:: ImplSource ;
13
13
14
14
use crate :: { self_predicate, traits:: utils:: erase_and_norm} ;
@@ -73,6 +73,11 @@ pub enum ImplExprAtom<'tcx> {
73
73
/// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that
74
74
/// built-in implementation.
75
75
Dyn ,
76
+ /// A virtual `Drop` implementation.
77
+ /// `Drop` doesn't work like a real trait but we want to pretend it does. If a type has a
78
+ /// user-defined `impl Drop for X` we just use the `Concrete` variant, but if it doesn't we use
79
+ /// this variant to supply the data needed to know what code will run on drop.
80
+ Drop ( DropData < ' tcx > ) ,
76
81
/// A built-in trait whose implementation is computed by the compiler, such as `FnMut`. This
77
82
/// morally points to an invisible `impl` block; as such it contains the information we may
78
83
/// need from one.
@@ -89,6 +94,27 @@ pub enum ImplExprAtom<'tcx> {
89
94
Error ( String ) ,
90
95
}
91
96
97
+ #[ derive( Debug , Clone ) ]
98
+ pub enum DropData < ' tcx > {
99
+ /// A drop that does nothing, e.g. for scalars and pointers.
100
+ Noop ,
101
+ /// An implicit `Drop` local clause, if the `resolve_drop_bounds` option is `false`. If that
102
+ /// option is `true`, we'll add `Drop` bounds to every type param, and use that to resolve
103
+ /// `Drop` impls of generics. If it's `false`, we use this variant to indicate that the drop
104
+ /// clause comes from a generic or associated type.
105
+ Implicit ,
106
+ /// The implicit `Drop` impl that exists for every type without an explicit `Drop` impl. The
107
+ /// virtual impl is considered to have one `T: Drop` bound for each generic argument of the
108
+ /// target type; it then simply drops each field in order.
109
+ Glue {
110
+ /// The type we're generating glue for.
111
+ ty : Ty < ' tcx > ,
112
+ /// The `ImplExpr`s for the `T: Drop` bounds of the virtual impl. There is one for each
113
+ /// generic argument, in order.
114
+ impl_exprs : Vec < ImplExpr < ' tcx > > ,
115
+ } ,
116
+ }
117
+
92
118
#[ derive( Clone , Debug ) ]
93
119
pub struct ImplExpr < ' tcx > {
94
120
/// The trait this is an impl for.
@@ -197,6 +223,22 @@ struct Candidate<'tcx> {
197
223
origin : AnnotatedTraitPred < ' tcx > ,
198
224
}
199
225
226
+ impl < ' tcx > Candidate < ' tcx > {
227
+ fn into_impl_expr ( self , tcx : TyCtxt < ' tcx > ) -> ImplExprAtom < ' tcx > {
228
+ let path = self . path ;
229
+ let r#trait = self . origin . clause . to_poly_trait_ref ( ) ;
230
+ match self . origin . origin {
231
+ BoundPredicateOrigin :: SelfPred => ImplExprAtom :: SelfImpl { r#trait, path } ,
232
+ BoundPredicateOrigin :: Item ( index) => ImplExprAtom :: LocalBound {
233
+ predicate : self . origin . clause . upcast ( tcx) ,
234
+ index,
235
+ r#trait,
236
+ path,
237
+ } ,
238
+ }
239
+ }
240
+ }
241
+
200
242
/// Stores a set of predicates along with where they came from.
201
243
pub struct PredicateSearcher < ' tcx > {
202
244
tcx : TyCtxt < ' tcx > ,
@@ -375,10 +417,12 @@ impl<'tcx> PredicateSearcher<'tcx> {
375
417
use rustc_trait_selection:: traits:: {
376
418
BuiltinImplSource , ImplSource , ImplSourceUserDefinedData ,
377
419
} ;
420
+ let tcx = self . tcx ;
421
+ let drop_trait = tcx. lang_items ( ) . drop_trait ( ) . unwrap ( ) ;
378
422
379
423
let erased_tref = erase_and_norm ( self . tcx , self . typing_env , * tref) ;
424
+ let trait_def_id = erased_tref. skip_binder ( ) . def_id ;
380
425
381
- let tcx = self . tcx ;
382
426
let impl_source = shallow_resolve_trait_ref ( tcx, self . typing_env . param_env , erased_tref) ;
383
427
let atom = match impl_source {
384
428
Ok ( ImplSource :: UserDefined ( ImplSourceUserDefinedData {
@@ -397,21 +441,7 @@ impl<'tcx> PredicateSearcher<'tcx> {
397
441
}
398
442
Ok ( ImplSource :: Param ( _) ) => {
399
443
match self . resolve_local ( erased_tref. upcast ( self . tcx ) , warn) ? {
400
- Some ( candidate) => {
401
- let path = candidate. path ;
402
- let r#trait = candidate. origin . clause . to_poly_trait_ref ( ) ;
403
- match candidate. origin . origin {
404
- BoundPredicateOrigin :: SelfPred => {
405
- ImplExprAtom :: SelfImpl { r#trait, path }
406
- }
407
- BoundPredicateOrigin :: Item ( index) => ImplExprAtom :: LocalBound {
408
- predicate : candidate. origin . clause . upcast ( tcx) ,
409
- index,
410
- r#trait,
411
- path,
412
- } ,
413
- }
414
- }
444
+ Some ( candidate) => candidate. into_impl_expr ( tcx) ,
415
445
None => {
416
446
let msg = format ! (
417
447
"Could not find a clause for `{tref:?}` in the item parameters"
@@ -424,9 +454,8 @@ impl<'tcx> PredicateSearcher<'tcx> {
424
454
Ok ( ImplSource :: Builtin ( BuiltinImplSource :: Object { .. } , _) ) => ImplExprAtom :: Dyn ,
425
455
Ok ( ImplSource :: Builtin ( _, _) ) => {
426
456
// Resolve the predicates implied by the trait.
427
- let trait_def_id = erased_tref. skip_binder ( ) . def_id ;
428
457
// If we wanted to not skip this binder, we'd have to instantiate the bound
429
- // regions, solve, then wrap the result in a binder. And track higher-kinded
458
+ // regions, solve, then wrap the result in a binder. And track higher-kinded
430
459
// clauses better all over.
431
460
let impl_exprs = self . resolve_item_implied_predicates (
432
461
trait_def_id,
@@ -463,9 +492,106 @@ impl<'tcx> PredicateSearcher<'tcx> {
463
492
types,
464
493
}
465
494
}
495
+ // Resolve `Drop` trait impls by adding virtual impls when a real one can't be found.
496
+ Err ( CodegenObligationError :: Unimplemented )
497
+ if erased_tref. skip_binder ( ) . def_id == drop_trait =>
498
+ {
499
+ // If we wanted to not skip this binder, we'd have to instantiate the bound
500
+ // regions, solve, then wrap the result in a binder. And track higher-kinded
501
+ // clauses better all over.
502
+ let mut resolve_drop = |ty : Ty < ' tcx > | {
503
+ let tref = ty:: Binder :: dummy ( ty:: TraitRef :: new ( tcx, drop_trait, [ ty] ) ) ;
504
+ self . resolve ( & tref, warn)
505
+ } ;
506
+ let find_drop_impl = |ty : Ty < ' tcx > | {
507
+ let mut dtor = None ;
508
+ tcx. for_each_relevant_impl ( drop_trait, ty, |impl_did| {
509
+ dtor = Some ( impl_did) ;
510
+ } ) ;
511
+ dtor
512
+ } ;
513
+ // TODO: how to check if there is a real drop impl?????
514
+ let ty = erased_tref. skip_binder ( ) . args [ 0 ] . as_type ( ) . unwrap ( ) ;
515
+ // Source of truth are `ty::needs_drop_components` and `tcx.needs_drop_raw`.
516
+ match ty. kind ( ) {
517
+ // TODO: Does `UnsafeBinder` drop its contents?
518
+ ty:: Bool
519
+ | ty:: Char
520
+ | ty:: Int ( ..)
521
+ | ty:: Uint ( ..)
522
+ | ty:: Float ( ..)
523
+ | ty:: Foreign ( ..)
524
+ | ty:: Str
525
+ | ty:: RawPtr ( ..)
526
+ | ty:: Ref ( ..)
527
+ | ty:: FnDef ( ..)
528
+ | ty:: FnPtr ( ..)
529
+ | ty:: UnsafeBinder ( ..)
530
+ | ty:: Never => ImplExprAtom :: Drop ( DropData :: Noop ) ,
531
+ ty:: Array ( inner_ty, _) | ty:: Pat ( inner_ty, _) | ty:: Slice ( inner_ty) => {
532
+ ImplExprAtom :: Drop ( DropData :: Glue {
533
+ ty,
534
+ impl_exprs : vec ! [ resolve_drop( * inner_ty) ?] ,
535
+ } )
536
+ }
537
+ ty:: Tuple ( tys) => ImplExprAtom :: Drop ( DropData :: Glue {
538
+ ty,
539
+ impl_exprs : tys. iter ( ) . map ( resolve_drop) . try_collect ( ) ?,
540
+ } ) ,
541
+ ty:: Adt ( ..) if let Some ( _) = find_drop_impl ( ty) => {
542
+ // We should have been able to resolve the `T: Drop` clause above, if we
543
+ // get here we don't know how to reconstruct the arguments to the impl.
544
+ let msg = format ! ( "Cannot resolve clause `{tref:?}`" ) ;
545
+ warn ( & msg) ;
546
+ ImplExprAtom :: Error ( msg)
547
+ }
548
+ ty:: Adt ( _, args)
549
+ | ty:: Closure ( _, args)
550
+ | ty:: Coroutine ( _, args)
551
+ | ty:: CoroutineClosure ( _, args)
552
+ | ty:: CoroutineWitness ( _, args) => ImplExprAtom :: Drop ( DropData :: Glue {
553
+ ty,
554
+ impl_exprs : args
555
+ . iter ( )
556
+ . filter_map ( |arg| arg. as_type ( ) )
557
+ . map ( resolve_drop)
558
+ . try_collect ( ) ?,
559
+ } ) ,
560
+ // Every `dyn` has a `Drop` in its vtable, ergo we pretend that every `dyn` has
561
+ // `Drop` in its list of traits.
562
+ ty:: Dynamic ( ..) => ImplExprAtom :: Dyn ,
563
+ ty:: Param ( ..) | ty:: Alias ( ..) | ty:: Bound ( ..) => {
564
+ if self . add_drop {
565
+ // We've added `Drop` impls on everything, we should be able to resolve
566
+ // it.
567
+ match self . resolve_local ( erased_tref. upcast ( self . tcx ) , warn) ? {
568
+ Some ( candidate) => candidate. into_impl_expr ( tcx) ,
569
+ None => {
570
+ let msg =
571
+ format ! ( "Cannot find virtual `Drop` clause: `{tref:?}`" ) ;
572
+ warn ( & msg) ;
573
+ ImplExprAtom :: Error ( msg)
574
+ }
575
+ }
576
+ } else {
577
+ ImplExprAtom :: Drop ( DropData :: Implicit )
578
+ }
579
+ }
580
+
581
+ ty:: Placeholder ( ..) | ty:: Infer ( ..) | ty:: Error ( ..) => {
582
+ let msg = format ! (
583
+ "Cannot resolve clause `{tref:?}` \
584
+ because of a type error"
585
+ ) ;
586
+ warn ( & msg) ;
587
+ ImplExprAtom :: Error ( msg)
588
+ }
589
+ }
590
+ }
466
591
Err ( e) => {
467
592
let msg = format ! (
468
- "Could not find a clause for `{tref:?}` in the current context: `{e:?}`"
593
+ "Could not find a clause for `{tref:?}` \
594
+ in the current context: `{e:?}`"
469
595
) ;
470
596
warn ( & msg) ;
471
597
ImplExprAtom :: Error ( msg)
0 commit comments