Skip to main content

charon_driver/hax/
rustc_utils.rs

1use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
2
3use rustc_hir::def::DefKind as RDefKind;
4use rustc_middle::infer::canonical::QueryRegionConstraints;
5use rustc_middle::ty::relate::{
6    Relate, RelateResult, TypeRelation, relate_args_with_variances, structurally_relate_consts,
7    structurally_relate_tys,
8};
9use rustc_middle::{mir, ty};
10use rustc_span::kw;
11
12use crate::hax::prelude::*;
13
14/// The data of a user annotation, bound in an existentially-quantified binder.
15pub type UserAnnotation<'tcx> = ty::Binder<'tcx, UserAnnotationData<'tcx>>;
16/// The data of a user annotation: for each used projection we get the type of the corresponding
17/// place, and we record outlives predicates that must hold. The first vec matches the input list
18/// of projections, the second is free-form.
19pub type UserAnnotationData<'tcx> = (Vec<ty::Ty<'tcx>>, Vec<ty::Clause<'tcx>>);
20/// Denotes a subplace of a user annotation, e.g. in `let Foo { x, .. }: Self = ...;` the
21/// annotation will have a projection for `x`.
22pub type UserAnnotationProj = Vec<mir::ProjectionKind>;
23
24/// Convert a type annotation into data we can use, by fetching the types that rustc inferred and
25/// gathering the predicates that still need to be checked at borrowck time.
26pub fn translate_user_annotation<'tcx>(
27    tcx: ty::TyCtxt<'tcx>,
28    typing_env: ty::TypingEnv<'tcx>,
29    owner: RDefId,
30    annotation: &ty::CanonicalUserTypeAnnotation<'tcx>,
31    projections: &[UserAnnotationProj],
32) -> Result<UserAnnotation<'tcx>, String> {
33    use rustc_trait_selection::infer::{RegionVariableOrigin, TyCtxtInferExt};
34    use rustc_trait_selection::traits::query::type_op::{AscribeUserType, Normalize, TypeOp};
35    use ty::{TypeVisitableExt, Upcast};
36
37    let span = annotation.span;
38    let owner = tcx.typeck_root_def_id(owner).as_local().unwrap();
39    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
40
41    let (user_ty, _) = infcx.instantiate_canonical(span, &annotation.user_ty);
42    let user_ty = ty::fold_regions(tcx, user_ty, |r, _| {
43        if r.is_erased() {
44            infcx.next_region_var(RegionVariableOrigin::Misc(span))
45        } else {
46            r
47        }
48    });
49    let inferred_ty = ty::fold_regions(tcx, annotation.inferred_ty, |_, _| {
50        infcx.next_region_var(RegionVariableOrigin::Misc(span))
51    });
52
53    // Compute the inferred type of the place, and constraints needed to match it with the
54    // user-provided type.
55    let (projected_tys, constraints): (Vec<ty::Ty<'tcx>>, QueryRegionConstraints<'tcx>) = {
56        let mut all_constraints: Vec<Option<&'tcx QueryRegionConstraints<'tcx>>> = Vec::new();
57
58        // `AscribeUserType` needs a normalized type.
59        let normalized = param_env
60            .and(Normalize {
61                value: ty::set_opaques_to_non_rigid(tcx, inferred_ty),
62            })
63            .fully_perform(&infcx, owner, span)
64            .map_err(|_| "could not normalize inferred annotation type".to_owned())?;
65        let inferred_ty = normalized.output;
66        all_constraints.push(normalized.constraints);
67
68        let ascribe_result = param_env
69            .and(AscribeUserType {
70                mir_ty: inferred_ty,
71                user_ty,
72            })
73            .fully_perform(&infcx, owner, span)
74            .map_err(|_| "could not recover user type ascription".to_owned())?;
75        all_constraints.push(ascribe_result.constraints);
76
77        let mut projected_tys = Vec::new();
78        for projections in projections {
79            let mut projected_ty = mir::PlaceTy::from_ty(inferred_ty);
80            let mut iter = projections.iter();
81            loop {
82                let resolved = param_env
83                    .and(Normalize {
84                        value: ty::Unnormalized::new_wip(projected_ty.ty),
85                    })
86                    .fully_perform(&infcx, owner, span)
87                    .map_err(|_| "could not normalize user type projection".to_owned())?;
88                projected_ty.ty = resolved.output;
89                all_constraints.push(resolved.constraints);
90                let Some(projection) = iter.next() else { break };
91                if matches!(
92                    projection,
93                    mir::ProjectionElem::OpaqueCast(())
94                        | mir::ProjectionElem::UnwrapUnsafeBinder(())
95                ) {
96                    return Err("unsupported cast in user type projection".into());
97                }
98                projected_ty = projected_ty.projection_ty_core(
99                    tcx,
100                    projection,
101                    |ty, variant, field, ()| {
102                        mir::PlaceTy::field_ty(tcx, ty, variant, field).skip_normalization()
103                    },
104                    |()| unreachable!(),
105                );
106            }
107            projected_tys.push(projected_ty.ty);
108        }
109
110        // Merge the constraints we got from normalizing, relating and projecting.
111        let mut constraints: QueryRegionConstraints<'tcx> = Default::default();
112        for c in all_constraints.into_iter().flatten() {
113            constraints
114                .constraints
115                .extend(c.constraints.iter().copied());
116            constraints
117                .assumptions
118                .extend(c.assumptions.iter().copied());
119        }
120
121        (projected_tys, constraints)
122    };
123
124    // Apply the region equality constraints to remove redundant regions.
125    let (projected_tys, constraints) = {
126        let cause = rustc_middle::traits::ObligationCause::dummy_with_span(span);
127        for constraint in &constraints.constraints {
128            if let ty::RegionConstraint::Eq(eq @ ty::RegionEqPredicate(lhs, rhs)) =
129                constraint.constraint
130                && [lhs, rhs]
131                    .into_iter()
132                    .all(|r| infcx.universe_of_region(r) == ty::UniverseIndex::ROOT)
133            {
134                infcx.register_region_eq_constraint(eq, constraint.visible_for_leak_check, &cause);
135            }
136        }
137        infcx.deeply_resolve_via_unification_table((projected_tys, constraints))
138    };
139
140    // Turn the constraints into clauses.
141    let clauses: Vec<ty::Clause<'tcx>> = {
142        if !constraints.assumptions.is_empty() {
143            return Err("unsupported assumptions in user type ascription constraints".into());
144        }
145        let mut clauses = Vec::new();
146        let mut push_clause = |kind| clauses.push(ty::Binder::dummy(kind).upcast(tcx));
147        for constraint in constraints.constraints {
148            match constraint.constraint {
149                ty::RegionConstraint::Outlives(ty::OutlivesClause(lhs, rhs)) => {
150                    let clause = match lhs.kind() {
151                        ty::GenericArgKind::Lifetime(lhs) => {
152                            ty::ClauseKind::RegionOutlives(ty::OutlivesClause(lhs, rhs))
153                        }
154                        ty::GenericArgKind::Type(lhs) => {
155                            ty::ClauseKind::TypeOutlives(ty::OutlivesClause(lhs, rhs))
156                        }
157                        ty::GenericArgKind::Const(_) => {
158                            return Err("const outlives constraint in user type ascription".into());
159                        }
160                    };
161                    push_clause(clause);
162                }
163                ty::RegionConstraint::Eq(ty::RegionEqPredicate(lhs, rhs)) => {
164                    if lhs != rhs {
165                        // Equality is the conjunction of the two outlives relations.
166                        for (lhs, rhs) in [(lhs, rhs), (rhs, lhs)] {
167                            push_clause(ty::ClauseKind::RegionOutlives(ty::OutlivesClause(
168                                lhs, rhs,
169                            )));
170                        }
171                    }
172                }
173            }
174        }
175        clauses
176    };
177
178    // Bind all the inferred regions in a binder.
179    let bound = {
180        let value = (projected_tys, clauses);
181        if value.has_non_region_infer() || value.has_non_region_placeholders() {
182            return Err("unresolved type or const in user type ascription".into());
183        }
184        let mut regions = HashMap::default();
185        let mut bound_vars = Vec::new();
186        let mut unsupported_region = false;
187        let value = ty::fold_regions(tcx, value, |region, depth| match region.kind() {
188            ty::ReVar(_) if infcx.universe_of_region(region) == ty::UniverseIndex::ROOT => {
189                let var = *regions.entry(region).or_insert_with(|| {
190                    let var = ty::BoundVar::from_usize(bound_vars.len());
191                    bound_vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
192                    var
193                });
194                ty::Region::new_bound(
195                    tcx,
196                    depth,
197                    ty::BoundRegion {
198                        var,
199                        kind: ty::BoundRegionKind::Anon,
200                    },
201                )
202            }
203            ty::ReVar(_) | ty::RePlaceholder(_) | ty::ReErased => {
204                unsupported_region = true;
205                region
206            }
207            _ => region,
208        });
209        if unsupported_region {
210            return Err("unsupported region in user type ascription constraints".into());
211        }
212        ty::Binder::bind_with_vars(value, tcx.mk_bound_variable_kinds(&bound_vars))
213    };
214
215    Ok(bound)
216}
217
218/// Computes the variance of each region bound by `sig`.
219///
220/// This follows rustc's `FunctionalVariances` helper from the `impl_trait_overcaptures` lint.
221pub fn fn_sig_bound_region_variances<'tcx>(
222    tcx: ty::TyCtxt<'tcx>,
223    sig: ty::PolyFnSig<'tcx>,
224) -> HashMap<ty::BoundVar, ty::Variance> {
225    struct FunctionalVariances<'tcx> {
226        tcx: ty::TyCtxt<'tcx>,
227        variances: HashMap<ty::BoundVar, ty::Variance>,
228        ambient_variance: ty::Variance,
229        target_binder: ty::DebruijnIndex,
230    }
231
232    impl<'tcx> TypeRelation<ty::TyCtxt<'tcx>> for FunctionalVariances<'tcx> {
233        fn cx(&self) -> ty::TyCtxt<'tcx> {
234            self.tcx
235        }
236
237        fn relate_ty_args(
238            &mut self,
239            a_ty: ty::Ty<'tcx>,
240            _: ty::Ty<'tcx>,
241            def_id: rustc_hir::def_id::DefId,
242            a_args: ty::GenericArgsRef<'tcx>,
243            b_args: ty::GenericArgsRef<'tcx>,
244            _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> ty::Ty<'tcx>,
245        ) -> RelateResult<'tcx, ty::Ty<'tcx>> {
246            relate_args_with_variances(self, self.tcx.variances_of(def_id), a_args, b_args)?;
247            Ok(a_ty)
248        }
249
250        fn relate_with_variance<T: Relate<ty::TyCtxt<'tcx>>>(
251            &mut self,
252            variance: ty::Variance,
253            _: ty::VarianceDiagInfo<ty::TyCtxt<'tcx>>,
254            a: T,
255            b: T,
256        ) -> RelateResult<'tcx, T> {
257            let old_variance = self.ambient_variance;
258            self.ambient_variance = self.ambient_variance.xform(variance);
259            let result = self.relate(a, b);
260            self.ambient_variance = old_variance;
261            result
262        }
263
264        fn tys(&mut self, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>) -> RelateResult<'tcx, ty::Ty<'tcx>> {
265            structurally_relate_tys(self, a, b)
266        }
267
268        fn regions(
269            &mut self,
270            a: ty::Region<'tcx>,
271            _: ty::Region<'tcx>,
272        ) -> RelateResult<'tcx, ty::Region<'tcx>> {
273            if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), ty::BoundRegion { var, .. }) =
274                a.kind()
275                && binder == self.target_binder
276            {
277                self.variances
278                    .entry(var)
279                    .and_modify(|old| *old = unify_variances(*old, self.ambient_variance))
280                    .or_insert(self.ambient_variance);
281            }
282            Ok(a)
283        }
284
285        fn consts(
286            &mut self,
287            a: ty::Const<'tcx>,
288            b: ty::Const<'tcx>,
289        ) -> RelateResult<'tcx, ty::Const<'tcx>> {
290            structurally_relate_consts(self, a, b)
291        }
292
293        fn binders<T>(
294            &mut self,
295            a: ty::Binder<'tcx, T>,
296            b: ty::Binder<'tcx, T>,
297        ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
298        where
299            T: Relate<ty::TyCtxt<'tcx>>,
300        {
301            let old_target_binder = self.target_binder;
302            self.target_binder = self.target_binder.shifted_in(1);
303            let result = self.relate(a.skip_binder(), b.skip_binder());
304            self.target_binder = old_target_binder;
305            result?;
306            Ok(a)
307        }
308    }
309
310    fn unify_variances(a: ty::Variance, b: ty::Variance) -> ty::Variance {
311        match (a, b) {
312            (ty::Bivariant, other) | (other, ty::Bivariant) => other,
313            (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
314            (ty::Contravariant, ty::Covariant) | (ty::Covariant, ty::Contravariant) => {
315                ty::Invariant
316            }
317            (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
318            (ty::Covariant, ty::Covariant) => ty::Covariant,
319        }
320    }
321
322    let mut relation = FunctionalVariances {
323        tcx,
324        variances: HashMap::default(),
325        // `Relate for FnSig` makes inputs contravariant. We are computing the variance of the
326        // signature's own bound parameters, so cancel that outer function-type variance. Nested
327        // function types still introduce their own contravariance as usual.
328        ambient_variance: ty::Contravariant,
329        target_binder: ty::INNERMOST,
330    };
331    relation
332        .relate(sig.skip_binder(), sig.skip_binder())
333        .expect("a signature must relate to itself");
334
335    // A bound region that does not occur in the signature is bivariant.
336    for (index, var) in sig.bound_vars().iter().enumerate() {
337        if matches!(var, ty::BoundVariableKind::Region(_)) {
338            relation
339                .variances
340                .entry(ty::BoundVar::from_usize(index))
341                .or_insert(ty::Bivariant);
342        }
343    }
344    relation.variances
345}
346
347/// Instantiate this binder with the provided args. Use `None` if the args are known to be the
348/// identity args.
349pub fn inst_binder<'tcx, T>(
350    tcx: ty::TyCtxt<'tcx>,
351    typing_env: ty::TypingEnv<'tcx>,
352    args: Option<ty::GenericArgsRef<'tcx>>,
353    x: ty::EarlyBinder<'tcx, T>,
354) -> T
355where
356    T: ty::TypeFoldable<ty::TyCtxt<'tcx>> + Clone,
357{
358    match args {
359        None => x.instantiate_identity().skip_normalization(),
360        Some(args) => normalize(tcx, typing_env, x.instantiate(tcx, args)),
361    }
362}
363
364/// Instantiate this value with the provided args. Use `None` if the args are known to be the
365/// identity args.
366pub fn substitute<'tcx, T>(
367    tcx: ty::TyCtxt<'tcx>,
368    typing_env: ty::TypingEnv<'tcx>,
369    args: Option<ty::GenericArgsRef<'tcx>>,
370    x: T,
371) -> T
372where
373    T: ty::TypeFoldable<ty::TyCtxt<'tcx>>,
374{
375    inst_binder(tcx, typing_env, args, ty::EarlyBinder::bind(tcx, x))
376}
377
378/// Closures and inline consts have special type params that are used as inference variables. After
379/// analysis, they can be computed from the rest of the args (modulo some erased regions). This
380/// computes the identity args for this `def_id` with the inference ars properly inferred.
381pub fn identity_args_with_inferred<'tcx>(
382    tcx: ty::TyCtxt<'tcx>,
383    def_id: RDefId,
384) -> ty::GenericArgsRef<'tcx> {
385    match tcx.def_kind(def_id) {
386        RDefKind::Closure | RDefKind::SyntheticCoroutineBody => {
387            let type_of = tcx
388                .type_of(def_id)
389                .instantiate_identity()
390                .skip_normalization();
391            match *type_of.kind() {
392                ty::Closure(_, args) | ty::Coroutine(_, args) => args,
393                _ => unreachable!(),
394            }
395        }
396        RDefKind::AnonConst
397            if tcx.anon_const_kind(def_id) == ty::AnonConstKind::NonTypeSystemInline =>
398        {
399            // `tcx.type_of` fetches its result from the provided arguments, which circularly can't
400            // help us. We get the real type from the MIR body which is sad but works.
401            let get_ret_ty = |body: &mir::Body<'tcx>| body.local_decls[mir::Local::ZERO].ty;
402            let ret_ty = mir_kinds::CTFE::get_mir(tcx, def_id, get_ret_ty)
403                .or_else(|| mir_kinds::Optimized::get_mir(tcx, def_id, get_ret_ty))
404                .expect("could not compute the type of this inline const: {def_id:?}");
405            let mut args = ty::GenericArgs::identity_for_item(tcx, def_id).to_vec();
406            *args
407                .last_mut()
408                .expect("inline const has a return type parameter") = ret_ty.into();
409            tcx.mk_args_from_iter(args.into_iter())
410        }
411        _ => ty::GenericArgs::identity_for_item(tcx, def_id),
412    }
413}
414
415/// Replace each erased region in this value with a fresh placeholder region.
416pub fn unerase_lifetimes<'tcx, T>(
417    s: &impl UnderOwnerState<'tcx>,
418    val: T,
419    new_region_name: Symbol,
420) -> (T, Vec<ty::PlaceholderRegion<'tcx>>)
421where
422    T: ty::TypeFoldable<ty::TyCtxt<'tcx>>,
423{
424    let tcx = s.base().tcx;
425    let mut extra_regions = Vec::new();
426    let val = ty::fold_regions(tcx, val, |region, _| {
427        if region.is_erased() {
428            let placeholder = ty::PlaceholderRegion::new(
429                ty::UniverseIndex::ROOT,
430                ty::BoundRegion {
431                    var: ty::BoundVar::from_usize(extra_regions.len()),
432                    kind: ty::BoundRegionKind::NamedForPrinting(new_region_name),
433                },
434            );
435            extra_regions.push(placeholder);
436            ty::Region::new_placeholder(tcx, placeholder)
437        } else {
438            region
439        }
440    });
441    (val, extra_regions)
442}
443
444#[extension_traits::extension(pub trait SubstBinder)]
445impl<'tcx, T: ty::TypeFoldable<ty::TyCtxt<'tcx>>> ty::Binder<'tcx, T> {
446    fn subst(
447        self,
448        tcx: ty::TyCtxt<'tcx>,
449        generics: &[ty::GenericArg<'tcx>],
450    ) -> ty::Binder<'tcx, T> {
451        ty::EarlyBinder::bind(tcx, self)
452            .instantiate(tcx, generics)
453            .skip_normalization()
454    }
455}
456
457/// Whether the item can have generic parameters.
458pub(crate) fn can_have_generics<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> bool {
459    use RDefKind::*;
460    !matches!(
461        get_def_kind(tcx, def_id),
462        ConstParam
463            | ExternCrate
464            | ForeignMod
465            | GlobalAsm
466            | LifetimeParam
467            | Macro(..)
468            | Mod
469            | TyParam
470            | Use
471    )
472}
473
474pub(crate) fn get_variant_kind<'s, S: UnderOwnerState<'s>>(
475    adt_def: &ty::AdtDef<'s>,
476    variant_index: rustc_abi::VariantIdx,
477    _s: &S,
478) -> VariantKind {
479    if adt_def.is_struct() {
480        VariantKind::Struct
481    } else if adt_def.is_union() {
482        VariantKind::Union
483    } else {
484        let index = variant_index;
485        VariantKind::Enum { index }
486    }
487}
488
489/// Gets the children of a module.
490pub fn get_mod_children<'tcx>(
491    tcx: ty::TyCtxt<'tcx>,
492    def_id: RDefId,
493) -> Vec<(Option<rustc_span::Ident>, RDefId)> {
494    match def_id.as_local() {
495        Some(ldid) => match tcx.hir_node_by_def_id(ldid) {
496            rustc_hir::Node::Crate(m)
497            | rustc_hir::Node::Item(&rustc_hir::Item {
498                kind: rustc_hir::ItemKind::Mod(_, m),
499                ..
500            }) => m
501                .item_ids
502                .iter()
503                .map(|&item_id| {
504                    let opt_ident = tcx.hir_item(item_id).kind.ident();
505                    let def_id = item_id.owner_id.to_def_id();
506                    (opt_ident, def_id)
507                })
508                .collect(),
509            node => panic!("DefKind::Module is an unexpected node: {node:?}"),
510        },
511        None => tcx
512            .module_children(def_id)
513            .iter()
514            .filter_map(|child| Some((Some(child.ident), child.res.opt_def_id()?)))
515            .collect(),
516    }
517}
518
519/// Gets the children of an `extern` block. Empty if the block is not defined in the current crate.
520pub fn get_foreign_mod_children<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Vec<RDefId> {
521    match def_id.as_local() {
522        Some(ldid) => tcx
523            .hir_node_by_def_id(ldid)
524            .expect_item()
525            .expect_foreign_mod()
526            .1
527            .iter()
528            .map(|foreign_item_ref| foreign_item_ref.owner_id.to_def_id())
529            .collect(),
530        None => vec![],
531    }
532}
533
534/// The signature of a method impl may be a subtype of the one expected from the trait decl, as in
535/// the example below. For correctness, we must be able to map from the method generics declared in
536/// the trait to the actual method generics. Because this would require type inference, we instead
537/// simply return the declared signature. This will cause issues if it is possible to use such a
538/// more-specific implementation with its more-specific type, but we have a few other issues with
539/// lifetime-generic function pointers anyway so this is unlikely to cause problems.
540///
541/// ```ignore
542/// trait MyCompare<Other>: Sized {
543///     fn compare(self, other: Other) -> bool;
544/// }
545/// impl<'a> MyCompare<&'a ()> for &'a () {
546///     // This implementation is more general because it works for non-`'a` refs. Note that only
547///     // late-bound vars may differ in this way.
548///     // `<&'a () as MyCompare<&'a ()>>::compare` has type `fn<'b>(&'a (), &'b ()) -> bool`,
549///     // but type `fn(&'a (), &'a ()) -> bool` was expected from the trait declaration.
550///     fn compare<'b>(self, _other: &'b ()) -> bool {
551///         true
552///     }
553/// }
554/// ```
555pub fn get_method_sig<'tcx>(
556    tcx: ty::TyCtxt<'tcx>,
557    typing_env: ty::TypingEnv<'tcx>,
558    def_id: RDefId,
559    method_args: Option<ty::GenericArgsRef<'tcx>>,
560) -> ty::PolyFnSig<'tcx> {
561    let real_sig = inst_binder(tcx, typing_env, method_args, tcx.fn_sig(def_id));
562    let item = tcx.associated_item(def_id);
563    let ty::AssocContainer::TraitImpl(Ok(decl_method_id)) = item.container else {
564        return real_sig;
565    };
566    let declared_sig = tcx.fn_sig(decl_method_id);
567
568    let impl_def_id = item.container_id(tcx);
569    let method_args =
570        method_args.unwrap_or_else(|| ty::GenericArgs::identity_for_item(tcx, def_id));
571    // The trait predicate that is implemented by the surrounding impl block.
572    let implemented_trait_ref = tcx
573        .impl_trait_ref(impl_def_id)
574        .instantiate(tcx, method_args);
575    let implemented_trait_ref = normalize(tcx, typing_env, implemented_trait_ref);
576    // Construct arguments for the declared method generics in the context of the implemented
577    // method generics.
578    let decl_args = method_args.rebase_onto(tcx, impl_def_id, implemented_trait_ref.args);
579    let sig = declared_sig.instantiate(tcx, decl_args);
580    let sig = normalize(tcx, typing_env, sig);
581
582    if let container_named_lts = tcx
583        .generics_of(impl_def_id)
584        .own_params
585        .iter()
586        .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
587        .filter(|p| p.name != kw::UnderscoreLifetime)
588        .map(|p| p.name)
589        .collect::<HashSet<_>>()
590        && sig
591            .bound_vars()
592            .iter()
593            .map(|v| v.expect_region())
594            .filter_map(|v| v.get_name(tcx))
595            .any(|lt| container_named_lts.contains(&lt))
596    {
597        // Avoids using the same lifetime name twice in the same scope (once in impl parameters,
598        // second in the method declaration late-bound vars).
599        tcx.anonymize_bound_vars(sig)
600    } else {
601        sig
602    }
603}
604
605/// Generates a list of `<trait_ref>::Ty` type aliases for each non-gat associated type of the
606/// given trait and its parents, in a specific order.
607pub fn assoc_tys_for_trait<'tcx>(
608    tcx: ty::TyCtxt<'tcx>,
609    typing_env: ty::TypingEnv<'tcx>,
610    tref: ty::TraitRef<'tcx>,
611) -> Vec<ty::AliasTy<'tcx>> {
612    fn gather_assoc_tys<'tcx>(
613        tcx: ty::TyCtxt<'tcx>,
614        typing_env: ty::TypingEnv<'tcx>,
615        assoc_tys: &mut Vec<ty::AliasTy<'tcx>>,
616        tref: ty::TraitRef<'tcx>,
617    ) {
618        assoc_tys.extend(
619            tcx.associated_items(tref.def_id)
620                .in_definition_order()
621                .filter(|assoc| matches!(assoc.kind, ty::AssocKind::Type { .. }))
622                .filter(|assoc| {
623                    tcx.generics_of(assoc.def_id).own_params.is_empty()
624                        && tcx.clauses_of(assoc.def_id).clauses.is_empty()
625                })
626                .map(|assoc| {
627                    let alias_ty = ty::AliasTyKind::Projection {
628                        def_id: assoc.def_id,
629                    };
630                    ty::AliasTy::new(tcx, alias_ty, tref.args)
631                }),
632        );
633        for clause in tcx
634            .explicit_super_clauses_of(tref.def_id)
635            .map_bound(|clauses| clauses.iter().map(|(clause, _span)| *clause))
636            .iter_instantiated(tcx, tref.args)
637        {
638            if let Some(pred) = clause.as_trait_clause() {
639                let tref = erase_and_norm(tcx, typing_env, pred.map(|b| b.skip_binder().trait_ref));
640                gather_assoc_tys(tcx, typing_env, assoc_tys, tref);
641            }
642        }
643    }
644    let mut ret = vec![];
645    gather_assoc_tys(tcx, typing_env, &mut ret, tref);
646    ret
647}
648
649/// Generates a `dyn Trait<Args.., Ty = <Self as Trait>::Ty..>` type for the given trait ref.
650pub fn dyn_self_ty<'tcx>(
651    tcx: ty::TyCtxt<'tcx>,
652    typing_env: ty::TypingEnv<'tcx>,
653    tref: ty::TraitRef<'tcx>,
654) -> Option<ty::Ty<'tcx>> {
655    let re_erased = tcx.lifetimes.re_erased;
656    if !tcx.is_dyn_compatible(tref.def_id) {
657        return None;
658    }
659
660    // The main `Trait<Args>` predicate.
661    let main_pred = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
662        ty::ExistentialTraitRef::erase_self_ty(tcx, tref),
663    ));
664
665    let ty_constraints = assoc_tys_for_trait(tcx, typing_env, tref)
666        .into_iter()
667        .map(|alias_ty| {
668            let proj = ty::ProjectionClause {
669                projection_term: alias_ty.into(),
670                term: ty::Ty::new_alias(tcx, ty::IsRigid::No, alias_ty).into(),
671            };
672            let proj = ty::ExistentialProjection::erase_self_ty(tcx, proj);
673            ty::Binder::dummy(ty::ExistentialPredicate::Projection(proj))
674        });
675
676    let preds = {
677        // Stable sort predicates to prevent platform-specific ordering issues
678        let mut preds: Vec<_> = [main_pred].into_iter().chain(ty_constraints).collect();
679        preds.sort_by(|a, b| {
680            use rustc_middle::ty::ExistentialPredicateStableCmpExt;
681            a.skip_binder().stable_cmp(tcx, &b.skip_binder())
682        });
683        tcx.mk_poly_existential_predicates(&preds)
684    };
685    let ty = tcx.mk_ty_from_kind(ty::Dynamic(preds, re_erased));
686    let ty = normalize(tcx, typing_env, ty::Unnormalized::new_wip(ty));
687    Some(ty)
688}
689
690pub fn closure_once_shim<'tcx>(
691    tcx: ty::TyCtxt<'tcx>,
692    closure_ty: ty::Ty<'tcx>,
693) -> Option<mir::Body<'tcx>> {
694    let ty::Closure(def_id, args) = closure_ty.kind() else {
695        unreachable!()
696    };
697    let instance = match args.as_closure().kind() {
698        ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
699            ty::Instance::fn_once_adapter_instance(tcx, *def_id, args)
700        }
701        ty::ClosureKind::FnOnce => return None,
702    };
703    let mir = tcx.instance_mir(instance.def).clone();
704    let mir = ty::EarlyBinder::bind(tcx, mir)
705        .instantiate(tcx, instance.args)
706        .skip_normalization();
707    Some(mir)
708}
709
710pub fn drop_glue_shim<'tcx>(
711    s: &impl UnderOwnerState<'tcx>,
712    def_id: &DefId,
713    instantiate: Option<ty::GenericArgsRef<'tcx>>,
714) -> mir::Body<'tcx> {
715    let tcx = s.base().tcx;
716    let drop_glue =
717        tcx.require_lang_item(rustc_hir::attrs::LangItem::DropGlue, rustc_span::DUMMY_SP);
718    let ty = inst_binder(tcx, s.typing_env(), instantiate, def_id.type_of(s));
719    let mut body = rustc_mir_transform::build_drop_shim(tcx, drop_glue, Some(ty), s.typing_env());
720    // Set the mir phase so that charon knows the contained drops are precise.
721    body.phase = mir::MirPhase::Runtime(mir::RuntimePhase::Optimized);
722    body
723}