hir_ty/
lib.rs

1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists.
3
4#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
5
6#[cfg(feature = "in-rust-tree")]
7extern crate rustc_index;
8
9#[cfg(not(feature = "in-rust-tree"))]
10extern crate ra_ap_rustc_index as rustc_index;
11
12#[cfg(feature = "in-rust-tree")]
13extern crate rustc_abi;
14
15#[cfg(not(feature = "in-rust-tree"))]
16extern crate ra_ap_rustc_abi as rustc_abi;
17
18#[cfg(feature = "in-rust-tree")]
19extern crate rustc_pattern_analysis;
20
21#[cfg(not(feature = "in-rust-tree"))]
22extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
23
24#[cfg(feature = "in-rust-tree")]
25extern crate rustc_ast_ir;
26
27#[cfg(not(feature = "in-rust-tree"))]
28extern crate ra_ap_rustc_ast_ir as rustc_ast_ir;
29
30#[cfg(feature = "in-rust-tree")]
31extern crate rustc_type_ir;
32
33#[cfg(not(feature = "in-rust-tree"))]
34extern crate ra_ap_rustc_type_ir as rustc_type_ir;
35
36#[cfg(feature = "in-rust-tree")]
37extern crate rustc_next_trait_solver;
38
39#[cfg(not(feature = "in-rust-tree"))]
40extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
41
42mod builder;
43mod chalk_db;
44mod chalk_ext;
45mod drop;
46mod infer;
47mod inhabitedness;
48mod interner;
49mod lower;
50mod lower_nextsolver;
51mod mapping;
52pub mod next_solver;
53mod target_feature;
54mod tls;
55mod utils;
56
57pub mod autoderef;
58pub mod consteval;
59pub mod consteval_nextsolver;
60pub mod db;
61pub mod diagnostics;
62pub mod display;
63pub mod dyn_compatibility;
64pub mod generics;
65pub mod lang_items;
66pub mod layout;
67pub mod method_resolution;
68pub mod mir;
69pub mod primitive;
70pub mod traits;
71
72#[cfg(test)]
73mod test_db;
74#[cfg(test)]
75mod tests;
76mod variance;
77
78use std::hash::Hash;
79
80use chalk_ir::{
81    NoSolution, VariableKinds,
82    fold::{Shift, TypeFoldable},
83    interner::HasInterner,
84};
85use either::Either;
86use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness};
87use hir_expand::name::Name;
88use indexmap::{IndexMap, map::Entry};
89use intern::{Symbol, sym};
90use la_arena::{Arena, Idx};
91use mir::{MirEvalError, VTableMap};
92use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
93use rustc_type_ir::inherent::SliceLike;
94use syntax::ast::{ConstArg, make};
95use traits::FnTrait;
96use triomphe::Arc;
97
98use crate::{
99    consteval::unknown_const,
100    db::HirDatabase,
101    display::{DisplayTarget, HirDisplay},
102    generics::Generics,
103    infer::unify::InferenceTable,
104    next_solver::{DbInterner, mapping::convert_ty_for_result},
105};
106
107pub use autoderef::autoderef;
108pub use builder::{ParamKind, TyBuilder};
109pub use chalk_ext::*;
110pub use drop::DropGlue;
111pub use infer::{
112    Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult,
113    InferenceTyDiagnosticSource, OverloadedDeref, PointerCast,
114    cast::CastError,
115    closure::{CaptureKind, CapturedItem},
116    could_coerce, could_unify, could_unify_deeply,
117};
118pub use interner::Interner;
119pub use lower::{
120    ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext,
121    ValueTyDefId, diagnostics::*,
122};
123pub use lower_nextsolver::associated_type_shorthand_candidates;
124pub use mapping::{
125    ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
126    lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
127    to_foreign_def_id, to_placeholder_idx,
128};
129pub use method_resolution::check_orphan_rules;
130pub use target_feature::TargetFeatures;
131pub use traits::TraitEnvironment;
132pub use utils::{Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call};
133pub use variance::Variance;
134
135pub use chalk_ir::{
136    AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
137    cast::Cast,
138    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
139};
140
141pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
142pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
143pub type FnDefId = chalk_ir::FnDefId<Interner>;
144pub type ClosureId = chalk_ir::ClosureId<Interner>;
145pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
146pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
147
148pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
149
150pub(crate) type VariableKind = chalk_ir::VariableKind<Interner>;
151/// Represents generic parameters and an item bound by them. When the item has parent, the binders
152/// also contain the generic parameters for its parent. See chalk's documentation for details.
153///
154/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
155/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
156/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
157/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
158/// motivation in detail.
159pub type Binders<T> = chalk_ir::Binders<T>;
160/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
161/// it contains generic arguments for both its parent and itself. See chalk's documentation for
162/// details.
163///
164/// See `Binders` for the constraint on the ordering.
165pub type Substitution = chalk_ir::Substitution<Interner>;
166pub type GenericArg = chalk_ir::GenericArg<Interner>;
167pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
168
169pub type Ty = chalk_ir::Ty<Interner>;
170pub type TyKind = chalk_ir::TyKind<Interner>;
171pub type TypeFlags = chalk_ir::TypeFlags;
172pub(crate) type DynTy = chalk_ir::DynTy<Interner>;
173pub type FnPointer = chalk_ir::FnPointer<Interner>;
174pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor
175
176pub type AliasTy = chalk_ir::AliasTy<Interner>;
177
178pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
179pub(crate) type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
180pub(crate) type InferenceVar = chalk_ir::InferenceVar;
181
182pub(crate) type Lifetime = chalk_ir::Lifetime<Interner>;
183pub(crate) type LifetimeData = chalk_ir::LifetimeData<Interner>;
184pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
185
186pub type ConstValue = chalk_ir::ConstValue<Interner>;
187
188pub type Const = chalk_ir::Const<Interner>;
189pub(crate) type ConstData = chalk_ir::ConstData<Interner>;
190pub(crate) type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
191
192pub type TraitRef = chalk_ir::TraitRef<Interner>;
193pub type QuantifiedWhereClause = Binders<WhereClause>;
194pub type Canonical<T> = chalk_ir::Canonical<T>;
195
196pub(crate) type ChalkTraitId = chalk_ir::TraitId<Interner>;
197pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
198
199pub(crate) type FnSig = chalk_ir::FnSig<Interner>;
200
201pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
202pub type AliasEq = chalk_ir::AliasEq<Interner>;
203pub type WhereClause = chalk_ir::WhereClause<Interner>;
204
205pub(crate) type DomainGoal = chalk_ir::DomainGoal<Interner>;
206pub(crate) type Goal = chalk_ir::Goal<Interner>;
207
208pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>;
209pub(crate) type GoalData = chalk_ir::GoalData<Interner>;
210pub(crate) type ProgramClause = chalk_ir::ProgramClause<Interner>;
211
212/// A constant can have reference to other things. Memory map job is holding
213/// the necessary bits of memory of the const eval session to keep the constant
214/// meaningful.
215#[derive(Debug, Default, Clone, PartialEq, Eq)]
216pub enum MemoryMap<'db> {
217    #[default]
218    Empty,
219    Simple(Box<[u8]>),
220    Complex(Box<ComplexMemoryMap<'db>>),
221}
222
223#[derive(Debug, Default, Clone, PartialEq, Eq)]
224pub struct ComplexMemoryMap<'db> {
225    memory: IndexMap<usize, Box<[u8]>, FxBuildHasher>,
226    vtable: VTableMap<'db>,
227}
228
229impl ComplexMemoryMap<'_> {
230    fn insert(&mut self, addr: usize, val: Box<[u8]>) {
231        match self.memory.entry(addr) {
232            Entry::Occupied(mut e) => {
233                if e.get().len() < val.len() {
234                    e.insert(val);
235                }
236            }
237            Entry::Vacant(e) => {
238                e.insert(val);
239            }
240        }
241    }
242}
243
244impl<'db> MemoryMap<'db> {
245    pub fn vtable_ty(&self, id: usize) -> Result<crate::next_solver::Ty<'db>, MirEvalError> {
246        match self {
247            MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)),
248            MemoryMap::Complex(cm) => cm.vtable.ty(id),
249        }
250    }
251
252    fn simple(v: Box<[u8]>) -> Self {
253        MemoryMap::Simple(v)
254    }
255
256    /// This functions convert each address by a function `f` which gets the byte intervals and assign an address
257    /// to them. It is useful when you want to load a constant with a memory map in a new memory. You can pass an
258    /// allocator function as `f` and it will return a mapping of old addresses to new addresses.
259    fn transform_addresses(
260        &self,
261        mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError>,
262    ) -> Result<FxHashMap<usize, usize>, MirEvalError> {
263        let mut transform = |(addr, val): (&usize, &[u8])| {
264            let addr = *addr;
265            let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) };
266            f(val, align).map(|it| (addr, it))
267        };
268        match self {
269            MemoryMap::Empty => Ok(Default::default()),
270            MemoryMap::Simple(m) => transform((&0, m)).map(|(addr, val)| {
271                let mut map = FxHashMap::with_capacity_and_hasher(1, rustc_hash::FxBuildHasher);
272                map.insert(addr, val);
273                map
274            }),
275            MemoryMap::Complex(cm) => {
276                cm.memory.iter().map(|(addr, val)| transform((addr, val))).collect()
277            }
278        }
279    }
280
281    fn get(&self, addr: usize, size: usize) -> Option<&[u8]> {
282        if size == 0 {
283            Some(&[])
284        } else {
285            match self {
286                MemoryMap::Empty => Some(&[]),
287                MemoryMap::Simple(m) if addr == 0 => m.get(0..size),
288                MemoryMap::Simple(_) => None,
289                MemoryMap::Complex(cm) => cm.memory.get(&addr)?.get(0..size),
290            }
291        }
292    }
293}
294
295// FIXME(next-solver): add a lifetime to this
296/// A concrete constant value
297#[derive(Debug, Clone, PartialEq, Eq)]
298pub enum ConstScalar {
299    Bytes(Box<[u8]>, MemoryMap<'static>),
300    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
301    // constants
302    UnevaluatedConst(GeneralConstId, Substitution),
303    /// Case of an unknown value that rustc might know but we don't
304    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
305    // constants
306    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
307    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
308    Unknown,
309}
310
311impl Hash for ConstScalar {
312    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
313        core::mem::discriminant(self).hash(state);
314        if let ConstScalar::Bytes(b, _) = self {
315            b.hash(state)
316        }
317    }
318}
319
320/// A concrete constant value
321#[derive(Debug, Clone, PartialEq, Eq)]
322pub enum ConstScalarNs<'db> {
323    Bytes(Box<[u8]>, MemoryMap<'db>),
324    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
325    // constants
326    UnevaluatedConst(GeneralConstId, Substitution),
327    /// Case of an unknown value that rustc might know but we don't
328    // FIXME: this is a hack to get around chalk not being able to represent unevaluatable
329    // constants
330    // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177
331    // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348
332    Unknown,
333}
334
335impl Hash for ConstScalarNs<'_> {
336    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
337        core::mem::discriminant(self).hash(state);
338        if let ConstScalarNs::Bytes(b, _) = self {
339            b.hash(state)
340        }
341    }
342}
343
344/// Return an index of a parameter in the generic type parameter list by it's id.
345pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
346    generics::generics(db, id.parent).type_or_const_param_idx(id)
347}
348
349pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
350where
351    T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
352{
353    Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
354}
355
356pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
357    value: T,
358) -> Binders<T> {
359    Binders::new(
360        chalk_ir::VariableKinds::from_iter(
361            Interner,
362            std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
363        ),
364        value,
365    )
366}
367
368pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
369    db: &dyn HirDatabase,
370    generics: &Generics,
371    value: T,
372) -> Binders<T> {
373    Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value)
374}
375
376pub(crate) fn variable_kinds_from_iter(
377    db: &dyn HirDatabase,
378    iter: impl Iterator<Item = hir_def::GenericParamId>,
379) -> VariableKinds<Interner> {
380    VariableKinds::from_iter(
381        Interner,
382        iter.map(|x| match x {
383            hir_def::GenericParamId::ConstParamId(id) => {
384                chalk_ir::VariableKind::Const(db.const_param_ty(id))
385            }
386            hir_def::GenericParamId::TypeParamId(_) => {
387                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
388            }
389            hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
390        }),
391    )
392}
393
394// FIXME: get rid of this, just replace it by FnPointer
395/// A function signature as seen by type inference: Several parameter types and
396/// one return type.
397#[derive(Clone, PartialEq, Eq, Debug)]
398pub struct CallableSig {
399    params_and_return: Arc<[Ty]>,
400    is_varargs: bool,
401    safety: Safety,
402    abi: FnAbi,
403}
404
405has_interner!(CallableSig);
406
407#[derive(Debug, Copy, Clone, Eq)]
408pub enum FnAbi {
409    Aapcs,
410    AapcsUnwind,
411    AvrInterrupt,
412    AvrNonBlockingInterrupt,
413    C,
414    CCmseNonsecureCall,
415    CCmseNonsecureEntry,
416    CDecl,
417    CDeclUnwind,
418    CUnwind,
419    Efiapi,
420    Fastcall,
421    FastcallUnwind,
422    Msp430Interrupt,
423    PtxKernel,
424    RiscvInterruptM,
425    RiscvInterruptS,
426    Rust,
427    RustCall,
428    RustCold,
429    RustIntrinsic,
430    Stdcall,
431    StdcallUnwind,
432    System,
433    SystemUnwind,
434    Sysv64,
435    Sysv64Unwind,
436    Thiscall,
437    ThiscallUnwind,
438    Unadjusted,
439    Vectorcall,
440    VectorcallUnwind,
441    Wasm,
442    Win64,
443    Win64Unwind,
444    X86Interrupt,
445    Unknown,
446}
447
448impl PartialEq for FnAbi {
449    fn eq(&self, _other: &Self) -> bool {
450        // FIXME: Proper equality breaks `coercion::two_closures_lub` test
451        true
452    }
453}
454
455impl Hash for FnAbi {
456    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
457        // Required because of the FIXME above and due to us implementing `Eq`, without this
458        // we would break the `Hash` + `Eq` contract
459        core::mem::discriminant(&Self::Unknown).hash(state);
460    }
461}
462
463impl FnAbi {
464    #[rustfmt::skip]
465    pub fn from_symbol(s: &Symbol) -> FnAbi {
466        match s {
467            s if *s == sym::aapcs_dash_unwind => FnAbi::AapcsUnwind,
468            s if *s == sym::aapcs => FnAbi::Aapcs,
469            s if *s == sym::avr_dash_interrupt => FnAbi::AvrInterrupt,
470            s if *s == sym::avr_dash_non_dash_blocking_dash_interrupt => FnAbi::AvrNonBlockingInterrupt,
471            s if *s == sym::C_dash_cmse_dash_nonsecure_dash_call => FnAbi::CCmseNonsecureCall,
472            s if *s == sym::C_dash_cmse_dash_nonsecure_dash_entry => FnAbi::CCmseNonsecureEntry,
473            s if *s == sym::C_dash_unwind => FnAbi::CUnwind,
474            s if *s == sym::C => FnAbi::C,
475            s if *s == sym::cdecl_dash_unwind => FnAbi::CDeclUnwind,
476            s if *s == sym::cdecl => FnAbi::CDecl,
477            s if *s == sym::efiapi => FnAbi::Efiapi,
478            s if *s == sym::fastcall_dash_unwind => FnAbi::FastcallUnwind,
479            s if *s == sym::fastcall => FnAbi::Fastcall,
480            s if *s == sym::msp430_dash_interrupt => FnAbi::Msp430Interrupt,
481            s if *s == sym::ptx_dash_kernel => FnAbi::PtxKernel,
482            s if *s == sym::riscv_dash_interrupt_dash_m => FnAbi::RiscvInterruptM,
483            s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
484            s if *s == sym::rust_dash_call => FnAbi::RustCall,
485            s if *s == sym::rust_dash_cold => FnAbi::RustCold,
486            s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
487            s if *s == sym::Rust => FnAbi::Rust,
488            s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
489            s if *s == sym::stdcall => FnAbi::Stdcall,
490            s if *s == sym::system_dash_unwind => FnAbi::SystemUnwind,
491            s if *s == sym::system => FnAbi::System,
492            s if *s == sym::sysv64_dash_unwind => FnAbi::Sysv64Unwind,
493            s if *s == sym::sysv64 => FnAbi::Sysv64,
494            s if *s == sym::thiscall_dash_unwind => FnAbi::ThiscallUnwind,
495            s if *s == sym::thiscall => FnAbi::Thiscall,
496            s if *s == sym::unadjusted => FnAbi::Unadjusted,
497            s if *s == sym::vectorcall_dash_unwind => FnAbi::VectorcallUnwind,
498            s if *s == sym::vectorcall => FnAbi::Vectorcall,
499            s if *s == sym::wasm => FnAbi::Wasm,
500            s if *s == sym::win64_dash_unwind => FnAbi::Win64Unwind,
501            s if *s == sym::win64 => FnAbi::Win64,
502            s if *s == sym::x86_dash_interrupt => FnAbi::X86Interrupt,
503            _ => FnAbi::Unknown,
504        }
505    }
506
507    pub fn as_str(self) -> &'static str {
508        match self {
509            FnAbi::Aapcs => "aapcs",
510            FnAbi::AapcsUnwind => "aapcs-unwind",
511            FnAbi::AvrInterrupt => "avr-interrupt",
512            FnAbi::AvrNonBlockingInterrupt => "avr-non-blocking-interrupt",
513            FnAbi::C => "C",
514            FnAbi::CCmseNonsecureCall => "C-cmse-nonsecure-call",
515            FnAbi::CCmseNonsecureEntry => "C-cmse-nonsecure-entry",
516            FnAbi::CDecl => "C-decl",
517            FnAbi::CDeclUnwind => "cdecl-unwind",
518            FnAbi::CUnwind => "C-unwind",
519            FnAbi::Efiapi => "efiapi",
520            FnAbi::Fastcall => "fastcall",
521            FnAbi::FastcallUnwind => "fastcall-unwind",
522            FnAbi::Msp430Interrupt => "msp430-interrupt",
523            FnAbi::PtxKernel => "ptx-kernel",
524            FnAbi::RiscvInterruptM => "riscv-interrupt-m",
525            FnAbi::RiscvInterruptS => "riscv-interrupt-s",
526            FnAbi::Rust => "Rust",
527            FnAbi::RustCall => "rust-call",
528            FnAbi::RustCold => "rust-cold",
529            FnAbi::RustIntrinsic => "rust-intrinsic",
530            FnAbi::Stdcall => "stdcall",
531            FnAbi::StdcallUnwind => "stdcall-unwind",
532            FnAbi::System => "system",
533            FnAbi::SystemUnwind => "system-unwind",
534            FnAbi::Sysv64 => "sysv64",
535            FnAbi::Sysv64Unwind => "sysv64-unwind",
536            FnAbi::Thiscall => "thiscall",
537            FnAbi::ThiscallUnwind => "thiscall-unwind",
538            FnAbi::Unadjusted => "unadjusted",
539            FnAbi::Vectorcall => "vectorcall",
540            FnAbi::VectorcallUnwind => "vectorcall-unwind",
541            FnAbi::Wasm => "wasm",
542            FnAbi::Win64 => "win64",
543            FnAbi::Win64Unwind => "win64-unwind",
544            FnAbi::X86Interrupt => "x86-interrupt",
545            FnAbi::Unknown => "unknown-abi",
546        }
547    }
548}
549
550/// A polymorphic function signature.
551pub type PolyFnSig = Binders<CallableSig>;
552
553impl CallableSig {
554    pub fn from_params_and_return(
555        params: impl Iterator<Item = Ty>,
556        ret: Ty,
557        is_varargs: bool,
558        safety: Safety,
559        abi: FnAbi,
560    ) -> CallableSig {
561        let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1);
562        params_and_return.extend(params);
563        params_and_return.push(ret);
564        CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi }
565    }
566
567    pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
568        let callable_def = ToChalk::from_chalk(db, def);
569        let sig = db.callable_item_signature(callable_def);
570        sig.substitute(Interner, substs)
571    }
572    pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
573        CallableSig {
574            // FIXME: what to do about lifetime params? -> return PolyFnSig
575            params_and_return: Arc::from_iter(
576                fn_ptr
577                    .substitution
578                    .clone()
579                    .shifted_out_to(Interner, DebruijnIndex::ONE)
580                    .expect("unexpected lifetime vars in fn ptr")
581                    .0
582                    .as_slice(Interner)
583                    .iter()
584                    .map(|arg| arg.assert_ty_ref(Interner).clone()),
585            ),
586            is_varargs: fn_ptr.sig.variadic,
587            safety: fn_ptr.sig.safety,
588            abi: fn_ptr.sig.abi,
589        }
590    }
591    pub fn from_fn_sig_and_header<'db>(
592        interner: DbInterner<'db>,
593        sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>,
594        header: rustc_type_ir::FnHeader<DbInterner<'db>>,
595    ) -> CallableSig {
596        CallableSig {
597            // FIXME: what to do about lifetime params? -> return PolyFnSig
598            params_and_return: Arc::from_iter(
599                sig.skip_binder()
600                    .inputs_and_output
601                    .iter()
602                    .map(|t| convert_ty_for_result(interner, t)),
603            ),
604            is_varargs: header.c_variadic,
605            safety: match header.safety {
606                next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe,
607                next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
608            },
609            abi: header.abi,
610        }
611    }
612
613    pub fn to_fn_ptr(&self) -> FnPointer {
614        FnPointer {
615            num_binders: 0,
616            sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs },
617            substitution: FnSubst(Substitution::from_iter(
618                Interner,
619                self.params_and_return.iter().cloned(),
620            )),
621        }
622    }
623
624    pub fn abi(&self) -> FnAbi {
625        self.abi
626    }
627
628    pub fn params(&self) -> &[Ty] {
629        &self.params_and_return[0..self.params_and_return.len() - 1]
630    }
631
632    pub fn ret(&self) -> &Ty {
633        &self.params_and_return[self.params_and_return.len() - 1]
634    }
635}
636
637impl TypeFoldable<Interner> for CallableSig {
638    fn try_fold_with<E>(
639        self,
640        folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
641        outer_binder: DebruijnIndex,
642    ) -> Result<Self, E> {
643        let vec = self.params_and_return.to_vec();
644        let folded = vec.try_fold_with(folder, outer_binder)?;
645        Ok(CallableSig {
646            params_and_return: folded.into(),
647            is_varargs: self.is_varargs,
648            safety: self.safety,
649            abi: self.abi,
650        })
651    }
652}
653
654#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
655pub enum ImplTraitId {
656    ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
657    TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
658    AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
659}
660
661#[derive(PartialEq, Eq, Debug, Hash)]
662pub struct ImplTraits {
663    pub(crate) impl_traits: Arena<ImplTrait>,
664}
665
666has_interner!(ImplTraits);
667
668#[derive(PartialEq, Eq, Debug, Hash)]
669pub struct ImplTrait {
670    pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
671}
672
673pub type ImplTraitIdx = Idx<ImplTrait>;
674
675pub fn static_lifetime() -> Lifetime {
676    LifetimeData::Static.intern(Interner)
677}
678
679pub fn error_lifetime() -> Lifetime {
680    LifetimeData::Error.intern(Interner)
681}
682
683pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
684    t: T,
685    for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
686    for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
687) -> T {
688    use chalk_ir::fold::TypeFolder;
689
690    #[derive(chalk_derive::FallibleTypeFolder)]
691    #[has_interner(Interner)]
692    struct FreeVarFolder<
693        F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
694        F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
695    >(F1, F2);
696    impl<F1: FnMut(BoundVar, DebruijnIndex) -> Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const>
697        TypeFolder<Interner> for FreeVarFolder<F1, F2>
698    {
699        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
700            self
701        }
702
703        fn interner(&self) -> Interner {
704            Interner
705        }
706
707        fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
708            self.0(bound_var, outer_binder)
709        }
710
711        fn fold_free_var_const(
712            &mut self,
713            ty: Ty,
714            bound_var: BoundVar,
715            outer_binder: DebruijnIndex,
716        ) -> Const {
717            self.1(ty, bound_var, outer_binder)
718        }
719    }
720    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
721}
722
723pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
724    t: T,
725    mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
726    binders: DebruijnIndex,
727) -> T {
728    fold_tys_and_consts(
729        t,
730        |x, d| match x {
731            Either::Left(x) => Either::Left(for_ty(x, d)),
732            Either::Right(x) => Either::Right(x),
733        },
734        binders,
735    )
736}
737
738pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
739    t: T,
740    f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
741    binders: DebruijnIndex,
742) -> T {
743    use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
744    #[derive(chalk_derive::FallibleTypeFolder)]
745    #[has_interner(Interner)]
746    struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
747    impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
748        for TyFolder<F>
749    {
750        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
751            self
752        }
753
754        fn interner(&self) -> Interner {
755            Interner
756        }
757
758        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
759            let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
760            self.0(Either::Left(ty), outer_binder).left().unwrap()
761        }
762
763        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
764            self.0(Either::Right(c), outer_binder).right().unwrap()
765        }
766    }
767    t.fold_with(&mut TyFolder(f), binders)
768}
769
770pub(crate) fn fold_generic_args<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
771    t: T,
772    f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData,
773    binders: DebruijnIndex,
774) -> T {
775    use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
776    #[derive(chalk_derive::FallibleTypeFolder)]
777    #[has_interner(Interner)]
778    struct TyFolder<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData>(F);
779    impl<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData> TypeFolder<Interner>
780        for TyFolder<F>
781    {
782        fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
783            self
784        }
785
786        fn interner(&self) -> Interner {
787            Interner
788        }
789
790        fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
791            let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
792            self.0(GenericArgData::Ty(ty), outer_binder)
793                .intern(Interner)
794                .ty(Interner)
795                .unwrap()
796                .clone()
797        }
798
799        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
800            self.0(GenericArgData::Const(c), outer_binder)
801                .intern(Interner)
802                .constant(Interner)
803                .unwrap()
804                .clone()
805        }
806
807        fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime {
808            let lt = lt.super_fold_with(self.as_dyn(), outer_binder);
809            self.0(GenericArgData::Lifetime(lt), outer_binder)
810                .intern(Interner)
811                .lifetime(Interner)
812                .unwrap()
813                .clone()
814        }
815    }
816    t.fold_with(&mut TyFolder(f), binders)
817}
818
819/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
820/// ensures there are no unbound variables or inference variables anywhere in
821/// the `t`.
822pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
823where
824    T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
825{
826    use chalk_ir::{
827        Fallible,
828        fold::{FallibleTypeFolder, TypeSuperFoldable},
829    };
830    struct ErrorReplacer {
831        vars: usize,
832    }
833    impl FallibleTypeFolder<Interner> for ErrorReplacer {
834        type Error = NoSolution;
835
836        fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
837            self
838        }
839
840        fn interner(&self) -> Interner {
841            Interner
842        }
843
844        fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
845            if let TyKind::Error = ty.kind(Interner) {
846                let index = self.vars;
847                self.vars += 1;
848                Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
849            } else {
850                ty.try_super_fold_with(self.as_dyn(), outer_binder)
851            }
852        }
853
854        fn try_fold_inference_ty(
855            &mut self,
856            _var: InferenceVar,
857            _kind: TyVariableKind,
858            _outer_binder: DebruijnIndex,
859        ) -> Fallible<Ty> {
860            if cfg!(debug_assertions) {
861                // we don't want to just panic here, because then the error message
862                // won't contain the whole thing, which would not be very helpful
863                Err(NoSolution)
864            } else {
865                Ok(TyKind::Error.intern(Interner))
866            }
867        }
868
869        fn try_fold_free_var_ty(
870            &mut self,
871            _bound_var: BoundVar,
872            _outer_binder: DebruijnIndex,
873        ) -> Fallible<Ty> {
874            if cfg!(debug_assertions) {
875                // we don't want to just panic here, because then the error message
876                // won't contain the whole thing, which would not be very helpful
877                Err(NoSolution)
878            } else {
879                Ok(TyKind::Error.intern(Interner))
880            }
881        }
882
883        fn try_fold_inference_const(
884            &mut self,
885            ty: Ty,
886            _var: InferenceVar,
887            _outer_binder: DebruijnIndex,
888        ) -> Fallible<Const> {
889            if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
890        }
891
892        fn try_fold_free_var_const(
893            &mut self,
894            ty: Ty,
895            _bound_var: BoundVar,
896            _outer_binder: DebruijnIndex,
897        ) -> Fallible<Const> {
898            if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
899        }
900
901        fn try_fold_inference_lifetime(
902            &mut self,
903            _var: InferenceVar,
904            _outer_binder: DebruijnIndex,
905        ) -> Fallible<Lifetime> {
906            if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) }
907        }
908
909        fn try_fold_free_var_lifetime(
910            &mut self,
911            _bound_var: BoundVar,
912            _outer_binder: DebruijnIndex,
913        ) -> Fallible<Lifetime> {
914            if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) }
915        }
916    }
917    let mut error_replacer = ErrorReplacer { vars: 0 };
918    let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
919        Ok(t) => t,
920        Err(_) => panic!("Encountered unbound or inference vars in {t:?}"),
921    };
922    let kinds = (0..error_replacer.vars).map(|_| {
923        chalk_ir::CanonicalVarKind::new(
924            chalk_ir::VariableKind::Ty(TyVariableKind::General),
925            chalk_ir::UniverseIndex::ROOT,
926        )
927    });
928    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
929}
930
931pub fn callable_sig_from_fn_trait(
932    self_ty: &Ty,
933    trait_env: Arc<TraitEnvironment>,
934    db: &dyn HirDatabase,
935) -> Option<(FnTrait, CallableSig)> {
936    let krate = trait_env.krate;
937    let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
938    let output_assoc_type = fn_once_trait
939        .trait_items(db)
940        .associated_type_by_name(&Name::new_symbol_root(sym::Output))?;
941
942    let mut table = InferenceTable::new(db, trait_env.clone());
943    let b = TyBuilder::trait_ref(db, fn_once_trait);
944    if b.remaining() != 2 {
945        return None;
946    }
947
948    // Register two obligations:
949    // - Self: FnOnce<?args_ty>
950    // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
951    let args_ty = table.new_type_var();
952    let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
953    let projection = TyBuilder::assoc_type_projection(
954        db,
955        output_assoc_type,
956        Some(trait_ref.substitution.clone()),
957    )
958    .build();
959
960    let block = trait_env.block;
961    let trait_env = trait_env.env.clone();
962    let obligation =
963        InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() };
964    let canonical = table.canonicalize(obligation.clone());
965    if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() {
966        table.register_obligation(obligation.goal);
967        let return_ty = table.normalize_projection_ty(projection);
968        for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
969            let fn_x_trait = fn_x.get_id(db, krate)?;
970            trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
971            let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
972                goal: trait_ref.clone().cast(Interner),
973                environment: trait_env.clone(),
974            };
975            let canonical = table.canonicalize(obligation.clone());
976            if !db.trait_solve(krate, block, canonical.cast(Interner)).no_solution() {
977                let ret_ty = table.resolve_completely(return_ty);
978                let args_ty = table.resolve_completely(args_ty);
979                let params = args_ty
980                    .as_tuple()?
981                    .iter(Interner)
982                    .map(|it| it.assert_ty_ref(Interner))
983                    .cloned();
984
985                return Some((
986                    fn_x,
987                    CallableSig::from_params_and_return(
988                        params,
989                        ret_ty,
990                        false,
991                        Safety::Safe,
992                        FnAbi::RustCall,
993                    ),
994                ));
995            }
996        }
997        unreachable!("It should at least implement FnOnce at this point");
998    } else {
999        None
1000    }
1001}
1002
1003struct PlaceholderCollector<'db> {
1004    db: &'db dyn HirDatabase,
1005    placeholders: FxHashSet<TypeOrConstParamId>,
1006}
1007
1008impl PlaceholderCollector<'_> {
1009    fn collect(&mut self, idx: PlaceholderIndex) {
1010        let id = from_placeholder_idx(self.db, idx);
1011        self.placeholders.insert(id);
1012    }
1013}
1014
1015impl TypeVisitor<Interner> for PlaceholderCollector<'_> {
1016    type BreakTy = ();
1017
1018    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
1019        self
1020    }
1021
1022    fn interner(&self) -> Interner {
1023        Interner
1024    }
1025
1026    fn visit_ty(
1027        &mut self,
1028        ty: &Ty,
1029        outer_binder: DebruijnIndex,
1030    ) -> std::ops::ControlFlow<Self::BreakTy> {
1031        let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER;
1032        let chalk_ir::TyData { kind, flags } = ty.data(Interner);
1033
1034        if let TyKind::Placeholder(idx) = kind {
1035            self.collect(*idx);
1036        } else if flags.intersects(has_placeholder_bits) {
1037            return ty.super_visit_with(self, outer_binder);
1038        } else {
1039            // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate
1040            // that there are no placeholders.
1041        }
1042
1043        std::ops::ControlFlow::Continue(())
1044    }
1045
1046    fn visit_const(
1047        &mut self,
1048        constant: &chalk_ir::Const<Interner>,
1049        _outer_binder: DebruijnIndex,
1050    ) -> std::ops::ControlFlow<Self::BreakTy> {
1051        if let chalk_ir::ConstValue::Placeholder(idx) = constant.data(Interner).value {
1052            self.collect(idx);
1053        }
1054        std::ops::ControlFlow::Continue(())
1055    }
1056}
1057
1058/// Returns unique placeholders for types and consts contained in `value`.
1059pub fn collect_placeholders<T>(value: &T, db: &dyn HirDatabase) -> Vec<TypeOrConstParamId>
1060where
1061    T: ?Sized + TypeVisitable<Interner>,
1062{
1063    let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() };
1064    _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
1065    collector.placeholders.into_iter().collect()
1066}
1067
1068pub fn known_const_to_ast(
1069    konst: &Const,
1070    db: &dyn HirDatabase,
1071    display_target: DisplayTarget,
1072) -> Option<ConstArg> {
1073    Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str()))
1074}
1075
1076#[derive(Debug, Copy, Clone)]
1077pub(crate) enum DeclOrigin {
1078    LetExpr,
1079    /// from `let x = ..`
1080    LocalDecl {
1081        has_else: bool,
1082    },
1083}
1084
1085/// Provides context for checking patterns in declarations. More specifically this
1086/// allows us to infer array types if the pattern is irrefutable and allows us to infer
1087/// the size of the array. See issue rust-lang/rust#76342.
1088#[derive(Debug, Copy, Clone)]
1089pub(crate) struct DeclContext {
1090    pub(crate) origin: DeclOrigin,
1091}
1092
1093pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
1094    use std::env;
1095    use std::sync::LazyLock;
1096    use tracing_subscriber::{Registry, layer::SubscriberExt};
1097    use tracing_tree::HierarchicalLayer;
1098
1099    static ENABLE: LazyLock<bool> = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok());
1100    if !*ENABLE {
1101        return None;
1102    }
1103
1104    let filter: tracing_subscriber::filter::Targets =
1105        env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default();
1106    let layer = HierarchicalLayer::default()
1107        .with_indent_lines(true)
1108        .with_ansi(false)
1109        .with_indent_amount(2)
1110        .with_writer(std::io::stderr);
1111    let subscriber = Registry::default().with(filter).with(layer);
1112    Some(tracing::subscriber::set_default(subscriber))
1113}