Skip to content

Commit 27649b7

Browse files
committed
Auto merge of #50983 - nikomatsakis:issue-50970-migration-lint-fq-path, r=alexcrichton
Issue 50970 migration lint fq path Similar issue, but for fully qualified paths. Fixes #50970 r? @alexcrichton
2 parents e249596 + 688324e commit 27649b7

11 files changed

+379
-30
lines changed

src/librustc_resolve/lib.rs

+130-20
Original file line numberDiff line numberDiff line change
@@ -2222,7 +2222,7 @@ impl<'a> Resolver<'a> {
22222222
segments: use_tree.prefix.make_root().into_iter().collect(),
22232223
span: use_tree.span,
22242224
};
2225-
self.resolve_use_tree(item.id, use_tree, &path);
2225+
self.resolve_use_tree(item.id, use_tree.span, item.id, use_tree, &path);
22262226
}
22272227

22282228
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => {
@@ -2233,7 +2233,18 @@ impl<'a> Resolver<'a> {
22332233
}
22342234
}
22352235

2236-
fn resolve_use_tree(&mut self, id: NodeId, use_tree: &ast::UseTree, prefix: &Path) {
2236+
/// For the most part, use trees are desugared into `ImportDirective` instances
2237+
/// when building the reduced graph (see `build_reduced_graph_for_use_tree`). But
2238+
/// there is one special case we handle here: an empty nested import like
2239+
/// `a::{b::{}}`, which desugares into...no import directives.
2240+
fn resolve_use_tree(
2241+
&mut self,
2242+
root_id: NodeId,
2243+
root_span: Span,
2244+
id: NodeId,
2245+
use_tree: &ast::UseTree,
2246+
prefix: &Path,
2247+
) {
22372248
match use_tree.kind {
22382249
ast::UseTreeKind::Nested(ref items) => {
22392250
let path = Path {
@@ -2247,10 +2258,16 @@ impl<'a> Resolver<'a> {
22472258

22482259
if items.len() == 0 {
22492260
// Resolve prefix of an import with empty braces (issue #28388).
2250-
self.smart_resolve_path(id, None, &path, PathSource::ImportPrefix);
2261+
self.smart_resolve_path_with_crate_lint(
2262+
id,
2263+
None,
2264+
&path,
2265+
PathSource::ImportPrefix,
2266+
CrateLint::UsePath { root_id, root_span },
2267+
);
22512268
} else {
22522269
for &(ref tree, nested_id) in items {
2253-
self.resolve_use_tree(nested_id, tree, &path);
2270+
self.resolve_use_tree(root_id, root_span, nested_id, tree, &path);
22542271
}
22552272
}
22562273
}
@@ -2354,7 +2371,8 @@ impl<'a> Resolver<'a> {
23542371
None,
23552372
&path,
23562373
trait_ref.path.span,
2357-
PathSource::Trait(AliasPossibility::No)
2374+
PathSource::Trait(AliasPossibility::No),
2375+
CrateLint::SimplePath(trait_ref.ref_id),
23582376
).base_def();
23592377
if def != Def::Err {
23602378
new_id = Some(def.def_id());
@@ -2787,18 +2805,38 @@ impl<'a> Resolver<'a> {
27872805
path: &Path,
27882806
source: PathSource)
27892807
-> PathResolution {
2808+
self.smart_resolve_path_with_crate_lint(id, qself, path, source, CrateLint::SimplePath(id))
2809+
}
2810+
2811+
/// A variant of `smart_resolve_path` where you also specify extra
2812+
/// information about where the path came from; this extra info is
2813+
/// sometimes needed for the lint that recommends rewriting
2814+
/// absoluate paths to `crate`, so that it knows how to frame the
2815+
/// suggestion. If you are just resolving a path like `foo::bar`
2816+
/// that appears...somewhere, though, then you just want
2817+
/// `CrateLint::SimplePath`, which is what `smart_resolve_path`
2818+
/// already provides.
2819+
fn smart_resolve_path_with_crate_lint(
2820+
&mut self,
2821+
id: NodeId,
2822+
qself: Option<&QSelf>,
2823+
path: &Path,
2824+
source: PathSource,
2825+
crate_lint: CrateLint
2826+
) -> PathResolution {
27902827
let segments = &path.segments.iter()
27912828
.map(|seg| seg.ident)
27922829
.collect::<Vec<_>>();
2793-
self.smart_resolve_path_fragment(id, qself, segments, path.span, source)
2830+
self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint)
27942831
}
27952832

27962833
fn smart_resolve_path_fragment(&mut self,
27972834
id: NodeId,
27982835
qself: Option<&QSelf>,
27992836
path: &[Ident],
28002837
span: Span,
2801-
source: PathSource)
2838+
source: PathSource,
2839+
crate_lint: CrateLint)
28022840
-> PathResolution {
28032841
let ident_span = path.last().map_or(span, |ident| ident.span);
28042842
let ns = source.namespace();
@@ -2999,9 +3037,16 @@ impl<'a> Resolver<'a> {
29993037
err_path_resolution()
30003038
};
30013039

3002-
let resolution = match self.resolve_qpath_anywhere(id, qself, path, ns, span,
3003-
source.defer_to_typeck(),
3004-
source.global_by_default()) {
3040+
let resolution = match self.resolve_qpath_anywhere(
3041+
id,
3042+
qself,
3043+
path,
3044+
ns,
3045+
span,
3046+
source.defer_to_typeck(),
3047+
source.global_by_default(),
3048+
crate_lint,
3049+
) {
30053050
Some(resolution) if resolution.unresolved_segments() == 0 => {
30063051
if is_expected(resolution.base_def()) || resolution.base_def() == Def::Err {
30073052
resolution
@@ -3102,14 +3147,15 @@ impl<'a> Resolver<'a> {
31023147
primary_ns: Namespace,
31033148
span: Span,
31043149
defer_to_typeck: bool,
3105-
global_by_default: bool)
3150+
global_by_default: bool,
3151+
crate_lint: CrateLint)
31063152
-> Option<PathResolution> {
31073153
let mut fin_res = None;
31083154
// FIXME: can't resolve paths in macro namespace yet, macros are
31093155
// processed by the little special hack below.
31103156
for (i, ns) in [primary_ns, TypeNS, ValueNS, /*MacroNS*/].iter().cloned().enumerate() {
31113157
if i == 0 || ns != primary_ns {
3112-
match self.resolve_qpath(id, qself, path, ns, span, global_by_default) {
3158+
match self.resolve_qpath(id, qself, path, ns, span, global_by_default, crate_lint) {
31133159
// If defer_to_typeck, then resolution > no resolution,
31143160
// otherwise full resolution > partial resolution > no resolution.
31153161
Some(res) if res.unresolved_segments() == 0 || defer_to_typeck =>
@@ -3137,19 +3183,60 @@ impl<'a> Resolver<'a> {
31373183
path: &[Ident],
31383184
ns: Namespace,
31393185
span: Span,
3140-
global_by_default: bool)
3186+
global_by_default: bool,
3187+
crate_lint: CrateLint)
31413188
-> Option<PathResolution> {
3189+
debug!(
3190+
"resolve_qpath(id={:?}, qself={:?}, path={:?}, \
3191+
ns={:?}, span={:?}, global_by_default={:?})",
3192+
id,
3193+
qself,
3194+
path,
3195+
ns,
3196+
span,
3197+
global_by_default,
3198+
);
3199+
31423200
if let Some(qself) = qself {
31433201
if qself.position == 0 {
3144-
// FIXME: Create some fake resolution that can't possibly be a type.
3202+
// This is a case like `<T>::B`, where there is no
3203+
// trait to resolve. In that case, we leave the `B`
3204+
// segment to be resolved by type-check.
31453205
return Some(PathResolution::with_unresolved_segments(
31463206
Def::Mod(DefId::local(CRATE_DEF_INDEX)), path.len()
31473207
));
31483208
}
3149-
// Make sure `A::B` in `<T as A>::B::C` is a trait item.
3209+
3210+
// Make sure `A::B` in `<T as A::B>::C` is a trait item.
3211+
//
3212+
// Currently, `path` names the full item (`A::B::C`, in
3213+
// our example). so we extract the prefix of that that is
3214+
// the trait (the slice upto and including
3215+
// `qself.position`). And then we recursively resolve that,
3216+
// but with `qself` set to `None`.
3217+
//
3218+
// However, setting `qself` to none (but not changing the
3219+
// span) loses the information about where this path
3220+
// *actually* appears, so for the purposes of the crate
3221+
// lint we pass along information that this is the trait
3222+
// name from a fully qualified path, and this also
3223+
// contains the full span (the `CrateLint::QPathTrait`).
31503224
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
3151-
let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1],
3152-
span, PathSource::TraitItem(ns));
3225+
let res = self.smart_resolve_path_fragment(
3226+
id,
3227+
None,
3228+
&path[..qself.position + 1],
3229+
span,
3230+
PathSource::TraitItem(ns),
3231+
CrateLint::QPathTrait {
3232+
qpath_id: id,
3233+
qpath_span: qself.path_span,
3234+
},
3235+
);
3236+
3237+
// The remaining segments (the `C` in our example) will
3238+
// have to be resolved by type-check, since that requires doing
3239+
// trait resolution.
31533240
return Some(PathResolution::with_unresolved_segments(
31543241
res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1
31553242
));
@@ -3160,7 +3247,7 @@ impl<'a> Resolver<'a> {
31603247
Some(ns),
31613248
true,
31623249
span,
3163-
CrateLint::SimplePath(id),
3250+
crate_lint,
31643251
) {
31653252
PathResult::NonModule(path_res) => path_res,
31663253
PathResult::Module(module) if !module.is_normal() => {
@@ -3231,6 +3318,16 @@ impl<'a> Resolver<'a> {
32313318
let mut allow_super = true;
32323319
let mut second_binding = None;
32333320

3321+
debug!(
3322+
"resolve_path(path={:?}, opt_ns={:?}, record_used={:?}, \
3323+
path_span={:?}, crate_lint={:?})",
3324+
path,
3325+
opt_ns,
3326+
record_used,
3327+
path_span,
3328+
crate_lint,
3329+
);
3330+
32343331
for (i, &ident) in path.iter().enumerate() {
32353332
debug!("resolve_path ident {} {:?}", i, ident);
32363333
let is_last = i == path.len() - 1;
@@ -3406,6 +3503,7 @@ impl<'a> Resolver<'a> {
34063503
CrateLint::No => return,
34073504
CrateLint::SimplePath(id) => (id, path_span),
34083505
CrateLint::UsePath { root_id, root_span } => (root_id, root_span),
3506+
CrateLint::QPathTrait { qpath_id, qpath_span } => (qpath_id, qpath_span),
34093507
};
34103508

34113509
let first_name = match path.get(0) {
@@ -4093,8 +4191,14 @@ impl<'a> Resolver<'a> {
40934191
let segments = path.make_root().iter().chain(path.segments.iter())
40944192
.map(|seg| seg.ident)
40954193
.collect::<Vec<_>>();
4096-
let def = self.smart_resolve_path_fragment(id, None, &segments, path.span,
4097-
PathSource::Visibility).base_def();
4194+
let def = self.smart_resolve_path_fragment(
4195+
id,
4196+
None,
4197+
&segments,
4198+
path.span,
4199+
PathSource::Visibility,
4200+
CrateLint::SimplePath(id),
4201+
).base_def();
40984202
if def == Def::Err {
40994203
ty::Visibility::Public
41004204
} else {
@@ -4454,6 +4558,7 @@ pub enum MakeGlobMap {
44544558
No,
44554559
}
44564560

4561+
#[derive(Copy, Clone, Debug)]
44574562
enum CrateLint {
44584563
/// Do not issue the lint
44594564
No,
@@ -4467,6 +4572,11 @@ enum CrateLint {
44674572
/// have nested things like `use a::{b, c}`, we care about the
44684573
/// `use a` part.
44694574
UsePath { root_id: NodeId, root_span: Span },
4575+
4576+
/// This is the "trait item" from a fully qualified path. For example,
4577+
/// we might be resolving `X::Y::Z` from a path like `<T as X::Y>::Z`.
4578+
/// The `path_span` is the span of the to the trait itself (`X::Y`).
4579+
QPathTrait { qpath_id: NodeId, qpath_span: Span },
44704580
}
44714581

44724582
__build_diagnostic_array! { librustc_resolve, DIAGNOSTICS }

src/libsyntax/ast.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,11 @@ pub enum ExprKind {
12111211
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
12121212
pub struct QSelf {
12131213
pub ty: P<Ty>,
1214+
1215+
/// The span of `a::b::Trait` in a path like `<Vec<T> as
1216+
/// a::b::Trait>::AssociatedItem`; in the case where `position ==
1217+
/// 0`, this is an empty span.
1218+
pub path_span: Span,
12141219
pub position: usize
12151220
}
12161221

src/libsyntax/ext/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
373373

374374
(ast::QSelf {
375375
ty: self_type,
376+
path_span: path.span,
376377
position: path.segments.len() - 1
377378
}, path)
378379
}

src/libsyntax/fold.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,10 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
390390
TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))),
391391
TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)),
392392
TyKind::Path(qself, path) => {
393-
let qself = qself.map(|QSelf { ty, position }| {
393+
let qself = qself.map(|QSelf { ty, path_span, position }| {
394394
QSelf {
395395
ty: fld.fold_ty(ty),
396+
path_span: fld.new_span(path_span),
396397
position,
397398
}
398399
});
@@ -1131,7 +1132,11 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
11311132
}
11321133
PatKind::Path(opt_qself, pth) => {
11331134
let opt_qself = opt_qself.map(|qself| {
1134-
QSelf { ty: folder.fold_ty(qself.ty), position: qself.position }
1135+
QSelf {
1136+
ty: folder.fold_ty(qself.ty),
1137+
path_span: folder.new_span(qself.path_span),
1138+
position: qself.position,
1139+
}
11351140
});
11361141
PatKind::Path(opt_qself, folder.fold_path(pth))
11371142
}
@@ -1292,9 +1297,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
12921297
lim)
12931298
}
12941299
ExprKind::Path(qself, path) => {
1295-
let qself = qself.map(|QSelf { ty, position }| {
1300+
let qself = qself.map(|QSelf { ty, path_span, position }| {
12961301
QSelf {
12971302
ty: folder.fold_ty(ty),
1303+
path_span: folder.new_span(path_span),
12981304
position,
12991305
}
13001306
});

src/libsyntax/parse/parser.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -1715,8 +1715,11 @@ impl<'a> Parser<'a> {
17151715
self.parse_path_segments(&mut segments, T::PATH_STYLE, true)?;
17161716

17171717
let span = ty.span.to(self.prev_span);
1718-
let recovered =
1719-
base.to_recovered(Some(QSelf { ty, position: 0 }), ast::Path { segments, span });
1718+
let path_span = span.to(span); // use an empty path since `position` == 0
1719+
let recovered = base.to_recovered(
1720+
Some(QSelf { ty, path_span, position: 0 }),
1721+
ast::Path { segments, span },
1722+
);
17201723

17211724
self.diagnostic()
17221725
.struct_span_err(span, "missing angle brackets in associated item path")
@@ -1905,21 +1908,32 @@ impl<'a> Parser<'a> {
19051908
/// `qualified_path = <type [as trait_ref]>::path`
19061909
///
19071910
/// # Examples
1911+
/// `<T>::default`
19081912
/// `<T as U>::a`
19091913
/// `<T as U>::F::a<S>` (without disambiguator)
19101914
/// `<T as U>::F::a::<S>` (with disambiguator)
19111915
fn parse_qpath(&mut self, style: PathStyle) -> PResult<'a, (QSelf, ast::Path)> {
19121916
let lo = self.prev_span;
19131917
let ty = self.parse_ty()?;
1914-
let mut path = if self.eat_keyword(keywords::As) {
1915-
self.parse_path(PathStyle::Type)?
1918+
1919+
// `path` will contain the prefix of the path up to the `>`,
1920+
// if any (e.g., `U` in the `<T as U>::*` examples
1921+
// above). `path_span` has the span of that path, or an empty
1922+
// span in the case of something like `<T>::Bar`.
1923+
let (mut path, path_span);
1924+
if self.eat_keyword(keywords::As) {
1925+
let path_lo = self.span;
1926+
path = self.parse_path(PathStyle::Type)?;
1927+
path_span = path_lo.to(self.prev_span);
19161928
} else {
1917-
ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP }
1918-
};
1929+
path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
1930+
path_span = self.span.to(self.span);
1931+
}
1932+
19191933
self.expect(&token::Gt)?;
19201934
self.expect(&token::ModSep)?;
19211935

1922-
let qself = QSelf { ty, position: path.segments.len() };
1936+
let qself = QSelf { ty, path_span, position: path.segments.len() };
19231937
self.parse_path_segments(&mut path.segments, style, true)?;
19241938

19251939
Ok((qself, ast::Path { segments: path.segments, span: lo.to(self.prev_span) }))

0 commit comments

Comments
 (0)