]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/closure.rs
Rollup merge of #103488 - oli-obk:impl_trait_for_tait, r=lcnr
[rust.git] / compiler / rustc_middle / src / ty / closure.rs
1 use crate::hir::place::{
2     Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
3 };
4 use crate::{mir, ty};
5
6 use std::fmt::Write;
7
8 use hir::LangItem;
9 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
10 use rustc_hir as hir;
11 use rustc_hir::def_id::{DefId, LocalDefId};
12 use rustc_span::{Span, Symbol};
13
14 use super::{Ty, TyCtxt};
15
16 use self::BorrowKind::*;
17
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);
21
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,
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, HashStable)]
32 #[derive(TypeFoldable, TypeVisitable)]
33 pub struct UpvarId {
34     pub var_path: UpvarPath,
35     pub closure_expr_id: LocalDefId,
36 }
37
38 impl UpvarId {
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 }
41     }
42 }
43
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.
52     ByValue,
53
54     /// Upvar is captured by reference.
55     ByRef(BorrowKind),
56 }
57
58 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
59 pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
60
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>>;
64
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.
68 ///
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>>;
72
73 /// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
74 pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
75
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.
79 ///
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)]
83 #[derive(HashStable)]
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.
88     Fn,
89     FnMut,
90     FnOnce,
91 }
92
93 impl<'tcx> ClosureKind {
94     // This is the initial value used when doing upvar inference.
95     pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
96
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 {
100         matches!(
101             (self, other),
102             (ClosureKind::Fn, ClosureKind::Fn)
103                 | (ClosureKind::Fn, ClosureKind::FnMut)
104                 | (ClosureKind::Fn, ClosureKind::FnOnce)
105                 | (ClosureKind::FnMut, ClosureKind::FnMut)
106                 | (ClosureKind::FnMut, ClosureKind::FnOnce)
107                 | (ClosureKind::FnOnce, ClosureKind::FnOnce)
108         )
109     }
110
111     /// Returns the representative scalar type for this closure kind.
112     /// See `Ty::to_opt_closure_kind` for more details.
113     pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
114         match self {
115             ClosureKind::Fn => tcx.types.i8,
116             ClosureKind::FnMut => tcx.types.i16,
117             ClosureKind::FnOnce => tcx.types.i32,
118         }
119     }
120
121     pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
122         if Some(def_id) == tcx.lang_items().fn_once_trait() {
123             Some(ClosureKind::FnOnce)
124         } else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
125             Some(ClosureKind::FnMut)
126         } else if Some(def_id) == tcx.lang_items().fn_trait() {
127             Some(ClosureKind::Fn)
128         } else {
129             None
130         }
131     }
132
133     pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
134         tcx.require_lang_item(
135             match self {
136                 ClosureKind::Fn => LangItem::Fn,
137                 ClosureKind::FnMut => LangItem::FnMut,
138                 ClosureKind::FnOnce => LangItem::FnOnce,
139             },
140             None,
141         )
142     }
143 }
144
145 /// A composite describing a `Place` that is captured by a closure.
146 #[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
147 #[derive(TypeFoldable, TypeVisitable)]
148 pub struct CapturedPlace<'tcx> {
149     /// The `Place` that is captured.
150     pub place: HirPlace<'tcx>,
151
152     /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
153     pub info: CaptureInfo,
154
155     /// Represents if `place` can be mutated or not.
156     pub mutability: hir::Mutability,
157
158     /// Region of the resulting reference if the upvar is captured by ref.
159     pub region: Option<ty::Region<'tcx>>,
160 }
161
162 impl<'tcx> CapturedPlace<'tcx> {
163     pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
164         place_to_string_for_capture(tcx, &self.place)
165     }
166
167     /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
168     fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
169         let hir_id = match self.place.base {
170             HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
171             base => bug!("Expected an upvar, found {:?}", base),
172         };
173         let mut symbol = tcx.hir().name(hir_id).as_str().to_string();
174
175         let mut ty = self.place.base_ty;
176         for proj in self.place.projections.iter() {
177             match proj.kind {
178                 HirProjectionKind::Field(idx, variant) => match ty.kind() {
179                     ty::Tuple(_) => write!(&mut symbol, "__{}", idx).unwrap(),
180                     ty::Adt(def, ..) => {
181                         write!(
182                             &mut symbol,
183                             "__{}",
184                             def.variant(variant).fields[idx as usize].name.as_str(),
185                         )
186                         .unwrap();
187                     }
188                     ty => {
189                         span_bug!(
190                             self.get_capture_kind_span(tcx),
191                             "Unexpected type {:?} for `Field` projection",
192                             ty
193                         )
194                     }
195                 },
196
197                 // Ignore derefs for now, as they are likely caused by
198                 // autoderefs that don't appear in the original code.
199                 HirProjectionKind::Deref => {}
200                 proj => bug!("Unexpected projection {:?} in captured place", proj),
201             }
202             ty = proj.ty;
203         }
204
205         Symbol::intern(&symbol)
206     }
207
208     /// Returns the hir-id of the root variable for the captured place.
209     /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
210     pub fn get_root_variable(&self) -> hir::HirId {
211         match self.place.base {
212             HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
213             base => bug!("Expected upvar, found={:?}", base),
214         }
215     }
216
217     /// Returns the `LocalDefId` of the closure that captured this Place
218     pub fn get_closure_local_def_id(&self) -> LocalDefId {
219         match self.place.base {
220             HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id,
221             base => bug!("expected upvar, found={:?}", base),
222         }
223     }
224
225     /// Return span pointing to use that resulted in selecting the captured path
226     pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
227         if let Some(path_expr_id) = self.info.path_expr_id {
228             tcx.hir().span(path_expr_id)
229         } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
230             tcx.hir().span(capture_kind_expr_id)
231         } else {
232             // Fallback on upvars mentioned if neither path or capture expr id is captured
233
234             // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
235             tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
236                 [&self.get_root_variable()]
237                 .span
238         }
239     }
240
241     /// Return span pointing to use that resulted in selecting the current capture kind
242     pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
243         if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
244             tcx.hir().span(capture_kind_expr_id)
245         } else if let Some(path_expr_id) = self.info.path_expr_id {
246             tcx.hir().span(path_expr_id)
247         } else {
248             // Fallback on upvars mentioned if neither path or capture expr id is captured
249
250             // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
251             tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
252                 [&self.get_root_variable()]
253                 .span
254         }
255     }
256 }
257
258 fn symbols_for_closure_captures<'tcx>(
259     tcx: TyCtxt<'tcx>,
260     def_id: (LocalDefId, LocalDefId),
261 ) -> Vec<Symbol> {
262     let typeck_results = tcx.typeck(def_id.0);
263     let captures = typeck_results.closure_min_captures_flattened(def_id.1);
264     captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
265 }
266
267 /// Return true if the `proj_possible_ancestor` represents an ancestor path
268 /// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
269 /// assuming they both start off of the same root variable.
270 ///
271 /// **Note:** It's the caller's responsibility to ensure that both lists of projections
272 ///           start off of the same root variable.
273 ///
274 /// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of
275 ///        `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`.
276 ///        Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`.
277 ///     2. Since we only look at the projections here function will return `bar.x` as an a valid
278 ///        ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
279 ///        list are being applied to the same root variable.
280 pub fn is_ancestor_or_same_capture(
281     proj_possible_ancestor: &[HirProjectionKind],
282     proj_capture: &[HirProjectionKind],
283 ) -> bool {
284     // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
285     // Therefore we can't just check if all projections are same in the zipped iterator below.
286     if proj_possible_ancestor.len() > proj_capture.len() {
287         return false;
288     }
289
290     proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b)
291 }
292
293 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
294 /// for a particular capture as well as identifying the part of the source code
295 /// that triggered this capture to occur.
296 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
297 #[derive(TypeFoldable, TypeVisitable)]
298 pub struct CaptureInfo {
299     /// Expr Id pointing to use that resulted in selecting the current capture kind
300     ///
301     /// Eg:
302     /// ```rust,no_run
303     /// let mut t = (0,1);
304     ///
305     /// let c = || {
306     ///     println!("{t:?}"); // L1
307     ///     t.1 = 4; // L2
308     /// };
309     /// ```
310     /// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
311     /// use on L1.
312     ///
313     /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
314     /// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
315     /// None. In such case we fallback on uvpars_mentioned for span.
316     ///
317     /// Eg:
318     /// ```rust,no_run
319     /// let x = 5;
320     ///
321     /// let c = || {
322     ///     let _ = x;
323     /// };
324     /// ```
325     ///
326     /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
327     /// but we won't see it being used during capture analysis, since it's essentially a discard.
328     pub capture_kind_expr_id: Option<hir::HirId>,
329     /// Expr Id pointing to use that resulted the corresponding place being captured
330     ///
331     /// See `capture_kind_expr_id` for example.
332     ///
333     pub path_expr_id: Option<hir::HirId>,
334
335     /// Capture mode that was selected
336     pub capture_kind: UpvarCapture,
337 }
338
339 pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
340     let mut curr_string: String = match place.base {
341         HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
342         _ => bug!("Capture_information should only contain upvars"),
343     };
344
345     for (i, proj) in place.projections.iter().enumerate() {
346         match proj.kind {
347             HirProjectionKind::Deref => {
348                 curr_string = format!("*{}", curr_string);
349             }
350             HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
351                 ty::Adt(def, ..) => {
352                     curr_string = format!(
353                         "{}.{}",
354                         curr_string,
355                         def.variant(variant).fields[idx as usize].name.as_str()
356                     );
357                 }
358                 ty::Tuple(_) => {
359                     curr_string = format!("{}.{}", curr_string, idx);
360                 }
361                 _ => {
362                     bug!(
363                         "Field projection applied to a type other than Adt or Tuple: {:?}.",
364                         place.ty_before_projection(i).kind()
365                     )
366                 }
367             },
368             proj => bug!("{:?} unexpected because it isn't captured", proj),
369         }
370     }
371
372     curr_string
373 }
374
375 #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
376 #[derive(TypeFoldable, TypeVisitable)]
377 pub enum BorrowKind {
378     /// Data must be immutable and is aliasable.
379     ImmBorrow,
380
381     /// Data must be immutable but not aliasable. This kind of borrow
382     /// cannot currently be expressed by the user and is used only in
383     /// implicit closure bindings. It is needed when the closure
384     /// is borrowing or mutating a mutable referent, e.g.:
385     ///
386     /// ```
387     /// let mut z = 3;
388     /// let x: &mut isize = &mut z;
389     /// let y = || *x += 5;
390     /// ```
391     ///
392     /// If we were to try to translate this closure into a more explicit
393     /// form, we'd encounter an error with the code as written:
394     ///
395     /// ```compile_fail,E0594
396     /// struct Env<'a> { x: &'a &'a mut isize }
397     /// let mut z = 3;
398     /// let x: &mut isize = &mut z;
399     /// let y = (&mut Env { x: &x }, fn_ptr);  // Closure is pair of env and fn
400     /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
401     /// ```
402     ///
403     /// This is then illegal because you cannot mutate a `&mut` found
404     /// in an aliasable location. To solve, you'd have to translate with
405     /// an `&mut` borrow:
406     ///
407     /// ```compile_fail,E0596
408     /// struct Env<'a> { x: &'a mut &'a mut isize }
409     /// let mut z = 3;
410     /// let x: &mut isize = &mut z;
411     /// let y = (&mut Env { x: &mut x }, fn_ptr); // changed from &x to &mut x
412     /// fn fn_ptr(env: &mut Env) { **env.x += 5; }
413     /// ```
414     ///
415     /// Now the assignment to `**env.x` is legal, but creating a
416     /// mutable pointer to `x` is not because `x` is not mutable. We
417     /// could fix this by declaring `x` as `let mut x`. This is ok in
418     /// user code, if awkward, but extra weird for closures, since the
419     /// borrow is hidden.
420     ///
421     /// So we introduce a "unique imm" borrow -- the referent is
422     /// immutable, but not aliasable. This solves the problem. For
423     /// simplicity, we don't give users the way to express this
424     /// borrow, it's just used when translating closures.
425     UniqueImmBorrow,
426
427     /// Data is mutable and not aliasable.
428     MutBorrow,
429 }
430
431 impl BorrowKind {
432     pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
433         match m {
434             hir::Mutability::Mut => MutBorrow,
435             hir::Mutability::Not => ImmBorrow,
436         }
437     }
438
439     /// Returns a mutability `m` such that an `&m T` pointer could be used to obtain this borrow
440     /// kind. Because borrow kinds are richer than mutabilities, we sometimes have to pick a
441     /// mutability that is stronger than necessary so that it at least *would permit* the borrow in
442     /// question.
443     pub fn to_mutbl_lossy(self) -> hir::Mutability {
444         match self {
445             MutBorrow => hir::Mutability::Mut,
446             ImmBorrow => hir::Mutability::Not,
447
448             // We have no type corresponding to a unique imm borrow, so
449             // use `&mut`. It gives all the capabilities of a `&uniq`
450             // and hence is a safe "over approximation".
451             UniqueImmBorrow => hir::Mutability::Mut,
452         }
453     }
454 }
455
456 pub fn provide(providers: &mut ty::query::Providers) {
457     *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }
458 }