From 7e79c575e9676e27d2ccee3ef40b177a99a86cea Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 9 Dec 2022 12:26:01 +0000 Subject: [PATCH 1/8] Help rust-analyzer normalize query return types --- compiler/rustc_middle/src/query/keys.rs | 98 ++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 880632561b9e8..a96bc115e3b45 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -15,7 +15,7 @@ use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { - type CacheSelector = DefaultCacheSelector; + type CacheSelector; /// Given an instance of this key, what crate is it referring to? /// This is used to find the provider. @@ -37,6 +37,8 @@ pub trait Key: Sized { } impl Key for () { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -48,6 +50,8 @@ impl Key for () { } impl<'tcx> Key for ty::InstanceDef<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -59,6 +63,8 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } impl<'tcx> Key for ty::Instance<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -70,6 +76,8 @@ impl<'tcx> Key for ty::Instance<'tcx> { } impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -81,6 +89,8 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } impl<'tcx> Key for (Ty<'tcx>, Option>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -92,6 +102,8 @@ impl<'tcx> Key for (Ty<'tcx>, Option>) { } impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -145,6 +157,8 @@ impl Key for LocalDefId { } impl Key for DefId { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.krate == LOCAL_CRATE @@ -159,6 +173,8 @@ impl Key for DefId { } impl Key for ty::WithOptConstParam { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -169,6 +185,8 @@ impl Key for ty::WithOptConstParam { } impl Key for SimplifiedType { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -179,6 +197,8 @@ impl Key for SimplifiedType { } impl Key for (DefId, DefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -189,6 +209,8 @@ impl Key for (DefId, DefId) { } impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -199,6 +221,8 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { } impl Key for (DefId, LocalDefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -209,6 +233,8 @@ impl Key for (DefId, LocalDefId) { } impl Key for (LocalDefId, DefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -219,6 +245,8 @@ impl Key for (LocalDefId, DefId) { } impl Key for (LocalDefId, LocalDefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -229,6 +257,8 @@ impl Key for (LocalDefId, LocalDefId) { } impl Key for (DefId, Option) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -243,6 +273,8 @@ impl Key for (DefId, Option) { } impl Key for (DefId, LocalDefId, Ident) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -253,6 +285,8 @@ impl Key for (DefId, LocalDefId, Ident) { } impl Key for (CrateNum, DefId) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0 == LOCAL_CRATE @@ -263,6 +297,8 @@ impl Key for (CrateNum, DefId) { } impl Key for (CrateNum, SimplifiedType) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0 == LOCAL_CRATE @@ -273,6 +309,8 @@ impl Key for (CrateNum, SimplifiedType) { } impl Key for (DefId, SimplifiedType) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -283,6 +321,8 @@ impl Key for (DefId, SimplifiedType) { } impl<'tcx> Key for SubstsRef<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -293,6 +333,8 @@ impl<'tcx> Key for SubstsRef<'tcx> { } impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.krate == LOCAL_CRATE @@ -303,6 +345,8 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { (self.0).def.did.krate == LOCAL_CRATE @@ -313,6 +357,8 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { } impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -323,6 +369,8 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { } impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.1.def_id().krate == LOCAL_CRATE @@ -333,6 +381,8 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -343,6 +393,8 @@ impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { } impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -353,6 +405,8 @@ impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { } impl<'tcx> Key for ty::PolyTraitRef<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.def_id().krate == LOCAL_CRATE @@ -363,6 +417,8 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { } impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.def_id().krate == LOCAL_CRATE @@ -373,6 +429,8 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { } impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.0.def_id().krate == LOCAL_CRATE @@ -383,6 +441,8 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { } impl<'tcx> Key for GenericArg<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -393,6 +453,8 @@ impl<'tcx> Key for GenericArg<'tcx> { } impl<'tcx> Key for mir::ConstantKind<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -403,6 +465,8 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { } impl<'tcx> Key for ty::Const<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -413,6 +477,8 @@ impl<'tcx> Key for ty::Const<'tcx> { } impl<'tcx> Key for Ty<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -429,6 +495,8 @@ impl<'tcx> Key for Ty<'tcx> { } impl<'tcx> Key for TyAndLayout<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -439,6 +507,8 @@ impl<'tcx> Key for TyAndLayout<'tcx> { } impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -449,6 +519,8 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { } impl<'tcx> Key for &'tcx ty::List> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -459,6 +531,8 @@ impl<'tcx> Key for &'tcx ty::List> { } impl<'tcx> Key for ty::ParamEnv<'tcx> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -469,6 +543,8 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { self.value.query_crate_is_local() @@ -479,6 +555,8 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { } impl Key for Symbol { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -489,6 +567,8 @@ impl Key for Symbol { } impl Key for Option { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -501,6 +581,8 @@ impl Key for Option { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. impl<'tcx, T> Key for Canonical<'tcx, T> { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -512,6 +594,8 @@ impl<'tcx, T> Key for Canonical<'tcx, T> { } impl Key for (Symbol, u32, u32) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -523,6 +607,8 @@ impl Key for (Symbol, u32, u32) { } impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -534,6 +620,8 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { } impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -545,6 +633,8 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { } impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -556,6 +646,8 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List>) { } impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -567,6 +659,8 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List>) { } impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -578,6 +672,8 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { } impl Key for HirId { + type CacheSelector = DefaultCacheSelector; + #[inline(always)] fn query_crate_is_local(&self) -> bool { true From d0db3279ab251db3612204cc1e3f386e8beae996 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Dec 2022 18:00:56 +0000 Subject: [PATCH 2/8] Don't bug if we're trying to cast dyn* to a nother type --- compiler/rustc_hir_typeck/src/cast.rs | 4 +++- src/test/ui/dyn-star/dyn-to-rigid.rs | 11 +++++++++++ src/test/ui/dyn-star/dyn-to-rigid.stderr | 9 +++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/dyn-star/dyn-to-rigid.rs create mode 100644 src/test/ui/dyn-star/dyn-to-rigid.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index b050ad20afbdb..042a50f2fd42e 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -847,13 +847,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), - (_, DynStar) | (DynStar, _) => { + (_, DynStar) => { if fcx.tcx.features().dyn_star { bug!("should be handled by `try_coerce`") } else { Err(CastError::IllegalCast) } } + + (DynStar, _) => Err(CastError::IllegalCast), } } diff --git a/src/test/ui/dyn-star/dyn-to-rigid.rs b/src/test/ui/dyn-star/dyn-to-rigid.rs new file mode 100644 index 0000000000000..e80ee15902eef --- /dev/null +++ b/src/test/ui/dyn-star/dyn-to-rigid.rs @@ -0,0 +1,11 @@ +#![feature(dyn_star)] +#![allow(incomplete_features)] + +trait Tr {} + +fn f(x: dyn* Tr) -> usize { + x as usize + //~^ ERROR casting `(dyn* Tr + 'static)` as `usize` is invalid +} + +fn main() {} diff --git a/src/test/ui/dyn-star/dyn-to-rigid.stderr b/src/test/ui/dyn-star/dyn-to-rigid.stderr new file mode 100644 index 0000000000000..588e6d97e5ca3 --- /dev/null +++ b/src/test/ui/dyn-star/dyn-to-rigid.stderr @@ -0,0 +1,9 @@ +error[E0606]: casting `(dyn* Tr + 'static)` as `usize` is invalid + --> $DIR/dyn-to-rigid.rs:7:5 + | +LL | x as usize + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0606`. From bcaf210575f8b8ca4ea7fd37ef2ef40e7c263ad9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Dec 2022 18:24:21 +0000 Subject: [PATCH 3/8] bail in collect_trait_impl_trait_tys if signatures reference errors --- .../src/check/compare_method.rs | 2 ++ .../ui/async-await/in-trait/bad-signatures.rs | 16 ++++++++++++ .../in-trait/bad-signatures.stderr | 26 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/test/ui/async-await/in-trait/bad-signatures.rs create mode 100644 src/test/ui/async-await/in-trait/bad-signatures.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index ba7d31cea2e2f..13bd034a7b559 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -373,6 +373,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( tcx.fn_sig(impl_m.def_id), ), ); + impl_sig.error_reported()?; let impl_return_ty = impl_sig.output(); // Normalize the trait signature with liberated bound vars, passing it through @@ -387,6 +388,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( ) .fold_with(&mut collector); let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); + trait_sig.error_reported()?; let trait_return_ty = trait_sig.output(); let wf_tys = FxIndexSet::from_iter( diff --git a/src/test/ui/async-await/in-trait/bad-signatures.rs b/src/test/ui/async-await/in-trait/bad-signatures.rs new file mode 100644 index 0000000000000..b86f1d1c13585 --- /dev/null +++ b/src/test/ui/async-await/in-trait/bad-signatures.rs @@ -0,0 +1,16 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete + +trait MyTrait { + async fn bar(&abc self); + //~^ ERROR expected identifier, found keyword `self` + //~| ERROR expected one of `:`, `@`, or `|`, found keyword `self` +} + +impl MyTrait for () { + async fn bar(&self) {} +} + +fn main() {} diff --git a/src/test/ui/async-await/in-trait/bad-signatures.stderr b/src/test/ui/async-await/in-trait/bad-signatures.stderr new file mode 100644 index 0000000000000..e0ba7b53ec415 --- /dev/null +++ b/src/test/ui/async-await/in-trait/bad-signatures.stderr @@ -0,0 +1,26 @@ +error: expected identifier, found keyword `self` + --> $DIR/bad-signatures.rs:7:23 + | +LL | async fn bar(&abc self); + | ^^^^ expected identifier, found keyword + +error: expected one of `:`, `@`, or `|`, found keyword `self` + --> $DIR/bad-signatures.rs:7:23 + | +LL | async fn bar(&abc self); + | -----^^^^ + | | | + | | expected one of `:`, `@`, or `|` + | help: declare the type after the parameter binding: `: ` + +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-signatures.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 2 previous errors; 1 warning emitted + From 14b508fbec6d9fdebda3397b0df908d829bbdb0b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Dec 2022 14:51:48 +0100 Subject: [PATCH 4/8] Don't add "Read more" link if there is no extra content --- src/librustdoc/html/markdown.rs | 27 +++++++++++++++++++++------ src/librustdoc/html/render/mod.rs | 5 +++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b141820fe423c..aeaee524fd453 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -567,11 +567,12 @@ struct SummaryLine<'a, I: Iterator>> { inner: I, started: bool, depth: u32, + skipped_tags: u32, } impl<'a, I: Iterator>> SummaryLine<'a, I> { fn new(iter: I) -> Self { - SummaryLine { inner: iter, started: false, depth: 0 } + SummaryLine { inner: iter, started: false, depth: 0, skipped_tags: 0 } } } @@ -601,6 +602,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { let is_allowed_tag = match event { Event::Start(ref c) => { if is_forbidden_tag(c) { + self.skipped_tags += 1; return None; } self.depth += 1; @@ -608,6 +610,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { } Event::End(ref c) => { if is_forbidden_tag(c) { + self.skipped_tags += 1; return None; } self.depth -= 1; @@ -616,6 +619,9 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { } _ => true, }; + if !is_allowed_tag { + self.skipped_tags += 1; + } return if !is_allowed_tag { if is_start { Some(Event::Start(Tag::Paragraph)) @@ -1096,11 +1102,11 @@ impl MarkdownItemInfo<'_> { } impl MarkdownSummaryLine<'_> { - pub(crate) fn into_string(self) -> String { + pub(crate) fn into_string_with_has_more_content(self) -> (String, bool) { let MarkdownSummaryLine(md, links) = self; // This is actually common enough to special-case if md.is_empty() { - return String::new(); + return (String::new(), false); } let mut replacer = |broken_link: BrokenLink<'_>| { @@ -1110,17 +1116,26 @@ impl MarkdownSummaryLine<'_> { .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) }; - let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); + let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)) + .peekable(); + let mut summary = SummaryLine::new(p); let mut s = String::new(); - let without_paragraphs = LinkReplacer::new(SummaryLine::new(p), links).filter(|event| { + let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| { !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) }); html::push_html(&mut s, without_paragraphs); - s + let has_more_content = + matches!(summary.inner.peek(), Some(Event::Start(_))) || summary.skipped_tags > 0; + + (s, has_more_content) + } + + pub(crate) fn into_string(self) -> String { + self.into_string_with_has_more_content().0 } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 80fbe9c1f066c..146e5010e4e42 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -467,9 +467,10 @@ fn document_short( return; } if let Some(s) = item.doc_value() { - let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string(); + let (mut summary_html, has_more_content) = + MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); - if s.contains('\n') { + if has_more_content { let link = format!(r#" Read more"#, assoc_href_attr(item, link, cx)); if let Some(idx) = summary_html.rfind("

") { From 80059e1b7274fc7ba8d9201ea075fd1c7b7608f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 16 Dec 2022 14:52:25 +0100 Subject: [PATCH 5/8] Add test for presence of read more links --- src/test/rustdoc/read-more-unneeded.rs | 34 ++++++++++++++++++++++++++ src/test/rustdoc/trait-impl.rs | 2 -- 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc/read-more-unneeded.rs diff --git a/src/test/rustdoc/read-more-unneeded.rs b/src/test/rustdoc/read-more-unneeded.rs new file mode 100644 index 0000000000000..0303e44426141 --- /dev/null +++ b/src/test/rustdoc/read-more-unneeded.rs @@ -0,0 +1,34 @@ +// Regression test for https://github.com/rust-lang/rust/issues/105677. +// This test ensures that the "Read more" link is only generated when +// there is actually more documentation to read after the short summary. + +#![crate_name = "foo"] + +pub trait MyFrom { + /// # Hello + /// ## Yolo + /// more! + fn try_from1(); + /// a + /// b + /// c + fn try_from2(); + /// a + /// + /// b + /// + /// c + fn try_from3(); +} + +pub struct NonZero; + +// @has 'foo/struct.NonZero.html' +impl MyFrom for NonZero { + // @matches - '//*[@class="docblock"]' '^Hello Read more$' + fn try_from1() {} + // @matches - '//*[@class="docblock"]' '^a\sb\sc$' + fn try_from2() {} + // @matches - '//*[@class="docblock"]' '^a Read more$' + fn try_from3() {} +} diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs index 195cdf009b993..9cf3226f738c8 100644 --- a/src/test/rustdoc/trait-impl.rs +++ b/src/test/rustdoc/trait-impl.rs @@ -30,8 +30,6 @@ impl Trait for Struct { // @has - '//*[@id="method.b"]/../../div[@class="docblock"]' 'These docs contain' // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'reference link' // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'https://example.com' - // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a' 'Read more' - // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.b' fn b() {} // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]' 'code block' From 08a0e71ec9de799f9d867348c24e1193b570d159 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 16 Dec 2022 04:05:26 +0000 Subject: [PATCH 6/8] Detect inherent associated types not having CamelCase Fixes #105341. --- compiler/rustc_lint/src/nonstandard_style.rs | 12 +++++++++++- src/test/ui/associated-inherent-types/style.rs | 12 ++++++++++++ src/test/ui/associated-inherent-types/style.stderr | 14 ++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/associated-inherent-types/style.rs create mode 100644 src/test/ui/associated-inherent-types/style.stderr diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 7e50801f80c7b..91fcd6d690ee7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -175,13 +175,23 @@ impl EarlyLintPass for NonCamelCaseTypes { return; } - match it.kind { + match &it.kind { ast::ItemKind::TyAlias(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident), ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident), ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident), + + // N.B. This check is only for inherent associated types, so that we don't lint against + // trait impls where we should have warned for the trait definition already. + ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => { + for it in items { + if let ast::AssocItemKind::Type(..) = it.kind { + self.check_case(cx, "associated type", &it.ident); + } + } + } _ => (), } } diff --git a/src/test/ui/associated-inherent-types/style.rs b/src/test/ui/associated-inherent-types/style.rs new file mode 100644 index 0000000000000..8775bd19e1f98 --- /dev/null +++ b/src/test/ui/associated-inherent-types/style.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features, dead_code)] +#![deny(non_camel_case_types)] + +struct S; + +impl S { + type typ = (); + //~^ ERROR associated type `typ` should have an upper camel case name +} + +fn main() {} diff --git a/src/test/ui/associated-inherent-types/style.stderr b/src/test/ui/associated-inherent-types/style.stderr new file mode 100644 index 0000000000000..f83061f8c4216 --- /dev/null +++ b/src/test/ui/associated-inherent-types/style.stderr @@ -0,0 +1,14 @@ +error: associated type `typ` should have an upper camel case name + --> $DIR/style.rs:8:10 + | +LL | type typ = (); + | ^^^ help: convert the identifier to upper camel case: `Typ` + | +note: the lint level is defined here + --> $DIR/style.rs:3:9 + | +LL | #![deny(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 452c745518246484807bd8c73a30400a10cd5057 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 16 Dec 2022 15:10:48 +0000 Subject: [PATCH 7/8] Add a comment warning against using associated type defaults <3 --- compiler/rustc_middle/src/query/keys.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index a96bc115e3b45..e4bb3ce3d5a99 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -15,6 +15,14 @@ use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { + // N.B. Most of the keys down below have `type CacheSelector = DefaultCacheSelector;`, + // it would be reasonable to use associated type defaults, to remove the duplication... + // + // ...But r-a doesn't support them yet and using a default here causes r-a to not infer + // return types of queries which is very annoying. Thus, until r-a support associated + // type defaults, plese restrain from using them here <3 + // + // r-a issue: type CacheSelector; /// Given an instance of this key, what crate is it referring to? From 8751d3b2e9a2fa903822a1f9061c0fe2c4c0bef2 Mon Sep 17 00:00:00 2001 From: Collin Baker Date: Fri, 16 Dec 2022 17:32:29 -0500 Subject: [PATCH 8/8] Make enum-match.rs test robust against variable name changes https://reviews.llvm.org/D140192 caused the LLVM variable generated for enum discriminant checks to be named differently (%narrow vs %1). This adjusts the test CHECK directives to match any name. --- src/test/codegen/enum-match.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/enum-match.rs b/src/test/codegen/enum-match.rs index 44f1b408d21b8..827eb20154afd 100644 --- a/src/test/codegen/enum-match.rs +++ b/src/test/codegen/enum-match.rs @@ -34,8 +34,8 @@ pub enum Enum1 { // CHECK: define i8 @match1{{.*}} // CHECK-NEXT: start: -// CHECK-NEXT: %1 = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1) -// CHECK-NEXT: switch i8 %1, label {{.*}} [ +// CHECK-NEXT: [[DISCR:%.*]] = {{.*}}call i8 @llvm.usub.sat.i8(i8 %0, i8 1) +// CHECK-NEXT: switch i8 [[DISCR]], label {{.*}} [ #[no_mangle] pub fn match1(e: Enum1) -> u8 { use Enum1::*;