blob: 34ce0ab1f8b988569f956aa66c3441ff617d7475 [file] [log] [blame]
use super::FnCtxt;
use hir::def_id::DefId;
use hir::Node;
use rustc_hir as hir;
use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
use rustc_middle::ty::RvalueScopes;
/// 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 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
}