mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #95563 - dingxiangfei2009:dxf-rfc66-refactor, r=nikomatsakis
Move the extended lifetime resolution into typeck context Related to #15023 This PR is based on the [idea](https://github.com/rust-lang/rust/issues/15023#issuecomment-1070931433) of #15023 by `@nikomatsakis.` This PR specifically proposes to - Delay the resolution of scopes of rvalues to a later stage, so that enough type information is available to refine those scopes based on relationships of lifetimes. - Highlight relevant parts that would help future reviews on the next installments of works to fully implement a solution to RFC 66.
This commit is contained in:
commit
653463731a
@ -1370,7 +1370,7 @@ pub enum UnsafeSource {
|
|||||||
UserProvided,
|
UserProvided,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||||
pub struct BodyId {
|
pub struct BodyId {
|
||||||
pub hir_id: HirId,
|
pub hir_id: HirId,
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ macro_rules! arena_types {
|
|||||||
[] const_allocs: rustc_middle::mir::interpret::Allocation,
|
[] const_allocs: rustc_middle::mir::interpret::Allocation,
|
||||||
// Required for the incremental on-disk cache
|
// Required for the incremental on-disk cache
|
||||||
[] mir_keys: rustc_hir::def_id::DefIdSet,
|
[] mir_keys: rustc_hir::def_id::DefIdSet,
|
||||||
[] region_scope_tree: rustc_middle::middle::region::ScopeTree,
|
|
||||||
[] dropck_outlives:
|
[] dropck_outlives:
|
||||||
rustc_middle::infer::canonical::Canonical<'tcx,
|
rustc_middle::infer::canonical::Canonical<'tcx,
|
||||||
rustc_middle::infer::canonical::QueryResponse<'tcx,
|
rustc_middle::infer::canonical::QueryResponse<'tcx,
|
||||||
|
@ -203,7 +203,7 @@ impl Scope {
|
|||||||
pub type ScopeDepth = u32;
|
pub type ScopeDepth = u32;
|
||||||
|
|
||||||
/// The region scope tree encodes information about region relationships.
|
/// The region scope tree encodes information about region relationships.
|
||||||
#[derive(Default, Debug)]
|
#[derive(TyEncodable, TyDecodable, Default, Debug)]
|
||||||
pub struct ScopeTree {
|
pub struct ScopeTree {
|
||||||
/// If not empty, this body is the root of this region hierarchy.
|
/// If not empty, this body is the root of this region hierarchy.
|
||||||
pub root_body: Option<hir::HirId>,
|
pub root_body: Option<hir::HirId>,
|
||||||
@ -223,15 +223,12 @@ pub struct ScopeTree {
|
|||||||
/// Maps from a `NodeId` to the associated destruction scope (if any).
|
/// Maps from a `NodeId` to the associated destruction scope (if any).
|
||||||
destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
|
destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
|
||||||
|
|
||||||
/// `rvalue_scopes` includes entries for those expressions whose
|
/// Identifies expressions which, if captured into a temporary, ought to
|
||||||
/// cleanup scope is larger than the default. The map goes from the
|
/// have a temporary whose lifetime extends to the end of the enclosing *block*,
|
||||||
/// expression ID to the cleanup scope id. For rvalues not present in
|
/// and not the enclosing *statement*. Expressions that are not present in this
|
||||||
/// this table, the appropriate cleanup scope is the innermost
|
/// table are not rvalue candidates. The set of rvalue candidates is computed
|
||||||
/// enclosing statement, conditional expression, or repeating
|
/// during type check based on a traversal of the AST.
|
||||||
/// block (see `terminating_scopes`).
|
pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
|
||||||
/// 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>>,
|
|
||||||
|
|
||||||
/// If there are any `yield` nested within a scope, this map
|
/// If there are any `yield` nested within a scope, this map
|
||||||
/// stores the `Span` of the last one and its index in the
|
/// stores the `Span` of the last one and its index in the
|
||||||
@ -315,6 +312,17 @@ pub struct ScopeTree {
|
|||||||
pub body_expr_count: FxHashMap<hir::BodyId, usize>,
|
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)]
|
#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub struct YieldData {
|
pub struct YieldData {
|
||||||
/// The `Span` of the yield.
|
/// The `Span` of the yield.
|
||||||
@ -349,12 +357,20 @@ impl ScopeTree {
|
|||||||
self.var_map.insert(var, lifetime);
|
self.var_map.insert(var, lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
|
pub fn record_rvalue_candidate(
|
||||||
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
|
&mut self,
|
||||||
if let Some(lifetime) = lifetime {
|
var: hir::HirId,
|
||||||
assert!(var != lifetime.item_local_id());
|
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.
|
/// Returns the narrowest scope that encloses `id`, if any.
|
||||||
@ -367,34 +383,6 @@ impl ScopeTree {
|
|||||||
self.var_map.get(&var_id).cloned()
|
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
|
/// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
|
||||||
/// `false` otherwise.
|
/// `false` otherwise.
|
||||||
///
|
///
|
||||||
@ -439,7 +427,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
|
|||||||
ref parent_map,
|
ref parent_map,
|
||||||
ref var_map,
|
ref var_map,
|
||||||
ref destruction_scopes,
|
ref destruction_scopes,
|
||||||
ref rvalue_scopes,
|
ref rvalue_candidates,
|
||||||
ref yield_in_scope,
|
ref yield_in_scope,
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
@ -448,7 +436,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
|
|||||||
parent_map.hash_stable(hcx, hasher);
|
parent_map.hash_stable(hcx, hasher);
|
||||||
var_map.hash_stable(hcx, hasher);
|
var_map.hash_stable(hcx, hasher);
|
||||||
destruction_scopes.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);
|
yield_in_scope.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1048,12 +1048,6 @@ rustc_queries! {
|
|||||||
desc { "reachability" }
|
desc { "reachability" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
|
|
||||||
/// in the case of closures, this will be redirected to the enclosing function.
|
|
||||||
query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
|
|
||||||
desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates a MIR body for the shim.
|
/// Generates a MIR body for the shim.
|
||||||
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
|
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
|
||||||
storage(ArenaCacheSelector<'tcx>)
|
storage(ArenaCacheSelector<'tcx>)
|
||||||
|
@ -6,6 +6,7 @@ use crate::hir::place::Place as HirPlace;
|
|||||||
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
||||||
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
|
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
|
use crate::middle::region::ScopeTree;
|
||||||
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
|
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
|
||||||
use crate::middle::stability;
|
use crate::middle::stability;
|
||||||
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
|
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
|
||||||
@ -74,6 +75,8 @@ use std::mem;
|
|||||||
use std::ops::{Bound, Deref};
|
use std::ops::{Bound, Deref};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::RvalueScopes;
|
||||||
|
|
||||||
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
|
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
|
||||||
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
|
||||||
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
|
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
|
||||||
@ -535,6 +538,17 @@ pub struct TypeckResults<'tcx> {
|
|||||||
/// issue by fake reading `t`.
|
/// issue by fake reading `t`.
|
||||||
pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
|
pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
|
||||||
|
|
||||||
|
/// Tracks critical information about regions in a body.
|
||||||
|
/// This includes containment relationship between regions,
|
||||||
|
/// liveness relationship between variables and regions and
|
||||||
|
/// information about yield points.
|
||||||
|
pub region_scope_tree: ScopeTree,
|
||||||
|
|
||||||
|
/// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
|
||||||
|
/// by applying extended parameter rules.
|
||||||
|
/// Details may be find in `rustc_typeck::check::rvalue_scopes`.
|
||||||
|
pub rvalue_scopes: RvalueScopes,
|
||||||
|
|
||||||
/// Stores the type, expression, span and optional scope span of all types
|
/// Stores the type, expression, span and optional scope span of all types
|
||||||
/// that are live across the yield of this generator (if a generator).
|
/// that are live across the yield of this generator (if a generator).
|
||||||
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
|
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
|
||||||
@ -572,6 +586,8 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||||||
concrete_opaque_types: Default::default(),
|
concrete_opaque_types: Default::default(),
|
||||||
closure_min_captures: Default::default(),
|
closure_min_captures: Default::default(),
|
||||||
closure_fake_reads: Default::default(),
|
closure_fake_reads: Default::default(),
|
||||||
|
region_scope_tree: Default::default(),
|
||||||
|
rvalue_scopes: Default::default(),
|
||||||
generator_interior_types: ty::Binder::dummy(Default::default()),
|
generator_interior_types: ty::Binder::dummy(Default::default()),
|
||||||
treat_byte_string_as_slice: Default::default(),
|
treat_byte_string_as_slice: Default::default(),
|
||||||
closure_size_eval: Default::default(),
|
closure_size_eval: Default::default(),
|
||||||
|
@ -72,6 +72,7 @@ pub use self::context::{
|
|||||||
};
|
};
|
||||||
pub use self::instance::{Instance, InstanceDef};
|
pub use self::instance::{Instance, InstanceDef};
|
||||||
pub use self::list::List;
|
pub use self::list::List;
|
||||||
|
pub use self::rvalue_scopes::RvalueScopes;
|
||||||
pub use self::sty::BoundRegionKind::*;
|
pub use self::sty::BoundRegionKind::*;
|
||||||
pub use self::sty::RegionKind::*;
|
pub use self::sty::RegionKind::*;
|
||||||
pub use self::sty::TyKind::*;
|
pub use self::sty::TyKind::*;
|
||||||
@ -118,6 +119,7 @@ mod generics;
|
|||||||
mod impls_ty;
|
mod impls_ty;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod list;
|
mod list;
|
||||||
|
mod rvalue_scopes;
|
||||||
mod structural_impls;
|
mod structural_impls;
|
||||||
mod sty;
|
mod sty;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
|||||||
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
use crate::middle::lib_features::LibFeatures;
|
use crate::middle::lib_features::LibFeatures;
|
||||||
use crate::middle::privacy::AccessLevels;
|
use crate::middle::privacy::AccessLevels;
|
||||||
use crate::middle::region;
|
|
||||||
use crate::middle::resolve_lifetime::{
|
use crate::middle::resolve_lifetime::{
|
||||||
LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
|
LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
|
||||||
};
|
};
|
||||||
|
57
compiler/rustc_middle/src/ty/rvalue_scopes.rs
Normal file
57
compiler/rustc_middle/src/ty/rvalue_scopes.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use crate::middle::region::{Scope, ScopeData, ScopeTree};
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
|
||||||
|
/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
|
||||||
|
/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
|
||||||
|
#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
|
||||||
|
pub struct RvalueScopes {
|
||||||
|
map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RvalueScopes {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { map: <_>::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
|
||||||
|
pub fn temporary_scope(
|
||||||
|
&self,
|
||||||
|
region_scope_tree: &ScopeTree,
|
||||||
|
expr_id: hir::ItemLocalId,
|
||||||
|
) -> Option<Scope> {
|
||||||
|
// Check for a designated rvalue scope.
|
||||||
|
if let Some(&s) = self.map.get(&expr_id) {
|
||||||
|
debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
|
||||||
|
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, _)) = region_scope_tree.parent_map.get(&id) {
|
||||||
|
match p.data {
|
||||||
|
ScopeData::Destruction => {
|
||||||
|
debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
|
||||||
|
return Some(id);
|
||||||
|
}
|
||||||
|
_ => id = p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("temporary_scope({expr_id:?}) = None");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make an association between a sub-expression and an extended lifetime
|
||||||
|
pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
|
||||||
|
debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
|
||||||
|
if let Some(lifetime) = lifetime {
|
||||||
|
assert!(var != lifetime.item_local_id());
|
||||||
|
}
|
||||||
|
self.map.insert(var, lifetime);
|
||||||
|
}
|
||||||
|
}
|
@ -108,7 +108,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
let_scope_stack.push(remainder_scope);
|
let_scope_stack.push(remainder_scope);
|
||||||
|
|
||||||
// Declare the bindings, which may create a source scope.
|
// Declare the bindings, which may create a source scope.
|
||||||
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
|
let remainder_span =
|
||||||
|
remainder_scope.span(this.tcx, &this.typeck_results.region_scope_tree);
|
||||||
|
|
||||||
let visibility_scope =
|
let visibility_scope =
|
||||||
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
||||||
|
@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
|
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
|
||||||
// Altough there is almost always scope for given variable in corner cases
|
// Altough there is almost always scope for given variable in corner cases
|
||||||
// like #92893 we might get variable with no scope.
|
// like #92893 we might get variable with no scope.
|
||||||
if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
|
if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) && schedule_drop{
|
||||||
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
|
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
|
||||||
}
|
}
|
||||||
Place::from(local_id)
|
Place::from(local_id)
|
||||||
@ -712,7 +712,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
for_guard: ForGuard,
|
for_guard: ForGuard,
|
||||||
) {
|
) {
|
||||||
let local_id = self.var_local_id(var, for_guard);
|
let local_id = self.var_local_id(var, for_guard);
|
||||||
if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
|
if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) {
|
||||||
self.schedule_drop(span, region_scope, local_id, DropKind::Value);
|
self.schedule_drop(span, region_scope, local_id, DropKind::Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,6 @@ struct Builder<'a, 'tcx> {
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
region_scope_tree: &'tcx region::ScopeTree,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
thir: &'a Thir<'tcx>,
|
thir: &'a Thir<'tcx>,
|
||||||
@ -881,7 +880,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
tcx,
|
tcx,
|
||||||
infcx,
|
infcx,
|
||||||
typeck_results: tcx.typeck_opt_const_arg(def),
|
typeck_results: tcx.typeck_opt_const_arg(def),
|
||||||
region_scope_tree: tcx.region_scope_tree(def.did),
|
|
||||||
param_env,
|
param_env,
|
||||||
def_id: def.did.to_def_id(),
|
def_id: def.did.to_def_id(),
|
||||||
hir_id,
|
hir_id,
|
||||||
|
@ -916,7 +916,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if scope.region_scope == region_scope {
|
if scope.region_scope == region_scope {
|
||||||
let region_scope_span = region_scope.span(self.tcx, &self.region_scope_tree);
|
let region_scope_span =
|
||||||
|
region_scope.span(self.tcx, &self.typeck_results.region_scope_tree);
|
||||||
// Attribute scope exit drops to scope's closing brace.
|
// Attribute scope exit drops to scope's closing brace.
|
||||||
let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
|
let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
|
pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
|
let temp_lifetime =
|
||||||
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id);
|
||||||
let expr_scope =
|
let expr_scope =
|
||||||
region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
|
region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
|
||||||
|
|
||||||
@ -161,7 +162,8 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let expr_ty = self.typeck_results().expr_ty(expr);
|
let expr_ty = self.typeck_results().expr_ty(expr);
|
||||||
let expr_span = expr.span;
|
let expr_span = expr.span;
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime =
|
||||||
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||||
|
|
||||||
let kind = match expr.kind {
|
let kind = match expr.kind {
|
||||||
// Here comes the interesting stuff:
|
// Here comes the interesting stuff:
|
||||||
@ -575,7 +577,9 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
},
|
},
|
||||||
hir::ExprKind::Loop(ref body, ..) => {
|
hir::ExprKind::Loop(ref body, ..) => {
|
||||||
let block_ty = self.typeck_results().node_type(body.hir_id);
|
let block_ty = self.typeck_results().node_type(body.hir_id);
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
|
let temp_lifetime = self
|
||||||
|
.rvalue_scopes
|
||||||
|
.temporary_scope(self.region_scope_tree, body.hir_id.local_id);
|
||||||
let block = self.mirror_block(body);
|
let block = self.mirror_block(body);
|
||||||
let body = self.thir.exprs.push(Expr {
|
let body = self.thir.exprs.push(Expr {
|
||||||
ty: block_ty,
|
ty: block_ty,
|
||||||
@ -776,7 +780,8 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
|
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
|
||||||
) -> Expr<'tcx> {
|
) -> Expr<'tcx> {
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime =
|
||||||
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||||
let (def_id, substs, user_ty) = match overloaded_callee {
|
let (def_id, substs, user_ty) = match overloaded_callee {
|
||||||
Some((def_id, substs)) => (def_id, substs, None),
|
Some((def_id, substs)) => (def_id, substs, None),
|
||||||
None => {
|
None => {
|
||||||
@ -863,7 +868,9 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
// a constant reference (or constant raw pointer for `static mut`) in MIR
|
// a constant reference (or constant raw pointer for `static mut`) in MIR
|
||||||
Res::Def(DefKind::Static(_), id) => {
|
Res::Def(DefKind::Static(_), id) => {
|
||||||
let ty = self.tcx.static_ptr_ty(id);
|
let ty = self.tcx.static_ptr_ty(id);
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime = self
|
||||||
|
.rvalue_scopes
|
||||||
|
.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||||
let kind = if self.tcx.is_thread_local_static(id) {
|
let kind = if self.tcx.is_thread_local_static(id) {
|
||||||
ExprKind::ThreadLocalRef(id)
|
ExprKind::ThreadLocalRef(id)
|
||||||
} else {
|
} else {
|
||||||
@ -939,7 +946,8 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
|
|
||||||
// construct the complete expression `foo()` for the overloaded call,
|
// construct the complete expression `foo()` for the overloaded call,
|
||||||
// which will yield the &T type
|
// which will yield the &T type
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
let temp_lifetime =
|
||||||
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||||
let fun = self.method_callee(expr, span, overloaded_callee);
|
let fun = self.method_callee(expr, span, overloaded_callee);
|
||||||
let fun = self.thir.exprs.push(fun);
|
let fun = self.thir.exprs.push(fun);
|
||||||
let fun_ty = self.thir[fun].ty;
|
let fun_ty = self.thir[fun].ty;
|
||||||
@ -959,7 +967,9 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
closure_expr: &'tcx hir::Expr<'tcx>,
|
closure_expr: &'tcx hir::Expr<'tcx>,
|
||||||
place: HirPlace<'tcx>,
|
place: HirPlace<'tcx>,
|
||||||
) -> Expr<'tcx> {
|
) -> Expr<'tcx> {
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
let temp_lifetime = self
|
||||||
|
.rvalue_scopes
|
||||||
|
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
|
||||||
let var_ty = place.base_ty;
|
let var_ty = place.base_ty;
|
||||||
|
|
||||||
// The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
|
// The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
|
||||||
@ -1014,7 +1024,9 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
let upvar_capture = captured_place.info.capture_kind;
|
let upvar_capture = captured_place.info.capture_kind;
|
||||||
let captured_place_expr =
|
let captured_place_expr =
|
||||||
self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
|
self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
|
||||||
let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
let temp_lifetime = self
|
||||||
|
.rvalue_scopes
|
||||||
|
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
|
||||||
|
|
||||||
match upvar_capture {
|
match upvar_capture {
|
||||||
ty::UpvarCapture::ByValue => captured_place_expr,
|
ty::UpvarCapture::ByValue => captured_place_expr,
|
||||||
|
@ -16,7 +16,7 @@ use rustc_middle::middle::region;
|
|||||||
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
|
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
|
||||||
use rustc_middle::mir::ConstantKind;
|
use rustc_middle::mir::ConstantKind;
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
pub(crate) fn thir_body<'tcx>(
|
pub(crate) fn thir_body<'tcx>(
|
||||||
@ -51,6 +51,7 @@ struct Cx<'tcx> {
|
|||||||
|
|
||||||
pub(crate) region_scope_tree: &'tcx region::ScopeTree,
|
pub(crate) region_scope_tree: &'tcx region::ScopeTree,
|
||||||
pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||||
|
pub(crate) rvalue_scopes: &'tcx RvalueScopes,
|
||||||
|
|
||||||
/// When applying adjustments to the expression
|
/// When applying adjustments to the expression
|
||||||
/// with the given `HirId`, use the given `Span`,
|
/// with the given `HirId`, use the given `Span`,
|
||||||
@ -71,8 +72,9 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
tcx,
|
tcx,
|
||||||
thir: Thir::new(),
|
thir: Thir::new(),
|
||||||
param_env: tcx.param_env(def.did),
|
param_env: tcx.param_env(def.did),
|
||||||
region_scope_tree: tcx.region_scope_tree(def.did),
|
region_scope_tree: &typeck_results.region_scope_tree,
|
||||||
typeck_results,
|
typeck_results,
|
||||||
|
rvalue_scopes: &typeck_results.rvalue_scopes,
|
||||||
body_owner: def.did.to_def_id(),
|
body_owner: def.did.to_def_id(),
|
||||||
adjustment_span: None,
|
adjustment_span: None,
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ mod liveness;
|
|||||||
pub mod loops;
|
pub mod loops;
|
||||||
mod naked_functions;
|
mod naked_functions;
|
||||||
mod reachable;
|
mod reachable;
|
||||||
mod region;
|
|
||||||
pub mod stability;
|
pub mod stability;
|
||||||
mod upvars;
|
mod upvars;
|
||||||
mod weak_lang_items;
|
mod weak_lang_items;
|
||||||
@ -57,7 +56,6 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
liveness::provide(providers);
|
liveness::provide(providers);
|
||||||
intrinsicck::provide(providers);
|
intrinsicck::provide(providers);
|
||||||
reachable::provide(providers);
|
reachable::provide(providers);
|
||||||
region::provide(providers);
|
|
||||||
stability::provide(providers);
|
stability::provide(providers);
|
||||||
upvars::provide(providers);
|
upvars::provide(providers);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use crate::astconv::{
|
|||||||
};
|
};
|
||||||
use crate::check::callee::{self, DeferredCallResolution};
|
use crate::check::callee::{self, DeferredCallResolution};
|
||||||
use crate::check::method::{self, MethodCallee, SelfSource};
|
use crate::check::method::{self, MethodCallee, SelfSource};
|
||||||
|
use crate::check::{region, rvalue_scopes};
|
||||||
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
|
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
|
||||||
|
|
||||||
use rustc_data_structures::captures::Captures;
|
use rustc_data_structures::captures::Captures;
|
||||||
@ -620,6 +621,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
|
self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
|
||||||
|
let scope_tree = region::region_scope_tree(self.tcx, def_id);
|
||||||
|
let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, &scope_tree, def_id) };
|
||||||
|
let mut typeck_results = self.inh.typeck_results.borrow_mut();
|
||||||
|
typeck_results.region_scope_tree = scope_tree;
|
||||||
|
typeck_results.rvalue_scopes = rvalue_scopes;
|
||||||
|
}
|
||||||
|
|
||||||
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
|
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
|
||||||
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
||||||
for (body_id, interior, kind) in generators.drain(..) {
|
for (body_id, interior, kind) in generators.drain(..) {
|
||||||
|
@ -14,7 +14,7 @@ use rustc_hir::hir_id::HirIdSet;
|
|||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
|
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
|
||||||
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
|
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@ -23,8 +23,9 @@ mod drop_ranges;
|
|||||||
|
|
||||||
struct InteriorVisitor<'a, 'tcx> {
|
struct InteriorVisitor<'a, 'tcx> {
|
||||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||||
|
region_scope_tree: &'a region::ScopeTree,
|
||||||
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
|
types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
|
||||||
region_scope_tree: &'tcx region::ScopeTree,
|
rvalue_scopes: &'a RvalueScopes,
|
||||||
expr_count: usize,
|
expr_count: usize,
|
||||||
kind: hir::GeneratorKind,
|
kind: hir::GeneratorKind,
|
||||||
prev_unresolved_span: Option<Span>,
|
prev_unresolved_span: Option<Span>,
|
||||||
@ -179,10 +180,12 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||||||
kind: hir::GeneratorKind,
|
kind: hir::GeneratorKind,
|
||||||
) {
|
) {
|
||||||
let body = fcx.tcx.hir().body(body_id);
|
let body = fcx.tcx.hir().body(body_id);
|
||||||
|
let typeck_results = fcx.inh.typeck_results.borrow();
|
||||||
let mut visitor = InteriorVisitor {
|
let mut visitor = InteriorVisitor {
|
||||||
fcx,
|
fcx,
|
||||||
types: FxIndexSet::default(),
|
types: FxIndexSet::default(),
|
||||||
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
|
region_scope_tree: &typeck_results.region_scope_tree,
|
||||||
|
rvalue_scopes: &typeck_results.rvalue_scopes,
|
||||||
expr_count: 0,
|
expr_count: 0,
|
||||||
kind,
|
kind,
|
||||||
prev_unresolved_span: None,
|
prev_unresolved_span: None,
|
||||||
@ -192,7 +195,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||||||
intravisit::walk_body(&mut visitor, body);
|
intravisit::walk_body(&mut visitor, body);
|
||||||
|
|
||||||
// Check that we visited the same amount of expressions as the RegionResolutionVisitor
|
// Check that we visited the same amount of expressions as the RegionResolutionVisitor
|
||||||
let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
|
let region_expr_count = typeck_results.region_scope_tree.body_expr_count(body_id).unwrap();
|
||||||
assert_eq!(region_expr_count, visitor.expr_count);
|
assert_eq!(region_expr_count, visitor.expr_count);
|
||||||
|
|
||||||
// The types are already kept in insertion order.
|
// The types are already kept in insertion order.
|
||||||
@ -248,8 +251,9 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||||||
let witness =
|
let witness =
|
||||||
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
|
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
|
||||||
|
|
||||||
|
drop(typeck_results);
|
||||||
// Store the generator types and spans into the typeck results for this generator.
|
// Store the generator types and spans into the typeck results for this generator.
|
||||||
visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types =
|
fcx.inh.typeck_results.borrow_mut().generator_interior_types =
|
||||||
ty::Binder::bind_with_vars(type_causes, bound_vars);
|
ty::Binder::bind_with_vars(type_causes, bound_vars);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
@ -381,12 +385,14 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
|||||||
// temporary on the stack that is live for the current temporary scope and then return a
|
// temporary on the stack that is live for the current temporary scope and then return a
|
||||||
// reference to it. That value may be live across the entire temporary scope.
|
// reference to it. That value may be live across the entire temporary scope.
|
||||||
let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
|
let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
|
||||||
self.region_scope_tree.temporary_scope(expr.hir_id.local_id)
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
|
||||||
} else {
|
} else {
|
||||||
debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
|
debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
|
||||||
match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
|
match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
|
||||||
Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
|
Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
|
||||||
None => self.region_scope_tree.temporary_scope(expr.hir_id.local_id),
|
None => {
|
||||||
|
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,11 +41,12 @@ pub fn compute_drop_ranges<'a, 'tcx>(
|
|||||||
if fcx.sess().opts.debugging_opts.drop_tracking {
|
if fcx.sess().opts.debugging_opts.drop_tracking {
|
||||||
let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
|
let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
|
||||||
|
|
||||||
let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
|
let typeck_results = &fcx.typeck_results.borrow();
|
||||||
|
let num_exprs = typeck_results.region_scope_tree.body_expr_count(body.id()).unwrap_or(0);
|
||||||
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
|
let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
|
||||||
fcx.tcx.hir(),
|
fcx.tcx.hir(),
|
||||||
fcx.tcx,
|
fcx.tcx,
|
||||||
&fcx.typeck_results.borrow(),
|
typeck_results,
|
||||||
consumed_borrowed_places,
|
consumed_borrowed_places,
|
||||||
body,
|
body,
|
||||||
num_exprs,
|
num_exprs,
|
||||||
|
@ -85,7 +85,9 @@ pub mod method;
|
|||||||
mod op;
|
mod op;
|
||||||
mod pat;
|
mod pat;
|
||||||
mod place_op;
|
mod place_op;
|
||||||
|
mod region;
|
||||||
mod regionck;
|
mod regionck;
|
||||||
|
pub mod rvalue_scopes;
|
||||||
mod upvar;
|
mod upvar;
|
||||||
mod wfcheck;
|
mod wfcheck;
|
||||||
pub mod writeback;
|
pub mod writeback;
|
||||||
@ -473,6 +475,9 @@ fn typeck_with_fallback<'tcx>(
|
|||||||
// because they don't constrain other type variables.
|
// because they don't constrain other type variables.
|
||||||
fcx.closure_analyze(body);
|
fcx.closure_analyze(body);
|
||||||
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
|
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
|
||||||
|
// Before the generator analysis, temporary scopes shall be marked to provide more
|
||||||
|
// precise information on types to be captured.
|
||||||
|
fcx.resolve_rvalue_scopes(def_id.to_def_id());
|
||||||
fcx.resolve_generator_interiors(def_id.to_def_id());
|
fcx.resolve_generator_interiors(def_id.to_def_id());
|
||||||
|
|
||||||
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
|
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
|
||||||
|
@ -14,7 +14,6 @@ use rustc_hir::intravisit::{self, Visitor};
|
|||||||
use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
|
use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::middle::region::*;
|
use rustc_middle::middle::region::*;
|
||||||
use rustc_middle::ty::query::Providers;
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::source_map;
|
use rustc_span::source_map;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
@ -527,7 +526,13 @@ fn resolve_local<'tcx>(
|
|||||||
|
|
||||||
if let Some(pat) = pat {
|
if let Some(pat) = pat {
|
||||||
if is_binding_pat(pat) {
|
if is_binding_pat(pat) {
|
||||||
record_rvalue_scope(visitor, &expr, blk_scope);
|
visitor.scope_tree.record_rvalue_candidate(
|
||||||
|
expr.hir_id,
|
||||||
|
RvalueCandidateType::Pattern {
|
||||||
|
target: expr.hir_id.local_id,
|
||||||
|
lifetime: blk_scope,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,9 +630,15 @@ fn resolve_local<'tcx>(
|
|||||||
blk_id: Option<Scope>,
|
blk_id: Option<Scope>,
|
||||||
) {
|
) {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
hir::ExprKind::AddrOf(_, _, ref subexpr) => {
|
hir::ExprKind::AddrOf(_, _, subexpr) => {
|
||||||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
||||||
record_rvalue_scope(visitor, &subexpr, blk_id);
|
visitor.scope_tree.record_rvalue_candidate(
|
||||||
|
subexpr.hir_id,
|
||||||
|
RvalueCandidateType::Borrow {
|
||||||
|
target: subexpr.hir_id.local_id,
|
||||||
|
lifetime: blk_id,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
hir::ExprKind::Struct(_, fields, _) => {
|
hir::ExprKind::Struct(_, fields, _) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
@ -647,52 +658,15 @@ fn resolve_local<'tcx>(
|
|||||||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
|
||||||
}
|
// FIXME(@dingxiangfei2009): choose call arguments here
|
||||||
}
|
// for candidacy for extended parameter rule application
|
||||||
|
|
||||||
/// 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<'tcx>(
|
|
||||||
visitor: &mut RegionResolutionVisitor<'tcx>,
|
|
||||||
expr: &hir::Expr<'_>,
|
|
||||||
blk_scope: Option<Scope>,
|
|
||||||
) {
|
|
||||||
let mut expr = expr;
|
|
||||||
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.
|
|
||||||
visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope);
|
|
||||||
|
|
||||||
match expr.kind {
|
|
||||||
hir::ExprKind::AddrOf(_, _, ref subexpr)
|
|
||||||
| hir::ExprKind::Unary(hir::UnOp::Deref, ref subexpr)
|
|
||||||
| hir::ExprKind::Field(ref subexpr, _)
|
|
||||||
| hir::ExprKind::Index(ref subexpr, _) => {
|
|
||||||
expr = &subexpr;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hir::ExprKind::Index(..) => {
|
||||||
|
// FIXME(@dingxiangfei2009): select the indices
|
||||||
|
// as candidate for rvalue scope rules
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -821,14 +795,16 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
|
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
|
||||||
|
/// in the case of closures, this will be redirected to the enclosing function.
|
||||||
|
pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> ScopeTree {
|
||||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
|
||||||
if typeck_root_def_id != def_id {
|
if typeck_root_def_id != def_id {
|
||||||
return tcx.region_scope_tree(typeck_root_def_id);
|
return region_scope_tree(tcx, typeck_root_def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||||
let scope_tree = if let Some(body_id) = tcx.hir().maybe_body_owned_by(id) {
|
if let Some(body_id) = tcx.hir().maybe_body_owned_by(id) {
|
||||||
let mut visitor = RegionResolutionVisitor {
|
let mut visitor = RegionResolutionVisitor {
|
||||||
tcx,
|
tcx,
|
||||||
scope_tree: ScopeTree::default(),
|
scope_tree: ScopeTree::default(),
|
||||||
@ -845,11 +821,5 @@ fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
|
|||||||
visitor.scope_tree
|
visitor.scope_tree
|
||||||
} else {
|
} else {
|
||||||
ScopeTree::default()
|
ScopeTree::default()
|
||||||
};
|
}
|
||||||
|
|
||||||
tcx.arena.alloc(scope_tree)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
|
||||||
*providers = Providers { region_scope_tree, ..*providers };
|
|
||||||
}
|
}
|
@ -75,7 +75,6 @@
|
|||||||
use crate::check::dropck;
|
use crate::check::dropck;
|
||||||
use crate::check::FnCtxt;
|
use crate::check::FnCtxt;
|
||||||
use crate::mem_categorization as mc;
|
use crate::mem_categorization as mc;
|
||||||
use crate::middle::region;
|
|
||||||
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
||||||
use rustc_data_structures::stable_set::FxHashSet;
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
@ -219,8 +218,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
pub struct RegionCtxt<'a, 'tcx> {
|
pub struct RegionCtxt<'a, 'tcx> {
|
||||||
pub fcx: &'a FnCtxt<'a, 'tcx>,
|
pub fcx: &'a FnCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
pub region_scope_tree: &'tcx region::ScopeTree,
|
|
||||||
|
|
||||||
outlives_environment: OutlivesEnvironment<'tcx>,
|
outlives_environment: OutlivesEnvironment<'tcx>,
|
||||||
|
|
||||||
// id of innermost fn body id
|
// id of innermost fn body id
|
||||||
@ -247,11 +244,9 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
|||||||
Subject(subject): Subject,
|
Subject(subject): Subject,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> RegionCtxt<'a, 'tcx> {
|
) -> RegionCtxt<'a, 'tcx> {
|
||||||
let region_scope_tree = fcx.tcx.region_scope_tree(subject);
|
|
||||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||||
RegionCtxt {
|
RegionCtxt {
|
||||||
fcx,
|
fcx,
|
||||||
region_scope_tree,
|
|
||||||
body_id: initial_body_id,
|
body_id: initial_body_id,
|
||||||
body_owner: subject,
|
body_owner: subject,
|
||||||
subject_def_id: subject,
|
subject_def_id: subject,
|
||||||
|
83
compiler/rustc_typeck/src/check/rvalue_scopes.rs
Normal file
83
compiler/rustc_typeck/src/check/rvalue_scopes.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
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 hir_map = tcx.hir();
|
||||||
|
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 Some(Node::Expr(expr)) = hir_map.find(hir_id) else {
|
||||||
|
bug!("hir node does not exist")
|
||||||
|
};
|
||||||
|
record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
|
||||||
|
}
|
||||||
|
rvalue_scopes
|
||||||
|
}
|
@ -71,6 +71,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
wbcx.visit_user_provided_sigs();
|
wbcx.visit_user_provided_sigs();
|
||||||
wbcx.visit_generator_interior_types();
|
wbcx.visit_generator_interior_types();
|
||||||
|
|
||||||
|
wbcx.typeck_results.region_scope_tree =
|
||||||
|
mem::take(&mut self.typeck_results.borrow_mut().region_scope_tree);
|
||||||
|
wbcx.typeck_results.rvalue_scopes =
|
||||||
|
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
|
||||||
|
|
||||||
let used_trait_imports =
|
let used_trait_imports =
|
||||||
mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
|
mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
|
||||||
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
||||||
|
@ -3,7 +3,9 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
|||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet;
|
||||||
use clippy_utils::ty::has_iter_method;
|
use clippy_utils::ty::has_iter_method;
|
||||||
use clippy_utils::visitors::is_local_used;
|
use clippy_utils::visitors::is_local_used;
|
||||||
use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
|
use clippy_utils::{
|
||||||
|
contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq,
|
||||||
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
@ -27,12 +29,7 @@ pub(super) fn check<'tcx>(
|
|||||||
body: &'tcx Expr<'_>,
|
body: &'tcx Expr<'_>,
|
||||||
expr: &'tcx Expr<'_>,
|
expr: &'tcx Expr<'_>,
|
||||||
) {
|
) {
|
||||||
if let Some(higher::Range {
|
if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::Range::hir(arg) {
|
||||||
start: Some(start),
|
|
||||||
ref end,
|
|
||||||
limits,
|
|
||||||
}) = higher::Range::hir(arg)
|
|
||||||
{
|
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
|
if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
|
||||||
let mut visitor = VarVisitor {
|
let mut visitor = VarVisitor {
|
||||||
@ -58,7 +55,11 @@ pub(super) fn check<'tcx>(
|
|||||||
// ensure that the indexed variable was declared before the loop, see #601
|
// ensure that the indexed variable was declared before the loop, see #601
|
||||||
if let Some(indexed_extent) = indexed_extent {
|
if let Some(indexed_extent) = indexed_extent {
|
||||||
let parent_def_id = cx.tcx.hir().get_parent_item(expr.hir_id);
|
let parent_def_id = cx.tcx.hir().get_parent_item(expr.hir_id);
|
||||||
let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
|
let parent_body_id = cx
|
||||||
|
.tcx
|
||||||
|
.hir()
|
||||||
|
.body_owned_by(cx.tcx.hir().local_def_id_to_hir_id(parent_def_id));
|
||||||
|
let region_scope_tree = &cx.tcx.typeck_body(parent_body_id).region_scope_tree;
|
||||||
let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
|
let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
|
||||||
if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
|
if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
|
||||||
return;
|
return;
|
||||||
@ -107,17 +108,22 @@ pub(super) fn check<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
|
if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty)
|
||||||
|
{
|
||||||
String::new()
|
String::new()
|
||||||
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
|
} else if visitor.indexed_mut.contains(&indexed)
|
||||||
|
&& contains_name(indexed, take_expr)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
match limits {
|
match limits {
|
||||||
ast::RangeLimits::Closed => {
|
ast::RangeLimits::Closed => {
|
||||||
let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
|
let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
|
||||||
format!(".take({})", take_expr + sugg::ONE)
|
format!(".take({})", take_expr + sugg::ONE)
|
||||||
},
|
}
|
||||||
ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, take_expr.span, "..")),
|
ast::RangeLimits::HalfOpen => {
|
||||||
|
format!(".take({})", snippet(cx, take_expr.span, ".."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -143,7 +149,10 @@ pub(super) fn check<'tcx>(
|
|||||||
cx,
|
cx,
|
||||||
NEEDLESS_RANGE_LOOP,
|
NEEDLESS_RANGE_LOOP,
|
||||||
arg.span,
|
arg.span,
|
||||||
&format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
|
&format!(
|
||||||
|
"the loop variable `{}` is used to index `{}`",
|
||||||
|
ident.name, indexed
|
||||||
|
),
|
||||||
|diag| {
|
|diag| {
|
||||||
multispan_sugg(
|
multispan_sugg(
|
||||||
diag,
|
diag,
|
||||||
@ -152,7 +161,10 @@ pub(super) fn check<'tcx>(
|
|||||||
(pat.span, format!("({}, <item>)", ident.name)),
|
(pat.span, format!("({}, <item>)", ident.name)),
|
||||||
(
|
(
|
||||||
arg.span,
|
arg.span,
|
||||||
format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
|
format!(
|
||||||
|
"{}.{}().enumerate(){}{}",
|
||||||
|
indexed, method, method_1, method_2
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -169,7 +181,10 @@ pub(super) fn check<'tcx>(
|
|||||||
cx,
|
cx,
|
||||||
NEEDLESS_RANGE_LOOP,
|
NEEDLESS_RANGE_LOOP,
|
||||||
arg.span,
|
arg.span,
|
||||||
&format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed),
|
&format!(
|
||||||
|
"the loop variable `{}` is only used to index `{}`",
|
||||||
|
ident.name, indexed
|
||||||
|
),
|
||||||
|diag| {
|
|diag| {
|
||||||
multispan_sugg(
|
multispan_sugg(
|
||||||
diag,
|
diag,
|
||||||
@ -246,7 +261,12 @@ struct VarVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
||||||
fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
|
fn check(
|
||||||
|
&mut self,
|
||||||
|
idx: &'tcx Expr<'_>,
|
||||||
|
seqexpr: &'tcx Expr<'_>,
|
||||||
|
expr: &'tcx Expr<'_>,
|
||||||
|
) -> bool {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
// the indexed container is referenced by a name
|
// the indexed container is referenced by a name
|
||||||
if let ExprKind::Path(ref seqpath) = seqexpr.kind;
|
if let ExprKind::Path(ref seqpath) = seqexpr.kind;
|
||||||
@ -262,7 +282,16 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
|||||||
match res {
|
match res {
|
||||||
Res::Local(hir_id) => {
|
Res::Local(hir_id) => {
|
||||||
let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
|
let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
|
||||||
let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id).unwrap();
|
let parent_body_id = self.cx
|
||||||
|
.tcx
|
||||||
|
.hir()
|
||||||
|
.body_owned_by(self.cx.tcx.hir().local_def_id_to_hir_id(parent_def_id));
|
||||||
|
let extent = self.cx
|
||||||
|
.tcx
|
||||||
|
.typeck_body(parent_body_id)
|
||||||
|
.region_scope_tree
|
||||||
|
.var_scope(hir_id.local_id)
|
||||||
|
.unwrap();
|
||||||
if index_used_directly {
|
if index_used_directly {
|
||||||
self.indexed_directly.insert(
|
self.indexed_directly.insert(
|
||||||
seqvar.segments[0].ident.name,
|
seqvar.segments[0].ident.name,
|
||||||
@ -331,13 +360,13 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||||||
self.visit_expr(lhs);
|
self.visit_expr(lhs);
|
||||||
self.prefer_mutable = false;
|
self.prefer_mutable = false;
|
||||||
self.visit_expr(rhs);
|
self.visit_expr(rhs);
|
||||||
},
|
}
|
||||||
ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
|
ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
|
||||||
if mutbl == Mutability::Mut {
|
if mutbl == Mutability::Mut {
|
||||||
self.prefer_mutable = true;
|
self.prefer_mutable = true;
|
||||||
}
|
}
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
},
|
}
|
||||||
ExprKind::Call(f, args) => {
|
ExprKind::Call(f, args) => {
|
||||||
self.visit_expr(f);
|
self.visit_expr(f);
|
||||||
for expr in args {
|
for expr in args {
|
||||||
@ -350,10 +379,11 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ExprKind::MethodCall(_, args, _) => {
|
ExprKind::MethodCall(_, args, _) => {
|
||||||
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||||
for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
|
for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args)
|
||||||
|
{
|
||||||
self.prefer_mutable = false;
|
self.prefer_mutable = false;
|
||||||
if let ty::Ref(_, _, mutbl) = *ty.kind() {
|
if let ty::Ref(_, _, mutbl) = *ty.kind() {
|
||||||
if mutbl == Mutability::Mut {
|
if mutbl == Mutability::Mut {
|
||||||
@ -362,11 +392,11 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
self.visit_expr(expr);
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ExprKind::Closure(_, _, body_id, ..) => {
|
ExprKind::Closure(_, _, body_id, ..) => {
|
||||||
let body = self.cx.tcx.hir().body(body_id);
|
let body = self.cx.tcx.hir().body(body_id);
|
||||||
self.visit_expr(&body.value);
|
self.visit_expr(&body.value);
|
||||||
},
|
}
|
||||||
_ => walk_expr(self, expr),
|
_ => walk_expr(self, expr),
|
||||||
}
|
}
|
||||||
self.prefer_mutable = old;
|
self.prefer_mutable = old;
|
||||||
|
@ -5,7 +5,9 @@ use rustc_data_structures::fx::FxHashMap;
|
|||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::hir_id::ItemLocalId;
|
use rustc_hir::hir_id::ItemLocalId;
|
||||||
use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
|
use rustc_hir::{
|
||||||
|
Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp,
|
||||||
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
@ -139,27 +141,31 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
|
|||||||
|
|
||||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
|
fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
|
||||||
let hir = cx.tcx.hir();
|
let hir = cx.tcx.hir();
|
||||||
if !matches!(
|
if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
|
||||||
hir.body_owner_kind(hir.body_owner_def_id(body.id())),
|
{
|
||||||
BodyOwnerKind::Closure
|
|
||||||
) {
|
|
||||||
self.bindings.push(FxHashMap::default());
|
self.bindings.push(FxHashMap::default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
|
fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
|
||||||
let hir = cx.tcx.hir();
|
let hir = cx.tcx.hir();
|
||||||
if !matches!(
|
if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
|
||||||
hir.body_owner_kind(hir.body_owner_def_id(body.id())),
|
{
|
||||||
BodyOwnerKind::Closure
|
|
||||||
) {
|
|
||||||
self.bindings.pop();
|
self.bindings.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
|
fn is_shadow(
|
||||||
let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
|
cx: &LateContext<'_>,
|
||||||
|
owner: LocalDefId,
|
||||||
|
first: ItemLocalId,
|
||||||
|
second: ItemLocalId,
|
||||||
|
) -> bool {
|
||||||
|
let scope_tree = &cx
|
||||||
|
.tcx
|
||||||
|
.typeck_body(cx.tcx.hir().body_owned_by(cx.tcx.hir().local_def_id_to_hir_id(owner)))
|
||||||
|
.region_scope_tree;
|
||||||
let first_scope = scope_tree.var_scope(first).unwrap();
|
let first_scope = scope_tree.var_scope(first).unwrap();
|
||||||
let second_scope = scope_tree.var_scope(second).unwrap();
|
let second_scope = scope_tree.var_scope(second).unwrap();
|
||||||
scope_tree.is_subscope_of(second_scope, first_scope)
|
scope_tree.is_subscope_of(second_scope, first_scope)
|
||||||
@ -174,15 +180,16 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
|
|||||||
snippet(cx, expr.span, "..")
|
snippet(cx, expr.span, "..")
|
||||||
);
|
);
|
||||||
(SHADOW_SAME, msg)
|
(SHADOW_SAME, msg)
|
||||||
},
|
}
|
||||||
Some(expr) if is_local_used(cx, expr, shadowed) => {
|
Some(expr) if is_local_used(cx, expr, shadowed) => {
|
||||||
let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
|
let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
|
||||||
(SHADOW_REUSE, msg)
|
(SHADOW_REUSE, msg)
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
|
let msg =
|
||||||
|
format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
|
||||||
(SHADOW_UNRELATED, msg)
|
(SHADOW_UNRELATED, msg)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
span_lint_and_note(
|
span_lint_and_note(
|
||||||
cx,
|
cx,
|
||||||
@ -211,14 +218,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
|
|||||||
expr = match expr.kind {
|
expr = match expr.kind {
|
||||||
ExprKind::Box(e)
|
ExprKind::Box(e)
|
||||||
| ExprKind::AddrOf(_, _, e)
|
| ExprKind::AddrOf(_, _, e)
|
||||||
| ExprKind::Block(
|
| ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _)
|
||||||
&Block {
|
|
||||||
stmts: [],
|
|
||||||
expr: Some(e),
|
|
||||||
..
|
|
||||||
},
|
|
||||||
_,
|
|
||||||
)
|
|
||||||
| ExprKind::Unary(UnOp::Deref, e) => e,
|
| ExprKind::Unary(UnOp::Deref, e) => e,
|
||||||
ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
|
ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
|
||||||
_ => break false,
|
_ => break false,
|
||||||
|
Loading…
Reference in New Issue
Block a user