1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use hir::def_id::DefId;
use hir::Node;
use rustc_hir as hir;
use rustc_middle::bug;
use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
use rustc_middle::ty::RvalueScopes;
use tracing::debug;

use super::FnCtxt;

/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
/// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
/// statement.
///
/// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
/// `<rvalue>` as `blk_id`:
///
/// ```text
///     ET = *ET
///        | ET[...]
///        | ET.f
///        | (ET)
///        | <rvalue>
/// ```
///
/// Note: ET is intended to match "rvalues or places based on rvalues".
fn record_rvalue_scope_rec(
    rvalue_scopes: &mut RvalueScopes,
    mut expr: &hir::Expr<'_>,
    lifetime: Option<Scope>,
) {
    loop {
        // Note: give all the expressions matching `ET` with the
        // extended temporary lifetime, not just the innermost rvalue,
        // because in codegen if we must compile e.g., `*rvalue()`
        // into a temporary, we request the temporary scope of the
        // outer expression.

        rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime);

        match expr.kind {
            hir::ExprKind::AddrOf(_, _, subexpr)
            | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
            | hir::ExprKind::Field(subexpr, _)
            | hir::ExprKind::Index(subexpr, _, _) => {
                expr = subexpr;
            }
            _ => {
                return;
            }
        }
    }
}
fn record_rvalue_scope(
    rvalue_scopes: &mut RvalueScopes,
    expr: &hir::Expr<'_>,
    candidate: &RvalueCandidateType,
) {
    debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
    match candidate {
        RvalueCandidateType::Borrow { lifetime, .. }
        | RvalueCandidateType::Pattern { lifetime, .. } => {
            record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime)
        } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
    }
}

pub(crate) fn resolve_rvalue_scopes<'a, 'tcx>(
    fcx: &'a FnCtxt<'a, 'tcx>,
    scope_tree: &'a ScopeTree,
    def_id: DefId,
) -> RvalueScopes {
    let tcx = &fcx.tcx;
    let mut rvalue_scopes = RvalueScopes::new();
    debug!("start resolving rvalue scopes, def_id={def_id:?}");
    debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
    for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
        let Node::Expr(expr) = tcx.hir_node(hir_id) else { bug!("hir node does not exist") };
        record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
    }
    rvalue_scopes
}