1 use crate::hir::place::{
2 Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
9 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
11 use rustc_hir::def_id::{DefId, LocalDefId};
12 use rustc_span::{Span, Symbol};
14 use super::{Ty, TyCtxt};
16 use self::BorrowKind::*;
18 /// Captures are represented using fields inside a structure.
19 /// This represents accessing self in the closure structure
20 pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
22 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
23 #[derive(TypeFoldable, TypeVisitable)]
24 pub struct UpvarPath {
25 pub hir_id: hir::HirId,
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, HashStable)]
32 #[derive(TypeFoldable, TypeVisitable)]
34 pub var_path: UpvarPath,
35 pub closure_expr_id: LocalDefId,
39 pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
40 UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id }
44 /// Information describing the capture of an upvar. This is computed
45 /// during `typeck`, specifically by `regionck`.
46 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
47 #[derive(TypeFoldable, TypeVisitable)]
48 pub enum UpvarCapture {
49 /// Upvar is captured by value. This is always true when the
50 /// closure is labeled `move`, but can also be true in other cases
51 /// depending on inference.
54 /// Upvar is captured by reference.
58 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
59 pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
61 /// Given the closure DefId this map provides a map of root variables to minimum
62 /// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
63 pub type MinCaptureInformationMap<'tcx> = FxHashMap<LocalDefId, RootVariableMinCaptureList<'tcx>>;
65 /// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
66 /// Used to track the minimum set of `Place`s that need to be captured to support all
67 /// Places captured by the closure starting at a given root variable.
69 /// This provides a convenient and quick way of checking if a variable being used within
70 /// a closure is a capture of a local variable.
71 pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
73 /// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
74 pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
76 /// Represents the various closure traits in the language. This
77 /// will determine the type of the environment (`self`, in the
78 /// desugaring) argument that the closure expects.
80 /// You can get the environment type of a closure using
81 /// `tcx.closure_env_ty()`.
82 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
84 pub enum ClosureKind {
85 // Warning: Ordering is significant here! The ordering is chosen
86 // because the trait Fn is a subtrait of FnMut and so in turn, and
87 // hence we order it so that Fn < FnMut < FnOnce.
93 impl<'tcx> ClosureKind {
94 /// This is the initial value used when doing upvar inference.
95 pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
97 /// Returns `true` if a type that impls this closure kind
98 /// must also implement `other`.
99 pub fn extends(self, other: ty::ClosureKind) -> bool {
103 /// Converts `self` to a [`DefId`] of the corresponding trait.
105 /// Note: the inverse of this function is [`TyCtxt::fn_trait_kind_from_def_id`].
106 pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
107 tcx.require_lang_item(
109 ClosureKind::Fn => LangItem::Fn,
110 ClosureKind::FnMut => LangItem::FnMut,
111 ClosureKind::FnOnce => LangItem::FnOnce,
117 /// Returns the representative scalar type for this closure kind.
118 /// See `Ty::to_opt_closure_kind` for more details.
119 pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
121 ClosureKind::Fn => tcx.types.i8,
122 ClosureKind::FnMut => tcx.types.i16,
123 ClosureKind::FnOnce => tcx.types.i32,
128 /// A composite describing a `Place` that is captured by a closure.
129 #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
130 #[derive(TypeFoldable, TypeVisitable)]
131 pub struct CapturedPlace<'tcx> {
132 /// The `Place` that is captured.
133 pub place: HirPlace<'tcx>,
135 /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
136 pub info: CaptureInfo,
138 /// Represents if `place` can be mutated or not.
139 pub mutability: hir::Mutability,
141 /// Region of the resulting reference if the upvar is captured by ref.
142 pub region: Option<ty::Region<'tcx>>,
145 impl<'tcx> CapturedPlace<'tcx> {
146 pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
147 place_to_string_for_capture(tcx, &self.place)
150 /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
151 fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
152 let hir_id = match self.place.base {
153 HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
154 base => bug!("Expected an upvar, found {:?}", base),
156 let mut symbol = tcx.hir().name(hir_id).as_str().to_string();
158 let mut ty = self.place.base_ty;
159 for proj in self.place.projections.iter() {
161 HirProjectionKind::Field(idx, variant) => match ty.kind() {
162 ty::Tuple(_) => write!(&mut symbol, "__{}", idx).unwrap(),
163 ty::Adt(def, ..) => {
167 def.variant(variant).fields[idx as usize].name.as_str(),
173 self.get_capture_kind_span(tcx),
174 "Unexpected type {:?} for `Field` projection",
180 // Ignore derefs for now, as they are likely caused by
181 // autoderefs that don't appear in the original code.
182 HirProjectionKind::Deref => {}
183 proj => bug!("Unexpected projection {:?} in captured place", proj),
188 Symbol::intern(&symbol)
191 /// Returns the hir-id of the root variable for the captured place.
192 /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
193 pub fn get_root_variable(&self) -> hir::HirId {
194 match self.place.base {
195 HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
196 base => bug!("Expected upvar, found={:?}", base),
200 /// Returns the `LocalDefId` of the closure that captured this Place
201 pub fn get_closure_local_def_id(&self) -> LocalDefId {
202 match self.place.base {
203 HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id,
204 base => bug!("expected upvar, found={:?}", base),
208 /// Return span pointing to use that resulted in selecting the captured path
209 pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
210 if let Some(path_expr_id) = self.info.path_expr_id {
211 tcx.hir().span(path_expr_id)
212 } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
213 tcx.hir().span(capture_kind_expr_id)
215 // Fallback on upvars mentioned if neither path or capture expr id is captured
217 // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
218 tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
219 [&self.get_root_variable()]
224 /// Return span pointing to use that resulted in selecting the current capture kind
225 pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
226 if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
227 tcx.hir().span(capture_kind_expr_id)
228 } else if let Some(path_expr_id) = self.info.path_expr_id {
229 tcx.hir().span(path_expr_id)
231 // Fallback on upvars mentioned if neither path or capture expr id is captured
233 // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
234 tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
235 [&self.get_root_variable()]
241 fn symbols_for_closure_captures(tcx: TyCtxt<'_>, def_id: (LocalDefId, LocalDefId)) -> Vec<Symbol> {
242 let typeck_results = tcx.typeck(def_id.0);
243 let captures = typeck_results.closure_min_captures_flattened(def_id.1);
244 captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
247 /// Return true if the `proj_possible_ancestor` represents an ancestor path
248 /// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
249 /// assuming they both start off of the same root variable.
251 /// **Note:** It's the caller's responsibility to ensure that both lists of projections
252 /// start off of the same root variable.
254 /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
255 /// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
256 /// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
257 /// 2. Since we only look at the projections here function will return `bar.x` as an a valid
258 /// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
259 /// list are being applied to the same root variable.
260 pub fn is_ancestor_or_same_capture(
261 proj_possible_ancestor: &[HirProjectionKind],
262 proj_capture: &[HirProjectionKind],
264 // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
265 // Therefore we can't just check if all projections are same in the zipped iterator below.
266 if proj_possible_ancestor.len() > proj_capture.len() {
270 proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
273 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
274 /// for a particular capture as well as identifying the part of the source code
275 /// that triggered this capture to occur.
276 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
277 #[derive(TypeFoldable, TypeVisitable)]
278 pub struct CaptureInfo {
279 /// Expr Id pointing to use that resulted in selecting the current capture kind
283 /// let mut t = (0,1);
286 /// println!("{t:?}"); // L1
290 /// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
293 /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
294 /// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
295 /// None. In such case we fallback on uvpars_mentioned for span.
306 /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
307 /// but we won't see it being used during capture analysis, since it's essentially a discard.
308 pub capture_kind_expr_id: Option<hir::HirId>,
309 /// Expr Id pointing to use that resulted the corresponding place being captured
311 /// See `capture_kind_expr_id` for example.
313 pub path_expr_id: Option<hir::HirId>,
315 /// Capture mode that was selected
316 pub capture_kind: UpvarCapture,
319 pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
320 let mut curr_string: String = match place.base {
321 HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
322 _ => bug!("Capture_information should only contain upvars"),
325 for (i, proj) in place.projections.iter().enumerate() {
327 HirProjectionKind::Deref => {
328 curr_string = format!("*{}", curr_string);
330 HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
331 ty::Adt(def, ..) => {
332 curr_string = format!(
335 def.variant(variant).fields[idx as usize].name.as_str()
339 curr_string = format!("{}.{}", curr_string, idx);
343 "Field projection applied to a type other than Adt or Tuple: {:?}.",
344 place.ty_before_projection(i).kind()
348 proj => bug!("{:?} unexpected because it isn't captured", proj),
355 #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
356 #[derive(TypeFoldable, TypeVisitable)]
357 pub enum BorrowKind {
358 /// Data must be immutable and is aliasable.
361 /// Data must be immutable but not aliasable. This kind of borrow
362 /// cannot currently be expressed by the user and is used only in
363 /// implicit closure bindings. It is needed when the closure
364 /// is borrowing or mutating a mutable referent, e.g.:
368 /// let x: &mut isize = &mut z;
369 /// let y = || *x += 5;
372 /// If we were to try to translate this closure into a more explicit
373 /// form, we'd encounter an error with the code as written:
375 /// ```compile_fail,E0594
376 /// struct Env<'a> { x: &'a &'a mut isize }
378 /// let x: &mut isize = &mut z;
379 /// let y = (&mut Env { x: &x }, fn_ptr); // Closure is pair of env and fn
380 /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
383 /// This is then illegal because you cannot mutate a `&mut` found
384 /// in an aliasable location. To solve, you'd have to translate with
385 /// an `&mut` borrow:
387 /// ```compile_fail,E0596
388 /// struct Env<'a> { x: &'a mut &'a mut isize }
390 /// let x: &mut isize = &mut z;
391 /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x
392 /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
395 /// Now the assignment to `**env.x` is legal, but creating a
396 /// mutable pointer to `x` is not because `x` is not mutable. We
397 /// could fix this by declaring `x` as `let mut x`. This is ok in
398 /// user code, if awkward, but extra weird for closures, since the
399 /// borrow is hidden.
401 /// So we introduce a "unique imm" borrow -- the referent is
402 /// immutable, but not aliasable. This solves the problem. For
403 /// simplicity, we don't give users the way to express this
404 /// borrow, it's just used when translating closures.
407 /// Data is mutable and not aliasable.
412 pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
414 hir::Mutability::Mut => MutBorrow,
415 hir::Mutability::Not => ImmBorrow,
419 /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow
420 /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a
421 /// mutability that is stronger than necessary so that it at least *would permit* the borrow in
423 pub fn to_mutbl_lossy(self) -> hir::Mutability {
425 MutBorrow => hir::Mutability::Mut,
426 ImmBorrow => hir::Mutability::Not,
428 // We have no type corresponding to a unique imm borrow, so
429 // use `&mut`. It gives all the capabilities of a `&uniq`
430 // and hence is a safe "over approximation".
431 UniqueImmBorrow => hir::Mutability::Mut,
436 pub fn provide(providers: &mut ty::query::Providers) {
437 *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }