2019-02-23 14:24:07 +00:00
|
|
|
//! 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
|
2022-09-26 11:00:29 +00:00
|
|
|
//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
|
2019-02-23 14:24:07 +00:00
|
|
|
//! 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.
|
|
|
|
|
2024-08-28 15:12:16 +00:00
|
|
|
pub(crate) mod cast;
|
2023-07-12 14:46:23 +00:00
|
|
|
pub(crate) mod closure;
|
|
|
|
mod coerce;
|
|
|
|
mod expr;
|
|
|
|
mod mutability;
|
|
|
|
mod pat;
|
|
|
|
mod path;
|
|
|
|
pub(crate) mod unify;
|
|
|
|
|
2024-08-16 06:53:37 +00:00
|
|
|
use std::{cell::OnceCell, convert::identity, iter, ops::Index};
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2023-04-23 15:35:04 +00:00
|
|
|
use chalk_ir::{
|
2024-03-15 18:31:12 +00:00
|
|
|
cast::Cast,
|
|
|
|
fold::TypeFoldable,
|
|
|
|
interner::HasInterner,
|
|
|
|
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
|
|
|
DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance,
|
2023-04-23 15:35:04 +00:00
|
|
|
};
|
2023-02-25 12:50:27 +00:00
|
|
|
use either::Either;
|
2019-10-30 14:28:30 +00:00
|
|
|
use hir_def::{
|
2024-10-07 20:02:02 +00:00
|
|
|
body::{Body, HygieneId},
|
2022-12-06 22:29:38 +00:00
|
|
|
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
2022-04-26 14:25:10 +00:00
|
|
|
data::{ConstData, StaticData},
|
2024-08-10 05:55:46 +00:00
|
|
|
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
|
2023-01-21 16:29:07 +00:00
|
|
|
lang_item::{LangItem, LangItemTarget},
|
2022-12-06 22:29:38 +00:00
|
|
|
layout::Integer,
|
2023-03-08 17:28:52 +00:00
|
|
|
path::{ModPath, Path},
|
2021-07-22 11:40:18 +00:00
|
|
|
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
2024-09-06 13:25:22 +00:00
|
|
|
type_ref::{LifetimeRef, TypeRefId, TypesMap},
|
2024-08-10 05:55:46 +00:00
|
|
|
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
|
|
|
|
TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
|
2019-10-30 14:28:30 +00:00
|
|
|
};
|
2024-07-12 13:57:54 +00:00
|
|
|
use hir_expand::name::Name;
|
2024-01-06 14:04:58 +00:00
|
|
|
use indexmap::IndexSet;
|
2024-07-12 13:57:54 +00:00
|
|
|
use intern::sym;
|
2023-04-11 01:02:11 +00:00
|
|
|
use la_arena::{ArenaMap, Entry};
|
2023-03-05 14:04:46 +00:00
|
|
|
use rustc_hash::{FxHashMap, FxHashSet};
|
2023-03-08 17:28:52 +00:00
|
|
|
use stdx::{always, never};
|
2023-05-02 14:12:22 +00:00
|
|
|
use triomphe::Arc;
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2020-01-24 14:22:00 +00:00
|
|
|
use crate::{
|
2023-06-06 23:42:41 +00:00
|
|
|
db::HirDatabase,
|
2024-06-29 05:06:39 +00:00
|
|
|
fold_tys,
|
2024-06-21 08:49:19 +00:00
|
|
|
generics::Generics,
|
2024-10-10 17:25:15 +00:00
|
|
|
infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable},
|
2024-11-20 21:05:48 +00:00
|
|
|
lower::{ImplTraitLoweringMode, TyLoweringDiagnostic},
|
2024-08-24 19:46:45 +00:00
|
|
|
mir::MirSpan,
|
2024-04-02 12:03:49 +00:00
|
|
|
to_assoc_type_id,
|
2023-06-06 23:42:41 +00:00
|
|
|
traits::FnTrait,
|
2024-06-21 08:49:19 +00:00
|
|
|
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
2024-02-16 11:16:43 +00:00
|
|
|
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
2024-06-21 16:54:58 +00:00
|
|
|
ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy,
|
|
|
|
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
|
2020-01-24 14:22:00 +00:00
|
|
|
};
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2021-03-16 15:45:46 +00:00
|
|
|
// This lint has a false positive here. See the link below for details.
|
|
|
|
//
|
|
|
|
// https://github.com/rust-lang/rust/issues/57411
|
2022-03-21 17:54:20 +00:00
|
|
|
#[allow(unreachable_pub)]
|
2022-03-20 23:08:12 +00:00
|
|
|
pub use coerce::could_coerce;
|
2021-03-16 15:45:46 +00:00
|
|
|
#[allow(unreachable_pub)]
|
2023-12-11 15:04:20 +00:00
|
|
|
pub use unify::{could_unify, could_unify_deeply};
|
2019-12-01 21:14:28 +00:00
|
|
|
|
2024-08-28 15:12:16 +00:00
|
|
|
use cast::{CastCheck, CastError};
|
2023-07-12 14:46:23 +00:00
|
|
|
pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
|
2019-04-20 10:34:36 +00:00
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// The entry point of type inference.
|
2020-03-13 15:05:46 +00:00
|
|
|
pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
|
2024-06-06 23:52:25 +00:00
|
|
|
let _p = tracing::info_span!("infer_query").entered();
|
2020-03-13 15:05:46 +00:00
|
|
|
let resolver = def.resolver(db.upcast());
|
2022-04-15 19:44:47 +00:00
|
|
|
let body = db.body(def);
|
|
|
|
let mut ctx = InferenceContext::new(db, def, &body, resolver);
|
2019-02-23 14:24:07 +00:00
|
|
|
|
2019-11-27 13:02:33 +00:00
|
|
|
match def {
|
2023-03-03 15:44:25 +00:00
|
|
|
DefWithBodyId::FunctionId(f) => {
|
|
|
|
ctx.collect_fn(f);
|
|
|
|
}
|
2019-11-27 13:02:33 +00:00
|
|
|
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
2020-05-10 15:08:28 +00:00
|
|
|
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
2022-10-11 07:37:35 +00:00
|
|
|
DefWithBodyId::VariantId(v) => {
|
2024-01-15 09:24:14 +00:00
|
|
|
ctx.return_ty = TyBuilder::builtin(
|
2024-01-18 12:59:49 +00:00
|
|
|
match db.enum_data(v.lookup(db.upcast()).parent).variant_body_type() {
|
2024-01-15 09:24:14 +00:00
|
|
|
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,
|
|
|
|
}),
|
|
|
|
},
|
2022-12-06 22:29:38 +00:00
|
|
|
},
|
2024-01-15 09:24:14 +00:00
|
|
|
);
|
2022-10-11 07:37:35 +00:00
|
|
|
}
|
2023-06-06 23:42:41 +00:00
|
|
|
DefWithBodyId::InTypeConstId(c) => {
|
2023-06-11 21:07:11 +00:00
|
|
|
// FIXME(const-generic-body): We should not get the return type in this way.
|
2023-06-12 16:21:17 +00:00
|
|
|
ctx.return_ty = c
|
|
|
|
.lookup(db.upcast())
|
2023-12-14 13:11:12 +00:00
|
|
|
.expected_ty
|
2023-06-12 16:21:17 +00:00
|
|
|
.box_any()
|
|
|
|
.downcast::<InTypeConstIdMetadata>()
|
|
|
|
.unwrap()
|
|
|
|
.0;
|
2023-06-05 11:27:19 +00:00
|
|
|
}
|
2019-03-30 11:17:31 +00:00
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
|
|
|
|
ctx.infer_body();
|
|
|
|
|
2023-03-17 10:32:55 +00:00
|
|
|
ctx.infer_mut_body();
|
|
|
|
|
2023-04-06 12:44:38 +00:00
|
|
|
ctx.infer_closures();
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
Arc::new(ctx.resolve_all())
|
|
|
|
}
|
|
|
|
|
2021-11-27 13:13:47 +00:00
|
|
|
/// 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.
|
2023-04-28 17:14:30 +00:00
|
|
|
pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
|
2023-05-03 15:24:30 +00:00
|
|
|
// 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(..))
|
|
|
|
{
|
2021-11-27 13:13:47 +00:00
|
|
|
return ty;
|
|
|
|
}
|
2022-03-12 13:35:25 +00:00
|
|
|
let mut table = unify::InferenceTable::new(db, trait_env);
|
2021-11-27 13:13:47 +00:00
|
|
|
|
|
|
|
let ty_with_vars = table.normalize_associated_types_in(ty);
|
|
|
|
table.resolve_obligations_as_possible();
|
|
|
|
table.propagate_diverging_flag();
|
|
|
|
table.resolve_completely(ty_with_vars)
|
|
|
|
}
|
|
|
|
|
2019-03-16 18:13:13 +00:00
|
|
|
/// Binding modes inferred for patterns.
|
2021-06-14 04:57:10 +00:00
|
|
|
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
|
2024-01-18 12:59:49 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
2021-12-12 09:24:10 +00:00
|
|
|
pub enum BindingMode {
|
2024-01-18 12:59:49 +00:00
|
|
|
#[default]
|
2019-03-16 18:13:13 +00:00
|
|
|
Move,
|
|
|
|
Ref(Mutability),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BindingMode {
|
2020-11-02 15:31:38 +00:00
|
|
|
fn convert(annotation: BindingAnnotation) -> BindingMode {
|
2019-03-16 18:13:13 +00:00
|
|
|
match annotation {
|
|
|
|
BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
|
2021-03-01 18:30:34 +00:00
|
|
|
BindingAnnotation::Ref => BindingMode::Ref(Mutability::Not),
|
2019-03-16 18:13:13 +00:00
|
|
|
BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-01 19:53:10 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-06 16:05:40 +00:00
|
|
|
pub(crate) struct InferOk<T> {
|
|
|
|
value: T,
|
2021-05-16 16:27:17 +00:00
|
|
|
goals: Vec<InEnvironment<Goal>>,
|
2021-05-01 19:53:10 +00:00
|
|
|
}
|
2021-07-06 16:05:40 +00:00
|
|
|
|
|
|
|
impl<T> InferOk<T> {
|
|
|
|
fn map<U>(self, f: impl FnOnce(T) -> U) -> InferOk<U> {
|
|
|
|
InferOk { value: f(self.value), goals: self.goals }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-20 21:05:48 +00:00
|
|
|
#[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,
|
|
|
|
}
|
|
|
|
|
2021-05-01 19:53:10 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub(crate) struct TypeError;
|
2021-07-06 16:05:40 +00:00
|
|
|
pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
|
2021-05-01 19:53:10 +00:00
|
|
|
|
2021-06-12 14:17:23 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
|
|
pub enum InferenceDiagnostic {
|
2023-03-03 19:41:17 +00:00
|
|
|
NoSuchField {
|
2023-09-09 08:45:29 +00:00
|
|
|
field: ExprOrPatId,
|
2023-09-08 21:19:30 +00:00
|
|
|
private: bool,
|
2024-04-23 12:53:12 +00:00
|
|
|
variant: VariantId,
|
2023-03-03 19:41:17 +00:00
|
|
|
},
|
|
|
|
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>,
|
2023-12-12 12:24:33 +00:00
|
|
|
assoc_func_with_same_name: Option<AssocItemId>,
|
2023-03-03 19:41:17 +00:00
|
|
|
},
|
2023-12-31 17:33:36 +00:00
|
|
|
UnresolvedAssocItem {
|
|
|
|
id: ExprOrPatId,
|
|
|
|
},
|
2024-02-11 15:34:52 +00:00
|
|
|
UnresolvedIdent {
|
Handle destructuring assignments uniformly
Instead of lowering them to `<expr> = <expr>`, then hacking on-demand to resolve them, we lower them to `<pat> = <expr>`, and use the pattern infrastructure to handle them. It turns out, destructuring assignments are surprisingly similar to pattern bindings, and so only minor modifications are needed.
This fixes few bugs that arose because of the non-uniform handling (for example, MIR lowering not handling slice and record patterns, and closure capture calculation not handling destructuring assignments at all), and furthermore, guarantees we won't have such bugs in the future, since the programmer will always have to explicitly handle `Expr::Assignment`.
Tests don't pass yet; that's because the generated patterns do not exist in the source map. The next commit will fix that.
2024-10-06 15:14:07 +00:00
|
|
|
id: ExprOrPatId,
|
2024-02-11 15:34:52 +00:00
|
|
|
},
|
2023-04-06 13:37:53 +00:00
|
|
|
// FIXME: This should be emitted in body lowering
|
|
|
|
BreakOutsideOfLoop {
|
|
|
|
expr: ExprId,
|
|
|
|
is_break: bool,
|
|
|
|
bad_value_break: bool,
|
|
|
|
},
|
2023-03-03 19:41:17 +00:00
|
|
|
MismatchedArgCount {
|
|
|
|
call_expr: ExprId,
|
|
|
|
expected: usize,
|
|
|
|
found: usize,
|
|
|
|
},
|
2023-09-08 12:31:26 +00:00
|
|
|
MismatchedTupleStructPatArgCount {
|
|
|
|
pat: ExprOrPatId,
|
|
|
|
expected: usize,
|
|
|
|
found: usize,
|
|
|
|
},
|
2023-03-03 19:41:17 +00:00
|
|
|
ExpectedFunction {
|
|
|
|
call_expr: ExprId,
|
|
|
|
found: Ty,
|
|
|
|
},
|
2023-05-28 11:30:34 +00:00
|
|
|
TypedHole {
|
|
|
|
expr: ExprId,
|
|
|
|
expected: Ty,
|
|
|
|
},
|
2024-08-28 15:12:16 +00:00
|
|
|
CastToUnsized {
|
|
|
|
expr: ExprId,
|
|
|
|
cast_ty: Ty,
|
|
|
|
},
|
|
|
|
InvalidCast {
|
|
|
|
expr: ExprId,
|
|
|
|
error: CastError,
|
|
|
|
expr_ty: Ty,
|
|
|
|
cast_ty: Ty,
|
|
|
|
},
|
2024-11-20 21:05:48 +00:00
|
|
|
TyDiagnostic {
|
|
|
|
source: InferenceTyDiagnosticSource,
|
|
|
|
diag: TyLoweringDiagnostic,
|
|
|
|
},
|
2021-06-12 14:17:23 +00:00
|
|
|
}
|
|
|
|
|
2019-08-11 10:40:08 +00:00
|
|
|
/// A mismatch between an expected and an inferred type.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
|
|
|
pub struct TypeMismatch {
|
|
|
|
pub expected: Ty,
|
|
|
|
pub actual: Ty,
|
|
|
|
}
|
|
|
|
|
2021-03-14 16:25:29 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
struct InternedStandardTypes {
|
|
|
|
unknown: Ty,
|
2021-08-22 15:21:47 +00:00
|
|
|
bool_: Ty,
|
|
|
|
unit: Ty,
|
2023-02-10 15:08:47 +00:00
|
|
|
never: Ty,
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for InternedStandardTypes {
|
|
|
|
fn default() -> Self {
|
2021-08-22 15:21:47 +00:00
|
|
|
InternedStandardTypes {
|
2021-12-19 16:58:39 +00:00
|
|
|
unknown: TyKind::Error.intern(Interner),
|
|
|
|
bool_: TyKind::Scalar(Scalar::Bool).intern(Interner),
|
|
|
|
unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
|
2023-02-10 15:08:47 +00:00
|
|
|
never: TyKind::Never.intern(Interner),
|
2021-08-22 15:21:47 +00:00
|
|
|
}
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 12:31:16 +00:00
|
|
|
/// 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:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// 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.
|
2023-07-06 14:03:17 +00:00
|
|
|
/// E.g., `struct Foo<T> { it: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
|
2021-07-08 12:31:16 +00:00
|
|
|
/// 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]>`.
|
2021-07-06 16:05:40 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct Adjustment {
|
|
|
|
pub kind: Adjust,
|
|
|
|
pub target: Ty,
|
|
|
|
}
|
|
|
|
|
2023-03-11 18:13:53 +00:00
|
|
|
impl Adjustment {
|
2024-06-29 05:06:39 +00:00
|
|
|
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 }
|
2023-03-11 18:13:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-29 05:06:39 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
2021-07-06 16:05:40 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
|
2021-07-08 12:31:16 +00:00
|
|
|
/// 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.
|
2023-03-04 20:08:04 +00:00
|
|
|
///
|
|
|
|
/// Mutability is `None` when we are not sure.
|
2021-07-06 16:05:40 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
2023-03-04 20:08:04 +00:00
|
|
|
pub struct OverloadedDeref(pub Option<Mutability>);
|
2021-07-06 16:05:40 +00:00
|
|
|
|
2024-06-29 05:06:39 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
2021-07-06 16:05:40 +00:00
|
|
|
pub enum AutoBorrow {
|
2021-07-08 12:31:16 +00:00
|
|
|
/// Converts from T to &T.
|
2024-06-29 05:06:39 +00:00
|
|
|
Ref(Lifetime, Mutability),
|
2021-07-08 12:31:16 +00:00
|
|
|
/// Converts from T to *T.
|
2021-07-06 16:05:40 +00:00
|
|
|
RawPtr(Mutability),
|
|
|
|
}
|
|
|
|
|
2023-04-06 12:44:38 +00:00
|
|
|
impl AutoBorrow {
|
2024-06-29 05:06:39 +00:00
|
|
|
fn mutability(&self) -> Mutability {
|
|
|
|
let (AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) = self;
|
|
|
|
*m
|
2023-04-06 12:44:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 16:05:40 +00:00
|
|
|
#[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,
|
|
|
|
|
2022-02-02 12:35:46 +00:00
|
|
|
#[allow(dead_code)]
|
2021-07-06 16:05:40 +00:00
|
|
|
/// 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,
|
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// The result of type inference: A mapping from expressions and patterns to types.
|
2023-06-04 10:39:49 +00:00
|
|
|
///
|
|
|
|
/// 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.
|
2019-07-14 12:23:44 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Default)]
|
2019-02-23 14:24:07 +00:00
|
|
|
pub struct InferenceResult {
|
|
|
|
/// For each method call expr, records the function it resolves to.
|
2021-05-23 14:59:23 +00:00
|
|
|
method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
|
2019-02-23 14:24:07 +00:00
|
|
|
/// For each field access expr, records the field it resolves to.
|
2024-01-06 14:04:58 +00:00
|
|
|
field_resolutions: FxHashMap<ExprId, Either<FieldId, TupleFieldId>>,
|
2021-04-06 17:44:28 +00:00
|
|
|
/// For each struct literal or pattern, records the variant it resolves to.
|
2019-11-27 13:25:01 +00:00
|
|
|
variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
|
2019-03-02 19:05:37 +00:00
|
|
|
/// For each associated item record what it resolves to
|
2022-12-10 16:05:33 +00:00
|
|
|
assoc_resolutions: FxHashMap<ExprOrPatId, (AssocItemId, Substitution)>,
|
2024-01-06 14:04:58 +00:00
|
|
|
/// 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.
|
|
|
|
pub tuple_field_access_types: FxHashMap<TupleId, Substitution>,
|
2021-06-12 14:17:23 +00:00
|
|
|
pub diagnostics: Vec<InferenceDiagnostic>,
|
2019-11-27 14:46:02 +00:00
|
|
|
pub type_of_expr: ArenaMap<ExprId, Ty>,
|
2021-05-19 04:23:16 +00:00
|
|
|
/// 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.
|
2019-11-27 14:46:02 +00:00
|
|
|
pub type_of_pat: ArenaMap<PatId, Ty>,
|
2023-02-18 20:32:55 +00:00
|
|
|
pub type_of_binding: ArenaMap<BindingId, Ty>,
|
2024-03-15 18:31:12 +00:00
|
|
|
pub type_of_rpit: ArenaMap<ImplTraitIdx, Ty>,
|
2023-03-02 07:48:50 +00:00
|
|
|
/// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
|
2023-03-04 20:08:04 +00:00
|
|
|
pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
|
2021-05-19 04:23:16 +00:00
|
|
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
2024-03-29 05:13:31 +00:00
|
|
|
/// Whether there are any type-mismatching errors in the result.
|
|
|
|
pub(crate) has_errors: bool,
|
2022-10-11 07:37:35 +00:00
|
|
|
/// Interned common types to return references to.
|
2024-04-15 18:38:54 +00:00
|
|
|
// FIXME: Move this into `InferenceContext`
|
2021-03-14 16:25:29 +00:00
|
|
|
standard_types: InternedStandardTypes,
|
2021-06-01 20:29:07 +00:00
|
|
|
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
2022-05-14 12:26:08 +00:00
|
|
|
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
2023-10-22 20:04:27 +00:00
|
|
|
/// 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,
|
|
|
|
/// };
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
/// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
|
|
|
|
pub binding_modes: ArenaMap<PatId, BindingMode>,
|
2021-07-06 16:05:40 +00:00
|
|
|
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
|
2023-04-06 12:44:38 +00:00
|
|
|
pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
|
|
|
|
// FIXME: remove this field
|
|
|
|
pub mutated_bindings_in_closure: FxHashSet<BindingId>,
|
2024-08-28 15:12:16 +00:00
|
|
|
pub coercion_casts: FxHashSet<ExprId>,
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl InferenceResult {
|
2021-05-23 14:59:23 +00:00
|
|
|
pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
|
|
|
|
self.method_resolutions.get(&expr).cloned()
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2024-01-06 14:04:58 +00:00
|
|
|
pub fn field_resolution(&self, expr: ExprId) -> Option<Either<FieldId, TupleFieldId>> {
|
2019-07-04 17:26:44 +00:00
|
|
|
self.field_resolutions.get(&expr).copied()
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-11-27 13:25:01 +00:00
|
|
|
pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.variant_resolutions.get(&id.into()).copied()
|
|
|
|
}
|
2019-11-27 13:25:01 +00:00
|
|
|
pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.variant_resolutions.get(&id.into()).copied()
|
2019-07-12 16:56:18 +00:00
|
|
|
}
|
2024-10-06 19:52:56 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
2022-12-10 16:05:33 +00:00
|
|
|
pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
|
2022-12-05 01:53:11 +00:00
|
|
|
self.assoc_resolutions.get(&id.into()).cloned()
|
2019-03-04 14:49:18 +00:00
|
|
|
}
|
2022-12-10 16:05:33 +00:00
|
|
|
pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
|
2022-12-05 01:53:11 +00:00
|
|
|
self.assoc_resolutions.get(&id.into()).cloned()
|
2019-03-01 23:26:49 +00:00
|
|
|
}
|
2024-10-06 19:52:56 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
2019-08-11 10:40:08 +00:00
|
|
|
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
|
2021-05-19 04:23:16 +00:00
|
|
|
self.type_mismatches.get(&expr.into())
|
|
|
|
}
|
|
|
|
pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
|
|
|
|
self.type_mismatches.get(&pat.into())
|
|
|
|
}
|
2023-02-28 14:13:45 +00:00
|
|
|
pub fn type_mismatches(&self) -> impl Iterator<Item = (ExprOrPatId, &TypeMismatch)> {
|
|
|
|
self.type_mismatches.iter().map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch))
|
|
|
|
}
|
2021-05-19 04:23:16 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
2023-04-30 11:01:43 +00:00
|
|
|
pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
|
2023-04-06 12:44:38 +00:00
|
|
|
self.closure_info.get(closure).unwrap()
|
|
|
|
}
|
2024-10-06 19:52:56 +00:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<ExprId> for InferenceResult {
|
|
|
|
type Output = Ty;
|
|
|
|
|
|
|
|
fn index(&self, expr: ExprId) -> &Ty {
|
2021-03-14 16:25:29 +00:00
|
|
|
self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<PatId> for InferenceResult {
|
|
|
|
type Output = Ty;
|
|
|
|
|
|
|
|
fn index(&self, pat: PatId) -> &Ty {
|
2021-03-14 16:25:29 +00:00
|
|
|
self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 19:52:56 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
/// The inference context contains all information needed during type inference.
|
|
|
|
#[derive(Clone, Debug)]
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) struct InferenceContext<'a> {
|
|
|
|
pub(crate) db: &'a dyn HirDatabase,
|
2022-03-20 13:45:28 +00:00
|
|
|
pub(crate) owner: DefWithBodyId,
|
2022-04-15 19:44:47 +00:00
|
|
|
pub(crate) body: &'a Body,
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) resolver: Resolver,
|
2024-06-21 16:38:37 +00:00
|
|
|
generics: OnceCell<Option<Generics>>,
|
2021-04-11 09:20:45 +00:00
|
|
|
table: unify::InferenceTable<'a>,
|
2023-03-05 14:04:46 +00:00
|
|
|
/// The traits in scope, disregarding block modules. This is used for caching purposes.
|
|
|
|
traits_in_scope: FxHashSet<TraitId>,
|
2022-03-20 13:45:28 +00:00
|
|
|
pub(crate) result: InferenceResult,
|
2024-01-06 14:04:58 +00:00
|
|
|
tuple_field_accesses_rev:
|
|
|
|
IndexSet<Substitution, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>,
|
2022-03-23 22:39:35 +00:00
|
|
|
/// The return type of the function being inferred, the closure or async block if we're
|
2019-12-20 15:41:32 +00:00
|
|
|
/// currently within one.
|
|
|
|
///
|
|
|
|
/// We might consider using a nested inference context for checking
|
2023-03-03 15:44:25 +00:00
|
|
|
/// closures so we can swap all shared things out at once.
|
2019-02-23 14:24:07 +00:00
|
|
|
return_ty: Ty,
|
2023-03-03 15:44:25 +00:00
|
|
|
/// 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<CoerceMany>,
|
2023-12-25 22:12:45 +00:00
|
|
|
/// The resume type and the yield type, respectively, of the coroutine being inferred.
|
2022-10-11 07:37:35 +00:00
|
|
|
resume_yield_tys: Option<(Ty, Ty)>,
|
2020-05-08 15:36:11 +00:00
|
|
|
diverges: Diverges,
|
2020-05-08 15:59:58 +00:00
|
|
|
breakables: Vec<BreakableContext>,
|
2023-04-06 12:44:38 +00:00
|
|
|
|
Handle destructuring assignments uniformly
Instead of lowering them to `<expr> = <expr>`, then hacking on-demand to resolve them, we lower them to `<pat> = <expr>`, and use the pattern infrastructure to handle them. It turns out, destructuring assignments are surprisingly similar to pattern bindings, and so only minor modifications are needed.
This fixes few bugs that arose because of the non-uniform handling (for example, MIR lowering not handling slice and record patterns, and closure capture calculation not handling destructuring assignments at all), and furthermore, guarantees we won't have such bugs in the future, since the programmer will always have to explicitly handle `Expr::Assignment`.
Tests don't pass yet; that's because the generated patterns do not exist in the source map. The next commit will fix that.
2024-10-06 15:14:07 +00:00
|
|
|
/// Whether we are inside the pattern of a destructuring assignment.
|
|
|
|
inside_assignment: bool,
|
|
|
|
|
2023-07-12 14:46:23 +00:00
|
|
|
deferred_cast_checks: Vec<CastCheck>,
|
|
|
|
|
2023-04-06 12:44:38 +00:00
|
|
|
// fields related to closure capture
|
|
|
|
current_captures: Vec<CapturedItemWithoutTy>,
|
2024-08-24 19:46:45 +00:00
|
|
|
/// 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>,
|
2023-04-06 12:44:38 +00:00
|
|
|
current_closure: Option<ClosureId>,
|
|
|
|
/// Stores the list of closure ids that need to be analyzed before this closure. See the
|
|
|
|
/// comment on `InferenceContext::sort_closures`
|
2023-04-13 22:35:00 +00:00
|
|
|
closure_dependencies: FxHashMap<ClosureId, Vec<ClosureId>>,
|
2023-04-06 12:44:38 +00:00
|
|
|
deferred_closures: FxHashMap<ClosureId, Vec<(Ty, Ty, Vec<Ty>, ExprId)>>,
|
2020-05-08 15:59:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
struct BreakableContext {
|
2022-09-06 18:20:49 +00:00
|
|
|
/// Whether this context contains at least one break expression.
|
2020-11-02 12:13:32 +00:00
|
|
|
may_break: bool,
|
2022-09-06 18:20:49 +00:00
|
|
|
/// The coercion target of the context.
|
2023-03-03 16:28:57 +00:00
|
|
|
coerce: Option<CoerceMany>,
|
2022-09-06 18:20:49 +00:00
|
|
|
/// The optional label of the context.
|
2023-04-06 10:50:16 +00:00
|
|
|
label: Option<LabelId>,
|
2022-09-06 18:20:49 +00:00
|
|
|
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,
|
2020-05-31 08:59:40 +00:00
|
|
|
}
|
|
|
|
|
2024-01-18 12:59:49 +00:00
|
|
|
fn find_breakable(
|
|
|
|
ctxs: &mut [BreakableContext],
|
2023-04-06 10:50:16 +00:00
|
|
|
label: Option<LabelId>,
|
2024-01-18 12:59:49 +00:00
|
|
|
) -> Option<&mut BreakableContext> {
|
2022-09-06 18:20:49 +00:00
|
|
|
let mut ctxs = ctxs
|
|
|
|
.iter_mut()
|
|
|
|
.rev()
|
|
|
|
.take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
|
|
|
|
match label {
|
2023-04-06 10:50:16 +00:00
|
|
|
Some(_) => ctxs.find(|ctx| ctx.label == label),
|
2022-09-06 18:20:49 +00:00
|
|
|
None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-18 12:59:49 +00:00
|
|
|
fn find_continuable(
|
|
|
|
ctxs: &mut [BreakableContext],
|
2023-04-06 13:37:53 +00:00
|
|
|
label: Option<LabelId>,
|
2024-01-18 12:59:49 +00:00
|
|
|
) -> Option<&mut BreakableContext> {
|
2023-04-06 13:37:53 +00:00
|
|
|
match label {
|
|
|
|
Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
|
|
|
|
None => find_breakable(ctxs, label),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-18 13:48:47 +00:00
|
|
|
enum ImplTraitReplacingMode {
|
|
|
|
ReturnPosition(FxHashSet<Ty>),
|
|
|
|
TypeAlias,
|
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl<'a> InferenceContext<'a> {
|
2022-04-15 19:44:47 +00:00
|
|
|
fn new(
|
|
|
|
db: &'a dyn HirDatabase,
|
|
|
|
owner: DefWithBodyId,
|
|
|
|
body: &'a Body,
|
|
|
|
resolver: Resolver,
|
|
|
|
) -> Self {
|
2023-03-08 17:28:52 +00:00
|
|
|
let trait_env = db.trait_environment_for_body(owner);
|
2019-02-23 14:24:07 +00:00
|
|
|
InferenceContext {
|
2024-06-21 16:38:37 +00:00
|
|
|
generics: OnceCell::new(),
|
2019-07-14 12:23:44 +00:00
|
|
|
result: InferenceResult::default(),
|
2023-03-28 06:29:07 +00:00
|
|
|
table: unify::InferenceTable::new(db, trait_env),
|
2024-01-06 14:04:58 +00:00
|
|
|
tuple_field_accesses_rev: Default::default(),
|
2022-12-09 19:07:00 +00:00
|
|
|
return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
|
2022-10-11 07:37:35 +00:00
|
|
|
resume_yield_tys: None,
|
2023-03-03 15:44:25 +00:00
|
|
|
return_coercion: None,
|
2019-02-23 14:24:07 +00:00
|
|
|
db,
|
2019-11-12 13:46:27 +00:00
|
|
|
owner,
|
2022-04-15 19:44:47 +00:00
|
|
|
body,
|
2023-03-05 14:04:46 +00:00
|
|
|
traits_in_scope: resolver.traits_in_scope(db.upcast()),
|
2019-02-23 14:24:07 +00:00
|
|
|
resolver,
|
2020-05-08 15:36:11 +00:00
|
|
|
diverges: Diverges::Maybe,
|
2020-05-08 15:59:58 +00:00
|
|
|
breakables: Vec::new(),
|
2023-07-12 14:46:23 +00:00
|
|
|
deferred_cast_checks: Vec::new(),
|
|
|
|
current_captures: Vec::new(),
|
2024-08-24 19:46:45 +00:00
|
|
|
current_capture_span_stack: Vec::new(),
|
2023-04-06 12:44:38 +00:00
|
|
|
current_closure: None,
|
|
|
|
deferred_closures: FxHashMap::default(),
|
2023-04-13 22:35:00 +00:00
|
|
|
closure_dependencies: FxHashMap::default(),
|
Handle destructuring assignments uniformly
Instead of lowering them to `<expr> = <expr>`, then hacking on-demand to resolve them, we lower them to `<pat> = <expr>`, and use the pattern infrastructure to handle them. It turns out, destructuring assignments are surprisingly similar to pattern bindings, and so only minor modifications are needed.
This fixes few bugs that arose because of the non-uniform handling (for example, MIR lowering not handling slice and record patterns, and closure capture calculation not handling destructuring assignments at all), and furthermore, guarantees we won't have such bugs in the future, since the programmer will always have to explicitly handle `Expr::Assignment`.
Tests don't pass yet; that's because the generated patterns do not exist in the source map. The next commit will fix that.
2024-10-06 15:14:07 +00:00
|
|
|
inside_assignment: false,
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-21 16:38:37 +00:00
|
|
|
pub(crate) fn generics(&self) -> Option<&Generics> {
|
|
|
|
self.generics
|
|
|
|
.get_or_init(|| {
|
|
|
|
self.resolver
|
|
|
|
.generic_def()
|
|
|
|
.map(|def| crate::generics::generics(self.db.upcast(), def))
|
|
|
|
})
|
|
|
|
.as_ref()
|
2024-04-06 11:12:07 +00:00
|
|
|
}
|
|
|
|
|
2023-02-03 11:16:25 +00:00
|
|
|
// 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(self) -> InferenceResult {
|
2024-01-06 14:04:58 +00:00
|
|
|
let InferenceContext {
|
|
|
|
mut table,
|
|
|
|
mut result,
|
2024-08-28 15:12:16 +00:00
|
|
|
mut deferred_cast_checks,
|
2024-01-06 14:04:58 +00:00
|
|
|
tuple_field_accesses_rev,
|
|
|
|
..
|
|
|
|
} = self;
|
2023-06-04 11:32:46 +00:00
|
|
|
// 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,
|
|
|
|
diagnostics,
|
|
|
|
type_of_expr,
|
|
|
|
type_of_pat,
|
|
|
|
type_of_binding,
|
|
|
|
type_of_rpit,
|
|
|
|
type_of_for_iterator,
|
|
|
|
type_mismatches,
|
2024-03-29 05:13:31 +00:00
|
|
|
has_errors,
|
2023-06-04 11:32:46 +00:00
|
|
|
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: _,
|
2024-01-06 14:04:58 +00:00
|
|
|
tuple_field_access_types: _,
|
2024-08-28 15:12:16 +00:00
|
|
|
coercion_casts,
|
2023-06-04 11:32:46 +00:00
|
|
|
} = &mut result;
|
2023-01-05 12:31:10 +00:00
|
|
|
table.fallback_if_possible();
|
|
|
|
|
2023-07-12 14:46:23 +00:00
|
|
|
// 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.
|
2024-08-28 15:12:16 +00:00
|
|
|
let mut apply_adjustments = |expr, adj| {
|
|
|
|
expr_adjustments.insert(expr, adj);
|
|
|
|
};
|
|
|
|
let mut set_coercion_cast = |expr| {
|
|
|
|
coercion_casts.insert(expr);
|
|
|
|
};
|
|
|
|
for cast in deferred_cast_checks.iter_mut() {
|
|
|
|
if let Err(diag) =
|
|
|
|
cast.check(&mut table, &mut apply_adjustments, &mut set_coercion_cast)
|
|
|
|
{
|
|
|
|
diagnostics.push(diag);
|
|
|
|
}
|
2023-07-12 14:46:23 +00:00
|
|
|
}
|
|
|
|
|
2019-03-31 18:02:16 +00:00
|
|
|
// FIXME resolve obligations as well (use Guidance if necessary)
|
2022-04-15 19:25:44 +00:00
|
|
|
table.resolve_obligations_as_possible();
|
2021-05-15 17:28:58 +00:00
|
|
|
|
|
|
|
// make sure diverging type variables are marked as such
|
2022-04-15 19:25:44 +00:00
|
|
|
table.propagate_diverging_flag();
|
2023-06-04 11:32:46 +00:00
|
|
|
for ty in type_of_expr.values_mut() {
|
2022-04-15 19:25:44 +00:00
|
|
|
*ty = table.resolve_completely(ty.clone());
|
2024-07-06 18:41:46 +00:00
|
|
|
*has_errors = *has_errors || ty.contains_unknown();
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for ty in type_of_pat.values_mut() {
|
2022-04-15 19:25:44 +00:00
|
|
|
*ty = table.resolve_completely(ty.clone());
|
2024-07-06 18:41:46 +00:00
|
|
|
*has_errors = *has_errors || ty.contains_unknown();
|
2021-05-16 15:56:38 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for ty in type_of_binding.values_mut() {
|
2023-02-18 20:32:55 +00:00
|
|
|
*ty = table.resolve_completely(ty.clone());
|
2024-07-06 18:41:46 +00:00
|
|
|
*has_errors = *has_errors || ty.contains_unknown();
|
2023-02-18 20:32:55 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for ty in type_of_rpit.values_mut() {
|
2023-02-06 17:20:25 +00:00
|
|
|
*ty = table.resolve_completely(ty.clone());
|
2024-07-06 18:41:46 +00:00
|
|
|
*has_errors = *has_errors || ty.contains_unknown();
|
2023-02-06 17:20:25 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for ty in type_of_for_iterator.values_mut() {
|
2023-03-02 07:48:50 +00:00
|
|
|
*ty = table.resolve_completely(ty.clone());
|
2024-07-06 18:41:46 +00:00
|
|
|
*has_errors = *has_errors || ty.contains_unknown();
|
2023-03-02 07:48:50 +00:00
|
|
|
}
|
2024-03-29 05:13:31 +00:00
|
|
|
|
2024-09-06 12:44:05 +00:00
|
|
|
*has_errors |= !type_mismatches.is_empty();
|
2024-03-29 05:13:31 +00:00
|
|
|
|
2024-02-16 11:16:43 +00:00
|
|
|
type_mismatches.retain(|_, mismatch| {
|
2022-04-15 19:25:44 +00:00
|
|
|
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
|
|
|
|
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
|
2024-04-01 18:29:36 +00:00
|
|
|
chalk_ir::zip::Zip::zip_with(
|
|
|
|
&mut UnknownMismatch(self.db),
|
|
|
|
Variance::Invariant,
|
|
|
|
&mismatch.expected,
|
|
|
|
&mismatch.actual,
|
|
|
|
)
|
|
|
|
.is_ok()
|
2024-02-16 11:16:43 +00:00
|
|
|
});
|
2023-06-04 11:32:46 +00:00
|
|
|
diagnostics.retain_mut(|diagnostic| {
|
2023-05-28 11:30:34 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-03-03 19:41:17 +00:00
|
|
|
|
2023-05-28 11:30:34 +00:00
|
|
|
if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic {
|
|
|
|
if let Some(ty) = field_with_same_name {
|
|
|
|
*ty = table.resolve_completely(ty.clone());
|
|
|
|
if ty.contains_unknown() {
|
|
|
|
*field_with_same_name = None;
|
|
|
|
}
|
|
|
|
}
|
2023-03-03 19:41:17 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-28 11:30:34 +00:00
|
|
|
TypedHole { expected: ty, .. } => {
|
|
|
|
*ty = table.resolve_completely(ty.clone());
|
|
|
|
}
|
|
|
|
_ => (),
|
2023-03-03 17:04:24 +00:00
|
|
|
}
|
2023-03-03 18:32:18 +00:00
|
|
|
true
|
|
|
|
});
|
2023-06-04 11:32:46 +00:00
|
|
|
for (_, subst) in method_resolutions.values_mut() {
|
2022-04-15 19:25:44 +00:00
|
|
|
*subst = table.resolve_completely(subst.clone());
|
2024-09-06 12:44:05 +00:00
|
|
|
*has_errors =
|
|
|
|
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for (_, subst) in assoc_resolutions.values_mut() {
|
2022-12-14 12:56:55 +00:00
|
|
|
*subst = table.resolve_completely(subst.clone());
|
2024-09-06 12:44:05 +00:00
|
|
|
*has_errors =
|
|
|
|
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
2022-12-14 12:56:55 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for adjustment in expr_adjustments.values_mut().flatten() {
|
2022-04-15 19:25:44 +00:00
|
|
|
adjustment.target = table.resolve_completely(adjustment.target.clone());
|
2024-09-06 12:44:05 +00:00
|
|
|
*has_errors = *has_errors || adjustment.target.contains_unknown();
|
2021-07-10 16:19:23 +00:00
|
|
|
}
|
2023-06-04 11:32:46 +00:00
|
|
|
for adjustment in pat_adjustments.values_mut().flatten() {
|
2022-05-14 12:26:08 +00:00
|
|
|
*adjustment = table.resolve_completely(adjustment.clone());
|
2024-09-06 12:44:05 +00:00
|
|
|
*has_errors = *has_errors || adjustment.contains_unknown();
|
2021-07-10 16:19:23 +00:00
|
|
|
}
|
2024-01-06 14:04:58 +00:00
|
|
|
result.tuple_field_access_types = tuple_field_accesses_rev
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
2024-01-06 23:17:48 +00:00
|
|
|
.map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst)))
|
2024-09-06 12:44:05 +00:00
|
|
|
.inspect(|(_, subst)| {
|
|
|
|
*has_errors =
|
|
|
|
*has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown());
|
|
|
|
})
|
2024-01-06 14:04:58 +00:00
|
|
|
.collect();
|
2019-07-14 12:23:44 +00:00
|
|
|
result
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2022-04-15 19:25:44 +00:00
|
|
|
fn collect_const(&mut self, data: &ConstData) {
|
2024-11-20 21:05:48 +00:00
|
|
|
let return_ty =
|
|
|
|
self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
|
2024-03-15 18:31:12 +00:00
|
|
|
|
2024-08-10 05:55:46 +00:00
|
|
|
// Constants might be defining usage sites of TAITs.
|
|
|
|
self.make_tait_coercion_table(iter::once(&return_ty));
|
2024-03-15 18:31:12 +00:00
|
|
|
|
|
|
|
self.return_ty = return_ty;
|
2022-04-15 19:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_static(&mut self, data: &StaticData) {
|
2024-11-20 21:05:48 +00:00
|
|
|
let return_ty =
|
|
|
|
self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature);
|
2024-08-10 05:55:46 +00:00
|
|
|
|
|
|
|
// Statics might be defining usage sites of TAITs.
|
|
|
|
self.make_tait_coercion_table(iter::once(&return_ty));
|
|
|
|
|
|
|
|
self.return_ty = return_ty;
|
2022-04-15 19:25:44 +00:00
|
|
|
}
|
|
|
|
|
2022-04-26 14:25:10 +00:00
|
|
|
fn collect_fn(&mut self, func: FunctionId) {
|
|
|
|
let data = self.db.function_data(func);
|
2024-11-20 21:05:48 +00:00
|
|
|
let mut param_tys =
|
|
|
|
self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
|
|
|
|
ctx.type_param_mode(ParamLoweringMode::Placeholder)
|
|
|
|
.impl_trait_mode(ImplTraitLoweringMode::Param);
|
|
|
|
data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
|
|
|
|
});
|
2022-11-28 23:32:13 +00:00
|
|
|
// 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(),
|
|
|
|
};
|
|
|
|
|
2024-07-25 09:02:19 +00:00
|
|
|
param_tys.push(va_list_ty);
|
2022-11-28 23:32:13 +00:00
|
|
|
}
|
2024-03-06 14:57:05 +00:00
|
|
|
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 {
|
|
|
|
if let Some(ty) = param_tys.next() {
|
|
|
|
let ty = self.insert_type_vars(ty);
|
|
|
|
let ty = self.normalize_associated_types_in(ty);
|
|
|
|
self.write_binding_ty(self_param, ty);
|
|
|
|
}
|
|
|
|
}
|
2024-08-18 13:48:47 +00:00
|
|
|
let mut tait_candidates = FxHashSet::default();
|
2024-03-06 14:57:05 +00:00
|
|
|
for (ty, pat) in param_tys.zip(&*self.body.params) {
|
2022-04-15 19:25:44 +00:00
|
|
|
let ty = self.insert_type_vars(ty);
|
|
|
|
let ty = self.normalize_associated_types_in(ty);
|
|
|
|
|
2023-03-03 09:23:20 +00:00
|
|
|
self.infer_top_pat(*pat, &ty);
|
2024-08-18 13:48:47 +00:00
|
|
|
if ty
|
|
|
|
.data(Interner)
|
|
|
|
.flags
|
|
|
|
.intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER))
|
|
|
|
{
|
|
|
|
tait_candidates.insert(ty);
|
|
|
|
}
|
2022-04-15 19:25:44 +00:00
|
|
|
}
|
2024-09-06 13:25:22 +00:00
|
|
|
let return_ty = data.ret_type;
|
2022-04-26 14:25:10 +00:00
|
|
|
|
2024-11-20 21:05:48 +00:00
|
|
|
let return_ty =
|
|
|
|
self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| {
|
|
|
|
ctx.type_param_mode(ParamLoweringMode::Placeholder)
|
|
|
|
.impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
|
|
|
.lower_ty(return_ty)
|
|
|
|
});
|
2022-12-09 19:07:00 +00:00
|
|
|
let return_ty = self.insert_type_vars(return_ty);
|
|
|
|
|
|
|
|
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
2022-04-26 14:25:10 +00:00
|
|
|
// RPIT opaque types use substitution of their parent function.
|
|
|
|
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
2024-08-18 13:48:47 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-04-11 01:02:11 +00:00
|
|
|
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
|
2022-12-09 19:07:00 +00:00
|
|
|
} else {
|
|
|
|
return_ty
|
|
|
|
};
|
|
|
|
|
|
|
|
self.return_ty = self.normalize_associated_types_in(return_ty);
|
2023-03-03 15:44:25 +00:00
|
|
|
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
|
2024-03-15 18:31:12 +00:00
|
|
|
|
2024-08-10 05:55:46 +00:00
|
|
|
// Functions might be defining usage sites of TAITs.
|
|
|
|
// To define an TAITs, that TAIT must appear in the function's signatures.
|
2024-03-15 18:31:12 +00:00
|
|
|
// So, it suffices to check for params and return types.
|
2024-08-18 13:48:47 +00:00
|
|
|
if self
|
|
|
|
.return_ty
|
|
|
|
.data(Interner)
|
|
|
|
.flags
|
|
|
|
.intersects(TypeFlags::HAS_TY_OPAQUE.union(TypeFlags::HAS_TY_INFER))
|
|
|
|
{
|
|
|
|
tait_candidates.insert(self.return_ty.clone());
|
|
|
|
}
|
|
|
|
self.make_tait_coercion_table(tait_candidates.iter());
|
2022-04-15 19:25:44 +00:00
|
|
|
}
|
|
|
|
|
2024-08-18 13:48:47 +00:00
|
|
|
fn insert_inference_vars_for_impl_trait<T>(
|
|
|
|
&mut self,
|
|
|
|
t: T,
|
|
|
|
placeholders: Substitution,
|
|
|
|
mode: &mut ImplTraitReplacingMode,
|
|
|
|
) -> T
|
2023-04-11 01:02:11 +00:00
|
|
|
where
|
|
|
|
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
|
|
|
|
{
|
|
|
|
fold_tys(
|
|
|
|
t,
|
|
|
|
|ty, _| {
|
|
|
|
let opaque_ty_id = match ty.kind(Interner) {
|
|
|
|
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
|
|
|
|
_ => return ty,
|
|
|
|
};
|
2024-06-27 14:51:33 +00:00
|
|
|
let (impl_traits, idx) =
|
|
|
|
match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
2024-08-18 13:48:47 +00:00
|
|
|
// 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
|
2024-06-27 14:51:33 +00:00
|
|
|
ImplTraitId::ReturnTypeImplTrait(def, idx) => {
|
2024-08-18 13:48:47 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-06-27 14:51:33 +00:00
|
|
|
(self.db.return_type_impl_traits(def), idx)
|
|
|
|
}
|
2024-08-10 05:55:46 +00:00
|
|
|
ImplTraitId::TypeAliasImplTrait(def, idx) => {
|
2024-08-18 13:48:47 +00:00
|
|
|
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;
|
|
|
|
}
|
2024-06-27 14:51:33 +00:00
|
|
|
(self.db.type_alias_impl_traits(def), idx)
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
let Some(impl_traits) = impl_traits else {
|
|
|
|
return ty;
|
2023-04-11 01:02:11 +00:00
|
|
|
};
|
2024-06-27 14:51:33 +00:00
|
|
|
let bounds = (*impl_traits)
|
2024-08-18 13:48:47 +00:00
|
|
|
.map_ref(|its| its.impl_traits[idx].bounds.map_ref(|it| it.iter()));
|
2023-04-11 01:02:11 +00:00
|
|
|
let var = self.table.new_type_var();
|
|
|
|
let var_subst = Substitution::from1(Interner, var.clone());
|
|
|
|
for bound in bounds {
|
2024-08-18 13:48:47 +00:00
|
|
|
let predicate = bound.map(|it| it.cloned());
|
|
|
|
let predicate = predicate.substitute(Interner, &placeholders);
|
2023-04-11 01:02:11 +00:00
|
|
|
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
|
2024-08-18 13:48:47 +00:00
|
|
|
let var_predicate = self.insert_inference_vars_for_impl_trait(
|
|
|
|
var_predicate,
|
|
|
|
placeholders.clone(),
|
|
|
|
mode,
|
|
|
|
);
|
2023-04-11 01:02:11 +00:00
|
|
|
self.push_obligation(var_predicate.cast(Interner));
|
|
|
|
}
|
|
|
|
self.result.type_of_rpit.insert(idx, var.clone());
|
|
|
|
var
|
|
|
|
},
|
|
|
|
DebruijnIndex::INNERMOST,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-03-15 18:31:12 +00:00
|
|
|
/// The coercion of a non-inference var into an opaque type should fail,
|
2024-08-10 05:55:46 +00:00
|
|
|
/// 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.
|
2024-03-15 18:31:12 +00:00
|
|
|
///
|
|
|
|
/// The inference var stretagy is effective because;
|
|
|
|
///
|
2024-08-10 05:55:46 +00:00
|
|
|
/// - It can still unify types that coerced into TAITs
|
2024-03-15 18:31:12 +00:00
|
|
|
/// - We are pushing `impl Trait` bounds into it
|
|
|
|
///
|
|
|
|
/// This function inserts a map that maps the opaque type to that proxy inference var.
|
2024-08-10 05:55:46 +00:00
|
|
|
fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator<Item = &'b Ty>) {
|
|
|
|
struct TypeAliasImplTraitCollector<'a, 'b> {
|
|
|
|
db: &'b dyn HirDatabase,
|
2024-03-15 18:31:12 +00:00
|
|
|
table: &'b mut InferenceTable<'a>,
|
2024-08-10 05:55:46 +00:00
|
|
|
assocs: FxHashMap<OpaqueTyId, (ImplId, Ty)>,
|
|
|
|
non_assocs: FxHashMap<OpaqueTyId, Ty>,
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
|
|
|
|
2024-10-22 09:02:41 +00:00
|
|
|
impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> {
|
2024-03-15 18:31:12 +00:00
|
|
|
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.resolve_ty_shallow(ty);
|
|
|
|
|
|
|
|
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
|
2024-08-10 05:55:46 +00:00
|
|
|
if 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());
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ty.super_visit_with(self, outer_binder)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-10 05:55:46 +00:00
|
|
|
let mut collector = TypeAliasImplTraitCollector {
|
|
|
|
db: self.db,
|
|
|
|
table: &mut self.table,
|
|
|
|
assocs: FxHashMap::default(),
|
|
|
|
non_assocs: FxHashMap::default(),
|
2024-03-15 18:31:12 +00:00
|
|
|
};
|
2024-08-10 05:55:46 +00:00
|
|
|
for ty in tait_candidates {
|
|
|
|
ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 05:55:46 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}));
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
2024-08-10 05:55:46 +00:00
|
|
|
|
|
|
|
let tait_coercion_table: FxHashMap<_, _> = taits
|
2024-03-15 18:31:12 +00:00
|
|
|
.into_iter()
|
2024-08-10 05:55:46 +00:00
|
|
|
.filter_map(|(id, ty)| {
|
|
|
|
if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
|
|
|
|
self.db.lookup_intern_impl_trait_id(id.into())
|
2024-03-15 18:31:12 +00:00
|
|
|
{
|
2024-08-10 05:55:46 +00:00
|
|
|
let subst = TyBuilder::placeholder_subst(self.db, alias_id);
|
2024-08-18 13:48:47 +00:00
|
|
|
let ty = self.insert_inference_vars_for_impl_trait(
|
|
|
|
ty,
|
|
|
|
subst,
|
|
|
|
&mut ImplTraitReplacingMode::TypeAlias,
|
|
|
|
);
|
2024-08-10 05:55:46 +00:00
|
|
|
Some((id, ty))
|
|
|
|
} else {
|
|
|
|
None
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2024-08-10 05:55:46 +00:00
|
|
|
if !tait_coercion_table.is_empty() {
|
|
|
|
self.table.tait_coercion_table = Some(tait_coercion_table);
|
2024-03-15 18:31:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-15 19:25:44 +00:00
|
|
|
fn infer_body(&mut self) {
|
2023-03-03 15:44:25 +00:00
|
|
|
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()),
|
2024-10-10 17:25:15 +00:00
|
|
|
ExprIsRead::Yes,
|
2023-03-03 15:44:25 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2022-04-15 19:25:44 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
fn write_expr_ty(&mut self, expr: ExprId, ty: Ty) {
|
2019-07-14 12:23:44 +00:00
|
|
|
self.result.type_of_expr.insert(expr, ty);
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 16:05:40 +00:00
|
|
|
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
|
|
|
|
self.result.expr_adjustments.insert(expr, adjustments);
|
|
|
|
}
|
|
|
|
|
2021-05-23 14:59:23 +00:00
|
|
|
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
|
|
|
|
self.result.method_resolutions.insert(expr, (func, subst));
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 13:25:01 +00:00
|
|
|
fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
|
2019-07-21 11:11:45 +00:00
|
|
|
self.result.variant_resolutions.insert(id, variant);
|
2019-07-12 16:56:18 +00:00
|
|
|
}
|
|
|
|
|
2022-12-10 16:05:33 +00:00
|
|
|
fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId, subs: Substitution) {
|
2022-12-05 01:53:11 +00:00
|
|
|
self.result.assoc_resolutions.insert(id, (item, subs));
|
2019-03-01 23:26:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 14:24:07 +00:00
|
|
|
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
|
2019-07-14 12:23:44 +00:00
|
|
|
self.result.type_of_pat.insert(pat, ty);
|
|
|
|
}
|
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
fn write_binding_ty(&mut self, id: BindingId, ty: Ty) {
|
|
|
|
self.result.type_of_binding.insert(id, ty);
|
|
|
|
}
|
|
|
|
|
2019-07-14 12:23:44 +00:00
|
|
|
fn push_diagnostic(&mut self, diagnostic: InferenceDiagnostic) {
|
|
|
|
self.result.diagnostics.push(diagnostic);
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2024-11-20 21:05:48 +00:00
|
|
|
fn push_ty_diagnostics(
|
|
|
|
&mut self,
|
|
|
|
source: InferenceTyDiagnosticSource,
|
|
|
|
diagnostics: Vec<TyLoweringDiagnostic>,
|
|
|
|
) {
|
|
|
|
self.result.diagnostics.extend(
|
|
|
|
diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-09-06 13:25:22 +00:00
|
|
|
fn with_ty_lowering<R>(
|
2024-11-20 21:05:48 +00:00
|
|
|
&mut self,
|
2024-09-06 13:25:22 +00:00
|
|
|
types_map: &TypesMap,
|
2024-11-20 21:05:48 +00:00
|
|
|
types_source: InferenceTyDiagnosticSource,
|
2024-09-06 13:25:22 +00:00
|
|
|
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
|
|
|
|
) -> R {
|
|
|
|
let mut ctx = crate::lower::TyLoweringContext::new(
|
|
|
|
self.db,
|
|
|
|
&self.resolver,
|
|
|
|
types_map,
|
|
|
|
self.owner.into(),
|
|
|
|
);
|
2024-11-20 21:05:48 +00:00
|
|
|
let result = f(&mut ctx);
|
|
|
|
self.push_ty_diagnostics(types_source, ctx.diagnostics);
|
|
|
|
result
|
2024-09-06 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn with_body_ty_lowering<R>(
|
2024-11-20 21:05:48 +00:00
|
|
|
&mut self,
|
2024-09-06 13:25:22 +00:00
|
|
|
f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
|
|
|
|
) -> R {
|
2024-11-20 21:05:48 +00:00
|
|
|
self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f)
|
2024-09-06 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2024-11-20 21:05:48 +00:00
|
|
|
fn make_ty(
|
|
|
|
&mut self,
|
|
|
|
type_ref: TypeRefId,
|
|
|
|
types_map: &TypesMap,
|
|
|
|
type_source: InferenceTyDiagnosticSource,
|
|
|
|
) -> Ty {
|
|
|
|
let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref));
|
2019-08-07 20:06:09 +00:00
|
|
|
let ty = self.insert_type_vars(ty);
|
|
|
|
self.normalize_associated_types_in(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2024-09-06 13:25:22 +00:00
|
|
|
fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
|
2024-11-20 21:05:48 +00:00
|
|
|
self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body)
|
2024-09-06 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2022-04-15 19:25:44 +00:00
|
|
|
fn err_ty(&self) -> Ty {
|
|
|
|
self.result.standard_types.unknown.clone()
|
|
|
|
}
|
|
|
|
|
2024-11-20 21:05:48 +00:00
|
|
|
fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
|
|
|
|
let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| {
|
|
|
|
ctx.lower_lifetime(lifetime_ref)
|
|
|
|
});
|
2024-03-19 04:44:45 +00:00
|
|
|
self.insert_type_vars(lt)
|
|
|
|
}
|
|
|
|
|
2022-12-28 20:43:12 +00:00
|
|
|
/// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
|
2019-02-23 14:24:07 +00:00
|
|
|
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
|
2023-03-29 12:44:23 +00:00
|
|
|
self.table.insert_type_vars_shallow(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2023-04-23 15:35:04 +00:00
|
|
|
fn insert_type_vars<T>(&mut self, ty: T) -> T
|
|
|
|
where
|
|
|
|
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
|
|
|
{
|
2023-03-29 12:44:23 +00:00
|
|
|
self.table.insert_type_vars(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2021-04-01 19:45:44 +00:00
|
|
|
fn push_obligation(&mut self, o: DomainGoal) {
|
2021-12-19 16:58:39 +00:00
|
|
|
self.table.register_obligation(o.cast(Interner));
|
2021-04-01 19:45:44 +00:00
|
|
|
}
|
|
|
|
|
2019-12-01 19:30:28 +00:00
|
|
|
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
2023-06-05 11:27:19 +00:00
|
|
|
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)
|
2019-12-01 19:30:28 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 12:31:32 +00:00
|
|
|
/// 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
|
|
|
|
}
|
|
|
|
|
2022-04-15 19:25:44 +00:00
|
|
|
/// Recurses through the given type, normalizing associated types mentioned
|
|
|
|
/// in it by replacing them by type variables and registering obligations to
|
|
|
|
/// resolve later. This should be done once for every type we get from some
|
|
|
|
/// type annotation (e.g. from a let type annotation, field type or function
|
|
|
|
/// call). `make_ty` handles this already, but e.g. for field types we need
|
|
|
|
/// to do it as well.
|
2023-04-23 15:35:04 +00:00
|
|
|
fn normalize_associated_types_in<T>(&mut self, ty: T) -> T
|
|
|
|
where
|
|
|
|
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
|
|
|
{
|
2022-04-15 19:25:44 +00:00
|
|
|
self.table.normalize_associated_types_in(ty)
|
|
|
|
}
|
|
|
|
|
2021-05-16 13:56:27 +00:00
|
|
|
fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
|
2019-12-01 19:30:28 +00:00
|
|
|
self.table.resolve_ty_shallow(ty)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
2019-12-13 11:44:07 +00:00
|
|
|
fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
|
2019-12-19 04:45:07 +00:00
|
|
|
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>,
|
2022-10-11 07:37:35 +00:00
|
|
|
// FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
|
|
|
|
// handled when we support them.
|
2022-03-09 18:50:24 +00:00
|
|
|
params: &[GenericArg],
|
2019-12-19 04:45:07 +00:00
|
|
|
) -> Ty {
|
2019-12-13 11:44:07 +00:00
|
|
|
match assoc_ty {
|
|
|
|
Some(res_assoc_ty) => {
|
2020-07-03 15:39:06 +00:00
|
|
|
let trait_ = match res_assoc_ty.lookup(self.db.upcast()).container {
|
2021-12-07 16:31:26 +00:00
|
|
|
hir_def::ItemContainerId::TraitId(trait_) => trait_,
|
2020-07-03 15:39:06 +00:00
|
|
|
_ => panic!("resolve_associated_type called with non-associated type"),
|
|
|
|
};
|
2019-12-13 11:44:07 +00:00
|
|
|
let ty = self.table.new_type_var();
|
2022-03-09 18:50:24 +00:00
|
|
|
let mut param_iter = params.iter().cloned();
|
2021-04-03 19:50:52 +00:00
|
|
|
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
|
2019-12-19 19:04:55 +00:00
|
|
|
.push(inner_ty)
|
2022-03-09 18:50:24 +00:00
|
|
|
.fill(|_| param_iter.next().unwrap())
|
2020-07-03 15:39:06 +00:00
|
|
|
.build();
|
2021-03-19 01:07:15 +00:00
|
|
|
let alias_eq = AliasEq {
|
|
|
|
alias: AliasTy::Projection(ProjectionTy {
|
2021-03-14 15:26:12 +00:00
|
|
|
associated_ty_id: to_assoc_type_id(res_assoc_ty),
|
2021-04-03 19:50:52 +00:00
|
|
|
substitution: trait_ref.substitution.clone(),
|
2021-03-19 01:07:15 +00:00
|
|
|
}),
|
|
|
|
ty: ty.clone(),
|
2019-12-13 11:44:07 +00:00
|
|
|
};
|
2021-12-19 16:58:39 +00:00
|
|
|
self.push_obligation(trait_ref.cast(Interner));
|
|
|
|
self.push_obligation(alias_eq.cast(Interner));
|
2021-05-16 15:56:38 +00:00
|
|
|
ty
|
2019-12-13 11:44:07 +00:00
|
|
|
}
|
2021-03-13 13:44:51 +00:00
|
|
|
None => self.err_ty(),
|
2019-12-13 11:44:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 11:40:18 +00:00
|
|
|
fn resolve_variant(&mut self, path: Option<&Path>, value_ns: bool) -> (Ty, Option<VariantId>) {
|
2019-02-23 14:24:07 +00:00
|
|
|
let path = match path {
|
|
|
|
Some(path) => path,
|
2021-03-13 13:44:51 +00:00
|
|
|
None => return (self.err_ty(), None),
|
2019-02-23 14:24:07 +00:00
|
|
|
};
|
2024-10-30 19:24:19 +00:00
|
|
|
let mut ctx = crate::lower::TyLoweringContext::new(
|
2024-09-06 13:25:22 +00:00
|
|
|
self.db,
|
|
|
|
&self.resolver,
|
|
|
|
&self.body.types,
|
|
|
|
self.owner.into(),
|
|
|
|
);
|
2021-07-22 11:40:18 +00:00
|
|
|
let (resolution, unresolved) = if value_ns {
|
2024-10-07 20:02:02 +00:00
|
|
|
match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
|
2023-08-17 08:52:13 +00:00
|
|
|
Some(ResolveValueResult::ValueNs(value, _)) => match value {
|
2021-07-22 11:40:18 +00:00
|
|
|
ValueNs::EnumVariantId(var) => {
|
|
|
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(
|
|
|
|
InferenceTyDiagnosticSource::Body,
|
|
|
|
ctx.diagnostics,
|
|
|
|
);
|
2024-01-15 09:24:14 +00:00
|
|
|
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2021-07-22 11:40:18 +00:00
|
|
|
return (ty, Some(var.into()));
|
|
|
|
}
|
|
|
|
ValueNs::StructId(strukt) => {
|
|
|
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(
|
|
|
|
InferenceTyDiagnosticSource::Body,
|
|
|
|
ctx.diagnostics,
|
|
|
|
);
|
2021-07-22 11:40:18 +00:00
|
|
|
let ty = self.db.ty(strukt.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2021-07-22 11:40:18 +00:00
|
|
|
return (ty, Some(strukt.into()));
|
|
|
|
}
|
2022-08-23 07:05:52 +00:00
|
|
|
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
|
2021-07-22 11:40:18 +00:00
|
|
|
_ => return (self.err_ty(), None),
|
|
|
|
},
|
2023-08-17 08:52:13 +00:00
|
|
|
Some(ResolveValueResult::Partial(typens, unresolved, _)) => {
|
|
|
|
(typens, Some(unresolved))
|
|
|
|
}
|
2021-07-22 11:40:18 +00:00
|
|
|
None => return (self.err_ty(), None),
|
|
|
|
}
|
|
|
|
} else {
|
2023-03-08 17:28:52 +00:00
|
|
|
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path) {
|
2023-08-17 08:52:13 +00:00
|
|
|
Some((it, idx, _)) => (it, idx),
|
2021-03-13 13:44:51 +00:00
|
|
|
None => return (self.err_ty(), None),
|
2021-07-22 11:40:18 +00:00
|
|
|
}
|
|
|
|
};
|
2023-03-08 17:28:52 +00:00
|
|
|
let Some(mod_path) = path.mod_path() else {
|
|
|
|
never!("resolver should always resolve lang item paths");
|
|
|
|
return (self.err_ty(), None);
|
|
|
|
};
|
2020-05-15 15:15:40 +00:00
|
|
|
return match resolution {
|
|
|
|
TypeNs::AdtId(AdtId::StructId(strukt)) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, strukt.into(), true);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
2019-11-26 18:04:24 +00:00
|
|
|
let ty = self.db.ty(strukt.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-05-15 15:15:40 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2020-08-07 13:24:20 +00:00
|
|
|
TypeNs::AdtId(AdtId::UnionId(u)) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, u.into(), true);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
2020-08-07 13:24:20 +00:00
|
|
|
let ty = self.db.ty(u.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-08-07 13:24:20 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(u.into())), unresolved)
|
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::EnumVariantId(var) => {
|
2021-03-13 21:44:36 +00:00
|
|
|
let substs = ctx.substs_from_path(path, var.into(), true);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
2024-01-15 09:24:14 +00:00
|
|
|
let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into());
|
2021-12-19 16:58:39 +00:00
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
2020-05-15 15:15:40 +00:00
|
|
|
forbid_unresolved_segments((ty, Some(var.into())), unresolved)
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::SelfType(impl_id) => {
|
2024-06-21 08:49:19 +00:00
|
|
|
let generics = crate::generics::generics(self.db.upcast(), impl_id.into());
|
2022-03-09 18:50:24 +00:00
|
|
|
let substs = generics.placeholder_subst(self.db);
|
2023-03-29 12:44:23 +00:00
|
|
|
let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
|
|
|
|
|
|
|
let Some(mut remaining_idx) = unresolved else {
|
|
|
|
return self.resolve_variant_on_alias(ty, None, mod_path);
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut remaining_segments = path.segments().skip(remaining_idx);
|
|
|
|
|
|
|
|
// We need to try resolving unresolved segments one by one because each may resolve
|
|
|
|
// to a projection, which `TyLoweringContext` cannot handle on its own.
|
|
|
|
while !remaining_segments.is_empty() {
|
|
|
|
let resolved_segment = path.segments().get(remaining_idx - 1).unwrap();
|
|
|
|
let current_segment = remaining_segments.take(1);
|
|
|
|
|
|
|
|
// 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 = self.db.enum_data(id);
|
|
|
|
let name = current_segment.first().unwrap().name;
|
2024-01-15 09:24:14 +00:00
|
|
|
if let Some(variant) = enum_data.variant(name) {
|
2023-03-29 12:44:23 +00:00
|
|
|
return if remaining_segments.len() == 1 {
|
|
|
|
(ty, Some(variant.into()))
|
|
|
|
} else {
|
|
|
|
// We still have unresolved paths, but enum variants never have
|
|
|
|
// associated types!
|
|
|
|
(self.err_ty(), None)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// `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, _) = ctx.lower_partly_resolved_path(
|
|
|
|
resolution,
|
|
|
|
resolved_segment,
|
|
|
|
current_segment,
|
|
|
|
false,
|
2024-11-20 21:05:48 +00:00
|
|
|
&mut |_, _reason| {
|
|
|
|
// FIXME: Report an error.
|
|
|
|
},
|
2023-03-29 12:44:23 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
ty = self.table.insert_type_vars(ty);
|
|
|
|
ty = self.table.normalize_associated_types_in(ty);
|
|
|
|
ty = self.table.resolve_ty_shallow(&ty);
|
|
|
|
if ty.is_unknown() {
|
|
|
|
return (self.err_ty(), None);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(inherent_associated_types): update `resolution` based on `ty` here.
|
|
|
|
remaining_idx += 1;
|
|
|
|
remaining_segments = remaining_segments.skip(1);
|
|
|
|
}
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
2023-03-29 12:44:23 +00:00
|
|
|
|
|
|
|
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)
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
TypeNs::TypeAliasId(it) => {
|
2023-11-26 12:46:02 +00:00
|
|
|
let resolved_seg = match unresolved {
|
|
|
|
None => path.segments().last().unwrap(),
|
|
|
|
Some(n) => path.segments().get(path.segments().len() - n - 1).unwrap(),
|
2022-10-11 07:37:35 +00:00
|
|
|
};
|
2023-11-26 12:46:02 +00:00
|
|
|
let substs =
|
|
|
|
ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None);
|
2024-11-20 21:05:48 +00:00
|
|
|
self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics);
|
2023-11-26 12:46:02 +00:00
|
|
|
let ty = self.db.ty(it.into());
|
|
|
|
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
|
|
|
|
2023-03-08 17:28:52 +00:00
|
|
|
self.resolve_variant_on_alias(ty, unresolved, mod_path)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
TypeNs::AdtSelfType(_) => {
|
|
|
|
// FIXME this could happen in array size expressions, once we're checking them
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
TypeNs::GenericParam(_) => {
|
|
|
|
// FIXME potentially resolve assoc type
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
2023-03-03 15:24:07 +00:00
|
|
|
TypeNs::AdtId(AdtId::EnumId(_))
|
|
|
|
| TypeNs::BuiltinType(_)
|
|
|
|
| TypeNs::TraitId(_)
|
|
|
|
| TypeNs::TraitAliasId(_) => {
|
2020-05-15 15:15:40 +00:00
|
|
|
// FIXME diagnostic
|
2021-03-13 13:44:51 +00:00
|
|
|
(self.err_ty(), None)
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-15 15:15:40 +00:00
|
|
|
fn forbid_unresolved_segments(
|
|
|
|
result: (Ty, Option<VariantId>),
|
|
|
|
unresolved: Option<usize>,
|
|
|
|
) -> (Ty, Option<VariantId>) {
|
|
|
|
if unresolved.is_none() {
|
|
|
|
result
|
|
|
|
} else {
|
|
|
|
// FIXME diagnostic
|
2021-12-19 16:58:39 +00:00
|
|
|
(TyKind::Error.intern(Interner), None)
|
2020-05-15 15:15:40 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-07 09:31:50 +00:00
|
|
|
}
|
2020-05-15 15:15:40 +00:00
|
|
|
|
2021-04-07 09:31:50 +00:00
|
|
|
fn resolve_variant_on_alias(
|
|
|
|
&mut self,
|
|
|
|
ty: Ty,
|
|
|
|
unresolved: Option<usize>,
|
2023-03-08 17:28:52 +00:00
|
|
|
path: &ModPath,
|
2021-04-07 09:31:50 +00:00
|
|
|
) -> (Ty, Option<VariantId>) {
|
2023-07-06 14:03:17 +00:00
|
|
|
let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0);
|
2023-12-18 14:31:58 +00:00
|
|
|
let ty = match ty.kind(Interner) {
|
|
|
|
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
|
2024-08-14 00:37:20 +00:00
|
|
|
let ty = self.table.normalize_projection_ty(proj_ty.clone());
|
|
|
|
self.table.resolve_ty_shallow(&ty)
|
2023-12-18 14:31:58 +00:00
|
|
|
}
|
|
|
|
_ => ty,
|
|
|
|
};
|
2022-04-27 15:34:08 +00:00
|
|
|
match remaining {
|
2021-04-07 09:31:50 +00:00
|
|
|
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) => {
|
2023-03-08 17:28:52 +00:00
|
|
|
let segment = path.segments().last().unwrap();
|
2021-04-07 09:31:50 +00:00
|
|
|
// this could be an enum variant or associated type
|
|
|
|
if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
|
|
|
|
let enum_data = self.db.enum_data(enum_id);
|
2024-01-15 09:24:14 +00:00
|
|
|
if let Some(variant) = enum_data.variant(segment) {
|
2021-04-07 09:31:50 +00:00
|
|
|
return (ty, Some(variant.into()));
|
|
|
|
}
|
2020-03-06 14:26:49 +00:00
|
|
|
}
|
2021-04-07 09:31:50 +00:00
|
|
|
// FIXME potentially resolve assoc type
|
|
|
|
(self.err_ty(), None)
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
// FIXME diagnostic
|
|
|
|
(self.err_ty(), None)
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-21 16:29:07 +00:00
|
|
|
fn resolve_lang_item(&self, item: LangItem) -> Option<LangItemTarget> {
|
2022-03-31 09:12:08 +00:00
|
|
|
let krate = self.resolver.krate();
|
2023-01-21 16:29:07 +00:00
|
|
|
self.db.lang_item(krate, item)
|
2019-12-29 16:39:31 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 10:25:34 +00:00
|
|
|
fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> {
|
2024-07-14 10:19:19 +00:00
|
|
|
self.db
|
|
|
|
.trait_data(trait_)
|
|
|
|
.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))
|
2022-10-26 14:40:41 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 10:25:34 +00:00
|
|
|
fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> {
|
|
|
|
self.resolve_lang_item(lang)?.as_trait()
|
|
|
|
}
|
|
|
|
|
2019-12-13 11:44:42 +00:00
|
|
|
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
|
2023-01-27 10:25:34 +00:00
|
|
|
self.resolve_output_on(self.resolve_lang_trait(LangItem::Neg)?)
|
2019-12-13 11:44:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
|
2023-01-27 10:25:34 +00:00
|
|
|
self.resolve_output_on(self.resolve_lang_trait(LangItem::Not)?)
|
2019-12-13 11:44:42 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 12:56:20 +00:00
|
|
|
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let ItemContainerId::TraitId(trait_) = self
|
|
|
|
.resolve_lang_item(LangItem::IntoFutureIntoFuture)?
|
|
|
|
.as_function()?
|
|
|
|
.lookup(self.db.upcast())
|
|
|
|
.container
|
2023-07-03 18:34:09 +00:00
|
|
|
else {
|
|
|
|
return None;
|
|
|
|
};
|
2023-01-27 10:25:34 +00:00
|
|
|
self.resolve_output_on(trait_)
|
2019-07-20 11:11:18 +00:00
|
|
|
}
|
2019-09-11 15:53:41 +00:00
|
|
|
|
2019-11-26 11:29:12 +00:00
|
|
|
fn resolve_boxed_box(&self) -> Option<AdtId> {
|
2023-01-21 16:29:07 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::OwnedBox)?.as_struct()?;
|
2019-11-26 11:29:12 +00:00
|
|
|
Some(struct_.into())
|
2019-09-11 15:53:41 +00:00
|
|
|
}
|
2019-11-28 19:10:16 +00:00
|
|
|
|
|
|
|
fn resolve_range_full(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::RangeFull)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::Range)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_inclusive(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::RangeInclusiveStruct)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_from(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::RangeFrom)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_to(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::RangeTo)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
|
2023-01-21 17:47:37 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::RangeToInclusive)?.as_struct()?;
|
2019-11-28 19:10:16 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
2019-12-19 04:45:07 +00:00
|
|
|
|
|
|
|
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
|
2023-01-27 10:25:34 +00:00
|
|
|
self.resolve_output_on(self.resolve_lang_trait(LangItem::Index)?)
|
2019-12-19 04:45:07 +00:00
|
|
|
}
|
2022-11-28 23:32:13 +00:00
|
|
|
|
|
|
|
fn resolve_va_list(&self) -> Option<AdtId> {
|
2023-01-21 16:29:07 +00:00
|
|
|
let struct_ = self.resolve_lang_item(LangItem::VaList)?.as_struct()?;
|
2022-11-28 23:32:13 +00:00
|
|
|
Some(struct_.into())
|
|
|
|
}
|
2023-03-05 14:04:46 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// When inferring an expression, we propagate downward whatever type hint we
|
|
|
|
/// are able in the form of an `Expectation`.
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
2022-03-09 18:50:24 +00:00
|
|
|
pub(crate) enum Expectation {
|
2021-05-21 15:41:20 +00:00
|
|
|
None,
|
|
|
|
HasType(Ty),
|
2023-02-10 15:08:47 +00:00
|
|
|
#[allow(dead_code)]
|
2023-02-08 11:57:08 +00:00
|
|
|
Castable(Ty),
|
2021-05-21 15:41:20 +00:00
|
|
|
RValueLikeUnsized(Ty),
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Expectation {
|
|
|
|
/// The expectation that the type of the expression needs to equal the given
|
|
|
|
/// type.
|
|
|
|
fn has_type(ty: Ty) -> Self {
|
2021-05-21 15:41:20 +00:00
|
|
|
if ty.is_unknown() {
|
|
|
|
// FIXME: get rid of this?
|
|
|
|
Expectation::None
|
|
|
|
} else {
|
|
|
|
Expectation::HasType(ty)
|
|
|
|
}
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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:
|
|
|
|
///
|
2023-07-06 14:03:17 +00:00
|
|
|
/// let it: &[isize] = &[1, 2, 3];
|
2020-02-29 14:31:07 +00:00
|
|
|
///
|
|
|
|
/// 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,.
|
2023-03-29 12:31:32 +00:00
|
|
|
fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self {
|
|
|
|
match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) {
|
2021-05-21 15:41:20 +00:00
|
|
|
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
|
|
|
|
_ => Expectation::has_type(ty),
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This expresses no expectation on the type.
|
|
|
|
fn none() -> Self {
|
2021-05-21 15:41:20 +00:00
|
|
|
Expectation::None
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:02:08 +00:00
|
|
|
fn resolve(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
|
2021-05-21 15:41:20 +00:00
|
|
|
match self {
|
|
|
|
Expectation::None => Expectation::None,
|
|
|
|
Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
|
2023-02-08 11:57:08 +00:00
|
|
|
Expectation::Castable(t) => Expectation::Castable(table.resolve_ty_shallow(t)),
|
2021-05-21 15:41:20 +00:00
|
|
|
Expectation::RValueLikeUnsized(t) => {
|
|
|
|
Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
|
|
|
|
}
|
2021-03-14 16:25:29 +00:00
|
|
|
}
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
|
|
|
|
2022-07-20 13:02:08 +00:00
|
|
|
fn to_option(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
|
2021-05-21 15:41:20 +00:00
|
|
|
match self.resolve(table) {
|
|
|
|
Expectation::None => None,
|
2023-02-08 11:57:08 +00:00
|
|
|
Expectation::HasType(t)
|
|
|
|
| Expectation::Castable(t)
|
|
|
|
| Expectation::RValueLikeUnsized(t) => Some(t),
|
2021-05-21 15:41:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-20 13:02:08 +00:00
|
|
|
fn only_has_type(&self, table: &mut unify::InferenceTable<'_>) -> Option<Ty> {
|
2021-05-21 15:41:20 +00:00
|
|
|
match self {
|
|
|
|
Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
|
2023-02-08 11:57:08 +00:00
|
|
|
Expectation::Castable(_) | Expectation::RValueLikeUnsized(_) | Expectation::None => {
|
|
|
|
None
|
|
|
|
}
|
2020-02-29 14:31:07 +00:00
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2021-06-03 21:12:35 +00:00
|
|
|
|
2023-02-10 15:08:47 +00:00
|
|
|
fn coercion_target_type(&self, table: &mut unify::InferenceTable<'_>) -> Ty {
|
|
|
|
self.only_has_type(table).unwrap_or_else(|| table.new_type_var())
|
|
|
|
}
|
|
|
|
|
2021-06-03 21:12:35 +00:00
|
|
|
/// 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.
|
2022-07-20 13:02:08 +00:00
|
|
|
fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'_>) -> Expectation {
|
2021-06-03 21:12:35 +00:00
|
|
|
match self {
|
|
|
|
Expectation::HasType(ety) => {
|
2021-06-13 03:54:16 +00:00
|
|
|
let ety = table.resolve_ty_shallow(ety);
|
2024-01-17 17:23:14 +00:00
|
|
|
if ety.is_ty_var() {
|
2021-06-03 21:12:35 +00:00
|
|
|
Expectation::None
|
2024-01-17 17:23:14 +00:00
|
|
|
} else {
|
|
|
|
Expectation::HasType(ety)
|
2021-06-03 21:12:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
|
|
|
|
_ => Expectation::None,
|
|
|
|
}
|
|
|
|
}
|
2019-02-23 14:24:07 +00:00
|
|
|
}
|
2019-03-23 13:28:47 +00:00
|
|
|
|
2020-05-08 15:36:11 +00:00
|
|
|
#[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;
|
|
|
|
}
|
|
|
|
}
|
2024-04-01 18:29:36 +00:00
|
|
|
|
|
|
|
/// 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<'_> {
|
2024-02-16 11:16:43 +00:00
|
|
|
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) => (),
|
2024-04-01 18:29:36 +00:00
|
|
|
(TyKind::Error, _)
|
|
|
|
| (_, TyKind::Error)
|
|
|
|
| (TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _), _)
|
|
|
|
| (_, TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _)) => {
|
|
|
|
return Err(chalk_ir::NoSolution)
|
|
|
|
}
|
2024-02-16 11:16:43 +00:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|