1 use rustc_hash
::FxHashSet
;
3 use super::{builder::ClauseBuilder, generalize}
;
4 use crate::RustIrDatabase
;
6 cast
::Cast
, fold
::shift
::Shift
, interner
::Interner
, Binders
, BoundVar
, DebruijnIndex
, TraitId
,
7 TraitRef
, Ty
, TyKind
, WhereClause
,
10 /// If the self type `S` of an `Implemented` goal is a `dyn trait` type, we wish
11 /// to generate program-clauses that indicates that it implements its own
12 /// traits. For example, a `dyn Write` type implements `Write` and so on.
14 /// To see how this works, consider as an example the type `dyn Fn(&u8)`. This
15 /// is really shorthand for `dyn for<'a> Fn<(&'a u8), Output = ()>`, and we
16 /// represent that type as something like this:
20 /// forall<'a> { Implemented(T: Fn<'a>) },
21 /// forall<'a> { AliasEq(<T as Fn<'a>>::Output, ()) },
25 /// so what we will do is to generate one program clause for each of the
26 /// conditions. Thus we get two program clauses:
29 /// forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) }
35 /// forall<'a> { AliasEq(<dyn Fn(&u8) as Fn<'a>>::Output, ()) },
37 pub(super) fn build_dyn_self_ty_clauses
<I
: Interner
>(
38 db
: &dyn RustIrDatabase
<I
>,
39 builder
: &mut ClauseBuilder
<'_
, I
>,
42 let interner
= db
.interner();
43 let dyn_ty
= match self_ty
.kind(interner
) {
44 TyKind
::Dyn(dyn_ty
) => dyn_ty
.clone(),
47 let generalized_dyn_ty
= generalize
::Generalize
::apply(db
.interner(), dyn_ty
);
49 // Here, `self_ty` is the `dyn Fn(&u8)`, and `dyn_ty` is the `exists<T> { ..
50 // }` clauses shown above.
52 // Turn free BoundVars in the type into new existentials. E.g.
53 // we might get some `dyn Foo<?X>`, and we don't want to return
54 // a clause with a free variable. We can instead return a
55 // slightly more general clause by basically turning this into
56 // `exists<A> dyn Foo<A>`.
58 builder
.push_binders(generalized_dyn_ty
, |builder
, dyn_ty
| {
59 for exists_qwc
in dyn_ty
.bounds
.map_ref(|r
| r
.iter(interner
)) {
60 // Replace the `T` from `exists<T> { .. }` with `self_ty`,
61 // yielding clases like
64 // forall<'a> { Implemented(dyn Fn(&u8): Fn<(&'a u8)>) }
68 .substitute(interner
, &[self_ty
.clone().cast(interner
)]);
70 builder
.push_binders(qwc
, |builder
, wc
| match &wc
{
71 // For the implemented traits, we need to elaborate super traits and add where clauses from the trait
72 WhereClause
::Implemented(trait_ref
) => {
73 push_dyn_ty_impl_clauses(db
, builder
, trait_ref
.clone())
75 // Associated item bindings are just taken as facts (?)
76 WhereClause
::AliasEq(_
) => builder
.push_fact(wc
),
77 WhereClause
::LifetimeOutlives(..) => {}
78 WhereClause
::TypeOutlives(..) => {}
84 /// Generate `Implemented` clauses for a `dyn Trait` type. We need to generate
85 /// `Implemented` clauses for all super traits, and for each trait we require
86 /// its where clauses. (See #203.)
87 fn push_dyn_ty_impl_clauses
<I
: Interner
>(
88 db
: &dyn RustIrDatabase
<I
>,
89 builder
: &mut ClauseBuilder
<'_
, I
>,
90 trait_ref
: TraitRef
<I
>,
92 let interner
= db
.interner();
93 // We have some `dyn Trait`, and some `trait SuperTrait: WC`
94 // which is a super trait of `Trait` (including actually
95 // just being the same trait); then we want to push
96 // `Implemented(dyn Trait: SuperTrait) :- WC`.
98 let super_trait_refs
=
99 super_traits(db
, trait_ref
.trait_id
).substitute(interner
, &trait_ref
.substitution
);
101 for q_super_trait_ref
in super_trait_refs
{
102 builder
.push_binders(q_super_trait_ref
.clone(), |builder
, super_trait_ref
| {
103 let trait_datum
= db
.trait_datum(super_trait_ref
.trait_id
);
107 .substitute(interner
, &super_trait_ref
.substitution
);
108 builder
.push_clause(super_trait_ref
, wc
);
113 pub fn super_traits
<I
: Interner
>(
114 db
: &dyn RustIrDatabase
<I
>,
115 trait_id
: TraitId
<I
>,
116 ) -> Binders
<Vec
<Binders
<TraitRef
<I
>>>> {
117 let interner
= db
.interner();
118 let mut seen_traits
= FxHashSet
::default();
119 let trait_datum
= db
.trait_datum(trait_id
);
120 let trait_ref
= Binders
::empty(
124 substitution
: trait_datum
126 .identity_substitution(interner
)
127 .shifted_in(interner
),
130 let mut trait_refs
= Vec
::new();
131 go(db
, trait_ref
, &mut seen_traits
, &mut trait_refs
);
134 db
: &dyn RustIrDatabase
<I
>,
135 trait_ref
: Binders
<TraitRef
<I
>>,
136 seen_traits
: &mut FxHashSet
<TraitId
<I
>>,
137 trait_refs
: &mut Vec
<Binders
<TraitRef
<I
>>>,
139 let interner
= db
.interner();
140 let trait_id
= trait_ref
.skip_binders().trait_id
;
142 if !seen_traits
.insert(trait_id
) {
145 trait_refs
.push(trait_ref
.clone());
146 let trait_datum
= db
.trait_datum(trait_id
);
147 let super_trait_refs
= trait_datum
153 qwc
.as_ref().filter_map(|wc
| match wc
{
154 WhereClause
::Implemented(tr
) => {
155 let self_ty
= tr
.self_type_parameter(db
.interner());
157 // We're looking for where clauses
158 // of the form `Self: Trait`. That's
159 // ^1.0 because we're one binder in.
160 if self_ty
.bound_var(db
.interner())
161 != Some(BoundVar
::new(DebruijnIndex
::ONE
, 0))
167 WhereClause
::AliasEq(_
) => None
,
168 WhereClause
::LifetimeOutlives(..) => None
,
169 WhereClause
::TypeOutlives(..) => None
,
174 // we skip binders on the trait_ref here and add them to the binders
175 // on the trait ref in the loop below. We could probably avoid this if
176 // we could turn the `Binders<Vec<>>` into a `Vec<Binders<>>` easily.
177 .substitute(db
.interner(), &trait_ref
.skip_binders().substitution
);
178 for q_super_trait_ref
in super_trait_refs
{
179 // So now we need to combine the binders of trait_ref with the
180 // binders of super_trait_ref.
181 let actual_binders
= Binders
::new(trait_ref
.binders
.clone(), q_super_trait_ref
);
182 let q_super_trait_ref
= actual_binders
.fuse_binders(interner
);
183 go(db
, q_super_trait_ref
, seen_traits
, trait_refs
);
185 seen_traits
.remove(&trait_id
);
188 Binders
::new(trait_datum
.binders
.binders
.clone(), trait_refs
)