Skip to content

Commit e2d69f2

Browse files
committed
Make errors more concise and helpful
Before: ``` = note: this link partially resolves to the struct `S` = note: no `fmt` in `S` ``` After: ``` = note: the struct `S` has no field or associated item named `fmt` ```
1 parent 7b8d0be commit e2d69f2

File tree

7 files changed

+81
-65
lines changed

7 files changed

+81
-65
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,11 +1406,18 @@ fn resolution_failure(
14061406
let in_scope = kinds.iter().any(|kind| kind.res().is_some());
14071407
let mut reported_not_in_scope = false;
14081408
let item = |res: Res| {
1409-
if let Some(id) = res.opt_def_id() {
1410-
(format!("the {} `{}`", res.descr(), cx.tcx.item_name(id).to_string()), ",")
1411-
} else {
1412-
(format!("{} {}", res.article(), res.descr()), "")
1413-
}
1409+
format!("the {} `{}`", res.descr(), cx.tcx.item_name(res.def_id()).to_string())
1410+
};
1411+
let assoc_item_not_allowed = |res: Res, diag: &mut DiagnosticBuilder<'_>| {
1412+
let def_id = res.def_id();
1413+
let name = cx.tcx.item_name(def_id);
1414+
let note = format!(
1415+
"`{}` is {} {}, not a module or type, and cannot have associated items",
1416+
name,
1417+
res.article(),
1418+
res.descr()
1419+
);
1420+
diag.note(&note);
14141421
};
14151422
for failure in kinds {
14161423
match failure {
@@ -1425,11 +1432,9 @@ fn resolution_failure(
14251432
}
14261433
ResolutionFailure::Dummy => continue,
14271434
ResolutionFailure::WrongNamespace(res, expected_ns) => {
1428-
let (item, comma) = item(res);
14291435
let note = format!(
1430-
"this link resolves to {}{} which is not in the {} namespace",
1431-
item,
1432-
comma,
1436+
"this link resolves to {}, which is not in the {} namespace",
1437+
item(res),
14331438
expected_ns.descr()
14341439
);
14351440
diag.note(&note);
@@ -1450,10 +1455,9 @@ fn resolution_failure(
14501455
panic!("all intra doc links should have a parent item")
14511456
}
14521457
ResolutionFailure::NoPrimitiveImpl(res, _) => {
1453-
let (item, comma) = item(res);
14541458
let note = format!(
1455-
"this link partially resolves to {}{} which does not have any associated items",
1456-
item, comma,
1459+
"this link partially resolves to {}, which does not have any associated items",
1460+
item(res),
14571461
);
14581462
diag.note(&note);
14591463
}
@@ -1465,41 +1469,62 @@ fn resolution_failure(
14651469
diag.note(&note);
14661470
}
14671471
ResolutionFailure::NoAssocItem(res, assoc_item) => {
1468-
let (item, _) = item(res);
1469-
diag.note(&format!("this link partially resolves to {}", item));
1470-
// FIXME: when are items neither a primitive nor a Def?
1471-
if let Res::Def(_, def_id) = res {
1472-
let name = cx.tcx.item_name(def_id);
1473-
let note = format!("no `{}` in `{}`", assoc_item, name,);
1474-
diag.note(&note);
1475-
}
1472+
use DefKind::*;
1473+
1474+
let (kind, def_id) = match res {
1475+
Res::Def(kind, def_id) => (kind, def_id),
1476+
_ => unreachable!(
1477+
"primitives are covered above and other `Res` variants aren't possible at module scope"
1478+
),
1479+
};
1480+
let name = cx.tcx.item_name(def_id);
1481+
let path_description = match kind {
1482+
Mod | ForeignMod => "inner item",
1483+
Struct => "field or associated item",
1484+
Enum | Union => "variant or associated item",
1485+
Variant
1486+
| Field
1487+
| Closure
1488+
| Generator
1489+
| AssocTy
1490+
| AssocConst
1491+
| AssocFn
1492+
| Fn
1493+
| Macro(_)
1494+
| Const
1495+
| ConstParam
1496+
| ExternCrate
1497+
| Use
1498+
| LifetimeParam
1499+
| Ctor(_, _)
1500+
| AnonConst => return assoc_item_not_allowed(res, diag),
1501+
Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
1502+
| Static => "associated item",
1503+
Impl | GlobalAsm => unreachable!("not a path"),
1504+
};
1505+
let note = format!(
1506+
"the {} `{}` has no {} named `{}`",
1507+
res.descr(),
1508+
name,
1509+
path_description,
1510+
assoc_item
1511+
);
1512+
diag.note(&note);
14761513
}
14771514
ResolutionFailure::CannotHaveAssociatedItems(res, _) => {
1478-
let (item, _) = item(res);
1479-
diag.note(&format!("this link partially resolves to {}", item));
1480-
if let Res::Def(kind, def_id) = res {
1481-
let name = cx.tcx.item_name(def_id);
1482-
let note = format!(
1483-
"`{}` is {} {}, not a module or type, and cannot have associated items",
1484-
name,
1485-
kind.article(),
1486-
kind.descr(def_id)
1487-
);
1488-
diag.note(&note);
1489-
}
1515+
assoc_item_not_allowed(res, diag)
14901516
}
14911517
// TODO: is there ever a case where this happens?
14921518
ResolutionFailure::NotAnEnum(res) => {
1493-
let (item, comma) = item(res);
14941519
let note =
1495-
format!("this link resolves to {}{} which is not an enum", item, comma);
1520+
format!("this link resolves to {}, which is not an enum", item(res));
14961521
diag.note(&note);
14971522
diag.note("if this were an enum, it might have a variant which resolved");
14981523
}
14991524
ResolutionFailure::NotAVariant(res, variant) => {
15001525
let note = format!(
15011526
"this link partially resolves to {}, but there is no variant named {}",
1502-
item(res).0,
1527+
item(res),
15031528
variant
15041529
);
15051530
diag.note(&note);

src/test/rustdoc-ui/assoc-item-not-in-scope.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ error: unresolved link to `S::fmt`
22
--> $DIR/assoc-item-not-in-scope.rs:4:14
33
|
44
LL | /// Link to [`S::fmt`]
5-
| ^^^^^^^^ unresolved link
5+
| ^^^^^^^^
66
|
77
note: the lint level is defined here
88
--> $DIR/assoc-item-not-in-scope.rs:1:9
99
|
1010
LL | #![deny(broken_intra_doc_links)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^
12-
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
12+
= note: the struct `S` has no field or associated item named `fmt`
1313

1414
error: aborting due to previous error
1515

src/test/rustdoc-ui/intra-doc-alias-ice.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ note: the lint level is defined here
99
|
1010
LL | #![deny(broken_intra_doc_links)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^
12-
= note: this link partially resolves to the type alias `TypeAlias`
13-
= note: no `hoge` in `TypeAlias`
12+
= note: the type alias `TypeAlias` has no associated item named `hoge`
1413

1514
error: aborting due to previous error
1615

src/test/rustdoc-ui/intra-link-errors.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,19 @@
1212

1313
/// [f::A]
1414
//~^ ERROR unresolved link
15-
//~| NOTE this link partially resolves
1615
//~| NOTE `f` is a function, not a module
1716

1817
/// [S::A]
1918
//~^ ERROR unresolved link
20-
//~| NOTE this link partially resolves
21-
//~| NOTE no `A` in `S`
19+
//~| NOTE struct `S` has no field or associated item
2220

2321
/// [S::fmt]
2422
//~^ ERROR unresolved link
25-
//~| NOTE this link partially resolves
26-
//~| NOTE no `fmt` in `S`
23+
//~| NOTE struct `S` has no field or associated item
2724

2825
/// [E::D]
2926
//~^ ERROR unresolved link
30-
//~| NOTE this link partially resolves
31-
//~| NOTE no `D` in `E`
27+
//~| NOTE enum `E` has no variant or associated item
3228

3329
/// [u8::not_found]
3430
//~^ ERROR unresolved link

src/test/rustdoc-ui/intra-link-errors.stderr

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,67 +13,63 @@ LL | #![deny(broken_intra_doc_links)]
1313
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
1414

1515
error: unresolved link to `f::A`
16-
--> $DIR/intra-link-errors.rs:14:6
16+
--> $DIR/intra-link-errors.rs:13:6
1717
|
1818
LL | /// [f::A]
1919
| ^^^^
2020
|
21-
= note: this link partially resolves to the function `f`
2221
= note: `f` is a function, not a module or type, and cannot have associated items
2322

2423
error: unresolved link to `S::A`
25-
--> $DIR/intra-link-errors.rs:19:6
24+
--> $DIR/intra-link-errors.rs:17:6
2625
|
2726
LL | /// [S::A]
2827
| ^^^^
2928
|
30-
= note: this link partially resolves to the struct `S`
31-
= note: no `A` in `S`
29+
= note: the struct `S` has no field or associated item named `A`
3230

3331
error: unresolved link to `S::fmt`
34-
--> $DIR/intra-link-errors.rs:24:6
32+
--> $DIR/intra-link-errors.rs:21:6
3533
|
3634
LL | /// [S::fmt]
3735
| ^^^^^^
3836
|
39-
= note: this link partially resolves to the struct `S`
40-
= note: no `fmt` in `S`
37+
= note: the struct `S` has no field or associated item named `fmt`
4138

4239
error: unresolved link to `E::D`
43-
--> $DIR/intra-link-errors.rs:29:6
40+
--> $DIR/intra-link-errors.rs:25:6
4441
|
4542
LL | /// [E::D]
4643
| ^^^^
4744
|
48-
= note: this link partially resolves to the enum `E`
49-
= note: no `D` in `E`
45+
= note: the enum `E` has no variant or associated item named `D`
5046

5147
error: unresolved link to `u8::not_found`
52-
--> $DIR/intra-link-errors.rs:34:6
48+
--> $DIR/intra-link-errors.rs:29:6
5349
|
5450
LL | /// [u8::not_found]
5551
| ^^^^^^^^^^^^^
5652
|
5753
= note: the builtin type `u8` does not have an associated item named `not_found`
5854

5955
error: unresolved link to `S`
60-
--> $DIR/intra-link-errors.rs:38:6
56+
--> $DIR/intra-link-errors.rs:33:6
6157
|
6258
LL | /// [S!]
6359
| ^^ help: to link to the struct, use its disambiguator: `struct@S`
6460
|
6561
= note: this link resolves to the struct `S`, which is not in the macro namespace
6662

6763
error: unresolved link to `T::g`
68-
--> $DIR/intra-link-errors.rs:56:6
64+
--> $DIR/intra-link-errors.rs:51:6
6965
|
7066
LL | /// [type@T::g]
7167
| ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `T::g()`
7268
|
7369
= note: this link resolves to the associated function `g`, which is not in the type namespace
7470

7571
error: unresolved link to `T::h`
76-
--> $DIR/intra-link-errors.rs:61:6
72+
--> $DIR/intra-link-errors.rs:56:6
7773
|
7874
LL | /// [T::h!]
7975
| ^^^^^
@@ -82,7 +78,7 @@ LL | /// [T::h!]
8278
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
8379

8480
error: unresolved link to `S::h`
85-
--> $DIR/intra-link-errors.rs:48:6
81+
--> $DIR/intra-link-errors.rs:43:6
8682
|
8783
LL | /// [type@S::h]
8884
| ^^^^^^^^^ help: to link to the associated function, use its disambiguator: `S::h()`

src/test/rustdoc-ui/intra-links-warning.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ LL | //! Test with [Foo::baz], [Bar::foo], ...
55
| ^^^^^^^^
66
|
77
= note: `#[warn(broken_intra_doc_links)]` on by default
8-
= note: this link partially resolves to the struct `Foo`
9-
= note: no `baz` in `Foo`
8+
= note: the struct `Foo` has no field or associated item named `baz`
109

1110
warning: unresolved link to `Bar::foo`
1211
--> $DIR/intra-links-warning.rs:3:35

src/test/rustdoc-ui/lint-group.stderr

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ error: unresolved link to `error`
3232
--> $DIR/lint-group.rs:9:29
3333
|
3434
LL | /// what up, let's make an [error]
35-
| ^^^^^ unresolved link
35+
| ^^^^^
3636
|
3737
note: the lint level is defined here
3838
--> $DIR/lint-group.rs:7:9
3939
|
4040
LL | #![deny(rustdoc)]
4141
| ^^^^^^^
4242
= note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]`
43+
= note: no item named `error` is in scope
4344
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
4445

4546
error: aborting due to 3 previous errors

0 commit comments

Comments
 (0)