Skip to content

Commit c1d3e44

Browse files
committed
save-analysis: handle function types in bounds
This special cases the function type sugar in paths and deals with traits bounds as just the path parts. That required refactoring the path collector to distinguish between variable decls and references in patterns, basically just to please the borrow checker. cc rust-dev-tools/rls-analysis#37
1 parent 90ef337 commit c1d3e44

File tree

2 files changed

+81
-58
lines changed

2 files changed

+81
-58
lines changed

src/librustc_save_analysis/dump_visitor.rs

+42-42
Original file line numberDiff line numberDiff line change
@@ -318,25 +318,24 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
318318
let mut collector = PathCollector::new();
319319
collector.visit_pat(&arg.pat);
320320
let span_utils = self.span.clone();
321-
for &(id, ref p, ..) in &collector.collected_paths {
321+
322+
for (id, i, sp, ..) in collector.collected_idents {
322323
let hir_id = self.tcx.hir.node_to_hir_id(id);
323324
let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) {
324325
Some(s) => s.to_string(),
325326
None => continue,
326327
};
327-
// get the span only for the name of the variable (I hope the path is only ever a
328-
// variable name, but who knows?)
329-
let sub_span = span_utils.span_for_last_ident(p.span);
330-
if !self.span.filter_generated(sub_span, p.span) {
328+
let sub_span = span_utils.span_for_last_ident(sp);
329+
if !self.span.filter_generated(sub_span, sp) {
331330
let id = ::id_from_node_id(id, &self.save_ctxt);
332331
let span = self.span_from_span(sub_span.expect("No span found for variable"));
333332

334333
self.dumper.dump_def(false, Def {
335334
kind: DefKind::Local,
336335
id,
337336
span,
338-
name: path_to_string(p),
339-
qualname: format!("{}::{}", qualname, path_to_string(p)),
337+
name: i.to_string(),
338+
qualname: format!("{}::{}", qualname, i.to_string()),
340339
value: typ,
341340
parent: None,
342341
children: vec![],
@@ -391,14 +390,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
391390
}
392391
}
393392

394-
fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) {
395-
let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref);
396-
if let Some(trait_ref_data) = trait_ref_data {
397-
self.dumper.dump_ref(trait_ref_data);
398-
}
399-
self.process_path(trait_ref.ref_id, &trait_ref.path);
400-
}
401-
402393
fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
403394
let field_data = self.save_ctxt.get_field_data(field, parent_id);
404395
if let Some(field_data) = field_data {
@@ -783,7 +774,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
783774
}
784775
}
785776

786-
fn process_path(&mut self, id: NodeId, path: &ast::Path) {
777+
fn process_path(&mut self, id: NodeId, path: &'l ast::Path) {
787778
let path_data = self.save_ctxt.get_path_data(id, path);
788779
if generated_code(path.span) && path_data.is_none() {
789780
return;
@@ -798,6 +789,27 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
798789

799790
self.dumper.dump_ref(path_data);
800791

792+
// Type parameters
793+
for seg in &path.segments {
794+
if let Some(ref params) = seg.parameters {
795+
match **params {
796+
ast::PathParameters::AngleBracketed(ref data) => {
797+
for t in &data.types {
798+
self.visit_ty(t);
799+
}
800+
}
801+
ast::PathParameters::Parenthesized(ref data) => {
802+
for t in &data.inputs {
803+
self.visit_ty(t);
804+
}
805+
if let Some(ref t) = data.output {
806+
self.visit_ty(t);
807+
}
808+
}
809+
}
810+
}
811+
}
812+
801813
// Modules or types in the path prefix.
802814
match self.save_ctxt.get_path_def(id) {
803815
HirDef::Method(did) => {
@@ -904,7 +916,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
904916
collector.visit_pat(&p);
905917
self.visit_pat(&p);
906918

907-
for &(id, ref p, immut) in &collector.collected_paths {
919+
for (id, i, sp, immut) in collector.collected_idents {
908920
let mut value = match immut {
909921
ast::Mutability::Immutable => value.to_string(),
910922
_ => String::new(),
@@ -924,18 +936,18 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
924936

925937
// Get the span only for the name of the variable (I hope the path
926938
// is only ever a variable name, but who knows?).
927-
let sub_span = self.span.span_for_last_ident(p.span);
939+
let sub_span = self.span.span_for_last_ident(sp);
928940
// Rust uses the id of the pattern for var lookups, so we'll use it too.
929-
if !self.span.filter_generated(sub_span, p.span) {
930-
let qualname = format!("{}${}", path_to_string(p), id);
941+
if !self.span.filter_generated(sub_span, sp) {
942+
let qualname = format!("{}${}", i.to_string(), id);
931943
let id = ::id_from_node_id(id, &self.save_ctxt);
932944
let span = self.span_from_span(sub_span.expect("No span found for variable"));
933945

934946
self.dumper.dump_def(false, Def {
935947
kind: DefKind::Local,
936948
id,
937949
span,
938-
name: path_to_string(p),
950+
name: i.to_string(),
939951
qualname,
940952
value: typ,
941953
parent: None,
@@ -1263,7 +1275,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
12631275
for param in generics.ty_params.iter() {
12641276
for bound in param.bounds.iter() {
12651277
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
1266-
self.process_trait_ref(&trait_ref.trait_ref);
1278+
self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
12671279
}
12681280
}
12691281
if let Some(ref ty) = param.default {
@@ -1430,15 +1442,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
14301442
self.visit_pat(&pattern);
14311443
}
14321444

1433-
// This is to get around borrow checking, because we need mut self to call process_path.
1434-
let mut paths_to_process = vec![];
1435-
14361445
// process collected paths
1437-
for &(id, ref p, immut) in &collector.collected_paths {
1446+
for (id, i, sp, immut) in collector.collected_idents {
14381447
match self.save_ctxt.get_path_def(id) {
14391448
HirDef::Local(id) => {
14401449
let mut value = if immut == ast::Mutability::Immutable {
1441-
self.span.snippet(p.span).to_string()
1450+
self.span.snippet(sp).to_string()
14421451
} else {
14431452
"<mutable>".to_string()
14441453
};
@@ -1451,18 +1460,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
14511460
value.push_str(": ");
14521461
value.push_str(&typ);
14531462

1454-
assert!(p.segments.len() == 1,
1455-
"qualified path for local variable def in arm");
1456-
if !self.span.filter_generated(Some(p.span), p.span) {
1457-
let qualname = format!("{}${}", path_to_string(p), id);
1463+
if !self.span.filter_generated(Some(sp), sp) {
1464+
let qualname = format!("{}${}", i.to_string(), id);
14581465
let id = ::id_from_node_id(id, &self.save_ctxt);
1459-
let span = self.span_from_span(p.span);
1466+
let span = self.span_from_span(sp);
14601467

14611468
self.dumper.dump_def(false, Def {
14621469
kind: DefKind::Local,
14631470
id,
14641471
span,
1465-
name: path_to_string(p),
1472+
name: i.to_string(),
14661473
qualname,
14671474
value: typ,
14681475
parent: None,
@@ -1474,19 +1481,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
14741481
});
14751482
}
14761483
}
1477-
HirDef::StructCtor(..) | HirDef::VariantCtor(..) |
1478-
HirDef::Const(..) | HirDef::AssociatedConst(..) |
1479-
HirDef::Struct(..) | HirDef::Variant(..) |
1480-
HirDef::TyAlias(..) | HirDef::AssociatedTy(..) |
1481-
HirDef::SelfTy(..) => {
1482-
paths_to_process.push((id, p.clone()))
1483-
}
1484-
def => error!("unexpected definition kind when processing collected paths: {:?}",
1484+
def => error!("unexpected definition kind when processing collected idents: {:?}",
14851485
def),
14861486
}
14871487
}
14881488

1489-
for &(id, ref path) in &paths_to_process {
1489+
for (id, ref path) in collector.collected_paths {
14901490
self.process_path(id, path);
14911491
}
14921492
walk_list!(self, visit_expr, &arm.guard);

src/librustc_save_analysis/lib.rs

+39-16
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
614614
}
615615

616616
pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
617+
// Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
618+
fn fn_type(path: &ast::Path) -> bool {
619+
if path.segments.len() != 1 {
620+
return false;
621+
}
622+
if let Some(ref params) = path.segments[0].parameters {
623+
if let ast::PathParameters::Parenthesized(_) = **params {
624+
return true;
625+
}
626+
}
627+
false
628+
}
629+
617630
let def = self.get_path_def(id);
618631
let sub_span = self.span_utils.span_for_last_ident(path.span);
619632
filter!(self.span_utils, sub_span, path.span, None);
@@ -639,6 +652,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
639652
ref_id: id_from_def_id(def.def_id()),
640653
})
641654
}
655+
HirDef::Trait(def_id) if fn_type(path) => {
656+
// Function type bounds are desugared in the parser, so we have to
657+
// special case them here.
658+
let fn_span = self.span_utils.span_for_first_ident(path.span);
659+
fn_span.map(|span| Ref {
660+
kind: RefKind::Type,
661+
span: self.span_from_span(span),
662+
ref_id: id_from_def_id(def_id),
663+
})
664+
}
642665
HirDef::Struct(def_id) |
643666
HirDef::Variant(def_id, ..) |
644667
HirDef::Union(def_id) |
@@ -818,29 +841,31 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
818841
sig
819842
}
820843

821-
// An AST visitor for collecting paths from patterns.
822-
struct PathCollector {
823-
// The Row field identifies the kind of pattern.
824-
collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>,
844+
// An AST visitor for collecting paths (e.g., the names of structs) and formal
845+
// variables (idents) from patterns.
846+
struct PathCollector<'l> {
847+
collected_paths: Vec<(NodeId, &'l ast::Path)>,
848+
collected_idents: Vec<(NodeId, ast::Ident, Span, ast::Mutability)>,
825849
}
826850

827-
impl PathCollector {
828-
fn new() -> PathCollector {
829-
PathCollector { collected_paths: vec![] }
851+
impl<'l> PathCollector<'l> {
852+
fn new() -> PathCollector<'l> {
853+
PathCollector {
854+
collected_paths: vec![],
855+
collected_idents: vec![],
856+
}
830857
}
831858
}
832859

833-
impl<'a> Visitor<'a> for PathCollector {
834-
fn visit_pat(&mut self, p: &ast::Pat) {
860+
impl<'l, 'a: 'l> Visitor<'a> for PathCollector<'l> {
861+
fn visit_pat(&mut self, p: &'a ast::Pat) {
835862
match p.node {
836863
PatKind::Struct(ref path, ..) => {
837-
self.collected_paths.push((p.id, path.clone(),
838-
ast::Mutability::Mutable));
864+
self.collected_paths.push((p.id, path));
839865
}
840866
PatKind::TupleStruct(ref path, ..) |
841867
PatKind::Path(_, ref path) => {
842-
self.collected_paths.push((p.id, path.clone(),
843-
ast::Mutability::Mutable));
868+
self.collected_paths.push((p.id, path));
844869
}
845870
PatKind::Ident(bm, ref path1, _) => {
846871
debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
@@ -854,9 +879,7 @@ impl<'a> Visitor<'a> for PathCollector {
854879
ast::BindingMode::ByRef(_) => ast::Mutability::Immutable,
855880
ast::BindingMode::ByValue(mt) => mt,
856881
};
857-
// collect path for either visit_local or visit_arm
858-
let path = ast::Path::from_ident(path1.span, path1.node);
859-
self.collected_paths.push((p.id, path, immut));
882+
self.collected_idents.push((p.id, path1.node, path1.span, immut));
860883
}
861884
_ => {}
862885
}

0 commit comments

Comments
 (0)