Skip to content

Commit df511d5

Browse files
committed
Auto merge of #43826 - kennytm:fix-43796-mis-calculated-spans, r=petrochenkov
Fix "Mis-calculated spans" errors from `-Z save-analysis` + refactoring Removed the path span extraction methods from `SpanUtils`: * spans_with_brackets * spans_for_path_segments * spans_for_ty_params Use the `span` fields in `PathSegment` and `TyParam` instead. (Note that since it processes `ast::Path` not a qualified path (`hir::QPath` / `ast::QSelf`), UFCS path will be flattened: `<Foo as a::b::c::Trait>::D::E::F::g` will be seen as `a::b::c::Trait::D::E::F::g`.) Fix #43796. Close #41478. r? @nrc
2 parents f1ca76c + 60377e4 commit df511d5

File tree

4 files changed

+33
-123
lines changed

4 files changed

+33
-123
lines changed

src/librustc_save_analysis/dump_visitor.rs

+6-38
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
use rustc::hir::def::Def as HirDef;
2828
use rustc::hir::def_id::DefId;
2929
use rustc::hir::map::Node;
30-
use rustc::session::Session;
3130
use rustc::ty::{self, TyCtxt};
3231
use rustc_data_structures::fx::FxHashSet;
3332

@@ -62,7 +61,6 @@ macro_rules! down_cast_data {
6261

6362
pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> {
6463
save_ctxt: SaveContext<'l, 'tcx>,
65-
sess: &'l Session,
6664
tcx: TyCtxt<'l, 'tcx, 'tcx>,
6765
dumper: &'ll mut JsonDumper<O>,
6866

@@ -84,7 +82,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
8482
-> DumpVisitor<'l, 'tcx, 'll, O> {
8583
let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
8684
DumpVisitor {
87-
sess: &save_ctxt.tcx.sess,
8885
tcx: save_ctxt.tcx,
8986
save_ctxt: save_ctxt,
9087
dumper: dumper,
@@ -147,47 +144,23 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
147144
// For each prefix, we return the span for the last segment in the prefix and
148145
// a str representation of the entire prefix.
149146
fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
150-
let spans = self.span.spans_for_path_segments(path);
151147
let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
152148

153-
// Paths to enums seem to not match their spans - the span includes all the
154-
// variants too. But they seem to always be at the end, so I hope we can cope with
155-
// always using the first ones. So, only error out if we don't have enough spans.
156-
// What could go wrong...?
157-
if spans.len() < segments.len() {
158-
if generated_code(path.span) {
159-
return vec![];
160-
}
161-
error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
162-
path_to_string(path),
163-
spans.len(),
164-
segments.len());
165-
for s in &spans {
166-
let loc = self.sess.codemap().lookup_char_pos(s.lo);
167-
error!(" '{}' in {}, line {}",
168-
self.span.snippet(*s),
169-
loc.file.name,
170-
loc.line);
171-
}
172-
error!(" master span: {:?}: `{}`", path.span, self.span.snippet(path.span));
173-
return vec![];
174-
}
175-
176-
let mut result: Vec<(Span, String)> = vec![];
149+
let mut result = Vec::with_capacity(segments.len());
177150

178151
let mut segs = vec![];
179-
for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() {
152+
for (i, seg) in segments.iter().enumerate() {
180153
segs.push(seg.clone());
181154
let sub_path = ast::Path {
182-
span: *span, // span for the last segment
155+
span: seg.span, // span for the last segment
183156
segments: segs,
184157
};
185158
let qualname = if i == 0 && path.is_global() {
186159
format!("::{}", path_to_string(&sub_path))
187160
} else {
188161
path_to_string(&sub_path)
189162
};
190-
result.push((*span, qualname));
163+
result.push((seg.span, qualname));
191164
segs = sub_path.segments;
192165
}
193166

@@ -437,13 +410,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
437410
full_span: Span,
438411
prefix: &str,
439412
id: NodeId) {
440-
// We can't only use visit_generics since we don't have spans for param
441-
// bindings, so we reparse the full_span to get those sub spans.
442-
// However full span is the entire enum/fn/struct block, so we only want
443-
// the first few to match the number of generics we're looking for.
444-
let param_sub_spans = self.span.spans_for_ty_params(full_span,
445-
(generics.ty_params.len() as isize));
446-
for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
413+
for param in &generics.ty_params {
414+
let param_ss = param.span;
447415
let name = escape(self.span.snippet(param_ss));
448416
// Append $id to name to make sure each one is unique
449417
let qualname = format!("{}::{}${}",

src/librustc_save_analysis/span_utils.rs

-85
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use std::cell::Cell;
1616
use std::env;
1717
use std::path::Path;
1818

19-
use syntax::ast;
2019
use syntax::parse::lexer::{self, StringReader};
2120
use syntax::parse::token::{self, Token};
2221
use syntax::symbol::keywords;
@@ -207,75 +206,6 @@ impl<'a> SpanUtils<'a> {
207206
result
208207
}
209208

210-
// Reparse span and return an owned vector of sub spans of the first limit
211-
// identifier tokens in the given nesting level.
212-
// example with Foo<Bar<T,V>, Bar<T,V>>
213-
// Nesting = 0: all idents outside of angle brackets: [Foo]
214-
// Nesting = 1: idents within one level of angle brackets: [Bar, Bar]
215-
pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec<Span> {
216-
let mut result: Vec<Span> = vec![];
217-
218-
let mut toks = self.retokenise_span(span);
219-
// We keep track of how many brackets we're nested in
220-
let mut angle_count: isize = 0;
221-
let mut bracket_count: isize = 0;
222-
let mut found_ufcs_sep = false;
223-
loop {
224-
let ts = toks.real_token();
225-
if ts.tok == token::Eof {
226-
if angle_count != 0 || bracket_count != 0 {
227-
if generated_code(span) {
228-
return vec![];
229-
}
230-
let loc = self.sess.codemap().lookup_char_pos(span.lo);
231-
span_bug!(span,
232-
"Mis-counted brackets when breaking path? \
233-
Parsing '{}' in {}, line {}",
234-
self.snippet(span),
235-
loc.file.name,
236-
loc.line);
237-
}
238-
return result
239-
}
240-
if (result.len() as isize) == limit {
241-
return result;
242-
}
243-
bracket_count += match ts.tok {
244-
token::OpenDelim(token::Bracket) => 1,
245-
token::CloseDelim(token::Bracket) => -1,
246-
_ => 0,
247-
};
248-
if bracket_count > 0 {
249-
continue;
250-
}
251-
angle_count += match ts.tok {
252-
token::Lt => 1,
253-
token::Gt => -1,
254-
token::BinOp(token::Shl) => 2,
255-
token::BinOp(token::Shr) => -2,
256-
_ => 0,
257-
};
258-
259-
// Ignore the `>::` in `<Type as Trait>::AssocTy`.
260-
261-
// The root cause of this hack is that the AST representation of
262-
// qpaths is horrible. It treats <A as B>::C as a path with two
263-
// segments, B and C and notes that there is also a self type A at
264-
// position 0. Because we don't have spans for individual idents,
265-
// only the whole path, we have to iterate over the tokens in the
266-
// path, trying to pull out the non-nested idents (e.g., avoiding 'a
267-
// in `<A as B<'a>>::C`). So we end up with a span for `B>::C` from
268-
// the start of the first ident to the end of the path.
269-
if !found_ufcs_sep && angle_count == -1 {
270-
found_ufcs_sep = true;
271-
angle_count += 1;
272-
}
273-
if ts.tok.is_ident() && angle_count == nesting {
274-
result.push(ts.sp);
275-
}
276-
}
277-
}
278-
279209
pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
280210
let mut toks = self.retokenise_span(span);
281211
let mut prev = toks.real_token();
@@ -330,21 +260,6 @@ impl<'a> SpanUtils<'a> {
330260
}
331261
}
332262

333-
334-
// Returns a list of the spans of idents in a path.
335-
// E.g., For foo::bar<x,t>::baz, we return [foo, bar, baz] (well, their spans)
336-
pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec<Span> {
337-
self.spans_with_brackets(path.span, 0, -1)
338-
}
339-
340-
// Return an owned vector of the subspans of the param identifier
341-
// tokens found in span.
342-
pub fn spans_for_ty_params(&self, span: Span, number: isize) -> Vec<Span> {
343-
// Type params are nested within one level of brackets:
344-
// i.e. we want Vec<A, B> from Foo<A, B<T,U>>
345-
self.spans_with_brackets(span, 1, number)
346-
}
347-
348263
// // Return the name for a macro definition (identifier after first `!`)
349264
// pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
350265
// let mut toks = self.retokenise_span(span);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-include ../tools.mk
2+
3+
all:
4+
# Work in /tmp, because we need to create the `save-analysis-temp` folder.
5+
cp a.rs $(TMPDIR)/
6+
cd $(TMPDIR) && $(RUSTC) -Zsave-analysis $(TMPDIR)/a.rs 2> $(TMPDIR)/stderr.txt || ( cat $(TMPDIR)/stderr.txt && exit 1 )
7+
[ ! -s $(TMPDIR)/stderr.txt ] || ( cat $(TMPDIR)/stderr.txt && exit 1 )
8+
[ -f $(TMPDIR)/save-analysis/liba.json ] || ( ls -la $(TMPDIR) && exit 1 )
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "lib"]
12+
pub struct V<S>(S);
13+
pub trait An {
14+
type U;
15+
}
16+
pub trait F<A> {
17+
}
18+
impl<A: An> F<A> for V<<A as An>::U> {
19+
}

0 commit comments

Comments
 (0)