Migrate inference to next solver

This commit is contained in:
Chayim Refael Friedman 2025-09-30 10:36:23 +03:00
parent 2b2d9d8f88
commit d1288f6353
90 changed files with 4560 additions and 4904 deletions

View file

@ -18,7 +18,7 @@ use base_db::salsa;
use either::Either;
use hir_def::{
AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId,
ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
LocalFieldId, ModuleDefId, StructId, TraitId, VariantId,
expr_store::{
Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId,
lower::ExprCollector,
@ -36,9 +36,10 @@ use hir_expand::{
mod_path::{ModPath, PathKind, path},
name::{AsName, Name},
};
use hir_ty::next_solver::GenericArgs;
use hir_ty::{
Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy,
Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
Substitution, ToChalk, TraitEnvironment, Ty, TyKind, TyLoweringContext,
diagnostics::{
InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
unsafe_operations,
@ -67,16 +68,16 @@ use triomphe::Arc;
pub(crate) struct SourceAnalyzer<'db> {
pub(crate) file_id: HirFileId,
pub(crate) resolver: Resolver<'db>,
pub(crate) body_or_sig: Option<BodyOrSig>,
pub(crate) body_or_sig: Option<BodyOrSig<'db>>,
}
#[derive(Debug)]
pub(crate) enum BodyOrSig {
pub(crate) enum BodyOrSig<'db> {
Body {
def: DefWithBodyId,
body: Arc<Body>,
source_map: Arc<BodySourceMap>,
infer: Option<Arc<InferenceResult>>,
infer: Option<Arc<InferenceResult<'db>>>,
},
// To be folded into body once it is considered one
VariantFields {
@ -116,7 +117,7 @@ impl<'db> SourceAnalyzer<'db> {
def: DefWithBodyId,
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
offset: Option<TextSize>,
infer: Option<Arc<InferenceResult>>,
infer: Option<Arc<InferenceResult<'db>>>,
) -> SourceAnalyzer<'db> {
let (body, source_map) = db.body_with_source_map(def);
let scopes = db.expr_scopes(def);
@ -182,7 +183,9 @@ impl<'db> SourceAnalyzer<'db> {
}
// FIXME: Remove this
fn body_(&self) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult>)> {
fn body_(
&self,
) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult<'db>>)> {
self.body_or_sig.as_ref().and_then(|it| match it {
BodyOrSig::Body { def, body, source_map, infer } => {
Some((*def, &**body, &**source_map, infer.as_deref()))
@ -191,7 +194,7 @@ impl<'db> SourceAnalyzer<'db> {
})
}
fn infer(&self) -> Option<&InferenceResult> {
fn infer(&self) -> Option<&InferenceResult<'db>> {
self.body_or_sig.as_ref().and_then(|it| match it {
BodyOrSig::Sig { .. } => None,
BodyOrSig::VariantFields { .. } => None,
@ -250,7 +253,7 @@ impl<'db> SourceAnalyzer<'db> {
if let Pat::Bind { id, .. } = self.store()?[pat_id.as_pat()?] { Some(id) } else { None }
}
pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]> {
pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment<'db>]> {
// It is safe to omit destructuring assignments here because they have no adjustments (neither
// expressions nor patterns).
let expr_id = self.expr_id(expr.clone())?.as_expr()?;
@ -288,9 +291,11 @@ impl<'db> SourceAnalyzer<'db> {
let coerced = expr_id
.as_expr()
.and_then(|expr_id| infer.expr_adjustment(expr_id))
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
let ty = infer[expr_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
.and_then(|adjusts| adjusts.last().map(|adjust| adjust.target));
let ty = infer[expr_id];
let mk_ty = |ty: hir_ty::next_solver::Ty<'_>| {
Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))
};
Some((mk_ty(ty), coerced.map(mk_ty)))
}
@ -311,8 +316,10 @@ impl<'db> SourceAnalyzer<'db> {
}
};
let ty = infer[expr_or_pat_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
let ty = infer[expr_or_pat_id];
let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| {
Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))
};
Some((mk_ty(ty), coerced.map(mk_ty)))
}
@ -323,8 +330,10 @@ impl<'db> SourceAnalyzer<'db> {
) -> Option<Type<'db>> {
let binding_id = self.binding_id_of_pat(pat)?;
let infer = self.infer()?;
let ty = infer[binding_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
let ty = infer[binding_id];
let mk_ty = |ty: hir_ty::next_solver::Ty<'db>| {
Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))
};
Some(mk_ty(ty))
}
@ -334,8 +343,8 @@ impl<'db> SourceAnalyzer<'db> {
_param: &ast::SelfParam,
) -> Option<Type<'db>> {
let binding = self.body()?.self_param?;
let ty = self.infer()?[binding].clone();
Some(Type::new_with_resolver(db, &self.resolver, ty))
let ty = self.infer()?[binding];
Some(Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure())))
}
pub(crate) fn binding_mode_of_pat(
@ -347,8 +356,10 @@ impl<'db> SourceAnalyzer<'db> {
let infer = self.infer()?;
infer.binding_mode(id.as_pat()?).map(|bm| match bm {
hir_ty::BindingMode::Move => BindingMode::Move,
hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Mut) => {
BindingMode::Ref(Mutability::Mut)
}
hir_ty::BindingMode::Ref(hir_ty::next_solver::Mutability::Not) => {
BindingMode::Ref(Mutability::Shared)
}
})
@ -364,7 +375,9 @@ impl<'db> SourceAnalyzer<'db> {
infer
.pat_adjustment(pat_id.as_pat()?)?
.iter()
.map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
.map(|ty| {
Type::new_with_resolver(db, &self.resolver, ty.to_chalk(DbInterner::conjure()))
})
.collect(),
)
}
@ -375,9 +388,8 @@ impl<'db> SourceAnalyzer<'db> {
call: &ast::MethodCallExpr,
) -> Option<Callable<'db>> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
let (func, substs) = self.infer()?.method_resolution(expr_id)?;
let (func, args) = self.infer()?.method_resolution(expr_id)?;
let interner = DbInterner::new_with(db, None, None);
let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
let ty = db.value_ty(func.into())?.instantiate(interner, args);
let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner));
let mut res = ty.as_callable(db)?;
@ -403,13 +415,18 @@ impl<'db> SourceAnalyzer<'db> {
) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
let inference_result = self.infer()?;
let interner = DbInterner::new_with(db, None, None);
match inference_result.method_resolution(expr_id) {
Some((f_in_trait, substs)) => {
let (fn_, subst) =
self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs);
Some((
Either::Left(fn_.into()),
Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))),
Some(GenericSubstitution::new(
fn_.into(),
subst.to_chalk(interner),
self.trait_environment(db),
)),
))
}
None => {
@ -443,7 +460,7 @@ impl<'db> SourceAnalyzer<'db> {
fn field_subst(
&self,
field_expr: ExprId,
infer: &InferenceResult,
infer: &InferenceResult<'db>,
db: &'db dyn HirDatabase,
) -> Option<GenericSubstitution<'db>> {
let body = self.store()?;
@ -451,7 +468,7 @@ impl<'db> SourceAnalyzer<'db> {
let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?;
return Some(GenericSubstitution::new(
adt.into(),
subst.clone(),
subst.to_chalk(DbInterner::conjure()),
self.trait_environment(db),
));
}
@ -467,6 +484,7 @@ impl<'db> SourceAnalyzer<'db> {
let (def, ..) = self.body_()?;
let expr_id = self.expr_id(field.clone().into())?.as_expr()?;
let inference_result = self.infer()?;
let interner = DbInterner::new_with(db, None, None);
match inference_result.field_resolution(expr_id) {
Some(field) => match field {
Either::Left(field) => Some((
@ -486,7 +504,11 @@ impl<'db> SourceAnalyzer<'db> {
let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs);
(
Either::Right(f.into()),
Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))),
Some(GenericSubstitution::new(
f.into(),
subst.to_chalk(interner),
self.trait_environment(db),
)),
)
}),
}
@ -560,11 +582,11 @@ impl<'db> SourceAnalyzer<'db> {
}
}
let future_trait = LangItem::Future.resolve_trait(db, self.resolver.krate())?;
let poll_fn = LangItem::FuturePoll.resolve_function(db, self.resolver.krate())?;
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
let interner = DbInterner::new_with(db, None, None);
let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]);
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
}
@ -573,7 +595,7 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
prefix_expr: &ast::PrefixExpr,
) -> Option<FunctionId> {
let (op_trait, op_fn) = match prefix_expr.op_kind()? {
let (_op_trait, op_fn) = match prefix_expr.op_kind()? {
ast::UnaryOp::Deref => {
// This can be either `Deref::deref` or `DerefMut::deref_mut`.
// Since deref kind is inferenced and stored in `InferenceResult.method_resolution`,
@ -603,9 +625,10 @@ impl<'db> SourceAnalyzer<'db> {
let ty = self.ty_of_expr(prefix_expr.expr()?)?;
let interner = DbInterner::new_with(db, None, None);
// HACK: subst for all methods coincides with that for their trait because the methods
// don't have any generic parameters, so we skip building another subst for the methods.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]);
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
@ -618,27 +641,28 @@ impl<'db> SourceAnalyzer<'db> {
let base_ty = self.ty_of_expr(index_expr.base()?)?;
let index_ty = self.ty_of_expr(index_expr.index()?)?;
let (index_trait, index_fn) =
let (_index_trait, index_fn) =
self.lang_trait_fn(db, LangItem::Index, &Name::new_symbol_root(sym::index))?;
let (op_trait, op_fn) = self
let op_fn = self
.infer()
.and_then(|infer| {
let expr = self.expr_id(index_expr.clone().into())?.as_expr()?;
let (func, _) = infer.method_resolution(expr)?;
let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
let (_index_mut_trait, index_mut_fn) = self.lang_trait_fn(
db,
LangItem::IndexMut,
&Name::new_symbol_root(sym::index_mut),
)?;
if func == index_mut_fn { Some((index_mut_trait, index_mut_fn)) } else { None }
if func == index_mut_fn { Some(index_mut_fn) } else { None }
})
.unwrap_or((index_trait, index_fn));
.unwrap_or(index_fn);
// HACK: subst for all methods coincides with that for their trait because the methods
// don't have any generic parameters, so we skip building another subst for the methods.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
.push(base_ty.clone())
.push(index_ty.clone())
.build();
let interner = DbInterner::new_with(db, None, None);
let substs = GenericArgs::new_from_iter(
interner,
[base_ty.to_nextsolver(interner).into(), index_ty.to_nextsolver(interner).into()],
);
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
@ -651,14 +675,15 @@ impl<'db> SourceAnalyzer<'db> {
let lhs = self.ty_of_expr(binop_expr.lhs()?)?;
let rhs = self.ty_of_expr(binop_expr.rhs()?)?;
let (op_trait, op_fn) = lang_items_for_bin_op(op)
let (_op_trait, op_fn) = lang_items_for_bin_op(op)
.and_then(|(name, lang_item)| self.lang_trait_fn(db, lang_item, &name))?;
// HACK: subst for `index()` coincides with that for `Index` because `index()` itself
// doesn't have any generic parameters, so we skip building another subst for `index()`.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
.push(lhs.clone())
.push(rhs.clone())
.build();
let interner = DbInterner::new_with(db, None, None);
let substs = GenericArgs::new_from_iter(
interner,
[lhs.to_nextsolver(interner).into(), rhs.to_nextsolver(interner).into()],
);
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
@ -671,13 +696,10 @@ impl<'db> SourceAnalyzer<'db> {
let ty = self.ty_of_expr(try_expr.expr()?)?;
let op_fn = LangItem::TryTraitBranch.resolve_function(db, self.resolver.krate())?;
let op_trait = match op_fn.lookup(db).container {
ItemContainerId::TraitId(id) => id,
_ => return None,
};
// HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
let interner = DbInterner::new_with(db, None, None);
let substs = GenericArgs::new_from_iter(interner, [ty.to_nextsolver(interner).into()]);
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
@ -690,6 +712,7 @@ impl<'db> SourceAnalyzer<'db> {
let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
let expr = ast::Expr::from(record_expr);
let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?;
let interner = DbInterner::new_with(db, None, None);
let ast_name = field.field_name()?;
let local_name = ast_name.as_name();
@ -713,16 +736,17 @@ impl<'db> SourceAnalyzer<'db> {
}
};
let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
let subst = subst.to_chalk(interner);
let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?;
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
let field_ty =
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst);
Some((
field.into(),
local,
Type::new_with_resolver(db, &self.resolver, field_ty),
GenericSubstitution::new(adt.into(), subst.clone(), self.trait_environment(db)),
GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)),
))
}
@ -731,6 +755,7 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
field: &ast::RecordPatField,
) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
let interner = DbInterner::new_with(db, None, None);
let field_name = field.field_name()?.as_name();
let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
let pat_id = self.pat_id(&record_pat.into())?;
@ -738,12 +763,13 @@ impl<'db> SourceAnalyzer<'db> {
let variant_data = variant.fields(db);
let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?;
let subst = subst.to_chalk(interner);
let field_ty =
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, &subst);
Some((
field.into(),
Type::new_with_resolver(db, &self.resolver, field_ty),
GenericSubstitution::new(adt.into(), subst.clone(), self.trait_environment(db)),
GenericSubstitution::new(adt.into(), subst, self.trait_environment(db)),
))
}
@ -859,6 +885,7 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
path: &ast::Path,
) -> Option<(PathResolution, Option<GenericSubstitution<'db>>)> {
let interner = DbInterner::new_with(db, None, None);
let parent = path.syntax().parent();
let parent = || parent.clone();
@ -874,29 +901,31 @@ impl<'db> SourceAnalyzer<'db> {
None => {
let subst = GenericSubstitution::new(
f_in_trait.into(),
subs,
subs.to_chalk(interner),
self.trait_environment(db),
);
(assoc, subst)
}
Some(func_ty) => {
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
if let TyKind::FnDef(_fn_def, subs) =
func_ty.to_chalk(interner).kind(Interner)
{
let (fn_, subst) = self
.resolve_impl_method_or_trait_def_with_subst(
db,
f_in_trait,
subs.clone(),
subs.to_nextsolver(interner),
);
let subst = GenericSubstitution::new(
fn_.into(),
subst,
subst.to_chalk(interner),
self.trait_environment(db),
);
(fn_.into(), subst)
} else {
let subst = GenericSubstitution::new(
f_in_trait.into(),
subs,
subs.to_chalk(interner),
self.trait_environment(db),
);
(assoc, subst)
@ -909,7 +938,7 @@ impl<'db> SourceAnalyzer<'db> {
self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);
let subst = GenericSubstitution::new(
konst.into(),
subst,
subst.to_chalk(interner),
self.trait_environment(db),
);
(konst.into(), subst)
@ -918,7 +947,7 @@ impl<'db> SourceAnalyzer<'db> {
assoc,
GenericSubstitution::new(
type_alias.into(),
subs,
subs.to_chalk(interner),
self.trait_environment(db),
),
),
@ -942,7 +971,7 @@ impl<'db> SourceAnalyzer<'db> {
self.resolve_impl_const_or_trait_def_with_subst(db, const_id, subs);
let subst = GenericSubstitution::new(
konst.into(),
subst,
subst.to_chalk(interner),
self.trait_environment(db),
);
(konst.into(), subst)
@ -951,7 +980,7 @@ impl<'db> SourceAnalyzer<'db> {
assoc,
GenericSubstitution::new(
assoc.into(),
subs,
subs.to_chalk(interner),
self.trait_environment(db),
),
),
@ -1149,10 +1178,10 @@ impl<'db> SourceAnalyzer<'db> {
let parent = parent()?;
let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {
let expr_id = self.expr_id(expr)?;
self.infer()?.type_of_expr_or_pat(expr_id)?
self.infer()?.type_of_expr_or_pat(expr_id)?.to_chalk(interner)
} else if let Some(pat) = ast::Pat::cast(parent) {
let pat_id = self.pat_id(&pat)?;
&self.infer()?[pat_id]
self.infer()?[pat_id].to_chalk(interner)
} else {
return None;
};
@ -1232,7 +1261,8 @@ impl<'db> SourceAnalyzer<'db> {
record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?
}
};
let res = self.missing_fields(db, substs, variant, missing_fields);
let interner = DbInterner::new_with(db, None, None);
let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields);
Some(res)
}
@ -1249,7 +1279,8 @@ impl<'db> SourceAnalyzer<'db> {
let (variant, missing_fields, _exhaustive) =
record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
let res = self.missing_fields(db, substs, variant, missing_fields);
let interner = DbInterner::new_with(db, None, None);
let res = self.missing_fields(db, &substs.to_chalk(interner), variant, missing_fields);
Some(res)
}
@ -1379,7 +1410,7 @@ impl<'db> SourceAnalyzer<'db> {
&self,
db: &'db dyn HirDatabase,
func: FunctionId,
substs: Substitution,
substs: GenericArgs<'db>,
) -> FunctionId {
self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0
}
@ -1388,8 +1419,8 @@ impl<'db> SourceAnalyzer<'db> {
&self,
db: &'db dyn HirDatabase,
func: FunctionId,
substs: Substitution,
) -> (FunctionId, Substitution) {
substs: GenericArgs<'db>,
) -> (FunctionId, GenericArgs<'db>) {
let owner = match self.resolver.body_owner() {
Some(it) => it,
None => return (func, substs),
@ -1402,14 +1433,19 @@ impl<'db> SourceAnalyzer<'db> {
&self,
db: &'db dyn HirDatabase,
const_id: ConstId,
subs: Substitution,
) -> (ConstId, Substitution) {
subs: GenericArgs<'db>,
) -> (ConstId, GenericArgs<'db>) {
let owner = match self.resolver.body_owner() {
Some(it) => it,
None => return (const_id, subs),
};
let env = db.trait_environment_for_body(owner);
method_resolution::lookup_impl_const(db, env, const_id, subs)
method_resolution::lookup_impl_const(
DbInterner::new_with(db, None, None),
env,
const_id,
subs,
)
}
fn lang_trait_fn(
@ -1423,8 +1459,10 @@ impl<'db> SourceAnalyzer<'db> {
Some((trait_id, fn_id))
}
fn ty_of_expr(&self, expr: ast::Expr) -> Option<&Ty> {
self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?)
fn ty_of_expr(&self, expr: ast::Expr) -> Option<Ty> {
self.infer()?
.type_of_expr_or_pat(self.expr_id(expr)?)
.map(|ty| ty.to_chalk(DbInterner::conjure()))
}
}