Skip to main content

rustc_hir_analysis/
delegation.rs

1//! Support inheriting generic parameters and predicates for function delegation.
2//!
3//! For more information about delegation design, see the tracking issue #118212.
4
5use rustc_data_structures::debug_assert_matches;
6use rustc_data_structures::fx::FxHashMap;
7use rustc_hir::def::DefKind;
8use rustc_hir::def_id::{DefId, LocalDefId};
9use rustc_middle::ty::{
10    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
11};
12use rustc_span::{ErrorGuaranteed, Span};
13
14type RemapTable = FxHashMap<u32, u32>;
15
16struct ParamIndexRemapper<'tcx> {
17    tcx: TyCtxt<'tcx>,
18    remap_table: RemapTable,
19}
20
21impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
22    fn cx(&self) -> TyCtxt<'tcx> {
23        self.tcx
24    }
25
26    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
27        if !ty.has_param() {
28            return ty;
29        }
30
31        if let ty::Param(param) = ty.kind()
32            && let Some(index) = self.remap_table.get(&param.index)
33        {
34            return Ty::new_param(self.tcx, *index, param.name);
35        }
36        ty.super_fold_with(self)
37    }
38
39    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
40        if let ty::ReEarlyParam(param) = r.kind()
41            && let Some(index) = self.remap_table.get(&param.index).copied()
42        {
43            return ty::Region::new_early_param(
44                self.tcx,
45                ty::EarlyParamRegion { index, name: param.name },
46            );
47        }
48        r
49    }
50
51    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
52        if let ty::ConstKind::Param(param) = ct.kind()
53            && let Some(idx) = self.remap_table.get(&param.index)
54        {
55            let param = ty::ParamConst::new(*idx, param.name);
56            return ty::Const::new_param(self.tcx, param);
57        }
58        ct.super_fold_with(self)
59    }
60}
61
62#[derive(#[automatically_derived]
impl ::core::clone::Clone for FnKind {
    #[inline]
    fn clone(&self) -> FnKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for FnKind { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for FnKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                FnKind::Free => "Free",
                FnKind::AssocInherentImpl => "AssocInherentImpl",
                FnKind::AssocTrait => "AssocTrait",
                FnKind::AssocTraitImpl => "AssocTraitImpl",
            })
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for FnKind {
    #[inline]
    fn eq(&self, other: &FnKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
63enum FnKind {
64    Free,
65    AssocInherentImpl,
66    AssocTrait,
67    AssocTraitImpl,
68}
69
70fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
71    if true {
    match tcx.def_kind(def_id) {
        DefKind::Fn | DefKind::AssocFn => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "DefKind::Fn | DefKind::AssocFn",
                ::core::option::Option::None);
        }
    };
};debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
72
73    let parent = tcx.parent(def_id);
74    match tcx.def_kind(parent) {
75        DefKind::Trait => FnKind::AssocTrait,
76        DefKind::Impl { of_trait: true } => FnKind::AssocTraitImpl,
77        DefKind::Impl { of_trait: false } => FnKind::AssocInherentImpl,
78        _ => FnKind::Free,
79    }
80}
81
82/// Given the current context(caller and callee `FnKind`), it specifies
83/// the policy of predicates and generic parameters inheritance.
84#[derive(#[automatically_derived]
impl ::core::clone::Clone for InheritanceKind {
    #[inline]
    fn clone(&self) -> InheritanceKind {
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InheritanceKind { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for InheritanceKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            InheritanceKind::WithParent(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "WithParent", &__self_0),
            InheritanceKind::Own =>
                ::core::fmt::Formatter::write_str(f, "Own"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for InheritanceKind {
    #[inline]
    fn eq(&self, other: &InheritanceKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (InheritanceKind::WithParent(__self_0),
                    InheritanceKind::WithParent(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq)]
85enum InheritanceKind {
86    /// Copying all predicates and parameters, including those of the parent
87    /// container.
88    ///
89    /// Boolean value defines whether the `Self` parameter or `Self: Trait`
90    /// predicate are copied. It's always equal to `false` except when
91    /// delegating from a free function to a trait method.
92    ///
93    /// FIXME(fn_delegation): This often leads to type inference
94    /// errors. Support providing generic arguments or restrict use sites.
95    WithParent(bool),
96    /// The trait implementation should be compatible with the original trait.
97    /// Therefore, for trait implementations only the method's own parameters
98    /// and predicates are copied.
99    Own,
100}
101
102fn build_generics<'tcx>(
103    tcx: TyCtxt<'tcx>,
104    sig_id: DefId,
105    parent: Option<DefId>,
106    inh_kind: InheritanceKind,
107) -> ty::Generics {
108    let mut own_params = ::alloc::vec::Vec::new()vec![];
109
110    let sig_generics = tcx.generics_of(sig_id);
111    if let InheritanceKind::WithParent(has_self) = inh_kind
112        && let Some(parent_def_id) = sig_generics.parent
113    {
114        let sig_parent_generics = tcx.generics_of(parent_def_id);
115        own_params.append(&mut sig_parent_generics.own_params.clone());
116        if !has_self {
117            own_params.remove(0);
118        }
119    }
120    own_params.append(&mut sig_generics.own_params.clone());
121
122    // Lifetime parameters must be declared before type and const parameters.
123    // Therefore, When delegating from a free function to a associated function,
124    // generic parameters need to be reordered:
125    //
126    // trait Trait<'a, A> {
127    //     fn foo<'b, B>(...) {...}
128    // }
129    //
130    // reuse Trait::foo;
131    // desugaring:
132    // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
133    //     Trait::foo(...)
134    // }
135    own_params.sort_by_key(|key| key.kind.is_ty_or_const());
136
137    let (parent_count, has_self) = if let Some(def_id) = parent {
138        let parent_generics = tcx.generics_of(def_id);
139        let parent_kind = tcx.def_kind(def_id);
140        (parent_generics.count(), parent_kind == DefKind::Trait)
141    } else {
142        (0, false)
143    };
144
145    for (idx, param) in own_params.iter_mut().enumerate() {
146        param.index = (idx + parent_count) as u32;
147        // FIXME(fn_delegation): Default parameters are not inherited, because they are
148        // not permitted in functions. Therefore, there are 2 options here:
149        //
150        // - We can create non-default generic parameters.
151        // - We can substitute default parameters into the signature.
152        //
153        // At the moment, first option has been selected as the most general.
154        if let ty::GenericParamDefKind::Type { has_default, .. }
155        | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
156        {
157            *has_default = false;
158        }
159    }
160
161    let param_def_id_to_index =
162        own_params.iter().map(|param| (param.def_id, param.index)).collect();
163
164    ty::Generics {
165        parent,
166        parent_count,
167        own_params,
168        param_def_id_to_index,
169        has_self,
170        has_late_bound_regions: sig_generics.has_late_bound_regions,
171    }
172}
173
174fn build_predicates<'tcx>(
175    tcx: TyCtxt<'tcx>,
176    sig_id: DefId,
177    parent: Option<DefId>,
178    inh_kind: InheritanceKind,
179    args: ty::GenericArgsRef<'tcx>,
180) -> ty::GenericPredicates<'tcx> {
181    struct PredicatesCollector<'tcx> {
182        tcx: TyCtxt<'tcx>,
183        preds: Vec<(ty::Clause<'tcx>, Span)>,
184        args: ty::GenericArgsRef<'tcx>,
185    }
186
187    impl<'tcx> PredicatesCollector<'tcx> {
188        fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> {
189            PredicatesCollector { tcx, preds: ::alloc::vec::Vec::new()vec![], args }
190        }
191
192        fn with_own_preds(
193            mut self,
194            f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>,
195            def_id: DefId,
196        ) -> Self {
197            let preds = f(def_id).instantiate_own(self.tcx, self.args);
198            self.preds.extend(preds);
199            self
200        }
201
202        fn with_preds(
203            mut self,
204            f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy,
205            def_id: DefId,
206        ) -> Self {
207            let preds = f(def_id);
208            if let Some(parent_def_id) = preds.parent {
209                self = self.with_own_preds(f, parent_def_id);
210            }
211            self.with_own_preds(f, def_id)
212        }
213    }
214    let collector = PredicatesCollector::new(tcx, args);
215
216    // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate.
217    // Note: `predicates_of` query can also add inferred outlives predicates, but that
218    // is not the case here as `sig_id` is either a trait or a function.
219    let preds = match inh_kind {
220        InheritanceKind::WithParent(false) => {
221            collector.with_preds(|def_id| tcx.explicit_predicates_of(def_id), sig_id)
222        }
223        InheritanceKind::WithParent(true) => {
224            collector.with_preds(|def_id| tcx.predicates_of(def_id), sig_id)
225        }
226        InheritanceKind::Own => {
227            collector.with_own_preds(|def_id| tcx.predicates_of(def_id), sig_id)
228        }
229    }
230    .preds;
231
232    ty::GenericPredicates { parent, predicates: tcx.arena.alloc_from_iter(preds) }
233}
234
235fn build_generic_args<'tcx>(
236    tcx: TyCtxt<'tcx>,
237    sig_id: DefId,
238    def_id: LocalDefId,
239    args: ty::GenericArgsRef<'tcx>,
240) -> ty::GenericArgsRef<'tcx> {
241    let caller_generics = tcx.generics_of(def_id);
242    let callee_generics = tcx.generics_of(sig_id);
243
244    let mut remap_table = FxHashMap::default();
245    for caller_param in &caller_generics.own_params {
246        let callee_index = callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
247        remap_table.insert(callee_index, caller_param.index);
248    }
249
250    let mut folder = ParamIndexRemapper { tcx, remap_table };
251    args.fold_with(&mut folder)
252}
253
254fn create_generic_args<'tcx>(
255    tcx: TyCtxt<'tcx>,
256    def_id: LocalDefId,
257    sig_id: DefId,
258) -> ty::GenericArgsRef<'tcx> {
259    let caller_kind = fn_kind(tcx, def_id.into());
260    let callee_kind = fn_kind(tcx, sig_id);
261    match (caller_kind, callee_kind) {
262        (FnKind::Free, FnKind::Free)
263        | (FnKind::Free, FnKind::AssocTrait)
264        | (FnKind::AssocInherentImpl, FnKind::Free)
265        | (FnKind::AssocTrait, FnKind::Free)
266        | (FnKind::AssocTrait, FnKind::AssocTrait) => {
267            let args = ty::GenericArgs::identity_for_item(tcx, sig_id);
268            build_generic_args(tcx, sig_id, def_id, args)
269        }
270
271        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
272            let callee_generics = tcx.generics_of(sig_id);
273            let parent = tcx.parent(def_id.into());
274            let parent_args = tcx.impl_trait_header(parent).trait_ref.instantiate_identity().args;
275
276            let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
277            let method_args = tcx.mk_args(&trait_args[callee_generics.parent_count..]);
278            let method_args = build_generic_args(tcx, sig_id, def_id, method_args);
279
280            tcx.mk_args_from_iter(parent_args.iter().chain(method_args))
281        }
282
283        (FnKind::AssocInherentImpl, FnKind::AssocTrait) => {
284            let parent = tcx.parent(def_id.into());
285            let self_ty = tcx.type_of(parent).instantiate_identity();
286            let generic_self_ty = ty::GenericArg::from(self_ty);
287
288            let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
289            let trait_args = build_generic_args(tcx, sig_id, def_id, trait_args);
290
291            let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1));
292            tcx.mk_args_from_iter(args)
293        }
294
295        // For trait impl's `sig_id` is always equal to the corresponding trait method.
296        // For inherent methods delegation is not yet supported.
297        (FnKind::AssocTraitImpl, _)
298        | (_, FnKind::AssocTraitImpl)
299        | (_, FnKind::AssocInherentImpl) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
300    }
301}
302
303// FIXME(fn_delegation): Move generics inheritance to the AST->HIR lowering.
304// For now, generic parameters are not propagated to the generated call,
305// which leads to inference errors:
306//
307// fn foo<T>(x: i32) {}
308//
309// reuse foo as bar;
310// desugaring:
311// fn bar<T>() {
312//   foo::<_>() // ERROR: type annotations needed
313// }
314pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
315    tcx: TyCtxt<'tcx>,
316    def_id: LocalDefId,
317    sig_id: DefId,
318) -> ty::Generics {
319    let caller_kind = fn_kind(tcx, def_id.into());
320    let callee_kind = fn_kind(tcx, sig_id);
321    match (caller_kind, callee_kind) {
322        (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
323            build_generics(tcx, sig_id, None, InheritanceKind::WithParent(true))
324        }
325
326        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
327            build_generics(tcx, sig_id, Some(tcx.parent(def_id.into())), InheritanceKind::Own)
328        }
329
330        (FnKind::AssocInherentImpl, FnKind::AssocTrait)
331        | (FnKind::AssocTrait, FnKind::AssocTrait)
332        | (FnKind::AssocInherentImpl, FnKind::Free)
333        | (FnKind::AssocTrait, FnKind::Free) => build_generics(
334            tcx,
335            sig_id,
336            Some(tcx.parent(def_id.into())),
337            InheritanceKind::WithParent(false),
338        ),
339
340        // For trait impl's `sig_id` is always equal to the corresponding trait method.
341        // For inherent methods delegation is not yet supported.
342        (FnKind::AssocTraitImpl, _)
343        | (_, FnKind::AssocTraitImpl)
344        | (_, FnKind::AssocInherentImpl) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
345    }
346}
347
348pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
349    tcx: TyCtxt<'tcx>,
350    def_id: LocalDefId,
351    sig_id: DefId,
352) -> ty::GenericPredicates<'tcx> {
353    let args = create_generic_args(tcx, def_id, sig_id);
354    let caller_kind = fn_kind(tcx, def_id.into());
355    let callee_kind = fn_kind(tcx, sig_id);
356    match (caller_kind, callee_kind) {
357        (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => {
358            build_predicates(tcx, sig_id, None, InheritanceKind::WithParent(true), args)
359        }
360
361        (FnKind::AssocTraitImpl, FnKind::AssocTrait) => build_predicates(
362            tcx,
363            sig_id,
364            Some(tcx.parent(def_id.into())),
365            InheritanceKind::Own,
366            args,
367        ),
368
369        (FnKind::AssocInherentImpl, FnKind::AssocTrait)
370        | (FnKind::AssocTrait, FnKind::AssocTrait)
371        | (FnKind::AssocInherentImpl, FnKind::Free)
372        | (FnKind::AssocTrait, FnKind::Free) => build_predicates(
373            tcx,
374            sig_id,
375            Some(tcx.parent(def_id.into())),
376            InheritanceKind::WithParent(false),
377            args,
378        ),
379
380        // For trait impl's `sig_id` is always equal to the corresponding trait method.
381        // For inherent methods delegation is not yet supported.
382        (FnKind::AssocTraitImpl, _)
383        | (_, FnKind::AssocTraitImpl)
384        | (_, FnKind::AssocInherentImpl) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
385    }
386}
387
388fn check_constraints<'tcx>(
389    tcx: TyCtxt<'tcx>,
390    def_id: LocalDefId,
391    sig_id: DefId,
392) -> Result<(), ErrorGuaranteed> {
393    let mut ret = Ok(());
394
395    let mut emit = |descr| {
396        ret = Err(tcx.dcx().emit_err(crate::errors::UnsupportedDelegation {
397            span: tcx.def_span(def_id),
398            descr,
399            callee_span: tcx.def_span(sig_id),
400        }));
401    };
402
403    if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic {
404        // See issue #127443 for explanation.
405        emit("delegation to C-variadic functions is not allowed");
406    }
407
408    ret
409}
410
411pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
412    tcx: TyCtxt<'tcx>,
413    def_id: LocalDefId,
414) -> &'tcx [Ty<'tcx>] {
415    let sig_id = tcx.hir_opt_delegation_sig_id(def_id).unwrap();
416    let caller_sig = tcx.fn_sig(sig_id);
417    if let Err(err) = check_constraints(tcx, def_id, sig_id) {
418        let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
419        let err_type = Ty::new_error(tcx, err);
420        return tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type));
421    }
422    let args = create_generic_args(tcx, def_id, sig_id);
423
424    // Bound vars are also inherited from `sig_id`.
425    // They will be rebound later in `lower_fn_ty`.
426    let sig = caller_sig.instantiate(tcx, args).skip_binder();
427    let sig_iter = sig.inputs().iter().cloned().chain(std::iter::once(sig.output()));
428    tcx.arena.alloc_from_iter(sig_iter)
429}