]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/util.rs
Auto merge of #75137 - Aaron1011:fix/hygiene-skip-expndata, r=petrochenkov
[rust.git] / src / librustc_mir / interpret / util.rs
1 use rustc_middle::mir::interpret::InterpResult;
2 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
3 use std::convert::TryInto;
4
5 /// Returns `true` if a used generic parameter requires substitution.
6 crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
7 where
8     T: TypeFoldable<'tcx>,
9 {
10     debug!("ensure_monomorphic_enough: ty={:?}", ty);
11     if !ty.needs_subst() {
12         return Ok(());
13     }
14
15     struct UsedParamsNeedSubstVisitor<'tcx> {
16         tcx: TyCtxt<'tcx>,
17     };
18
19     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
20         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
21             if !c.needs_subst() {
22                 return false;
23             }
24
25             match c.val {
26                 ty::ConstKind::Param(..) => true,
27                 _ => c.super_visit_with(self),
28             }
29         }
30
31         fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
32             if !ty.needs_subst() {
33                 return false;
34             }
35
36             match ty.kind {
37                 ty::Param(_) => true,
38                 ty::Closure(def_id, substs)
39                 | ty::Generator(def_id, substs, ..)
40                 | ty::FnDef(def_id, substs) => {
41                     let unused_params = self.tcx.unused_generic_params(def_id);
42                     for (index, subst) in substs.into_iter().enumerate() {
43                         let index = index
44                             .try_into()
45                             .expect("more generic parameters than can fit into a `u32`");
46                         let is_used =
47                             unused_params.contains(index).map(|unused| !unused).unwrap_or(true);
48                         // Only recurse when generic parameters in fns, closures and generators
49                         // are used and require substitution.
50                         match (is_used, subst.needs_subst()) {
51                             // Just in case there are closures or generators within this subst,
52                             // recurse.
53                             (true, true) if subst.super_visit_with(self) => {
54                                 // Only return when we find a parameter so the remaining substs
55                                 // are not skipped.
56                                 return true;
57                             }
58                             // Confirm that polymorphization replaced the parameter with
59                             // `ty::Param`/`ty::ConstKind::Param`.
60                             (false, true) if cfg!(debug_assertions) => match subst.unpack() {
61                                 ty::subst::GenericArgKind::Type(ty) => {
62                                     assert!(matches!(ty.kind, ty::Param(_)))
63                                 }
64                                 ty::subst::GenericArgKind::Const(ct) => {
65                                     assert!(matches!(ct.val, ty::ConstKind::Param(_)))
66                                 }
67                                 ty::subst::GenericArgKind::Lifetime(..) => (),
68                             },
69                             _ => {}
70                         }
71                     }
72                     false
73                 }
74                 _ => ty.super_visit_with(self),
75             }
76         }
77     }
78
79     let mut vis = UsedParamsNeedSubstVisitor { tcx };
80     if ty.visit_with(&mut vis) {
81         throw_inval!(TooGeneric);
82     } else {
83         Ok(())
84     }
85 }