]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir/src/interpret/util.rs
Auto merge of #79780 - camelid:use-summary_opts, r=GuillaumeGomez
[rust.git] / compiler / rustc_mir / src / 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 use std::ops::ControlFlow;
5
6 /// Returns `true` if a used generic parameter requires substitution.
7 crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
8 where
9     T: TypeFoldable<'tcx>,
10 {
11     debug!("ensure_monomorphic_enough: ty={:?}", ty);
12     if !ty.needs_subst() {
13         return Ok(());
14     }
15
16     struct FoundParam;
17     struct UsedParamsNeedSubstVisitor<'tcx> {
18         tcx: TyCtxt<'tcx>,
19     }
20
21     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
22         type BreakTy = FoundParam;
23
24         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
25             if !c.needs_subst() {
26                 return ControlFlow::CONTINUE;
27             }
28
29             match c.val {
30                 ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
31                 _ => c.super_visit_with(self),
32             }
33         }
34
35         fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
36             if !ty.needs_subst() {
37                 return ControlFlow::CONTINUE;
38             }
39
40             match *ty.kind() {
41                 ty::Param(_) => ControlFlow::Break(FoundParam),
42                 ty::Closure(def_id, substs)
43                 | ty::Generator(def_id, substs, ..)
44                 | ty::FnDef(def_id, substs) => {
45                     let unused_params = self.tcx.unused_generic_params(def_id);
46                     for (index, subst) in substs.into_iter().enumerate() {
47                         let index = index
48                             .try_into()
49                             .expect("more generic parameters than can fit into a `u32`");
50                         let is_used =
51                             unused_params.contains(index).map(|unused| !unused).unwrap_or(true);
52                         // Only recurse when generic parameters in fns, closures and generators
53                         // are used and require substitution.
54                         match (is_used, subst.needs_subst()) {
55                             // Just in case there are closures or generators within this subst,
56                             // recurse.
57                             (true, true) => return subst.super_visit_with(self),
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                     ControlFlow::CONTINUE
73                 }
74                 _ => ty.super_visit_with(self),
75             }
76         }
77     }
78
79     let mut vis = UsedParamsNeedSubstVisitor { tcx };
80     if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
81         throw_inval!(TooGeneric);
82     } else {
83         Ok(())
84     }
85 }