Skip to content

Commit 23ee2af

Browse files
committed
Auto merge of rust-lang#109788 - compiler-errors:trait-item-from-non-trait, r=petrochenkov
More descriptive error when qself path doesnt have a trait on the RHS of `as` `<Ty as Enum>::Assoc` should report that `Enum` is a trait. Main question is whether to eagerly report the error, or raise it with `return Err(..)` -- i'll note that in an inline comment though. cc `@GuillaumeGomez` who said this came up at a Paris Rust meetup. r? `@petrochenkov`
2 parents da63695 + d5b1ef1 commit 23ee2af

10 files changed

+205
-120
lines changed

compiler/rustc_resolve/src/late.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ pub(crate) enum ConstantItemKind {
122122
Static,
123123
}
124124

125+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
126+
enum RecordPartialRes {
127+
Yes,
128+
No,
129+
}
130+
125131
/// The rib kind restricts certain accesses,
126132
/// e.g. to a `Res::Local` of an outer item.
127133
#[derive(Copy, Clone, Debug)]
@@ -2682,6 +2688,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
26822688
&path,
26832689
PathSource::Trait(AliasPossibility::No),
26842690
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
2691+
RecordPartialRes::Yes,
26852692
);
26862693
self.diagnostic_metadata.currently_processing_impl_trait = None;
26872694
if let Some(def_id) = res.expect_full_res().opt_def_id() {
@@ -3420,6 +3427,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
34203427
&Segment::from_path(path),
34213428
source,
34223429
Finalize::new(id, path.span),
3430+
RecordPartialRes::Yes,
34233431
);
34243432
}
34253433

@@ -3430,6 +3438,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
34303438
path: &[Segment],
34313439
source: PathSource<'ast>,
34323440
finalize: Finalize,
3441+
record_partial_res: RecordPartialRes,
34333442
) -> PartialRes {
34343443
let ns = source.namespace();
34353444

@@ -3636,7 +3645,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
36363645
_ => report_errors(self, None),
36373646
};
36383647

3639-
if !matches!(source, PathSource::TraitItem(..)) {
3648+
if record_partial_res == RecordPartialRes::Yes {
36403649
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
36413650
self.r.record_partial_res(node_id, partial_res);
36423651
self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span);
@@ -3740,7 +3749,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
37403749
)));
37413750
}
37423751

3743-
// Make sure `A::B` in `<T as A::B>::C` is a trait item.
3752+
let num_privacy_errors = self.r.privacy_errors.len();
3753+
// Make sure that `A` in `<T as A>::B::C` is a trait.
3754+
let trait_res = self.smart_resolve_path_fragment(
3755+
&None,
3756+
&path[..qself.position],
3757+
PathSource::Trait(AliasPossibility::No),
3758+
Finalize::new(finalize.node_id, qself.path_span),
3759+
RecordPartialRes::No,
3760+
);
3761+
3762+
if trait_res.expect_full_res() == Res::Err {
3763+
return Ok(Some(trait_res));
3764+
}
3765+
3766+
// Truncate additional privacy errors reported above,
3767+
// because they'll be recomputed below.
3768+
self.r.privacy_errors.truncate(num_privacy_errors);
3769+
3770+
// Make sure `A::B` in `<T as A>::B::C` is a trait item.
37443771
//
37453772
// Currently, `path` names the full item (`A::B::C`, in
37463773
// our example). so we extract the prefix of that that is
@@ -3753,6 +3780,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
37533780
&path[..=qself.position],
37543781
PathSource::TraitItem(ns),
37553782
Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span),
3783+
RecordPartialRes::No,
37563784
);
37573785

37583786
// The remaining segments (the `C` in our example) will

tests/ui/parser/dyn-trait-compatibility.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ type A2 = dyn<dyn, dyn>;
99
type A3 = dyn<<dyn as dyn>::dyn>;
1010
//~^ ERROR cannot find type `dyn` in this scope
1111
//~| ERROR cannot find type `dyn` in this scope
12-
//~| ERROR use of undeclared crate or module `dyn`
12+
//~| ERROR cannot find trait `dyn` in this scope
1313

1414
fn main() {}

tests/ui/parser/dyn-trait-compatibility.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ error[E0433]: failed to resolve: use of undeclared crate or module `dyn`
44
LL | type A1 = dyn::dyn;
55
| ^^^ use of undeclared crate or module `dyn`
66

7-
error[E0433]: failed to resolve: use of undeclared crate or module `dyn`
8-
--> $DIR/dyn-trait-compatibility.rs:9:23
9-
|
10-
LL | type A3 = dyn<<dyn as dyn>::dyn>;
11-
| ^^^ use of undeclared crate or module `dyn`
12-
137
error[E0412]: cannot find type `dyn` in this scope
148
--> $DIR/dyn-trait-compatibility.rs:1:11
159
|
@@ -40,6 +34,12 @@ error[E0412]: cannot find type `dyn` in this scope
4034
LL | type A3 = dyn<<dyn as dyn>::dyn>;
4135
| ^^^ not found in this scope
4236

37+
error[E0405]: cannot find trait `dyn` in this scope
38+
--> $DIR/dyn-trait-compatibility.rs:9:23
39+
|
40+
LL | type A3 = dyn<<dyn as dyn>::dyn>;
41+
| ^^^ not found in this scope
42+
4343
error[E0412]: cannot find type `dyn` in this scope
4444
--> $DIR/dyn-trait-compatibility.rs:9:16
4545
|
@@ -48,5 +48,5 @@ LL | type A3 = dyn<<dyn as dyn>::dyn>;
4848

4949
error: aborting due to 8 previous errors
5050

51-
Some errors have detailed explanations: E0412, E0433.
52-
For more information about an error, try `rustc --explain E0412`.
51+
Some errors have detailed explanations: E0405, E0412, E0433.
52+
For more information about an error, try `rustc --explain E0405`.

tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ mod foo {
1818
fn main() {
1919
let _: <foo::Baz as crate::foo::Foo>::Bar = ();
2020
//~^ ERROR absolute paths must start with
21-
//~| this is accepted in the current edition
21+
//~| WARN this is accepted in the current edition
22+
//~| ERROR absolute paths must start with
23+
//~| WARN this is accepted in the current edition
2224

2325
let _: <crate::foo::Baz as foo::Foo>::Bar = ();
2426
//~^ ERROR absolute paths must start with
25-
//~| this is accepted in the current edition
27+
//~| WARN this is accepted in the current edition
2628
}

tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ mod foo {
1818
fn main() {
1919
let _: <foo::Baz as ::foo::Foo>::Bar = ();
2020
//~^ ERROR absolute paths must start with
21-
//~| this is accepted in the current edition
21+
//~| WARN this is accepted in the current edition
22+
//~| ERROR absolute paths must start with
23+
//~| WARN this is accepted in the current edition
2224

2325
let _: <::foo::Baz as foo::Foo>::Bar = ();
2426
//~^ ERROR absolute paths must start with
25-
//~| this is accepted in the current edition
27+
//~| WARN this is accepted in the current edition
2628
}

tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr

+11-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,22 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
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:23:13
16+
--> $DIR/edition-lint-fully-qualified-paths.rs:19:25
17+
|
18+
LL | let _: <foo::Baz as ::foo::Foo>::Bar = ();
19+
| ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo`
20+
|
21+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
22+
= note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
23+
24+
error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
25+
--> $DIR/edition-lint-fully-qualified-paths.rs:25:13
1726
|
1827
LL | let _: <::foo::Baz as foo::Foo>::Bar = ();
1928
| ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz`
2029
|
2130
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
2231
= note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
2332

24-
error: aborting due to 2 previous errors
33+
error: aborting due to 3 previous errors
2534

tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expec
1818

1919
fn issue_95327() where <u8 as Unresolved>::Assoc: String {}
2020
//~^ ERROR expected trait, found struct
21-
//~| ERROR use of undeclared type `Unresolved`
21+
//~| ERROR cannot find trait `Unresolved` in this scope
2222

2323
fn main() {}

tests/ui/traits/associated_type_bound/assoc_type_bound_with_struct.stderr

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error[E0433]: failed to resolve: use of undeclared type `Unresolved`
2-
--> $DIR/assoc_type_bound_with_struct.rs:19:31
3-
|
4-
LL | fn issue_95327() where <u8 as Unresolved>::Assoc: String {}
5-
| ^^^^^^^^^^ use of undeclared type `Unresolved`
6-
71
error[E0404]: expected trait, found struct `String`
82
--> $DIR/assoc_type_bound_with_struct.rs:5:46
93
|
@@ -76,6 +70,12 @@ help: a trait with a similar name exists
7670
LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
7771
| ~~~~~~~~
7872

73+
error[E0405]: cannot find trait `Unresolved` in this scope
74+
--> $DIR/assoc_type_bound_with_struct.rs:19:31
75+
|
76+
LL | fn issue_95327() where <u8 as Unresolved>::Assoc: String {}
77+
| ^^^^^^^^^^ not found in this scope
78+
7979
error[E0404]: expected trait, found struct `String`
8080
--> $DIR/assoc_type_bound_with_struct.rs:19:51
8181
|
@@ -87,5 +87,5 @@ LL | fn issue_95327() where <u8 as Unresolved>::Assoc: String {}
8787

8888
error: aborting due to 6 previous errors
8989

90-
Some errors have detailed explanations: E0404, E0433.
90+
Some errors have detailed explanations: E0404, E0405.
9191
For more information about an error, try `rustc --explain E0404`.

tests/ui/ufcs/ufcs-partially-resolved.rs

+22-22
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,37 @@ type A = u32;
1717

1818
fn main() {
1919
let _: <u8 as Tr>::N; //~ ERROR cannot find associated type `N` in trait `Tr`
20-
let _: <u8 as E>::N; //~ ERROR cannot find associated type `N` in enum `E`
21-
let _: <u8 as A>::N; //~ ERROR cannot find associated type `N` in `A`
20+
let _: <u8 as E>::N; //~ ERROR expected trait, found enum `E`
21+
let _: <u8 as A>::N; //~ ERROR expected trait, found type alias `A`
2222
<u8 as Tr>::N; //~ ERROR cannot find method or associated constant `N` in trait `Tr`
23-
<u8 as E>::N; //~ ERROR cannot find method or associated constant `N` in enum `E`
24-
<u8 as A>::N; //~ ERROR cannot find method or associated constant `N` in `A`
23+
<u8 as E>::N; //~ ERROR expected trait, found enum `E`
24+
<u8 as A>::N; //~ ERROR expected trait, found type alias `A`
2525
let _: <u8 as Tr>::Y; // OK
26-
let _: <u8 as E>::Y; //~ ERROR expected associated type, found variant `E::Y`
26+
let _: <u8 as E>::Y; //~ ERROR expected trait, found enum `E`
2727
<u8 as Tr>::Y; // OK
28-
<u8 as E>::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y`
28+
<u8 as E>::Y; //~ ERROR expected trait, found enum `E`
2929

3030
let _: <u8 as Tr>::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr`
31-
let _: <u8 as E>::N::NN; //~ ERROR cannot find associated type `N` in enum `E`
32-
let _: <u8 as A>::N::NN; //~ ERROR cannot find associated type `N` in `A`
31+
let _: <u8 as E>::N::NN; //~ ERROR expected trait, found enum `E`
32+
let _: <u8 as A>::N::NN; //~ ERROR expected trait, found type alias `A`
3333
<u8 as Tr>::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr`
34-
<u8 as E>::N::NN; //~ ERROR cannot find associated type `N` in enum `E`
35-
<u8 as A>::N::NN; //~ ERROR cannot find associated type `N` in `A`
34+
<u8 as E>::N::NN; //~ ERROR expected trait, found enum `E`
35+
<u8 as A>::N::NN; //~ ERROR expected trait, found type alias `A`
3636
let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
37-
let _: <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
37+
let _: <u8 as E>::Y::NN; //~ ERROR expected trait, found enum `E`
3838
<u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found for type `u16`
39-
<u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
39+
<u8 as E>::Y::NN; //~ ERROR expected trait, found enum `E`
4040

41-
let _: <u8 as Tr::N>::NN; //~ ERROR cannot find associated type `NN` in `Tr::N`
42-
let _: <u8 as E::N>::NN; //~ ERROR cannot find associated type `NN` in `E::N`
43-
let _: <u8 as A::N>::NN; //~ ERROR cannot find associated type `NN` in `A::N`
44-
<u8 as Tr::N>::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::N`
45-
<u8 as E::N>::NN; //~ ERROR cannot find method or associated constant `NN` in `E::N`
46-
<u8 as A::N>::NN; //~ ERROR cannot find method or associated constant `NN` in `A::N`
47-
let _: <u8 as Tr::Y>::NN; //~ ERROR cannot find associated type `NN` in `Tr::Y`
48-
let _: <u8 as E::Y>::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module
49-
<u8 as Tr::Y>::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y`
50-
<u8 as E::Y>::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module
41+
let _: <u8 as Tr::N>::NN; //~ ERROR cannot find trait `N` in trait `Tr`
42+
let _: <u8 as E::N>::NN; //~ ERROR cannot find trait `N` in enum `E`
43+
let _: <u8 as A::N>::NN; //~ ERROR cannot find trait `N` in `A`
44+
<u8 as Tr::N>::NN; //~ ERROR cannot find trait `N` in trait `Tr`
45+
<u8 as E::N>::NN; //~ ERROR cannot find trait `N` in enum `E`
46+
<u8 as A::N>::NN; //~ ERROR cannot find trait `N` in `A`
47+
let _: <u8 as Tr::Y>::NN; //~ ERROR expected trait, found associated type `Tr::Y
48+
let _: <u8 as E::Y>::NN; //~ ERROR expected trait, found variant `E::Y`
49+
<u8 as Tr::Y>::NN; //~ ERROR expected trait, found associated type `Tr::Y`
50+
<u8 as E::Y>::NN; //~ ERROR expected trait, found variant `E::Y`
5151

5252
let _: <u8 as Dr>::Z; //~ ERROR expected associated type, found associated function `Dr::Z`
5353
<u8 as Dr>::X; //~ ERROR expected method or associated constant, found associated type `Dr::X`

0 commit comments

Comments
 (0)