1 //! Various extensions traits for Chalk types.
3 use chalk_ir
::{FloatTy, IntTy, Mutability, Scalar, UintTy}
;
5 builtin_type
::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint}
,
6 generics
::TypeOrConstParamData
,
8 FunctionId
, GenericDefId
, HasModule
, ItemContainerId
, Lookup
, TraitId
,
13 db
::HirDatabase
, from_assoc_type_id
, from_chalk_trait_id
, from_foreign_def_id
,
14 from_placeholder_idx
, to_chalk_trait_id
, utils
::generics
, AdtId
, AliasEq
, AliasTy
, Binders
,
15 CallableDefId
, CallableSig
, FnPointer
, ImplTraitId
, Interner
, Lifetime
, ProjectionTy
,
16 QuantifiedWhereClause
, Substitution
, TraitRef
, Ty
, TyBuilder
, TyKind
, WhereClause
,
20 fn is_unit(&self) -> bool
;
21 fn is_never(&self) -> bool
;
22 fn is_unknown(&self) -> bool
;
23 fn is_ty_var(&self) -> bool
;
25 fn as_adt(&self) -> Option
<(hir_def
::AdtId
, &Substitution
)>;
26 fn as_builtin(&self) -> Option
<BuiltinType
>;
27 fn as_tuple(&self) -> Option
<&Substitution
>;
28 fn as_fn_def(&self, db
: &dyn HirDatabase
) -> Option
<FunctionId
>;
29 fn as_reference(&self) -> Option
<(&Ty
, Lifetime
, Mutability
)>;
30 fn as_reference_or_ptr(&self) -> Option
<(&Ty
, Rawness
, Mutability
)>;
31 fn as_generic_def(&self, db
: &dyn HirDatabase
) -> Option
<GenericDefId
>;
33 fn callable_def(&self, db
: &dyn HirDatabase
) -> Option
<CallableDefId
>;
34 fn callable_sig(&self, db
: &dyn HirDatabase
) -> Option
<CallableSig
>;
36 fn strip_references(&self) -> &Ty
;
37 fn strip_reference(&self) -> &Ty
;
39 /// If this is a `dyn Trait`, returns that trait.
40 fn dyn_trait(&self) -> Option
<TraitId
>;
42 fn impl_trait_bounds(&self, db
: &dyn HirDatabase
) -> Option
<Vec
<QuantifiedWhereClause
>>;
43 fn associated_type_parent_trait(&self, db
: &dyn HirDatabase
) -> Option
<TraitId
>;
45 /// FIXME: Get rid of this, it's not a good abstraction
46 fn equals_ctor(&self, other
: &Ty
) -> bool
;
50 fn is_unit(&self) -> bool
{
51 matches
!(self.kind(Interner
), TyKind
::Tuple(0, _
))
54 fn is_never(&self) -> bool
{
55 matches
!(self.kind(Interner
), TyKind
::Never
)
58 fn is_unknown(&self) -> bool
{
59 matches
!(self.kind(Interner
), TyKind
::Error
)
62 fn is_ty_var(&self) -> bool
{
63 matches
!(self.kind(Interner
), TyKind
::InferenceVar(_
, _
))
66 fn as_adt(&self) -> Option
<(hir_def
::AdtId
, &Substitution
)> {
67 match self.kind(Interner
) {
68 TyKind
::Adt(AdtId(adt
), parameters
) => Some((*adt
, parameters
)),
73 fn as_builtin(&self) -> Option
<BuiltinType
> {
74 match self.kind(Interner
) {
75 TyKind
::Str
=> Some(BuiltinType
::Str
),
76 TyKind
::Scalar(Scalar
::Bool
) => Some(BuiltinType
::Bool
),
77 TyKind
::Scalar(Scalar
::Char
) => Some(BuiltinType
::Char
),
78 TyKind
::Scalar(Scalar
::Float(fty
)) => Some(BuiltinType
::Float(match fty
{
79 FloatTy
::F64
=> BuiltinFloat
::F64
,
80 FloatTy
::F32
=> BuiltinFloat
::F32
,
82 TyKind
::Scalar(Scalar
::Int(ity
)) => Some(BuiltinType
::Int(match ity
{
83 IntTy
::Isize
=> BuiltinInt
::Isize
,
84 IntTy
::I8
=> BuiltinInt
::I8
,
85 IntTy
::I16
=> BuiltinInt
::I16
,
86 IntTy
::I32
=> BuiltinInt
::I32
,
87 IntTy
::I64
=> BuiltinInt
::I64
,
88 IntTy
::I128
=> BuiltinInt
::I128
,
90 TyKind
::Scalar(Scalar
::Uint(ity
)) => Some(BuiltinType
::Uint(match ity
{
91 UintTy
::Usize
=> BuiltinUint
::Usize
,
92 UintTy
::U8
=> BuiltinUint
::U8
,
93 UintTy
::U16
=> BuiltinUint
::U16
,
94 UintTy
::U32
=> BuiltinUint
::U32
,
95 UintTy
::U64
=> BuiltinUint
::U64
,
96 UintTy
::U128
=> BuiltinUint
::U128
,
102 fn as_tuple(&self) -> Option
<&Substitution
> {
103 match self.kind(Interner
) {
104 TyKind
::Tuple(_
, substs
) => Some(substs
),
109 fn as_fn_def(&self, db
: &dyn HirDatabase
) -> Option
<FunctionId
> {
110 match self.callable_def(db
) {
111 Some(CallableDefId
::FunctionId(func
)) => Some(func
),
112 Some(CallableDefId
::StructId(_
) | CallableDefId
::EnumVariantId(_
)) | None
=> None
,
115 fn as_reference(&self) -> Option
<(&Ty
, Lifetime
, Mutability
)> {
116 match self.kind(Interner
) {
117 TyKind
::Ref(mutability
, lifetime
, ty
) => Some((ty
, lifetime
.clone(), *mutability
)),
122 fn as_reference_or_ptr(&self) -> Option
<(&Ty
, Rawness
, Mutability
)> {
123 match self.kind(Interner
) {
124 TyKind
::Ref(mutability
, _
, ty
) => Some((ty
, Rawness
::Ref
, *mutability
)),
125 TyKind
::Raw(mutability
, ty
) => Some((ty
, Rawness
::RawPtr
, *mutability
)),
130 fn as_generic_def(&self, db
: &dyn HirDatabase
) -> Option
<GenericDefId
> {
131 match *self.kind(Interner
) {
132 TyKind
::Adt(AdtId(adt
), ..) => Some(adt
.into()),
133 TyKind
::FnDef(callable
, ..) => {
134 Some(db
.lookup_intern_callable_def(callable
.into()).into())
136 TyKind
::AssociatedType(type_alias
, ..) => Some(from_assoc_type_id(type_alias
).into()),
137 TyKind
::Foreign(type_alias
, ..) => Some(from_foreign_def_id(type_alias
).into()),
142 fn callable_def(&self, db
: &dyn HirDatabase
) -> Option
<CallableDefId
> {
143 match self.kind(Interner
) {
144 &TyKind
::FnDef(def
, ..) => Some(db
.lookup_intern_callable_def(def
.into())),
149 fn callable_sig(&self, db
: &dyn HirDatabase
) -> Option
<CallableSig
> {
150 match self.kind(Interner
) {
151 TyKind
::Function(fn_ptr
) => Some(CallableSig
::from_fn_ptr(fn_ptr
)),
152 TyKind
::FnDef(def
, parameters
) => {
153 let callable_def
= db
.lookup_intern_callable_def((*def
).into());
154 let sig
= db
.callable_item_signature(callable_def
);
155 Some(sig
.substitute(Interner
, parameters
))
157 TyKind
::Closure(.., substs
) => {
158 let sig_param
= substs
.at(Interner
, 0).assert_ty_ref(Interner
);
159 sig_param
.callable_sig(db
)
165 fn dyn_trait(&self) -> Option
<TraitId
> {
166 let trait_ref
= match self.kind(Interner
) {
167 // The principal trait bound should be the first element of the bounds. This is an
168 // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
169 // FIXME: dyn types may not have principal trait and we don't want to return auto trait
171 TyKind
::Dyn(dyn_ty
) => dyn_ty
.bounds
.skip_binders().interned().get(0).and_then(|b
| {
172 match b
.skip_binders() {
173 WhereClause
::Implemented(trait_ref
) => Some(trait_ref
),
179 Some(from_chalk_trait_id(trait_ref
.trait_id
))
182 fn strip_references(&self) -> &Ty
{
183 let mut t
: &Ty
= self;
184 while let TyKind
::Ref(_mutability
, _lifetime
, ty
) = t
.kind(Interner
) {
190 fn strip_reference(&self) -> &Ty
{
191 self.as_reference().map_or(self, |(ty
, _
, _
)| ty
)
194 fn impl_trait_bounds(&self, db
: &dyn HirDatabase
) -> Option
<Vec
<QuantifiedWhereClause
>> {
195 match self.kind(Interner
) {
196 TyKind
::OpaqueType(opaque_ty_id
, subst
) => {
197 match db
.lookup_intern_impl_trait_id((*opaque_ty_id
).into()) {
198 ImplTraitId
::AsyncBlockTypeImplTrait(def
, _expr
) => {
199 let krate
= def
.module(db
.upcast()).krate();
200 if let Some(future_trait
) = db
201 .lang_item(krate
, SmolStr
::new_inline("future_trait"))
202 .and_then(|item
| item
.as_trait())
204 // This is only used by type walking.
205 // Parameters will be walked outside, and projection predicate is not used.
206 // So just provide the Future trait.
207 let impl_bound
= Binders
::empty(
209 WhereClause
::Implemented(TraitRef
{
210 trait_id
: to_chalk_trait_id(future_trait
),
211 substitution
: Substitution
::empty(Interner
),
214 Some(vec
![impl_bound
])
219 ImplTraitId
::ReturnTypeImplTrait(func
, idx
) => {
220 db
.return_type_impl_traits(func
).map(|it
| {
223 .map(|rpit
| rpit
.impl_traits
[idx
as usize].bounds
.clone());
224 data
.substitute(Interner
, &subst
).into_value_and_skipped_binders().0
229 TyKind
::Alias(AliasTy
::Opaque(opaque_ty
)) => {
230 let predicates
= match db
.lookup_intern_impl_trait_id(opaque_ty
.opaque_ty_id
.into())
232 ImplTraitId
::ReturnTypeImplTrait(func
, idx
) => {
233 db
.return_type_impl_traits(func
).map(|it
| {
236 .map(|rpit
| rpit
.impl_traits
[idx
as usize].bounds
.clone());
237 data
.substitute(Interner
, &opaque_ty
.substitution
)
240 // It always has an parameter for Future::Output type.
241 ImplTraitId
::AsyncBlockTypeImplTrait(..) => unreachable
!(),
244 predicates
.map(|it
| it
.into_value_and_skipped_binders().0)
246 TyKind
::Placeholder(idx
) => {
247 let id
= from_placeholder_idx(db
, *idx
);
248 let generic_params
= db
.generic_params(id
.parent
);
249 let param_data
= &generic_params
.type_or_consts
[id
.local_id
];
251 TypeOrConstParamData
::TypeParamData(p
) => match p
.provenance
{
252 hir_def
::generics
::TypeParamProvenance
::ArgumentImplTrait
=> {
253 let substs
= TyBuilder
::placeholder_subst(db
, id
.parent
);
255 .generic_predicates(id
.parent
)
257 .map(|pred
| pred
.clone().substitute(Interner
, &substs
))
258 .filter(|wc
| match &wc
.skip_binders() {
259 WhereClause
::Implemented(tr
) => {
260 &tr
.self_type_parameter(Interner
) == self
262 WhereClause
::AliasEq(AliasEq
{
263 alias
: AliasTy
::Projection(proj
),
265 }) => &proj
.self_type_parameter(db
) == self,
268 .collect
::<Vec
<_
>>();
281 fn associated_type_parent_trait(&self, db
: &dyn HirDatabase
) -> Option
<TraitId
> {
282 match self.kind(Interner
) {
283 TyKind
::AssociatedType(id
, ..) => {
284 match from_assoc_type_id(*id
).lookup(db
.upcast()).container
{
285 ItemContainerId
::TraitId(trait_id
) => Some(trait_id
),
289 TyKind
::Alias(AliasTy
::Projection(projection_ty
)) => {
290 match from_assoc_type_id(projection_ty
.associated_ty_id
)
294 ItemContainerId
::TraitId(trait_id
) => Some(trait_id
),
302 fn equals_ctor(&self, other
: &Ty
) -> bool
{
303 match (self.kind(Interner
), other
.kind(Interner
)) {
304 (TyKind
::Adt(adt
, ..), TyKind
::Adt(adt2
, ..)) => adt
== adt2
,
305 (TyKind
::Slice(_
), TyKind
::Slice(_
)) | (TyKind
::Array(_
, _
), TyKind
::Array(_
, _
)) => {
308 (TyKind
::FnDef(def_id
, ..), TyKind
::FnDef(def_id2
, ..)) => def_id
== def_id2
,
309 (TyKind
::OpaqueType(ty_id
, ..), TyKind
::OpaqueType(ty_id2
, ..)) => ty_id
== ty_id2
,
310 (TyKind
::AssociatedType(ty_id
, ..), TyKind
::AssociatedType(ty_id2
, ..)) => {
313 (TyKind
::Foreign(ty_id
, ..), TyKind
::Foreign(ty_id2
, ..)) => ty_id
== ty_id2
,
314 (TyKind
::Closure(id1
, _
), TyKind
::Closure(id2
, _
)) => id1
== id2
,
315 (TyKind
::Ref(mutability
, ..), TyKind
::Ref(mutability2
, ..))
316 | (TyKind
::Raw(mutability
, ..), TyKind
::Raw(mutability2
, ..)) => {
317 mutability
== mutability2
320 TyKind
::Function(FnPointer { num_binders, sig, .. }
),
321 TyKind
::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }
),
322 ) => num_binders
== num_binders2
&& sig
== sig2
,
323 (TyKind
::Tuple(cardinality
, _
), TyKind
::Tuple(cardinality2
, _
)) => {
324 cardinality
== cardinality2
326 (TyKind
::Str
, TyKind
::Str
) | (TyKind
::Never
, TyKind
::Never
) => true,
327 (TyKind
::Scalar(scalar
), TyKind
::Scalar(scalar2
)) => scalar
== scalar2
,
333 pub trait ProjectionTyExt
{
334 fn trait_ref(&self, db
: &dyn HirDatabase
) -> TraitRef
;
335 fn trait_(&self, db
: &dyn HirDatabase
) -> TraitId
;
336 fn self_type_parameter(&self, db
: &dyn HirDatabase
) -> Ty
;
339 impl ProjectionTyExt
for ProjectionTy
{
340 fn trait_ref(&self, db
: &dyn HirDatabase
) -> TraitRef
{
341 // FIXME: something like `Split` trait from chalk-solve might be nice.
342 let generics
= generics(db
.upcast(), from_assoc_type_id(self.associated_ty_id
).into());
343 let substitution
= Substitution
::from_iter(
345 self.substitution
.iter(Interner
).skip(generics
.len_self()),
347 TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
350 fn trait_(&self, db
: &dyn HirDatabase
) -> TraitId
{
351 match from_assoc_type_id(self.associated_ty_id
).lookup(db
.upcast()).container
{
352 ItemContainerId
::TraitId(it
) => it
,
353 _
=> panic
!("projection ty without parent trait"),
357 fn self_type_parameter(&self, db
: &dyn HirDatabase
) -> Ty
{
358 self.trait_ref(db
).self_type_parameter(Interner
)
362 pub trait TraitRefExt
{
363 fn hir_trait_id(&self) -> TraitId
;
366 impl TraitRefExt
for TraitRef
{
367 fn hir_trait_id(&self) -> TraitId
{
368 from_chalk_trait_id(self.trait_id
)