rustc_hir_typeck/
rvalue_scopes.rs

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