Skip to content

Commit 1da4efb

Browse files
committed
Resolve virtual Drop trait refs
1 parent 2b1fd4f commit 1da4efb

File tree

5 files changed

+188
-32
lines changed

5 files changed

+188
-32
lines changed

engine/lib/import_thir.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ end) : EXPR = struct
11471147
| Dyn -> Dyn
11481148
| SelfImpl { path; _ } -> List.fold ~init:Self ~f:browse_path path
11491149
| Builtin { trait; _ } -> Builtin (c_trait_ref span trait.value)
1150+
| Drop _ -> failwith @@ "impl_expr_atom: Drop"
11501151
| Error str -> failwith @@ "impl_expr_atom: Error " ^ str
11511152

11521153
and c_generic_value (span : Thir.span) (ty : Thir.generic_arg) : generic_value

frontend/exporter/src/traits.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ pub enum ImplExprAtom {
9393
/// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that
9494
/// built-in implementation.
9595
Dyn,
96+
/// A virtual `Drop` implementation.
97+
/// `Drop` doesn't work like a real trait but we want to pretend it does. If a type has a
98+
/// user-defined `impl Drop for X` we just use the `Concrete` variant, but if it doesn't we use
99+
/// this variant to supply the data needed to know what code will run on drop.
100+
Drop(DropData),
96101
/// A built-in trait whose implementation is computed by the compiler, such as `FnMut`. This
97102
/// morally points to an invisible `impl` block; as such it contains the information we may
98103
/// need from one.
@@ -109,6 +114,30 @@ pub enum ImplExprAtom {
109114
Error(String),
110115
}
111116

117+
#[derive(AdtInto)]
118+
#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::DropData<'tcx>, state: S as s)]
119+
#[derive_group(Serializers)]
120+
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
121+
pub enum DropData {
122+
/// A drop that does nothing, e.g. for scalars and pointers.
123+
Noop,
124+
/// An implicit `Drop` local clause, if the `resolve_drop_bounds` option is `false`. If that
125+
/// option is `true`, we'll add `Drop` bounds to every type param, and use that to resolve
126+
/// `Drop` impls of generics. If it's `false`, we use this variant to indicate that the drop
127+
/// clause comes from a generic or associated type.
128+
Implicit,
129+
/// The implicit `Drop` impl that exists for every type without an explicit `Drop` impl. The
130+
/// virtual impl is considered to have one `T: Drop` bound for each generic argument of the
131+
/// target type; it then simply drops each field in order.
132+
Glue {
133+
/// The type we're generating glue for.
134+
ty: Ty,
135+
/// The `ImplExpr`s for the `T: Drop` bounds of the virtual impl. There is one for each
136+
/// generic argument, in order.
137+
impl_exprs: Vec<ImplExpr>,
138+
},
139+
}
140+
112141
/// An `ImplExpr` describes the full data of a trait implementation. Because of generics, this may
113142
/// need to combine several concrete trait implementation items. For example, `((1u8, 2u8),
114143
/// "hello").clone()` combines the generic implementation of `Clone` for `(A, B)` with the

frontend/exporter/src/traits/resolution.rs

Lines changed: 146 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::collections::{hash_map::Entry, HashMap};
88
use rustc_hir::def::DefKind;
99
use rustc_hir::def_id::DefId;
1010
use rustc_middle::traits::CodegenObligationError;
11-
use rustc_middle::ty::*;
11+
use rustc_middle::ty::{self, *};
1212
use rustc_trait_selection::traits::ImplSource;
1313

1414
use crate::{self_predicate, traits::utils::erase_and_norm};
@@ -73,6 +73,11 @@ pub enum ImplExprAtom<'tcx> {
7373
/// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that
7474
/// built-in implementation.
7575
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>),
7681
/// A built-in trait whose implementation is computed by the compiler, such as `FnMut`. This
7782
/// morally points to an invisible `impl` block; as such it contains the information we may
7883
/// need from one.
@@ -89,6 +94,27 @@ pub enum ImplExprAtom<'tcx> {
8994
Error(String),
9095
}
9196

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+
92118
#[derive(Clone, Debug)]
93119
pub struct ImplExpr<'tcx> {
94120
/// The trait this is an impl for.
@@ -197,6 +223,22 @@ struct Candidate<'tcx> {
197223
origin: AnnotatedTraitPred<'tcx>,
198224
}
199225

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+
200242
/// Stores a set of predicates along with where they came from.
201243
pub struct PredicateSearcher<'tcx> {
202244
tcx: TyCtxt<'tcx>,
@@ -375,10 +417,12 @@ impl<'tcx> PredicateSearcher<'tcx> {
375417
use rustc_trait_selection::traits::{
376418
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData,
377419
};
420+
let tcx = self.tcx;
421+
let drop_trait = tcx.lang_items().drop_trait().unwrap();
378422

379423
let erased_tref = erase_and_norm(self.tcx, self.typing_env, *tref);
424+
let trait_def_id = erased_tref.skip_binder().def_id;
380425

381-
let tcx = self.tcx;
382426
let impl_source = shallow_resolve_trait_ref(tcx, self.typing_env.param_env, erased_tref);
383427
let atom = match impl_source {
384428
Ok(ImplSource::UserDefined(ImplSourceUserDefinedData {
@@ -397,21 +441,7 @@ impl<'tcx> PredicateSearcher<'tcx> {
397441
}
398442
Ok(ImplSource::Param(_)) => {
399443
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),
415445
None => {
416446
let msg = format!(
417447
"Could not find a clause for `{tref:?}` in the item parameters"
@@ -424,9 +454,8 @@ impl<'tcx> PredicateSearcher<'tcx> {
424454
Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn,
425455
Ok(ImplSource::Builtin(_, _)) => {
426456
// Resolve the predicates implied by the trait.
427-
let trait_def_id = erased_tref.skip_binder().def_id;
428457
// 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
430459
// clauses better all over.
431460
let impl_exprs = self.resolve_item_implied_predicates(
432461
trait_def_id,
@@ -463,9 +492,106 @@ impl<'tcx> PredicateSearcher<'tcx> {
463492
types,
464493
}
465494
}
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+
}
466591
Err(e) => {
467592
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:?}`"
469595
);
470596
warn(&msg);
471597
ImplExprAtom::Error(msg)

test-harness/src/snapshots/toolchain__attribute-opaque into-fstar.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class t_T (v_Self: Type0) = {
133133
val impl_T_for_u8:t_T u8
134134

135135
class t_TrGeneric (v_Self: Type0) (v_U: Type0) = {
136-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_11075708886900110455:Core.Clone.t_Clone v_U;
136+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_16006850527666200319:Core.Clone.t_Clone v_U;
137137
f_f_pre:v_U -> Type0;
138138
f_f_post:v_U -> v_Self -> Type0;
139139
f_f:x0: v_U -> Prims.Pure v_Self (f_f_pre x0) (fun result -> f_f_post x0 result)

test-harness/src/snapshots/toolchain__traits into-fstar.snap

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ open FStar.Mul
3535
class t_BlockSizeUser (v_Self: Type0) = { f_BlockSize:Type0 }
3636

3737
class t_ParBlocksSizeUser (v_Self: Type0) = {
38-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_12386035071644742916:t_BlockSizeUser v_Self
38+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_7386178880507589171:t_BlockSizeUser v_Self
3939
}
4040

4141
class t_BlockBackend (v_Self: Type0) = {
42-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_5078033630945970482:t_ParBlocksSizeUser v_Self;
42+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_5132789780856779344:t_ParBlocksSizeUser v_Self;
4343
f_proc_block_pre:Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global -> Type0;
4444
f_proc_block_post:Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global -> Prims.unit -> Type0;
4545
f_proc_block:x0: Alloc.Vec.t_Vec _ Alloc.Alloc.t_Global
@@ -55,7 +55,7 @@ open FStar.Mul
5555
class t_Bar (v_Self: Type0) (v_T: Type0) = { __marker_trait_t_Bar:Prims.unit }
5656

5757
class t_Foo (v_Self: Type0) = {
58-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_13709452385921529338:t_Bar v_Self f_U;
58+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_12633113900214769645:t_Bar v_Self f_U;
5959
f_U:Type0
6060
}
6161
'''
@@ -425,11 +425,11 @@ let associated_function_caller
425425
()
426426

427427
class t_SubTrait (v_Self: Type0) (v_TypeArg: Type0) (v_ConstArg: usize) = {
428-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_5670955395916535991:t_Trait v_Self
428+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_2013377997652678570:t_Trait v_Self
429429
v_TypeArg
430430
v_ConstArg;
431431
f_AssocType:Type0;
432-
f_AssocType_6891123870612467806:t_Trait f_AssocType v_TypeArg v_ConstArg
432+
f_AssocType_4339496849715937257:t_Trait f_AssocType v_TypeArg v_ConstArg
433433
}
434434
'''
435435
"Traits.Interlaced_consts_types.fst" = '''
@@ -506,11 +506,11 @@ open FStar.Mul
506506

507507
class t_Trait1 (v_Self: Type0) = {
508508
f_T:Type0;
509-
f_T_6736093233391770582:t_Trait1 f_T
509+
f_T_14544816729875926394:t_Trait1 f_T
510510
}
511511

512512
class t_Trait2 (v_Self: Type0) = {
513-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_15807083732906695011:t_Trait1 v_Self;
513+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_17908617371471168181:t_Trait1 v_Self;
514514
f_U:Type0
515515
}
516516
'''
@@ -567,7 +567,7 @@ open Core
567567
open FStar.Mul
568568

569569
class t_SuperTrait (v_Self: Type0) = {
570-
[@@@ FStar.Tactics.Typeclasses.no_method]_super_16027770981543256320:Core.Clone.t_Clone v_Self;
570+
[@@@ FStar.Tactics.Typeclasses.no_method]_super_12761901852309354934:Core.Clone.t_Clone v_Self;
571571
f_function_of_super_trait_pre:v_Self -> Type0;
572572
f_function_of_super_trait_post:v_Self -> u32 -> Type0;
573573
f_function_of_super_trait:x0: v_Self
@@ -579,7 +579,7 @@ class t_SuperTrait (v_Self: Type0) = {
579579
[@@ FStar.Tactics.Typeclasses.tcinstance]
580580
let impl: t_SuperTrait i32 =
581581
{
582-
_super_16027770981543256320 = FStar.Tactics.Typeclasses.solve;
582+
_super_12761901852309354934 = FStar.Tactics.Typeclasses.solve;
583583
f_function_of_super_trait_pre = (fun (self: i32) -> true);
584584
f_function_of_super_trait_post = (fun (self: i32) (out: u32) -> true);
585585
f_function_of_super_trait = fun (self: i32) -> cast (Core.Num.impl_i32__abs self <: i32) <: u32
@@ -651,7 +651,7 @@ let uuse_iimpl_trait (_: Prims.unit) : Prims.unit =
651651

652652
class t_Foo (v_Self: Type0) = {
653653
f_AssocType:Type0;
654-
f_AssocType_6638784903434849583:t_SuperTrait f_AssocType;
654+
f_AssocType_16421706098796818672:t_SuperTrait f_AssocType;
655655
f_N:usize;
656656
f_assoc_f_pre:Prims.unit -> Type0;
657657
f_assoc_f_post:Prims.unit -> Prims.unit -> Type0;
@@ -688,7 +688,7 @@ let g (#v_T: Type0) (#[FStar.Tactics.Typeclasses.tcresolve ()] i1: t_Foo v_T) (x
688688
let impl_Foo_for_tuple_: t_Foo Prims.unit =
689689
{
690690
f_AssocType = i32;
691-
f_AssocType_6638784903434849583 = FStar.Tactics.Typeclasses.solve;
691+
f_AssocType_16421706098796818672 = FStar.Tactics.Typeclasses.solve;
692692
f_N = mk_usize 32;
693693
f_assoc_f_pre = (fun (_: Prims.unit) -> true);
694694
f_assoc_f_post = (fun (_: Prims.unit) (out: Prims.unit) -> true);

0 commit comments

Comments
 (0)