diff options
Diffstat (limited to 'crates/hir_ty/src/chalk_ext.rs')
-rw-r--r-- | crates/hir_ty/src/chalk_ext.rs | 229 |
1 files changed, 226 insertions, 3 deletions
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs index 0f4cb43e9..8e8a1aa48 100644 --- a/crates/hir_ty/src/chalk_ext.rs +++ b/crates/hir_ty/src/chalk_ext.rs | |||
@@ -1,20 +1,243 @@ | |||
1 | //! Various extensions traits for Chalk types. | 1 | //! Various extensions traits for Chalk types. |
2 | 2 | ||
3 | use hir_def::{AssocContainerId, Lookup, TraitId}; | 3 | use chalk_ir::Mutability; |
4 | use hir_def::{ | ||
5 | type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId, | ||
6 | }; | ||
4 | 7 | ||
5 | use crate::{ | 8 | use crate::{ |
6 | db::HirDatabase, from_assoc_type_id, to_chalk_trait_id, Interner, ProjectionTy, TraitRef, Ty, | 9 | db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, |
7 | TyKind, | 10 | from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId, |
11 | CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, | ||
12 | Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause, | ||
8 | }; | 13 | }; |
9 | 14 | ||
10 | pub trait TyExt { | 15 | pub trait TyExt { |
11 | fn is_unit(&self) -> bool; | 16 | fn is_unit(&self) -> bool; |
17 | fn is_never(&self) -> bool; | ||
18 | fn is_unknown(&self) -> bool; | ||
19 | |||
20 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; | ||
21 | fn as_tuple(&self) -> Option<&Substitution>; | ||
22 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>; | ||
23 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; | ||
24 | fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>; | ||
25 | fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>; | ||
26 | |||
27 | fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>; | ||
28 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>; | ||
29 | |||
30 | fn strip_references(&self) -> &Ty; | ||
31 | |||
32 | /// If this is a `dyn Trait`, returns that trait. | ||
33 | fn dyn_trait(&self) -> Option<TraitId>; | ||
34 | |||
35 | fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>; | ||
36 | fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>; | ||
12 | } | 37 | } |
13 | 38 | ||
14 | impl TyExt for Ty { | 39 | impl TyExt for Ty { |
15 | fn is_unit(&self) -> bool { | 40 | fn is_unit(&self) -> bool { |
16 | matches!(self.kind(&Interner), TyKind::Tuple(0, _)) | 41 | matches!(self.kind(&Interner), TyKind::Tuple(0, _)) |
17 | } | 42 | } |
43 | |||
44 | fn is_never(&self) -> bool { | ||
45 | matches!(self.kind(&Interner), TyKind::Never) | ||
46 | } | ||
47 | |||
48 | fn is_unknown(&self) -> bool { | ||
49 | matches!(self.kind(&Interner), TyKind::Error) | ||
50 | } | ||
51 | |||
52 | fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { | ||
53 | match self.kind(&Interner) { | ||
54 | TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), | ||
55 | _ => None, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | fn as_tuple(&self) -> Option<&Substitution> { | ||
60 | match self.kind(&Interner) { | ||
61 | TyKind::Tuple(_, substs) => Some(substs), | ||
62 | _ => None, | ||
63 | } | ||
64 | } | ||
65 | |||
66 | fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> { | ||
67 | if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) { | ||
68 | Some(func) | ||
69 | } else { | ||
70 | None | ||
71 | } | ||
72 | } | ||
73 | fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { | ||
74 | match self.kind(&Interner) { | ||
75 | TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)), | ||
76 | _ => None, | ||
77 | } | ||
78 | } | ||
79 | |||
80 | fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { | ||
81 | match self.kind(&Interner) { | ||
82 | TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)), | ||
83 | TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)), | ||
84 | _ => None, | ||
85 | } | ||
86 | } | ||
87 | |||
88 | fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { | ||
89 | match *self.kind(&Interner) { | ||
90 | TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), | ||
91 | TyKind::FnDef(callable, ..) => { | ||
92 | Some(db.lookup_intern_callable_def(callable.into()).into()) | ||
93 | } | ||
94 | TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), | ||
95 | TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), | ||
96 | _ => None, | ||
97 | } | ||
98 | } | ||
99 | |||
100 | fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> { | ||
101 | match self.kind(&Interner) { | ||
102 | &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())), | ||
103 | _ => None, | ||
104 | } | ||
105 | } | ||
106 | |||
107 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> { | ||
108 | match self.kind(&Interner) { | ||
109 | TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)), | ||
110 | TyKind::FnDef(def, parameters) => { | ||
111 | let callable_def = db.lookup_intern_callable_def((*def).into()); | ||
112 | let sig = db.callable_item_signature(callable_def); | ||
113 | Some(sig.substitute(&Interner, ¶meters)) | ||
114 | } | ||
115 | TyKind::Closure(.., substs) => { | ||
116 | let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner); | ||
117 | sig_param.callable_sig(db) | ||
118 | } | ||
119 | _ => None, | ||
120 | } | ||
121 | } | ||
122 | |||
123 | fn dyn_trait(&self) -> Option<TraitId> { | ||
124 | let trait_ref = match self.kind(&Interner) { | ||
125 | TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { | ||
126 | match b.skip_binders() { | ||
127 | WhereClause::Implemented(trait_ref) => Some(trait_ref), | ||
128 | _ => None, | ||
129 | } | ||
130 | }), | ||
131 | _ => None, | ||
132 | }?; | ||
133 | Some(from_chalk_trait_id(trait_ref.trait_id)) | ||
134 | } | ||
135 | |||
136 | fn strip_references(&self) -> &Ty { | ||
137 | let mut t: &Ty = self; | ||
138 | while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) { | ||
139 | t = ty; | ||
140 | } | ||
141 | t | ||
142 | } | ||
143 | |||
144 | fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> { | ||
145 | match self.kind(&Interner) { | ||
146 | TyKind::OpaqueType(opaque_ty_id, ..) => { | ||
147 | match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { | ||
148 | ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { | ||
149 | let krate = def.module(db.upcast()).krate(); | ||
150 | if let Some(future_trait) = db | ||
151 | .lang_item(krate, "future_trait".into()) | ||
152 | .and_then(|item| item.as_trait()) | ||
153 | { | ||
154 | // This is only used by type walking. | ||
155 | // Parameters will be walked outside, and projection predicate is not used. | ||
156 | // So just provide the Future trait. | ||
157 | let impl_bound = Binders::empty( | ||
158 | &Interner, | ||
159 | WhereClause::Implemented(TraitRef { | ||
160 | trait_id: to_chalk_trait_id(future_trait), | ||
161 | substitution: Substitution::empty(&Interner), | ||
162 | }), | ||
163 | ); | ||
164 | Some(vec![impl_bound]) | ||
165 | } else { | ||
166 | None | ||
167 | } | ||
168 | } | ||
169 | ImplTraitId::ReturnTypeImplTrait(..) => None, | ||
170 | } | ||
171 | } | ||
172 | TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { | ||
173 | let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into()) | ||
174 | { | ||
175 | ImplTraitId::ReturnTypeImplTrait(func, idx) => { | ||
176 | db.return_type_impl_traits(func).map(|it| { | ||
177 | let data = (*it) | ||
178 | .as_ref() | ||
179 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
180 | data.substitute(&Interner, &opaque_ty.substitution) | ||
181 | }) | ||
182 | } | ||
183 | // It always has an parameter for Future::Output type. | ||
184 | ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(), | ||
185 | }; | ||
186 | |||
187 | predicates.map(|it| it.into_value_and_skipped_binders().0) | ||
188 | } | ||
189 | TyKind::Placeholder(idx) => { | ||
190 | let id = from_placeholder_idx(db, *idx); | ||
191 | let generic_params = db.generic_params(id.parent); | ||
192 | let param_data = &generic_params.types[id.local_id]; | ||
193 | match param_data.provenance { | ||
194 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | ||
195 | let substs = TyBuilder::type_params_subst(db, id.parent); | ||
196 | let predicates = db | ||
197 | .generic_predicates(id.parent) | ||
198 | .into_iter() | ||
199 | .map(|pred| pred.clone().substitute(&Interner, &substs)) | ||
200 | .filter(|wc| match &wc.skip_binders() { | ||
201 | WhereClause::Implemented(tr) => { | ||
202 | tr.self_type_parameter(&Interner) == self | ||
203 | } | ||
204 | WhereClause::AliasEq(AliasEq { | ||
205 | alias: AliasTy::Projection(proj), | ||
206 | ty: _, | ||
207 | }) => proj.self_type_parameter(&Interner) == self, | ||
208 | _ => false, | ||
209 | }) | ||
210 | .collect::<Vec<_>>(); | ||
211 | |||
212 | Some(predicates) | ||
213 | } | ||
214 | _ => None, | ||
215 | } | ||
216 | } | ||
217 | _ => None, | ||
218 | } | ||
219 | } | ||
220 | |||
221 | fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> { | ||
222 | match self.kind(&Interner) { | ||
223 | TyKind::AssociatedType(id, ..) => { | ||
224 | match from_assoc_type_id(*id).lookup(db.upcast()).container { | ||
225 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
226 | _ => None, | ||
227 | } | ||
228 | } | ||
229 | TyKind::Alias(AliasTy::Projection(projection_ty)) => { | ||
230 | match from_assoc_type_id(projection_ty.associated_ty_id) | ||
231 | .lookup(db.upcast()) | ||
232 | .container | ||
233 | { | ||
234 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
235 | _ => None, | ||
236 | } | ||
237 | } | ||
238 | _ => None, | ||
239 | } | ||
240 | } | ||
18 | } | 241 | } |
19 | 242 | ||
20 | pub trait ProjectionTyExt { | 243 | pub trait ProjectionTyExt { |