diff --git a/frontend/exporter/src/types/new/full_def.rs b/frontend/exporter/src/types/new/full_def.rs index 281a4b17a..fcc920612 100644 --- a/frontend/exporter/src/types/new/full_def.rs +++ b/frontend/exporter/src/types/new/full_def.rs @@ -410,6 +410,15 @@ pub enum FullDefKind { drop_glue: Option, /// Info required to construct a virtual `Drop` impl for this closure. destruct_impl: Box, + /// The function signature when this closure is used as `FnMut` (or `Fn`) in a vtable. + /// `None` if this closure does not support `FnMut` or `Fn`. + /// `Some(sig)` if this closure implements `FnMut` (or `Fn`), + /// where `sig` is the trait method declaration's signature with `Self` + /// replaced by `dyn Trait` and associated types normalized (same as vtable_sig in `AssocFn`). + fn_mut_vtable_sig: Option, + fn_vtable_sig: Option, + fn_mut_sig: Option, + fn_sig: Option, }, // Constants @@ -554,6 +563,43 @@ fn gen_vtable_sig<'tcx>( Some(normalized_sig.sinto(s)) } +#[cfg(feature = "rustc")] +fn gen_closure_sig<'tcx>( + // The state that owns the method DefId + s: &impl UnderOwnerState<'tcx>, + // The `Fn` or `FnMut` trait reference of the closure + fn_or_fn_mut_ref: Option>, + // whether construct a vtable_sig or a real_sig + is_vtable: bool, +) -> Option { + let fn_or_fn_mut_ref = fn_or_fn_mut_ref?; + let tcx = s.base().tcx; + + // Get AssocItems of `Fn` or `FnMut` + let assoc_item = tcx.associated_items(fn_or_fn_mut_ref.def_id); + // Pick `call` or `call_mut` + let call_method = assoc_item.in_definition_order(). + next().map(|elem| elem).unwrap(); + // Get its signature + let fn_decl_sig = tcx.fn_sig(call_method.def_id); + let trait_args = if is_vtable { + // Generate type of shim receiver + let dyn_self = dyn_self_ty(tcx, s.typing_env(), fn_or_fn_mut_ref).unwrap(); + // Construct signature with dyn_self + let mut full_args = vec![ty::GenericArg::from(dyn_self)]; + full_args.extend(fn_or_fn_mut_ref.args[1..].iter()); + tcx.mk_args(&full_args) + } else { + fn_or_fn_mut_ref.args + }; + + // Instantiate and normalize the signature. + let method_decl_sig = fn_decl_sig.instantiate(tcx, trait_args); + let normalized_sig = normalize(tcx, s.typing_env(), method_decl_sig); + + Some(normalized_sig.sinto(s)) +} + #[cfg(feature = "rustc")] /// Construct the `FullDefKind` for this item. /// @@ -822,6 +868,14 @@ where let fn_mut_trait = tcx.lang_items().fn_mut_trait().unwrap(); let fn_trait = tcx.lang_items().fn_trait().unwrap(); let destruct_trait = tcx.lang_items().destruct_trait().unwrap(); + + let fn_mut_ref = matches!(closure.kind(), FnMut | Fn) + .then(|| ty::TraitRef::new(tcx, fn_mut_trait, trait_args)); + + let fn_ref = matches!(closure.kind(), Fn) + .then(|| ty::TraitRef::new(tcx, fn_trait, trait_args)); + + FullDefKind::Closure { param_env: get_param_env(s, args), is_const: tcx.constness(def_id) == rustc_hir::Constness::Const, @@ -840,6 +894,10 @@ where .then(|| virtual_impl_for(s, ty::TraitRef::new(tcx, fn_mut_trait, trait_args))), fn_impl: matches!(closure.kind(), Fn) .then(|| virtual_impl_for(s, ty::TraitRef::new(tcx, fn_trait, trait_args))), + fn_mut_vtable_sig: gen_closure_sig(s, fn_mut_ref, true), + fn_vtable_sig: gen_closure_sig(s, fn_ref, true), + fn_mut_sig: gen_closure_sig(s, fn_mut_ref, false), + fn_sig: gen_closure_sig(s, fn_ref, false), } } kind @ (RDefKind::Const { .. }