Skip to content

Commit 42d0b36

Browse files
committed
handle fully qualified paths properly when linting
fixes #50970
1 parent be2bb80 commit 42d0b36

7 files changed

+261
-8
lines changed

src/librustc_resolve/lib.rs

+48-8
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 {
@@ -2252,11 +2263,11 @@ impl<'a> Resolver<'a> {
22522263
None,
22532264
&path,
22542265
PathSource::ImportPrefix,
2255-
CrateLint::SimplePath(id), // TODO seems wrong
2266+
CrateLint::UsePath { root_id, root_span },
22562267
);
22572268
} else {
22582269
for &(ref tree, nested_id) in items {
2259-
self.resolve_use_tree(nested_id, tree, &path);
2270+
self.resolve_use_tree(root_id, root_span, nested_id, tree, &path);
22602271
}
22612272
}
22622273
}
@@ -3188,21 +3199,44 @@ impl<'a> Resolver<'a> {
31883199

31893200
if let Some(qself) = qself {
31903201
if qself.position == 0 {
3191-
// 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.
31923205
return Some(PathResolution::with_unresolved_segments(
31933206
Def::Mod(DefId::local(CRATE_DEF_INDEX)), path.len()
31943207
));
31953208
}
3196-
// 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`).
31973224
let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
31983225
let res = self.smart_resolve_path_fragment(
31993226
id,
32003227
None,
32013228
&path[..qself.position + 1],
32023229
span,
32033230
PathSource::TraitItem(ns),
3204-
crate_lint, // TODO wrong
3231+
CrateLint::QPathTrait {
3232+
qpath_id: id,
3233+
qpath_span: qself.path_span,
3234+
},
32053235
);
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.
32063240
return Some(PathResolution::with_unresolved_segments(
32073241
res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1
32083242
));
@@ -3213,7 +3247,7 @@ impl<'a> Resolver<'a> {
32133247
Some(ns),
32143248
true,
32153249
span,
3216-
CrateLint::SimplePath(id),
3250+
crate_lint,
32173251
) {
32183252
PathResult::NonModule(path_res) => path_res,
32193253
PathResult::Module(module) if !module.is_normal() => {
@@ -3468,6 +3502,7 @@ impl<'a> Resolver<'a> {
34683502
CrateLint::No => return,
34693503
CrateLint::SimplePath(id) => (id, path_span),
34703504
CrateLint::UsePath { root_id, root_span } => (root_id, root_span),
3505+
CrateLint::QPathTrait { qpath_id, qpath_span } => (qpath_id, qpath_span),
34713506
};
34723507

34733508
let first_name = match path.get(0) {
@@ -4536,6 +4571,11 @@ enum CrateLint {
45364571
/// have nested things like `use a::{b, c}`, we care about the
45374572
/// `use a` part.
45384573
UsePath { root_id: NodeId, root_span: Span },
4574+
4575+
/// This is the "trait item" from a fully qualified path. For example,
4576+
/// we might be resolving `X::Y::Z` from a path like `<T as X::Y>::Z`.
4577+
/// The `path_span` is the span of the to the trait itself (`X::Y`).
4578+
QPathTrait { qpath_id: NodeId, qpath_span: Span },
45394579
}
45404580

45414581
__build_diagnostic_array! { librustc_resolve, DIAGNOSTICS }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2018 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+
// run-rustfix
12+
13+
#![feature(rust_2018_preview)]
14+
#![deny(absolute_path_not_starting_with_crate)]
15+
16+
mod foo {
17+
crate trait Foo {
18+
type Bar;
19+
}
20+
21+
crate struct Baz { }
22+
23+
impl Foo for Baz {
24+
type Bar = ();
25+
}
26+
}
27+
28+
29+
fn main() {
30+
let _: <foo::Baz as crate::foo::Foo>::Bar = ();
31+
//~^ ERROR absolute paths must start with
32+
//~| this was previously accepted
33+
34+
let _: <crate::foo::Baz as foo::Foo>::Bar = ();
35+
//~^ ERROR absolute paths must start with
36+
//~| this was previously accepted
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2018 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+
// run-rustfix
12+
13+
#![feature(rust_2018_preview)]
14+
#![deny(absolute_path_not_starting_with_crate)]
15+
16+
mod foo {
17+
crate trait Foo {
18+
type Bar;
19+
}
20+
21+
crate struct Baz { }
22+
23+
impl Foo for Baz {
24+
type Bar = ();
25+
}
26+
}
27+
28+
29+
fn main() {
30+
let _: <foo::Baz as ::foo::Foo>::Bar = ();
31+
//~^ ERROR absolute paths must start with
32+
//~| this was previously accepted
33+
34+
let _: <::foo::Baz as foo::Foo>::Bar = ();
35+
//~^ ERROR absolute paths must start with
36+
//~| this was previously accepted
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
2+
--> $DIR/edition-lint-fully-qualified-paths.rs:30:25
3+
|
4+
LL | let _: <foo::Baz as ::foo::Foo>::Bar = ();
5+
| ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo`
6+
|
7+
note: lint level defined here
8+
--> $DIR/edition-lint-fully-qualified-paths.rs:14:9
9+
|
10+
LL | #![deny(absolute_path_not_starting_with_crate)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
13+
= note: for more information, see issue TBD
14+
15+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
16+
--> $DIR/edition-lint-fully-qualified-paths.rs:34:13
17+
|
18+
LL | let _: <::foo::Baz as foo::Foo>::Bar = ();
19+
| ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz`
20+
|
21+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
22+
= note: for more information, see issue TBD
23+
24+
error: aborting due to 2 previous errors
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2018 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+
// run-rustfix
12+
13+
#![feature(rust_2018_preview)]
14+
#![deny(absolute_path_not_starting_with_crate)]
15+
#![allow(unused_imports)]
16+
#![allow(dead_code)]
17+
18+
crate mod foo {
19+
crate mod bar {
20+
crate mod baz { }
21+
crate mod baz1 { }
22+
23+
crate struct XX;
24+
}
25+
}
26+
27+
use crate::foo::{bar::{baz::{}}};
28+
//~^ ERROR absolute paths must start with
29+
//~| WARN this was previously accepted
30+
31+
use crate::foo::{bar::{XX, baz::{}}};
32+
//~^ ERROR absolute paths must start with
33+
//~| WARN this was previously accepted
34+
35+
use crate::foo::{bar::{baz::{}, baz1::{}}};
36+
//~^ ERROR absolute paths must start with
37+
//~| WARN this was previously accepted
38+
39+
fn main() {
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2018 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+
// run-rustfix
12+
13+
#![feature(rust_2018_preview)]
14+
#![deny(absolute_path_not_starting_with_crate)]
15+
#![allow(unused_imports)]
16+
#![allow(dead_code)]
17+
18+
crate mod foo {
19+
crate mod bar {
20+
crate mod baz { }
21+
crate mod baz1 { }
22+
23+
crate struct XX;
24+
}
25+
}
26+
27+
use foo::{bar::{baz::{}}};
28+
//~^ ERROR absolute paths must start with
29+
//~| WARN this was previously accepted
30+
31+
use foo::{bar::{XX, baz::{}}};
32+
//~^ ERROR absolute paths must start with
33+
//~| WARN this was previously accepted
34+
35+
use foo::{bar::{baz::{}, baz1::{}}};
36+
//~^ ERROR absolute paths must start with
37+
//~| WARN this was previously accepted
38+
39+
fn main() {
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
2+
--> $DIR/edition-lint-nested-empty-paths.rs:27:5
3+
|
4+
LL | use foo::{bar::{baz::{}}};
5+
| ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}`
6+
|
7+
note: lint level defined here
8+
--> $DIR/edition-lint-nested-empty-paths.rs:14:9
9+
|
10+
LL | #![deny(absolute_path_not_starting_with_crate)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
13+
= note: for more information, see issue TBD
14+
15+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
16+
--> $DIR/edition-lint-nested-empty-paths.rs:31:5
17+
|
18+
LL | use foo::{bar::{XX, baz::{}}};
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
20+
|
21+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
22+
= note: for more information, see issue TBD
23+
24+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
25+
--> $DIR/edition-lint-nested-empty-paths.rs:35:5
26+
|
27+
LL | use foo::{bar::{baz::{}, baz1::{}}};
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
29+
|
30+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
31+
= note: for more information, see issue TBD
32+
33+
error: aborting due to 3 previous errors
34+

0 commit comments

Comments
 (0)