Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lib.rs')
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 1727cec989..26a839f0e9 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -570,6 +570,10 @@ impl CallableSig { } } + pub fn abi(&self) -> FnAbi { + self.abi + } + pub fn params(&self) -> &[Ty] { &self.params_and_return[0..self.params_and_return.len() - 1] } @@ -892,20 +896,16 @@ where Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } } -pub fn callable_sig_from_fnonce( - mut self_ty: &Ty, - env: Arc<TraitEnvironment>, +pub fn callable_sig_from_fn_trait( + self_ty: &Ty, + trait_env: Arc<TraitEnvironment>, db: &dyn HirDatabase, -) -> Option<CallableSig> { - if let Some((ty, _, _)) = self_ty.as_reference() { - // This will happen when it implements fn or fn mut, since we add a autoborrow adjustment - self_ty = ty; - } - let krate = env.krate; +) -> Option<(FnTrait, CallableSig)> { + let krate = trait_env.krate; 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); + let mut table = InferenceTable::new(db, trait_env.clone()); let b = TyBuilder::trait_ref(db, fn_once_trait); if b.remaining() != 2 { return None; @@ -915,23 +915,56 @@ pub fn callable_sig_from_fnonce( // - 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 mut 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 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, FnAbi::RustCall)) + let block = trait_env.block; + let trait_env = trait_env.env.clone(); + let obligation = + InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() }; + let canonical = table.canonicalize(obligation.clone()); + if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { + table.register_obligation(obligation.goal); + let return_ty = table.normalize_projection_ty(projection); + for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { + let fn_x_trait = fn_x.get_id(db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = table.canonicalize(obligation.clone()); + if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { + let ret_ty = table.resolve_completely(return_ty); + let args_ty = table.resolve_completely(args_ty); + let params = args_ty + .as_tuple()? + .iter(Interner) + .map(|it| it.assert_ty_ref(Interner)) + .cloned() + .collect(); + + return Some(( + fn_x, + CallableSig::from_params_and_return( + params, + ret_ty, + false, + Safety::Safe, + FnAbi::RustCall, + ), + )); + } + } + unreachable!("It should at least implement FnOnce at this point"); + } else { + None + } } struct PlaceholderCollector<'db> { |