use rustc_span::{Span, DUMMY_SP};
use std::fmt;
+use std::ops::Deref;
/// Represents a statically-describable scope that can be used to
/// bound the lifetime/region for values.
pub type ScopeDepth = u32;
/// The region scope tree encodes information about region relationships.
-#[derive(Default, Debug)]
+#[derive(TyEncodable, TyDecodable, Default, Debug)]
pub struct ScopeTree {
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
/// Maps from a `NodeId` to the associated destruction scope (if any).
destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
- /// `rvalue_scopes` includes entries for those expressions whose
- /// cleanup scope is larger than the default. The map goes from the
- /// expression ID to the cleanup scope id. For rvalues not present in
- /// this table, the appropriate cleanup scope is the innermost
- /// enclosing statement, conditional expression, or repeating
- /// block (see `terminating_scopes`).
- /// In constants, None is used to indicate that certain expressions
- /// escape into 'static and should have no local cleanup scope.
- rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+ /// Identifies expressions which, if captured into a temporary, ought to
+ /// have a temporary whose lifetime extends to the end of the enclosing *block*,
+ /// and not the enclosing *statement*. Expressions that are not present in this
+ /// table are not rvalue candidates. The set of rvalue candidates is computed
+ /// during type check based on a traversal of the AST.
+ pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
/// If there are any `yield` nested within a scope, this map
/// stores the `Span` of the last one and its index in the
pub body_expr_count: FxHashMap<hir::BodyId, usize>,
}
+/// Identifies the reason that a given expression is an rvalue candidate
+/// (see the `rvalue_candidates` field for more information what rvalue
+/// candidates in general). In constants, the `lifetime` field is None
+/// to indicate that certain expressions escape into 'static and
+/// should have no local cleanup scope.
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum RvalueCandidateType {
+ Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
+ Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
+}
+
#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
pub struct YieldData {
/// The `Span` of the yield.
self.var_map.insert(var, lifetime);
}
- pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
- debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
- if let Some(lifetime) = lifetime {
- assert!(var != lifetime.item_local_id());
+ pub fn record_rvalue_candidate(
+ &mut self,
+ var: hir::HirId,
+ candidate_type: RvalueCandidateType,
+ ) {
+ debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
+ match &candidate_type {
+ RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
+ | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
+ assert!(var.local_id != lifetime.item_local_id())
+ }
+ _ => {}
}
- self.rvalue_scopes.insert(var, lifetime);
+ self.rvalue_candidates.insert(var, candidate_type);
}
/// Returns the narrowest scope that encloses `id`, if any.
self.var_map.get(&var_id).cloned()
}
- /// Returns the scope when the temp created by `expr_id` will be cleaned up.
- pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
- // Check for a designated rvalue scope.
- if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
- debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
- return s;
- }
-
- // Otherwise, locate the innermost terminating scope
- // if there's one. Static items, for instance, won't
- // have an enclosing scope, hence no scope will be
- // returned.
- let mut id = Scope { id: expr_id, data: ScopeData::Node };
-
- while let Some(&(p, _)) = self.parent_map.get(&id) {
- match p.data {
- ScopeData::Destruction => {
- debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id);
- return Some(id);
- }
- _ => id = p,
- }
- }
-
- debug!("temporary_scope({:?}) = None", expr_id);
- None
- }
-
/// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
/// `false` otherwise.
///
/// Checks whether the given scope contains a `yield`. If so,
/// returns `Some(YieldData)`. If not, returns `None`.
- pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
- self.yield_in_scope.get(&scope)
+ pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> {
+ self.yield_in_scope.get(&scope).map(Deref::deref)
}
/// Gives the number of expressions visited in a body.
ref parent_map,
ref var_map,
ref destruction_scopes,
- ref rvalue_scopes,
+ ref rvalue_candidates,
ref yield_in_scope,
} = *self;
parent_map.hash_stable(hcx, hasher);
var_map.hash_stable(hcx, hasher);
destruction_scopes.hash_stable(hcx, hasher);
- rvalue_scopes.hash_stable(hcx, hasher);
+ rvalue_candidates.hash_stable(hcx, hasher);
yield_in_scope.hash_stable(hcx, hasher);
}
}