diff options
| author | Ryo Yoshida <low.ryoshida@gmail.com> | 2022-12-25 05:07:44 +0900 |
|---|---|---|
| committer | Ryo Yoshida <low.ryoshida@gmail.com> | 2022-12-25 05:07:44 +0900 |
| commit | a639917b6612692a3c76a47c9b747c8bfbfaec0f (patch) | |
| tree | f4b8bf1c2334326e3522c27235f0173457f6f9ee | |
| parent | 1927c2e1d8d222656cae7051cdd924aa44428622 (diff) | |
| download | rust-a639917b6612692a3c76a47c9b747c8bfbfaec0f.tar.gz rust-a639917b6612692a3c76a47c9b747c8bfbfaec0f.zip | |
fix: handle lifetime variables in `CallableSig` query
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 66 |
1 files changed, 23 insertions, 43 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 48581d4e0a4..41151e4a116 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -40,7 +40,7 @@ use std::sync::Arc; use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, - NoSolution, UniverseIndex, + NoSolution, }; use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId}; use hir_expand::name; @@ -48,7 +48,9 @@ use itertools::Either; use traits::FnTrait; use utils::Generics; -use crate::{consteval::unknown_const, db::HirDatabase, utils::generics}; +use crate::{ + consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics, +}; pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; @@ -533,53 +535,31 @@ pub fn callable_sig_from_fnonce( let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; + let mut table = InferenceTable::new(db, env.clone()); let b = TyBuilder::trait_ref(db, fn_once_trait); if b.remaining() != 2 { return None; } - let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); - let kinds = fn_once - .substitution - .iter(Interner) - .skip(1) - .map(|x| { - let vk = match x.data(Interner) { - chalk_ir::GenericArgData::Ty(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, - chalk_ir::GenericArgData::Const(c) => { - chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) - } - }; - chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) - }) - .collect::<Vec<_>>(); - - // FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve - // `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple. - let trait_env = env.env.clone(); - let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env }; - let canonical = - Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation }; - let subst = match db.trait_solve(krate, canonical) { - Some(Solution::Unique(vars)) => vars.value.subst, - _ => return None, - }; - let args = subst.at(Interner, 0).ty(Interner)?; - let params = match args.kind(Interner) { - chalk_ir::TyKind::Tuple(_, subst) => { - subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>() - } - _ => return None, - }; - let fn_once = - TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build(); - let projection = - TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution)).build(); + // Register two obligations: + // - Self: FnOnce<?args_ty> + // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty + let args_ty = table.new_type_var(); + let trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build(); + let projection = TyBuilder::assoc_type_projection( + db, + output_assoc_type, + Some(trait_ref.substitution.clone()), + ) + .build(); + table.register_obligation(trait_ref.cast(Interner)); + let ret_ty = table.normalize_projection_ty(projection); + + let ret_ty = table.resolve_completely(ret_ty); + let args_ty = table.resolve_completely(args_ty); - let ret_ty = db.normalize_projection(projection, env); + let params = + args_ty.as_tuple()?.iter(Interner).map(|it| it.assert_ty_ref(Interner)).cloned().collect(); Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe)) } |
