From 34fafd363ca46802c0e9581353511cfc7be7e4ae Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 7 Jun 2022 21:22:53 +0100 Subject: [PATCH 01/10] Windows: No panic if function not (yet) available In some situations it is possible for required functions to be called before they've had a chance to be loaded. Therefore, we make it possible to recover from this situation simply by looking at error codes. --- library/std/src/sys/windows/c.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 27776fdf533ee..5469487df1eed 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -276,6 +276,7 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; +pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -1264,7 +1265,7 @@ compat_fn! { EaBuffer: *mut c_void, EaLength: ULONG ) -> NTSTATUS { - panic!("`NtCreateFile` not available"); + STATUS_NOT_IMPLEMENTED } pub fn NtReadFile( FileHandle: BorrowedHandle<'_>, @@ -1277,7 +1278,7 @@ compat_fn! { ByteOffset: Option<&LARGE_INTEGER>, Key: Option<&ULONG> ) -> NTSTATUS { - panic!("`NtReadFile` not available"); + STATUS_NOT_IMPLEMENTED } pub fn NtWriteFile( FileHandle: BorrowedHandle<'_>, @@ -1290,12 +1291,12 @@ compat_fn! { ByteOffset: Option<&LARGE_INTEGER>, Key: Option<&ULONG> ) -> NTSTATUS { - panic!("`NtWriteFile` not available"); + STATUS_NOT_IMPLEMENTED } pub fn RtlNtStatusToDosError( Status: NTSTATUS ) -> ULONG { - panic!("`RtlNtStatusToDosError` not available"); + Status as ULONG } pub fn NtCreateKeyedEvent( KeyedEventHandle: LPHANDLE, From 324286f1019bcf9abef19543d4bb8749d9f91ed9 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 28 Mar 2022 10:01:59 +0800 Subject: [PATCH 02/10] std: Stabilize feature try_reserve_2 Signed-off-by: Xuanwo --- library/alloc/src/collections/binary_heap.rs | 6 ++---- library/std/src/ffi/os_str.rs | 6 ++---- library/std/src/path.rs | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 839088eac21ea..3706300dcfeb7 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -978,7 +978,6 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(try_reserve_2)] /// use std::collections::BinaryHeap; /// use std::collections::TryReserveError; /// @@ -995,7 +994,7 @@ impl BinaryHeap { /// } /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.data.try_reserve_exact(additional) } @@ -1014,7 +1013,6 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// #![feature(try_reserve_2)] /// use std::collections::BinaryHeap; /// use std::collections::TryReserveError; /// @@ -1031,7 +1029,7 @@ impl BinaryHeap { /// } /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.data.try_reserve(additional) } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 247bdd954589c..bdc44771643a5 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -280,7 +280,6 @@ impl OsString { /// # Examples /// /// ``` - /// #![feature(try_reserve_2)] /// use std::ffi::{OsStr, OsString}; /// use std::collections::TryReserveError; /// @@ -297,7 +296,7 @@ impl OsString { /// } /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); /// ``` - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve(additional) @@ -348,7 +347,6 @@ impl OsString { /// # Examples /// /// ``` - /// #![feature(try_reserve_2)] /// use std::ffi::{OsStr, OsString}; /// use std::collections::TryReserveError; /// @@ -365,7 +363,7 @@ impl OsString { /// } /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); /// ``` - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve_exact(additional) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 36d6469c02d31..6bbc8f55ace35 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1520,7 +1520,7 @@ impl PathBuf { /// Invokes [`try_reserve`] on the underlying instance of [`OsString`]. /// /// [`try_reserve`]: OsString::try_reserve - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve(additional) @@ -1538,7 +1538,7 @@ impl PathBuf { /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`]. /// /// [`try_reserve_exact`]: OsString::try_reserve_exact - #[unstable(feature = "try_reserve_2", issue = "91789")] + #[stable(feature = "try_reserve_2", since = "1.63.0")] #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.inner.try_reserve_exact(additional) From 260c5fd58778f14c4f4d19e1b91784a4e0a675e3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 6 Jun 2022 17:42:53 +0400 Subject: [PATCH 03/10] Fix a typo !(a & b) = !a | !b --- compiler/rustc_errors/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8b6eba122f8f0..25fa2c30e7ebb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1145,7 +1145,7 @@ impl HandlerInner { !this.emitted_diagnostics.insert(diagnostic_hash) }; - // Only emit the diagnostic if we've been asked to deduplicate and + // Only emit the diagnostic if we've been asked to deduplicate or // haven't already emitted an equivalent diagnostic. if !(self.flags.deduplicate_diagnostics && already_emitted(self)) { debug!(?diagnostic); From 87fded1eddf834f2decbfd05e6fda35cb1ee4747 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 6 Jun 2022 18:04:42 +0400 Subject: [PATCH 04/10] Improve suggestions when its parts are far from each other Previously we only show at most 6 lines of suggestions and, if the suggestions are more than 6 lines apart, we've just showed ... at the end. This is probably fine, but quite confusing in my opinion. This commit is an attempt to show ... in places where there is nothing to suggest instead, for example: Before: ```text help: consider enclosing expression in a block | 3 ~ 'l: { match () { () => break 'l, 4 | 5 | 6 | 7 | 8 | ... ``` After: ```text help: consider enclosing expression in a block | 3 ~ 'l: { match () { () => break 'l, 4 | ... 31| 32~ } }; | ``` --- compiler/rustc_errors/src/emitter.rs | 167 ++++++++++++++++----------- 1 file changed, 99 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e9e7065ec03cc..269d34ea4325d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -656,11 +656,6 @@ impl Emitter for SilentEmitter { } } -/// Maximum number of lines we will print for a multiline suggestion; arbitrary. -/// -/// This should be replaced with a more involved mechanism to output multiline suggestions that -/// more closely mimics the regular diagnostic output, where irrelevant code lines are elided. -pub const MAX_SUGGESTION_HIGHLIGHT_LINES: usize = 6; /// Maximum number of suggestions to be shown /// /// Arbitrary, but taken from trait import suggestion limit @@ -1839,79 +1834,115 @@ impl EmitterWriter { } row_num += line_end - line_start; } - for (line_pos, (line, highlight_parts)) in - lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate() - { - // Print the span column to avoid confusion - buffer.puts( - row_num, - 0, - &self.maybe_anonymized(line_start + line_pos), - Style::LineNumber, - ); - if let DisplaySuggestion::Diff = show_code_change { - // Add the line number for both addition and removal to drive the point home. - // - // N - fn foo(bar: A) { - // N + fn foo(bar: impl T) { + let mut unhighlighted_lines = Vec::new(); + for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() { + debug!(%line_pos, %line, ?highlight_parts); + + let print_line = |line_pos: usize, + line: &str, + highlight_parts: &Vec, + buffer: &mut StyledBuffer, + row_num: &mut usize| { + // Print the span column to avoid confusion buffer.puts( - row_num - 1, + *row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber, ); - buffer.puts(row_num - 1, max_line_num_len + 1, "- ", Style::Removal); - buffer.puts( - row_num - 1, - max_line_num_len + 3, - &normalize_whitespace( - &*file_lines - .file - .get_line(file_lines.lines[line_pos].line_index) - .unwrap(), - ), - Style::NoStyle, - ); - buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition); - } else if is_multiline { - match &highlight_parts[..] { - [SubstitutionHighlight { start: 0, end }] if *end == line.len() => { - buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition); - } - [] => { - draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); - } - _ => { - buffer.puts(row_num, max_line_num_len + 1, "~ ", Style::Addition); + if let DisplaySuggestion::Diff = show_code_change { + // Add the line number for both addition and removal to drive the point home. + // + // N - fn foo(bar: A) { + // N + fn foo(bar: impl T) { + buffer.puts( + *row_num - 1, + 0, + &self.maybe_anonymized(line_start + line_pos), + Style::LineNumber, + ); + buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); + buffer.puts( + *row_num - 1, + max_line_num_len + 3, + &normalize_whitespace( + &*file_lines + .file + .get_line(file_lines.lines[line_pos].line_index) + .unwrap(), + ), + Style::NoStyle, + ); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + } else if is_multiline { + match &highlight_parts[..] { + [SubstitutionHighlight { start: 0, end }] if *end == line.len() => { + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + } + [] => { + draw_col_separator(buffer, *row_num, max_line_num_len + 1); + } + _ => { + buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition); + } } + } else { + draw_col_separator(buffer, *row_num, max_line_num_len + 1); } - } else { - draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); - } - // print the suggestion - buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle); + // print the suggestion + buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle); - // Colorize addition/replacements with green. - for &SubstitutionHighlight { start, end } in highlight_parts { - // Account for tabs when highlighting (#87972). - let tabs: usize = line - .chars() - .take(start) - .map(|ch| match ch { - '\t' => 3, - _ => 0, - }) - .sum(); - buffer.set_style_range( - row_num, - max_line_num_len + 3 + start + tabs, - max_line_num_len + 3 + end + tabs, - Style::Addition, - true, - ); + // Colorize addition/replacements with green. + for &SubstitutionHighlight { start, end } in highlight_parts { + // Account for tabs when highlighting (#87972). + let tabs: usize = line + .chars() + .take(start) + .map(|ch| match ch { + '\t' => 3, + _ => 0, + }) + .sum(); + buffer.set_style_range( + *row_num, + max_line_num_len + 3 + start + tabs, + max_line_num_len + 3 + end + tabs, + Style::Addition, + true, + ); + } + *row_num += 1; + }; + + if highlight_parts.is_empty() { + unhighlighted_lines.push((line_pos, line)); + continue; } - row_num += 1; + + match unhighlighted_lines.len() { + 0 => (), + // Since we show first line, "..." line and last line, + // There is no reason to hide if there are 3 or less lines + // (because then we just replace a line with ... which is + // not helpful) + n if n <= 3 => unhighlighted_lines.drain(..).for_each(|(p, l)| { + print_line(p, l, &Vec::new(), &mut buffer, &mut row_num) + }), + _ => { + unhighlighted_lines + .drain(..1) + .next() + .map(|(p, l)| print_line(p, l, &Vec::new(), &mut buffer, &mut row_num)); + buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); + row_num += 1; + unhighlighted_lines + .pop() + .map(|(p, l)| print_line(p, l, &Vec::new(), &mut buffer, &mut row_num)); + } + } + + print_line(line_pos, line, highlight_parts, &mut buffer, &mut row_num) } // This offset and the ones below need to be signed to account for replacement code From a607cffc8c731f47a828c16d461bb97fda5ed41c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 6 Jun 2022 19:26:50 +0400 Subject: [PATCH 05/10] --bless ui --- src/test/ui/associated-consts/issue-93835.stderr | 7 +++---- .../migrations/auto_traits.stderr | 14 ++++++-------- .../migrations/multi_diagnostics.stderr | 7 +++---- src/test/ui/imports/issue-59764.stderr | 3 +-- src/test/ui/issues/issue-22644.stderr | 7 +++---- src/test/ui/let-else/let-else-if.stderr | 3 +-- .../parser/recover-labeled-non-block-expr.stderr | 7 +++---- src/test/ui/type/ascription/issue-34255-1.stderr | 3 +-- .../unboxed-closure-sugar-lifetime-elision.stderr | 7 +++---- 9 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/test/ui/associated-consts/issue-93835.stderr b/src/test/ui/associated-consts/issue-93835.stderr index 12df0e4381d15..0406a16a39732 100644 --- a/src/test/ui/associated-consts/issue-93835.stderr +++ b/src/test/ui/associated-consts/issue-93835.stderr @@ -19,11 +19,10 @@ help: you might have meant to write a `struct` literal | LL ~ fn e() { SomeStruct { LL | p:a> -LL | -LL | -LL | -LL | ... +LL | +LL ~ }} + | help: maybe you meant to write a path separator here | LL | p::a> diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index a8367766ae1cf..a3c43690f1f32 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -17,11 +17,10 @@ help: add a dummy let to cause `fptr` to be fully captured | LL ~ thread::spawn(move || { let _ = &fptr; unsafe { LL | -LL | -LL | -LL | -LL | *fptr.0 = 20; ... +LL | +LL ~ } }); + | error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:42:19 @@ -39,12 +38,11 @@ LL | *fptr.0.0 = 20; help: add a dummy let to cause `fptr` to be fully captured | LL ~ thread::spawn(move || { let _ = &fptr; unsafe { -LL | -LL | -LL | -LL | LL | ... +LL | +LL ~ } }); + | error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements --> $DIR/auto_traits.rs:67:13 diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 483eae6bb4b1f..fa6082cbb59b4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -108,12 +108,11 @@ LL | *fptr2.0 = 20; help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured | LL ~ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { -LL | -LL | -LL | -LL | LL | ... +LL | +LL ~ } }); + | error: aborting due to 5 previous errors diff --git a/src/test/ui/imports/issue-59764.stderr b/src/test/ui/imports/issue-59764.stderr index c2cfc0939d6b3..8d99d757c17d6 100644 --- a/src/test/ui/imports/issue-59764.stderr +++ b/src/test/ui/imports/issue-59764.stderr @@ -209,8 +209,7 @@ help: a macro with this name exists at the root of the crate | LL ~ issue_59764::{makro as foobar, LL | -LL | foobaz, -LL | + ... LL | LL ~ foo::{baz} | diff --git a/src/test/ui/issues/issue-22644.stderr b/src/test/ui/issues/issue-22644.stderr index 6bec98121b759..039ffbfd3d89f 100644 --- a/src/test/ui/issues/issue-22644.stderr +++ b/src/test/ui/issues/issue-22644.stderr @@ -89,12 +89,11 @@ LL | 5); help: try comparing the cast value | LL ~ println!("{}", (a -LL | -LL | -LL | as -LL | LL | ... +LL | +LL ~ usize) + | error: `<` is interpreted as a start of generic arguments for `usize`, not a shift --> $DIR/issue-22644.rs:32:31 diff --git a/src/test/ui/let-else/let-else-if.stderr b/src/test/ui/let-else/let-else-if.stderr index a0324565673da..746738bbd939b 100644 --- a/src/test/ui/let-else/let-else-if.stderr +++ b/src/test/ui/let-else/let-else-if.stderr @@ -8,8 +8,7 @@ help: try placing this code inside a block | LL ~ let Some(_) = Some(()) else { if true { LL | -LL | return; -LL | } else { + ... LL | return; LL ~ } }; | diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.stderr b/src/test/ui/parser/recover-labeled-non-block-expr.stderr index 767389c48088a..d95c25fdea8b5 100644 --- a/src/test/ui/parser/recover-labeled-non-block-expr.stderr +++ b/src/test/ui/parser/recover-labeled-non-block-expr.stderr @@ -54,11 +54,10 @@ help: consider enclosing expression in a block | LL ~ let _i = 'label: { match x { LL | 0 => 42, -LL | 1 if false => break 'label 17, -LL | 1 => { -LL | if true { -LL | break 'label 13 ... +LL | _ => 1, +LL ~ } }; + | error: expected `while`, `for`, `loop` or `{` after a label --> $DIR/recover-labeled-non-block-expr.rs:26:24 diff --git a/src/test/ui/type/ascription/issue-34255-1.stderr b/src/test/ui/type/ascription/issue-34255-1.stderr index 43f0fbbc4e387..6819d14bb0106 100644 --- a/src/test/ui/type/ascription/issue-34255-1.stderr +++ b/src/test/ui/type/ascription/issue-34255-1.stderr @@ -8,8 +8,7 @@ help: you might have meant to write a `struct` literal | LL ~ pub fn new() -> Self { SomeStruct { LL | input_cells: Vec::new() -LL | -LL | + ... LL | LL ~ }} | diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr index 64d14d0fc5fa4..d25452456bb21 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr @@ -9,11 +9,10 @@ help: consider introducing a named lifetime parameter | LL ~ fn main<'a>() { LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=&'a isize>, -LL | dyn Foo(&isize) -> &isize >(); -LL | eq::< dyn for<'a> Foo<(&'a isize,), Output=(&'a isize, &'a isize)>, -LL | dyn Foo(&isize) -> (&isize, &isize) >(); -LL | ... +LL | +LL ~ let _: dyn Foo(&'a isize, &'a usize) -> &'a usize; + | error: aborting due to previous error From cf6f821c3372b5ddc3cb0a92afcc48a1e0313efa Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 13 Jun 2022 15:22:26 +0400 Subject: [PATCH 06/10] Try to clean up code... I'm not sure if I succeeded --- compiler/rustc_errors/src/emitter.rs | 243 +++++++++++++++++---------- 1 file changed, 150 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 269d34ea4325d..690ba14e69975 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -10,7 +10,7 @@ use Destination::*; use rustc_span::source_map::SourceMap; -use rustc_span::{SourceFile, Span}; +use rustc_span::{FileLines, SourceFile, Span}; use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; use crate::styled_buffer::StyledBuffer; @@ -1756,12 +1756,6 @@ impl EmitterWriter { let has_deletion = parts.iter().any(|p| p.is_deletion()); let is_multiline = complete.lines().count() > 1; - enum DisplaySuggestion { - Underline, - Diff, - None, - } - if let Some(span) = span.primary_span() { // Compare the primary span of the diagnostic with the span of the suggestion // being emitted. If they belong to the same file, we don't *need* to show the @@ -1838,83 +1832,7 @@ impl EmitterWriter { for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() { debug!(%line_pos, %line, ?highlight_parts); - let print_line = |line_pos: usize, - line: &str, - highlight_parts: &Vec, - buffer: &mut StyledBuffer, - row_num: &mut usize| { - // Print the span column to avoid confusion - buffer.puts( - *row_num, - 0, - &self.maybe_anonymized(line_start + line_pos), - Style::LineNumber, - ); - if let DisplaySuggestion::Diff = show_code_change { - // Add the line number for both addition and removal to drive the point home. - // - // N - fn foo(bar: A) { - // N + fn foo(bar: impl T) { - buffer.puts( - *row_num - 1, - 0, - &self.maybe_anonymized(line_start + line_pos), - Style::LineNumber, - ); - buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); - buffer.puts( - *row_num - 1, - max_line_num_len + 3, - &normalize_whitespace( - &*file_lines - .file - .get_line(file_lines.lines[line_pos].line_index) - .unwrap(), - ), - Style::NoStyle, - ); - buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); - } else if is_multiline { - match &highlight_parts[..] { - [SubstitutionHighlight { start: 0, end }] if *end == line.len() => { - buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); - } - [] => { - draw_col_separator(buffer, *row_num, max_line_num_len + 1); - } - _ => { - buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition); - } - } - } else { - draw_col_separator(buffer, *row_num, max_line_num_len + 1); - } - - // print the suggestion - buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle); - - // Colorize addition/replacements with green. - for &SubstitutionHighlight { start, end } in highlight_parts { - // Account for tabs when highlighting (#87972). - let tabs: usize = line - .chars() - .take(start) - .map(|ch| match ch { - '\t' => 3, - _ => 0, - }) - .sum(); - buffer.set_style_range( - *row_num, - max_line_num_len + 3 + start + tabs, - max_line_num_len + 3 + end + tabs, - Style::Addition, - true, - ); - } - *row_num += 1; - }; - + // Remember lines that are not highlighted to hide them if needed if highlight_parts.is_empty() { unhighlighted_lines.push((line_pos, line)); continue; @@ -1927,22 +1845,77 @@ impl EmitterWriter { // (because then we just replace a line with ... which is // not helpful) n if n <= 3 => unhighlighted_lines.drain(..).for_each(|(p, l)| { - print_line(p, l, &Vec::new(), &mut buffer, &mut row_num) + self.draw_code_line( + &mut buffer, + &mut row_num, + &Vec::new(), + p, + l, + line_start, + show_code_change, + max_line_num_len, + &file_lines, + is_multiline, + ) }), + // Print first unhighlighted line, "..." and last unhighlighted line, like so: + // + // LL | this line was highlighted + // LL | this line is just for context + // ... + // LL | this line is just for context + // LL | this line was highlighted _ => { - unhighlighted_lines - .drain(..1) - .next() - .map(|(p, l)| print_line(p, l, &Vec::new(), &mut buffer, &mut row_num)); + let last_line = unhighlighted_lines.pop(); + let first_line = unhighlighted_lines.drain(..).next(); + + first_line.map(|(p, l)| { + self.draw_code_line( + &mut buffer, + &mut row_num, + &Vec::new(), + p, + l, + line_start, + show_code_change, + max_line_num_len, + &file_lines, + is_multiline, + ) + }); + buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); row_num += 1; - unhighlighted_lines - .pop() - .map(|(p, l)| print_line(p, l, &Vec::new(), &mut buffer, &mut row_num)); + + last_line.map(|(p, l)| { + self.draw_code_line( + &mut buffer, + &mut row_num, + &Vec::new(), + p, + l, + line_start, + show_code_change, + max_line_num_len, + &file_lines, + is_multiline, + ) + }); } } - print_line(line_pos, line, highlight_parts, &mut buffer, &mut row_num) + self.draw_code_line( + &mut buffer, + &mut row_num, + highlight_parts, + line_pos, + line, + line_start, + show_code_change, + max_line_num_len, + &file_lines, + is_multiline, + ) } // This offset and the ones below need to be signed to account for replacement code @@ -2127,6 +2100,90 @@ impl EmitterWriter { } } } + + fn draw_code_line( + &self, + buffer: &mut StyledBuffer, + row_num: &mut usize, + highlight_parts: &Vec, + line_pos: usize, + line: &str, + line_start: usize, + show_code_change: DisplaySuggestion, + max_line_num_len: usize, + file_lines: &FileLines, + is_multiline: bool, + ) { + // Print the span column to avoid confusion + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber); + if let DisplaySuggestion::Diff = show_code_change { + // Add the line number for both addition and removal to drive the point home. + // + // N - fn foo(bar: A) { + // N + fn foo(bar: impl T) { + buffer.puts( + *row_num - 1, + 0, + &self.maybe_anonymized(line_start + line_pos), + Style::LineNumber, + ); + buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal); + buffer.puts( + *row_num - 1, + max_line_num_len + 3, + &normalize_whitespace( + &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(), + ), + Style::NoStyle, + ); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + } else if is_multiline { + match &highlight_parts[..] { + [SubstitutionHighlight { start: 0, end }] if *end == line.len() => { + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + } + [] => { + draw_col_separator(buffer, *row_num, max_line_num_len + 1); + } + _ => { + buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition); + } + } + } else { + draw_col_separator(buffer, *row_num, max_line_num_len + 1); + } + + // print the suggestion + buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle); + + // Colorize addition/replacements with green. + for &SubstitutionHighlight { start, end } in highlight_parts { + // Account for tabs when highlighting (#87972). + let tabs: usize = line + .chars() + .take(start) + .map(|ch| match ch { + '\t' => 3, + _ => 0, + }) + .sum(); + buffer.set_style_range( + *row_num, + max_line_num_len + 3 + start + tabs, + max_line_num_len + 3 + end + tabs, + Style::Addition, + true, + ); + } + *row_num += 1; + } +} + +#[derive(Clone, Copy)] +enum DisplaySuggestion { + Underline, + Diff, + None, } impl FileWithAnnotatedLines { From 3c55672795bdc4473bbaa1922c1703916839c4aa Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 13 Jun 2022 18:28:31 +0400 Subject: [PATCH 07/10] Add back MAX_SUGGESTION_HIGHLIGHT_LINES so clippy is happy & buildable --- compiler/rustc_errors/src/emitter.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 690ba14e69975..1329e3a0b959d 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -656,6 +656,11 @@ impl Emitter for SilentEmitter { } } +/// Maximum number of lines we will print for a multiline suggestion; arbitrary. +/// +/// This should be replaced with a more involved mechanism to output multiline suggestions that +/// more closely mimics the regular diagnostic output, where irrelevant code lines are elided. +pub const MAX_SUGGESTION_HIGHLIGHT_LINES: usize = 6; /// Maximum number of suggestions to be shown /// /// Arbitrary, but taken from trait import suggestion limit From e502b9a0ff4ab37176c82a994586e6f11e57e18f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 16 Jun 2022 18:00:32 +0400 Subject: [PATCH 08/10] bless clippy ui tests --- .../ui/bind_instead_of_map_multipart.stderr | 18 ++++++++ .../shared_at_top_and_bottom.stderr | 3 +- src/tools/clippy/tests/ui/entry.stderr | 41 ++++++++++++++++--- .../clippy/tests/ui/entry_with_else.stderr | 17 ++++++-- src/tools/clippy/tests/ui/let_unit.stderr | 3 +- .../clippy/tests/ui/manual_async_fn.stderr | 9 +++- .../ui/needless_for_each_unfixable.stderr | 3 +- .../tests/ui/new_without_default.stderr | 3 +- src/tools/clippy/tests/ui/ptr_arg.stderr | 3 +- .../ui/significant_drop_in_scrutinee.stderr | 9 +++- src/tools/clippy/tests/ui/unit_arg.stderr | 8 +++- .../clippy/tests/ui/unnecessary_wraps.stderr | 6 ++- 12 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr index f822b6f49fa35..0152a93feee42 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr @@ -56,7 +56,25 @@ LL | if s == "43" { LL ~ return 43; LL | } LL | s == "42" +LL | } { +LL ~ return 45; +LL | } +LL | match s.len() { +LL ~ 10 => 2, +LL | 20 => { ... +LL | if foo() { +LL ~ return 20; +LL | } +LL | println!("foo"); +LL ~ 3 +LL | }; +LL | } +LL ~ 20 +LL | }, +LL ~ 40 => 30, +LL ~ _ => 1, + | error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` --> $DIR/bind_instead_of_map_multipart.rs:61:13 diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index 1db2343d3fe97..37fe2f76f4a02 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr @@ -98,7 +98,8 @@ LL + id: e_id, LL + name: "Player 1".to_string(), LL + some_data: vec![0x12, 0x34, 0x56, 0x78, 0x90], LL + }; - ... +LL + process_data(pack); + | error: all if blocks contain the same code at the start and the end. Here at the start --> $DIR/shared_at_top_and_bottom.rs:94:5 diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr index 1076500498d32..2ef9966525cef 100644 --- a/src/tools/clippy/tests/ui/entry.stderr +++ b/src/tools/clippy/tests/ui/entry.stderr @@ -28,7 +28,8 @@ LL + v LL + } else { LL + v2 LL + } - ... +LL + }); + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:38:5 @@ -50,7 +51,8 @@ LL + v LL + } else { LL + v2 LL + } - ... +LL + }); + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:47:5 @@ -72,7 +74,9 @@ LL + e.insert(v); LL + } else { LL + e.insert(v2); LL + return; - ... +LL + } +LL + } + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:57:5 @@ -111,7 +115,11 @@ LL + 1 if true => { LL + v LL + }, LL + _ => { - ... +LL + v2 +LL + }, +LL + } +LL + }); + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:75:5 @@ -133,7 +141,9 @@ LL + 0 => foo(), LL + _ => { LL + e.insert(v2); LL + }, - ... +LL + }; +LL + } + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:85:5 @@ -155,7 +165,26 @@ LL + match 0 { LL + 0 if false => { LL + v LL + }, - ... +LL + 1 => { +LL + foo(); +LL + v +LL + }, +LL + 2 | 3 => { +LL + for _ in 0..2 { +LL + foo(); +LL + } +LL + if true { +LL + v +LL + } else { +LL + v2 +LL + } +LL + }, +LL + _ => { +LL + v2 +LL + }, +LL + } +LL + }); + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry.rs:119:5 diff --git a/src/tools/clippy/tests/ui/entry_with_else.stderr b/src/tools/clippy/tests/ui/entry_with_else.stderr index 7279efc595959..e0f6671b460ed 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.stderr +++ b/src/tools/clippy/tests/ui/entry_with_else.stderr @@ -17,7 +17,9 @@ LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Occupied(mut e) => { LL + e.insert(v2); - ... +LL + } +LL + } + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry_with_else.rs:22:5 @@ -37,7 +39,9 @@ LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Vacant(e) => { LL + e.insert(v2); - ... +LL + } +LL + } + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry_with_else.rs:28:5 @@ -95,7 +99,9 @@ LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Occupied(mut e) => { LL + e.insert(v2); - ... +LL + } +LL + } + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry_with_else.rs:46:5 @@ -115,7 +121,10 @@ LL + if true { Some(e.insert(v)) } else { Some(e.insert(v2)) } LL + } LL + std::collections::hash_map::Entry::Vacant(e) => { LL + e.insert(v); - ... +LL + None +LL + } +LL ~ }; + | error: usage of `contains_key` followed by `insert` on a `HashMap` --> $DIR/entry_with_else.rs:52:5 diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr index 13ec11a6d33e9..45bf67acdb736 100644 --- a/src/tools/clippy/tests/ui/let_unit.stderr +++ b/src/tools/clippy/tests/ui/let_unit.stderr @@ -32,7 +32,8 @@ LL + .map(|i| i * 2) LL + .filter(|i| i % 2 == 0) LL + .map(|_| ()) LL + .next() - ... +LL + .unwrap(); + | error: this let-binding has unit value --> $DIR/let_unit.rs:80:5 diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index 7435f46074c81..0a903ed6fd436 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -122,7 +122,14 @@ LL + let a = 42; LL + let b = 21; LL + if a < b { LL + let c = 21; - ... +LL + let d = 42; +LL + if c < d { +LL + let _ = 42; +LL + } +LL + } +LL + 42 +LL + } + | error: this function can be simplified using the `async fn` syntax --> $DIR/manual_async_fn.rs:92:1 diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr index f607e0a430e24..7893ff31a6fdb 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr @@ -19,7 +19,8 @@ LL + return; LL + } else { LL + println!("{}", v); LL + } - ... +LL + } + | help: ...and replace `return` with `continue` | LL | continue; diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index 19572dfe8b075..212a69ab94e65 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -117,7 +117,8 @@ LL + Self::new() LL + } LL + } LL + - ... +LL ~ impl Foo { + | error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index a9613daadde10..7ec4a566ff34b 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -56,7 +56,8 @@ LL | let f = e.clone(); // OK LL | let g = x; LL ~ let h = g.to_owned(); LL | let i = (e).clone(); - ... +LL ~ x.to_owned() + | error: writing `&String` instead of `&str` involves a new object where a slice will do --> $DIR/ptr_arg.rs:57:18 diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index 303f3c1df033c..5ce9520441637 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -188,7 +188,9 @@ LL + _ => mutex2.lock().unwrap(), LL + } LL + .s LL + .len() - ... +LL + > 1; +LL ~ match value + | error: temporary with significant drop in match scrutinee --> $DIR/significant_drop_in_scrutinee.rs:397:11 @@ -211,7 +213,10 @@ LL + } else { LL + mutex2.lock().unwrap() LL + } LL + .s - ... +LL + .len() +LL + > 1; +LL ~ match value + | error: temporary with significant drop in match scrutinee --> $DIR/significant_drop_in_scrutinee.rs:451:11 diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 394dee29dc96e..11cfe66a30e85 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -137,7 +137,13 @@ LL + foo(1); LL + }; LL + { LL + foo(2); - ... +LL + foo(3); +LL + }; +LL + taking_multiple_units( +LL + (), +LL + (), +LL ~ ); + | error: passing a unit value to a function --> $DIR/unit_arg.rs:85:13 diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr index 8e31db3950247..a6a0b22cf689f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -23,7 +23,8 @@ LL | if a { LL | Some(-1); LL ~ 2 LL | } else { - ... +LL ~ return 1337; + | error: this function's return value is unnecessarily wrapped by `Option` --> $DIR/unnecessary_wraps.rs:21:1 @@ -122,7 +123,8 @@ LL | if a { LL | Some(()); LL ~ LL | } else { - ... +LL ~ return ; + | error: this function's return value is unnecessary --> $DIR/unnecessary_wraps.rs:117:1 From 784e28e218a12fcf8fd9caaca62798d7c18068b2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 11 Jun 2022 13:21:38 -0700 Subject: [PATCH 09/10] Subtype FRU fields first in type_changing_struct_update --- compiler/rustc_typeck/src/check/expr.rs | 119 +++++++++--------- .../coerce-in-base-expr.rs | 28 +++++ .../type-generic-update.rs | 1 - .../type-generic-update.stderr | 23 ++-- 4 files changed, 93 insertions(+), 78 deletions(-) create mode 100644 src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index dc9d76160c4e9..37d12b4ed5da4 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1561,73 +1561,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: We are currently creating two branches here in order to maintain // consistency. But they should be merged as much as possible. let fru_tys = if self.tcx.features().type_changing_struct_update { - if let ty::Adt(adt, substs) = adt_ty.kind() && adt.is_struct() { - // Make an ADT with fresh inference substitutions. This - // will allow us to guide inference along so that, e.g. + if adt.is_struct() { + // Make some fresh substitutions for our ADT type. + let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did()); + // We do subtyping on the FRU fields first, so we can + // learn exactly what types we expect the base expr + // needs constrained to be compatible with the struct + // type we expect from the expectation value. + let fru_tys = variant + .fields + .iter() + .map(|f| { + let fru_ty = self.normalize_associated_types_in( + expr_span, + self.field_ty(base_expr.span, f, fresh_substs), + ); + let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + let target_ty = self.field_ty(base_expr.span, f, substs); + let cause = self.misc(base_expr.span); + match self.at(&cause, self.param_env).sup(target_ty, fru_ty) { + Ok(InferOk { obligations, value: () }) => { + self.register_predicates(obligations) + } + Err(_) => { + // This should never happen, since we're just subtyping the + // remaining_fields, but it's fine to emit this, I guess. + self.report_mismatched_types( + &cause, + target_ty, + fru_ty, + FieldMisMatch(variant.name, ident.name), + ) + .emit(); + } + } + } + self.resolve_vars_if_possible(fru_ty) + }) + .collect(); + // The use of fresh substs that we have subtyped against + // our base ADT type's fields allows us to guide inference + // along so that, e.g. // ``` - // let x = MyStruct<'a, B, const C: usize> { - // f: 1, - // ..Default::default() + // MyStruct<'a, F1, F2, const C: usize> { + // f: F1, + // // Other fields that reference `'a`, `F2`, and `C` + // } + // + // let x = MyStruct { + // f: 1usize, + // ..other_struct // }; // ``` - // will have the default base expression constrained to - // `MyStruct<'_, _, _>`, as opposed to just `_`... This - // will allow us to then do a subtyping relation on all - // of the `remaining_fields` below, per the RFC. - let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did()); + // will have the `other_struct` expression constrained to + // `MyStruct<'a, _, F2, C>`, as opposed to just `_`... + // This is important to allow coercions to happen in + // `other_struct` itself. See `coerce-in-base-expr.rs`. let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs); - let base_ty = self.check_expr_has_type_or_error( + self.check_expr_has_type_or_error( base_expr, - fresh_base_ty, - |_| { - error_happened = true; - }, + self.resolve_vars_if_possible(fresh_base_ty), + |_| {}, ); - let base_ty = self.shallow_resolve(base_ty); - if let ty::Adt(base_adt, base_substs) = base_ty.kind() && adt == base_adt { - variant - .fields - .iter() - .map(|f| { - let fru_ty = self.normalize_associated_types_in( - expr_span, - self.field_ty(base_expr.span, f, base_substs), - ); - let ident = self - .tcx - .adjust_ident(f.ident(self.tcx), variant.def_id); - if let Some(_) = remaining_fields.remove(&ident) { - let target_ty = - self.field_ty(base_expr.span, f, substs); - let cause = self.misc(base_expr.span); - match self - .at(&cause, self.param_env) - .sup(target_ty, fru_ty) - { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations) - } - // FIXME: Need better diagnostics for `FieldMisMatch` error - Err(_) => { - self.report_mismatched_types( - &cause, - target_ty, - fru_ty, - FieldMisMatch(variant.name, ident.name), - ) - .emit(); - } - } - } - self.resolve_vars_if_possible(fru_ty) - }) - .collect() - } else { - if !error_happened && !base_ty.references_error() { - span_bug!(base_expr.span, "expected an error to have been reported in `check_expr_has_type_or_error`"); - } - return; - } + fru_tys } else { // Check the base_expr, regardless of a bad expected adt_ty, so we can get // type errors on that expression, too. diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs new file mode 100644 index 0000000000000..75e48bf4a482a --- /dev/null +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/coerce-in-base-expr.rs @@ -0,0 +1,28 @@ +// check-pass + +#![feature(type_changing_struct_update)] +#![allow(incomplete_features)] + +use std::any::Any; + +struct Foo { + a: A, + b: Box, + c: Box, +} + +struct B; +struct C; + +fn main() { + let y = Foo:: { + a: 0, + b: Box::new(B), + ..Foo { + a: 0, + b: Box::new(B), + // C needs to be told to coerce to `Box` + c: Box::new(C), + } + }; +} diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs index d8b1396a692a7..dae1241d35a5f 100644 --- a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs @@ -50,7 +50,6 @@ fn fail_update() { let m3 = Machine:: { ..m1 //~^ ERROR mismatched types [E0308] - //~| ERROR mismatched types [E0308] }; } diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr index fa8d6ee23d5ec..6f31b1a962078 100644 --- a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr +++ b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr @@ -2,29 +2,20 @@ error[E0308]: mismatched types --> $DIR/type-generic-update.rs:46:11 | LL | ..m1 - | ^^ field type mismatch: Machine.state + | ^^ expected `i32`, found `f64` | - = note: expected type `i32` - found type `f64` + = note: expected struct `Machine<'_, i32, _>` + found struct `Machine<'_, f64, _>` error[E0308]: mismatched types --> $DIR/type-generic-update.rs:51:11 | LL | ..m1 - | ^^ field type mismatch: Machine.state + | ^^ expected `i32`, found `f64` | - = note: expected type `i32` - found type `f64` + = note: expected struct `Machine<'_, i32, i32>` + found struct `Machine<'_, f64, f64>` -error[E0308]: mismatched types - --> $DIR/type-generic-update.rs:51:11 - | -LL | ..m1 - | ^^ field type mismatch: Machine.message - | - = note: expected type `i32` - found type `f64` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. From 2135331a3352fa81dcb8592daa435d7a32d93ca0 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 17 Jun 2022 18:48:09 +0900 Subject: [PATCH 10/10] remove the rest of unnecessary `to_string` --- compiler/rustc_parse/src/parser/diagnostics.rs | 8 ++++---- src/tools/clippy/clippy_utils/src/sugg.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index c56f70e853daa..acf892cec5328 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2042,9 +2042,9 @@ impl<'a> Parser<'a> { match pat.kind { PatKind::Ident(_, ident, _) => ( ident, - "self: ".to_string(), + "self: ", ": TypeName".to_string(), - "_: ".to_string(), + "_: ", pat.span.shrink_to_lo(), pat.span.shrink_to_hi(), pat.span.shrink_to_lo(), @@ -2058,9 +2058,9 @@ impl<'a> Parser<'a> { let mutab = mutab.prefix_str(); ( ident, - "self: ".to_string(), + "self: ", format!("{ident}: &{mutab}TypeName"), - "_: ".to_string(), + "_: ", pat.span.shrink_to_lo(), pat.span, pat.span.shrink_to_lo(), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 4d21ba8bd1d16..aa119539b1b39 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -771,7 +771,7 @@ impl DiagnosticExt for rustc_errors::Diagnostic { } } - self.span_suggestion(remove_span, msg, String::new(), applicability); + self.span_suggestion(remove_span, msg, "", applicability); } }