]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/rvalue_scopes.rs
Auto merge of #93717 - pietroalbini:pa-ci-profiler, r=Mark-Simulacrum
[rust.git] / compiler / rustc_typeck / src / check / rvalue_scopes.rs
1 use super::FnCtxt;
2 use hir::def_id::DefId;
3 use hir::Node;
4 use rustc_hir as hir;
5 use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
6 use rustc_middle::ty::RvalueScopes;
7
8 /// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
9 /// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
10 /// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
11 /// statement.
12 ///
13 /// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
14 /// `<rvalue>` as `blk_id`:
15 ///
16 /// ```text
17 ///     ET = *ET
18 ///        | ET[...]
19 ///        | ET.f
20 ///        | (ET)
21 ///        | <rvalue>
22 /// ```
23 ///
24 /// Note: ET is intended to match "rvalues or places based on rvalues".
25 fn record_rvalue_scope_rec(
26     rvalue_scopes: &mut RvalueScopes,
27     mut expr: &hir::Expr<'_>,
28     lifetime: Option<Scope>,
29 ) {
30     loop {
31         // Note: give all the expressions matching `ET` with the
32         // extended temporary lifetime, not just the innermost rvalue,
33         // because in codegen if we must compile e.g., `*rvalue()`
34         // into a temporary, we request the temporary scope of the
35         // outer expression.
36
37         rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime);
38
39         match expr.kind {
40             hir::ExprKind::AddrOf(_, _, subexpr)
41             | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
42             | hir::ExprKind::Field(subexpr, _)
43             | hir::ExprKind::Index(subexpr, _) => {
44                 expr = subexpr;
45             }
46             _ => {
47                 return;
48             }
49         }
50     }
51 }
52 fn record_rvalue_scope(
53     rvalue_scopes: &mut RvalueScopes,
54     expr: &hir::Expr<'_>,
55     candidate: &RvalueCandidateType,
56 ) {
57     debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
58     match candidate {
59         RvalueCandidateType::Borrow { lifetime, .. }
60         | RvalueCandidateType::Pattern { lifetime, .. } => {
61             record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime)
62         } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
63     }
64 }
65
66 pub fn resolve_rvalue_scopes<'a, 'tcx>(
67     fcx: &'a FnCtxt<'a, 'tcx>,
68     scope_tree: &'a ScopeTree,
69     def_id: DefId,
70 ) -> RvalueScopes {
71     let tcx = &fcx.tcx;
72     let hir_map = tcx.hir();
73     let mut rvalue_scopes = RvalueScopes::new();
74     debug!("start resolving rvalue scopes, def_id={def_id:?}");
75     debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
76     for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
77         let Some(Node::Expr(expr)) = hir_map.find(hir_id) else {
78             bug!("hir node does not exist")
79         };
80         record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
81     }
82     rvalue_scopes
83 }