diff options
| author | bors <bors@rust-lang.org> | 2021-04-12 00:38:20 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-04-12 00:38:20 +0000 |
| commit | e41f378f825488a537b024fc3ed599d9c12fda96 (patch) | |
| tree | b9d939abd2fa4e173de4c8d45d02e7c8d3033a52 /src | |
| parent | 3f8added7003120582953d4f3f43991fb3bb2798 (diff) | |
| parent | 1ff117e987be82e9cff59350fd1810ebe21f8b26 (diff) | |
Auto merge of #84112 - Dylan-DPC:rollup-tapsrzz, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #83669 (Issue 81508 fix) - #84014 (Improve trait/impl method discrepancy errors) - #84059 (Bump libc dependency of std to 0.2.93) - #84067 (clean up example on read_to_string) - #84079 (Improve test for `rustdoc::bare_urls` lint) - #84094 (Remove FixedSizeArray) - #84101 (rustdoc: Move crate loader to collect_intra_doc_links::early ) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'src')
24 files changed, 498 insertions, 182 deletions
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c9fdaa50534..be7bff1a29c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -5,8 +5,8 @@ use rustc_driver::abort_on_err; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; -use rustc_hir::def::{Namespace::TypeNS, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def::Res; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_hir::{ intravisit::{self, NestedVisitorMap, Visitor}, @@ -356,55 +356,7 @@ crate fn create_resolver<'a>( let (krate, resolver, _) = &*parts; let resolver = resolver.borrow().clone(); - // Letting the resolver escape at the end of the function leads to inconsistencies between the - // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates - // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ... - struct IntraLinkCrateLoader { - current_mod: DefId, - resolver: Rc<RefCell<interface::BoxedResolver>>, - } - impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { - fn visit_attribute(&mut self, attr: &ast::Attribute) { - use crate::html::markdown::{markdown_links, MarkdownLink}; - use crate::passes::collect_intra_doc_links::Disambiguator; - - if let Some(doc) = attr.doc_str() { - for MarkdownLink { link, .. } in markdown_links(&doc.as_str()) { - // FIXME: this misses a *lot* of the preprocessing done in collect_intra_doc_links - // I think most of it shouldn't be necessary since we only need the crate prefix? - let path_str = match Disambiguator::from_str(&link) { - Ok(x) => x.map_or(link.as_str(), |(_, p)| p), - Err(_) => continue, - }; - self.resolver.borrow_mut().access(|resolver| { - let _ = resolver.resolve_str_path_error( - attr.span, - path_str, - TypeNS, - self.current_mod, - ); - }); - } - } - ast::visit::walk_attribute(self, attr); - } - - fn visit_item(&mut self, item: &ast::Item) { - use rustc_ast_lowering::ResolverAstLowering; - - if let ast::ItemKind::Mod(..) = item.kind { - let new_mod = - self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id)); - let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id()); - ast::visit::walk_item(self, item); - self.current_mod = old_mod; - } else { - ast::visit::walk_item(self, item); - } - } - } - let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(); - let mut loader = IntraLinkCrateLoader { current_mod: crate_id, resolver }; + let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver); ast::visit::walk_crate(&mut loader, krate); loader.resolver diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4bc7544e33d..6342110adfe 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -39,13 +39,16 @@ use crate::passes::Pass; use super::span_of_attrs; +mod early; +crate use early::IntraLinkCrateLoader; + crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass { name: "collect-intra-doc-links", run: collect_intra_doc_links, description: "resolves intra-doc links", }; -crate fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { +fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { LinkCollector { cx, mod_ids: Vec::new(), @@ -892,6 +895,117 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } +enum PreprocessingError<'a> { + Anchor(AnchorFailure), + Disambiguator(Range<usize>, String), + Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>), +} + +impl From<AnchorFailure> for PreprocessingError<'_> { + fn from(err: AnchorFailure) -> Self { + Self::Anchor(err) + } +} + +struct PreprocessingInfo { + path_str: String, + disambiguator: Option<Disambiguator>, + extra_fragment: Option<String>, + link_text: String, +} + +/// Returns: +/// - `None` if the link should be ignored. +/// - `Some(Err)` if the link should emit an error +/// - `Some(Ok)` if the link is valid +/// +/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored. +fn preprocess_link<'a>( + ori_link: &'a MarkdownLink, +) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> { + // [] is mostly likely not supposed to be a link + if ori_link.link.is_empty() { + return None; + } + + // Bail early for real links. + if ori_link.link.contains('/') { + return None; + } + + let stripped = ori_link.link.replace("`", ""); + let mut parts = stripped.split('#'); + + let link = parts.next().unwrap(); + if link.trim().is_empty() { + // This is an anchor to an element of the current page, nothing to do in here! + return None; + } + let extra_fragment = parts.next(); + if parts.next().is_some() { + // A valid link can't have multiple #'s + return Some(Err(AnchorFailure::MultipleAnchors.into())); + } + + // Parse and strip the disambiguator from the link, if present. + let (path_str, disambiguator) = match Disambiguator::from_str(&link) { + Ok(Some((d, path))) => (path.trim(), Some(d)), + Ok(None) => (link.trim(), None), + Err((err_msg, relative_range)) => { + // Only report error if we would not have ignored this link. See issue #83859. + if !should_ignore_link_with_disambiguators(link) { + let no_backticks_range = range_between_backticks(&ori_link); + let disambiguator_range = (no_backticks_range.start + relative_range.start) + ..(no_backticks_range.start + relative_range.end); + return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg))); + } else { + return None; + } + } + }; + + if should_ignore_link(path_str) { + return None; + } + + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + let link_text = + disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned()); + + // Strip generics from the path. + let path_str = if path_str.contains(['<', '>'].as_slice()) { + match strip_generics_from_path(&path_str) { + Ok(path) => path, + Err(err_kind) => { + debug!("link has malformed generics: {}", path_str); + return Some(Err(PreprocessingError::Resolution( + err_kind, + path_str.to_owned(), + disambiguator, + ))); + } + } + } else { + path_str.to_owned() + }; + + // Sanity check to make sure we don't have any angle brackets after stripping generics. + assert!(!path_str.contains(['<', '>'].as_slice())); + + // The link is not an intra-doc link if it still contains spaces after stripping generics. + if path_str.contains(' ') { + return None; + } + + Some(Ok(PreprocessingInfo { + path_str, + disambiguator, + extra_fragment: extra_fragment.map(String::from), + link_text, + })) +} + impl LinkCollector<'_, '_> { /// This is the entry point for resolving an intra-doc link. /// @@ -907,16 +1021,6 @@ impl LinkCollector<'_, '_> { ) -> Option<ItemLink> { trace!("considering link '{}'", ori_link.link); - // Bail early for real links. - if ori_link.link.contains('/') { - return None; - } - - // [] is mostly likely not supposed to be a link - if ori_link.link.is_empty() { - return None; - } - let diag_info = DiagnosticInfo { item, dox, @@ -924,47 +1028,29 @@ impl LinkCollector<'_, '_> { link_range: ori_link.range.clone(), }; - let link = ori_link.link.replace("`", ""); - let no_backticks_range = range_between_backticks(&ori_link); - let parts = link.split('#').collect::<Vec<_>>(); - let (link, extra_fragment) = if parts.len() > 2 { - // A valid link can't have multiple #'s - anchor_failure(self.cx, diag_info, AnchorFailure::MultipleAnchors); - return None; - } else if parts.len() == 2 { - if parts[0].trim().is_empty() { - // This is an anchor to an element of the current page, nothing to do in here! - return None; - } - (parts[0], Some(parts[1].to_owned())) - } else { - (parts[0], None) - }; - - // Parse and strip the disambiguator from the link, if present. - let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) { - Ok(Some((d, path))) => (path.trim(), Some(d)), - Ok(None) => (link.trim(), None), - Err((err_msg, relative_range)) => { - if !should_ignore_link_with_disambiguators(link) { - // Only report error if we would not have ignored this link. - // See issue #83859. - let disambiguator_range = (no_backticks_range.start + relative_range.start) - ..(no_backticks_range.start + relative_range.end); - disambiguator_error(self.cx, diag_info, disambiguator_range, &err_msg); + let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = + match preprocess_link(&ori_link)? { + Ok(x) => x, + Err(err) => { + match err { + PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err), + PreprocessingError::Disambiguator(range, msg) => { + disambiguator_error(self.cx, diag_info, range, &msg) + } + PreprocessingError::Resolution(err, path_str, disambiguator) => { + resolution_failure( + self, + diag_info, + &path_str, + disambiguator, + smallvec![err], + ); + } + } + return None; } - return None; - } - }; - - if should_ignore_link(path_str) { - return None; - } - - // We stripped `()` and `!` when parsing the disambiguator. - // Add them back to be displayed, but not prefix disambiguators. - let link_text = - disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned()); + }; + let mut path_str = &*path_str; // In order to correctly resolve intra-doc links we need to // pick a base AST node to work from. If the documentation for @@ -1029,39 +1115,12 @@ impl LinkCollector<'_, '_> { module_id = DefId { krate, index: CRATE_DEF_INDEX }; } - // Strip generics from the path. - let stripped_path_string; - if path_str.contains(['<', '>'].as_slice()) { - stripped_path_string = match strip_generics_from_path(path_str) { - Ok(path) => path, - Err(err_kind) => { - debug!("link has malformed generics: {}", path_str); - resolution_failure( - self, - diag_info, - path_str, - disambiguator, - smallvec![err_kind], - ); - return None; - } - }; - path_str = &stripped_path_string; - } - // Sanity check to make sure we don't have any angle brackets after stripping generics. - assert!(!path_str.contains(['<', '>'].as_slice())); - - // The link is not an intra-doc link if it still contains spaces after stripping generics. - if path_str.contains(' ') { - return None; - } - let (mut res, mut fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { module_id, dis: disambiguator, path_str: path_str.to_owned(), - extra_fragment, + extra_fragment: extra_fragment.map(String::from), }, diag_info.clone(), // this struct should really be Copy, but Range is not :( matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), @@ -1438,7 +1497,7 @@ fn should_ignore_link(path_str: &str) -> bool { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] /// Disambiguators for a link. -crate enum Disambiguator { +enum Disambiguator { /// `prim@` /// /// This is buggy, see <https://github.com/rust-lang/rust/pull/77875#discussion_r503583103> @@ -1467,7 +1526,7 @@ impl Disambiguator { /// This returns `Ok(Some(...))` if a disambiguator was found, /// `Ok(None)` if no disambiguator was found, or `Err(...)` /// if there was a problem with the disambiguator. - crate fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> { + fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> { use Disambiguator::{Kind, Namespace as NS, Primitive}; if let Some(idx) = link.find('@') { diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs new file mode 100644 index 00000000000..7cba2523d1a --- /dev/null +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -0,0 +1,63 @@ +use rustc_ast as ast; +use rustc_hir::def::Namespace::TypeNS; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; +use rustc_interface::interface; + +use std::cell::RefCell; +use std::mem; +use std::rc::Rc; + +// Letting the resolver escape at the end of the function leads to inconsistencies between the +// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates +// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ... +crate struct IntraLinkCrateLoader { + current_mod: DefId, + crate resolver: Rc<RefCell<interface::BoxedResolver>>, +} + +impl IntraLinkCrateLoader { + crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self { + let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(); + Self { current_mod: crate_id, resolver } + } +} + +impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { + fn visit_attribute(&mut self, attr: &ast::Attribute) { + use crate::html::markdown::markdown_links; + use crate::passes::collect_intra_doc_links::preprocess_link; + + if let Some(doc) = attr.doc_str() { + for link in markdown_links(&doc.as_str()) { + let path_str = if let Some(Ok(x)) = preprocess_link(&link) { + x.path_str + } else { + continue; + }; + self.resolver.borrow_mut().access(|resolver| { + let _ = resolver.resolve_str_path_error( + attr.span, + &path_str, + TypeNS, + self.current_mod, + ); + }); + } + } + ast::visit::walk_attribute(self, attr); + } + + fn visit_item(&mut self, item: &ast::Item) { + use rustc_ast_lowering::ResolverAstLowering; + + if let ast::ItemKind::Mod(..) = item.kind { + let new_mod = + self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id)); + let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id()); + ast::visit::walk_item(self, item); + self.current_mod = old_mod; + } else { + ast::visit::walk_item(self, item); + } + } +} diff --git a/src/test/rustdoc-ui/bare-urls.fixed b/src/test/rustdoc-ui/bare-urls.fixed new file mode 100644 index 00000000000..23aa5c44c21 --- /dev/null +++ b/src/test/rustdoc-ui/bare-urls.fixed @@ -0,0 +1,60 @@ +// run-rustfix + +#![deny(rustdoc::bare_urls)] + +/// <https://somewhere.com> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a> +//~^ ERROR this URL is not a hyperlink +/// <https://www.somewhere.com> +//~^ ERROR this URL is not a hyperlink +/// <https://www.somewhere.com/a> +//~^ ERROR this URL is not a hyperlink +/// <https://subdomain.example.com> +//~^ ERROR not a hyperlink +/// <https://somewhere.com?> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?hello=12> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com?hello=12#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com/a?hello=12#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://example.com/a#xyz> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12&bye=11> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com/a?hello=12&bye=11> +//~^ ERROR this URL is not a hyperlink +/// <https://somewhere.com?hello=12&bye=11#xyz> +//~^ ERROR this URL is not a hyperlink +/// hey! <https://somewhere.com/a?hello=12&bye=11#xyz> +//~^ ERROR this URL is not a hyperlink +pub fn c() {} + +/// <https://somewhere.com> +/// [a](http://a.com) +/// [b] +/// +/// [b]: http://b.com +/// +/// ``` +/// This link should not be linted: http://example.com +/// +/// Nor this one: <http://example.com> or this one: [x](http://example.com) +/// ``` +/// +/// [should_not.lint](should_not.lint) +pub fn everything_is_fine_here() {} + +#[allow(rustdoc::bare_urls)] +pub mod foo { + /// https://somewhere.com/a?hello=12&bye=11#xyz + pub fn bar() {} +} diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/bare-urls.rs index 43a13b02d0a..592f57343bc 100644 --- a/src/test/rustdoc-ui/url-improvements.rs +++ b/src/test/rustdoc-ui/bare-urls.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![deny(rustdoc::bare_urls)] /// https://somewhere.com diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/bare-urls.stderr index 3d5ebd8be6b..6b612f81590 100644 --- a/src/test/rustdoc-ui/url-improvements.stderr +++ b/src/test/rustdoc-ui/bare-urls.stderr @@ -1,107 +1,107 @@ error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:3:5 + --> $DIR/bare-urls.rs:5:5 | LL | /// https://somewhere.com | ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>` | note: the lint level is defined here - --> $DIR/url-improvements.rs:1:9 + --> $DIR/bare-urls.rs:3:9 | LL | #![deny(rustdoc::bare_urls)] | ^^^^^^^^^^^^^^^^^^ error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:5:5 + --> $DIR/bare-urls.rs:7:5 | LL | /// https://somewhere.com/a | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:7:5 + --> $DIR/bare-urls.rs:9:5 | LL | /// https://www.somewhere.com | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:9:5 + --> $DIR/bare-urls.rs:11:5 | LL | /// https://www.somewhere.com/a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:11:5 + --> $DIR/bare-urls.rs:13:5 | LL | /// https://subdomain.example.com | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:13:5 + --> $DIR/bare-urls.rs:15:5 | LL | /// https://somewhere.com? | ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:15:5 + --> $DIR/bare-urls.rs:17:5 | LL | /// https://somewhere.com/a? | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:17:5 + --> $DIR/bare-urls.rs:19:5 | LL | /// https://somewhere.com?hello=12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:19:5 + --> $DIR/bare-urls.rs:21:5 | LL | /// https://somewhere.com/a?hello=12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:21:5 + --> $DIR/bare-urls.rs:23:5 | LL | /// https://example.com?hello=12#xyz | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:23:5 + --> $DIR/bare-urls.rs:25:5 | LL | /// https://example.com/a?hello=12#xyz | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:25:5 + --> $DIR/bare-urls.rs:27:5 | LL | /// https://example.com#xyz | ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:27:5 + --> $DIR/bare-urls.rs:29:5 | LL | /// https://example.com/a#xyz | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:29:5 + --> $DIR/bare-urls.rs:31:5 | LL | /// https://somewhere.com?hello=12&bye=11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:31:5 + --> $DIR/bare-urls.rs:33:5 | LL | /// https://somewhere.com/a?hello=12&bye=11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:33:5 + --> $DIR/bare-urls.rs:35:5 | LL | /// https://somewhere.com?hello=12&bye=11#xyz | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>` error: this URL is not a hyperlink - --> $DIR/url-improvements.rs:35:10 + --> $DIR/bare-urls.rs:37:10 | LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>` diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty.rs b/src/test/rustdoc/intra-doc/auxiliary/empty.rs new file mode 100644 index 00000000000..d11c69f812a --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/empty.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty2.rs b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs new file mode 100644 index 00000000000..d11c69f812a --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs index 0964c79de06..5d8dcf8bc1d 100644 --- a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs +++ b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs @@ -1,8 +1,19 @@ +// This test is just a little cursed. // aux-build:issue-66159-1.rs // aux-crate:priv:issue_66159_1=issue-66159-1.rs +// aux-build:empty.rs +// aux-crate:priv:empty=empty.rs +// aux-build:empty2.rs +// aux-crate:priv:empty2=empty2.rs // build-aux-docs -// compile-flags:-Z unstable-options +// compile-flags:-Z unstable-options --edition 2018 // @has extern_crate_only_used_in_link/index.html // @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something' //! [issue_66159_1::Something] + +// @has - '//a[@href="../empty/index.html"]' 'empty' +//! [`empty`] + +// @has - '//a[@href="../empty2/index.html"]' 'empty2' +//! [empty2<x>] diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 920f8322813..3c7dc1fc3c9 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -15,7 +15,10 @@ LL | fn make() -> Self::Ty { | -------- type in trait ... LL | fn make() -> u8 { 0 } - | ^^ expected associated type, found `u8` + | ^^ + | | + | expected associated type, found `u8` + | help: change the output type to match the trait: `<A<T> as Tr>::Ty` | = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty` found fn pointer `fn() -> u8` @@ -30,7 +33,10 @@ LL | default type Ty = bool; | ----------------------- expected this associated type LL | LL | fn make() -> bool { true } - | ^^^^ expected associated type, found `bool` + | ^^^^ + | | + | expected associated type, found `bool` + | help: change the output type to match the trait: `<B<T> as Tr>::Ty` | = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty` found fn pointer `fn() -> bool` diff --git a/src/test/ui/compare-method/bad-self-type.rs b/src/test/ui/compare-method/bad-self-type.rs new file mode 100644 index 00000000000..f42a9e49abd --- /dev/null +++ b/src/test/ui/compare-method/bad-self-type.rs @@ -0,0 +1,26 @@ +use std::future::Future; +use std::task::{Context, Poll}; + +fn main() {} + +struct MyFuture {} + +impl Future for MyFuture { + type Output = (); + fn poll(self, _: &mut Context<'_>) -> Poll<()> { + //~^ ERROR method `poll` has an incompatible type for trait + todo!() + } +} + +trait T { + fn foo(self); + fn bar(self) -> Option<()>; +} + +impl T for MyFuture { + fn foo(self: Box<Self>) {} + //~^ ERROR method `foo` has an incompatible type for trait + fn bar(self) {} + //~^ ERROR method `bar` has an incompatible type for trait +} diff --git a/src/test/ui/compare-method/bad-self-type.stderr b/src/test/ui/compare-method/bad-self-type.stderr new file mode 100644 index 00000000000..76f91fbf241 --- /dev/null +++ b/src/test/ui/compare-method/bad-self-type.stderr @@ -0,0 +1,46 @@ +error[E0053]: method `poll` has an incompatible type for trait + --> $DIR/bad-self-type.rs:10:13 + | +LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> { + | ^^^^ + | | + | expected struct `Pin`, found struct `MyFuture` + | help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>` + | + = note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>` + found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>` + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/bad-self-type.rs:22:18 + | +LL | fn foo(self); + | ---- type in trait +... +LL | fn foo(self: Box<Self>) {} + | ------^^^^^^^^^ + | | | + | | expected struct `MyFuture`, found struct `Box` + | help: change the self-receiver type to match the trait: `self` + | + = note: expected fn pointer `fn(MyFuture)` + found fn pointer `fn(Box<MyFuture>)` + +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/bad-self-type.rs:24:18 + | +LL | fn bar(self) -> Option<()>; + | ---------- type in trait +... +LL | fn bar(self) {} + | ^ expected enum `Option`, found `()` + | + = note: expected fn pointer `fn(MyFuture) -> Option<()>` + found fn pointer `fn(MyFuture)` +help: change the output type to match the trait + | +LL | fn bar(self) -> Option<()> {} + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0053`. diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index f1f8a663f21..d581628ea48 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -5,8 +5,10 @@ LL | fn b<C:Clone,D>(&self, x: C) -> C; | - type in trait ... LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() } - | - - ^ expected type parameter `F`, found type parameter `G` - | | | + | - - ^ + | | | | + | | | expected type parameter `F`, found type parameter `G` + | | | help: change the parameter type to match the trait: `F` | | found type parameter | expected type parameter | diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr index 638a0093fb2..d37670db085 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -5,8 +5,10 @@ LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug); | -- type in trait ... LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { } - | - ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug` - | | + | - ^^^^^^^^^^^ + | | | + | | expected type parameter `B`, found type parameter `impl Debug` + | | help: change the parameter type to match the trait: `&B` | expected type parameter | = note: expected fn pointer `fn(&(), &B, &impl Debug)` diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 961bb735118..bea24339837 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -1,8 +1,11 @@ error[E0053]: method `fmt` has an incompatible type for trait - --> $DIR/trait_type.rs:7:4 + --> $DIR/trait_type.rs:7:21 | LL | fn fmt(&self, x: &str) -> () { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^ + | | + | types differ in mutability + | help: change the parameter type to match the trait: `&mut Formatter<'_>` | = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` found fn pointer `fn(&MyType, &str)` diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index 57447fa48aa..6c3651ff121 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ | | | types differ in mutability - | help: consider changing the mutability to match the trait: `&mut dyn Foo` + | help: change the parameter type to match the trait: `&mut dyn Foo` | = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)` found fn pointer `fn(&mut Baz, &dyn Foo)` diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 3bcc50ded84..6f4813ca623 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -1,33 +1,42 @@ error[E0053]: method `call` has an incompatible type for trait - --> $DIR/issue-20225.rs:6:3 + --> $DIR/issue-20225.rs:6:43 | LL | impl<'a, T> Fn<(&'a T,)> for Foo { | - this type parameter LL | extern "rust-call" fn call(&self, (_,): (T,)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` + | ^^^^ + | | + | expected `&T`, found type parameter `T` + | help: change the parameter type to match the trait: `(&'a T,)` | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&Foo, (T,))` error[E0053]: method `call_mut` has an incompatible type for trait - --> $DIR/issue-20225.rs:11:3 + --> $DIR/issue-20225.rs:11:51 | LL | impl<'a, T> FnMut<(&'a T,)> for Foo { | - this type parameter LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` + | ^^^^ + | | + | expected `&T`, found type parameter `T` + | help: change the parameter type to match the trait: `(&'a T,)` | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` error[E0053]: method `call_once` has an incompatible type for trait - --> $DIR/issue-20225.rs:18:3 + --> $DIR/issue-20225.rs:18:47 | LL | impl<'a, T> FnOnce<(&'a T,)> for Foo { | - this type parameter ... LL | extern "rust-call" fn call_once(self, (_,): (T,)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` + | ^^^^ + | | + | expected `&T`, found type parameter `T` + | help: change the parameter type to match the trait: `(&'a T,)` | = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(Foo, (T,))` diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index 35863fbebe3..d92966da17c 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -1,8 +1,11 @@ error[E0053]: method `next` has an incompatible type for trait - --> $DIR/issue-21332.rs:5:5 + --> $DIR/issue-21332.rs:5:27 | LL | fn next(&mut self) -> Result<i32, i32> { Ok(7) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result` + | ^^^^^^^^^^^^^^^^ + | | + | expected enum `Option`, found enum `Result` + | help: change the output type to match the trait: `Option<i32>` | = note: expected fn pointer `fn(&mut S) -> Option<i32>` found fn pointer `fn(&mut S) -> Result<i32, i32>` diff --git a/src/test/ui/issues/issue-35869.stderr b/src/test/ui/issues/issue-35869.stderr index f80561bf6be..71b2a9df095 100644 --- a/src/test/ui/issues/issue-35869.stderr +++ b/src/test/ui/issues/issue-35869.stderr @@ -5,7 +5,10 @@ LL | fn foo(_: fn(u8) -> ()); | ------------ type in trait ... LL | fn foo(_: fn(u16) -> ()) {} - | ^^^^^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^^^^^ + | | + | expected `u8`, found `u16` + | help: change the parameter type to match the trait: `fn(u8)` | = note: expected fn pointer `fn(fn(u8))` found fn pointer `fn(fn(u16))` @@ -17,7 +20,10 @@ LL | fn bar(_: Option<u8>); | ---------- type in trait ... LL | fn bar(_: Option<u16>) {} - | ^^^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^^^ + | | + | expected `u8`, found `u16` + | help: change the parameter type to match the trait: `Option<u8>` | = note: expected fn pointer `fn(Option<u8>)` found fn pointer `fn(Option<u16>)` @@ -29,7 +35,10 @@ LL | fn baz(_: (u8, u16)); | --------- type in trait ... LL | fn baz(_: (u16, u16)) {} - | ^^^^^^^^^^ expected `u8`, found `u16` + | ^^^^^^^^^^ + | | + | expected `u8`, found `u16` + | help: change the parameter type to match the trait: `(u8, u16)` | = note: expected fn pointer `fn((u8, _))` found fn pointer `fn((u16, _))` @@ -41,7 +50,10 @@ LL | fn qux() -> u8; | -- type in trait ... LL | fn qux() -> u16 { 5u16 } - | ^^^ expected `u8`, found `u16` + | ^^^ + | | + | expected `u8`, found `u16` + | help: change the output type to match the trait: `u8` | = note: expected fn pointer `fn() -> u8` found fn pointer `fn() -> u16` diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index e0a3ce922b9..6ce8126b9f9 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -5,7 +5,10 @@ LL | fn foo(x: u16); | --- type in trait ... LL | fn foo(x: i16) { } - | ^^^ expected `u16`, found `i16` + | ^^^ + | | + | expected `u16`, found `i16` + | help: change the parameter type to match the trait: `u16` | = note: expected fn pointer `fn(u16)` found fn pointer `fn(i16)` @@ -20,7 +23,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ | | | types differ in mutability - | help: consider changing the mutability to match the trait: `&self` + | help: change the self-receiver type to match the trait: `self: &Bar` | = note: expected fn pointer `fn(&Bar)` found fn pointer `fn(&mut Bar)` diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 161843473b6..2ac4d1c33a9 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -5,7 +5,10 @@ LL | fn foo(x: u16); | --- type in trait ... LL | fn foo(x: i16) { } - | ^^^ expected `u16`, found `i16` + | ^^^ + | | + | expected `u16`, found `i16` + | help: change the parameter type to match the trait: `u16` | = note: expected fn pointer `fn(u16)` found fn pointer `fn(i16)` @@ -20,7 +23,7 @@ LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ | | | types differ in mutability - | help: consider changing the mutability to match the trait: `&mut Bar` + | help: change the parameter type to match the trait: `&mut Bar` | = note: expected fn pointer `fn(&mut Bar, &mut Bar)` found fn pointer `fn(&mut Bar, &Bar)` diff --git a/src/test/ui/resolve/issue-81508.rs b/src/test/ui/resolve/issue-81508.rs new file mode 100644 index 00000000000..23605cd2fd9 --- /dev/null +++ b/src/test/ui/resolve/issue-81508.rs @@ -0,0 +1,22 @@ +// Confusing diagnostic when using variable as a type: +// +// Previous warnings indicate Foo is not used, when in fact it is +// used improperly as a variable or constant. New warning points +// out user may be trying to use variable as a type. Test demonstrates +// cases for both local variable and const. + +fn main() { + let Baz: &str = ""; + + println!("{}", Baz::Bar); //~ ERROR: failed to resolve: use of undeclared type `Baz` +} + +#[allow(non_upper_case_globals)] +pub const Foo: &str = ""; + +mod submod { + use super::Foo; + fn function() { + println!("{}", Foo::Bar); //~ ERROR: failed to resolve: use of undeclared type `Foo` + } +} diff --git a/src/test/ui/resolve/issue-81508.stderr b/src/test/ui/resolve/issue-81508.stderr new file mode 100644 index 00000000000..15555631b90 --- /dev/null +++ b/src/test/ui/resolve/issue-81508.stderr @@ -0,0 +1,21 @@ +error[E0433]: failed to resolve: use of undeclared type `Baz` + --> $DIR/issue-81508.rs:11:20 + | +LL | let Baz: &str = ""; + | --- help: `Baz` is defined here, but is not a type +LL | +LL | println!("{}", Baz::Bar); + | ^^^ use of undeclared type `Baz` + +error[E0433]: failed to resolve: use of undeclared type `Foo` + --> $DIR/issue-81508.rs:20:24 + | +LL | use super::Foo; + | ---------- help: `Foo` is defined here, but is not a type +LL | fn function() { +LL | println!("{}", Foo::Bar); + | ^^^ use of undeclared type `Foo` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index 4c367fb9e9c..9f8896f01ee 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -1,26 +1,35 @@ error[E0053]: method `mul` has an incompatible type for trait - --> $DIR/wrong-mul-method-signature.rs:16:5 + --> $DIR/wrong-mul-method-signature.rs:16:21 | LL | fn mul(self, s: &f64) -> Vec1 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64` + | ^^^^ + | | + | expected `f64`, found `&f64` + | help: change the parameter type to match the trait: `f64` | = note: expected fn pointer `fn(Vec1, f64) -> Vec1` found fn pointer `fn(Vec1, &f64) -> Vec1` error[E0053]: method `mul` has an incompatible type for trait - --> $DIR/wrong-mul-method-signature.rs:33:5 + --> $DIR/wrong-mul-method-signature.rs:33:21 | LL | fn mul(self, s: f64) -> Vec2 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found `f64` + | ^^^ + | | + | expected struct `Vec2`, found `f64` + | help: change the parameter type to match the trait: `Vec2` | = note: expected fn pointer `fn(Vec2, Vec2) -> f64` found fn pointer `fn(Vec2, f64) -> Vec2` error[E0053]: method `mul` has an incompatible type for trait - --> $DIR/wrong-mul-method-signature.rs:52:5 + --> $DIR/wrong-mul-method-signature.rs:52:29 | LL | fn mul(self, s: f64) -> f64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `f64` + | ^^^ + | | + | expected `i32`, found `f64` + | help: change the output type to match the trait: `i32` | = note: expected fn pointer `fn(Vec3, _) -> i32` found fn pointer `fn(Vec3, _) -> f64` |
