1use chalk_ir::{
4 FloatTy, IntTy, Mutability, Scalar, TyVariableKind, TypeOutlives, UintTy, cast::Cast,
5};
6use hir_def::{
7 DefWithBodyId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
8 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
9 hir::generics::{TypeOrConstParamData, TypeParamProvenance},
10 lang_item::LangItem,
11 type_ref::Rawness,
12};
13
14use crate::{
15 AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
16 ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
17 QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags,
18 WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
19 from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
20};
21
22pub trait TyExt {
23 fn is_unit(&self) -> bool;
24 fn is_integral(&self) -> bool;
25 fn is_scalar(&self) -> bool;
26 fn is_floating_point(&self) -> bool;
27 fn is_never(&self) -> bool;
28 fn is_str(&self) -> bool;
29 fn is_unknown(&self) -> bool;
30 fn contains_unknown(&self) -> bool;
31 fn is_ty_var(&self) -> bool;
32 fn is_union(&self) -> bool;
33
34 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
35 fn as_builtin(&self) -> Option<BuiltinType>;
36 fn as_tuple(&self) -> Option<&Substitution>;
37 fn as_closure(&self) -> Option<ClosureId>;
38 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
39 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
40 fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)>;
41 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
42 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
43
44 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
45 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
46
47 fn strip_references(&self) -> &Ty;
48 fn strip_reference(&self) -> &Ty;
49
50 fn dyn_trait(&self) -> Option<TraitId>;
52
53 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
54 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
55 fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool;
56
57 fn equals_ctor(&self, other: &Ty) -> bool;
59}
60
61impl TyExt for Ty {
62 fn is_unit(&self) -> bool {
63 matches!(self.kind(Interner), TyKind::Tuple(0, _))
64 }
65
66 fn is_integral(&self) -> bool {
67 matches!(
68 self.kind(Interner),
69 TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
70 | TyKind::InferenceVar(_, TyVariableKind::Integer)
71 )
72 }
73
74 fn is_scalar(&self) -> bool {
75 matches!(self.kind(Interner), TyKind::Scalar(_))
76 }
77
78 fn is_floating_point(&self) -> bool {
79 matches!(
80 self.kind(Interner),
81 TyKind::Scalar(Scalar::Float(_)) | TyKind::InferenceVar(_, TyVariableKind::Float)
82 )
83 }
84
85 fn is_never(&self) -> bool {
86 matches!(self.kind(Interner), TyKind::Never)
87 }
88
89 fn is_str(&self) -> bool {
90 matches!(self.kind(Interner), TyKind::Str)
91 }
92
93 fn is_unknown(&self) -> bool {
94 matches!(self.kind(Interner), TyKind::Error)
95 }
96
97 fn contains_unknown(&self) -> bool {
98 self.data(Interner).flags.contains(TypeFlags::HAS_ERROR)
99 }
100
101 fn is_ty_var(&self) -> bool {
102 matches!(self.kind(Interner), TyKind::InferenceVar(_, _))
103 }
104
105 fn is_union(&self) -> bool {
106 matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_))))
107 }
108
109 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
110 match self.kind(Interner) {
111 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
112 _ => None,
113 }
114 }
115
116 fn as_builtin(&self) -> Option<BuiltinType> {
117 match self.kind(Interner) {
118 TyKind::Str => Some(BuiltinType::Str),
119 TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool),
120 TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char),
121 TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty {
122 FloatTy::F128 => BuiltinFloat::F128,
123 FloatTy::F64 => BuiltinFloat::F64,
124 FloatTy::F32 => BuiltinFloat::F32,
125 FloatTy::F16 => BuiltinFloat::F16,
126 })),
127 TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity {
128 IntTy::Isize => BuiltinInt::Isize,
129 IntTy::I8 => BuiltinInt::I8,
130 IntTy::I16 => BuiltinInt::I16,
131 IntTy::I32 => BuiltinInt::I32,
132 IntTy::I64 => BuiltinInt::I64,
133 IntTy::I128 => BuiltinInt::I128,
134 })),
135 TyKind::Scalar(Scalar::Uint(ity)) => Some(BuiltinType::Uint(match ity {
136 UintTy::Usize => BuiltinUint::Usize,
137 UintTy::U8 => BuiltinUint::U8,
138 UintTy::U16 => BuiltinUint::U16,
139 UintTy::U32 => BuiltinUint::U32,
140 UintTy::U64 => BuiltinUint::U64,
141 UintTy::U128 => BuiltinUint::U128,
142 })),
143 _ => None,
144 }
145 }
146
147 fn as_tuple(&self) -> Option<&Substitution> {
148 match self.kind(Interner) {
149 TyKind::Tuple(_, substs) => Some(substs),
150 _ => None,
151 }
152 }
153
154 fn as_closure(&self) -> Option<ClosureId> {
155 match self.kind(Interner) {
156 TyKind::Closure(id, _) => Some(*id),
157 _ => None,
158 }
159 }
160
161 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
162 match self.callable_def(db) {
163 Some(CallableDefId::FunctionId(func)) => Some(func),
164 Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None,
165 }
166 }
167
168 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
169 match self.kind(Interner) {
170 TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
171 _ => None,
172 }
173 }
174
175 fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)> {
176 match self.kind(Interner) {
177 TyKind::Raw(mutability, ty) => Some((ty, *mutability)),
178 _ => None,
179 }
180 }
181
182 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
183 match self.kind(Interner) {
184 TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
185 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
186 _ => None,
187 }
188 }
189
190 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
191 match *self.kind(Interner) {
192 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
193 TyKind::FnDef(callable, ..) => {
194 Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable)))
195 }
196 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
197 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
198 _ => None,
199 }
200 }
201
202 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
203 match self.kind(Interner) {
204 &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
205 _ => None,
206 }
207 }
208
209 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
210 match self.kind(Interner) {
211 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
212 TyKind::FnDef(def, parameters) => Some(CallableSig::from_def(db, *def, parameters)),
213 TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty().callable_sig(db),
214 _ => None,
215 }
216 }
217
218 fn dyn_trait(&self) -> Option<TraitId> {
219 let trait_ref = match self.kind(Interner) {
220 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().first().and_then(|b| {
225 match b.skip_binders() {
226 WhereClause::Implemented(trait_ref) => Some(trait_ref),
227 _ => None,
228 }
229 }),
230 _ => None,
231 }?;
232 Some(from_chalk_trait_id(trait_ref.trait_id))
233 }
234
235 fn strip_references(&self) -> &Ty {
236 let mut t: &Ty = self;
237 while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) {
238 t = ty;
239 }
240 t
241 }
242
243 fn strip_reference(&self) -> &Ty {
244 self.as_reference().map_or(self, |(ty, _, _)| ty)
245 }
246
247 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
248 match self.kind(Interner) {
249 TyKind::OpaqueType(opaque_ty_id, subst) => {
250 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
251 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
252 let krate = def.module(db).krate();
253 if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) {
254 let impl_bound = Binders::empty(
258 Interner,
259 WhereClause::Implemented(TraitRef {
260 trait_id: to_chalk_trait_id(future_trait),
261 substitution: Substitution::empty(Interner),
262 }),
263 );
264 Some(vec![impl_bound])
265 } else {
266 None
267 }
268 }
269 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
270 db.return_type_impl_traits(func).map(|it| {
271 let data =
272 (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
273 data.substitute(Interner, &subst).into_value_and_skipped_binders().0
274 })
275 }
276 ImplTraitId::TypeAliasImplTrait(alias, idx) => {
277 db.type_alias_impl_traits(alias).map(|it| {
278 let data =
279 (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
280 data.substitute(Interner, &subst).into_value_and_skipped_binders().0
281 })
282 }
283 }
284 }
285 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
286 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
287 {
288 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
289 db.return_type_impl_traits(func).map(|it| {
290 let data =
291 (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
292 data.substitute(Interner, &opaque_ty.substitution)
293 })
294 }
295 ImplTraitId::TypeAliasImplTrait(alias, idx) => {
296 db.type_alias_impl_traits(alias).map(|it| {
297 let data =
298 (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
299 data.substitute(Interner, &opaque_ty.substitution)
300 })
301 }
302 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
304 };
305
306 predicates.map(|it| it.into_value_and_skipped_binders().0)
307 }
308 TyKind::Placeholder(idx) => {
309 let id = from_placeholder_idx(db, *idx).0;
310 let generic_params = db.generic_params(id.parent);
311 let param_data = &generic_params[id.local_id];
312 match param_data {
313 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
314 TypeParamProvenance::ArgumentImplTrait => {
315 let substs = TyBuilder::placeholder_subst(db, id.parent);
316 let predicates = db
317 .generic_predicates(id.parent)
318 .iter()
319 .map(|pred| pred.clone().substitute(Interner, &substs))
320 .filter(|wc| match wc.skip_binders() {
321 WhereClause::Implemented(tr) => {
322 &tr.self_type_parameter(Interner) == self
323 }
324 WhereClause::AliasEq(AliasEq {
325 alias: AliasTy::Projection(proj),
326 ty: _,
327 }) => &proj.self_type_parameter(db) == self,
328 WhereClause::TypeOutlives(TypeOutlives { ty, lifetime: _ }) => {
329 ty == self
330 }
331 _ => false,
332 })
333 .collect::<Vec<_>>();
334
335 Some(predicates)
336 }
337 _ => None,
338 },
339 _ => None,
340 }
341 }
342 _ => None,
343 }
344 }
345
346 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
347 match self.kind(Interner) {
348 TyKind::AssociatedType(id, ..) => match from_assoc_type_id(*id).lookup(db).container {
349 ItemContainerId::TraitId(trait_id) => Some(trait_id),
350 _ => None,
351 },
352 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
353 match from_assoc_type_id(projection_ty.associated_ty_id).lookup(db).container {
354 ItemContainerId::TraitId(trait_id) => Some(trait_id),
355 _ => None,
356 }
357 }
358 _ => None,
359 }
360 }
361
362 fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool {
363 let crate_id = owner.module(db).krate();
364 let Some(copy_trait) = LangItem::Copy.resolve_trait(db, crate_id) else {
365 return false;
366 };
367 let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build();
368 let env = db.trait_environment_for_body(owner);
369 let goal = Canonical {
370 value: InEnvironment::new(&env.env, trait_ref.cast(Interner)),
371 binders: CanonicalVarKinds::empty(Interner),
372 };
373 !db.trait_solve(crate_id, None, goal).no_solution()
374 }
375
376 fn equals_ctor(&self, other: &Ty) -> bool {
377 match (self.kind(Interner), other.kind(Interner)) {
378 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
379 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
380 true
381 }
382 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
383 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
384 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
385 ty_id == ty_id2
386 }
387 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
388 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
389 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
390 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
391 mutability == mutability2
392 }
393 (
394 TyKind::Function(FnPointer { num_binders, sig, .. }),
395 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
396 ) => num_binders == num_binders2 && sig == sig2,
397 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
398 cardinality == cardinality2
399 }
400 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
401 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
402 _ => false,
403 }
404 }
405}
406
407pub trait ProjectionTyExt {
408 fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
409 fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
410 fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
411}
412
413impl ProjectionTyExt for ProjectionTy {
414 fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
415 let generics = generics(db, from_assoc_type_id(self.associated_ty_id).into());
417 let parent_len = generics.parent_generics().map_or(0, |g| g.len_self());
418 let substitution =
419 Substitution::from_iter(Interner, self.substitution.iter(Interner).take(parent_len));
420 TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
421 }
422
423 fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
424 match from_assoc_type_id(self.associated_ty_id).lookup(db).container {
425 ItemContainerId::TraitId(it) => it,
426 _ => panic!("projection ty without parent trait"),
427 }
428 }
429
430 fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
431 self.trait_ref(db).self_type_parameter(Interner)
432 }
433}
434
435pub trait DynTyExt {
436 fn principal(&self) -> Option<Binders<Binders<&TraitRef>>>;
437 fn principal_id(&self) -> Option<chalk_ir::TraitId<Interner>>;
438}
439
440impl DynTyExt for DynTy {
441 fn principal(&self) -> Option<Binders<Binders<&TraitRef>>> {
442 self.bounds.as_ref().filter_map(|bounds| {
443 bounds.interned().first().and_then(|b| {
444 b.as_ref().filter_map(|b| match b {
445 crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
446 _ => None,
447 })
448 })
449 })
450 }
451
452 fn principal_id(&self) -> Option<chalk_ir::TraitId<Interner>> {
453 self.bounds.skip_binders().interned().first().and_then(|b| match b.skip_binders() {
454 crate::WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id),
455 _ => None,
456 })
457 }
458}
459
460pub trait TraitRefExt {
461 fn hir_trait_id(&self) -> TraitId;
462}
463
464impl TraitRefExt for TraitRef {
465 fn hir_trait_id(&self) -> TraitId {
466 from_chalk_trait_id(self.trait_id)
467 }
468}