|  | //! Type inference, i.e. the process of walking through the code and determining | 
|  | //! the type of each expression and pattern. | 
|  | //! | 
|  | //! For type inference, compare the implementations in rustc (the various | 
|  | //! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and | 
|  | //! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for | 
|  | //! inference here is the `infer` function, which infers the types of all | 
|  | //! expressions in a given function. | 
|  | //! | 
|  | //! During inference, types (i.e. the `Ty` struct) can contain type 'variables' | 
|  | //! which represent currently unknown types; as we walk through the expressions, | 
|  | //! we might determine that certain variables need to be equal to each other, or | 
|  | //! to certain types. To record this, we use the union-find implementation from | 
|  | //! the `ena` crate, which is extracted from rustc. | 
|  |  | 
|  | mod autoderef; | 
|  | pub(crate) mod cast; | 
|  | pub(crate) mod closure; | 
|  | mod coerce; | 
|  | pub(crate) mod diagnostics; | 
|  | mod expr; | 
|  | mod mutability; | 
|  | mod pat; | 
|  | mod path; | 
|  | pub(crate) mod unify; | 
|  |  | 
|  | use std::{cell::OnceCell, convert::identity, iter, ops::Index}; | 
|  |  | 
|  | use base_db::Crate; | 
|  | use chalk_ir::{ | 
|  | DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance, | 
|  | cast::Cast, | 
|  | fold::TypeFoldable, | 
|  | interner::HasInterner, | 
|  | visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, | 
|  | }; | 
|  | use either::Either; | 
|  | use hir_def::{ | 
|  | AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, | 
|  | ImplId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, | 
|  | VariantId, | 
|  | builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, | 
|  | expr_store::{Body, ExpressionStore, HygieneId, path::Path}, | 
|  | hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, | 
|  | lang_item::{LangItem, LangItemTarget, lang_item}, | 
|  | layout::Integer, | 
|  | resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, | 
|  | signatures::{ConstSignature, StaticSignature}, | 
|  | type_ref::{ConstRef, LifetimeRefId, TypeRefId}, | 
|  | }; | 
|  | use hir_expand::{mod_path::ModPath, name::Name}; | 
|  | use indexmap::IndexSet; | 
|  | use intern::sym; | 
|  | use la_arena::{ArenaMap, Entry}; | 
|  | use rustc_hash::{FxHashMap, FxHashSet}; | 
|  | use stdx::{always, never}; | 
|  | use triomphe::Arc; | 
|  |  | 
|  | use crate::db::InternedClosureId; | 
|  | use crate::{ | 
|  | AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx, | 
|  | IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, | 
|  | PathLoweringDiagnostic, ProjectionTy, Substitution, TargetFeatures, TraitEnvironment, Ty, | 
|  | TyBuilder, TyExt, | 
|  | db::HirDatabase, | 
|  | fold_tys, | 
|  | generics::Generics, | 
|  | infer::{ | 
|  | coerce::{CoerceMany, DynamicCoerceMany}, | 
|  | diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext}, | 
|  | expr::ExprIsRead, | 
|  | unify::InferenceTable, | 
|  | }, | 
|  | lower::{ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic}, | 
|  | mir::MirSpan, | 
|  | next_solver::{ | 
|  | self, DbInterner, | 
|  | mapping::{ChalkToNextSolver, NextSolverToChalk}, | 
|  | }, | 
|  | static_lifetime, to_assoc_type_id, | 
|  | traits::FnTrait, | 
|  | utils::{TargetFeatureIsSafeInTarget, UnevaluatedConstEvaluatorFolder}, | 
|  | }; | 
|  |  | 
|  | // This lint has a false positive here. See the link below for details. | 
|  | // | 
|  | // https://github.com/rust-lang/rust/issues/57411 | 
|  | #[allow(unreachable_pub)] | 
|  | pub use coerce::could_coerce; | 
|  | #[allow(unreachable_pub)] | 
|  | pub use unify::{could_unify, could_unify_deeply}; | 
|  |  | 
|  | use cast::{CastCheck, CastError}; | 
|  | pub(crate) use closure::analysis::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; | 
|  |  | 
|  | /// The entry point of type inference. | 
|  | pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { | 
|  | let _p = tracing::info_span!("infer_query").entered(); | 
|  | let resolver = def.resolver(db); | 
|  | let body = db.body(def); | 
|  | let mut ctx = InferenceContext::new(db, def, &body, resolver); | 
|  |  | 
|  | match def { | 
|  | DefWithBodyId::FunctionId(f) => { | 
|  | ctx.collect_fn(f); | 
|  | } | 
|  | DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), | 
|  | DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), | 
|  | DefWithBodyId::VariantId(v) => { | 
|  | ctx.return_ty = TyBuilder::builtin( | 
|  | match db.enum_signature(v.lookup(db).parent).variant_body_type() { | 
|  | hir_def::layout::IntegerType::Pointer(signed) => match signed { | 
|  | true => BuiltinType::Int(BuiltinInt::Isize), | 
|  | false => BuiltinType::Uint(BuiltinUint::Usize), | 
|  | }, | 
|  | hir_def::layout::IntegerType::Fixed(size, signed) => match signed { | 
|  | true => BuiltinType::Int(match size { | 
|  | Integer::I8 => BuiltinInt::I8, | 
|  | Integer::I16 => BuiltinInt::I16, | 
|  | Integer::I32 => BuiltinInt::I32, | 
|  | Integer::I64 => BuiltinInt::I64, | 
|  | Integer::I128 => BuiltinInt::I128, | 
|  | }), | 
|  | false => BuiltinType::Uint(match size { | 
|  | Integer::I8 => BuiltinUint::U8, | 
|  | Integer::I16 => BuiltinUint::U16, | 
|  | Integer::I32 => BuiltinUint::U32, | 
|  | Integer::I64 => BuiltinUint::U64, | 
|  | Integer::I128 => BuiltinUint::U128, | 
|  | }), | 
|  | }, | 
|  | }, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | ctx.infer_body(); | 
|  |  | 
|  | ctx.infer_mut_body(); | 
|  |  | 
|  | ctx.infer_closures(); | 
|  |  | 
|  | Arc::new(ctx.resolve_all()) | 
|  | } | 
|  |  | 
|  | pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<InferenceResult> { | 
|  | Arc::new(InferenceResult { has_errors: true, ..Default::default() }) | 
|  | } | 
|  |  | 
|  | /// Fully normalize all the types found within `ty` in context of `owner` body definition. | 
|  | /// | 
|  | /// This is appropriate to use only after type-check: it assumes | 
|  | /// that normalization will succeed, for example. | 
|  | #[tracing::instrument(level = "debug", skip(db))] | 
|  | pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty { | 
|  | // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only | 
|  | // works for the type case, so we check array unconditionally. Remove the array part | 
|  | // when the bug in chalk becomes fixed. | 
|  | if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) | 
|  | && !matches!(ty.kind(Interner), TyKind::Array(..)) | 
|  | { | 
|  | return ty; | 
|  | } | 
|  | let mut table = unify::InferenceTable::new(db, trait_env); | 
|  |  | 
|  | let ty_with_vars = table.normalize_associated_types_in(ty); | 
|  | table.select_obligations_where_possible(); | 
|  | table.propagate_diverging_flag(); | 
|  | table.resolve_completely(ty_with_vars) | 
|  | } | 
|  |  | 
|  | /// Binding modes inferred for patterns. | 
|  | /// <https://doc.rust-lang.org/reference/patterns.html#binding-modes> | 
|  | #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] | 
|  | pub enum BindingMode { | 
|  | #[default] | 
|  | Move, | 
|  | Ref(Mutability), | 
|  | } | 
|  |  | 
|  | impl BindingMode { | 
|  | fn convert(annotation: BindingAnnotation) -> BindingMode { | 
|  | match annotation { | 
|  | BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, | 
|  | BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not), | 
|  | BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: Remove this `InferOk`, switch all code to the second one, that uses `Obligation` instead of `Goal`. | 
|  | #[derive(Debug)] | 
|  | pub(crate) struct InferOk<'db, T> { | 
|  | #[allow(dead_code)] | 
|  | value: T, | 
|  | goals: Vec<next_solver::Goal<'db, next_solver::Predicate<'db>>>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 
|  | pub enum InferenceTyDiagnosticSource { | 
|  | /// Diagnostics that come from types in the body. | 
|  | Body, | 
|  | /// Diagnostics that come from types in fn parameters/return type, or static & const types. | 
|  | Signature, | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | pub(crate) struct TypeError; | 
|  | pub(crate) type InferResult<'db, T> = Result<InferOk<'db, T>, TypeError>; | 
|  |  | 
|  | #[derive(Debug, PartialEq, Eq, Clone)] | 
|  | pub enum InferenceDiagnostic { | 
|  | NoSuchField { | 
|  | field: ExprOrPatId, | 
|  | private: Option<LocalFieldId>, | 
|  | variant: VariantId, | 
|  | }, | 
|  | PrivateField { | 
|  | expr: ExprId, | 
|  | field: FieldId, | 
|  | }, | 
|  | PrivateAssocItem { | 
|  | id: ExprOrPatId, | 
|  | item: AssocItemId, | 
|  | }, | 
|  | UnresolvedField { | 
|  | expr: ExprId, | 
|  | receiver: Ty, | 
|  | name: Name, | 
|  | method_with_same_name_exists: bool, | 
|  | }, | 
|  | UnresolvedMethodCall { | 
|  | expr: ExprId, | 
|  | receiver: Ty, | 
|  | name: Name, | 
|  | /// Contains the type the field resolves to | 
|  | field_with_same_name: Option<Ty>, | 
|  | assoc_func_with_same_name: Option<FunctionId>, | 
|  | }, | 
|  | UnresolvedAssocItem { | 
|  | id: ExprOrPatId, | 
|  | }, | 
|  | UnresolvedIdent { | 
|  | id: ExprOrPatId, | 
|  | }, | 
|  | // FIXME: This should be emitted in body lowering | 
|  | BreakOutsideOfLoop { | 
|  | expr: ExprId, | 
|  | is_break: bool, | 
|  | bad_value_break: bool, | 
|  | }, | 
|  | MismatchedArgCount { | 
|  | call_expr: ExprId, | 
|  | expected: usize, | 
|  | found: usize, | 
|  | }, | 
|  | MismatchedTupleStructPatArgCount { | 
|  | pat: ExprOrPatId, | 
|  | expected: usize, | 
|  | found: usize, | 
|  | }, | 
|  | ExpectedFunction { | 
|  | call_expr: ExprId, | 
|  | found: Ty, | 
|  | }, | 
|  | TypedHole { | 
|  | expr: ExprId, | 
|  | expected: Ty, | 
|  | }, | 
|  | CastToUnsized { | 
|  | expr: ExprId, | 
|  | cast_ty: Ty, | 
|  | }, | 
|  | InvalidCast { | 
|  | expr: ExprId, | 
|  | error: CastError, | 
|  | expr_ty: Ty, | 
|  | cast_ty: Ty, | 
|  | }, | 
|  | TyDiagnostic { | 
|  | source: InferenceTyDiagnosticSource, | 
|  | diag: TyLoweringDiagnostic, | 
|  | }, | 
|  | PathDiagnostic { | 
|  | node: ExprOrPatId, | 
|  | diag: PathLoweringDiagnostic, | 
|  | }, | 
|  | MethodCallIncorrectGenericsLen { | 
|  | expr: ExprId, | 
|  | provided_count: u32, | 
|  | expected_count: u32, | 
|  | kind: IncorrectGenericsLenKind, | 
|  | def: GenericDefId, | 
|  | }, | 
|  | MethodCallIncorrectGenericsOrder { | 
|  | expr: ExprId, | 
|  | param_id: GenericParamId, | 
|  | arg_idx: u32, | 
|  | /// Whether the `GenericArgs` contains a `Self` arg. | 
|  | has_self_arg: bool, | 
|  | }, | 
|  | } | 
|  |  | 
|  | /// A mismatch between an expected and an inferred type. | 
|  | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 
|  | pub struct TypeMismatch { | 
|  | pub expected: Ty, | 
|  | pub actual: Ty, | 
|  | } | 
|  |  | 
|  | #[derive(Clone, PartialEq, Eq, Debug)] | 
|  | struct InternedStandardTypes { | 
|  | unknown: Ty, | 
|  | bool_: Ty, | 
|  | unit: Ty, | 
|  | never: Ty, | 
|  | } | 
|  |  | 
|  | impl Default for InternedStandardTypes { | 
|  | fn default() -> Self { | 
|  | InternedStandardTypes { | 
|  | unknown: TyKind::Error.intern(Interner), | 
|  | bool_: TyKind::Scalar(Scalar::Bool).intern(Interner), | 
|  | unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), | 
|  | never: TyKind::Never.intern(Interner), | 
|  | } | 
|  | } | 
|  | } | 
|  | /// Represents coercing a value to a different type of value. | 
|  | /// | 
|  | /// We transform values by following a number of `Adjust` steps in order. | 
|  | /// See the documentation on variants of `Adjust` for more details. | 
|  | /// | 
|  | /// Here are some common scenarios: | 
|  | /// | 
|  | /// 1. The simplest cases are where a pointer is not adjusted fat vs thin. | 
|  | ///    Here the pointer will be dereferenced N times (where a dereference can | 
|  | ///    happen to raw or borrowed pointers or any smart pointer which implements | 
|  | ///    Deref, including Box<_>). The types of dereferences is given by | 
|  | ///    `autoderefs`. It can then be auto-referenced zero or one times, indicated | 
|  | ///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is | 
|  | ///    `false`. | 
|  | /// | 
|  | /// 2. A thin-to-fat coercion involves unsizing the underlying data. We start | 
|  | ///    with a thin pointer, deref a number of times, unsize the underlying data, | 
|  | ///    then autoref. The 'unsize' phase may change a fixed length array to a | 
|  | ///    dynamically sized one, a concrete object to a trait object, or statically | 
|  | ///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is | 
|  | ///    represented by: | 
|  | /// | 
|  | ///    ```ignore | 
|  | ///    Deref(None) -> [i32; 4], | 
|  | ///    Borrow(AutoBorrow::Ref) -> &[i32; 4], | 
|  | ///    Unsize -> &[i32], | 
|  | ///    ``` | 
|  | /// | 
|  | ///    Note that for a struct, the 'deep' unsizing of the struct is not recorded. | 
|  | ///    E.g., `struct Foo<T> { it: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> | 
|  | ///    The autoderef and -ref are the same as in the above example, but the type | 
|  | ///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about | 
|  | ///    the underlying conversions from `[i32; 4]` to `[i32]`. | 
|  | /// | 
|  | /// 3. Coercing a `Box<T>` to `Box<dyn Trait>` is an interesting special case. In | 
|  | ///    that case, we have the pointer we need coming in, so there are no | 
|  | ///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation. | 
|  | ///    At some point, of course, `Box` should move out of the compiler, in which | 
|  | ///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> | 
|  | ///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. | 
|  | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 
|  | pub struct Adjustment { | 
|  | pub kind: Adjust, | 
|  | pub target: Ty, | 
|  | } | 
|  |  | 
|  | impl Adjustment { | 
|  | pub fn borrow(m: Mutability, ty: Ty, lt: Lifetime) -> Self { | 
|  | let ty = TyKind::Ref(m, lt.clone(), ty).intern(Interner); | 
|  | Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(lt, m)), target: ty } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// At least for initial deployment, we want to limit two-phase borrows to | 
|  | /// only a few specific cases. Right now, those are mostly "things that desugar" | 
|  | /// into method calls: | 
|  | /// - using `x.some_method()` syntax, where some_method takes `&mut self`, | 
|  | /// - using `Foo::some_method(&mut x, ...)` syntax, | 
|  | /// - binary assignment operators (`+=`, `-=`, `*=`, etc.). | 
|  | /// | 
|  | /// Anything else should be rejected until generalized two-phase borrow support | 
|  | /// is implemented. Right now, dataflow can't handle the general case where there | 
|  | /// is more than one use of a mutable borrow, and we don't want to accept too much | 
|  | /// new code via two-phase borrows, so we try to limit where we create two-phase | 
|  | /// capable mutable borrows. | 
|  | /// See #49434 for tracking. | 
|  | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 
|  | pub(crate) enum AllowTwoPhase { | 
|  | // FIXME: We should use this when appropriate. | 
|  | Yes, | 
|  | No, | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 
|  | pub enum Adjust { | 
|  | /// Go from ! to any type. | 
|  | NeverToAny, | 
|  | /// Dereference once, producing a place. | 
|  | Deref(Option<OverloadedDeref>), | 
|  | /// Take the address and produce either a `&` or `*` pointer. | 
|  | Borrow(AutoBorrow), | 
|  | Pointer(PointerCast), | 
|  | } | 
|  |  | 
|  | /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` | 
|  | /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`. | 
|  | /// The target type is `U` in both cases, with the region and mutability | 
|  | /// being those shared by both the receiver and the returned reference. | 
|  | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 
|  | pub struct OverloadedDeref(pub Option<Mutability>); | 
|  |  | 
|  | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 
|  | pub enum AutoBorrow { | 
|  | /// Converts from T to &T. | 
|  | Ref(Lifetime, Mutability), | 
|  | /// Converts from T to *T. | 
|  | RawPtr(Mutability), | 
|  | } | 
|  |  | 
|  | impl AutoBorrow { | 
|  | fn mutability(&self) -> Mutability { | 
|  | let (AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) = self; | 
|  | *m | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 
|  | pub enum PointerCast { | 
|  | /// Go from a fn-item type to a fn-pointer type. | 
|  | ReifyFnPointer, | 
|  |  | 
|  | /// Go from a safe fn pointer to an unsafe fn pointer. | 
|  | UnsafeFnPointer, | 
|  |  | 
|  | /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. | 
|  | /// It cannot convert a closure that requires unsafe. | 
|  | ClosureFnPointer(Safety), | 
|  |  | 
|  | /// Go from a mut raw pointer to a const raw pointer. | 
|  | MutToConstPointer, | 
|  |  | 
|  | #[allow(dead_code)] | 
|  | /// Go from `*const [T; N]` to `*const T` | 
|  | ArrayToPointer, | 
|  |  | 
|  | /// Unsize a pointer/reference value, e.g., `&[T; n]` to | 
|  | /// `&[T]`. Note that the source could be a thin or fat pointer. | 
|  | /// This will do things like convert thin pointers to fat | 
|  | /// pointers, or convert structs containing thin pointers to | 
|  | /// structs containing fat pointers, or convert between fat | 
|  | /// pointers. We don't store the details of how the transform is | 
|  | /// done (in fact, we don't know that, because it might depend on | 
|  | /// the precise type parameters). We just store the target | 
|  | /// type. Codegen backends and miri figure out what has to be done | 
|  | /// based on the precise source/target type at hand. | 
|  | Unsize, | 
|  | } | 
|  |  | 
|  | /// The result of type inference: A mapping from expressions and patterns to types. | 
|  | /// | 
|  | /// When you add a field that stores types (including `Substitution` and the like), don't forget | 
|  | /// `resolve_completely()`'ing  them in `InferenceContext::resolve_all()`. Inference variables must | 
|  | /// not appear in the final inference result. | 
|  | #[derive(Clone, PartialEq, Eq, Debug, Default)] | 
|  | pub struct InferenceResult { | 
|  | /// For each method call expr, records the function it resolves to. | 
|  | method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>, | 
|  | /// For each field access expr, records the field it resolves to. | 
|  | field_resolutions: FxHashMap<ExprId, Either<FieldId, TupleFieldId>>, | 
|  | /// For each struct literal or pattern, records the variant it resolves to. | 
|  | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, | 
|  | /// For each associated item record what it resolves to | 
|  | assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Substitution)>, | 
|  | /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in | 
|  | /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of | 
|  | /// that which allows us to resolve a [`TupleFieldId`]s type. | 
|  | tuple_field_access_types: FxHashMap<TupleId, Substitution>, | 
|  | /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. | 
|  | diagnostics: Vec<InferenceDiagnostic>, | 
|  | pub(crate) type_of_expr: ArenaMap<ExprId, Ty>, | 
|  | /// For each pattern record the type it resolves to. | 
|  | /// | 
|  | /// **Note**: When a pattern type is resolved it may still contain | 
|  | /// unresolved or missing subpatterns or subpatterns of mismatched types. | 
|  | pub(crate) type_of_pat: ArenaMap<PatId, Ty>, | 
|  | pub(crate) type_of_binding: ArenaMap<BindingId, Ty>, | 
|  | pub(crate) type_of_rpit: ArenaMap<ImplTraitIdx, Ty>, | 
|  | type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>, | 
|  | /// Whether there are any type-mismatching errors in the result. | 
|  | // FIXME: This isn't as useful as initially thought due to us falling back placeholders to | 
|  | // `TyKind::Error`. | 
|  | // Which will then mark this field. | 
|  | pub(crate) has_errors: bool, | 
|  | /// Interned common types to return references to. | 
|  | // FIXME: Move this into `InferenceContext` | 
|  | standard_types: InternedStandardTypes, | 
|  | /// Stores the types which were implicitly dereferenced in pattern binding modes. | 
|  | pub(crate) pat_adjustments: FxHashMap<PatId, Vec<Ty>>, | 
|  | /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings. | 
|  | /// | 
|  | /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an | 
|  | /// or pattern can have multiple binding modes. For example: | 
|  | /// ``` | 
|  | /// fn foo(mut slice: &[u32]) -> usize { | 
|  | ///     slice = match slice { | 
|  | ///         [0, rest @ ..] | rest => rest, | 
|  | ///     }; | 
|  | ///     0 | 
|  | /// } | 
|  | /// ``` | 
|  | /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`. | 
|  | pub(crate) binding_modes: ArenaMap<PatId, BindingMode>, | 
|  | pub(crate) expr_adjustments: FxHashMap<ExprId, Box<[Adjustment]>>, | 
|  | pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>, | 
|  | // FIXME: remove this field | 
|  | pub mutated_bindings_in_closure: FxHashSet<BindingId>, | 
|  | pub(crate) coercion_casts: FxHashSet<ExprId>, | 
|  | } | 
|  |  | 
|  | impl InferenceResult { | 
|  | pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { | 
|  | self.method_resolutions.get(&expr).cloned() | 
|  | } | 
|  | pub fn field_resolution(&self, expr: ExprId) -> Option<Either<FieldId, TupleFieldId>> { | 
|  | self.field_resolutions.get(&expr).copied() | 
|  | } | 
|  | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { | 
|  | self.variant_resolutions.get(&id.into()).copied() | 
|  | } | 
|  | pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> { | 
|  | self.variant_resolutions.get(&id.into()).copied() | 
|  | } | 
|  | pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> { | 
|  | match id { | 
|  | ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id), | 
|  | ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id), | 
|  | } | 
|  | } | 
|  | pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> { | 
|  | self.assoc_resolutions.get(&id.into()).cloned() | 
|  | } | 
|  | pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> { | 
|  | self.assoc_resolutions.get(&id.into()).cloned() | 
|  | } | 
|  | pub fn assoc_resolutions_for_expr_or_pat( | 
|  | &self, | 
|  | id: ExprOrPatId, | 
|  | ) -> Option<(AssocItemId, Substitution)> { | 
|  | match id { | 
|  | ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id), | 
|  | ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), | 
|  | } | 
|  | } | 
|  | pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> { | 
|  | self.type_mismatches.get(&expr.into()) | 
|  | } | 
|  | pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> { | 
|  | self.type_mismatches.get(&pat.into()) | 
|  | } | 
|  | pub fn type_mismatches(&self) -> impl Iterator<Item = (ExprOrPatId, &TypeMismatch)> { | 
|  | self.type_mismatches.iter().map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch)) | 
|  | } | 
|  | pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> { | 
|  | self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat { | 
|  | ExprOrPatId::ExprId(expr) => Some((expr, mismatch)), | 
|  | _ => None, | 
|  | }) | 
|  | } | 
|  | pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) { | 
|  | self.closure_info.get(closure).unwrap() | 
|  | } | 
|  | pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> { | 
|  | match id { | 
|  | ExprOrPatId::ExprId(id) => self.type_of_expr.get(id), | 
|  | ExprOrPatId::PatId(id) => self.type_of_pat.get(id), | 
|  | } | 
|  | } | 
|  | pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<&Ty> { | 
|  | match self.expr_adjustments.get(&id).and_then(|adjustments| { | 
|  | adjustments | 
|  | .iter() | 
|  | .filter(|adj| { | 
|  | // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140 | 
|  | !matches!( | 
|  | adj, | 
|  | Adjustment { | 
|  | kind: Adjust::NeverToAny, | 
|  | target, | 
|  | } if target.is_never() | 
|  | ) | 
|  | }) | 
|  | .next_back() | 
|  | }) { | 
|  | Some(adjustment) => Some(&adjustment.target), | 
|  | None => self.type_of_expr.get(id), | 
|  | } | 
|  | } | 
|  | pub fn type_of_pat_with_adjust(&self, id: PatId) -> Option<&Ty> { | 
|  | match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { | 
|  | adjusted @ Some(_) => adjusted, | 
|  | None => self.type_of_pat.get(id), | 
|  | } | 
|  | } | 
|  | pub fn is_erroneous(&self) -> bool { | 
|  | self.has_errors && self.type_of_expr.iter().count() == 0 | 
|  | } | 
|  |  | 
|  | pub fn diagnostics(&self) -> &[InferenceDiagnostic] { | 
|  | &self.diagnostics | 
|  | } | 
|  |  | 
|  | pub fn tuple_field_access_type(&self, id: TupleId) -> &Substitution { | 
|  | &self.tuple_field_access_types[&id] | 
|  | } | 
|  |  | 
|  | pub fn pat_adjustment(&self, id: PatId) -> Option<&[Ty]> { | 
|  | self.pat_adjustments.get(&id).map(|it| &**it) | 
|  | } | 
|  |  | 
|  | pub fn expr_adjustment(&self, id: ExprId) -> Option<&[Adjustment]> { | 
|  | self.expr_adjustments.get(&id).map(|it| &**it) | 
|  | } | 
|  |  | 
|  | pub fn binding_mode(&self, id: PatId) -> Option<BindingMode> { | 
|  | self.binding_modes.get(id).copied() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Index<ExprId> for InferenceResult { | 
|  | type Output = Ty; | 
|  |  | 
|  | fn index(&self, expr: ExprId) -> &Ty { | 
|  | self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Index<PatId> for InferenceResult { | 
|  | type Output = Ty; | 
|  |  | 
|  | fn index(&self, pat: PatId) -> &Ty { | 
|  | self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Index<ExprOrPatId> for InferenceResult { | 
|  | type Output = Ty; | 
|  |  | 
|  | fn index(&self, id: ExprOrPatId) -> &Ty { | 
|  | self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Index<BindingId> for InferenceResult { | 
|  | type Output = Ty; | 
|  |  | 
|  | fn index(&self, b: BindingId) -> &Ty { | 
|  | self.type_of_binding.get(b).unwrap_or(&self.standard_types.unknown) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The inference context contains all information needed during type inference. | 
|  | #[derive(Clone, Debug)] | 
|  | pub(crate) struct InferenceContext<'db> { | 
|  | pub(crate) db: &'db dyn HirDatabase, | 
|  | pub(crate) owner: DefWithBodyId, | 
|  | pub(crate) body: &'db Body, | 
|  | /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext | 
|  | /// and resolve the path via its methods. This will ensure proper error reporting. | 
|  | pub(crate) resolver: Resolver<'db>, | 
|  | target_features: OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>, | 
|  | generic_def: GenericDefId, | 
|  | generics: OnceCell<Generics>, | 
|  | table: unify::InferenceTable<'db>, | 
|  | /// The traits in scope, disregarding block modules. This is used for caching purposes. | 
|  | traits_in_scope: FxHashSet<TraitId>, | 
|  | pub(crate) result: InferenceResult, | 
|  | tuple_field_accesses_rev: | 
|  | IndexSet<Substitution, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>, | 
|  | /// The return type of the function being inferred, the closure or async block if we're | 
|  | /// currently within one. | 
|  | /// | 
|  | /// We might consider using a nested inference context for checking | 
|  | /// closures so we can swap all shared things out at once. | 
|  | return_ty: Ty, | 
|  | /// If `Some`, this stores coercion information for returned | 
|  | /// expressions. If `None`, this is in a context where return is | 
|  | /// inappropriate, such as a const expression. | 
|  | return_coercion: Option<DynamicCoerceMany<'db>>, | 
|  | /// The resume type and the yield type, respectively, of the coroutine being inferred. | 
|  | resume_yield_tys: Option<(Ty, Ty)>, | 
|  | diverges: Diverges, | 
|  | breakables: Vec<BreakableContext<'db>>, | 
|  |  | 
|  | /// Whether we are inside the pattern of a destructuring assignment. | 
|  | inside_assignment: bool, | 
|  |  | 
|  | deferred_cast_checks: Vec<CastCheck>, | 
|  |  | 
|  | // fields related to closure capture | 
|  | current_captures: Vec<CapturedItemWithoutTy>, | 
|  | /// A stack that has an entry for each projection in the current capture. | 
|  | /// | 
|  | /// For example, in `a.b.c`, we capture the spans of `a`, `a.b`, and `a.b.c`. | 
|  | /// We do that because sometimes we truncate projections (when a closure captures | 
|  | /// both `a.b` and `a.b.c`), and we want to provide accurate spans in this case. | 
|  | current_capture_span_stack: Vec<MirSpan>, | 
|  | current_closure: Option<InternedClosureId>, | 
|  | /// Stores the list of closure ids that need to be analyzed before this closure. See the | 
|  | /// comment on `InferenceContext::sort_closures` | 
|  | closure_dependencies: FxHashMap<InternedClosureId, Vec<InternedClosureId>>, | 
|  | deferred_closures: FxHashMap<InternedClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>, | 
|  |  | 
|  | diagnostics: Diagnostics, | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Debug)] | 
|  | struct BreakableContext<'db> { | 
|  | /// Whether this context contains at least one break expression. | 
|  | may_break: bool, | 
|  | /// The coercion target of the context. | 
|  | coerce: Option<DynamicCoerceMany<'db>>, | 
|  | /// The optional label of the context. | 
|  | label: Option<LabelId>, | 
|  | kind: BreakableKind, | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Debug)] | 
|  | enum BreakableKind { | 
|  | Block, | 
|  | Loop, | 
|  | /// A border is something like an async block, closure etc. Anything that prevents | 
|  | /// breaking/continuing through | 
|  | Border, | 
|  | } | 
|  |  | 
|  | fn find_breakable<'a, 'db>( | 
|  | ctxs: &'a mut [BreakableContext<'db>], | 
|  | label: Option<LabelId>, | 
|  | ) -> Option<&'a mut BreakableContext<'db>> { | 
|  | let mut ctxs = ctxs | 
|  | .iter_mut() | 
|  | .rev() | 
|  | .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop)); | 
|  | match label { | 
|  | Some(_) => ctxs.find(|ctx| ctx.label == label), | 
|  | None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn find_continuable<'a, 'db>( | 
|  | ctxs: &'a mut [BreakableContext<'db>], | 
|  | label: Option<LabelId>, | 
|  | ) -> Option<&'a mut BreakableContext<'db>> { | 
|  | match label { | 
|  | Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)), | 
|  | None => find_breakable(ctxs, label), | 
|  | } | 
|  | } | 
|  |  | 
|  | enum ImplTraitReplacingMode { | 
|  | ReturnPosition(FxHashSet<Ty>), | 
|  | TypeAlias, | 
|  | } | 
|  |  | 
|  | impl<'db> InferenceContext<'db> { | 
|  | fn new( | 
|  | db: &'db dyn HirDatabase, | 
|  | owner: DefWithBodyId, | 
|  | body: &'db Body, | 
|  | resolver: Resolver<'db>, | 
|  | ) -> Self { | 
|  | let trait_env = db.trait_environment_for_body(owner); | 
|  | InferenceContext { | 
|  | target_features: OnceCell::new(), | 
|  | generics: OnceCell::new(), | 
|  | result: InferenceResult::default(), | 
|  | table: unify::InferenceTable::new(db, trait_env), | 
|  | tuple_field_accesses_rev: Default::default(), | 
|  | return_ty: TyKind::Error.intern(Interner), // set in collect_* calls | 
|  | resume_yield_tys: None, | 
|  | return_coercion: None, | 
|  | db, | 
|  | owner, | 
|  | generic_def: match owner { | 
|  | DefWithBodyId::FunctionId(it) => it.into(), | 
|  | DefWithBodyId::StaticId(it) => it.into(), | 
|  | DefWithBodyId::ConstId(it) => it.into(), | 
|  | DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), | 
|  | }, | 
|  | body, | 
|  | traits_in_scope: resolver.traits_in_scope(db), | 
|  | resolver, | 
|  | diverges: Diverges::Maybe, | 
|  | breakables: Vec::new(), | 
|  | deferred_cast_checks: Vec::new(), | 
|  | current_captures: Vec::new(), | 
|  | current_capture_span_stack: Vec::new(), | 
|  | current_closure: None, | 
|  | deferred_closures: FxHashMap::default(), | 
|  | closure_dependencies: FxHashMap::default(), | 
|  | inside_assignment: false, | 
|  | diagnostics: Diagnostics::default(), | 
|  | } | 
|  | } | 
|  |  | 
|  | pub(crate) fn generics(&self) -> &Generics { | 
|  | self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn krate(&self) -> Crate { | 
|  | self.resolver.krate() | 
|  | } | 
|  |  | 
|  | fn target_features<'a>( | 
|  | db: &dyn HirDatabase, | 
|  | target_features: &'a OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>, | 
|  | owner: DefWithBodyId, | 
|  | krate: Crate, | 
|  | ) -> (&'a TargetFeatures, TargetFeatureIsSafeInTarget) { | 
|  | let (target_features, target_feature_is_safe) = target_features.get_or_init(|| { | 
|  | let target_features = match owner { | 
|  | DefWithBodyId::FunctionId(id) => TargetFeatures::from_attrs(&db.attrs(id.into())), | 
|  | _ => TargetFeatures::default(), | 
|  | }; | 
|  | let target_feature_is_safe = match &krate.workspace_data(db).target { | 
|  | Ok(target) => crate::utils::target_feature_is_safe_in_target(target), | 
|  | Err(_) => TargetFeatureIsSafeInTarget::No, | 
|  | }; | 
|  | (target_features, target_feature_is_safe) | 
|  | }); | 
|  | (target_features, *target_feature_is_safe) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | pub(crate) fn set_tainted_by_errors(&mut self) { | 
|  | self.result.has_errors = true; | 
|  | } | 
|  |  | 
|  | // FIXME: This function should be private in module. It is currently only used in the consteval, since we need | 
|  | // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you | 
|  | // used this function for another workaround, mention it here. If you really need this function and believe that | 
|  | // there is no problem in it being `pub(crate)`, remove this comment. | 
|  | pub(crate) fn resolve_all(mut self) -> InferenceResult { | 
|  | self.table.select_obligations_where_possible(); | 
|  | self.table.fallback_if_possible(); | 
|  |  | 
|  | // Comment from rustc: | 
|  | // Even though coercion casts provide type hints, we check casts after fallback for | 
|  | // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. | 
|  | let cast_checks = std::mem::take(&mut self.deferred_cast_checks); | 
|  | for mut cast in cast_checks.into_iter() { | 
|  | if let Err(diag) = cast.check(&mut self) { | 
|  | self.diagnostics.push(diag); | 
|  | } | 
|  | } | 
|  |  | 
|  | let InferenceContext { | 
|  | mut table, mut result, tuple_field_accesses_rev, diagnostics, .. | 
|  | } = self; | 
|  | let mut diagnostics = diagnostics.finish(); | 
|  | // Destructure every single field so whenever new fields are added to `InferenceResult` we | 
|  | // don't forget to handle them here. | 
|  | let InferenceResult { | 
|  | method_resolutions, | 
|  | field_resolutions: _, | 
|  | variant_resolutions: _, | 
|  | assoc_resolutions, | 
|  | type_of_expr, | 
|  | type_of_pat, | 
|  | type_of_binding, | 
|  | type_of_rpit, | 
|  | type_mismatches, | 
|  | has_errors, | 
|  | standard_types: _, | 
|  | pat_adjustments, | 
|  | binding_modes: _, | 
|  | expr_adjustments, | 
|  | // Types in `closure_info` have already been `resolve_completely()`'d during | 
|  | // `InferenceContext::infer_closures()` (in `HirPlace::ty()` specifically), so no need | 
|  | // to resolve them here. | 
|  | closure_info: _, | 
|  | mutated_bindings_in_closure: _, | 
|  | tuple_field_access_types: _, | 
|  | coercion_casts: _, | 
|  | diagnostics: _, | 
|  | } = &mut result; | 
|  |  | 
|  | // FIXME resolve obligations as well (use Guidance if necessary) | 
|  | table.select_obligations_where_possible(); | 
|  |  | 
|  | // make sure diverging type variables are marked as such | 
|  | table.propagate_diverging_flag(); | 
|  | for ty in type_of_expr.values_mut() { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | *has_errors = *has_errors || ty.contains_unknown(); | 
|  | } | 
|  | type_of_expr.shrink_to_fit(); | 
|  | for ty in type_of_pat.values_mut() { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | *has_errors = *has_errors || ty.contains_unknown(); | 
|  | } | 
|  | type_of_pat.shrink_to_fit(); | 
|  | for ty in type_of_binding.values_mut() { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | *has_errors = *has_errors || ty.contains_unknown(); | 
|  | } | 
|  | type_of_binding.shrink_to_fit(); | 
|  | for ty in type_of_rpit.values_mut() { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | *has_errors = *has_errors || ty.contains_unknown(); | 
|  | } | 
|  | type_of_rpit.shrink_to_fit(); | 
|  |  | 
|  | *has_errors |= !type_mismatches.is_empty(); | 
|  |  | 
|  | type_mismatches.retain(|_, mismatch| { | 
|  | mismatch.expected = table.resolve_completely(mismatch.expected.clone()); | 
|  | mismatch.actual = table.resolve_completely(mismatch.actual.clone()); | 
|  | chalk_ir::zip::Zip::zip_with( | 
|  | &mut UnknownMismatch(self.db), | 
|  | Variance::Invariant, | 
|  | &mismatch.expected, | 
|  | &mismatch.actual, | 
|  | ) | 
|  | .is_ok() | 
|  | }); | 
|  | type_mismatches.shrink_to_fit(); | 
|  | diagnostics.retain_mut(|diagnostic| { | 
|  | use InferenceDiagnostic::*; | 
|  | match diagnostic { | 
|  | ExpectedFunction { found: ty, .. } | 
|  | | UnresolvedField { receiver: ty, .. } | 
|  | | UnresolvedMethodCall { receiver: ty, .. } => { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | // FIXME: Remove this when we are on par with rustc in terms of inference | 
|  | if ty.contains_unknown() { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic | 
|  | && let Some(ty) = field_with_same_name | 
|  | { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | if ty.contains_unknown() { | 
|  | *field_with_same_name = None; | 
|  | } | 
|  | } | 
|  | } | 
|  | TypedHole { expected: ty, .. } => { | 
|  | *ty = table.resolve_completely(ty.clone()); | 
|  | } | 
|  | _ => (), | 
|  | } | 
|  | true | 
|  | }); | 
|  | diagnostics.shrink_to_fit(); | 
|  | for (_, subst) in method_resolutions.values_mut() { | 
|  | *subst = | 
|  | table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); | 
|  | *has_errors = | 
|  | *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); | 
|  | } | 
|  | method_resolutions.shrink_to_fit(); | 
|  | for (_, subst) in assoc_resolutions.values_mut() { | 
|  | *subst = | 
|  | table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst.clone()); | 
|  | *has_errors = | 
|  | *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); | 
|  | } | 
|  | assoc_resolutions.shrink_to_fit(); | 
|  | for adjustment in expr_adjustments.values_mut().flatten() { | 
|  | adjustment.target = table.resolve_completely(adjustment.target.clone()); | 
|  | *has_errors = *has_errors || adjustment.target.contains_unknown(); | 
|  | } | 
|  | expr_adjustments.shrink_to_fit(); | 
|  | for adjustment in pat_adjustments.values_mut().flatten() { | 
|  | *adjustment = table.resolve_completely(adjustment.clone()); | 
|  | *has_errors = *has_errors || adjustment.contains_unknown(); | 
|  | } | 
|  | pat_adjustments.shrink_to_fit(); | 
|  | result.tuple_field_access_types = tuple_field_accesses_rev | 
|  | .into_iter() | 
|  | .enumerate() | 
|  | .map(|(idx, subst)| { | 
|  | ( | 
|  | TupleId(idx as u32), | 
|  | table.resolve_completely::<_, crate::next_solver::GenericArgs<'db>>(subst), | 
|  | ) | 
|  | }) | 
|  | .inspect(|(_, subst)| { | 
|  | *has_errors = | 
|  | *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); | 
|  | }) | 
|  | .collect(); | 
|  | result.tuple_field_access_types.shrink_to_fit(); | 
|  |  | 
|  | result.diagnostics = diagnostics; | 
|  |  | 
|  | result | 
|  | } | 
|  |  | 
|  | fn collect_const(&mut self, id: ConstId, data: &ConstSignature) { | 
|  | let return_ty = self.make_ty( | 
|  | data.type_ref, | 
|  | &data.store, | 
|  | InferenceTyDiagnosticSource::Signature, | 
|  | LifetimeElisionKind::for_const(id.loc(self.db).container), | 
|  | ); | 
|  |  | 
|  | // Constants might be defining usage sites of TAITs. | 
|  | self.make_tait_coercion_table(iter::once(&return_ty)); | 
|  |  | 
|  | self.return_ty = return_ty; | 
|  | } | 
|  |  | 
|  | fn collect_static(&mut self, data: &StaticSignature) { | 
|  | let return_ty = self.make_ty( | 
|  | data.type_ref, | 
|  | &data.store, | 
|  | InferenceTyDiagnosticSource::Signature, | 
|  | LifetimeElisionKind::Elided(static_lifetime()), | 
|  | ); | 
|  |  | 
|  | // Statics might be defining usage sites of TAITs. | 
|  | self.make_tait_coercion_table(iter::once(&return_ty)); | 
|  |  | 
|  | self.return_ty = return_ty; | 
|  | } | 
|  |  | 
|  | fn collect_fn(&mut self, func: FunctionId) { | 
|  | let data = self.db.function_signature(func); | 
|  | let mut param_tys = self.with_ty_lowering( | 
|  | &data.store, | 
|  | InferenceTyDiagnosticSource::Signature, | 
|  | LifetimeElisionKind::for_fn_params(&data), | 
|  | |ctx| { | 
|  | ctx.type_param_mode(ParamLoweringMode::Placeholder); | 
|  | data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>() | 
|  | }, | 
|  | ); | 
|  |  | 
|  | // Check if function contains a va_list, if it does then we append it to the parameter types | 
|  | // that are collected from the function data | 
|  | if data.is_varargs() { | 
|  | let va_list_ty = match self.resolve_va_list() { | 
|  | Some(va_list) => TyBuilder::adt(self.db, va_list) | 
|  | .fill_with_defaults(self.db, || self.table.new_type_var()) | 
|  | .build(), | 
|  | None => self.err_ty(), | 
|  | }; | 
|  |  | 
|  | param_tys.push(va_list_ty); | 
|  | } | 
|  | let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var())); | 
|  | if let Some(self_param) = self.body.self_param | 
|  | && let Some(ty) = param_tys.next() | 
|  | { | 
|  | let ty = self.process_user_written_ty(ty); | 
|  | self.write_binding_ty(self_param, ty); | 
|  | } | 
|  | let mut tait_candidates = FxHashSet::default(); | 
|  | for (ty, pat) in param_tys.zip(&*self.body.params) { | 
|  | let ty = self.process_user_written_ty(ty); | 
|  |  | 
|  | self.infer_top_pat(*pat, &ty, None); | 
|  | if ty | 
|  | .data(Interner) | 
|  | .flags | 
|  | .intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER)) | 
|  | { | 
|  | tait_candidates.insert(ty); | 
|  | } | 
|  | } | 
|  | let return_ty = match data.ret_type { | 
|  | Some(return_ty) => { | 
|  | let return_ty = self.with_ty_lowering( | 
|  | &data.store, | 
|  | InferenceTyDiagnosticSource::Signature, | 
|  | LifetimeElisionKind::for_fn_ret(), | 
|  | |ctx| { | 
|  | ctx.type_param_mode(ParamLoweringMode::Placeholder) | 
|  | .impl_trait_mode(ImplTraitLoweringMode::Opaque); | 
|  | ctx.lower_ty(return_ty) | 
|  | }, | 
|  | ); | 
|  | let return_ty = self.insert_type_vars(return_ty); | 
|  | if let Some(rpits) = self.db.return_type_impl_traits(func) { | 
|  | // RPIT opaque types use substitution of their parent function. | 
|  | let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); | 
|  | let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default()); | 
|  | let result = self.insert_inference_vars_for_impl_trait( | 
|  | return_ty, | 
|  | fn_placeholders, | 
|  | &mut mode, | 
|  | ); | 
|  | if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { | 
|  | tait_candidates.extend(taits); | 
|  | } | 
|  | let rpits = rpits.skip_binders(); | 
|  | for (id, _) in rpits.impl_traits.iter() { | 
|  | if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { | 
|  | never!("Missed RPIT in `insert_inference_vars_for_rpit`"); | 
|  | e.insert(TyKind::Error.intern(Interner)); | 
|  | } | 
|  | } | 
|  | result | 
|  | } else { | 
|  | return_ty | 
|  | } | 
|  | } | 
|  | None => self.result.standard_types.unit.clone(), | 
|  | }; | 
|  |  | 
|  | self.return_ty = self.process_user_written_ty(return_ty); | 
|  | self.return_coercion = | 
|  | Some(CoerceMany::new(self.return_ty.to_nextsolver(self.table.interner))); | 
|  |  | 
|  | // Functions might be defining usage sites of TAITs. | 
|  | // To define an TAITs, that TAIT must appear in the function's signatures. | 
|  | // So, it suffices to check for params and return types. | 
|  | fold_tys( | 
|  | self.return_ty.clone(), | 
|  | |ty, _| { | 
|  | match ty.kind(Interner) { | 
|  | TyKind::OpaqueType(..) | 
|  | | TyKind::Alias(AliasTy::Opaque(..)) | 
|  | | TyKind::InferenceVar(..) => { | 
|  | tait_candidates.insert(self.return_ty.clone()); | 
|  | } | 
|  | _ => {} | 
|  | } | 
|  | ty | 
|  | }, | 
|  | DebruijnIndex::INNERMOST, | 
|  | ); | 
|  |  | 
|  | self.make_tait_coercion_table(tait_candidates.iter()); | 
|  | } | 
|  |  | 
|  | fn insert_inference_vars_for_impl_trait<T>( | 
|  | &mut self, | 
|  | t: T, | 
|  | placeholders: Substitution, | 
|  | mode: &mut ImplTraitReplacingMode, | 
|  | ) -> T | 
|  | where | 
|  | T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>, | 
|  | { | 
|  | fold_tys( | 
|  | t, | 
|  | |ty, _| { | 
|  | let ty = self.table.structurally_resolve_type(&ty); | 
|  | let opaque_ty_id = match ty.kind(Interner) { | 
|  | TyKind::OpaqueType(opaque_ty_id, _) | 
|  | | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id, .. })) => { | 
|  | *opaque_ty_id | 
|  | } | 
|  | _ => return ty, | 
|  | }; | 
|  | let (impl_traits, idx) = | 
|  | match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { | 
|  | // We don't replace opaque types from other kind with inference vars | 
|  | // because `insert_inference_vars_for_impl_traits` for each kinds | 
|  | // and unreplaced opaque types of other kind are resolved while | 
|  | // inferencing because of `tait_coercion_table`. | 
|  | // Moreover, calling `insert_inference_vars_for_impl_traits` with same | 
|  | // `placeholders` for other kind may cause trouble because | 
|  | // the substs for the bounds of each impl traits do not match | 
|  | ImplTraitId::ReturnTypeImplTrait(def, idx) => { | 
|  | if matches!(mode, ImplTraitReplacingMode::TypeAlias) { | 
|  | // RPITs don't have `tait_coercion_table`, so use inserted inference | 
|  | // vars for them. | 
|  | if let Some(ty) = self.result.type_of_rpit.get(idx) { | 
|  | return ty.clone(); | 
|  | } | 
|  | return ty; | 
|  | } | 
|  | (self.db.return_type_impl_traits(def), idx) | 
|  | } | 
|  | ImplTraitId::TypeAliasImplTrait(def, idx) => { | 
|  | if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { | 
|  | // Gather TAITs while replacing RPITs because TAITs inside RPITs | 
|  | // may not visited while replacing TAITs | 
|  | taits.insert(ty.clone()); | 
|  | return ty; | 
|  | } | 
|  | (self.db.type_alias_impl_traits(def), idx) | 
|  | } | 
|  | _ => unreachable!(), | 
|  | }; | 
|  | let Some(impl_traits) = impl_traits else { | 
|  | return ty; | 
|  | }; | 
|  | let bounds = (*impl_traits) | 
|  | .map_ref(|its| its.impl_traits[idx].bounds.map_ref(|it| it.iter())); | 
|  | let var = self.table.new_type_var(); | 
|  | let var_subst = Substitution::from1(Interner, var.clone()); | 
|  | for bound in bounds { | 
|  | let predicate = bound.map(|it| it.cloned()); | 
|  | let predicate = predicate.substitute(Interner, &placeholders); | 
|  | let (var_predicate, binders) = | 
|  | predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); | 
|  | always!(binders.is_empty(Interner)); // quantified where clauses not yet handled | 
|  | let var_predicate = self.insert_inference_vars_for_impl_trait( | 
|  | var_predicate, | 
|  | placeholders.clone(), | 
|  | mode, | 
|  | ); | 
|  | self.push_obligation(var_predicate.cast(Interner)); | 
|  | } | 
|  | self.result.type_of_rpit.insert(idx, var.clone()); | 
|  | var | 
|  | }, | 
|  | DebruijnIndex::INNERMOST, | 
|  | ) | 
|  | } | 
|  |  | 
|  | /// The coercion of a non-inference var into an opaque type should fail, | 
|  | /// but not in the defining sites of the TAITs. | 
|  | /// In such cases, we insert an proxy inference var for each TAIT, | 
|  | /// and coerce into it instead of TAIT itself. | 
|  | /// | 
|  | /// The inference var stretagy is effective because; | 
|  | /// | 
|  | /// - It can still unify types that coerced into TAITs | 
|  | /// - We are pushing `impl Trait` bounds into it | 
|  | /// | 
|  | /// This function inserts a map that maps the opaque type to that proxy inference var. | 
|  | fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator<Item = &'b Ty>) { | 
|  | struct TypeAliasImplTraitCollector<'a, 'b> { | 
|  | db: &'b dyn HirDatabase, | 
|  | table: &'b mut InferenceTable<'a>, | 
|  | assocs: FxHashMap<OpaqueTyId, (ImplId, Ty)>, | 
|  | non_assocs: FxHashMap<OpaqueTyId, Ty>, | 
|  | } | 
|  |  | 
|  | impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> { | 
|  | type BreakTy = (); | 
|  |  | 
|  | fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { | 
|  | self | 
|  | } | 
|  |  | 
|  | fn interner(&self) -> Interner { | 
|  | Interner | 
|  | } | 
|  |  | 
|  | fn visit_ty( | 
|  | &mut self, | 
|  | ty: &chalk_ir::Ty<Interner>, | 
|  | outer_binder: DebruijnIndex, | 
|  | ) -> std::ops::ControlFlow<Self::BreakTy> { | 
|  | let ty = self.table.structurally_resolve_type(ty); | 
|  |  | 
|  | if let TyKind::OpaqueType(id, _) | 
|  | | TyKind::Alias(AliasTy::Opaque(crate::OpaqueTy { opaque_ty_id: id, .. })) = | 
|  | ty.kind(Interner) | 
|  | && let ImplTraitId::TypeAliasImplTrait(alias_id, _) = | 
|  | self.db.lookup_intern_impl_trait_id((*id).into()) | 
|  | { | 
|  | let loc = self.db.lookup_intern_type_alias(alias_id); | 
|  | match loc.container { | 
|  | ItemContainerId::ImplId(impl_id) => { | 
|  | self.assocs.insert(*id, (impl_id, ty.clone())); | 
|  | } | 
|  | ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => { | 
|  | self.non_assocs.insert(*id, ty.clone()); | 
|  | } | 
|  | _ => {} | 
|  | } | 
|  | } | 
|  |  | 
|  | ty.super_visit_with(self, outer_binder) | 
|  | } | 
|  | } | 
|  |  | 
|  | let mut collector = TypeAliasImplTraitCollector { | 
|  | db: self.db, | 
|  | table: &mut self.table, | 
|  | assocs: FxHashMap::default(), | 
|  | non_assocs: FxHashMap::default(), | 
|  | }; | 
|  | for ty in tait_candidates { | 
|  | _ = ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); | 
|  | } | 
|  |  | 
|  | // Non-assoc TAITs can be define-used everywhere as long as they are | 
|  | // in function signatures or const types, etc | 
|  | let mut taits = collector.non_assocs; | 
|  |  | 
|  | // assoc TAITs(ATPITs) can be only define-used inside their impl block. | 
|  | // They cannot be define-used in inner items like in the following; | 
|  | // | 
|  | // ``` | 
|  | // impl Trait for Struct { | 
|  | //     type Assoc = impl Default; | 
|  | // | 
|  | //     fn assoc_fn() -> Self::Assoc { | 
|  | //         let foo: Self::Assoc = true; // Allowed here | 
|  | // | 
|  | //         fn inner() -> Self::Assoc { | 
|  | //              false                   // Not allowed here | 
|  | //         } | 
|  | // | 
|  | //         foo | 
|  | //     } | 
|  | // } | 
|  | // ``` | 
|  | let impl_id = match self.owner { | 
|  | DefWithBodyId::FunctionId(it) => { | 
|  | let loc = self.db.lookup_intern_function(it); | 
|  | if let ItemContainerId::ImplId(impl_id) = loc.container { | 
|  | Some(impl_id) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } | 
|  | DefWithBodyId::ConstId(it) => { | 
|  | let loc = self.db.lookup_intern_const(it); | 
|  | if let ItemContainerId::ImplId(impl_id) = loc.container { | 
|  | Some(impl_id) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } | 
|  | _ => None, | 
|  | }; | 
|  |  | 
|  | if let Some(impl_id) = impl_id { | 
|  | taits.extend(collector.assocs.into_iter().filter_map(|(id, (impl_, ty))| { | 
|  | if impl_ == impl_id { Some((id, ty)) } else { None } | 
|  | })); | 
|  | } | 
|  |  | 
|  | let tait_coercion_table: FxHashMap<_, _> = taits | 
|  | .into_iter() | 
|  | .filter_map(|(id, ty)| { | 
|  | if let ImplTraitId::TypeAliasImplTrait(alias_id, _) = | 
|  | self.db.lookup_intern_impl_trait_id(id.into()) | 
|  | { | 
|  | let subst = TyBuilder::placeholder_subst(self.db, alias_id); | 
|  | let ty = self.insert_inference_vars_for_impl_trait( | 
|  | ty, | 
|  | subst, | 
|  | &mut ImplTraitReplacingMode::TypeAlias, | 
|  | ); | 
|  | Some((id, ty)) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | }) | 
|  | .collect(); | 
|  |  | 
|  | if !tait_coercion_table.is_empty() { | 
|  | self.table.tait_coercion_table = Some(tait_coercion_table); | 
|  | } | 
|  | } | 
|  |  | 
|  | fn infer_body(&mut self) { | 
|  | match self.return_coercion { | 
|  | Some(_) => self.infer_return(self.body.body_expr), | 
|  | None => { | 
|  | _ = self.infer_expr_coerce( | 
|  | self.body.body_expr, | 
|  | &Expectation::has_type(self.return_ty.clone()), | 
|  | ExprIsRead::Yes, | 
|  | ) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) { | 
|  | self.result.type_of_expr.insert(expr, ty); | 
|  | } | 
|  |  | 
|  | fn write_expr_adj(&mut self, expr: ExprId, adjustments: Box<[Adjustment]>) { | 
|  | if adjustments.is_empty() { | 
|  | return; | 
|  | } | 
|  | match self.result.expr_adjustments.entry(expr) { | 
|  | std::collections::hash_map::Entry::Occupied(mut entry) => { | 
|  | match (&mut entry.get_mut()[..], &adjustments[..]) { | 
|  | ( | 
|  | [Adjustment { kind: Adjust::NeverToAny, target }], | 
|  | [.., Adjustment { target: new_target, .. }], | 
|  | ) => { | 
|  | // NeverToAny coercion can target any type, so instead of adding a new | 
|  | // adjustment on top we can change the target. | 
|  | *target = new_target.clone(); | 
|  | } | 
|  | _ => { | 
|  | *entry.get_mut() = adjustments; | 
|  | } | 
|  | } | 
|  | } | 
|  | std::collections::hash_map::Entry::Vacant(entry) => { | 
|  | entry.insert(adjustments); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn write_pat_adj(&mut self, pat: PatId, adjustments: Box<[Ty]>) { | 
|  | if adjustments.is_empty() { | 
|  | return; | 
|  | } | 
|  | self.result.pat_adjustments.entry(pat).or_default().extend(adjustments); | 
|  | } | 
|  |  | 
|  | fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { | 
|  | self.result.method_resolutions.insert(expr, (func, subst)); | 
|  | } | 
|  |  | 
|  | fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { | 
|  | self.result.variant_resolutions.insert(id, variant); | 
|  | } | 
|  |  | 
|  | fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId, subs: Substitution) { | 
|  | self.result.assoc_resolutions.insert(id, (item, subs)); | 
|  | } | 
|  |  | 
|  | fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { | 
|  | self.result.type_of_pat.insert(pat, ty); | 
|  | } | 
|  |  | 
|  | fn write_binding_ty(&mut self, id: BindingId, ty: Ty) { | 
|  | self.result.type_of_binding.insert(id, ty); | 
|  | } | 
|  |  | 
|  | fn push_diagnostic(&self, diagnostic: InferenceDiagnostic) { | 
|  | self.diagnostics.push(diagnostic); | 
|  | } | 
|  |  | 
|  | fn with_ty_lowering<R>( | 
|  | &mut self, | 
|  | store: &ExpressionStore, | 
|  | types_source: InferenceTyDiagnosticSource, | 
|  | lifetime_elision: LifetimeElisionKind, | 
|  | f: impl FnOnce(&mut TyLoweringContext<'_>) -> R, | 
|  | ) -> R { | 
|  | let mut ctx = TyLoweringContext::new( | 
|  | self.db, | 
|  | &self.resolver, | 
|  | store, | 
|  | &self.diagnostics, | 
|  | types_source, | 
|  | self.generic_def, | 
|  | lifetime_elision, | 
|  | ); | 
|  | f(&mut ctx) | 
|  | } | 
|  |  | 
|  | fn with_body_ty_lowering<R>(&mut self, f: impl FnOnce(&mut TyLoweringContext<'_>) -> R) -> R { | 
|  | self.with_ty_lowering( | 
|  | self.body, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | LifetimeElisionKind::Infer, | 
|  | f, | 
|  | ) | 
|  | } | 
|  |  | 
|  | fn make_ty( | 
|  | &mut self, | 
|  | type_ref: TypeRefId, | 
|  | store: &ExpressionStore, | 
|  | type_source: InferenceTyDiagnosticSource, | 
|  | lifetime_elision: LifetimeElisionKind, | 
|  | ) -> Ty { | 
|  | let ty = self | 
|  | .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); | 
|  | self.process_user_written_ty(ty) | 
|  | } | 
|  |  | 
|  | fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { | 
|  | self.make_ty( | 
|  | type_ref, | 
|  | self.body, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | LifetimeElisionKind::Infer, | 
|  | ) | 
|  | } | 
|  |  | 
|  | fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty) -> Const { | 
|  | let const_ = self.with_ty_lowering( | 
|  | self.body, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | LifetimeElisionKind::Infer, | 
|  | |ctx| { | 
|  | ctx.type_param_mode = ParamLoweringMode::Placeholder; | 
|  | ctx.lower_const(&const_ref, ty) | 
|  | }, | 
|  | ); | 
|  | self.insert_type_vars(const_) | 
|  | } | 
|  |  | 
|  | fn make_path_as_body_const(&mut self, path: &Path, ty: Ty) -> Const { | 
|  | let const_ = self.with_ty_lowering( | 
|  | self.body, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | LifetimeElisionKind::Infer, | 
|  | |ctx| { | 
|  | ctx.type_param_mode = ParamLoweringMode::Placeholder; | 
|  | ctx.lower_path_as_const(path, ty) | 
|  | }, | 
|  | ); | 
|  | self.insert_type_vars(const_) | 
|  | } | 
|  |  | 
|  | fn err_ty(&self) -> Ty { | 
|  | self.result.standard_types.unknown.clone() | 
|  | } | 
|  |  | 
|  | fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Lifetime { | 
|  | let lt = self.with_ty_lowering( | 
|  | self.body, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | LifetimeElisionKind::Infer, | 
|  | |ctx| ctx.lower_lifetime(lifetime_ref), | 
|  | ); | 
|  | self.insert_type_vars(lt) | 
|  | } | 
|  |  | 
|  | /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it. | 
|  | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | 
|  | self.table.insert_type_vars_shallow(ty) | 
|  | } | 
|  |  | 
|  | fn insert_type_vars<T>(&mut self, ty: T) -> T | 
|  | where | 
|  | T: HasInterner<Interner = Interner> + TypeFoldable<Interner>, | 
|  | { | 
|  | self.table.insert_type_vars(ty) | 
|  | } | 
|  |  | 
|  | fn push_obligation(&mut self, o: DomainGoal) { | 
|  | let goal: crate::Goal = o.cast(Interner); | 
|  | self.table.register_obligation(goal.to_nextsolver(self.table.interner)); | 
|  | } | 
|  |  | 
|  | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 
|  | let ty1 = ty1 | 
|  | .clone() | 
|  | .try_fold_with( | 
|  | &mut UnevaluatedConstEvaluatorFolder { db: self.db }, | 
|  | DebruijnIndex::INNERMOST, | 
|  | ) | 
|  | .unwrap(); | 
|  | let ty2 = ty2 | 
|  | .clone() | 
|  | .try_fold_with( | 
|  | &mut UnevaluatedConstEvaluatorFolder { db: self.db }, | 
|  | DebruijnIndex::INNERMOST, | 
|  | ) | 
|  | .unwrap(); | 
|  | self.table.unify(&ty1, &ty2) | 
|  | } | 
|  |  | 
|  | /// Attempts to returns the deeply last field of nested structures, but | 
|  | /// does not apply any normalization in its search. Returns the same type | 
|  | /// if input `ty` is not a structure at all. | 
|  | fn struct_tail_without_normalization(&mut self, ty: Ty) -> Ty { | 
|  | self.struct_tail_with_normalize(ty, identity) | 
|  | } | 
|  |  | 
|  | /// Returns the deeply last field of nested structures, or the same type if | 
|  | /// not a structure at all. Corresponds to the only possible unsized field, | 
|  | /// and its type can be used to determine unsizing strategy. | 
|  | /// | 
|  | /// This is parameterized over the normalization strategy (i.e. how to | 
|  | /// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity | 
|  | /// function to indicate no normalization should take place. | 
|  | fn struct_tail_with_normalize( | 
|  | &mut self, | 
|  | mut ty: Ty, | 
|  | mut normalize: impl FnMut(Ty) -> Ty, | 
|  | ) -> Ty { | 
|  | // FIXME: fetch the limit properly | 
|  | let recursion_limit = 10; | 
|  | for iteration in 0.. { | 
|  | if iteration > recursion_limit { | 
|  | return self.err_ty(); | 
|  | } | 
|  | match ty.kind(Interner) { | 
|  | TyKind::Adt(chalk_ir::AdtId(hir_def::AdtId::StructId(struct_id)), substs) => { | 
|  | match self.db.field_types((*struct_id).into()).values().next_back().cloned() { | 
|  | Some(field) => { | 
|  | ty = field.substitute(Interner, substs); | 
|  | } | 
|  | None => break, | 
|  | } | 
|  | } | 
|  | TyKind::Adt(..) => break, | 
|  | TyKind::Tuple(_, substs) => { | 
|  | match substs | 
|  | .as_slice(Interner) | 
|  | .split_last() | 
|  | .and_then(|(last_ty, _)| last_ty.ty(Interner)) | 
|  | { | 
|  | Some(last_ty) => ty = last_ty.clone(), | 
|  | None => break, | 
|  | } | 
|  | } | 
|  | TyKind::Alias(..) => { | 
|  | let normalized = normalize(ty.clone()); | 
|  | if ty == normalized { | 
|  | return ty; | 
|  | } else { | 
|  | ty = normalized; | 
|  | } | 
|  | } | 
|  | _ => break, | 
|  | } | 
|  | } | 
|  | ty | 
|  | } | 
|  |  | 
|  | /// Whenever you lower a user-written type, you should call this. | 
|  | fn process_user_written_ty<T, U>(&mut self, ty: T) -> T | 
|  | where | 
|  | T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>, | 
|  | U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>, | 
|  | { | 
|  | self.table.process_user_written_ty(ty) | 
|  | } | 
|  |  | 
|  | /// The difference of this method from `process_user_written_ty()` is that this method doesn't register a well-formed obligation, | 
|  | /// while `process_user_written_ty()` should (but doesn't currently). | 
|  | fn process_remote_user_written_ty<T, U>(&mut self, ty: T) -> T | 
|  | where | 
|  | T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>, | 
|  | U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>, | 
|  | { | 
|  | self.table.process_remote_user_written_ty(ty) | 
|  | } | 
|  |  | 
|  | fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { | 
|  | self.table.resolve_ty_shallow(ty) | 
|  | } | 
|  |  | 
|  | fn shallow_resolve(&self, ty: crate::next_solver::Ty<'db>) -> crate::next_solver::Ty<'db> { | 
|  | self.table.shallow_resolve(ty) | 
|  | } | 
|  |  | 
|  | fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty { | 
|  | self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[]) | 
|  | } | 
|  |  | 
|  | fn resolve_associated_type_with_params( | 
|  | &mut self, | 
|  | inner_ty: Ty, | 
|  | assoc_ty: Option<TypeAliasId>, | 
|  | // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be | 
|  | // handled when we support them. | 
|  | params: &[GenericArg], | 
|  | ) -> Ty { | 
|  | match assoc_ty { | 
|  | Some(res_assoc_ty) => { | 
|  | let trait_ = match res_assoc_ty.lookup(self.db).container { | 
|  | hir_def::ItemContainerId::TraitId(trait_) => trait_, | 
|  | _ => panic!("resolve_associated_type called with non-associated type"), | 
|  | }; | 
|  | let ty = self.table.new_type_var(); | 
|  | let mut param_iter = params.iter().cloned(); | 
|  | let trait_ref = TyBuilder::trait_ref(self.db, trait_) | 
|  | .push(inner_ty) | 
|  | .fill(|_| param_iter.next().unwrap()) | 
|  | .build(); | 
|  | let alias_eq = AliasEq { | 
|  | alias: AliasTy::Projection(ProjectionTy { | 
|  | associated_ty_id: to_assoc_type_id(res_assoc_ty), | 
|  | substitution: trait_ref.substitution.clone(), | 
|  | }), | 
|  | ty: ty.clone(), | 
|  | }; | 
|  | self.push_obligation(trait_ref.cast(Interner)); | 
|  | self.push_obligation(alias_eq.cast(Interner)); | 
|  | ty | 
|  | } | 
|  | None => self.err_ty(), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn resolve_variant( | 
|  | &mut self, | 
|  | node: ExprOrPatId, | 
|  | path: Option<&Path>, | 
|  | value_ns: bool, | 
|  | ) -> (Ty, Option<VariantId>) { | 
|  | let path = match path { | 
|  | Some(path) => path, | 
|  | None => return (self.err_ty(), None), | 
|  | }; | 
|  | let mut ctx = TyLoweringContext::new( | 
|  | self.db, | 
|  | &self.resolver, | 
|  | &self.body.store, | 
|  | &self.diagnostics, | 
|  | InferenceTyDiagnosticSource::Body, | 
|  | self.generic_def, | 
|  | LifetimeElisionKind::Infer, | 
|  | ); | 
|  | let mut path_ctx = ctx.at_path(path, node); | 
|  | let (resolution, unresolved) = if value_ns { | 
|  | let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else { | 
|  | return (self.err_ty(), None); | 
|  | }; | 
|  | match res { | 
|  | ResolveValueResult::ValueNs(value, _) => match value { | 
|  | ValueNs::EnumVariantId(var) => { | 
|  | let substs = path_ctx.substs_from_path(var.into(), true, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(var.lookup(self.db).parent.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  | return (ty, Some(var.into())); | 
|  | } | 
|  | ValueNs::StructId(strukt) => { | 
|  | let substs = path_ctx.substs_from_path(strukt.into(), true, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(strukt.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  | return (ty, Some(strukt.into())); | 
|  | } | 
|  | ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None), | 
|  | _ => { | 
|  | drop(ctx); | 
|  | return (self.err_ty(), None); | 
|  | } | 
|  | }, | 
|  | ResolveValueResult::Partial(typens, unresolved, _) => (typens, Some(unresolved)), | 
|  | } | 
|  | } else { | 
|  | match path_ctx.resolve_path_in_type_ns() { | 
|  | Some((it, idx)) => (it, idx), | 
|  | None => return (self.err_ty(), None), | 
|  | } | 
|  | }; | 
|  | return match resolution { | 
|  | TypeNs::AdtId(AdtId::StructId(strukt)) => { | 
|  | let substs = path_ctx.substs_from_path(strukt.into(), true, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(strukt.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) | 
|  | } | 
|  | TypeNs::AdtId(AdtId::UnionId(u)) => { | 
|  | let substs = path_ctx.substs_from_path(u.into(), true, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(u.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  | forbid_unresolved_segments((ty, Some(u.into())), unresolved) | 
|  | } | 
|  | TypeNs::EnumVariantId(var) => { | 
|  | let substs = path_ctx.substs_from_path(var.into(), true, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(var.lookup(self.db).parent.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  | forbid_unresolved_segments((ty, Some(var.into())), unresolved) | 
|  | } | 
|  | TypeNs::SelfType(impl_id) => { | 
|  | let generics = crate::generics::generics(self.db, impl_id.into()); | 
|  | let substs = generics.placeholder_subst(self.db); | 
|  | let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); | 
|  |  | 
|  | let Some(remaining_idx) = unresolved else { | 
|  | drop(ctx); | 
|  | let Some(mod_path) = path.mod_path() else { | 
|  | never!("resolver should always resolve lang item paths"); | 
|  | return (self.err_ty(), None); | 
|  | }; | 
|  | return self.resolve_variant_on_alias(ty, None, mod_path); | 
|  | }; | 
|  |  | 
|  | let mut remaining_segments = path.segments().skip(remaining_idx); | 
|  |  | 
|  | if remaining_segments.len() >= 2 { | 
|  | path_ctx.ignore_last_segment(); | 
|  | } | 
|  |  | 
|  | // We need to try resolving unresolved segments one by one because each may resolve | 
|  | // to a projection, which `TyLoweringContext` cannot handle on its own. | 
|  | let mut tried_resolving_once = false; | 
|  | while let Some(current_segment) = remaining_segments.first() { | 
|  | // If we can resolve to an enum variant, it takes priority over associated type | 
|  | // of the same name. | 
|  | if let Some((AdtId::EnumId(id), _)) = ty.as_adt() { | 
|  | let enum_data = id.enum_variants(self.db); | 
|  | if let Some(variant) = enum_data.variant(current_segment.name) { | 
|  | return if remaining_segments.len() == 1 { | 
|  | (ty, Some(variant.into())) | 
|  | } else { | 
|  | // We still have unresolved paths, but enum variants never have | 
|  | // associated types! | 
|  | // FIXME: Report an error. | 
|  | (self.err_ty(), None) | 
|  | }; | 
|  | } | 
|  | } | 
|  |  | 
|  | if tried_resolving_once { | 
|  | // FIXME: with `inherent_associated_types` this is allowed, but our `lower_partly_resolved_path()` | 
|  | // will need to be updated to err at the correct segment. | 
|  | break; | 
|  | } | 
|  |  | 
|  | // `lower_partly_resolved_path()` returns `None` as type namespace unless | 
|  | // `remaining_segments` is empty, which is never the case here. We don't know | 
|  | // which namespace the new `ty` is in until normalized anyway. | 
|  | (ty, _) = path_ctx.lower_partly_resolved_path(resolution, true); | 
|  | tried_resolving_once = true; | 
|  |  | 
|  | ty = self.table.insert_type_vars(ty); | 
|  | ty = self.table.normalize_associated_types_in(ty); | 
|  | ty = self.table.structurally_resolve_type(&ty); | 
|  | if ty.is_unknown() { | 
|  | return (self.err_ty(), None); | 
|  | } | 
|  |  | 
|  | remaining_segments = remaining_segments.skip(1); | 
|  | } | 
|  | drop(ctx); | 
|  |  | 
|  | let variant = ty.as_adt().and_then(|(id, _)| match id { | 
|  | AdtId::StructId(s) => Some(VariantId::StructId(s)), | 
|  | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | 
|  | AdtId::EnumId(_) => { | 
|  | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | 
|  | None | 
|  | } | 
|  | }); | 
|  | (ty, variant) | 
|  | } | 
|  | TypeNs::TypeAliasId(it) => { | 
|  | let Some(mod_path) = path.mod_path() else { | 
|  | never!("resolver should always resolve lang item paths"); | 
|  | return (self.err_ty(), None); | 
|  | }; | 
|  | let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false); | 
|  | drop(ctx); | 
|  | let ty = self.db.ty(it.into()); | 
|  | let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); | 
|  |  | 
|  | self.resolve_variant_on_alias(ty, unresolved, mod_path) | 
|  | } | 
|  | TypeNs::AdtSelfType(_) => { | 
|  | // FIXME this could happen in array size expressions, once we're checking them | 
|  | (self.err_ty(), None) | 
|  | } | 
|  | TypeNs::GenericParam(_) => { | 
|  | // FIXME potentially resolve assoc type | 
|  | (self.err_ty(), None) | 
|  | } | 
|  | TypeNs::AdtId(AdtId::EnumId(_)) | 
|  | | TypeNs::BuiltinType(_) | 
|  | | TypeNs::TraitId(_) | 
|  | | TypeNs::ModuleId(_) => { | 
|  | // FIXME diagnostic | 
|  | (self.err_ty(), None) | 
|  | } | 
|  | }; | 
|  |  | 
|  | fn forbid_unresolved_segments( | 
|  | result: (Ty, Option<VariantId>), | 
|  | unresolved: Option<usize>, | 
|  | ) -> (Ty, Option<VariantId>) { | 
|  | if unresolved.is_none() { | 
|  | result | 
|  | } else { | 
|  | // FIXME diagnostic | 
|  | (TyKind::Error.intern(Interner), None) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn resolve_variant_on_alias( | 
|  | &mut self, | 
|  | ty: Ty, | 
|  | unresolved: Option<usize>, | 
|  | path: &ModPath, | 
|  | ) -> (Ty, Option<VariantId>) { | 
|  | let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); | 
|  | let ty = match ty.kind(Interner) { | 
|  | TyKind::Alias(AliasTy::Projection(proj_ty)) => { | 
|  | let ty = self.table.normalize_projection_ty(proj_ty.clone()); | 
|  | self.table.structurally_resolve_type(&ty) | 
|  | } | 
|  | _ => ty, | 
|  | }; | 
|  | match remaining { | 
|  | None => { | 
|  | let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { | 
|  | AdtId::StructId(s) => Some(VariantId::StructId(s)), | 
|  | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | 
|  | AdtId::EnumId(_) => { | 
|  | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | 
|  | None | 
|  | } | 
|  | }); | 
|  | (ty, variant) | 
|  | } | 
|  | Some(1) => { | 
|  | let segment = path.segments().last().unwrap(); | 
|  | // this could be an enum variant or associated type | 
|  | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | 
|  | let enum_data = enum_id.enum_variants(self.db); | 
|  | if let Some(variant) = enum_data.variant(segment) { | 
|  | return (ty, Some(variant.into())); | 
|  | } | 
|  | } | 
|  | // FIXME potentially resolve assoc type | 
|  | (self.err_ty(), None) | 
|  | } | 
|  | Some(_) => { | 
|  | // FIXME diagnostic | 
|  | (self.err_ty(), None) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn resolve_lang_item(&self, item: LangItem) -> Option<LangItemTarget> { | 
|  | let krate = self.resolver.krate(); | 
|  | lang_item(self.db, krate, item) | 
|  | } | 
|  |  | 
|  | fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> { | 
|  | trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output)) | 
|  | } | 
|  |  | 
|  | fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> { | 
|  | self.resolve_lang_item(lang)?.as_trait() | 
|  | } | 
|  |  | 
|  | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | 
|  | self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?) | 
|  | } | 
|  |  | 
|  | fn resolve_ops_not_output(&self) -> Option<TypeAliasId> { | 
|  | self.resolve_output_on(self.resolve_lang_trait(LangItem::Not)?) | 
|  | } | 
|  |  | 
|  | fn resolve_future_future_output(&self) -> Option<TypeAliasId> { | 
|  | let ItemContainerId::TraitId(trait_) = self | 
|  | .resolve_lang_item(LangItem::IntoFutureIntoFuture)? | 
|  | .as_function()? | 
|  | .lookup(self.db) | 
|  | .container | 
|  | else { | 
|  | return None; | 
|  | }; | 
|  | self.resolve_output_on(trait_) | 
|  | } | 
|  |  | 
|  | fn resolve_boxed_box(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::OwnedBox)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range_full(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::RangeFull)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::Range)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range_inclusive(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::RangeInclusiveStruct)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range_from(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::RangeFrom)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range_to(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::RangeTo)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::RangeToInclusive)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn resolve_ops_index_output(&self) -> Option<TypeAliasId> { | 
|  | self.resolve_output_on(self.resolve_lang_trait(LangItem::Index)?) | 
|  | } | 
|  |  | 
|  | fn resolve_va_list(&self) -> Option<AdtId> { | 
|  | let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?; | 
|  | Some(struct_.into()) | 
|  | } | 
|  |  | 
|  | fn get_traits_in_scope(&self) -> Either<FxHashSet<TraitId>, &FxHashSet<TraitId>> { | 
|  | let mut b_traits = self.resolver.traits_in_scope_from_block_scopes().peekable(); | 
|  | if b_traits.peek().is_some() { | 
|  | Either::Left(self.traits_in_scope.iter().copied().chain(b_traits).collect()) | 
|  | } else { | 
|  | Either::Right(&self.traits_in_scope) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// When inferring an expression, we propagate downward whatever type hint we | 
|  | /// are able in the form of an `Expectation`. | 
|  | #[derive(Clone, PartialEq, Eq, Debug)] | 
|  | pub(crate) enum Expectation { | 
|  | None, | 
|  | HasType(Ty), | 
|  | #[allow(dead_code)] | 
|  | Castable(Ty), | 
|  | RValueLikeUnsized(Ty), | 
|  | } | 
|  |  | 
|  | impl Expectation { | 
|  | /// The expectation that the type of the expression needs to equal the given | 
|  | /// type. | 
|  | fn has_type(ty: Ty) -> Self { | 
|  | if ty.is_unknown() { | 
|  | // FIXME: get rid of this? | 
|  | Expectation::None | 
|  | } else { | 
|  | Expectation::HasType(ty) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The following explanation is copied straight from rustc: | 
|  | /// Provides an expectation for an rvalue expression given an *optional* | 
|  | /// hint, which is not required for type safety (the resulting type might | 
|  | /// be checked higher up, as is the case with `&expr` and `box expr`), but | 
|  | /// is useful in determining the concrete type. | 
|  | /// | 
|  | /// The primary use case is where the expected type is a fat pointer, | 
|  | /// like `&[isize]`. For example, consider the following statement: | 
|  | /// | 
|  | ///     let it: &[isize] = &[1, 2, 3]; | 
|  | /// | 
|  | /// In this case, the expected type for the `&[1, 2, 3]` expression is | 
|  | /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the | 
|  | /// expectation `ExpectHasType([isize])`, that would be too strong -- | 
|  | /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. | 
|  | /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced | 
|  | /// to the type `&[isize]`. Therefore, we propagate this more limited hint, | 
|  | /// which still is useful, because it informs integer literals and the like. | 
|  | /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 | 
|  | /// for examples of where this comes up,. | 
|  | fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self { | 
|  | match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) { | 
|  | TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty), | 
|  | _ => Expectation::has_type(ty), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// This expresses no expectation on the type. | 
|  | fn none() -> Self { | 
|  | Expectation::None | 
|  | } | 
|  |  | 
|  | fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { | 
|  | match self { | 
|  | Expectation::None => Expectation::None, | 
|  | Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)), | 
|  | Expectation::Castable(t) => Expectation::Castable(table.resolve_ty_shallow(t)), | 
|  | Expectation::RValueLikeUnsized(t) => { | 
|  | Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t)) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> { | 
|  | match self.resolve(table) { | 
|  | Expectation::None => None, | 
|  | Expectation::HasType(t) | 
|  | | Expectation::Castable(t) | 
|  | | Expectation::RValueLikeUnsized(t) => Some(t), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> { | 
|  | match self { | 
|  | Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)), | 
|  | Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => { | 
|  | None | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn coercion_target_type(&self, table: &mut unify::InferenceTable<'_>) -> Ty { | 
|  | self.only_has_type(table).unwrap_or_else(|| table.new_type_var()) | 
|  | } | 
|  |  | 
|  | /// Comment copied from rustc: | 
|  | /// Disregard "castable to" expectations because they | 
|  | /// can lead us astray. Consider for example `if cond | 
|  | /// {22} else {c} as u8` -- if we propagate the | 
|  | /// "castable to u8" constraint to 22, it will pick the | 
|  | /// type 22u8, which is overly constrained (c might not | 
|  | /// be a u8). In effect, the problem is that the | 
|  | /// "castable to" expectation is not the tightest thing | 
|  | /// we can say, so we want to drop it in this case. | 
|  | /// The tightest thing we can say is "must unify with | 
|  | /// else branch". Note that in the case of a "has type" | 
|  | /// constraint, this limitation does not hold. | 
|  | /// | 
|  | /// If the expected type is just a type variable, then don't use | 
|  | /// an expected type. Otherwise, we might write parts of the type | 
|  | /// when checking the 'then' block which are incompatible with the | 
|  | /// 'else' branch. | 
|  | fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation { | 
|  | match self { | 
|  | Expectation::HasType(ety) => { | 
|  | let ety = table.structurally_resolve_type(ety); | 
|  | if ety.is_ty_var() { Expectation::None } else { Expectation::HasType(ety) } | 
|  | } | 
|  | Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()), | 
|  | _ => Expectation::None, | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] | 
|  | enum Diverges { | 
|  | Maybe, | 
|  | Always, | 
|  | } | 
|  |  | 
|  | impl Diverges { | 
|  | fn is_always(self) -> bool { | 
|  | self == Diverges::Always | 
|  | } | 
|  | } | 
|  |  | 
|  | impl std::ops::BitAnd for Diverges { | 
|  | type Output = Self; | 
|  | fn bitand(self, other: Self) -> Self { | 
|  | std::cmp::min(self, other) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl std::ops::BitOr for Diverges { | 
|  | type Output = Self; | 
|  | fn bitor(self, other: Self) -> Self { | 
|  | std::cmp::max(self, other) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl std::ops::BitAndAssign for Diverges { | 
|  | fn bitand_assign(&mut self, other: Self) { | 
|  | *self = *self & other; | 
|  | } | 
|  | } | 
|  |  | 
|  | impl std::ops::BitOrAssign for Diverges { | 
|  | fn bitor_assign(&mut self, other: Self) { | 
|  | *self = *self | other; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A zipper that checks for unequal occurrences of `{unknown}` and unresolved projections | 
|  | /// in the two types. Used to filter out mismatch diagnostics that only differ in | 
|  | /// `{unknown}` and unresolved projections. These mismatches are usually not helpful. | 
|  | /// As the cause is usually an underlying name resolution problem | 
|  | struct UnknownMismatch<'db>(&'db dyn HirDatabase); | 
|  | impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> { | 
|  | fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> { | 
|  | let zip_substs = |this: &mut Self, | 
|  | variances, | 
|  | sub_a: &Substitution, | 
|  | sub_b: &Substitution| { | 
|  | this.zip_substs(variance, variances, sub_a.as_slice(Interner), sub_b.as_slice(Interner)) | 
|  | }; | 
|  | match (a.kind(Interner), b.kind(Interner)) { | 
|  | (TyKind::Adt(id_a, sub_a), TyKind::Adt(id_b, sub_b)) if id_a == id_b => zip_substs( | 
|  | self, | 
|  | Some(self.unification_database().adt_variance(*id_a)), | 
|  | sub_a, | 
|  | sub_b, | 
|  | )?, | 
|  | ( | 
|  | TyKind::AssociatedType(assoc_ty_a, sub_a), | 
|  | TyKind::AssociatedType(assoc_ty_b, sub_b), | 
|  | ) if assoc_ty_a == assoc_ty_b => zip_substs(self, None, sub_a, sub_b)?, | 
|  | (TyKind::Tuple(arity_a, sub_a), TyKind::Tuple(arity_b, sub_b)) | 
|  | if arity_a == arity_b => | 
|  | { | 
|  | zip_substs(self, None, sub_a, sub_b)? | 
|  | } | 
|  | (TyKind::OpaqueType(opaque_ty_a, sub_a), TyKind::OpaqueType(opaque_ty_b, sub_b)) | 
|  | if opaque_ty_a == opaque_ty_b => | 
|  | { | 
|  | zip_substs(self, None, sub_a, sub_b)? | 
|  | } | 
|  | (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.zip_tys(variance, ty_a, ty_b)?, | 
|  | (TyKind::FnDef(fn_def_a, sub_a), TyKind::FnDef(fn_def_b, sub_b)) | 
|  | if fn_def_a == fn_def_b => | 
|  | { | 
|  | zip_substs( | 
|  | self, | 
|  | Some(self.unification_database().fn_def_variance(*fn_def_a)), | 
|  | sub_a, | 
|  | sub_b, | 
|  | )? | 
|  | } | 
|  | (TyKind::Ref(mutability_a, _, ty_a), TyKind::Ref(mutability_b, _, ty_b)) | 
|  | if mutability_a == mutability_b => | 
|  | { | 
|  | self.zip_tys(variance, ty_a, ty_b)? | 
|  | } | 
|  | (TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b)) | 
|  | if mutability_a == mutability_b => | 
|  | { | 
|  | self.zip_tys(variance, ty_a, ty_b)? | 
|  | } | 
|  | (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) if const_a == const_b => { | 
|  | self.zip_tys(variance, ty_a, ty_b)? | 
|  | } | 
|  | (TyKind::Closure(id_a, sub_a), TyKind::Closure(id_b, sub_b)) if id_a == id_b => { | 
|  | zip_substs(self, None, sub_a, sub_b)? | 
|  | } | 
|  | (TyKind::Coroutine(coroutine_a, sub_a), TyKind::Coroutine(coroutine_b, sub_b)) | 
|  | if coroutine_a == coroutine_b => | 
|  | { | 
|  | zip_substs(self, None, sub_a, sub_b)? | 
|  | } | 
|  | ( | 
|  | TyKind::CoroutineWitness(coroutine_a, sub_a), | 
|  | TyKind::CoroutineWitness(coroutine_b, sub_b), | 
|  | ) if coroutine_a == coroutine_b => zip_substs(self, None, sub_a, sub_b)?, | 
|  | (TyKind::Function(fn_ptr_a), TyKind::Function(fn_ptr_b)) | 
|  | if fn_ptr_a.sig == fn_ptr_b.sig && fn_ptr_a.num_binders == fn_ptr_b.num_binders => | 
|  | { | 
|  | zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)? | 
|  | } | 
|  | (TyKind::Error, TyKind::Error) => (), | 
|  | (TyKind::Error, _) | 
|  | | (_, TyKind::Error) | 
|  | | (TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _), _) | 
|  | | (_, TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _)) => { | 
|  | return Err(chalk_ir::NoSolution); | 
|  | } | 
|  | _ => (), | 
|  | } | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn zip_lifetimes(&mut self, _: Variance, _: &Lifetime, _: &Lifetime) -> chalk_ir::Fallible<()> { | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn zip_consts(&mut self, _: Variance, _: &Const, _: &Const) -> chalk_ir::Fallible<()> { | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn zip_binders<T>( | 
|  | &mut self, | 
|  | variance: Variance, | 
|  | a: &Binders<T>, | 
|  | b: &Binders<T>, | 
|  | ) -> chalk_ir::Fallible<()> | 
|  | where | 
|  | T: Clone | 
|  | + HasInterner<Interner = Interner> | 
|  | + chalk_ir::zip::Zip<Interner> | 
|  | + TypeFoldable<Interner>, | 
|  | { | 
|  | chalk_ir::zip::Zip::zip_with(self, variance, a.skip_binders(), b.skip_binders()) | 
|  | } | 
|  |  | 
|  | fn interner(&self) -> Interner { | 
|  | Interner | 
|  | } | 
|  |  | 
|  | fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> { | 
|  | &self.0 | 
|  | } | 
|  | } |