Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve suggestions for broken intra-doc links #75756

Merged
merged 25 commits into from
Sep 12, 2020

Conversation

jyn514
Copy link
Member

@jyn514 jyn514 commented Aug 20, 2020

Depends on #74489 and should not be merged before that PR. Merged 🎉
Depends on #75916 and should not be merged before. Merged

Fixes #75305.

This does a lot of different things 😆.

  • Add PerNS::into_iter() so I didn't have to keep rewriting hacks around it. Also add PerNS::iter() for consistency. Let me know if this should be impl IntoIterator instead.
  • Make ResolutionFailure an enum instead of a unit variant. This was most of the changes: everywhere that said ErrorKind::ResolutionFailure now has to say why the link failed to resolve.
  • Store the resolution in case of an anchor failure. Previously this was implemented as variants on AnchorFailure which was prone to typos and had inconsistent output compared to the rest of the diagnostics.
  • Turn some Errors into unwrap() or panic()s, because they're rustdoc bugs and not user error. These have comments as to why they're bugs (in particular this would have caught Intra-doc links are unresolved on pub use _ as _ items #76073 as a bug a while ago).
  • If an item is not in scope at all, say the first segment in the path that failed to resolve
  • If an item exists but not in the current namespaces, say that and suggests linking to that namespace.
  • If there is a partial resolution for an item (part of the segments resolved, but not all of them), say the partial resolution and why the following segment didn't resolve.
  • Add the DefId of associated items to kind_side_channel so it can be used for diagnostics (tl;dr of the hack: the rest of rustdoc expects the id of the item, but for diagnostics we need the associated item).
  • No longer suggests escaping the brackets for every link that failed to resolve; this was pretty obnoxious. Now it only suggests \[ \] if no segment resolved and there is no :: in the link.
  • Add Suggestion, which says what to prefix the link with, not just 'prefix with the item kind'.

Places where this is currently buggy:

All outdated

1. When the link has the wrong namespace: Now fixed.

/// [type@S::h]
impl S {
	pub fn h() {}
}

/// [type@T::g]
pub trait T {
	fn g() {}
}
error: unresolved link to `T::g`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:53:6
   |
53 | /// [type@T::g]
   |      ^^^^^^^^^
   |
   = note: this link partially resolves to the trait `T`,
   = note: `T` has no field, variant, or associated item named `g`

error: unresolved link to `S::h`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:48:6
   |
48 | /// [type@S::h]
   |      ^^^^^^^^^
   |
   = note: this link partially resolves to the struct `S`,
   = note: `S` has no field, variant, or associated item named `h`

Instead it should suggest changing the disambiguator, the way it currently does for macros:

error: unresolved link to `S`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:38:6
   |
38 | /// [S!]
   |      ^^ help: to link to the unit struct, use its disambiguator: `value@S`
   |
   = note: this link resolves to the unit struct `S`, which is not in the macro namespace
  1. Associated items for values. It says that the value isn't in scope; instead it should say that values can't have associated items. Fixed.
error: unresolved link to `f::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:14:6
   |
14 | /// [f::A]
   |      ^^^^
   |
   = note: no item named `f` is in scope
   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`

This is mostly fixed, it now says

warning: unresolved link to `f::A`
 --> /home/joshua/test-rustdoc/f.rs:1:6
  |
1 | /// [f::A]
  |      ^^^^
  |
  = note: this link partially resolves to the function `f`
  = note: `f` is a function, not a module

'function, not a module' seems awfully terse when what I actually mean is ':: isn't allowed here', though.

It looks a lot nicer now, it says

error: unresolved link to `f::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:13:6
   |
13 | /// [f::A]
   |      ^^^^
   |
   = note: `f` is a function, not a module or type, and cannot have associated items
  1. I'm also not very happy with the second note for this error:
``` error: unresolved link to `S::A` --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:19:6 | 19 | /// [S::A] | ^^^^ | = note: this link partially resolves to the struct `S`, = note: `S` has no field, variant, or associated item named `A` ```

but I'm not sure how better to word it.

I ended up going with 'no A in S' to match rustc_resolve but that seems terse as well.

This now says

error: unresolved link to `S::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:17:6
   |
17 | /// [S::A]
   |      ^^^^
   |
   = note: the struct `S` has no field or associated item named `A`

which I think looks pretty good :)

  1. This is minor, but it would be nice to say that path wasn't found instead of the full thing:
error: unresolved link to `path::to::nonexistent::module`
 --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:8:6
  |
8 | /// [path::to::nonexistent::module]
  |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It will now look at most 3 paths up (so it reports path::to as not in scope), but it doesn't work with arbitrarily many paths.

I recommend only reviewing the last few commits - the first 7 are all from #74489. Rebased so that only the relevant commits are shown. Let me know if I should squash the history some more.

r? @estebank

@jyn514 jyn514 added T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. A-diagnostics Area: Messages for errors, warnings, and lints A-intra-doc-links Area: Intra-doc links, the ability to link to items in docs by name A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. labels Aug 20, 2020
@rust-highfive

This comment has been minimized.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 20, 2020
@jyn514 jyn514 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 20, 2020
@jyn514 jyn514 force-pushed the diagnostic-suggestions branch 2 times, most recently from 8c40d00 to 1f28ca0 Compare August 21, 2020 04:31
@jyn514 jyn514 force-pushed the diagnostic-suggestions branch 2 times, most recently from e040d3b to a945a3a Compare August 21, 2020 20:41
@jyn514 jyn514 changed the title [WIP] Improve suggestions for broken intra-doc links Improve suggestions for broken intra-doc links Aug 21, 2020
@jyn514

This comment has been minimized.

@jyn514 jyn514 added S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 21, 2020
@bors

This comment has been minimized.

@jyn514 jyn514 force-pushed the diagnostic-suggestions branch 2 times, most recently from 2a19ba4 to 1c257d5 Compare August 24, 2020 01:47
@jyn514
Copy link
Member Author

jyn514 commented Aug 24, 2020

@estebank This is ready for review.

@jyn514 jyn514 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. labels Aug 24, 2020
@bors

This comment has been minimized.

Copy link
Member Author

@jyn514 jyn514 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left myself some comments 😆

src/librustdoc/passes/collect_intra_doc_links.rs Outdated Show resolved Hide resolved
This is both more specific and easier to read.
Previously, this called `check_full_res` for values and types, but not
macros. This would result in not showing when there was a partial
resolution for a parent of the item.

This now calls `check_full_res`. Additionally, it checks if there was a
disambiguator, and if so, says that specific kind wasn't found instead
of saying generically 'associated item'.
Moves this detection into `resolution_failure` to avoid doing
unnecessary work and make the control flow a little easier to work with.
@jyn514
Copy link
Member Author

jyn514 commented Sep 8, 2020

ping @estebank, it's been a week or so. I know this is a bit of a giant PR - would it be easier to only review the diagnostics themselves and I can get a rustdoc member to review the logic changes?

@estebank
Copy link
Contributor

Sorry, reviewing.

Copy link
Contributor

@estebank estebank left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it comes to the diagnostic output, the main change I'd make is turn the new notes into the main span_label. Ideally, we would create a new span for cases like [foo::bar] to point only at the part of the path that is problematic, be it foo or bar, but that can be addressed later.

src/librustdoc/passes/collect_intra_doc_links.rs Outdated Show resolved Hide resolved
src/librustdoc/passes/collect_intra_doc_links.rs Outdated Show resolved Hide resolved
src/test/rustdoc-ui/assoc-item-not-in-scope.stderr Outdated Show resolved Hide resolved
src/test/rustdoc-ui/intra-doc-alias-ice.stderr Outdated Show resolved Hide resolved
src/test/rustdoc-ui/intra-link-errors.stderr Outdated Show resolved Hide resolved
This decreases the size of the `Result`s being returned,
improving performance in the common case.
This puts the error message closer to the link, making it easier to see
what went wrong.
'not in scope' -> 'not in `module`'
@estebank
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Sep 11, 2020

📌 Commit 5ea3eaf has been approved by estebank

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 11, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Sep 12, 2020
…tebank

Improve suggestions for broken intra-doc links

~~Depends on rust-lang#74489 and should not be merged before that PR.~~ Merged 🎉
~~Depends on rust-lang#75916 and should not be merged before.~~ Merged

Fixes rust-lang#75305.

This does a lot of different things 😆.

- Add `PerNS::into_iter()` so I didn't have to keep rewriting hacks around it. Also add `PerNS::iter()` for consistency. Let me know if this should be `impl IntoIterator` instead.
- Make `ResolutionFailure` an enum instead of a unit variant. This was most of the changes: everywhere that said `ErrorKind::ResolutionFailure` now has to say _why_ the link failed to resolve.
- Store the resolution in case of an anchor failure. Previously this was implemented as variants on `AnchorFailure` which was prone to typos and had inconsistent output compared to the rest of the diagnostics.
- Turn some `Err`ors into unwrap() or panic()s, because they're rustdoc bugs and not user error. These have comments as to why they're bugs (in particular this would have caught rust-lang#76073 as a bug a while ago).
- If an item is not in scope at all, say the first segment in the path that failed to resolve
- If an item exists but not in the current namespaces, say that and suggests linking to that namespace.
- If there is a partial resolution for an item (part of the segments resolved, but not all of them), say the partial resolution and why the following segment didn't resolve.
- Add the `DefId` of associated items to `kind_side_channel` so it can be used for diagnostics (tl;dr of the hack: the rest of rustdoc expects the id of the item, but for diagnostics we need the associated item).
- No longer suggests escaping the brackets for every link that failed to resolve; this was pretty obnoxious. Now it only suggests `\[ \]` if no segment resolved and there is no `::` in the link.
- Add `Suggestion`, which says _what_ to prefix the link with, not just 'prefix with the item kind'.

Places where this is currently buggy:

<details><summary>All outdated</summary>

~~1. When the link has the wrong namespace:~~ Now fixed.

<details>

```rust
/// [type@S::h]
impl S {
	pub fn h() {}
}

/// [type@T::g]
pub trait T {
	fn g() {}
}
```
```
error: unresolved link to `T::g`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:53:6
   |
53 | /// [type@T::g]
   |      ^^^^^^^^^
   |
   = note: this link partially resolves to the trait `T`,
   = note: `T` has no field, variant, or associated item named `g`

error: unresolved link to `S::h`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:48:6
   |
48 | /// [type@S::h]
   |      ^^^^^^^^^
   |
   = note: this link partially resolves to the struct `S`,
   = note: `S` has no field, variant, or associated item named `h`
```
Instead it should suggest changing the disambiguator, the way it currently does for macros:
```
error: unresolved link to `S`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:38:6
   |
38 | /// [S!]
   |      ^^ help: to link to the unit struct, use its disambiguator: `value@S`
   |
   = note: this link resolves to the unit struct `S`, which is not in the macro namespace
```

</details>

2. ~~Associated items for values. It says that the value isn't in scope; instead it should say that values can't have associated items.~~ Fixed.

<details>

```
error: unresolved link to `f::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:14:6
   |
14 | /// [f::A]
   |      ^^^^
   |
   = note: no item named `f` is in scope
   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
```
This is _mostly_ fixed, it now says

```rust
warning: unresolved link to `f::A`
 --> /home/joshua/test-rustdoc/f.rs:1:6
  |
1 | /// [f::A]
  |      ^^^^
  |
  = note: this link partially resolves to the function `f`
  = note: `f` is a function, not a module
```

'function, not a module' seems awfully terse when what I actually mean is '`::` isn't allowed here', though.

</details>

It looks a lot nicer now, it says

```
error: unresolved link to `f::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:13:6
   |
13 | /// [f::A]
   |      ^^^^
   |
   = note: `f` is a function, not a module or type, and cannot have associated items
```

3. ~~I'm also not very happy with the second note for this error:~~

<details>
```
error: unresolved link to `S::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:19:6
   |
19 | /// [S::A]
   |      ^^^^
   |
   = note: this link partially resolves to the struct `S`,
   = note: `S` has no field, variant, or associated item named `A`
```

but I'm not sure how better to word it.

I ended up going with 'no `A` in `S`' to match `rustc_resolve` but that seems terse as well.

</details>

This now says

```
error: unresolved link to `S::A`
  --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:17:6
   |
17 | /// [S::A]
   |      ^^^^
   |
   = note: the struct `S` has no field or associated item named `A`
```

which I think looks pretty good :)

4. This is minor, but it would be nice to say that `path` wasn't found instead of the full thing:
```
error: unresolved link to `path::to::nonexistent::module`
 --> /home/joshua/rustc/src/test/rustdoc-ui/intra-link-errors.rs:8:6
  |
8 | /// [path::to::nonexistent::module]
  |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

It will now look at most 3 paths up (so it reports `path::to` as not in scope), but it doesn't work with arbitrarily many paths.

</details>

~~I recommend only reviewing the last few commits - the first 7 are all from rust-lang#74489.~~ Rebased so that only the relevant commits are shown. Let me know if I should squash the history some more.

r? @estebank
@bors
Copy link
Contributor

bors commented Sep 12, 2020

⌛ Testing commit 5ea3eaf with merge 0f5c769...

@bors
Copy link
Contributor

bors commented Sep 12, 2020

☀️ Test successful - checks-actions, checks-azure
Approved by: estebank
Pushing 0f5c769 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Sep 12, 2020
@bors bors merged commit 0f5c769 into rust-lang:master Sep 12, 2020
@rustbot rustbot added this to the 1.48.0 milestone Sep 12, 2020
@jyn514 jyn514 deleted the diagnostic-suggestions branch September 12, 2020 12:53
@jyn514
Copy link
Member Author

jyn514 commented Sep 12, 2020

Thanks so much for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-intra-doc-links Area: Intra-doc links, the ability to link to items in docs by name A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve diagnostics when intra-doc-resolution fails
5 participants