|
| 1 | +use crate::hir::place::{Place as HirPlace, PlaceBase as HirPlaceBase}; |
| 2 | +use crate::ty; |
| 3 | + |
| 4 | +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; |
| 5 | +use rustc_hir as hir; |
| 6 | +use rustc_hir::def_id::{DefId, LocalDefId}; |
| 7 | +use rustc_hir::lang_items::LangItem; |
| 8 | +use rustc_span::Span; |
| 9 | + |
| 10 | +use super::{BorrowKind, CaptureInfo, Ty, TyCtxt}; |
| 11 | + |
| 12 | +#[derive( |
| 13 | + Clone, |
| 14 | + Copy, |
| 15 | + Debug, |
| 16 | + PartialEq, |
| 17 | + Eq, |
| 18 | + Hash, |
| 19 | + TyEncodable, |
| 20 | + TyDecodable, |
| 21 | + TypeFoldable, |
| 22 | + HashStable |
| 23 | +)] |
| 24 | +pub struct UpvarPath { |
| 25 | + pub hir_id: hir::HirId, |
| 26 | +} |
| 27 | + |
| 28 | +/// Upvars do not get their own `NodeId`. Instead, we use the pair of |
| 29 | +/// the original var ID (that is, the root variable that is referenced |
| 30 | +/// by the upvar) and the ID of the closure expression. |
| 31 | +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)] |
| 32 | +pub struct UpvarId { |
| 33 | + pub var_path: UpvarPath, |
| 34 | + pub closure_expr_id: LocalDefId, |
| 35 | +} |
| 36 | + |
| 37 | +impl UpvarId { |
| 38 | + pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId { |
| 39 | + UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id } |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +/// Information describing the capture of an upvar. This is computed |
| 44 | +/// during `typeck`, specifically by `regionck`. |
| 45 | +#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] |
| 46 | +pub enum UpvarCapture<'tcx> { |
| 47 | + /// Upvar is captured by value. This is always true when the |
| 48 | + /// closure is labeled `move`, but can also be true in other cases |
| 49 | + /// depending on inference. |
| 50 | + /// |
| 51 | + /// If the upvar was inferred to be captured by value (e.g. `move` |
| 52 | + /// was not used), then the `Span` points to a usage that |
| 53 | + /// required it. There may be more than one such usage |
| 54 | + /// (e.g. `|| { a; a; }`), in which case we pick an |
| 55 | + /// arbitrary one. |
| 56 | + ByValue(Option<Span>), |
| 57 | + |
| 58 | + /// Upvar is captured by reference. |
| 59 | + ByRef(UpvarBorrow<'tcx>), |
| 60 | +} |
| 61 | + |
| 62 | +#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] |
| 63 | +pub struct UpvarBorrow<'tcx> { |
| 64 | + /// The kind of borrow: by-ref upvars have access to shared |
| 65 | + /// immutable borrows, which are not part of the normal language |
| 66 | + /// syntax. |
| 67 | + pub kind: BorrowKind, |
| 68 | + |
| 69 | + /// Region of the resulting reference. |
| 70 | + pub region: ty::Region<'tcx>, |
| 71 | +} |
| 72 | + |
| 73 | +pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>; |
| 74 | +pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>; |
| 75 | + |
| 76 | +/// Given the closure DefId this map provides a map of root variables to minimum |
| 77 | +/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure. |
| 78 | +pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>; |
| 79 | + |
| 80 | +/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`. |
| 81 | +/// Used to track the minimum set of `Place`s that need to be captured to support all |
| 82 | +/// Places captured by the closure starting at a given root variable. |
| 83 | +/// |
| 84 | +/// This provides a convenient and quick way of checking if a variable being used within |
| 85 | +/// a closure is a capture of a local variable. |
| 86 | +pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>; |
| 87 | + |
| 88 | +/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s. |
| 89 | +pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>; |
| 90 | + |
| 91 | +/// Represents the various closure traits in the language. This |
| 92 | +/// will determine the type of the environment (`self`, in the |
| 93 | +/// desugaring) argument that the closure expects. |
| 94 | +/// |
| 95 | +/// You can get the environment type of a closure using |
| 96 | +/// `tcx.closure_env_ty()`. |
| 97 | +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] |
| 98 | +#[derive(HashStable)] |
| 99 | +pub enum ClosureKind { |
| 100 | + // Warning: Ordering is significant here! The ordering is chosen |
| 101 | + // because the trait Fn is a subtrait of FnMut and so in turn, and |
| 102 | + // hence we order it so that Fn < FnMut < FnOnce. |
| 103 | + Fn, |
| 104 | + FnMut, |
| 105 | + FnOnce, |
| 106 | +} |
| 107 | + |
| 108 | +impl<'tcx> ClosureKind { |
| 109 | + // This is the initial value used when doing upvar inference. |
| 110 | + pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn; |
| 111 | + |
| 112 | + pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { |
| 113 | + match *self { |
| 114 | + ClosureKind::Fn => tcx.require_lang_item(LangItem::Fn, None), |
| 115 | + ClosureKind::FnMut => tcx.require_lang_item(LangItem::FnMut, None), |
| 116 | + ClosureKind::FnOnce => tcx.require_lang_item(LangItem::FnOnce, None), |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + /// Returns `true` if a type that impls this closure kind |
| 121 | + /// must also implement `other`. |
| 122 | + pub fn extends(self, other: ty::ClosureKind) -> bool { |
| 123 | + matches!( |
| 124 | + (self, other), |
| 125 | + (ClosureKind::Fn, ClosureKind::Fn) |
| 126 | + | (ClosureKind::Fn, ClosureKind::FnMut) |
| 127 | + | (ClosureKind::Fn, ClosureKind::FnOnce) |
| 128 | + | (ClosureKind::FnMut, ClosureKind::FnMut) |
| 129 | + | (ClosureKind::FnMut, ClosureKind::FnOnce) |
| 130 | + | (ClosureKind::FnOnce, ClosureKind::FnOnce) |
| 131 | + ) |
| 132 | + } |
| 133 | + |
| 134 | + /// Returns the representative scalar type for this closure kind. |
| 135 | + /// See `TyS::to_opt_closure_kind` for more details. |
| 136 | + pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { |
| 137 | + match self { |
| 138 | + ty::ClosureKind::Fn => tcx.types.i8, |
| 139 | + ty::ClosureKind::FnMut => tcx.types.i16, |
| 140 | + ty::ClosureKind::FnOnce => tcx.types.i32, |
| 141 | + } |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +/// A composite describing a `Place` that is captured by a closure. |
| 146 | +#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)] |
| 147 | +pub struct CapturedPlace<'tcx> { |
| 148 | + /// The `Place` that is captured. |
| 149 | + pub place: HirPlace<'tcx>, |
| 150 | + |
| 151 | + /// `CaptureKind` and expression(s) that resulted in such capture of `place`. |
| 152 | + pub info: CaptureInfo<'tcx>, |
| 153 | + |
| 154 | + /// Represents if `place` can be mutated or not. |
| 155 | + pub mutability: hir::Mutability, |
| 156 | +} |
| 157 | + |
| 158 | +impl CapturedPlace<'tcx> { |
| 159 | + /// Returns the hir-id of the root variable for the captured place. |
| 160 | + /// e.g., if `a.b.c` was captured, would return the hir-id for `a`. |
| 161 | + pub fn get_root_variable(&self) -> hir::HirId { |
| 162 | + match self.place.base { |
| 163 | + HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, |
| 164 | + base => bug!("Expected upvar, found={:?}", base), |
| 165 | + } |
| 166 | + } |
| 167 | +} |
0 commit comments