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 { 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/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"), diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 8fcd8cdeb1042..ebb1d8971b99d 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -275,20 +275,69 @@ 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 /// '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 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: +/// +/// ```compile_fail +/// // Each of these is a compiler error +/// ['\u{D800}', '\u{DFFF}', '\u{110000}']; +/// ``` +/// +/// ```should_panic +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(); +/// ``` +/// +/// ```no_run +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }; +/// ``` +/// +/// 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 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 /// /// `char` is always four bytes in size. This is a different representation than 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"); /// ``` diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 8fcd8cdeb1042..ebb1d8971b99d 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -275,20 +275,69 @@ 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 /// '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 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: +/// +/// ```compile_fail +/// // Each of these is a compiler error +/// ['\u{D800}', '\u{DFFF}', '\u{110000}']; +/// ``` +/// +/// ```should_panic +/// // Panics; from_u32 returns None. +/// char::from_u32(0xDE01).unwrap(); +/// ``` +/// +/// ```no_run +/// // Undefined behaviour +/// unsafe { char::from_u32_unchecked(0x110000) }; +/// ``` +/// +/// 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 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 /// /// `char` is always four bytes in size. This is a different representation than diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 08840626259dc..f4df9ef4a8c9d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -64,6 +64,23 @@ crate struct Buffer { buffer: String, } +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 { crate fn empty_from(v: &Buffer) -> Buffer { Buffer { for_html: v.for_html, buffer: String::new() } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index cc12b7ba05ba3..59a6187b62be9 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/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), 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 8f9c9248f5ff1..7be46a613c4fb 100644 --- a/src/test/rustdoc-gui/mobile.goml +++ b/src/test/rustdoc-gui/mobile.goml @@ -19,3 +19,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}) 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`.