]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/interpret/util.rs
New upstream version 1.47.0+dfsg1
[rustc.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 }