Auto merge of #54145 - nrc:save-path-segments, r=petrochenkov

Keep resolved defs in path prefixes and emit them in save-analysis

Closes https://github.com/nrc/rls-analysis/issues/109

r? @eddyb or @petrochenkov
This commit is contained in:
bors 2018-10-26 00:04:29 +00:00
commit 7b0735a832
40 changed files with 728 additions and 836 deletions

View file

@ -298,6 +298,9 @@ pub trait Visitor<'v> : Sized {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
fn visit_use(&mut self, path: &'v Path, id: NodeId, hir_id: HirId) {
walk_use(self, path, id, hir_id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
}
@ -471,8 +474,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
}
}
ItemKind::Use(ref path, _) => {
visitor.visit_id(item.id);
visitor.visit_path(path, item.hir_id);
visitor.visit_use(path, item.id, item.hir_id);
}
ItemKind::Static(ref typ, _, body) |
ItemKind::Const(ref typ, body) => {
@ -554,6 +556,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
walk_list!(visitor, visit_attribute, &item.attrs);
}
pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V,
path: &'v Path,
item_id: NodeId,
hir_id: HirId) {
visitor.visit_id(item_id);
visitor.visit_path(path, hir_id);
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
generics: &'v Generics,
@ -652,6 +662,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
path_span: Span,
segment: &'v PathSegment) {
visitor.visit_ident(segment.ident);
if let Some(id) = segment.id {
visitor.visit_id(id);
}
if let Some(ref args) = segment.args {
visitor.visit_generic_args(path_span, args);
}

View file

@ -143,8 +143,12 @@ pub struct LoweringContext<'a> {
}
pub trait Resolver {
/// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
/// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
fn resolve_hir_path(
&mut self,
path: &ast::Path,
is_value: bool,
) -> hir::Path;
/// Obtain the resolution for a node id
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
@ -163,7 +167,6 @@ pub trait Resolver {
span: Span,
crate_root: Option<&str>,
components: &[&str],
params: Option<P<hir::GenericArgs>>,
is_value: bool,
) -> hir::Path;
}
@ -1064,6 +1067,9 @@ impl<'a> LoweringContext<'a> {
}
fn lower_attr(&mut self, attr: &Attribute) -> Attribute {
// Note that we explicitly do not walk the path. Since we don't really
// lower attributes (we use the AST version) there is nowhere to keep
// the HirIds. We don't actually need HIR version of attributes anyway.
Attribute {
id: attr.id,
style: attr.style,
@ -1677,6 +1683,7 @@ impl<'a> LoweringContext<'a> {
num_lifetimes,
parenthesized_generic_args,
itctx.reborrow(),
None,
)
})
.collect(),
@ -1720,6 +1727,7 @@ impl<'a> LoweringContext<'a> {
0,
ParenthesizedGenericArgs::Warn,
itctx.reborrow(),
None,
));
let qpath = hir::QPath::TypeRelative(ty, segment);
@ -1748,6 +1756,7 @@ impl<'a> LoweringContext<'a> {
p: &Path,
ident: Option<Ident>,
param_mode: ParamMode,
explicit_owner: Option<NodeId>,
) -> hir::Path {
hir::Path {
def,
@ -1761,6 +1770,7 @@ impl<'a> LoweringContext<'a> {
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
explicit_owner,
)
})
.chain(ident.map(|ident| hir::PathSegment::from_ident(ident)))
@ -1771,7 +1781,7 @@ impl<'a> LoweringContext<'a> {
fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
let def = self.expect_full_def(id);
self.lower_path_extra(def, p, None, param_mode)
self.lower_path_extra(def, p, None, param_mode, None)
}
fn lower_path_segment(
@ -1782,6 +1792,7 @@ impl<'a> LoweringContext<'a> {
expected_lifetimes: usize,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: ImplTraitContext<'_>,
explicit_owner: Option<NodeId>,
) -> hir::PathSegment {
let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
let msg = "parenthesized parameters may only be used with a trait";
@ -1852,8 +1863,17 @@ impl<'a> LoweringContext<'a> {
}
}
let def = self.expect_full_def(segment.id);
let id = if let Some(owner) = explicit_owner {
self.lower_node_id_with_owner(segment.id, owner)
} else {
self.lower_node_id(segment.id)
};
hir::PathSegment::new(
segment.ident,
Some(id.node_id),
Some(def),
generic_args,
infer_types,
)
@ -2936,6 +2956,12 @@ impl<'a> LoweringContext<'a> {
attrs: &hir::HirVec<Attribute>,
) -> hir::ItemKind {
let path = &tree.prefix;
let segments = prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect();
match tree.kind {
UseTreeKind::Simple(rename, id1, id2) => {
@ -2943,12 +2969,7 @@ impl<'a> LoweringContext<'a> {
// First apply the prefix to the path
let mut path = Path {
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
segments,
span: path.span,
};
@ -2968,9 +2989,18 @@ impl<'a> LoweringContext<'a> {
// for later
let ret_def = defs.next().unwrap_or(Def::Err);
// Here, we are looping over namespaces, if they exist for the definition
// being imported. We only handle type and value namespaces because we
// won't be dealing with macros in the rest of the compiler.
// Essentially a single `use` which imports two names is desugared into
// two imports.
for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
let vis = vis.clone();
let name = name.clone();
let mut path = path.clone();
for seg in &mut path.segments {
seg.id = self.sess.next_node_id();
}
let span = path.span;
self.resolver.definitions().create_def_with_parent(
parent_def_index,
@ -2983,7 +3013,8 @@ impl<'a> LoweringContext<'a> {
self.with_hir_id_owner(new_node_id, |this| {
let new_id = this.lower_node_id(new_node_id);
let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
let path =
this.lower_path_extra(def, &path, None, ParamMode::Explicit, None);
let item = hir::ItemKind::Use(P(path), hir::UseKind::Single);
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
@ -2993,7 +3024,6 @@ impl<'a> LoweringContext<'a> {
let id = this.next_id();
hir::VisibilityKind::Restricted {
path: path.clone(),
// We are allocating a new NodeId here
id: id.node_id,
hir_id: id.hir_id,
}
@ -3016,19 +3046,15 @@ impl<'a> LoweringContext<'a> {
});
}
let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
let path =
P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit, None));
hir::ItemKind::Use(path, hir::UseKind::Single)
}
UseTreeKind::Glob => {
let path = P(self.lower_path(
id,
&Path {
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
segments,
span: path.span,
},
ParamMode::Explicit,
@ -3036,19 +3062,17 @@ impl<'a> LoweringContext<'a> {
hir::ItemKind::Use(path, hir::UseKind::Glob)
}
UseTreeKind::Nested(ref trees) => {
// Nested imports are desugared into simple imports.
let prefix = Path {
segments: prefix
.segments
.iter()
.chain(path.segments.iter())
.cloned()
.collect(),
segments,
span: prefix.span.to(path.span),
};
// Add all the nested PathListItems in the HIR
// Add all the nested PathListItems to the HIR.
for &(ref use_tree, id) in trees {
self.allocate_hir_id_counter(id, &use_tree);
let LoweredNodeId {
node_id: new_id,
hir_id: new_hir_id,
@ -3056,10 +3080,26 @@ impl<'a> LoweringContext<'a> {
let mut vis = vis.clone();
let mut name = name.clone();
let item =
self.lower_use_tree(use_tree, &prefix, new_id, &mut vis, &mut name, &attrs);
let mut prefix = prefix.clone();
// Give the segments new ids since they are being cloned.
for seg in &mut prefix.segments {
seg.id = self.sess.next_node_id();
}
// Each `use` import is an item and thus are owners of the
// names in the path. Up to this point the nested import is
// the current owner, since we want each desugared import to
// own its own names, we have to adjust the owner before
// lowering the rest of the import.
self.with_hir_id_owner(new_id, |this| {
let item = this.lower_use_tree(use_tree,
&prefix,
new_id,
&mut vis,
&mut name,
attrs);
let vis_kind = match vis.node {
hir::VisibilityKind::Public => hir::VisibilityKind::Public,
hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar),
@ -3068,7 +3108,6 @@ impl<'a> LoweringContext<'a> {
let id = this.next_id();
hir::VisibilityKind::Restricted {
path: path.clone(),
// We are allocating a new NodeId here
id: id.node_id,
hir_id: id.hir_id,
}
@ -3081,7 +3120,7 @@ impl<'a> LoweringContext<'a> {
hir::Item {
id: new_id,
hir_id: new_hir_id,
name: name,
name,
attrs: attrs.clone(),
node: item,
vis,
@ -3645,6 +3684,7 @@ impl<'a> LoweringContext<'a> {
0,
ParenthesizedGenericArgs::Err,
ImplTraitContext::disallowed(),
None,
);
let args = args.iter().map(|x| self.lower_expr(x)).collect();
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
@ -4498,8 +4538,15 @@ impl<'a> LoweringContext<'a> {
} else {
self.lower_node_id(id)
};
let def = self.expect_full_def(id);
hir::VisibilityKind::Restricted {
path: P(self.lower_path(id, path, ParamMode::Explicit)),
path: P(self.lower_path_extra(
def,
path,
None,
ParamMode::Explicit,
explicit_owner,
)),
id: lowered_id.node_id,
hir_id: lowered_id.hir_id,
}
@ -4806,8 +4853,17 @@ impl<'a> LoweringContext<'a> {
params: Option<P<hir::GenericArgs>>,
is_value: bool
) -> hir::Path {
self.resolver
.resolve_str_path(span, self.crate_root, components, params, is_value)
let mut path = self.resolver
.resolve_str_path(span, self.crate_root, components, is_value);
path.segments.last_mut().unwrap().args = params;
for seg in path.segments.iter_mut() {
if let Some(id) = seg.id {
seg.id = Some(self.lower_node_id(id).node_id);
}
}
path
}
fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty {

View file

@ -210,17 +210,22 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
None => format!("{:?}", node)
};
if hir_id == ::hir::DUMMY_HIR_ID {
debug!("Maybe you forgot to lower the node id {:?}?", id);
}
let forgot_str = if hir_id == ::hir::DUMMY_HIR_ID {
format!("\nMaybe you forgot to lower the node id {:?}?", id)
} else {
String::new()
};
bug!("inconsistent DepNode for `{}`: \
current_dep_node_owner={}, hir_id.owner={}",
current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}) {}",
node_str,
self.definitions
.def_path(self.current_dep_node_owner)
.to_string_no_crate(),
self.definitions.def_path(hir_id.owner).to_string_no_crate())
self.current_dep_node_owner,
self.definitions.def_path(hir_id.owner).to_string_no_crate(),
hir_id.owner,
forgot_str)
}
}
@ -392,6 +397,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment) {
if let Some(id) = path_segment.id {
self.insert(id, Node::PathSegment(path_segment));
}
intravisit::walk_path_segment(self, path_span, path_segment);
}
fn visit_ty(&mut self, ty: &'hir Ty) {
self.insert(ty.id, Node::Ty(ty));

View file

@ -88,7 +88,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
walk(self);
if owner_def_index == CRATE_DEF_INDEX {
return
return;
}
// There's always at least one entry for the owning item itself
@ -129,13 +129,16 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
local_id,
self.hir_map.node_to_string(node_id)));
}
self.errors.push(format!(
"ItemLocalIds not assigned densely in {}. \
Max ItemLocalId = {}, missing IDs = {:?}",
Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
max,
missing_items));
missing_items,
self.hir_ids_seen
.values()
.map(|n| format!("({:?} {})", n, self.hir_map.node_to_string(*n)))
.collect::<Vec<_>>()));
}
}
}
@ -155,6 +158,7 @@ impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}",
node_id,
self.hir_map.node_to_string(node_id)));
return;
}
if owner != stable_id.owner {

View file

@ -204,7 +204,7 @@ impl<'hir> Map<'hir> {
if let Some(entry) = self.map[id.as_usize()] {
self.dep_graph.read_index(entry.dep_node);
} else {
bug!("called `HirMap::read()` with invalid `NodeId`")
bug!("called `HirMap::read()` with invalid `NodeId`: {:?}", id)
}
}
@ -344,6 +344,7 @@ impl<'hir> Map<'hir> {
Node::AnonConst(_) |
Node::Expr(_) |
Node::Stmt(_) |
Node::PathSegment(_) |
Node::Ty(_) |
Node::TraitRef(_) |
Node::Pat(_) |
@ -884,6 +885,7 @@ impl<'hir> Map<'hir> {
Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
Some(Node::Expr(expr)) => expr.span,
Some(Node::Stmt(stmt)) => stmt.span,
Some(Node::PathSegment(seg)) => seg.ident.span,
Some(Node::Ty(ty)) => ty.span,
Some(Node::TraitRef(tr)) => tr.path.span,
Some(Node::Binding(pat)) => pat.span,
@ -1098,6 +1100,7 @@ impl<'a> print::State<'a> {
Node::AnonConst(a) => self.print_anon_const(&a),
Node::Expr(a) => self.print_expr(&a),
Node::Stmt(a) => self.print_stmt(&a),
Node::PathSegment(a) => self.print_path_segment(&a),
Node::Ty(a) => self.print_type(&a),
Node::TraitRef(a) => self.print_trait_ref(&a),
Node::Binding(a) |
@ -1215,6 +1218,9 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String {
Some(Node::Stmt(_)) => {
format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
}
Some(Node::PathSegment(_)) => {
format!("path segment {}{}", map.node_to_pretty_string(id), id_str)
}
Some(Node::Ty(_)) => {
format!("type {}{}", map.node_to_pretty_string(id), id_str)
}

View file

@ -347,6 +347,13 @@ impl fmt::Display for Path {
pub struct PathSegment {
/// The identifier portion of this path segment.
pub ident: Ident,
// `id` and `def` are optional. We currently only use these in save-analysis,
// any path segments without these will not have save-analysis info and
// therefore will not have 'jump to def' in IDEs, but otherwise will not be
// affected. (In general, we don't bother to get the defs for synthesized
// segments, only for segments which have come from the AST).
pub id: Option<NodeId>,
pub def: Option<Def>,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
@ -367,14 +374,24 @@ impl PathSegment {
pub fn from_ident(ident: Ident) -> PathSegment {
PathSegment {
ident,
id: None,
def: None,
infer_types: true,
args: None,
}
}
pub fn new(ident: Ident, args: GenericArgs, infer_types: bool) -> Self {
pub fn new(
ident: Ident,
id: Option<NodeId>,
def: Option<Def>,
args: GenericArgs,
infer_types: bool,
) -> Self {
PathSegment {
ident,
id,
def,
infer_types,
args: if args.is_empty() {
None
@ -2511,6 +2528,7 @@ pub enum Node<'hir> {
AnonConst(&'hir AnonConst),
Expr(&'hir Expr),
Stmt(&'hir Stmt),
PathSegment(&'hir PathSegment),
Ty(&'hir Ty),
TraitRef(&'hir TraitRef),
Binding(&'hir Pat),

View file

@ -1633,6 +1633,17 @@ impl<'a> State<'a> {
Ok(())
}
pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> {
if segment.ident.name != keywords::CrateRoot.name() &&
segment.ident.name != keywords::DollarCrate.name() {
self.print_ident(segment.ident)?;
segment.with_generic_args(|generic_args| {
self.print_generic_args(generic_args, segment.infer_types, false)
})?;
}
Ok(())
}
pub fn print_qpath(&mut self,
qpath: &hir::QPath,
colons_before_params: bool)

View file

@ -174,6 +174,8 @@ impl_stable_hash_for!(struct hir::Path {
impl_stable_hash_for!(struct hir::PathSegment {
ident -> (ident.name),
id,
def,
infer_types,
args
});

View file

@ -16,7 +16,7 @@
use macros::{InvocationData, ParentScope, LegacyScope};
use resolve_imports::ImportDirective;
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use Namespace::{self, TypeNS, ValueNS, MacroNS};
use {resolve_error, resolve_struct_error, ResolutionError};
@ -122,7 +122,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
use_tree: &ast::UseTree,
id: NodeId,
vis: ty::Visibility,
parent_prefix: &[Ident],
parent_prefix: &[Segment],
mut uniform_paths_canary_emitted: bool,
nested: bool,
item: &Item,
@ -139,10 +139,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
self.session.features_untracked().uniform_paths;
let prefix_iter = || parent_prefix.iter().cloned()
.chain(use_tree.prefix.segments.iter().map(|seg| seg.ident));
.chain(use_tree.prefix.segments.iter().map(|seg| seg.into()));
let prefix_start = prefix_iter().next();
let starts_with_non_keyword = prefix_start.map_or(false, |ident| {
!ident.is_path_segment_keyword()
let starts_with_non_keyword = prefix_start.map_or(false, |seg| {
!seg.ident.is_path_segment_keyword()
});
// Imports are resolved as global by default, prepend `CrateRoot`,
@ -156,7 +156,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
};
let root = if inject_crate_root {
let span = use_tree.prefix.span.shrink_to_lo();
Some(Ident::new(keywords::CrateRoot.name(), span))
Some(Segment::from_ident(Ident::new(keywords::CrateRoot.name(), span)))
} else {
None
};
@ -202,13 +202,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let source = prefix_start.unwrap();
// Helper closure to emit a canary with the given base path.
let emit = |this: &mut Self, base: Option<Ident>| {
let emit = |this: &mut Self, base: Option<Segment>| {
let subclass = SingleImport {
target: Ident {
name: keywords::Underscore.name().gensymed(),
span: source.span,
span: source.ident.span,
},
source,
source: source.ident,
result: PerNS {
type_ns: Cell::new(Err(Undetermined)),
value_ns: Cell::new(Err(Undetermined)),
@ -219,7 +219,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
this.add_import_directive(
base.into_iter().collect(),
subclass.clone(),
source.span,
source.ident.span,
id,
root_use_tree.span,
root_id,
@ -230,15 +230,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
};
// A single simple `self::x` canary.
emit(self, Some(Ident {
name: keywords::SelfValue.name(),
span: source.span,
emit(self, Some(Segment {
ident: Ident {
name: keywords::SelfValue.name(),
span: source.ident.span,
},
id: source.id
}));
// One special unprefixed canary per block scope around
// the import, to detect items unreachable by `self::x`.
let orig_current_module = self.current_module;
let mut span = source.span.modern();
let mut span = source.ident.span.modern();
loop {
match self.current_module.kind {
ModuleKind::Block(..) => emit(self, None),
@ -265,11 +268,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
if nested {
// Correctly handle `self`
if source.name == keywords::SelfValue.name() {
if source.ident.name == keywords::SelfValue.name() {
type_ns_only = true;
let empty_prefix = module_path.last().map_or(true, |ident| {
ident.name == keywords::CrateRoot.name()
let empty_prefix = module_path.last().map_or(true, |seg| {
seg.ident.name == keywords::CrateRoot.name()
});
if empty_prefix {
resolve_error(
@ -284,20 +287,20 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// Replace `use foo::self;` with `use foo;`
source = module_path.pop().unwrap();
if rename.is_none() {
ident = source;
ident = source.ident;
}
}
} else {
// Disallow `self`
if source.name == keywords::SelfValue.name() {
if source.ident.name == keywords::SelfValue.name() {
resolve_error(self,
use_tree.span,
ResolutionError::SelfImportsOnlyAllowedWithin);
}
// Disallow `use $crate;`
if source.name == keywords::DollarCrate.name() && module_path.is_empty() {
let crate_root = self.resolve_crate_root(source);
if source.ident.name == keywords::DollarCrate.name() && module_path.is_empty() {
let crate_root = self.resolve_crate_root(source.ident);
let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name,
ModuleKind::Block(..) => unreachable!(),
@ -307,11 +310,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
// while the current crate doesn't have a valid `crate_name`.
if crate_name != keywords::Invalid.name() {
// `crate_name` should not be interpreted as relative.
module_path.push(Ident {
name: keywords::CrateRoot.name(),
span: source.span,
module_path.push(Segment {
ident: Ident {
name: keywords::CrateRoot.name(),
span: source.ident.span,
},
id: Some(self.session.next_node_id()),
});
source.name = crate_name;
source.ident.name = crate_name;
}
if rename.is_none() {
ident.name = crate_name;
@ -332,7 +338,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
let subclass = SingleImport {
target: ident,
source,
source: source.ident,
result: PerNS {
type_ns: Cell::new(Err(Undetermined)),
value_ns: Cell::new(Err(Undetermined)),

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use {CrateLint, PathResult};
use {CrateLint, PathResult, Segment};
use std::collections::BTreeSet;
@ -23,8 +23,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
pub(crate) fn make_path_suggestion(
&mut self,
span: Span,
path: Vec<Ident>
) -> Option<Vec<Ident>> {
path: Vec<Segment>
) -> Option<Vec<Segment>> {
debug!("make_path_suggestion: span={:?} path={:?}", span, path);
// If we don't have a path to suggest changes to, then return.
if path.is_empty() {
@ -37,13 +37,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
match (path.get(0), path.get(1)) {
// Make suggestions that require at least two non-special path segments.
(Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => {
(Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => {
debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd);
self.make_missing_self_suggestion(span, path.clone())
.or_else(|| self.make_missing_crate_suggestion(span, path.clone()))
.or_else(|| self.make_missing_super_suggestion(span, path.clone()))
.or_else(|| self.make_external_crate_suggestion(span, path.clone()))
.or_else(|| self.make_external_crate_suggestion(span, path))
},
_ => None,
}
@ -59,10 +59,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
fn make_missing_self_suggestion(
&mut self,
span: Span,
mut path: Vec<Ident>
) -> Option<Vec<Ident>> {
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
// Replace first ident with `self` and check if that is valid.
path[0].name = keywords::SelfValue.name();
path[0].ident.name = keywords::SelfValue.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
@ -82,10 +82,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
fn make_missing_crate_suggestion(
&mut self,
span: Span,
mut path: Vec<Ident>
) -> Option<Vec<Ident>> {
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
// Replace first ident with `crate` and check if that is valid.
path[0].name = keywords::Crate.name();
path[0].ident.name = keywords::Crate.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
@ -105,10 +105,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
fn make_missing_super_suggestion(
&mut self,
span: Span,
mut path: Vec<Ident>
) -> Option<Vec<Ident>> {
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
// Replace first ident with `crate` and check if that is valid.
path[0].name = keywords::Super.name();
path[0].ident.name = keywords::Super.name();
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result);
if let PathResult::Module(..) = result {
@ -131,8 +131,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
fn make_external_crate_suggestion(
&mut self,
span: Span,
mut path: Vec<Ident>
) -> Option<Vec<Ident>> {
mut path: Vec<Segment>
) -> Option<Vec<Segment>> {
// Need to clone else we can't call `resolve_path` without a borrow error. We also store
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
// each time.
@ -148,7 +148,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
for name in external_crate_names.iter().rev() {
// Replace the first after root (a placeholder we inserted) with a crate name
// and check if that is valid.
path[1].name = *name;
path[1].ident.name = *name;
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result);
@ -157,8 +157,6 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
}
}
// Remove our placeholder segment.
path.remove(1);
None
}
}

View file

@ -632,6 +632,43 @@ impl<'a> PathSource<'a> {
}
}
// A minimal representation of a path segment. We use this in resolve because
// we synthesize 'path segments' which don't have the rest of an AST or HIR
// PathSegment.
#[derive(Clone, Copy, Debug)]
pub struct Segment {
ident: Ident,
id: Option<NodeId>,
}
impl Segment {
fn from_path(path: &Path) -> Vec<Segment> {
path.segments.iter().map(|s| s.into()).collect()
}
fn from_ident(ident: Ident) -> Segment {
Segment {
ident,
id: None,
}
}
fn names_to_string(segments: &[Segment]) -> String {
names_to_string(&segments.iter()
.map(|seg| seg.ident)
.collect::<Vec<_>>())
}
}
impl<'a> From<&'a ast::PathSegment> for Segment {
fn from(seg: &'a ast::PathSegment) -> Segment {
Segment {
ident: seg.ident,
id: Some(seg.id),
}
}
}
struct UsePlacementFinder {
target_module: NodeId,
span: Option<Span>,
@ -1534,7 +1571,11 @@ impl<'a, 'b: 'a, 'cl: 'b> ty::DefIdTree for &'a Resolver<'b, 'cl> {
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
/// the resolver is no longer needed as all the relevant information is inline.
impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
fn resolve_hir_path(
&mut self,
path: &ast::Path,
is_value: bool,
) -> hir::Path {
self.resolve_hir_path_cb(path, is_value,
|resolver, span, error| resolve_error(resolver, span, error))
}
@ -1544,33 +1585,22 @@ impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
span: Span,
crate_root: Option<&str>,
components: &[&str],
args: Option<P<hir::GenericArgs>>,
is_value: bool
) -> hir::Path {
let mut segments = iter::once(keywords::CrateRoot.ident())
let segments = iter::once(keywords::CrateRoot.ident())
.chain(
crate_root.into_iter()
.chain(components.iter().cloned())
.map(Ident::from_str)
).map(hir::PathSegment::from_ident).collect::<Vec<_>>();
).map(|i| self.new_ast_path_segment(i)).collect::<Vec<_>>();
if let Some(args) = args {
let ident = segments.last().unwrap().ident;
*segments.last_mut().unwrap() = hir::PathSegment {
ident,
args: Some(args),
infer_types: true,
};
}
let mut path = hir::Path {
let path = ast::Path {
span,
def: Def::Err,
segments: segments.into(),
segments,
};
self.resolve_hir_path(&mut path, is_value);
path
self.resolve_hir_path(&path, is_value)
}
fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
@ -1596,23 +1626,27 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
use std::iter;
let mut errored = false;
let mut path = if path_str.starts_with("::") {
hir::Path {
let path = if path_str.starts_with("::") {
ast::Path {
span,
def: Def::Err,
segments: iter::once(keywords::CrateRoot.ident()).chain({
path_str.split("::").skip(1).map(Ident::from_str)
}).map(hir::PathSegment::from_ident).collect(),
segments: iter::once(keywords::CrateRoot.ident())
.chain({
path_str.split("::").skip(1).map(Ident::from_str)
})
.map(|i| self.new_ast_path_segment(i))
.collect(),
}
} else {
hir::Path {
ast::Path {
span,
def: Def::Err,
segments: path_str.split("::").map(Ident::from_str)
.map(hir::PathSegment::from_ident).collect(),
segments: path_str
.split("::")
.map(Ident::from_str)
.map(|i| self.new_ast_path_segment(i))
.collect(),
}
};
self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true);
let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true);
if errored || path.def == Def::Err {
Err(())
} else {
@ -1621,19 +1655,25 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
}
/// resolve_hir_path, but takes a callback in case there was an error
fn resolve_hir_path_cb<F>(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F)
fn resolve_hir_path_cb<F>(
&mut self,
path: &ast::Path,
is_value: bool,
error_callback: F,
) -> hir::Path
where F: for<'c, 'b> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>)
{
let namespace = if is_value { ValueNS } else { TypeNS };
let hir::Path { ref segments, span, ref mut def } = *path;
let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
let span = path.span;
let segments = &path.segments;
let path = Segment::from_path(&path);
// FIXME (Manishearth): Intra doc links won't get warned of epoch changes
match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
*def = module.def().unwrap(),
module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
*def = path_res.base_def(),
PathResult::NonModule(..) =>
path_res.base_def(),
PathResult::NonModule(..) => {
if let PathResult::Failed(span, msg, _) = self.resolve_path(
None,
&path,
@ -1643,14 +1683,34 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
CrateLint::No,
) {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
},
}
Def::Err
}
PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) |
PathResult::Indeterminate => unreachable!(),
PathResult::Failed(span, msg, _) => {
error_callback(self, span, ResolutionError::FailedToResolve(&msg));
Def::Err
}
};
let segments: Vec<_> = segments.iter().map(|seg| {
let mut hir_seg = hir::PathSegment::from_ident(seg.ident);
hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def()));
hir_seg
}).collect();
hir::Path {
span,
def,
segments: segments.into(),
}
}
fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment {
let mut seg = ast::PathSegment::from_ident(ident);
seg.id = self.session.next_node_id();
seg
}
}
impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
@ -2457,9 +2517,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
let mut new_val = None;
let mut new_id = None;
if let Some(trait_ref) = opt_trait_ref {
let path: Vec<_> = trait_ref.path.segments.iter()
.map(|seg| seg.ident)
.collect();
let path: Vec<_> = Segment::from_path(&trait_ref.path);
let def = self.smart_resolve_path_fragment(
trait_ref.ref_id,
None,
@ -2955,21 +3013,25 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
source: PathSource,
crate_lint: CrateLint
) -> PathResolution {
let segments = &path.segments.iter()
.map(|seg| seg.ident)
.collect::<Vec<_>>();
self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint)
self.smart_resolve_path_fragment(
id,
qself,
&Segment::from_path(path),
path.span,
source,
crate_lint,
)
}
fn smart_resolve_path_fragment(&mut self,
id: NodeId,
qself: Option<&QSelf>,
path: &[Ident],
path: &[Segment],
span: Span,
source: PathSource,
crate_lint: CrateLint)
-> PathResolution {
let ident_span = path.last().map_or(span, |ident| ident.span);
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let ns = source.namespace();
let is_expected = &|def| source.is_expected(def);
let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
@ -2978,18 +3040,18 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
let report_errors = |this: &mut Self, def: Option<Def>| {
// Make the base error.
let expected = source.descr_expected();
let path_str = names_to_string(path);
let item_str = path.last().unwrap();
let path_str = Segment::names_to_string(path);
let item_str = path.last().unwrap().ident;
let code = source.error_code(def.is_some());
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
format!("not a {}", expected),
span)
} else {
let item_span = path.last().unwrap().span;
let item_span = path.last().unwrap().ident.span;
let (mod_prefix, mod_str) = if path.len() == 1 {
(String::new(), "this scope".to_string())
} else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() {
} else if path.len() == 2 && path[0].ident.name == keywords::CrateRoot.name() {
(String::new(), "the crate root".to_string())
} else {
let mod_path = &path[..path.len() - 1];
@ -2999,7 +3061,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
module.def(),
_ => None,
}.map_or(String::new(), |def| format!("{} ", def.kind_name()));
(mod_prefix, format!("`{}`", names_to_string(mod_path)))
(mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
};
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
format!("not found in {}", mod_str),
@ -3010,7 +3072,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
// Emit help message for fake-self from other languages like `this`(javascript)
if ["this", "my"].contains(&&*item_str.as_str())
&& this.self_value_is_available(path[0].span, span) {
&& this.self_value_is_available(path[0].ident.span, span) {
err.span_suggestion_with_applicability(
span,
"did you mean",
@ -3045,7 +3107,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
// Try to lookup the name in more relaxed fashion for better error reporting.
let ident = *path.last().unwrap();
let ident = path.last().unwrap().ident;
let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates =
@ -3072,7 +3134,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
if path.len() == 1 && this.self_type_is_available(span) {
if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) {
let self_is_available = this.self_value_is_available(path[0].span, span);
let self_is_available = this.self_value_is_available(path[0].ident.span, span);
match candidate {
AssocSuggestion::Field => {
err.span_suggestion_with_applicability(
@ -3307,7 +3369,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
// or `<T>::A::B`. If `B` should be resolved in value namespace then
// it needs to be added to the trait map.
if ns == ValueNS {
let item_name = *path.last().unwrap();
let item_name = path.last().unwrap().ident;
let traits = self.get_traits_containing_item(item_name, ns);
self.trait_map.insert(id, traits);
}
@ -3377,7 +3439,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_qpath_anywhere(&mut self,
id: NodeId,
qself: Option<&QSelf>,
path: &[Ident],
path: &[Segment],
primary_ns: Namespace,
span: Span,
defer_to_typeck: bool,
@ -3399,10 +3461,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
}
if primary_ns != MacroNS &&
(self.macro_names.contains(&path[0].modern()) ||
self.builtin_macros.get(&path[0].name).cloned()
(self.macro_names.contains(&path[0].ident.modern()) ||
self.builtin_macros.get(&path[0].ident.name).cloned()
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) ||
self.macro_use_prelude.get(&path[0].name).cloned()
self.macro_use_prelude.get(&path[0].ident.name).cloned()
.and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) {
// Return some dummy definition, it's enough for error reporting.
return Some(
@ -3416,7 +3478,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_qpath(&mut self,
id: NodeId,
qself: Option<&QSelf>,
path: &[Ident],
path: &[Segment],
ns: Namespace,
span: Span,
global_by_default: bool,
@ -3506,8 +3568,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
PathResult::Failed(..)
if (ns == TypeNS || path.len() > 1) &&
self.primitive_type_table.primitive_types
.contains_key(&path[0].name) => {
let prim = self.primitive_type_table.primitive_types[&path[0].name];
.contains_key(&path[0].ident.name) => {
let prim = self.primitive_type_table.primitive_types[&path[0].ident.name];
PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1)
}
PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
@ -3522,8 +3584,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
};
if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
path[0].name != keywords::CrateRoot.name() &&
path[0].name != keywords::DollarCrate.name() {
path[0].ident.name != keywords::CrateRoot.name() &&
path[0].ident.name != keywords::DollarCrate.name() {
let unqualified_result = {
match self.resolve_path(
None,
@ -3551,7 +3613,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_path(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
path: &[Ident],
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
record_used: bool,
path_span: Span,
@ -3565,7 +3627,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn resolve_path_with_parent_scope(
&mut self,
base_module: Option<ModuleOrUniformRoot<'a>>,
path: &[Ident],
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path
parent_scope: &ParentScope<'a>,
record_used: bool,
@ -3587,8 +3649,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
crate_lint,
);
for (i, &ident) in path.iter().enumerate() {
for (i, &Segment { ident, id }) in path.iter().enumerate() {
debug!("resolve_path ident {} {:?}", i, ident);
let is_last = i == path.len() - 1;
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
let name = ident.name;
@ -3648,7 +3711,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
} else {
format!("`{}`", name)
};
let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() {
let msg = if i == 1 && path[0].ident.name == keywords::CrateRoot.name() {
format!("global paths cannot start with {}", name_str)
} else {
format!("{} in paths can only be used in start position", name_str)
@ -3688,6 +3751,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(ModuleOrUniformRoot::Module(next_module));
if record_used {
if let Some(id) = id {
if !self.def_map.contains_key(&id) {
assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
self.record_def(id, PathResolution::new(def));
}
}
}
} else if def == Def::ToolMod && i + 1 != path.len() {
let def = Def::NonMacroAttr(NonMacroAttrKind::Tool);
return PathResult::NonModule(PathResolution::new(def));
@ -3737,7 +3808,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
} else if i == 0 {
format!("Use of undeclared type or module `{}`", ident)
} else {
format!("Could not find `{}` in `{}`", ident, path[i - 1])
format!("Could not find `{}` in `{}`", ident, path[i - 1].ident)
};
return PathResult::Failed(ident.span, msg, is_last);
}
@ -3755,7 +3826,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
fn lint_if_path_starts_with_module(
&self,
crate_lint: CrateLint,
path: &[Ident],
path: &[Segment],
path_span: Span,
second_binding: Option<&NameBinding>,
) {
@ -3772,7 +3843,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
};
let first_name = match path.get(0) {
Some(ident) => ident.name,
Some(ident) => ident.ident.name,
None => return,
};
@ -3784,7 +3855,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
match path.get(1) {
// If this import looks like `crate::...` it's already good
Some(ident) if ident.name == keywords::Crate.name() => return,
Some(Segment { ident, .. }) if ident.name == keywords::Crate.name() => return,
// Otherwise go below to see if it's an extern crate
Some(_) => {}
// If the path has length one (and it's `CrateRoot` most likely)
@ -3977,7 +4048,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
fn lookup_typo_candidate<FilterFn>(&mut self,
path: &[Ident],
path: &[Segment],
ns: Namespace,
filter_fn: FilterFn,
span: Span)
@ -4041,7 +4112,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
}
let name = path[path.len() - 1].name;
let name = path[path.len() - 1].ident.name;
// Make sure error reporting is deterministic.
names.sort_by_cached_key(|name| name.as_str());
match find_best_match_for_name(names.iter(), &name.as_str(), None) {
@ -4558,7 +4629,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
ast::VisibilityKind::Restricted { ref path, id, .. } => {
// Visibilities are resolved as global by default, add starting root segment.
let segments = path.make_root().iter().chain(path.segments.iter())
.map(|seg| seg.ident)
.map(|seg| Segment { ident: seg.ident, id: Some(seg.id) })
.collect::<Vec<_>>();
let def = self.smart_resolve_path_fragment(
id,
@ -4851,12 +4922,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}
}
fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].ident.name == keywords::SelfType.name()
}
fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
namespace == ValueNS && path.len() == 1 && path[0].ident.name == keywords::SelfValue.name()
}
fn names_to_string(idents: &[Ident]) -> String {

View file

@ -9,7 +9,7 @@
// except according to those terms.
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding};
use ModuleOrUniformRoot;
use Namespace::{self, *};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@ -461,14 +461,15 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
parent_scope: &ParentScope<'a>,
force: bool,
) -> Result<Def, Determinacy> {
let ast::Path { ref segments, span } = *path;
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
let span = path.span;
let mut path = Segment::from_path(path);
// Possibly apply the macro helper hack
if kind == MacroKind::Bang && path.len() == 1 &&
path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) {
let root = Ident::new(keywords::DollarCrate.name(), path[0].span);
path.insert(0, root);
path[0].ident.span.ctxt().outer().expn_info()
.map_or(false, |info| info.local_inner_macros) {
let root = Ident::new(keywords::DollarCrate.name(), path[0].ident.span);
path.insert(0, Segment::from_ident(root));
}
if path.len() > 1 {
@ -496,12 +497,16 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
};
parent_scope.module.macro_resolutions.borrow_mut()
.push((path.into_boxed_slice(), span));
.push((path
.iter()
.map(|seg| seg.ident)
.collect::<Vec<Ident>>()
.into_boxed_slice(), span));
def
} else {
let binding = self.early_resolve_ident_in_lexical_scope(
path[0], MacroNS, Some(kind), parent_scope, false, force, span
path[0].ident, MacroNS, Some(kind), parent_scope, false, force, span
);
match binding {
Ok(..) => {}
@ -510,7 +515,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
parent_scope.module.legacy_macro_resolutions.borrow_mut()
.push((path[0], kind, parent_scope.clone(), binding.ok()));
.push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
binding.map(|binding| binding.def_ignoring_ambiguity())
}
@ -846,6 +851,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
let path: Vec<_> = path.iter().map(|&ident| Segment::from_ident(ident)).collect();
match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) {
PathResult::NonModule(_) => {},
PathResult::Failed(span, msg, _) => {
@ -938,7 +944,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
};
let ident = Ident::new(Symbol::intern(name), span);
self.lookup_typo_candidate(&[ident], MacroNS, is_macro, span)
self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span)
});
if let Some(suggestion) = suggestion {

View file

@ -13,7 +13,7 @@ use self::ImportDirectiveSubclass::*;
use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use Resolver;
use {Resolver, Segment};
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};
@ -89,7 +89,7 @@ pub struct ImportDirective<'a> {
pub root_span: Span,
pub parent: Module<'a>,
pub module_path: Vec<Ident>,
pub module_path: Vec<Segment>,
/// The resolution of `module_path`.
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
pub subclass: ImportDirectiveSubclass<'a>,
@ -393,7 +393,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
module_path: Vec<Ident>,
module_path: Vec<Segment>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
@ -679,7 +679,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
let has_explicit_self =
!import.module_path.is_empty() &&
import.module_path[0].name == keywords::SelfValue.name();
import.module_path[0].ident.name == keywords::SelfValue.name();
self.per_ns(|_, ns| {
if let Some(result) = result[ns].get().ok() {
@ -728,9 +728,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
self.throw_unresolved_import_error(empty_vec, None);
}
if !seen_spans.contains(&span) {
let path = import_path_to_string(&import.module_path[..],
&import.subclass,
span);
let path = import_path_to_string(
&import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
&import.subclass,
span,
);
error_vec.push((span, path, err));
seen_spans.insert(span);
prev_root_id = import.root_id;
@ -851,9 +853,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
/// If successful, the resolved bindings are written into the module.
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
names_to_string(&directive.module_path[..]),
Segment::names_to_string(&directive.module_path[..]),
module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
self.current_module = directive.parent;
let module = if let Some(module) = directive.imported_module.get() {
@ -966,7 +969,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
) {
Some((
span,
format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path))
))
} else {
Some((span, msg))
@ -982,7 +985,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = module_path.clone();
full_path.push(keywords::Invalid.ident());
full_path.push(Segment::from_ident(keywords::Invalid.ident()));
self.lint_if_path_starts_with_module(
directive.crate_lint(),
&full_path,
@ -1146,7 +1149,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = module_path.clone();
full_path.push(ident);
full_path.push(Segment::from_ident(ident));
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
this.lint_if_path_starts_with_module(
@ -1288,7 +1291,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
let resolutions = imported_module.parent.expect("parent should exist")
.resolutions.borrow();
let enum_path_segment_index = directive.module_path.len() - 1;
let enum_ident = directive.module_path[enum_path_segment_index];
let enum_ident = directive.module_path[enum_path_segment_index].ident;
let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
.expect("resolution should exist");

View file

@ -34,12 +34,10 @@ use std::env;
use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID};
use syntax::parse::token;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{
bounds_to_string,
generic_params_to_string,
path_to_string,
ty_to_string
};
use syntax::ptr::P;
@ -219,95 +217,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
self.dumper.compilation_opts(data);
}
// Return all non-empty prefixes of a path.
// For each prefix, we return the span for the last segment in the prefix and
// a str representation of the entire prefix.
fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
let mut result = Vec::with_capacity(segments.len());
let mut segs = Vec::with_capacity(segments.len());
for (i, seg) in segments.iter().enumerate() {
segs.push(seg.clone());
let sub_path = ast::Path {
span: seg.ident.span, // span for the last segment
segments: segs,
};
let qualname = if i == 0 && path.is_global() {
format!("::{}", path_to_string(&sub_path))
} else {
path_to_string(&sub_path)
};
result.push((seg.ident.span, qualname));
segs = sub_path.segments;
}
result
}
fn write_sub_paths(&mut self, path: &ast::Path) {
let sub_paths = self.process_path_prefixes(path);
for (span, _) in sub_paths {
let span = self.span_from_span(span);
self.dumper.dump_ref(Ref {
kind: RefKind::Mod,
span,
ref_id: ::null_id(),
});
for seg in &path.segments {
if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
self.dumper.dump_ref(data);
}
}
}
// As write_sub_paths, but does not process the last ident in the path (assuming it
// will be processed elsewhere). See note on write_sub_paths about global.
fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
let sub_paths = self.process_path_prefixes(path);
let len = sub_paths.len();
if len <= 1 {
return;
}
for (span, _) in sub_paths.into_iter().take(len - 1) {
let span = self.span_from_span(span);
self.dumper.dump_ref(Ref {
kind: RefKind::Mod,
span,
ref_id: ::null_id(),
});
}
}
// As write_sub_paths, but expects a path of the form module_path::trait::method
// Where trait could actually be a struct too.
fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
let sub_paths = self.process_path_prefixes(path);
let len = sub_paths.len();
if len <= 1 {
return;
}
let sub_paths = &sub_paths[..(len - 1)];
// write the trait part of the sub-path
let (ref span, _) = sub_paths[len - 2];
let span = self.span_from_span(*span);
self.dumper.dump_ref(Ref {
kind: RefKind::Type,
ref_id: ::null_id(),
span,
});
// write the other sub-paths
if len <= 2 {
return;
}
let sub_paths = &sub_paths[..len - 2];
for &(ref span, _) in sub_paths {
let span = self.span_from_span(*span);
self.dumper.dump_ref(Ref {
kind: RefKind::Mod,
span,
ref_id: ::null_id(),
});
for seg in &path.segments[..path.segments.len() - 1] {
if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
self.dumper.dump_ref(data);
}
}
}
@ -323,7 +247,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
self.visit_pat(&arg.pat);
let mut collector = PathCollector::new();
collector.visit_pat(&arg.pat);
let span_utils = self.span.clone();
for (id, ident, ..) in collector.collected_idents {
let hir_id = self.tcx.hir.node_to_hir_id(id);
@ -331,10 +254,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
Some(s) => s.to_string(),
None => continue,
};
let sub_span = span_utils.span_for_last_ident(ident.span);
if !self.span.filter_generated(sub_span, ident.span) {
if !self.span.filter_generated(ident.span) {
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for variable"));
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&Access {
@ -373,7 +295,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
) {
debug!("process_method: {}:{}", id, ident);
if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident.name, span) {
if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident, span) {
let sig_str = ::make_signature(&sig.decl, &generics);
if body.is_some() {
self.nest_tables(
@ -382,7 +304,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
);
}
self.process_generic_params(&generics, span, &method_data.qualname, id);
self.process_generic_params(&generics, &method_data.qualname, id);
method_data.value = sig_str;
method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt);
@ -415,7 +337,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
fn process_generic_params(
&mut self,
generics: &'l ast::Generics,
full_span: Span,
prefix: &str,
id: NodeId,
) {
@ -427,7 +348,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
let name = escape(self.span.snippet(param_ss));
// Append $id to name to make sure each one is unique.
let qualname = format!("{}::{}${}", prefix, name, id);
if !self.span.filter_generated(Some(param_ss), full_span) {
if !self.span.filter_generated(param_ss) {
let id = ::id_from_node_id(param.id, &self.save_ctxt);
let span = self.span_from_span(param_ss);
@ -471,7 +392,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
item.id,
|v| v.process_formals(&decl.inputs, &fn_data.qualname),
);
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
self.process_generic_params(ty_params, &fn_data.qualname, item.id);
self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data);
}
@ -505,8 +426,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
fn process_assoc_const(
&mut self,
id: ast::NodeId,
name: ast::Name,
span: Span,
ident: ast::Ident,
typ: &'l ast::Ty,
expr: Option<&'l ast::Expr>,
parent_id: DefId,
@ -515,11 +435,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
) {
let qualname = format!("::{}", self.tcx.node_path_str(id));
let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
if !self.span.filter_generated(sub_span, span) {
let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for variable"));
if !self.span.filter_generated(ident.span) {
let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt);
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&access_from!(self.save_ctxt, vis, id),
@ -527,7 +445,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
kind: DefKind::Const,
id: ::id_from_node_id(id, &self.save_ctxt),
span,
name: name.to_string(),
name: ident.name.to_string(),
qualname,
value: ty_to_string(&typ),
parent: Some(::id_from_def_id(parent_id)),
@ -558,13 +476,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let (kind, keyword) = match item.node {
ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct),
ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union),
let kind = match item.node {
ast::ItemKind::Struct(_, _) => DefKind::Struct,
ast::ItemKind::Union(_, _) => DefKind::Union,
_ => unreachable!(),
};
let sub_span = self.span.sub_span_after_keyword(item.span, keyword);
let (value, fields) = match item.node {
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
@ -595,8 +512,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
_ => (String::new(), vec![]),
};
if !self.span.filter_generated(sub_span, item.span) {
let span = self.span_from_span(sub_span.expect("No span found for struct"));
if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span);
self.dumper.dump_def(
&access_from!(self.save_ctxt, item),
Def {
@ -621,7 +538,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
self.visit_ty(&field.ty);
}
self.process_generic_params(ty_params, item.span, &qualname, item.id);
self.process_generic_params(ty_params, &qualname, item.id);
}
fn process_enum(
@ -642,10 +559,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
for variant in &enum_definition.variants {
let name = variant.node.ident.name.to_string();
let qualname = format!("{}::{}", enum_data.qualname, name);
let name_span = variant.node.ident.span;
match variant.node.data {
ast::VariantData::Struct(ref fields, _) => {
let sub_span = self.span.span_for_first_ident(variant.span);
let fields_str = fields
.iter()
.enumerate()
@ -655,9 +572,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
.collect::<Vec<_>>()
.join(", ");
let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
if !self.span.filter_generated(sub_span, variant.span) {
let span = self
.span_from_span(sub_span.expect("No span found for struct variant"));
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
@ -684,7 +600,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
}
}
ref v => {
let sub_span = self.span.span_for_first_ident(variant.span);
let mut value = format!("{}::{}", enum_data.name, name);
if let &ast::VariantData::Tuple(ref fields, _) = v {
value.push('(');
@ -695,9 +610,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
.join(", "));
value.push(')');
}
if !self.span.filter_generated(sub_span, variant.span) {
let span =
self.span_from_span(sub_span.expect("No span found for tuple variant"));
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
@ -731,7 +645,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
self.visit_ty(&field.ty);
}
}
self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
self.process_generic_params(ty_params, &enum_data.qualname, item.id);
self.dumper.dump_def(&access, enum_data);
}
@ -755,7 +669,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
if let &Some(ref trait_ref) = trait_ref {
self.process_path(trait_ref.ref_id, &trait_ref.path);
}
self.process_generic_params(type_parameters, item.span, "", item.id);
self.process_generic_params(type_parameters, "", item.id);
for impl_item in impl_items {
let map = &self.tcx.hir;
self.process_impl_item(impl_item, map.local_def_id(item.id));
@ -779,10 +693,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
val.push_str(": ");
val.push_str(&bounds_to_string(trait_refs));
}
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
if !self.span.filter_generated(sub_span, item.span) {
if !self.span.filter_generated(item.ident.span) {
let id = ::id_from_node_id(item.id, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for trait"));
let span = self.span_from_span(item.ident.span);
let children = methods
.iter()
.map(|i| ::id_from_node_id(i.id, &self.save_ctxt))
@ -815,21 +728,18 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
let trait_ref = &trait_ref.trait_ref;
if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
if !self.span.filter_generated(sub_span, trait_ref.path.span) {
let span = self.span_from_span(sub_span.expect("No span found for trait ref"));
let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
let span = self.span_from_span(sub_span);
self.dumper.dump_ref(Ref {
kind: RefKind::Type,
span,
span: span.clone(),
ref_id: ::id_from_def_id(id),
});
}
if !self.span.filter_generated(sub_span, trait_ref.path.span) {
let sub_span = self.span_from_span(sub_span.expect("No span for inheritance"));
self.dumper.dump_relation(Relation {
kind: RelationKind::SuperTrait,
span: sub_span,
span,
from: ::id_from_def_id(id),
to: ::id_from_node_id(item.id, &self.save_ctxt),
});
@ -838,7 +748,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
}
// walk generics and methods
self.process_generic_params(generics, item.span, &qualname, item.id);
self.process_generic_params(generics, &qualname, item.id);
for method in methods {
let map = &self.tcx.hir;
self.process_trait_item(method, map.local_def_id(item.id))
@ -891,29 +801,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
}
}
// Modules or types in the path prefix.
match self.save_ctxt.get_path_def(id) {
HirDef::Method(did) => {
let ti = self.tcx.associated_item(did);
if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
self.write_sub_path_trait_truncated(path);
}
}
HirDef::Fn(..) |
HirDef::Const(..) |
HirDef::Static(..) |
HirDef::StructCtor(..) |
HirDef::VariantCtor(..) |
HirDef::AssociatedConst(..) |
HirDef::Local(..) |
HirDef::Upvar(..) |
HirDef::Struct(..) |
HirDef::Union(..) |
HirDef::Variant(..) |
HirDef::TyAlias(..) |
HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path),
_ => {}
}
self.write_sub_paths_truncated(path);
}
fn process_struct_lit(
@ -924,9 +812,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
variant: &'l ty::VariantDef,
base: &'l Option<P<ast::Expr>>,
) {
self.write_sub_paths_truncated(path);
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
self.write_sub_paths_truncated(path);
down_cast_data!(struct_lit_data, RefData, ex.span);
if !generated_code(ex.span) {
self.dumper.dump_ref(struct_lit_data);
@ -988,12 +875,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
};
let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
for &Spanned { node: ref field, span } in fields {
let sub_span = self.span.span_for_first_ident(span);
for &Spanned { node: ref field, .. } in fields {
if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
if !self.span.filter_generated(sub_span, span) {
let span =
self.span_from_span(sub_span.expect("No span fund for var ref"));
if !self.span.filter_generated(field.ident.span) {
let span = self.span_from_span(field.ident.span);
self.dumper.dump_ref(Ref {
kind: RefKind::Variable,
span,
@ -1034,7 +919,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
value.push_str(": ");
value.push_str(&typ);
if !self.span.filter_generated(Some(ident.span), ident.span) {
if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
@ -1109,14 +994,11 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
None => String::new(),
};
// Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?).
let sub_span = self.span.span_for_last_ident(ident.span);
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(sub_span, ident.span) {
if !self.span.filter_generated(ident.span) {
let qualname = format!("{}${}", ident.to_string(), id);
let id = ::id_from_node_id(id, &self.save_ctxt);
let span = self.span_from_span(sub_span.expect("No span found for variable"));
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
&Access {
@ -1190,8 +1072,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
ast::TraitItemKind::Const(ref ty, ref expr) => {
self.process_assoc_const(
trait_item.id,
trait_item.ident.name,
trait_item.span,
trait_item.ident,
&ty,
expr.as_ref().map(|e| &**e),
trait_id,
@ -1214,11 +1095,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
// FIXME do something with _bounds (for type refs)
let name = trait_item.ident.name.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
let sub_span = self.span
.sub_span_after_keyword(trait_item.span, keywords::Type);
if !self.span.filter_generated(sub_span, trait_item.span) {
let span = self.span_from_span(sub_span.expect("No span found for assoc type"));
if !self.span.filter_generated(trait_item.ident.span) {
let span = self.span_from_span(trait_item.ident.span);
let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
self.dumper.dump_def(
@ -1263,8 +1142,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
ast::ImplItemKind::Const(ref ty, ref expr) => {
self.process_assoc_const(
impl_item.id,
impl_item.ident.name,
impl_item.span,
impl_item.ident,
&ty,
Some(expr),
impl_id,
@ -1328,7 +1206,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
.map(::id_from_def_id);
match use_tree.kind {
ast::UseTreeKind::Simple(..) => {
ast::UseTreeKind::Simple(alias, ..) => {
let ident = use_tree.ident();
let path = ast::Path {
segments: prefix.segments
@ -1339,24 +1217,22 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
span: path.span,
};
let sub_span = self.span.span_for_last_ident(path.span);
let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As);
let ref_id = self.lookup_def_id(id);
if !self.span.filter_generated(sub_span, path.span) {
let span = self.span_from_span(sub_span.expect("No span found for use"));
let alias_span = alias_span.map(|sp| self.span_from_span(sp));
let sub_span = path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
let ref_id = self.lookup_def_id(id).map(|id| ::id_from_def_id(id));
let alias_span = alias.map(|i| self.span_from_span(i.span));
let span = self.span_from_span(sub_span);
self.dumper.import(&access, Import {
kind: ImportKind::Use,
ref_id: ref_id.map(|id| ::id_from_def_id(id)),
ref_id,
span,
alias_span,
name: ident.to_string(),
value: String::new(),
parent,
});
self.write_sub_paths_truncated(&path);
}
self.write_sub_paths_truncated(&path);
}
ast::UseTreeKind::Glob => {
let path = ast::Path {
@ -1377,9 +1253,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
Vec::new()
};
let sub_span = self.span.sub_span_of_token(use_tree.span,
token::BinOp(token::Star));
if !self.span.filter_generated(sub_span, use_tree.span) {
let sub_span =
self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star));
if !self.span.filter_generated(use_tree.span) {
let span =
self.span_from_span(sub_span.expect("No span found for use glob"));
self.dumper.import(&access, Import {
@ -1391,8 +1267,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
value: names.join(", "),
parent,
});
self.write_sub_paths(&path);
}
self.write_sub_paths(&path);
}
ast::UseTreeKind::Nested(ref nested_items) => {
let prefix = ast::Path {
@ -1471,11 +1347,9 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
self.process_use_tree(use_tree, item.id, item, &prefix);
}
ExternCrate(_) => {
let alias_span = self.span.span_for_last_ident(item.span);
if !self.span.filter_generated(alias_span, item.span) {
let span =
self.span_from_span(alias_span.expect("No span found for extern crate"));
let name_span = item.ident.span;
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let parent = self.save_ctxt.tcx.hir.opt_local_def_id(item.id)
.and_then(|id| self.save_ctxt.tcx.parent_def_id(id))
.map(::id_from_def_id);
@ -1518,9 +1392,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
Ty(ref ty, ref ty_params) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let value = ty_to_string(&ty);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
if !self.span.filter_generated(sub_span, item.span) {
let span = self.span_from_span(sub_span.expect("No span found for typedef"));
if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span);
let id = ::id_from_node_id(item.id, &self.save_ctxt);
self.dumper.dump_def(
@ -1543,15 +1416,14 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
}
self.visit_ty(&ty);
self.process_generic_params(ty_params, item.span, &qualname, item.id);
self.process_generic_params(ty_params, &qualname, item.id);
}
Existential(ref _bounds, ref ty_params) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
// FIXME do something with _bounds
let value = String::new();
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
if !self.span.filter_generated(sub_span, item.span) {
let span = self.span_from_span(sub_span.expect("No span found for typedef"));
if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span);
let id = ::id_from_node_id(item.id, &self.save_ctxt);
self.dumper.dump_def(
@ -1573,7 +1445,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
);
}
self.process_generic_params(ty_params, item.span, &qualname, item.id);
self.process_generic_params(ty_params, &qualname, item.id);
}
Mac(_) => (),
_ => visit::walk_item(self, item),
@ -1606,14 +1478,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
}
if let Some(id) = self.lookup_def_id(t.id) {
if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) {
let span = self.span_from_span(sub_span);
self.dumper.dump_ref(Ref {
kind: RefKind::Type,
span,
ref_id: ::id_from_def_id(id),
});
}
let sub_span = path.segments.last().unwrap().ident.span;
let span = self.span_from_span(sub_span);
self.dumper.dump_ref(Ref {
kind: RefKind::Type,
span,
ref_id: ::id_from_def_id(id),
});
}
self.write_sub_paths_truncated(path);
@ -1753,11 +1624,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(fn_data, DefData, item.span);
self.nest_tables(
item.id,
|v| v.process_formals(&decl.inputs, &fn_data.qualname),
);
self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
self.process_generic_params(generics, &fn_data.qualname, item.id);
self.dumper.dump_def(&access, fn_data);
}

View file

@ -57,12 +57,10 @@ use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use syntax::ast::{self, Attribute, NodeId, PatKind};
use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind};
use syntax::source_map::Spanned;
use syntax::parse::lexer::comments::strip_doc_comment_decoration;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax::print::pprust::{arg_to_string, ty_to_string};
use syntax::source_map::MacroAttribute;
@ -162,14 +160,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
match item.node {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
let sub_span = self.span_utils
.sub_span_after_keyword(item.span, keywords::Fn);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::ForeignFunction,
id: id_from_node_id(item.id, self),
span: self.span_from_span(sub_span.unwrap()),
span: self.span_from_span(item.ident.span),
name: item.ident.to_string(),
qualname,
value: make_signature(decl, generics),
@ -181,13 +177,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
attributes: lower_attributes(item.attrs.clone(), self),
}))
}
ast::ForeignItemKind::Static(ref ty, m) => {
let keyword = if m { keywords::Mut } else { keywords::Static };
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
filter!(self.span_utils, sub_span, item.span, None);
ast::ForeignItemKind::Static(ref ty, _) => {
filter!(self.span_utils, item.ident.span);
let id = ::id_from_node_id(item.id, self);
let span = self.span_from_span(sub_span.unwrap());
let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::ForeignStatic,
@ -214,13 +208,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
match item.node {
ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let sub_span = self.span_utils
.sub_span_after_keyword(item.span, keywords::Fn);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Function,
id: id_from_node_id(item.id, self),
span: self.span_from_span(sub_span.unwrap()),
span: self.span_from_span(item.ident.span),
name: item.ident.to_string(),
qualname,
value: make_signature(decl, generics),
@ -232,19 +224,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
attributes: lower_attributes(item.attrs.clone(), self),
}))
}
ast::ItemKind::Static(ref typ, mt, _) => {
ast::ItemKind::Static(ref typ, ..) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let keyword = match mt {
ast::Mutability::Mutable => keywords::Mut,
ast::Mutability::Immutable => keywords::Static,
};
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
let id = id_from_node_id(item.id, self);
let span = self.span_from_span(sub_span.unwrap());
let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Static,
@ -263,12 +249,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
ast::ItemKind::Const(ref typ, _) => {
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let sub_span = self.span_utils
.sub_span_after_keyword(item.span, keywords::Const);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
let id = id_from_node_id(item.id, self);
let span = self.span_from_span(sub_span.unwrap());
let span = self.span_from_span(item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Const,
@ -291,16 +275,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
let cm = self.tcx.sess.source_map();
let filename = cm.span_to_filename(m.inner);
let sub_span = self.span_utils
.sub_span_after_keyword(item.span, keywords::Mod);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
Some(Data::DefData(Def {
kind: DefKind::Mod,
id: id_from_node_id(item.id, self),
name: item.ident.to_string(),
qualname,
span: self.span_from_span(sub_span.unwrap()),
span: self.span_from_span(item.ident.span),
value: filename.to_string(),
parent: None,
children: m.items
@ -316,9 +298,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
ast::ItemKind::Enum(ref def, _) => {
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let sub_span = self.span_utils
.sub_span_after_keyword(item.span, keywords::Enum);
filter!(self.span_utils, sub_span, item.span, None);
filter!(self.span_utils, item.ident.span);
let variants_str = def.variants
.iter()
.map(|v| v.node.ident.to_string())
@ -328,7 +308,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Some(Data::DefData(Def {
kind: DefKind::Enum,
id: id_from_node_id(item.id, self),
span: self.span_from_span(sub_span.unwrap()),
span: self.span_from_span(item.ident.span),
name,
qualname,
value,
@ -349,11 +329,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
if generated_code(path.span) {
return None;
}
let sub_span = self.span_utils.sub_span_for_type_name(path.span);
filter!(self.span_utils, sub_span, typ.span, None);
let sub_span = path.segments.last().unwrap().ident.span;
filter!(self.span_utils, sub_span);
let impl_id = self.next_impl_id();
let span = self.span_from_span(sub_span.unwrap());
let span = self.span_from_span(sub_span);
let type_data = self.lookup_ref_id(typ.id);
type_data.map(|type_data| {
@ -402,15 +382,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
if let Some(ident) = field.ident {
let name = ident.to_string();
let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
let sub_span = self.span_utils
.sub_span_before_token(field.span, token::Colon);
filter!(self.span_utils, sub_span, field.span, None);
filter!(self.span_utils, ident.span);
let def_id = self.tcx.hir.local_def_id(field.id);
let typ = self.tcx.type_of(def_id).to_string();
let id = id_from_node_id(field.id, self);
let span = self.span_from_span(sub_span.unwrap());
let span = self.span_from_span(ident.span);
Some(Def {
kind: DefKind::Field,
@ -433,7 +411,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
// FIXME would be nice to take a MethodItem here, but the ast provides both
// trait and impl flavours, so the caller must do the disassembly.
pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> Option<Def> {
pub fn get_method_data(&self, id: ast::NodeId, ident: ast::Ident, span: Span) -> Option<Def> {
// The qualname for a method is the trait name or name of the struct in an impl in
// which the method is declared in, followed by the method's name.
let (qualname, parent_scope, decl_id, docs, attributes) =
@ -459,7 +437,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
qualname.push_str(&self.tcx.item_path_str(def_id));
self.tcx
.associated_items(def_id)
.find(|item| item.ident.name == name)
.find(|item| item.ident.name == ident.name)
.map(|item| decl_id = Some(item.def_id));
}
qualname.push_str(">");
@ -512,16 +490,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
},
};
let qualname = format!("{}::{}", qualname, name);
let qualname = format!("{}::{}", qualname, ident.name);
let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
filter!(self.span_utils, sub_span, span, None);
filter!(self.span_utils, ident.span);
Some(Def {
kind: DefKind::Method,
id: id_from_node_id(id, self),
span: self.span_from_span(sub_span.unwrap()),
name: name.to_string(),
span: self.span_from_span(ident.span),
name: ident.name.to_string(),
qualname,
// FIXME you get better data here by using the visitor.
value: String::new(),
@ -540,9 +517,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
if generated_code(span) {
return None;
}
let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
filter!(self.span_utils, sub_span, span, None);
let span = self.span_from_span(sub_span.unwrap());
let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
filter!(self.span_utils, sub_span);
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Type,
span,
@ -574,9 +551,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
ty::Adt(def, _) if !def.is_enum() => {
let variant = &def.non_enum_variant();
let index = self.tcx.find_field_index(ident, variant).unwrap();
let sub_span = self.span_utils.span_for_last_ident(expr.span);
filter!(self.span_utils, sub_span, expr.span, None);
let span = self.span_from_span(sub_span.unwrap());
filter!(self.span_utils, ident.span);
let span = self.span_from_span(ident.span);
return Some(Data::RefData(Ref {
kind: RefKind::Variable,
span,
@ -593,9 +569,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
ast::ExprKind::Struct(ref path, ..) => {
match self.tables.expr_ty_adjusted(&hir_node).sty {
ty::Adt(def, _) if !def.is_enum() => {
let sub_span = self.span_utils.span_for_last_ident(path.span);
filter!(self.span_utils, sub_span, path.span, None);
let span = self.span_from_span(sub_span.unwrap());
let sub_span = path.segments.last().unwrap().ident.span;
filter!(self.span_utils, sub_span);
let span = self.span_from_span(sub_span);
Some(Data::RefData(Ref {
kind: RefKind::Type,
span,
@ -624,7 +600,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
ty::TraitContainer(_) => (None, Some(method_id)),
};
let sub_span = seg.ident.span;
filter!(self.span_utils, Some(sub_span), expr.span, None);
filter!(self.span_utils, sub_span);
let span = self.span_from_span(sub_span);
Some(Data::RefData(Ref {
kind: RefKind::Function,
@ -656,6 +632,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Node::Visibility(&Spanned {
node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def,
Node::PathSegment(seg) => match seg.def {
Some(def) => def,
None => HirDef::Err,
},
Node::Expr(&hir::Expr {
node: hir::ExprKind::Struct(ref qpath, ..),
..
@ -708,13 +688,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
}
pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
pub fn get_path_data(&self, _id: NodeId, path: &ast::Path) -> Option<Ref> {
path.segments.last().and_then(|seg| self.get_path_segment_data(seg))
}
pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option<Ref> {
// Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
fn fn_type(path: &ast::Path) -> bool {
if path.segments.len() != 1 {
return false;
}
if let Some(ref generic_args) = path.segments[0].args {
fn fn_type(seg: &ast::PathSegment) -> bool {
if let Some(ref generic_args) = seg.args {
if let ast::GenericArgs::Parenthesized(_) = **generic_args {
return true;
}
@ -722,17 +703,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
false
}
if path.segments.is_empty() {
if path_seg.id == DUMMY_NODE_ID {
return None;
}
let def = self.get_path_def(id);
let last_seg = &path.segments[path.segments.len() - 1];
let sub_span = last_seg.ident.span;
filter!(self.span_utils, Some(sub_span), path.span, None);
let def = self.get_path_def(path_seg.id);
let span = path_seg.ident.span;
filter!(self.span_utils, span);
let span = self.span_from_span(span);
match def {
HirDef::Upvar(id, ..) | HirDef::Local(id) => {
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
@ -743,23 +724,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
HirDef::Const(..) |
HirDef::AssociatedConst(..) |
HirDef::VariantCtor(..) => {
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Variable,
span,
ref_id: id_from_def_id(def.def_id()),
})
}
HirDef::Trait(def_id) if fn_type(path) => {
// Function type bounds are desugared in the parser, so we have to
// special case them here.
let fn_span = self.span_utils.span_for_first_ident(path.span);
fn_span.map(|span| {
Ref {
kind: RefKind::Type,
span: self.span_from_span(span),
ref_id: id_from_def_id(def_id),
}
HirDef::Trait(def_id) if fn_type(path_seg) => {
Some(Ref {
kind: RefKind::Type,
span,
ref_id: id_from_def_id(def_id),
})
}
HirDef::Struct(def_id) |
@ -774,7 +749,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
HirDef::Trait(def_id) |
HirDef::Existential(def_id) |
HirDef::TyParam(def_id) => {
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Type,
span,
@ -785,7 +759,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
// This is a reference to a tuple struct where the def_id points
// to an invisible constructor function. That is not a very useful
// def, so adjust to point to the tuple struct itself.
let span = self.span_from_span(sub_span);
let parent_def_id = self.tcx.parent_def_id(def_id).unwrap();
Some(Ref {
kind: RefKind::Type,
@ -804,7 +777,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
} else {
None
};
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
@ -812,7 +784,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
})
}
HirDef::Fn(def_id) => {
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Function,
span,
@ -820,7 +791,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
})
}
HirDef::Mod(def_id) => {
let span = self.span_from_span(sub_span);
Some(Ref {
kind: RefKind::Mod,
span,
@ -843,15 +813,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
field_ref: &ast::Field,
variant: &ty::VariantDef,
) -> Option<Ref> {
let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap();
// We don't really need a sub-span here, but no harm done
let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
filter!(self.span_utils, sub_span, field_ref.ident.span, None);
let span = self.span_from_span(sub_span.unwrap());
Some(Ref {
kind: RefKind::Variable,
span,
ref_id: id_from_def_id(variant.fields[index].did),
filter!(self.span_utils, field_ref.ident.span);
self.tcx.find_field_index(field_ref.ident, variant).map(|index| {
let span = self.span_from_span(field_ref.ident.span);
Ref {
kind: RefKind::Variable,
span,
ref_id: id_from_def_id(variant.fields[index].did),
}
})
}

View file

@ -16,7 +16,6 @@ use std::cell::Cell;
use syntax::parse::lexer::{self, StringReader};
use syntax::parse::token::{self, Token};
use syntax::symbol::keywords;
use syntax_pos::*;
#[derive(Clone)]
@ -67,131 +66,6 @@ impl<'a> SpanUtils<'a> {
lexer::StringReader::retokenize(&self.sess.parse_sess, span)
}
// Re-parses a path and returns the span for the last identifier in the path
pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
let mut result = None;
let mut toks = self.retokenise_span(span);
let mut bracket_count = 0;
loop {
let ts = toks.real_token();
if ts.tok == token::Eof {
return result;
}
if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
result = Some(ts.sp);
}
bracket_count += match ts.tok {
token::Lt => 1,
token::Gt => -1,
token::BinOp(token::Shr) => -2,
_ => 0,
}
}
}
// Return the span for the first identifier in the path.
pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
let mut toks = self.retokenise_span(span);
let mut bracket_count = 0;
loop {
let ts = toks.real_token();
if ts.tok == token::Eof {
return None;
}
if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
return Some(ts.sp);
}
bracket_count += match ts.tok {
token::Lt => 1,
token::Gt => -1,
token::BinOp(token::Shr) => -2,
_ => 0,
}
}
}
// Return the span for the last ident before a `<` and outside any
// angle brackets, or the last span.
pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
let mut toks = self.retokenise_span(span);
let mut prev = toks.real_token();
let mut result = None;
// We keep track of the following two counts - the depth of nesting of
// angle brackets, and the depth of nesting of square brackets. For the
// angle bracket count, we only count tokens which occur outside of any
// square brackets (i.e. bracket_count == 0). The intuition here is
// that we want to count angle brackets in the type, but not any which
// could be in expression context (because these could mean 'less than',
// etc.).
let mut angle_count = 0;
let mut bracket_count = 0;
loop {
let next = toks.real_token();
if (next.tok == token::Lt || next.tok == token::Colon) && angle_count == 0
&& bracket_count == 0 && prev.tok.is_ident()
{
result = Some(prev.sp);
}
if bracket_count == 0 {
angle_count += match prev.tok {
token::Lt => 1,
token::Gt => -1,
token::BinOp(token::Shl) => 2,
token::BinOp(token::Shr) => -2,
_ => 0,
};
}
bracket_count += match prev.tok {
token::OpenDelim(token::Bracket) => 1,
token::CloseDelim(token::Bracket) => -1,
_ => 0,
};
if next.tok == token::Eof {
break;
}
prev = next;
}
#[cfg(debug_assertions)] {
if angle_count != 0 || bracket_count != 0 {
let loc = self.sess.source_map().lookup_char_pos(span.lo());
span_bug!(
span,
"Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
self.snippet(span),
loc.file.name,
loc.line
);
}
}
if result.is_none() && prev.tok.is_ident() {
return Some(prev.sp);
}
result
}
pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
let mut toks = self.retokenise_span(span);
let mut prev = toks.real_token();
loop {
if prev.tok == token::Eof {
return None;
}
let next = toks.real_token();
if next.tok == tok {
return Some(prev.sp);
}
prev = next;
}
}
pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
let mut toks = self.retokenise_span(span);
loop {
@ -205,28 +79,6 @@ impl<'a> SpanUtils<'a> {
}
}
pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option<Span> {
self.sub_span_after(span, |t| t.is_keyword(keyword))
}
fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
let mut toks = self.retokenise_span(span);
loop {
let ts = toks.real_token();
if ts.tok == token::Eof {
return None;
}
if f(ts.tok) {
let ts = toks.real_token();
if ts.tok == token::Eof {
return None;
} else {
return Some(ts.sp);
}
}
}
}
// // Return the name for a macro definition (identifier after first `!`)
// pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
// let mut toks = self.retokenise_span(span);
@ -271,42 +123,28 @@ impl<'a> SpanUtils<'a> {
///
/// Used to filter out spans of minimal value,
/// such as references to macro internal variables.
pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
if !generated_code(parent) {
// Edge case - this occurs on generated code with incorrect expansion info.
return sub_span.is_none()
}
// If sub_span is none, filter out generated code.
let sub_span = match sub_span {
Some(ss) => ss,
None => return true,
};
//If the span comes from a fake source_file, filter it.
if !self.sess
.source_map()
.lookup_char_pos(parent.lo())
.file
.is_real_file()
{
pub fn filter_generated(&self, span: Span) -> bool {
if span.is_dummy() {
return true;
}
// Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
// callsite. This filters out macro internal variables and most malformed spans.
!parent.source_callsite().contains(sub_span)
if !generated_code(span) {
return false;
}
//If the span comes from a fake source_file, filter it.
!self.sess
.source_map()
.lookup_char_pos(span.lo())
.file
.is_real_file()
}
}
macro_rules! filter {
($util: expr, $span: expr, $parent: expr, None) => {
if $util.filter_generated($span, $parent) {
($util: expr, $parent: expr) => {
if $util.filter_generated($parent) {
return None;
}
};
($util: expr, $span: ident, $parent: expr) => {
if $util.filter_generated($span, $parent) {
return;
}
};
}

View file

@ -4012,6 +4012,8 @@ where F: Fn(DefId) -> Def {
def: def_ctor(def_id),
segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
ident: ast::Ident::from_str(&s),
id: None,
def: None,
args: None,
infer_types: false,
}).collect())

View file

@ -186,6 +186,8 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocContext<'a, 'tcx, 'rcx, 'cstore> {
segments.push(hir::PathSegment::new(
real_name.unwrap_or(last.ident),
None,
None,
self.generics_to_path_params(generics.clone()),
false,
));

View file

@ -129,6 +129,8 @@ pub struct PathSegment {
/// The identifier portion of this path segment.
pub ident: Ident,
pub id: NodeId,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`.
/// `None` means that no parameter list is supplied (`Path`),
@ -140,7 +142,7 @@ pub struct PathSegment {
impl PathSegment {
pub fn from_ident(ident: Ident) -> Self {
PathSegment { ident, args: None }
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
}
pub fn crate_root(span: Span) -> Self {
PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span))

View file

@ -329,7 +329,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
} else {
None
};
segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args });
segments.push(ast::PathSegment {
ident: last_ident.with_span_pos(span),
id: ast::DUMMY_NODE_ID,
args,
});
let mut path = ast::Path { span, segments };
if global {
if let Some(seg) = path.make_root() {
@ -366,7 +370,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
} else {
None
};
path.segments.push(ast::PathSegment { ident, args });
path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args });
(ast::QSelf {
ty: self_type,

View file

@ -468,8 +468,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
Path {
segments: segments.move_map(|PathSegment { ident, args }| PathSegment {
segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment {
ident: fld.fold_ident(ident),
id: fld.new_id(id),
args: args.map(|args| args.map(|args| fld.fold_generic_args(args))),
}),
span: fld.new_span(span)
@ -1234,6 +1235,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
ExprKind::MethodCall(
PathSegment {
ident: folder.fold_ident(seg.ident),
id: folder.new_id(seg.id),
args: seg.args.map(|args| {
args.map(|args| folder.fold_generic_args(args))
}),

View file

@ -2134,7 +2134,7 @@ impl<'a> Parser<'a> {
ParenthesisedArgs { inputs, output, span }.into()
};
PathSegment { ident, args }
PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
} else {
// Generic arguments are not found.
PathSegment::from_ident(ident)

View file

@ -95,7 +95,7 @@ pub fn add_type_ascription_to_parameter() {
}
#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")]
#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_ascription_to_parameter() {
let closure = |x: u32| x + 1u32;

View file

@ -22,7 +22,7 @@ fn main() {
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
// let _2: &'10_1rs i32;
// let _2: &'11_1rs i32;
// ...
// let _1: i32;
// ...
@ -31,10 +31,10 @@ fn main() {
// _1 = const 3i32;
// FakeRead(ForLet, _1);
// StorageLive(_2);
// _2 = &'10_1rs _1;
// _2 = &'11_1rs _1;
// FakeRead(ForLet, _2);
// _0 = ();
// EndRegion('10_1rs);
// EndRegion('11_1rs);
// StorageDead(_2);
// StorageDead(_1);
// return;

View file

@ -27,9 +27,9 @@ fn main() {
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
// let _7: &'23_3rs bool;
// let _7: &'26_3rs bool;
// ...
// let _3: &'23_1rs bool;
// let _3: &'26_1rs bool;
// ...
// let _2: bool;
// ...
@ -47,7 +47,7 @@ fn main() {
// _2 = const true;
// FakeRead(ForLet, _2);
// StorageLive(_3);
// _3 = &'23_1rs _2;
// _3 = &'26_1rs _2;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = _2;
@ -59,7 +59,7 @@ fn main() {
// bb4: {
// _0 = ();
// StorageDead(_5);
// EndRegion('23_1rs);
// EndRegion('26_1rs);
// StorageDead(_3);
// StorageDead(_2);
// return;
@ -68,12 +68,12 @@ fn main() {
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
// _7 = &'23_3rs _2;
// _7 = &'26_3rs _2;
// FakeRead(ForLet, _7);
// _1 = ();
// EndRegion('23_3rs);
// EndRegion('26_3rs);
// StorageDead(_7);
// EndRegion('23_1rs);
// EndRegion('26_1rs);
// StorageDead(_3);
// StorageDead(_2);
// goto -> bb1;

View file

@ -28,9 +28,9 @@ fn main() {
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
// let _7: &'26_3rs bool;
// let _7: &'30_3rs bool;
// ...
// let _3: &'26_1rs bool;
// let _3: &'30_1rs bool;
// ...
// let mut _1: bool;
// ...
@ -48,7 +48,7 @@ fn main() {
// bb2: {
// _1 = const true;
// StorageLive(_3);
// _3 = &'26_1rs _1;
// _3 = &'30_1rs _1;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = _1;
@ -60,7 +60,7 @@ fn main() {
// bb4: {
// _0 = ();
// StorageDead(_5);
// EndRegion('26_1rs);
// EndRegion('30_1rs);
// StorageDead(_3);
// StorageDead(_1);
// return;
@ -69,12 +69,12 @@ fn main() {
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
// _7 = &'26_3rs _1;
// _7 = &'30_3rs _1;
// FakeRead(ForLet, _7);
// _2 = ();
// EndRegion('26_3rs);
// EndRegion('30_3rs);
// StorageDead(_7);
// EndRegion('26_1rs);
// EndRegion('30_1rs);
// StorageDead(_3);
// goto -> bb1;
// }

View file

@ -32,9 +32,9 @@ fn foo(i: i32) {
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// let mut _0: ();
// ...
// let _6: &'26_4rs i32;
// let _6: &'31_4rs i32;
// ...
// let _3: &'26_2rs i32;
// let _3: &'31_2rs i32;
// ...
// let _2: i32;
// ...
@ -50,7 +50,7 @@ fn foo(i: i32) {
// _2 = const 0i32;
// FakeRead(ForLet, _2);
// StorageLive(_3);
// _3 = &'26_2rs _2;
// _3 = &'31_2rs _2;
// FakeRead(ForLet, _3);
// StorageLive(_5);
// _5 = (*_3);
@ -62,18 +62,18 @@ fn foo(i: i32) {
// bb2: {
// StorageDead(_5);
// StorageLive(_6);
// _6 = &'26_4rs _2;
// _6 = &'31_4rs _2;
// FakeRead(ForLet, _6);
// _0 = ();
// EndRegion('26_4rs);
// EndRegion('31_4rs);
// StorageDead(_6);
// EndRegion('26_2rs);
// EndRegion('31_2rs);
// StorageDead(_3);
// StorageDead(_2);
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('26_2rs);
// EndRegion('31_2rs);
// drop(_1) -> bb1;
// }
// bb4: {

View file

@ -33,16 +33,16 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// let _1: D;
// ...
// let mut _2: ();
// let mut _3: [closure@NodeId(18) d:&'14s D];
// let mut _4: &'14s D;
// let mut _3: [closure@NodeId(28) d:&'18s D];
// let mut _4: &'18s D;
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
// StorageLive(_4);
// _4 = &'14s _1;
// _3 = [closure@NodeId(18)] { d: move _4 };
// _4 = &'18s _1;
// _3 = [closure@NodeId(28)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
@ -50,13 +50,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// resume;
// }
// bb2: {
// EndRegion('14s);
// EndRegion('18s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('14s);
// EndRegion('18s);
// drop(_1) -> bb1;
// }
// bb4: {
@ -67,11 +67,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 {
// fn main::{{closure}}(_1: [closure@NodeId(28) d:&'18s D]) -> i32 {
// let mut _0: i32;
//
// bb0: {
// _0 = ((*(_1.0: &'14s D)).0: i32);
// _0 = ((*(_1.0: &'18s D)).0: i32);
// return;
// }
// END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir

View file

@ -33,16 +33,16 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// let _1: D;
// ...
// let mut _2: ();
// let mut _3: [closure@NodeId(22) d:&'19s D];
// let mut _4: &'19s D;
// let mut _3: [closure@NodeId(33) d:&'24s D];
// let mut _4: &'24s D;
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
// StorageLive(_4);
// _4 = &'19s _1;
// _3 = [closure@NodeId(22)] { d: move _4 };
// _4 = &'24s _1;
// _3 = [closure@NodeId(33)] { d: move _4 };
// StorageDead(_4);
// _2 = const foo(move _3) -> [return: bb2, unwind: bb3];
// }
@ -50,13 +50,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// resume;
// }
// bb2: {
// EndRegion('19s);
// EndRegion('24s);
// StorageDead(_3);
// _0 = ();
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('19s);
// EndRegion('24s);
// drop(_1) -> bb1;
// }
// bb4: {
@ -66,17 +66,17 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 {
// fn main::{{closure}}(_1: [closure@NodeId(33) d:&'24s D]) -> i32 {
// let mut _0: i32;
// ...
// let _2: &'16_0rs D;
// let _2: &'21_0rs D;
// ...
// bb0: {
// StorageLive(_2);
// _2 = &'16_0rs (*(_1.0: &'19s D));
// _2 = &'21_0rs (*(_1.0: &'24s D));
// FakeRead(ForLet, _2);
// _0 = ((*_2).0: i32);
// EndRegion('16_0rs);
// EndRegion('21_0rs);
// StorageDead(_2);
// return;
// }

View file

@ -33,13 +33,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// let _1: D;
// ...
// let mut _2: ();
// let mut _3: [closure@NodeId(22) d:D];
// let mut _3: [closure@NodeId(33) d:D];
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_3);
// _3 = [closure@NodeId(22)] { d: move _1 };
// _3 = [closure@NodeId(33)] { d: move _1 };
// _2 = const foo(move _3) -> [return: bb2, unwind: bb4];
// }
// bb1: {
@ -67,17 +67,17 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
// fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
// fn main::{{closure}}(_1: [closure@NodeId(33) d:D]) -> i32 {
// let mut _0: i32;
// ...
// let _2: &'16_0rs D;
// let _2: &'21_0rs D;
// ...
// bb0: {
// StorageLive(_2);
// _2 = &'16_0rs (_1.0: D);
// _2 = &'21_0rs (_1.0: D);
// FakeRead(ForLet, _2);
// _0 = ((*_2).0: i32);
// EndRegion('16_0rs);
// EndRegion('21_0rs);
// StorageDead(_2);
// drop(_1) -> [return: bb2, unwind: bb1];
// }

View file

@ -31,37 +31,37 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// fn main() -> () {
// let mut _0: ();
// ...
// let _2: &'21_1rs D;
// let _2: &'26_1rs D;
// ...
// let _1: D;
// ...
// let mut _3: ();
// let mut _4: [closure@NodeId(22) r:&'19s D];
// let mut _4: [closure@NodeId(33) r:&'24s D];
// bb0: {
// StorageLive(_1);
// _1 = D::{{constructor}}(const 0i32,);
// FakeRead(ForLet, _1);
// StorageLive(_2);
// _2 = &'21_1rs _1;
// _2 = &'26_1rs _1;
// FakeRead(ForLet, _2);
// StorageLive(_4);
// _4 = [closure@NodeId(22)] { r: _2 };
// _4 = [closure@NodeId(33)] { r: _2 };
// _3 = const foo(move _4) -> [return: bb2, unwind: bb3];
// }
// bb1: {
// resume;
// }
// bb2: {
// EndRegion('19s);
// EndRegion('24s);
// StorageDead(_4);
// _0 = ();
// EndRegion('21_1rs);
// EndRegion('26_1rs);
// StorageDead(_2);
// drop(_1) -> [return: bb4, unwind: bb1];
// }
// bb3: {
// EndRegion('19s);
// EndRegion('21_1rs);
// EndRegion('24s);
// EndRegion('26_1rs);
// drop(_1) -> bb1;
// }
// bb4: {
@ -72,11 +72,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
// END rustc.main.SimplifyCfg-qualify-consts.after.mir
// START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir
// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 {
// fn main::{{closure}}(_1: [closure@NodeId(33) r:&'24s D]) -> i32 {
// let mut _0: i32;
//
// bb0: {
// _0 = ((*(_1.0: &'21_1rs D)).0: i32);
// _0 = ((*(_1.0: &'26_1rs D)).0: i32);
// return;
// }
// }

View file

@ -41,7 +41,7 @@ fn main() {
// fn main() -> () {
// let mut _0: ();
// ...
// let mut _4: &'33_0rs i32;
// let mut _4: &'37_0rs i32;
// ...
// let _2: i32;
// ...
@ -79,14 +79,14 @@ fn main() {
// bb5: {
// _0 = ();
// StorageDead(_7);
// EndRegion('33_0rs);
// EndRegion('37_0rs);
// StorageDead(_4);
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// bb6: {
// _4 = &'33_0rs _2;
// _4 = &'37_0rs _2;
// _6 = ();
// StorageDead(_7);
// _1 = const true;

View file

@ -45,24 +45,24 @@ fn query() -> bool { true }
// scope 1 {
// }
// scope 2 {
// let _2: S<'36_0rs>;
// let _2: S<'49_0rs>;
// }
// let mut _1: ();
// let mut _3: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>;
// let mut _3: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
// let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>;
// let mut _5: ();
// let mut _6: &'17s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
// let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>;
// let mut _8: &'36_0rs S<'36_0rs>;
// let mut _9: &'36_0rs S<'36_0rs>;
// let mut _6: &'25s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
// let mut _7: std::option::Option<&'49_0rs S<'49_0rs>>;
// let mut _8: &'49_0rs S<'49_0rs>;
// let mut _9: &'49_0rs S<'49_0rs>;
// let mut _10: ();
// let mut _11: bool;
// let mut _12: !;
// let mut _13: ();
// let mut _14: &'34s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
// let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>;
// let mut _16: &'36_0rs S<'36_0rs>;
// let mut _17: &'36_0rs S<'36_0rs>;
// let mut _14: &'47s std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
// let mut _15: std::option::Option<&'49_0rs S<'49_0rs>>;
// let mut _16: &'49_0rs S<'49_0rs>;
// let mut _17: &'49_0rs S<'49_0rs>;
// bb0: {
// goto -> bb1;
// }
@ -73,7 +73,7 @@ fn query() -> bool { true }
// StorageLive(_2);
// StorageLive(_3);
// StorageLive(_4);
// _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None;
// _4 = std::option::Option<&'49_0rs S<'49_0rs>>::None;
// _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb4, unwind: bb3];
// }
// bb3: {
@ -81,22 +81,22 @@ fn query() -> bool { true }
// }
// bb4: {
// StorageDead(_4);
// _2 = S<'36_0rs> { r: move _3 };
// _2 = S<'49_0rs> { r: move _3 };
// StorageDead(_3);
// FakeRead(ForLet, _2);
// StorageLive(_6);
// _6 = &'17s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
// _6 = &'25s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
// StorageLive(_7);
// StorageLive(_8);
// StorageLive(_9);
// _9 = &'36_0rs _2;
// _8 = &'36_0rs (*_9);
// _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,);
// _9 = &'49_0rs _2;
// _8 = &'49_0rs (*_9);
// _7 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _8,);
// StorageDead(_8);
// _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb5, unwind: bb3];
// }
// bb5: {
// EndRegion('17s);
// EndRegion('25s);
// StorageDead(_7);
// StorageDead(_6);
// StorageDead(_9);
@ -109,7 +109,7 @@ fn query() -> bool { true }
// bb7: {
// _0 = ();
// StorageDead(_11);
// EndRegion('36_0rs);
// EndRegion('49_0rs);
// StorageDead(_2);
// return;
// }
@ -117,23 +117,23 @@ fn query() -> bool { true }
// _10 = ();
// StorageDead(_11);
// StorageLive(_14);
// _14 = &'34s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>);
// _14 = &'47s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
// StorageLive(_15);
// StorageLive(_16);
// StorageLive(_17);
// _17 = &'36_0rs _2;
// _16 = &'36_0rs (*_17);
// _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,);
// _17 = &'49_0rs _2;
// _16 = &'49_0rs (*_17);
// _15 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _16,);
// StorageDead(_16);
// _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb9, unwind: bb3];
// }
// bb9: {
// EndRegion('34s);
// EndRegion('47s);
// StorageDead(_15);
// StorageDead(_14);
// StorageDead(_17);
// _1 = ();
// EndRegion('36_0rs);
// EndRegion('49_0rs);
// StorageDead(_2);
// goto -> bb1;
// }

View file

@ -41,16 +41,16 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// Notes on the MIR output below:
//
// 1. The `EndRegion('10s)` is allowed to precede the `drop(_3)`
// 1. The `EndRegion('13s)` is allowed to precede the `drop(_3)`
// solely because of the #[may_dangle] mentioned above.
//
// 2. Regarding the occurrence of `EndRegion('12ds)` *after* `StorageDead(_6)`
// (where we have borrows `&'12ds _6`): Eventually:
// 2. Regarding the occurrence of `EndRegion('15ds)` *after* `StorageDead(_6)`
// (where we have borrows `&'15ds _6`): Eventually:
//
// i. this code should be rejected (by mir-borrowck), or
//
// ii. the MIR code generation should be changed so that the
// EndRegion('12ds)` precedes `StorageDead(_6)` in the
// EndRegion('15ds)` precedes `StorageDead(_6)` in the
// control-flow. (Note: arielb1 views drop+storagedead as one
// unit, and does not see this option as a useful avenue to
// explore.), or
@ -66,13 +66,13 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// START rustc.main.QualifyAndPromoteConstants.before.mir
// fn main() -> () {
// let mut _0: ();
// let mut _1: &'12ds S1;
// let mut _2: D1<'12ds, '10s>;
// let mut _3: &'12ds S1;
// let mut _4: &'12ds S1;
// let mut _1: &'15ds S1;
// let mut _2: D1<'15ds, '13s>;
// let mut _3: &'15ds S1;
// let mut _4: &'15ds S1;
// let _5: S1;
// let mut _6: &'10s S1;
// let mut _7: &'10s S1;
// let mut _6: &'13s S1;
// let mut _7: &'13s S1;
// let _8: S1;
// bb0: {
// StorageLive(_2);
@ -80,19 +80,19 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// StorageLive(_4);
// StorageLive(_5);
// _5 = S1::{{constructor}}(const "ex1",);
// _4 = &'12ds _5;
// _3 = &'12ds (*_4);
// _4 = &'15ds _5;
// _3 = &'15ds (*_4);
// StorageLive(_6);
// StorageLive(_7);
// StorageLive(_8);
// _8 = S1::{{constructor}}(const "dang1",);
// _7 = &'10s _8;
// _6 = &'10s (*_7);
// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
// EndRegion('10s);
// _7 = &'13s _8;
// _6 = &'13s (*_7);
// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
// EndRegion('13s);
// StorageDead(_6);
// StorageDead(_3);
// _1 = (_2.0: &'12ds S1);
// _1 = (_2.0: &'15ds S1);
// drop(_2) -> [return: bb2, unwind: bb1];
// }
// bb1: {
@ -104,7 +104,7 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// StorageDead(_8);
// StorageDead(_4);
// StorageDead(_5);
// EndRegion('12ds);
// EndRegion('15ds);
// _0 = ();
// return;
// }
@ -114,29 +114,29 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// START rustc.main.QualifyAndPromoteConstants.after.mir
// fn main() -> (){
// let mut _0: ();
// let mut _1: &'12ds S1;
// let mut _2: D1<'12ds, '10s>;
// let mut _3: &'12ds S1;
// let mut _4: &'12ds S1;
// let mut _1: &'15ds S1;
// let mut _2: D1<'15ds, '13s>;
// let mut _3: &'15ds S1;
// let mut _4: &'15ds S1;
// let _5: S1;
// let mut _6: &'10s S1;
// let mut _7: &'10s S1;
// let mut _6: &'13s S1;
// let mut _7: &'13s S1;
// let _8: S1;
// bb0: {
// StorageLive(_2);
// StorageLive(_3);
// StorageLive(_4);
// _4 = &'12ds (promoted[1]: S1);
// _3 = &'12ds (*_4);
// _4 = &'15ds (promoted[1]: S1);
// _3 = &'15ds (*_4);
// StorageLive(_6);
// StorageLive(_7);
// _7 = &'10s (promoted[0]: S1);
// _6 = &'10s (*_7);
// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6);
// EndRegion('10s);
// _7 = &'13s (promoted[0]: S1);
// _6 = &'13s (*_7);
// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6);
// EndRegion('13s);
// StorageDead(_6);
// StorageDead(_3);
// _1 = (_2.0: &'12ds S1);
// _1 = (_2.0: &'15ds S1);
// drop(_2) -> [return: bb2, unwind: bb1];
// }
// bb1: {
@ -146,7 +146,7 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> {
// StorageDead(_2);
// StorageDead(_7);
// StorageDead(_4);
// EndRegion('12ds);
// EndRegion('15ds);
// _0 = ();
// return;
// }

View file

@ -30,7 +30,7 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
// ...
// bb0: {
// ...
// _3 = [closure@NodeId(39)];
// _3 = [closure@NodeId(53)];
// ...
// _4 = &_3;
// ...

View file

@ -26,7 +26,7 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
// ...
// bb0: {
// ...
// _3 = [closure@NodeId(28)];
// _3 = [closure@NodeId(39)];
// ...
// _4 = &_3;
// ...

View file

@ -40,35 +40,35 @@ fn main() {
// ...
// bb0: {
// ...
// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]);
// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [_1: i32]);
// _6 = &ReErased mut _1;
// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [(*_6): i32/ReScope(Node(ItemLocalId(13)))]);
// _5 = &ReErased mut (*_6);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(10)))]);
// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(10))) Test, _5: &ReScope(Node(ItemLocalId(10))) mut i32]);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(13)))]);
// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(13))) Test, _5: &ReScope(Node(ItemLocalId(13))) mut i32]);
// _2 = const Test::foo(move _3, move _5) -> bb1;
// }
//
// bb1: {
// Validate(Acquire, [_2: ()]);
// EndRegion(ReScope(Node(ItemLocalId(10))));
// EndRegion(ReScope(Node(ItemLocalId(13))));
// ...
// return;
// }
// }
// END rustc.main.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(65)], _2: &ReErased mut i32) -> i32 {
// ...
// bb0: {
// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(65)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 })), [(*_2): i32]);
// _3 = &ReErased (*_2);
// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }) (imm)]);
// _0 = (*_3);
// EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
// EndRegion(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }));
// StorageDead(_3);
// return;
// }

View file

@ -48,27 +48,27 @@ fn main() {
// StorageLive(_1);
// _1 = Test { x: const 0i32 };
// StorageLive(_2);
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 })), [_1: Test]);
// _2 = &ReErased _1;
// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
// StorageLive(_4);
// StorageLive(_5);
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]);
// _5 = &ReErased ((*_2).0: i32);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
// _4 = &ReErased (*_5);
// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]);
// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]);
// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(22))) (imm)]);
// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(22))) i32]);
// _3 = const foo(move _4) -> bb1;
// }
// bb1: {
// Validate(Acquire, [_3: ()]);
// EndRegion(ReScope(Node(ItemLocalId(18))));
// EndRegion(ReScope(Node(ItemLocalId(22))));
// StorageDead(_4);
// StorageDead(_5);
// _0 = ();
// EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }));
// EndRegion(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }));
// StorageDead(_2);
// StorageDead(_1);
// return;

View file

@ -48,11 +48,11 @@ fn main() {
// }
// END rustc.write_42.EraseRegions.after.mir
// START rustc.write_42-{{closure}}.EraseRegions.after.mir
// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(32)], _2: *mut i32) -> () {
// ...
// bb0: {
// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]);
// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]);
// (*_2) = const 23i32;
// _0 = ();
// return;
@ -76,11 +76,11 @@ fn main() {
// }
// END rustc.test.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(80)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// ...
// _0 = const write_42(move _3) -> bb1;

View file

@ -46,19 +46,19 @@ fn main() {
// }
// END rustc.test.EraseRegions.after.mir
// START rustc.main-{{closure}}.EraseRegions.after.mir
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(62)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(62)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// StorageLive(_4);
// StorageLive(_5);
// Validate(Suspend(ReScope(Node(ItemLocalId(12)))), [(*_2): i32]);
// Validate(Suspend(ReScope(Node(ItemLocalId(16)))), [(*_2): i32]);
// _5 = &ReErased mut (*_2);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(12)))]);
// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(16)))]);
// _4 = move _5 as *mut i32 (Misc);
// _3 = move _4;
// EndRegion(ReScope(Node(ItemLocalId(12))));
// EndRegion(ReScope(Node(ItemLocalId(16))));
// StorageDead(_4);
// StorageDead(_5);
// Validate(Release, [_0: bool, _3: *mut i32]);