From 4d4ec97e0a11eae5878ae6715536875c5689f074 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Sun, 30 Jan 2022 22:16:41 +0000 Subject: [PATCH 01/11] Document char validity --- library/core/src/primitive_docs.rs | 38 ++++++++++++++++++++++++++---- library/std/src/primitive_docs.rs | 38 ++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 8fcd8cdeb1042..e8b4fffbdd275 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -279,16 +279,44 @@ mod prim_never {} /// /// The `char` type represents a single character. More specifically, since /// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -/// scalar value]', which is similar to, but not the same as, a '[Unicode code -/// point]'. -/// -/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value -/// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// scalar value]'. /// /// This documentation describes a number of methods and trait implementations on the /// `char` type. For technical reasons, there is additional, separate /// documentation in [the `std::char` module](char/index.html) as well. /// +/// # Validity +/// +/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' +/// other than a [surrogate code point]. This has a fixed numerical definition: +/// code points are in the range `'\0'` to `char::MAX` (`'\u{10FFFF}'`), inclusive. +/// Surrogate code points, used by UTF-16, are in the range U+D800 to U+DFFF. +/// +/// No `char` may be constructed, whether as a literal or at runtime, that is not a +/// Unicode scalar value: +/// +/// ```text +/// let forbidden_chars = [ +/// // Each of these is a compiler error +/// '\u{D800}', '\u{DFFF}', '\u{110000}', +/// +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(), +/// +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }, +/// ]; +/// ``` +/// +/// Unicode is regularly updated. Many USVs are not currently assigned to a +/// character, but may be in the future ("reserved"); some will never be a character +/// ("noncharacters"); and some may be given different meanings by different users +/// ("private use"). +/// +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point +/// /// # Representation /// /// `char` is always four bytes in size. This is a different representation than diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 8fcd8cdeb1042..e8b4fffbdd275 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -279,16 +279,44 @@ mod prim_never {} /// /// The `char` type represents a single character. More specifically, since /// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -/// scalar value]', which is similar to, but not the same as, a '[Unicode code -/// point]'. -/// -/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value -/// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// scalar value]'. /// /// This documentation describes a number of methods and trait implementations on the /// `char` type. For technical reasons, there is additional, separate /// documentation in [the `std::char` module](char/index.html) as well. /// +/// # Validity +/// +/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' +/// other than a [surrogate code point]. This has a fixed numerical definition: +/// code points are in the range `'\0'` to `char::MAX` (`'\u{10FFFF}'`), inclusive. +/// Surrogate code points, used by UTF-16, are in the range U+D800 to U+DFFF. +/// +/// No `char` may be constructed, whether as a literal or at runtime, that is not a +/// Unicode scalar value: +/// +/// ```text +/// let forbidden_chars = [ +/// // Each of these is a compiler error +/// '\u{D800}', '\u{DFFF}', '\u{110000}', +/// +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(), +/// +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }, +/// ]; +/// ``` +/// +/// Unicode is regularly updated. Many USVs are not currently assigned to a +/// character, but may be in the future ("reserved"); some will never be a character +/// ("noncharacters"); and some may be given different meanings by different users +/// ("private use"). +/// +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point +/// /// # Representation /// /// `char` is always four bytes in size. This is a different representation than From c790128c3c2c26a4ca347fd68cffd4000ecb3295 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Fri, 28 Jan 2022 05:21:34 -0800 Subject: [PATCH 02/11] Improve wrapping on settings page Previously, the radio button choices for themes would wrap awkwardly on narrow screens. With this change, the group of choices will prefer bumping down to the next line together, leaving the setting name on its own line. Also fix some minor spacing issues: - Align the setting name vertically with the radio button choices. - Use margin instead of padding for most spacing choices. - Use no margin/padding on the right-hand side. --- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/static/css/settings.css | 16 +++++++++------- src/test/rustdoc-gui/mobile.goml | 6 ++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 32e4a82918421..a512511cff3b0 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -376,7 +376,7 @@ impl Setting { description, ), Setting::Select { js_data_name, description, default_value, ref options } => format!( - "
{}{}
", + "
{}
{}
", js_data_name, description, options diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 932000487b0a8..7b337c2bc7a33 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -1,5 +1,5 @@ .setting-line { - padding: 5px; + margin: 0.6em 0 0.6em 0.3em; position: relative; } @@ -17,17 +17,16 @@ border-bottom: 1px solid; } -.setting-line .radio-line { +.setting-line .radio-line, +.setting-line .choices { display: flex; flex-wrap: wrap; } -.setting-line .radio-line > * { - padding: 0.3em; -} - .setting-line .radio-line .setting-name { flex-grow: 1; + margin-top: auto; + margin-bottom: auto; } .setting-line .radio-line input { @@ -38,7 +37,10 @@ border-radius: 0.1em; border: 1px solid; margin-left: 0.5em; - min-width: 3.5em; + margin-top: 0.1em; + margin-bottom: 0.1em; + min-width: 3.8em; + padding: 0.3em; } .toggle { diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml index acde112392521..9edf662976d59 100644 --- a/src/test/rustdoc-gui/mobile.goml +++ b/src/test/rustdoc-gui/mobile.goml @@ -15,3 +15,9 @@ assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" } size: (1000, 1000) assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" }) + +// On the settings page, the theme buttons should not line-wrap. Instead, they should +// all be placed as a group on a line below the setting name "Theme." +goto: file://|DOC_PATH|/settings.html +size: (400, 600) +compare-elements-position-near-false: ("#preferred-light-theme .setting-name", "#preferred-light-theme .choice", {"y": 16}) From 5357ec1473c8a44dd8e324b2c664951bf4306b5a Mon Sep 17 00:00:00 2001 From: George Bateman Date: Mon, 31 Jan 2022 23:49:16 +0000 Subject: [PATCH 03/11] (#93493) Add items from code review --- library/core/src/primitive_docs.rs | 50 +++++++++++++++++++++--------- library/std/src/primitive_docs.rs | 50 +++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index e8b4fffbdd275..b9d71178921f7 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -289,32 +289,52 @@ mod prim_never {} /// /// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' /// other than a [surrogate code point]. This has a fixed numerical definition: -/// code points are in the range `'\0'` to `char::MAX` (`'\u{10FFFF}'`), inclusive. -/// Surrogate code points, used by UTF-16, are in the range U+D800 to U+DFFF. +/// code points are in the range 0 to 0x10FFFF, inclusive. +/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF. /// /// No `char` may be constructed, whether as a literal or at runtime, that is not a /// Unicode scalar value: /// /// ```text -/// let forbidden_chars = [ -/// // Each of these is a compiler error -/// '\u{D800}', '\u{DFFF}', '\u{110000}', +/// // Each of these is a compiler error +/// ['\u{D800}', '\u{DFFF}', '\u{110000}']; +/// ``` /// -/// // Panics; from_u32 returns None. -/// char::from_u32(0xDE01).unwrap(), +/// ```should_panic +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(); +/// ``` /// -/// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }, -/// ]; +/// ``` +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// -/// Unicode is regularly updated. Many USVs are not currently assigned to a -/// character, but may be in the future ("reserved"); some will never be a character -/// ("noncharacters"); and some may be given different meanings by different users -/// ("private use"). +/// USVs are also the exact set of values that may be encoded in UTF-8. Because +/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store +/// any `char` in a `str` or read any character from a `str` as a `char`. +/// +/// The gap in valid `char` values is understood by the compiler, so in the +/// below example the two ranges are understood to cover the whole range of +/// possible `char` values and there is no error for a [non-exhaustive match]. +/// +/// ``` +/// let c: char = 'a'; +/// match c { +/// '\0' ..= '\u{D7FF}' => false, +/// '\u{E000}' ..= '\u{10FFFF}' => true, +/// }; +/// ``` +/// +/// All USVs are valid `char` values, but not all of them represent a real +/// character. Many USVs are not currently assigned to a character, but may be +/// in the future ("reserved"); some will never be a character +/// ("noncharacters"); and some may be given different meanings by different +/// users ("private use"). /// -/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value /// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive /// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point /// /// # Representation diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index e8b4fffbdd275..b9d71178921f7 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -289,32 +289,52 @@ mod prim_never {} /// /// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' /// other than a [surrogate code point]. This has a fixed numerical definition: -/// code points are in the range `'\0'` to `char::MAX` (`'\u{10FFFF}'`), inclusive. -/// Surrogate code points, used by UTF-16, are in the range U+D800 to U+DFFF. +/// code points are in the range 0 to 0x10FFFF, inclusive. +/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF. /// /// No `char` may be constructed, whether as a literal or at runtime, that is not a /// Unicode scalar value: /// /// ```text -/// let forbidden_chars = [ -/// // Each of these is a compiler error -/// '\u{D800}', '\u{DFFF}', '\u{110000}', +/// // Each of these is a compiler error +/// ['\u{D800}', '\u{DFFF}', '\u{110000}']; +/// ``` /// -/// // Panics; from_u32 returns None. -/// char::from_u32(0xDE01).unwrap(), +/// ```should_panic +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(); +/// ``` /// -/// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }, -/// ]; +/// ``` +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// -/// Unicode is regularly updated. Many USVs are not currently assigned to a -/// character, but may be in the future ("reserved"); some will never be a character -/// ("noncharacters"); and some may be given different meanings by different users -/// ("private use"). +/// USVs are also the exact set of values that may be encoded in UTF-8. Because +/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store +/// any `char` in a `str` or read any character from a `str` as a `char`. +/// +/// The gap in valid `char` values is understood by the compiler, so in the +/// below example the two ranges are understood to cover the whole range of +/// possible `char` values and there is no error for a [non-exhaustive match]. +/// +/// ``` +/// let c: char = 'a'; +/// match c { +/// '\0' ..= '\u{D7FF}' => false, +/// '\u{E000}' ..= '\u{10FFFF}' => true, +/// }; +/// ``` +/// +/// All USVs are valid `char` values, but not all of them represent a real +/// character. Many USVs are not currently assigned to a character, but may be +/// in the future ("reserved"); some will never be a character +/// ("noncharacters"); and some may be given different meanings by different +/// users ("private use"). /// -/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value /// [Unicode code point]: https://www.unicode.org/glossary/#code_point +/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value +/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive /// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point /// /// # Representation From 76aa92906bb60adc36ea79393702b9585df6e9ed Mon Sep 17 00:00:00 2001 From: TheVoid <593767573@qq.com> Date: Tue, 1 Feb 2022 10:19:08 +0800 Subject: [PATCH 04/11] Fix incorrect panic message in example --- library/std/src/net/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 1ba54d892e3ce..cc4e4fd4fdc77 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -405,7 +405,7 @@ impl TcpStream { /// use std::net::TcpStream; /// /// let stream = TcpStream::connect("127.0.0.1:8000") - /// .expect("couldn't bind to address"); + /// .expect("Couldn't connect to the server..."); /// let mut buf = [0; 10]; /// let len = stream.peek(&mut buf).expect("peek failed"); /// ``` From 95bd87f849ebbd6a6d4bc24c318c40986a78b4f4 Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Tue, 11 Jan 2022 13:09:05 +0530 Subject: [PATCH 05/11] librustdoc: impl core::fmt::Write for rustdoc::html::render::Buffer Signed-off-by: Muhammad Falak R Wani --- src/librustdoc/html/format.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 08840626259dc..47d626a1d8877 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -64,6 +64,12 @@ crate struct Buffer { buffer: String, } +impl core::fmt::Write for Buffer { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.buffer.write_str(s) + } +} + impl Buffer { crate fn empty_from(v: &Buffer) -> Buffer { Buffer { for_html: v.for_html, buffer: String::new() } From 66d7e50cb6424f1928eb810e0bbc6d856e22a567 Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Tue, 11 Jan 2022 19:28:11 +0530 Subject: [PATCH 06/11] librustdoc: inline and forward all methods for `impl Write for Buffer` Signed-off-by: Muhammad Falak R Wani --- src/librustdoc/html/format.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 47d626a1d8877..f4df9ef4a8c9d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -65,9 +65,20 @@ crate struct Buffer { } impl core::fmt::Write for Buffer { + #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { self.buffer.write_str(s) } + + #[inline] + fn write_char(&mut self, c: char) -> fmt::Result { + self.buffer.write_char(c) + } + + #[inline] + fn write_fmt(self: &mut Self, args: fmt::Arguments<'_>) -> fmt::Result { + self.buffer.write_fmt(args) + } } impl Buffer { From 62bea63888a7f1753c019852258d20788a544dfb Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Tue, 1 Feb 2022 18:06:58 +0530 Subject: [PATCH 07/11] librustdoc: render: use render_into instead of creating a temp string Signed-off-by: Muhammad Falak R Wani --- src/librustdoc/html/render/print_item.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f2c111495edfb..6592a56ba46a8 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -139,8 +139,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, src_href: src_href.as_deref(), }; - let heading = item_vars.render().unwrap(); - buf.write_str(&heading); + item_vars.render_into(buf).unwrap(); match *item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), From e22729b46466a171b020f601e40e5e50283b1d8b Mon Sep 17 00:00:00 2001 From: Daniel Frampton Date: Tue, 1 Feb 2022 12:40:01 -0800 Subject: [PATCH 08/11] Add missing | between print options --- compiler/rustc_session/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a756de4c0fc45..d2d5b06ad67b6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1188,7 +1188,7 @@ pub fn rustc_short_optgroups() -> Vec { "Compiler information to print on stdout", "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\ target-cpus|target-features|relocation-models|code-models|\ - tls-models|target-spec-json|native-static-libs|stack-protector-strategies\ + tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\ link-args]", ), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), From 63b12aea27a5a6cd7a792660bbdeacb6c7eafbef Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Tue, 1 Feb 2022 22:32:02 +0100 Subject: [PATCH 09/11] Fix two incorrect "it's" --- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b1ab0f5b533dd..e9e6d61331077 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1642,7 +1642,7 @@ pub enum FakeReadCause { ForMatchedPlace(Option), /// A fake read of the RefWithinGuard version of a bind-by-value variable - /// in a match guard to ensure that it's value hasn't change by the time + /// in a match guard to ensure that its value hasn't change by the time /// we create the OutsideGuard version. ForGuardBinding, @@ -2939,7 +2939,7 @@ impl Location { let mut visited = FxHashSet::default(); while let Some(block) = queue.pop() { - // If we haven't visited this block before, then make sure we visit it's predecessors. + // If we haven't visited this block before, then make sure we visit its predecessors. if visited.insert(block) { queue.extend(predecessors[block].iter().cloned()); } else { From d372baf3f9a6401fdd4f74e3385ba553667b287d Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 1 Feb 2022 21:44:53 +0000 Subject: [PATCH 10/11] Fix annotation of code blocks --- library/core/src/primitive_docs.rs | 5 +++-- library/std/src/primitive_docs.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index b9d71178921f7..ebb1d8971b99d 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -275,6 +275,7 @@ mod prim_bool {} mod prim_never {} #[doc(primitive = "char")] +#[allow(rustdoc::invalid_rust_codeblocks)] /// A character type. /// /// The `char` type represents a single character. More specifically, since @@ -295,7 +296,7 @@ mod prim_never {} /// No `char` may be constructed, whether as a literal or at runtime, that is not a /// Unicode scalar value: /// -/// ```text +/// ```compile_fail /// // Each of these is a compiler error /// ['\u{D800}', '\u{DFFF}', '\u{110000}']; /// ``` @@ -305,7 +306,7 @@ mod prim_never {} /// char::from_u32(0xDE01).unwrap(); /// ``` /// -/// ``` +/// ```no_run /// // Undefined behaviour /// unsafe { char::from_u32_unchecked(0x110000) }; /// ``` diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index b9d71178921f7..ebb1d8971b99d 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -275,6 +275,7 @@ mod prim_bool {} mod prim_never {} #[doc(primitive = "char")] +#[allow(rustdoc::invalid_rust_codeblocks)] /// A character type. /// /// The `char` type represents a single character. More specifically, since @@ -295,7 +296,7 @@ mod prim_never {} /// No `char` may be constructed, whether as a literal or at runtime, that is not a /// Unicode scalar value: /// -/// ```text +/// ```compile_fail /// // Each of these is a compiler error /// ['\u{D800}', '\u{DFFF}', '\u{110000}']; /// ``` @@ -305,7 +306,7 @@ mod prim_never {} /// char::from_u32(0xDE01).unwrap(); /// ``` /// -/// ``` +/// ```no_run /// // Undefined behaviour /// unsafe { char::from_u32_unchecked(0x110000) }; /// ``` From b26ad8d10fabe45ead09aff0e2cd5b5e1289274a Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 11 Jan 2022 21:56:10 +0000 Subject: [PATCH 11/11] Detect `::` -> `:` typo in type argument When writing `Vec`, suggest `Vec`. --- compiler/rustc_resolve/src/late.rs | 6 ++- .../rustc_resolve/src/late/diagnostics.rs | 37 +++++++++++++++ ...type-ascription-instead-of-path-in-type.rs | 14 ++++++ ...-ascription-instead-of-path-in-type.stderr | 46 +++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs create mode 100644 src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2c678e71ae179..6aed3223480f1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -400,6 +400,8 @@ struct DiagnosticMetadata<'ast> { /// Given `where ::Baz: String`, suggest `where T: Bar`. current_where_predicate: Option<&'ast WherePredicate>, + + current_type_path: Option<&'ast Ty>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -472,8 +474,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_ty(&mut self, ty: &'ast Ty) { let prev = self.diagnostic_metadata.current_trait_object; + let prev_ty = self.diagnostic_metadata.current_type_path; match ty.kind { TyKind::Path(ref qself, ref path) => { + self.diagnostic_metadata.current_type_path = Some(ty); self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); } TyKind::ImplicitSelf => { @@ -490,6 +494,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } visit::walk_ty(self, ty); self.diagnostic_metadata.current_trait_object = prev; + self.diagnostic_metadata.current_type_path = prev_ty; } fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { self.smart_resolve_path( @@ -1936,7 +1941,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; - // get_from_node_id this.r.use_injections.push(UseError { err, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7e1e5c788052b..d05f139e3bf5a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use std::iter; +use std::ops::Deref; use tracing::debug; @@ -265,6 +266,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } + self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err); + // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { err.code(rustc_errors::error_code!(E0411)); @@ -603,6 +606,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { (err, candidates) } + fn detect_assoct_type_constraint_meant_as_path( + &self, + base_span: Span, + err: &mut DiagnosticBuilder<'_>, + ) { + let Some(ty) = self.diagnostic_metadata.current_type_path else { return; }; + let TyKind::Path(_, path) = &ty.kind else { return; }; + for segment in &path.segments { + let Some(params) = &segment.args else { continue; }; + let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; }; + for param in ¶ms.args { + let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; }; + let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else { + continue; + }; + for bound in bounds { + let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None) + = bound else + { + continue; + }; + if base_span == trait_ref.span { + err.span_suggestion_verbose( + constraint.ident.span.between(trait_ref.span), + "you might have meant to write a path instead of an associated type bound", + "::".to_string(), + Applicability::MachineApplicable, + ); + } + } + } + } + } + fn get_single_associated_item( &mut self, path: &[Segment], diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs new file mode 100644 index 0000000000000..48d19f6dd4e3f --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.rs @@ -0,0 +1,14 @@ +enum A { + B, +} + +fn main() { + let _: Vec = A::B; + //~^ ERROR cannot find trait `B` in this scope + //~| HELP you might have meant to write a path instead of an associated type bound + //~| ERROR associated type bounds are unstable + //~| HELP add `#![feature(associated_type_bounds)]` to the crate attributes to enable + //~| ERROR struct takes at least 1 generic argument but 0 generic arguments were supplied + //~| HELP add missing generic argument + //~| ERROR associated type bindings are not allowed here +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr new file mode 100644 index 0000000000000..951ff23d63563 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path-in-type.stderr @@ -0,0 +1,46 @@ +error[E0405]: cannot find trait `B` in this scope + --> $DIR/type-ascription-instead-of-path-in-type.rs:6:18 + | +LL | let _: Vec = A::B; + | ^ not found in this scope + | +help: you might have meant to write a path instead of an associated type bound + | +LL | let _: Vec = A::B; + | ~~ + +error[E0658]: associated type bounds are unstable + --> $DIR/type-ascription-instead-of-path-in-type.rs:6:16 + | +LL | let _: Vec = A::B; + | ^^^ + | + = note: see issue #52662 for more information + = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable + +error[E0107]: this struct takes at least 1 generic argument but 0 generic arguments were supplied + --> $DIR/type-ascription-instead-of-path-in-type.rs:6:12 + | +LL | let _: Vec = A::B; + | ^^^ expected at least 1 generic argument + | +note: struct defined here, with at least 1 generic parameter: `T` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | +LL | pub struct Vec { + | ^^^ - +help: add missing generic argument + | +LL | let _: Vec = A::B; + | ++ + +error[E0229]: associated type bindings are not allowed here + --> $DIR/type-ascription-instead-of-path-in-type.rs:6:16 + | +LL | let _: Vec = A::B; + | ^^^ associated type not allowed here + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0107, E0229, E0405, E0658. +For more information about an error, try `rustc --explain E0107`.