Skip to content

Commit a639917

Browse files
committed
fix: handle lifetime variables in CallableSig query
1 parent 1927c2e commit a639917

File tree

1 file changed

+23
-43
lines changed

1 file changed

+23
-43
lines changed

crates/hir-ty/src/lib.rs

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ use std::sync::Arc;
4040
use chalk_ir::{
4141
fold::{Shift, TypeFoldable},
4242
interner::HasInterner,
43-
NoSolution, UniverseIndex,
43+
NoSolution,
4444
};
4545
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
4646
use hir_expand::name;
4747
use itertools::Either;
4848
use traits::FnTrait;
4949
use utils::Generics;
5050

51-
use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
51+
use crate::{
52+
consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
53+
};
5254

5355
pub use autoderef::autoderef;
5456
pub use builder::{ParamKind, TyBuilder};
@@ -533,53 +535,31 @@ pub fn callable_sig_from_fnonce(
533535
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
534536
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
535537

538+
let mut table = InferenceTable::new(db, env.clone());
536539
let b = TyBuilder::trait_ref(db, fn_once_trait);
537540
if b.remaining() != 2 {
538541
return None;
539542
}
540-
let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
541-
let kinds = fn_once
542-
.substitution
543-
.iter(Interner)
544-
.skip(1)
545-
.map(|x| {
546-
let vk = match x.data(Interner) {
547-
chalk_ir::GenericArgData::Ty(_) => {
548-
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
549-
}
550-
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
551-
chalk_ir::GenericArgData::Const(c) => {
552-
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
553-
}
554-
};
555-
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
556-
})
557-
.collect::<Vec<_>>();
558-
559-
// FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
560-
// `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
561-
let trait_env = env.env.clone();
562-
let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env };
563-
let canonical =
564-
Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation };
565-
let subst = match db.trait_solve(krate, canonical) {
566-
Some(Solution::Unique(vars)) => vars.value.subst,
567-
_ => return None,
568-
};
569-
let args = subst.at(Interner, 0).ty(Interner)?;
570-
let params = match args.kind(Interner) {
571-
chalk_ir::TyKind::Tuple(_, subst) => {
572-
subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
573-
}
574-
_ => return None,
575-
};
576543

577-
let fn_once =
578-
TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build();
579-
let projection =
580-
TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution)).build();
544+
// Register two obligations:
545+
// - Self: FnOnce<?args_ty>
546+
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
547+
let args_ty = table.new_type_var();
548+
let trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
549+
let projection = TyBuilder::assoc_type_projection(
550+
db,
551+
output_assoc_type,
552+
Some(trait_ref.substitution.clone()),
553+
)
554+
.build();
555+
table.register_obligation(trait_ref.cast(Interner));
556+
let ret_ty = table.normalize_projection_ty(projection);
557+
558+
let ret_ty = table.resolve_completely(ret_ty);
559+
let args_ty = table.resolve_completely(args_ty);
581560

582-
let ret_ty = db.normalize_projection(projection, env);
561+
let params =
562+
args_ty.as_tuple()?.iter(Interner).map(|it| it.assert_ty_ref(Interner)).cloned().collect();
583563

584564
Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe))
585565
}

0 commit comments

Comments
 (0)