From 76438d26b1809c1499859f2943709e40f8df450c Mon Sep 17 00:00:00 2001 From: Fabian Hintringer Date: Mon, 28 Nov 2022 23:01:15 +0100 Subject: [PATCH 01/30] Add example for iterator_flatten --- library/core/src/iter/traits/iterator.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 83c7e8977e9f3..6e9b48cb794cc 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1495,6 +1495,14 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// + /// Flattening also works on other types like Option and Result: + /// + /// ``` + /// let values = vec![Some(123), Some(321), None, Some(231)]; + /// let flattened_values: Vec<_> = values.into_iter().flatten().collect(); + /// assert_eq!(flattened_values, vec![123, 321, 231]); + /// ``` + /// /// You can also rewrite this in terms of [`flat_map()`], which is preferable /// in this case since it conveys intent more clearly: /// From 083560b7d84fd3660a6ba99acb7f2570296063bd Mon Sep 17 00:00:00 2001 From: Fabian Hintringer Date: Tue, 13 Dec 2022 09:17:22 +0100 Subject: [PATCH 02/30] Add result example + rewording --- library/core/src/iter/traits/iterator.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 6e9b48cb794cc..53d353802b9f4 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1495,12 +1495,16 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// - /// Flattening also works on other types like Option and Result: + /// Flattening works on any `IntoIterator` type, including `Option` and `Result`: /// /// ``` - /// let values = vec![Some(123), Some(321), None, Some(231)]; - /// let flattened_values: Vec<_> = values.into_iter().flatten().collect(); - /// assert_eq!(flattened_values, vec![123, 321, 231]); + /// let options = vec![Some(123), Some(321), None, Some(231)]; + /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); + /// assert_eq!(flattened_options, vec![123, 321, 231]); + /// + /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; + /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); + /// assert_eq!(flattened_results, vec![123, 321, 231]); /// ``` /// /// You can also rewrite this in terms of [`flat_map()`], which is preferable From 11331b1030fba551df4c7fc2babd44496040030f Mon Sep 17 00:00:00 2001 From: Tomer Zeitune Date: Sun, 27 Nov 2022 00:35:52 +0200 Subject: [PATCH 03/30] Enable atomic cas for bpf targets --- compiler/rustc_target/src/spec/bpf_base.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index baf36587147a6..2b00cda44b511 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -6,7 +6,7 @@ pub fn opts(endian: Endian) -> TargetOptions { allow_asm: true, endian, linker_flavor: LinkerFlavor::Bpf, - atomic_cas: false, + atomic_cas: true, dynamic_linking: true, no_builtins: true, panic_strategy: PanicStrategy::Abort, @@ -19,6 +19,10 @@ pub fn opts(endian: Endian) -> TargetOptions { obj_is_bitcode: true, requires_lto: false, singlethread: true, + // When targeting the `v3` cpu in llvm, 32-bit atomics are also supported. + // But making this value change based on the target cpu can be mostly confusing + // and would require a bit of a refactor. + min_atomic_width: Some(64), max_atomic_width: Some(64), ..Default::default() } From 564435f20a740d9d95180f3a053aec36feed765d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 04:28:02 +0000 Subject: [PATCH 04/30] Suppress suggestions for nested use tree --- compiler/rustc_resolve/src/imports.rs | 44 ++++++++++++------- src/test/ui/imports/bad-import-in-nested.rs | 14 ++++++ .../ui/imports/bad-import-in-nested.stderr | 9 ++++ 3 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/imports/bad-import-in-nested.rs create mode 100644 src/test/ui/imports/bad-import-in-nested.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4d896b055268e..f9121ae046ad8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -475,12 +475,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { errors = vec![]; } if seen_spans.insert(err.span) { - let path = import_path_to_string( - &import.module_path.iter().map(|seg| seg.ident).collect::>(), - &import.kind, - err.span, - ); - errors.push((path, err)); + errors.push((import, err)); prev_root_id = import.root_id; } } else if is_indeterminate { @@ -496,8 +491,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { suggestion: None, candidate: None, }; + // FIXME: there should be a better way of doing this than + // formatting this as a string then checking for `::` if path.contains("::") { - errors.push((path, err)) + errors.push((import, err)) } } } @@ -507,7 +504,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) { + fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; } @@ -516,7 +513,17 @@ impl<'a, 'b> ImportResolver<'a, 'b> { const MAX_LABEL_COUNT: usize = 10; let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect()); - let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::>(); + let paths = errors + .iter() + .map(|(import, err)| { + let path = import_path_to_string( + &import.module_path.iter().map(|seg| seg.ident).collect::>(), + &import.kind, + err.span, + ); + format!("`{path}`") + }) + .collect::>(); let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),); let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg); @@ -525,7 +532,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.note(note); } - for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { + for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) { if let Some(label) = err.label { diag.span_label(err.span, label); } @@ -539,13 +546,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } if let Some(candidate) = &err.candidate { - import_candidates( - self.r.session, - &self.r.untracked.source_span, - &mut diag, - Some(err.span), - &candidate, - ) + match &import.kind { + ImportKind::Single { nested: false, .. } => import_candidates( + self.r.session, + &self.r.untracked.source_span, + &mut diag, + Some(err.span), + &candidate, + ), + _ => {} + } } } diff --git a/src/test/ui/imports/bad-import-in-nested.rs b/src/test/ui/imports/bad-import-in-nested.rs new file mode 100644 index 0000000000000..5ab0d3d60c9c2 --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.rs @@ -0,0 +1,14 @@ +#![allow(unused)] + +mod A { + pub(crate) type AA = (); +} + +mod C {} + +mod B { + use crate::C::{self, AA}; + //~^ ERROR unresolved import `crate::C::AA` +} + +fn main() {} diff --git a/src/test/ui/imports/bad-import-in-nested.stderr b/src/test/ui/imports/bad-import-in-nested.stderr new file mode 100644 index 0000000000000..a107048d579ca --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `crate::C::AA` + --> $DIR/bad-import-in-nested.rs:10:26 + | +LL | use crate::C::{self, AA}; + | ^^ no `AA` in `C` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. From 9e2536b9389f56386d7f722b403d9730911ee811 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 05:09:33 +0000 Subject: [PATCH 05/30] Note alternative import candidates in nested use tree --- compiler/rustc_resolve/src/diagnostics.rs | 5 ++-- compiler/rustc_resolve/src/imports.rs | 29 +++++++++++++------ src/test/ui/imports/bad-import-in-nested.rs | 17 +++++++++-- .../ui/imports/bad-import-in-nested.stderr | 25 ++++++++++++++-- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 37771693417b3..2e28dad52c7c4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2309,7 +2309,7 @@ enum FoundUse { } /// Whether a binding is part of a pattern or a use statement. Used for diagnostics. -enum DiagnosticMode { +pub(crate) enum DiagnosticMode { Normal, /// The binding is part of a pattern Pattern, @@ -2324,6 +2324,7 @@ pub(crate) fn import_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], + mode: DiagnosticMode, ) { show_candidates( session, @@ -2333,7 +2334,7 @@ pub(crate) fn import_candidates( candidates, Instead::Yes, FoundUse::Yes, - DiagnosticMode::Import, + mode, vec![], ); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f9121ae046ad8..b3593fc9e4712 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,6 +1,6 @@ //! A bunch of methods and structures more or less related to resolving imports. -use crate::diagnostics::{import_candidates, Suggestion}; +use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion}; use crate::Determinacy::{self, *}; use crate::Namespace::*; use crate::{module_to_string, names_to_string, ImportSuggestion}; @@ -402,7 +402,7 @@ struct UnresolvedImportError { label: Option, note: Option, suggestion: Option, - candidate: Option>, + candidates: Option>, } pub struct ImportResolver<'a, 'b> { @@ -489,7 +489,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: None, note: None, suggestion: None, - candidate: None, + candidates: None, }; // FIXME: there should be a better way of doing this than // formatting this as a string then checking for `::` @@ -545,15 +545,26 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.multipart_suggestion(&msg, suggestions, applicability); } - if let Some(candidate) = &err.candidate { + if let Some(candidates) = &err.candidates { match &import.kind { ImportKind::Single { nested: false, .. } => import_candidates( self.r.session, &self.r.untracked.source_span, &mut diag, Some(err.span), - &candidate, + &candidates, + DiagnosticMode::Import, ), + ImportKind::Single { nested: true, .. } => { + import_candidates( + self.r.session, + &self.r.untracked.source_span, + &mut diag, + None, + &candidates, + DiagnosticMode::Normal, + ); + } _ => {} } } @@ -717,14 +728,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { String::from("a similar path exists"), Applicability::MaybeIncorrect, )), - candidate: None, + candidates: None, }, None => UnresolvedImportError { span, label: Some(label), note: None, suggestion, - candidate: None, + candidates: None, }, }; return Some(err); @@ -771,7 +782,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { )), note: None, suggestion: None, - candidate: None, + candidates: None, }); } } @@ -953,7 +964,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(label), note, suggestion, - candidate: if !parent_suggestion.is_empty() { + candidates: if !parent_suggestion.is_empty() { Some(parent_suggestion) } else { None diff --git a/src/test/ui/imports/bad-import-in-nested.rs b/src/test/ui/imports/bad-import-in-nested.rs index 5ab0d3d60c9c2..2e95480ad412e 100644 --- a/src/test/ui/imports/bad-import-in-nested.rs +++ b/src/test/ui/imports/bad-import-in-nested.rs @@ -1,14 +1,27 @@ +// edition: 2021 + #![allow(unused)] mod A { pub(crate) type AA = (); + pub(crate) type BB = (); + + mod A2 { + use super::{super::C::D::AA, AA as _}; + //~^ ERROR unresolved import + } } -mod C {} +mod C { + pub mod D {} +} mod B { use crate::C::{self, AA}; - //~^ ERROR unresolved import `crate::C::AA` + //~^ ERROR unresolved import + + use crate::{A, C::BB}; + //~^ ERROR unresolved import } fn main() {} diff --git a/src/test/ui/imports/bad-import-in-nested.stderr b/src/test/ui/imports/bad-import-in-nested.stderr index a107048d579ca..855b1e637e97f 100644 --- a/src/test/ui/imports/bad-import-in-nested.stderr +++ b/src/test/ui/imports/bad-import-in-nested.stderr @@ -1,9 +1,30 @@ +error[E0432]: unresolved import `super::super::C::D::AA` + --> $DIR/bad-import-in-nested.rs:10:21 + | +LL | use super::{super::C::D::AA, AA as _}; + | ^^^^^^^^^^^^^^^ no `AA` in `C::D` + | + = note: consider importing this type alias instead: + crate::A::AA + error[E0432]: unresolved import `crate::C::AA` - --> $DIR/bad-import-in-nested.rs:10:26 + --> $DIR/bad-import-in-nested.rs:20:26 | LL | use crate::C::{self, AA}; | ^^ no `AA` in `C` + | + = note: consider importing this type alias instead: + crate::A::AA + +error[E0432]: unresolved import `crate::C::BB` + --> $DIR/bad-import-in-nested.rs:23:20 + | +LL | use crate::{A, C::BB}; + | ^^^^^ no `BB` in `C` + | + = note: consider importing this type alias instead: + crate::A::BB -error: aborting due to previous error +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0432`. From d2404d6dca59d34d5b9f0c66b425b08229f20f4b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 07:05:45 +0000 Subject: [PATCH 06/30] Dont clobber `as ..` rename in import suggestion --- compiler/rustc_resolve/src/diagnostics.rs | 9 ++++++- compiler/rustc_resolve/src/imports.rs | 6 +++-- src/test/ui/imports/bad-import-with-rename.rs | 16 ++++++++++++ .../ui/imports/bad-import-with-rename.stderr | 25 +++++++++++++++++++ .../inaccessible-test-modules.stderr | 4 +-- 5 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/imports/bad-import-with-rename.rs create mode 100644 src/test/ui/imports/bad-import-with-rename.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2e28dad52c7c4..c8b96aae7a699 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -161,6 +161,7 @@ impl<'a> Resolver<'a> { found_use, DiagnosticMode::Normal, path, + None, ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { @@ -690,6 +691,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Pattern, vec![], + None, ); } err @@ -1344,6 +1346,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Normal, vec![], + None, ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -2325,6 +2328,7 @@ pub(crate) fn import_candidates( use_placement_span: Option, candidates: &[ImportSuggestion], mode: DiagnosticMode, + append: Option<&str>, ) { show_candidates( session, @@ -2336,6 +2340,7 @@ pub(crate) fn import_candidates( FoundUse::Yes, mode, vec![], + append, ); } @@ -2353,10 +2358,12 @@ fn show_candidates( found_use: FoundUse, mode: DiagnosticMode, path: Vec, + append: Option<&str>, ) { if candidates.is_empty() { return; } + let append = append.unwrap_or(""); let mut accessible_path_strings: Vec<(String, &str, Option, &Option)> = Vec::new(); @@ -2417,7 +2424,7 @@ fn show_candidates( // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); + candidate.0 = format!("{add_use}{}{append};\n{additional_newline}", &candidate.0); } err.span_suggestions( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b3593fc9e4712..d99c1cb6d3cb3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -547,15 +547,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Some(candidates) = &err.candidates { match &import.kind { - ImportKind::Single { nested: false, .. } => import_candidates( + ImportKind::Single { nested: false, source, target, .. } => import_candidates( self.r.session, &self.r.untracked.source_span, &mut diag, Some(err.span), &candidates, DiagnosticMode::Import, + (source != target).then(|| format!(" as {target}")).as_deref(), ), - ImportKind::Single { nested: true, .. } => { + ImportKind::Single { nested: true, source, target, .. } => { import_candidates( self.r.session, &self.r.untracked.source_span, @@ -563,6 +564,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { None, &candidates, DiagnosticMode::Normal, + (source != target).then(|| format!(" as {target}")).as_deref(), ); } _ => {} diff --git a/src/test/ui/imports/bad-import-with-rename.rs b/src/test/ui/imports/bad-import-with-rename.rs new file mode 100644 index 0000000000000..ffe56916f92f0 --- /dev/null +++ b/src/test/ui/imports/bad-import-with-rename.rs @@ -0,0 +1,16 @@ +mod A { + pub type B = (); + pub type B2 = (); +} + +mod C { + use crate::D::B as _; + //~^ ERROR unresolved import `crate::D::B` + + use crate::D::B2; + //~^ ERROR unresolved import `crate::D::B2` +} + +mod D {} + +fn main() {} diff --git a/src/test/ui/imports/bad-import-with-rename.stderr b/src/test/ui/imports/bad-import-with-rename.stderr new file mode 100644 index 0000000000000..cace2a7a51c8e --- /dev/null +++ b/src/test/ui/imports/bad-import-with-rename.stderr @@ -0,0 +1,25 @@ +error[E0432]: unresolved import `crate::D::B` + --> $DIR/bad-import-with-rename.rs:7:9 + | +LL | use crate::D::B as _; + | ^^^^^^^^^^^^^^^^ no `B` in `D` + | +help: consider importing this type alias instead + | +LL | use A::B as _; + | ~~~~~~~~~~ + +error[E0432]: unresolved import `crate::D::B2` + --> $DIR/bad-import-with-rename.rs:10:9 + | +LL | use crate::D::B2; + | ^^^^^^^^^^^^ no `B2` in `D` + | +help: consider importing this type alias instead + | +LL | use A::B2; + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr index 0c16ecd4c862e..17ea648aad6ac 100644 --- a/src/test/ui/test-attrs/inaccessible-test-modules.stderr +++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr @@ -19,8 +19,8 @@ LL | use test as y; | ~~~~ help: consider importing this module instead | -LL | use test::test; - | ~~~~~~~~~~~ +LL | use test::test as y; + | ~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors From 050bc95ce2b23b034d5f41e5c3a8c6e627dfd52a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 07:17:22 +0000 Subject: [PATCH 07/30] Fix some totally useless suggestions --- compiler/rustc_resolve/src/imports.rs | 2 +- .../ui/hygiene/extern-prelude-from-opaque-fail.stderr | 5 +---- src/test/ui/test-attrs/inaccessible-test-modules.stderr | 9 +-------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d99c1cb6d3cb3..0a2a737e1a453 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -896,7 +896,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); let names = resolutions .filter_map(|(BindingKey { ident: i, .. }, resolution)| { - if *i == ident { + if i.name == ident.name { return None; } // Never suggest the same name match *resolution.borrow() { diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index e89c19b5881e5..f1f4caee36197 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -2,10 +2,7 @@ error[E0432]: unresolved import `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:20:9 | LL | use my_core; - | ^^^^^^^ - | | - | no `my_core` in the root - | help: a similar name exists in the module: `my_core` + | ^^^^^^^ no `my_core` in the root error[E0432]: unresolved import `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:7:13 diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr index 17ea648aad6ac..a45c5bd45880f 100644 --- a/src/test/ui/test-attrs/inaccessible-test-modules.stderr +++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr @@ -2,10 +2,7 @@ error[E0432]: unresolved import `main` --> $DIR/inaccessible-test-modules.rs:5:5 | LL | use main as x; - | ----^^^^^ - | | - | no `main` in the root - | help: a similar name exists in the module: `main` + | ^^^^^^^^^ no `main` in the root error[E0432]: unresolved import `test` --> $DIR/inaccessible-test-modules.rs:6:5 @@ -13,10 +10,6 @@ error[E0432]: unresolved import `test` LL | use test as y; | ^^^^^^^^^ no `test` in the root | -help: a similar name exists in the module - | -LL | use test as y; - | ~~~~ help: consider importing this module instead | LL | use test::test as y; From ecdf7f0524d776347bc9cb8154bb8190d025c8d9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 30 Dec 2022 21:51:12 +0000 Subject: [PATCH 08/30] Reuse ErrorGuaranteed during relation --- compiler/rustc_middle/src/ty/_match.rs | 4 +++- compiler/rustc_middle/src/ty/relate.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index cd147d7e55813..b9c5a4e0d0d49 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -89,7 +89,9 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, a, b))) } - (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => { + Ok(self.tcx().ty_error_with_guaranteed(guar)) + } _ => relate::super_relate_tys(self, a, b), } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 4d34ca3d66b5f..65fd8d9753de1 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -414,7 +414,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( bug!("bound types encountered in super_relate_tys") } - (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error_with_guaranteed(guar)), (&ty::Never, _) | (&ty::Char, _) From db6d3b3c019daa22032887ba213e3b7b1c141b36 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 1 Jan 2023 23:48:10 +0000 Subject: [PATCH 09/30] Filter impl and where-clause candidates that reference errors --- .../src/traits/select/candidate_assembly.rs | 3 +- .../src/traits/select/mod.rs | 3 ++ src/test/ui/c-variadic/issue-86053-1.rs | 2 +- src/test/ui/c-variadic/issue-86053-1.stderr | 22 +--------- .../issue-72787.min.stderr | 43 ++----------------- .../generic_const_exprs/issue-72787.rs | 2 - src/test/ui/traits/ignore-err-impls.rs | 9 ++++ src/test/ui/traits/ignore-err-impls.stderr | 11 +++++ .../ui/where-clauses/ignore-err-clauses.rs | 14 ++++++ .../where-clauses/ignore-err-clauses.stderr | 9 ++++ 10 files changed, 54 insertions(+), 64 deletions(-) create mode 100644 src/test/ui/traits/ignore-err-impls.rs create mode 100644 src/test/ui/traits/ignore-err-impls.stderr create mode 100644 src/test/ui/where-clauses/ignore-err-clauses.rs create mode 100644 src/test/ui/where-clauses/ignore-err-clauses.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c54d901e9b10a..170c1673dbd77 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -174,7 +174,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .param_env .caller_bounds() .iter() - .filter_map(|o| o.to_opt_poly_trait_pred()); + .filter_map(|p| p.to_opt_poly_trait_pred()) + .filter(|p| !p.references_error()); // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 760b4585f4e19..9a3fafd5d0dc9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2378,6 +2378,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + if impl_trait_ref.references_error() { + return Err(()); + } debug!(?impl_trait_ref); diff --git a/src/test/ui/c-variadic/issue-86053-1.rs b/src/test/ui/c-variadic/issue-86053-1.rs index b30548e19f9ff..49d5c0390bc13 100644 --- a/src/test/ui/c-variadic/issue-86053-1.rs +++ b/src/test/ui/c-variadic/issue-86053-1.rs @@ -2,7 +2,7 @@ // error-pattern:unexpected `self` parameter in function // error-pattern:`...` must be the last argument of a C-variadic function // error-pattern:cannot find type `F` in this scope -// error-pattern:in type `&'a &'b usize`, reference has a longer lifetime than the data it references + #![feature(c_variadic)] #![crate_type="lib"] diff --git a/src/test/ui/c-variadic/issue-86053-1.stderr b/src/test/ui/c-variadic/issue-86053-1.stderr index d1f13d52362da..5a02f4aa93a95 100644 --- a/src/test/ui/c-variadic/issue-86053-1.stderr +++ b/src/test/ui/c-variadic/issue-86053-1.stderr @@ -76,24 +76,6 @@ help: you might be missing a type parameter LL | fn ordering4 < 'a , 'b, F > ( a : , self , self , self , | +++ -error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references - --> $DIR/issue-86053-1.rs:11:52 - | -LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime `'a` as defined here - --> $DIR/issue-86053-1.rs:10:16 - | -LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , - | ^^ -note: but the referenced data is only valid for the lifetime `'b` as defined here - --> $DIR/issue-86053-1.rs:10:21 - | -LL | fn ordering4 < 'a , 'b > ( a : , self , self , self , - | ^^ - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0412, E0491. -For more information about an error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 0af5493f81675..ea6f5f6927659 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -17,7 +17,7 @@ LL | Condition<{ LHS <= RHS }>: True = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/issue-72787.rs:25:25 + --> $DIR/issue-72787.rs:23:25 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `I` @@ -26,7 +26,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/issue-72787.rs:25:36 + --> $DIR/issue-72787.rs:23:36 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `J` @@ -34,42 +34,5 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = help: const parameters may only be used as standalone arguments, i.e. `J` = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` - --> $DIR/issue-72787.rs:21:26 - | -LL | IsLessOrEqual: True, - | ^^^^ - | -note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual: True` found - --> $DIR/issue-72787.rs:10:1 - | -LL | impl True for IsLessOrEqual where - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | IsLessOrEqual: True, - | ^^^^ -... -LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^^^^ - -error[E0283]: type annotations needed: cannot satisfy `IsLessOrEqual: True` - --> $DIR/issue-72787.rs:21:26 - | -LL | IsLessOrEqual: True, - | ^^^^ - | -note: multiple `impl`s or `where` clauses satisfying `IsLessOrEqual: True` found - --> $DIR/issue-72787.rs:10:1 - | -LL | impl True for IsLessOrEqual where - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | IsLessOrEqual: True, - | ^^^^ -... -LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs b/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs index c651bf1c8de9d..657fec2e9cb70 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-72787.rs @@ -19,8 +19,6 @@ struct S; impl S where IsLessOrEqual: True, -//[min]~^ Error type annotations needed -//[min]~| Error type annotations needed IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, //[min]~^ Error generic parameters may not be used in const operations diff --git a/src/test/ui/traits/ignore-err-impls.rs b/src/test/ui/traits/ignore-err-impls.rs new file mode 100644 index 0000000000000..67e880b006a7f --- /dev/null +++ b/src/test/ui/traits/ignore-err-impls.rs @@ -0,0 +1,9 @@ +pub struct S; + +trait Generic {} + +impl<'a, T> Generic<&'a T> for S {} +impl Generic for S {} +//~^ ERROR cannot find type `Type` in this scope + +fn main() {} diff --git a/src/test/ui/traits/ignore-err-impls.stderr b/src/test/ui/traits/ignore-err-impls.stderr new file mode 100644 index 0000000000000..1390106a29125 --- /dev/null +++ b/src/test/ui/traits/ignore-err-impls.stderr @@ -0,0 +1,11 @@ +error[E0412]: cannot find type `Type` in this scope + --> $DIR/ignore-err-impls.rs:6:14 + | +LL | impl Generic for S {} + | - ^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/where-clauses/ignore-err-clauses.rs b/src/test/ui/where-clauses/ignore-err-clauses.rs new file mode 100644 index 0000000000000..c76f0e1a8b2b5 --- /dev/null +++ b/src/test/ui/where-clauses/ignore-err-clauses.rs @@ -0,0 +1,14 @@ +use std::ops::Add; + +fn dbl(x: T) -> ::Output +where + T: Copy + Add, + UUU: Copy, + //~^ ERROR cannot find type `UUU` in this scope +{ + x + x +} + +fn main() { + println!("{}", dbl(3)); +} diff --git a/src/test/ui/where-clauses/ignore-err-clauses.stderr b/src/test/ui/where-clauses/ignore-err-clauses.stderr new file mode 100644 index 0000000000000..cfddc3e10b64a --- /dev/null +++ b/src/test/ui/where-clauses/ignore-err-clauses.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `UUU` in this scope + --> $DIR/ignore-err-clauses.rs:6:5 + | +LL | UUU: Copy, + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From 6b01b35287f0b658cc5cd25243fbedd0a5ffed43 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 16 Oct 2022 16:15:39 +0200 Subject: [PATCH 10/30] Forbid #[suggestion_*(...)] on Vecs It is ambiguous whether this should produce several `.span_suggestions()` calls or one `.multipart_suggestions()` call. --- .../src/diagnostics/diagnostic_builder.rs | 21 +++--- .../src/diagnostics/subdiagnostic.rs | 21 ++++-- .../rustc_macros/src/diagnostics/utils.rs | 67 ++++++++++--------- .../session-diagnostic/diagnostic-derive.rs | 8 +++ .../diagnostic-derive.stderr | 12 +++- .../subdiagnostic-derive.rs | 10 +++ .../subdiagnostic-derive.stderr | 23 ++++++- 7 files changed, 117 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 82f6812026a7d..4a05478f892c1 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -322,11 +322,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { let generated_code = self .generate_inner_field_code( attr, - FieldInfo { - binding: binding_info, - ty: inner_ty.inner_type().unwrap_or(&field.ty), - span: &field.span(), - }, + FieldInfo { binding: binding_info, ty: inner_ty, span: &field.span() }, binding, ) .unwrap_or_else(|v| v.to_compile_error()); @@ -402,9 +398,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { - if type_matches_path(info.ty, &["rustc_span", "Span"]) { + if type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) - } else if type_is_unit(info.ty) { + } else if type_is_unit(info.ty.inner_type()) { Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { report_type_error(attr, "`Span` or `()`")? @@ -416,6 +412,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { code_field, code_init, } => { + if let FieldInnerTy::Vec(_) = info.ty { + throw_invalid_attr!(attr, &meta, |diag| { + diag + .note("`#[suggestion(...)]` applied to `Vec` field is ambiguous") + .help("to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`") + .help("to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]`") + }); + } + let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?; if let Some((static_applicability, span)) = static_applicability { @@ -473,7 +478,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { &self, info: FieldInfo<'_>, ) -> Result<(TokenStream, SpannedOption), DiagnosticDeriveError> { - match &info.ty { + match &info.ty.inner_type() { // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`. ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => { let binding = &info.binding.binding; diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index baffd3cec9c55..906e4c0b0e16c 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -247,11 +247,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { return quote! {}; } - let info = FieldInfo { - binding, - ty: inner_ty.inner_type().unwrap_or(&ast.ty), - span: &ast.span(), - }; + let info = FieldInfo { binding, ty: inner_ty, span: &ast.span() }; let generated = self .generate_field_code_inner(kind_stats, attr, info, inner_ty.will_iterate()) @@ -312,6 +308,21 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let binding = info.binding.binding.clone(); // FIXME(#100717): support `Option` on `primary_span` like in the // diagnostic derive + if !matches!(info.ty, FieldInnerTy::Plain(_)) { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + let diag = diag.note("there must be exactly one primary span"); + + if kind_stats.has_normal_suggestion { + diag.help( + "to create a suggestion with multiple spans, \ + use `#[multipart_suggestion]` instead", + ) + } else { + diag + } + }); + } + self.span_field.set_once(binding, span); } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 6f52a3de1b151..27b8f676f3fbb 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty( path: &[&str], ty_name: &str, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(info.ty, path) { + if !type_matches_path(info.ty.inner_type(), path) { report_type_error(attr, ty_name)?; } @@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span( attr: &Attribute, info: &FieldInfo<'_>, ) -> Result<(), DiagnosticDeriveError> { - if !type_matches_path(info.ty, &["rustc_span", "Span"]) - && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"]) + if !type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) + && !type_matches_path(info.ty.inner_type(), &["rustc_errors", "MultiSpan"]) { report_type_error(attr, "`Span` or `MultiSpan`")?; } @@ -115,44 +115,50 @@ pub(crate) fn report_error_if_not_applied_to_span( } /// Inner type of a field and type of wrapper. +#[derive(Copy, Clone)] pub(crate) enum FieldInnerTy<'ty> { /// Field is wrapped in a `Option<$inner>`. Option(&'ty Type), /// Field is wrapped in a `Vec<$inner>`. Vec(&'ty Type), /// Field isn't wrapped in an outer type. - None, + Plain(&'ty Type), } impl<'ty> FieldInnerTy<'ty> { /// Returns inner type for a field, if there is one. /// - /// - If `ty` is an `Option`, returns `FieldInnerTy::Option { inner: (inner type) }`. - /// - If `ty` is a `Vec`, returns `FieldInnerTy::Vec { inner: (inner type) }`. - /// - Otherwise returns `None`. + /// - If `ty` is an `Option`, returns `FieldInnerTy::Option(Inner)`. + /// - If `ty` is a `Vec`, returns `FieldInnerTy::Vec(Inner)`. + /// - Otherwise returns `FieldInnerTy::Plain(ty)`. pub(crate) fn from_type(ty: &'ty Type) -> Self { - let variant: &dyn Fn(&'ty Type) -> FieldInnerTy<'ty> = - if type_matches_path(ty, &["std", "option", "Option"]) { - &FieldInnerTy::Option - } else if type_matches_path(ty, &["std", "vec", "Vec"]) { - &FieldInnerTy::Vec - } else { - return FieldInnerTy::None; + fn single_generic_type(ty: &Type) -> &Type { + let Type::Path(ty_path) = ty else { + panic!("expected path type"); }; - if let Type::Path(ty_path) = ty { let path = &ty_path.path; let ty = path.segments.iter().last().unwrap(); - if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments { - if bracketed.args.len() == 1 { - if let syn::GenericArgument::Type(ty) = &bracketed.args[0] { - return variant(ty); - } - } - } + let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments else { + panic!("expected bracketed generic arguments"); + }; + + assert_eq!(bracketed.args.len(), 1); + + let syn::GenericArgument::Type(ty) = &bracketed.args[0] else { + panic!("expected generic parameter to be a type generic"); + }; + + ty } - unreachable!(); + if type_matches_path(ty, &["std", "option", "Option"]) { + FieldInnerTy::Option(single_generic_type(ty)) + } else if type_matches_path(ty, &["std", "vec", "Vec"]) { + FieldInnerTy::Vec(single_generic_type(ty)) + } else { + FieldInnerTy::Plain(ty) + } } /// Returns `true` if `FieldInnerTy::with` will result in iteration for this inner type (i.e. @@ -160,15 +166,16 @@ impl<'ty> FieldInnerTy<'ty> { pub(crate) fn will_iterate(&self) -> bool { match self { FieldInnerTy::Vec(..) => true, - FieldInnerTy::Option(..) | FieldInnerTy::None => false, + FieldInnerTy::Option(..) | FieldInnerTy::Plain(_) => false, } } - /// Returns `Option` containing inner type if there is one. - pub(crate) fn inner_type(&self) -> Option<&'ty Type> { + /// Returns the inner type. + pub(crate) fn inner_type(&self) -> &'ty Type { match self { - FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) => Some(inner), - FieldInnerTy::None => None, + FieldInnerTy::Option(inner) | FieldInnerTy::Vec(inner) | FieldInnerTy::Plain(inner) => { + inner + } } } @@ -185,7 +192,7 @@ impl<'ty> FieldInnerTy<'ty> { #inner } }, - FieldInnerTy::None => quote! { #inner }, + FieldInnerTy::Plain(..) => quote! { #inner }, } } } @@ -194,7 +201,7 @@ impl<'ty> FieldInnerTy<'ty> { /// `generate_*` methods from walking the attributes themselves. pub(crate) struct FieldInfo<'a> { pub(crate) binding: &'a BindingInfo<'a>, - pub(crate) ty: &'a Type, + pub(crate) ty: FieldInnerTy<'a>, pub(crate) span: &'a proc_macro2::Span, } diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index c19b639a8d581..26f7d18056c84 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -801,3 +801,11 @@ struct SuggestionStyleGood { #[suggestion(code = "", style = "hidden")] sub: Span, } + +#[derive(Diagnostic)] +#[diag(compiletest_example)] +struct SuggestionOnVec { + #[suggestion(suggestion, code = "")] + //~^ ERROR `#[suggestion(...)]` is not a valid attribute + sub: Vec, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f39d32a221cac..9bd64a5e6f78b 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -605,6 +605,16 @@ error: `code = "..."`/`code(...)` must contain only string literals LL | #[suggestion(code = 3)] | ^^^^^^^^ +error: `#[suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive.rs:808:5 + | +LL | #[suggestion(suggestion, code = "")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[suggestion(...)]` applied to `Vec` field is ambiguous + = help: to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]` + = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` + error: cannot find attribute `nonsense` in this scope --> $DIR/diagnostic-derive.rs:55:3 | @@ -676,7 +686,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 85 previous errors +error: aborting due to 86 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 61ac456a6b649..09ad696490983 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -798,3 +798,13 @@ struct SuggestionStyleInvalid4 { #[primary_span] sub: Span, } + +#[derive(Subdiagnostic)] +#[suggestion(parse_add_paren, code = "")] +//~^ ERROR suggestion without `#[primary_span]` field +struct PrimarySpanOnVec { + #[primary_span] + //~^ ERROR `#[primary_span]` is not a valid attribute + //~| NOTE there must be exactly one primary span + sub: Vec, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index b594fa6cde1e4..f9d1a63031d7c 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -501,6 +501,27 @@ error: `#[suggestion(style(...))]` is not a valid attribute LL | #[suggestion(parse_add_paren, code = "", style("foo"))] | ^^^^^^^^^^^^ +error: `#[primary_span]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:806:5 + | +LL | #[primary_span] + | ^^^^^^^^^^^^^^^ + | + = note: there must be exactly one primary span + = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead + +error: suggestion without `#[primary_span]` field + --> $DIR/subdiagnostic-derive.rs:803:1 + | +LL | / #[suggestion(parse_add_paren, code = "")] +LL | | +LL | | struct PrimarySpanOnVec { +LL | | #[primary_span] +... | +LL | | sub: Vec, +LL | | } + | |_^ + error: cannot find attribute `foo` in this scope --> $DIR/subdiagnostic-derive.rs:63:3 | @@ -561,6 +582,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 79 previous errors +error: aborting due to 81 previous errors For more information about this error, try `rustc --explain E0425`. From 3e2ae862b47981a3db498a449566d5a4df07f727 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 27 Dec 2022 20:46:39 +0100 Subject: [PATCH 11/30] rustc_parse: avoid creating unnecessary intermediate strings --- compiler/rustc_parse/src/parser/item.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a958c294930ef..a4d14645330bf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -22,6 +22,7 @@ use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; +use std::fmt::Write; use std::mem; use thin_vec::ThinVec; @@ -1109,7 +1110,7 @@ impl<'a> Parser<'a> { let fixed_name_sp = ident.span.to(idents.last().unwrap().span); let mut fixed_name = ident.name.to_string(); for part in idents { - fixed_name.push_str(&format!("_{}", part.name)); + write!(fixed_name, "_{}", part.name).unwrap(); } ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp); From 58edd7f688dc1c102fa6cd4c5d92805d3e8dfe29 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 5 Oct 2022 21:40:56 +0200 Subject: [PATCH 12/30] Use AddToDiagnostic for "use latest edition" help --- compiler/rustc_errors/src/diagnostic.rs | 48 ++++++++++++++----- .../rustc_errors/src/diagnostic_builder.rs | 1 - compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 6 +-- compiler/rustc_parse/src/parser/expr.rs | 6 +-- compiler/rustc_parse/src/parser/item.rs | 15 ++++-- 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index e19a6fe0ee9bf..9fe295f1f0db9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -555,18 +555,6 @@ impl Diagnostic { self } - /// Help the user upgrade to the latest edition. - /// This is factored out to make sure it does the right thing with `Cargo.toml`. - pub fn help_use_latest_edition(&mut self) -> &mut Self { - if std::env::var_os("CARGO").is_some() { - self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); - } else { - self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION)); - } - self.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); - self - } - /// Disallow attaching suggestions this diagnostic. /// Any suggestions attached e.g. with the `span_suggestion_*` methods /// (before and after the call to `disable_suggestions`) will be ignored. @@ -1064,3 +1052,39 @@ impl PartialEq for Diagnostic { self.keys() == other.keys() } } + +pub enum HelpUseLatestEdition { + Cargo, + Standalone, +} + +impl HelpUseLatestEdition { + pub fn new() -> Self { + if std::env::var_os("CARGO").is_some() { Self::Cargo } else { Self::Standalone } + } +} + +impl AddToDiagnostic for HelpUseLatestEdition { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + let msg = f( + diag, + match self { + Self::Cargo => { + format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION) + } + Self::Standalone => { + format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION) + } + } + .into(), + ); + diag.help(msg); + + let msg = + f(diag, "for more on editions, read https://doc.rust-lang.org/edition-guide".into()); + diag.note(msg); + } +} diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index cbfee582d871f..44b427397c4ba 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -616,7 +616,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { sp: impl Into, msg: impl Into, ) -> &mut Self); - forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self); forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b4d23e96f8f45..f9f7ca56b3741 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -370,7 +370,7 @@ pub struct GoodPathBug; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, - DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, + DiagnosticStyledString, HelpUseLatestEdition, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList}; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6ed1bc051a5fa..42966b7720bcd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -23,8 +23,8 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - ErrorGuaranteed, StashKey, + pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, + DiagnosticId, ErrorGuaranteed, HelpUseLatestEdition, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -2415,7 +2415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We know by construction that `.await` is either on Rust 2015 // or results in `ExprKind::Await`. Suggest switching the edition to 2018. err.note("to `.await` a `Future`, switch to Rust 2018 or later"); - err.help_use_latest_edition(); + HelpUseLatestEdition::new().add_to_diagnostic(&mut err); } err.emit(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f436783ceda6..798ea79ec08bb 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -39,8 +39,8 @@ use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, R use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{ - Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, - StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + HelpUseLatestEdition, IntoDiagnostic, PResult, StashKey, }; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; @@ -2874,7 +2874,7 @@ impl<'a> Parser<'a> { let mut async_block_err = |e: &mut Diagnostic, span: Span| { recover_async = true; e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later"); - e.help_use_latest_edition(); + HelpUseLatestEdition::new().add_to_diagnostic(e); }; while self.token != token::CloseDelim(close_delim) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a4d14645330bf..2e08e56b5c91e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -16,7 +16,10 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, IntoDiagnostic, PResult, StashKey}; +use rustc_errors::{ + struct_span_err, AddToDiagnostic, Applicability, HelpUseLatestEdition, IntoDiagnostic, PResult, + StashKey, +}; use rustc_span::edition::Edition; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; @@ -2436,10 +2439,12 @@ impl<'a> Parser<'a> { fn ban_async_in_2015(&self, span: Span) { if span.rust_2015() { let diag = self.diagnostic(); - struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015") - .span_label(span, "to use `async fn`, switch to Rust 2018 or later") - .help_use_latest_edition() - .emit(); + + let mut e = + struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015"); + e.span_label(span, "to use `async fn`, switch to Rust 2018 or later"); + HelpUseLatestEdition::new().add_to_diagnostic(&mut e); + e.emit(); } } From 27c0c4639f1116a5a0460f90a02b2ee411c5b288 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 5 Oct 2022 22:05:45 +0200 Subject: [PATCH 13/30] Implement IntoDiagnosticArg for ast::Visibility --- compiler/rustc_errors/src/diagnostic_impls.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 794b6efcc2b24..940548f20861a 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -177,6 +177,14 @@ impl IntoDiagnosticArg for type_ir::FloatTy { } } +impl IntoDiagnosticArg for ast::Visibility { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + let s = pprust::vis_to_string(&self); + let s = s.trim_end().to_string(); + DiagnosticArgValue::Str(Cow::Owned(s)) + } +} + impl IntoDiagnosticArg for Level { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Borrowed(match self { From f94a148035c7f508cecc2e30089fb1b127e6a144 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 6 Oct 2022 18:35:53 +0200 Subject: [PATCH 14/30] Fix condition for "missing `struct`" diagnostic on tuple structs The check previously matched this, and suggested adding a missing `struct`: pub Foo(...): It was probably intended to match this instead (semicolon instead of colon): pub Foo(...); --- compiler/rustc_parse/src/parser/item.rs | 2 +- src/test/ui/pub/pub-ident-fn-3.rs | 2 +- src/test/ui/pub/pub-ident-fn-3.stderr | 11 ++++++++--- src/test/ui/pub/pub-ident-fn-or-struct-2.rs | 2 +- src/test/ui/pub/pub-ident-fn-or-struct-2.stderr | 11 ++++++++--- src/test/ui/pub/pub-ident-struct-4.fixed | 6 ++++++ src/test/ui/pub/pub-ident-struct-4.rs | 6 ++++++ src/test/ui/pub/pub-ident-struct-4.stderr | 13 +++++++++++++ 8 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/pub/pub-ident-struct-4.fixed create mode 100644 src/test/ui/pub/pub-ident-struct-4.rs create mode 100644 src/test/ui/pub/pub-ident-struct-4.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2e08e56b5c91e..4d2882050bfa8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -412,7 +412,7 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(Delimiter::Brace)) { self.bump(); // `{` ("fn", kw_name, false) - } else if self.check(&token::Colon) { + } else if self.check(&token::Semi) { let kw = "struct"; (kw, kw, false) } else { diff --git a/src/test/ui/pub/pub-ident-fn-3.rs b/src/test/ui/pub/pub-ident-fn-3.rs index fdbea7cf487eb..50db4039d4fc1 100644 --- a/src/test/ui/pub/pub-ident-fn-3.rs +++ b/src/test/ui/pub/pub-ident-fn-3.rs @@ -2,7 +2,7 @@ mod foo { pub bar(); - //~^ ERROR missing `fn` or `struct` for function or struct definition + //~^ ERROR missing `struct` for struct definition } fn main() {} diff --git a/src/test/ui/pub/pub-ident-fn-3.stderr b/src/test/ui/pub/pub-ident-fn-3.stderr index 6d3d4e592c8ed..6969a376a5e76 100644 --- a/src/test/ui/pub/pub-ident-fn-3.stderr +++ b/src/test/ui/pub/pub-ident-fn-3.stderr @@ -1,8 +1,13 @@ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/pub-ident-fn-3.rs:4:8 +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct-2.rs:4:8 | LL | pub bar(); - | ---^--- help: if you meant to call a macro, try: `bar!` + | ^ + | +help: add `struct` here to parse `bar` as a public struct + | +LL | pub struct bar(); + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/pub/pub-ident-fn-or-struct-2.rs b/src/test/ui/pub/pub-ident-fn-or-struct-2.rs index 8f67cdd293342..dfa6cf2ee1e87 100644 --- a/src/test/ui/pub/pub-ident-fn-or-struct-2.rs +++ b/src/test/ui/pub/pub-ident-fn-or-struct-2.rs @@ -1,4 +1,4 @@ pub S(); -//~^ ERROR missing `fn` or `struct` for function or struct definition +//~^ ERROR missing `struct` for struct definition fn main() {} diff --git a/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr b/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr index 047e66b18d8cd..d94198a6b6deb 100644 --- a/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr +++ b/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr @@ -1,8 +1,13 @@ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/pub-ident-fn-or-struct-2.rs:1:4 +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct-3.rs:1:4 | LL | pub S(); - | ---^- help: if you meant to call a macro, try: `S!` + | ^ + | +help: add `struct` here to parse `S` as a public struct + | +LL | pub struct S(); + | ++++++ error: aborting due to previous error diff --git a/src/test/ui/pub/pub-ident-struct-4.fixed b/src/test/ui/pub/pub-ident-struct-4.fixed new file mode 100644 index 0000000000000..b49fa678e1b7d --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-4.fixed @@ -0,0 +1,6 @@ +// run-rustfix + +pub struct T(String); +//~^ ERROR missing `struct` for struct definition + +fn main() {} diff --git a/src/test/ui/pub/pub-ident-struct-4.rs b/src/test/ui/pub/pub-ident-struct-4.rs new file mode 100644 index 0000000000000..20bc94b0acb19 --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-4.rs @@ -0,0 +1,6 @@ +// run-rustfix + +pub T(String); +//~^ ERROR missing `struct` for struct definition + +fn main() {} diff --git a/src/test/ui/pub/pub-ident-struct-4.stderr b/src/test/ui/pub/pub-ident-struct-4.stderr new file mode 100644 index 0000000000000..90c7138e5cee0 --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-4.stderr @@ -0,0 +1,13 @@ +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct-4.rs:3:4 + | +LL | pub T(String); + | ^ + | +help: add `struct` here to parse `T` as a public struct + | +LL | pub struct T(String); + | ++++++ + +error: aborting due to previous error + From 5783b8c0a90948b87465e805d66e548414763433 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 27 Dec 2022 20:34:09 +0100 Subject: [PATCH 15/30] tests: rename test cases to match new behaviour --- src/test/ui/pub/{pub-ident-fn-3.rs => pub-ident-struct-2.rs} | 0 .../ui/pub/{pub-ident-fn-3.stderr => pub-ident-struct-2.stderr} | 0 .../ui/pub/{pub-ident-fn-or-struct-2.rs => pub-ident-struct-3.rs} | 0 ...{pub-ident-fn-or-struct-2.stderr => pub-ident-struct-3.stderr} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/pub/{pub-ident-fn-3.rs => pub-ident-struct-2.rs} (100%) rename src/test/ui/pub/{pub-ident-fn-3.stderr => pub-ident-struct-2.stderr} (100%) rename src/test/ui/pub/{pub-ident-fn-or-struct-2.rs => pub-ident-struct-3.rs} (100%) rename src/test/ui/pub/{pub-ident-fn-or-struct-2.stderr => pub-ident-struct-3.stderr} (100%) diff --git a/src/test/ui/pub/pub-ident-fn-3.rs b/src/test/ui/pub/pub-ident-struct-2.rs similarity index 100% rename from src/test/ui/pub/pub-ident-fn-3.rs rename to src/test/ui/pub/pub-ident-struct-2.rs diff --git a/src/test/ui/pub/pub-ident-fn-3.stderr b/src/test/ui/pub/pub-ident-struct-2.stderr similarity index 100% rename from src/test/ui/pub/pub-ident-fn-3.stderr rename to src/test/ui/pub/pub-ident-struct-2.stderr diff --git a/src/test/ui/pub/pub-ident-fn-or-struct-2.rs b/src/test/ui/pub/pub-ident-struct-3.rs similarity index 100% rename from src/test/ui/pub/pub-ident-fn-or-struct-2.rs rename to src/test/ui/pub/pub-ident-struct-3.rs diff --git a/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr b/src/test/ui/pub/pub-ident-struct-3.stderr similarity index 100% rename from src/test/ui/pub/pub-ident-fn-or-struct-2.stderr rename to src/test/ui/pub/pub-ident-struct-3.stderr From e5282a8f22e94d083794711e6609cf31ab02bc55 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Fri, 14 Oct 2022 23:16:25 +0200 Subject: [PATCH 16/30] rustc_parse: migrate more to diagnostic structs --- .../locales/en-US/parse.ftl | 157 +++++ compiler/rustc_parse/src/errors.rs | 537 +++++++++++++++++- compiler/rustc_parse/src/parser/expr.rs | 30 +- compiler/rustc_parse/src/parser/generics.rs | 26 +- compiler/rustc_parse/src/parser/item.rs | 413 +++++--------- .../rustc_parse/src/parser/nonterminal.rs | 22 +- compiler/rustc_parse/src/parser/pat.rs | 279 ++++----- compiler/rustc_parse/src/parser/stmt.rs | 5 +- src/test/ui/track-diagnostics/track4.stderr | 2 +- 9 files changed, 990 insertions(+), 481 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 3401978caf5f0..18590a95b3845 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -368,3 +368,160 @@ parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn` .suggestion = use `Fn` to refer to the trait + +parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 + .label = to use `async fn`, switch to Rust 2018 or later + +parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later + +parse_self_argument_pointer = cannot pass `self` by raw pointer + .label = cannot pass `self` by raw pointer + +parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item + .label = the visibility + .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}` + +parse_default_not_followed_by_item = `default` is not followed by an item + .label = the `default` qualifier + .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +parse_missing_struct_for_struct_definition = missing `struct` for struct definition + .suggestion = add `struct` here to parse `{$ident}` as a public struct + +parse_missing_fn_for_function_definition = missing `fn` for function definition + .suggestion = add `fn` here to parse `{$ident}` as a public function + +parse_missing_fn_for_method_definition = missing `fn` for method definition + .suggestion = add `fn` here to parse `{$ident}` as a public method + +parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition + .suggestion = if you meant to call a macro, try + .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier + +parse_missing_trait_in_trait_impl = missing trait in a trait impl + .suggestion_add_trait = add a trait here + .suggestion_remove_for = for an inherent impl, drop this `for` + +parse_missing_for_in_trait_impl = missing `for` in a trait impl + .suggestion = add `for` here + +parse_expected_trait_in_trait_impl_found_type = expected a trait, found type + +parse_non_item_in_item_list = non-item in item list + .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const + .label_list_start = item list starts here + .label_non_item = non-item starts here + .label_list_end = item list ends here + .suggestion_remove_semicolon = consider removing this semicolon + +parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases + +parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` + +parse_associated_static_item_not_allowed = associated `static` items are not allowed + +parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements + .label = dash-separated idents are not valid + .suggestion = if the original crate name uses dashes you need to use underscores in the code + +parse_extern_item_cannot_be_const = extern items cannot be `const` + .suggestion = try using a static value + .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +parse_const_global_cannot_be_mutable = const globals cannot be mutable + .label = cannot be mutable + .suggestion = you might want to declare a static instead + +parse_missing_const_type = missing type for `{$kind}` item + .suggestion = provide a type for the item + +parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive + .suggestion = replace `enum struct` with + +parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name +parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}` +parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}` +parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}` +parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}` +parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}` + +parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters + .note = you cannot use `Self` as a generic parameter because it is reserved for associated items + +parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item + .label = previous `where` clause starts here + .suggestion = consider joining the two `where` clauses into one + +parse_nonterminal_expected_item_keyword = expected an item keyword +parse_nonterminal_expected_statement = expected a statement +parse_nonterminal_expected_ident = expected ident, found `{$token}` +parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}` + +parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings +parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters +parse_sugg_remove_leading_vert_in_pattern = remove the `|` +parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses + +parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||` + +parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter + .suggestion = remove the `||` + +parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here + +parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern + .suggestion = use a single `|` to separate multiple alternative patterns + +parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern + .suggestion = remove the `{$token}` + +parse_dotdotdot_rest_pattern = unexpected `...` + .label = not a valid pattern + .suggestion = for a rest pattern, use `..` instead of `...` + +parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@` + .label_pattern = pattern on the left, should be on the right + .label_binding = binding on the right, should be on the left + .suggestion = switch the order + +parse_expected_binding_left_of_at = left-hand side of `@` must be a binding + .label_lhs = interpreted as a pattern, not a binding + .label_rhs = also a pattern + .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation + .suggestion = add parentheses to clarify the precedence + +parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern + .suggestion = remove the lifetime + +parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect + .suggestion = try switching the order + +parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding + .suggestion = add `mut` to each binding +parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding + .suggestion = remove the `mut` prefix +parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern` + +parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated + .suggestion = remove the additional `mut`s + +parse_extra_eq_in_inclusive_range_pattern = unexpected `=` after inclusive range + .suggestion = use `..=` instead + .note = inclusive ranges end with a single equals sign (`..=`) + +parse_inclusive_range_pattern_without_end = inclusive range with no end + .suggestion = use `..` instead + .note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed + .suggestion = use `..=` instead + +parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern + +parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `...` + .suggestion = to omit remaining fields, use one fewer `.` + +parse_expected_comma_after_pattern_field = expected `,` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 574591529f331..abcb203e57d0b 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,6 +1,8 @@ use rustc_ast::token::Token; -use rustc_ast::Path; -use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; +use rustc_ast::{Path, Visibility}; +use rustc_errors::{ + fluent, AddToDiagnostic, Applicability, EmissionGuarantee, HelpUseLatestEdition, IntoDiagnostic, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::symbol::Ident; @@ -1237,3 +1239,534 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { #[suggestion(applicability = "machine-applicable", code = "Fn", style = "verbose")] pub fn_token_span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_async_fn_in_2015, code = "E0670")] +pub(crate) struct AsyncFnIn2015 { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub help: HelpUseLatestEdition, +} + +#[derive(Subdiagnostic)] +#[label(parse_async_block_in_2015)] +pub(crate) struct AsyncBlockIn2015 { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_self_argument_pointer)] +pub(crate) struct SelfArgumentPointer { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_visibility_not_followed_by_item)] +#[help] +pub(crate) struct VisibilityNotFollowedByItem { + #[primary_span] + #[label] + pub span: Span, + pub vis: Visibility, +} + +#[derive(Diagnostic)] +#[diag(parse_default_not_followed_by_item)] +#[note] +pub(crate) struct DefaultNotFollowedByItem { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum MissingKeywordForItemDefinition { + #[diag(parse_missing_struct_for_struct_definition)] + Struct { + #[primary_span] + #[suggestion(style = "short", applicability = "maybe-incorrect", code = " struct ")] + span: Span, + ident: Ident, + }, + #[diag(parse_missing_fn_for_function_definition)] + Function { + #[primary_span] + #[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")] + span: Span, + ident: Ident, + }, + #[diag(parse_missing_fn_for_method_definition)] + Method { + #[primary_span] + #[suggestion(style = "short", applicability = "maybe-incorrect", code = " fn ")] + span: Span, + ident: Ident, + }, + #[diag(parse_ambiguous_missing_keyword_for_item_definition)] + Ambiguous { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiag: Option, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum AmbiguousMissingKwForItemSub { + #[suggestion(suggestion, applicability = "maybe-incorrect", code = "{snippet}!")] + SuggestMacro { + #[primary_span] + span: Span, + snippet: String, + }, + #[help(help)] + HelpMacro, +} + +#[derive(Diagnostic)] +#[diag(parse_missing_trait_in_trait_impl)] +pub(crate) struct MissingTraitInTraitImpl { + #[primary_span] + #[suggestion(suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")] + pub span: Span, + #[suggestion(suggestion_remove_for, code = "", applicability = "maybe-incorrect")] + pub for_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_missing_for_in_trait_impl)] +pub(crate) struct MissingForInTraitImpl { + #[primary_span] + #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_trait_in_trait_impl_found_type)] +pub(crate) struct ExpectedTraitInTraitImplFoundType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_non_item_in_item_list)] +pub(crate) struct NonItemInItemList { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sub: NonItemInItemListSub, + #[suggestion(suggestion_remove_semicolon, code = "", applicability = "maybe-incorrect")] + pub remove_semicolon: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum NonItemInItemListSub { + #[suggestion( + suggestion_use_const_not_let, + code = "const", + applicability = "machine-applicable" + )] + Let { + #[primary_span] + span: Span, + }, + Other { + #[label(label_list_start)] + list_start: Span, + #[label(label_non_item)] + non_item: Span, + #[label(label_list_end)] + list_end: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(parse_bounds_not_allowed_on_trait_aliases)] +pub(crate) struct BoundsNotAllowedOnTraitAliases { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_auto)] +pub(crate) struct TraitAliasCannotBeAuto { + #[primary_span] + #[label(parse_trait_alias_cannot_be_auto)] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_unsafe)] +pub(crate) struct TraitAliasCannotBeUnsafe { + #[primary_span] + #[label(parse_trait_alias_cannot_be_unsafe)] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_associated_static_item_not_allowed)] +pub(crate) struct AssociatedStaticItemNotAllowed { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_extern_crate_name_with_dashes)] +pub(crate) struct ExternCrateNameWithDashes { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: ExternCrateNameWithDashesSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(suggestion, applicability = "machine-applicable")] +pub(crate) struct ExternCrateNameWithDashesSugg { + #[suggestion_part(code = "_")] + pub dashes: Vec, +} + +#[derive(Diagnostic)] +#[diag(parse_extern_item_cannot_be_const)] +#[note] +pub(crate) struct ExternItemCannotBeConst { + #[primary_span] + pub ident_span: Span, + #[suggestion(code = "static ", applicability = "machine-applicable")] + pub const_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_const_global_cannot_be_mutable)] +pub(crate) struct ConstGlobalCannotBeMutable { + #[primary_span] + #[label] + pub ident_span: Span, + #[suggestion(code = "static", applicability = "maybe-incorrect")] + pub const_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_missing_const_type)] +pub(crate) struct MissingConstType { + #[primary_span] + #[suggestion(code = "{colon} ", applicability = "has-placeholders")] + pub span: Span, + + pub kind: &'static str, + pub colon: &'static str, +} + +#[derive(Diagnostic)] +#[diag(parse_enum_struct_mutually_exclusive)] +pub(crate) struct EnumStructMutuallyExclusive { + #[primary_span] + #[suggestion(code = "enum", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum UnexpectedTokenAfterStructName { + #[diag(parse_unexpected_token_after_struct_name_found_reserved_identifier)] + ReservedIdentifier { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + token: Token, + }, + #[diag(parse_unexpected_token_after_struct_name_found_keyword)] + Keyword { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + token: Token, + }, + #[diag(parse_unexpected_token_after_struct_name_found_reserved_keyword)] + ReservedKeyword { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + token: Token, + }, + #[diag(parse_unexpected_token_after_struct_name_found_doc_comment)] + DocComment { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + token: Token, + }, + #[diag(parse_unexpected_token_after_struct_name_found_other)] + Other { + #[primary_span] + #[label(parse_unexpected_token_after_struct_name)] + span: Span, + token: Token, + }, +} + +impl UnexpectedTokenAfterStructName { + pub fn new(span: Span, token: Token) -> Self { + match TokenDescription::from_token(&token) { + Some(TokenDescription::ReservedIdentifier) => Self::ReservedIdentifier { span, token }, + Some(TokenDescription::Keyword) => Self::Keyword { span, token }, + Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token }, + Some(TokenDescription::DocComment) => Self::DocComment { span, token }, + None => Self::Other { span, token }, + } + } +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_self_in_generic_parameters)] +#[note] +pub(crate) struct UnexpectedSelfInGenericParameters { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_multiple_where_clauses)] +pub(crate) struct MultipleWhereClauses { + #[primary_span] + pub span: Span, + #[label] + pub previous: Span, + #[suggestion(style = "verbose", code = ",", applicability = "maybe-incorrect")] + pub between: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum UnexpectedNonterminal { + #[diag(parse_nonterminal_expected_item_keyword)] + Item(#[primary_span] Span), + #[diag(parse_nonterminal_expected_statement)] + Statement(#[primary_span] Span), + #[diag(parse_nonterminal_expected_ident)] + Ident { + #[primary_span] + span: Span, + token: Token, + }, + #[diag(parse_nonterminal_expected_lifetime)] + Lifetime { + #[primary_span] + span: Span, + token: Token, + }, +} + +#[derive(Diagnostic)] +pub(crate) enum TopLevelOrPatternNotAllowed { + #[diag(parse_or_pattern_not_allowed_in_let_binding)] + LetBinding { + #[primary_span] + span: Span, + #[subdiagnostic] + sub: Option, + }, + #[diag(parse_or_pattern_not_allowed_in_fn_parameters)] + FunctionParameter { + #[primary_span] + span: Span, + #[subdiagnostic] + sub: Option, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum TopLevelOrPatternNotAllowedSugg { + #[suggestion( + parse_sugg_remove_leading_vert_in_pattern, + code = "{pat}", + applicability = "machine-applicable" + )] + RemoveLeadingVert { + #[primary_span] + span: Span, + pat: String, + }, + #[suggestion( + parse_sugg_wrap_pattern_in_parens, + code = "({pat})", + applicability = "machine-applicable" + )] + WrapInParens { + #[primary_span] + span: Span, + pat: String, + }, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_vert_vert_before_function_parameter)] +#[note(parse_note_pattern_alternatives_use_single_vert)] +pub(crate) struct UnexpectedVertVertBeforeFunctionParam { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_vert_vert_in_pattern)] +pub(crate) struct UnexpectedVertVertInPattern { + #[primary_span] + #[suggestion(code = "|", applicability = "machine-applicable")] + pub span: Span, + #[label(parse_label_while_parsing_or_pattern_here)] + pub start: Option, +} + +#[derive(Diagnostic)] +#[diag(parse_trailing_vert_not_allowed)] +pub(crate) struct TrailingVertNotAllowed { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + #[label(parse_label_while_parsing_or_pattern_here)] + pub start: Option, + pub token: Token, + #[note(parse_note_pattern_alternatives_use_single_vert)] + pub note_double_vert: Option<()>, +} + +#[derive(Diagnostic)] +#[diag(parse_dotdotdot_rest_pattern)] +pub(crate) struct DotDotDotRestPattern { + #[primary_span] + #[suggestion(style = "short", code = "..", applicability = "machine-applicable")] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_pattern_on_wrong_side_of_at)] +pub(crate) struct PatternOnWrongSideOfAt { + #[primary_span] + #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")] + pub whole_span: Span, + pub whole_pat: String, + #[label(label_pattern)] + pub pattern: Span, + #[label(label_binding)] + pub binding: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_binding_left_of_at)] +#[note] +pub(crate) struct ExpectedBindingLeftOfAt { + #[primary_span] + pub whole_span: Span, + #[label(label_lhs)] + pub lhs: Span, + #[label(label_rhs)] + pub rhs: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_ambiguous_range_pattern)] +pub(crate) struct AmbiguousRangePattern { + #[primary_span] + #[suggestion(code = "({pat})", applicability = "maybe-incorrect")] + pub span: Span, + pub pat: String, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_lifetime_in_pattern)] +pub(crate) struct UnexpectedLifetimeInPattern { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + pub symbol: Symbol, +} + +#[derive(Diagnostic)] +#[diag(parse_ref_mut_order_incorrect)] +pub(crate) struct RefMutOrderIncorrect { + #[primary_span] + #[suggestion(code = "ref mut", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +pub(crate) enum InvalidMutInPattern { + #[diag(parse_mut_on_nested_ident_pattern)] + #[note(parse_note_mut_pattern_usage)] + NestedIdent { + #[primary_span] + #[suggestion(code = "{pat}", applicability = "machine-applicable")] + span: Span, + pat: String, + }, + #[diag(parse_mut_on_non_ident_pattern)] + #[note(parse_note_mut_pattern_usage)] + NonIdent { + #[primary_span] + #[suggestion(code = "{pat}", applicability = "machine-applicable")] + span: Span, + pat: String, + }, +} + +#[derive(Diagnostic)] +#[diag(parse_repeated_mut_in_pattern)] +pub(crate) struct RepeatedMutInPattern { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_extra_eq_in_inclusive_range_pattern)] +#[note] +pub(crate) struct ExtraEqInInclusiveRangePattern { + #[primary_span] + #[suggestion(style = "short", code = "..=", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inclusive_range_pattern_without_end, code = "E0586")] +#[note] +pub(crate) struct InclusiveRangePatternWithoutEnd { + #[primary_span] + #[suggestion(style = "short", code = "..", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)] +pub(crate) struct DotDotDotRangeToPatternNotAllowed { + #[primary_span] + #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_enum_pattern_instead_of_identifier)] +pub(crate) struct EnumPatternInsteadOfIdentifier { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_dot_dot_dot_for_remaining_fields)] +pub(crate) struct DotDotDotForRemainingFields { + #[primary_span] + #[suggestion(code = "..", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_comma_after_pattern_field)] +pub(crate) struct ExpectedCommaAfterPatternField { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 798ea79ec08bb..9c20d0cd20fdc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -6,20 +6,20 @@ use super::{ SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; use crate::errors::{ - ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect, - BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric, - ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, - ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet, - FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt, - IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, - InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub, - InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator, - InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, - LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel, - MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, - MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, - NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub, - OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, + ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncBlockIn2015, + AsyncMoveOrderIncorrect, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, + ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg, + DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr, + ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, + FoundExprWouldBeStmt, IfExpressionMissingCondition, IfExpressionMissingThenBlock, + IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, + InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, + InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, + LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, + MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, + MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, + MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator, + NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere, StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf, UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses, @@ -2873,7 +2873,7 @@ impl<'a> Parser<'a> { let mut async_block_err = |e: &mut Diagnostic, span: Span| { recover_async = true; - e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later"); + AsyncBlockIn2015 { span }.add_to_diagnostic(e); HelpUseLatestEdition::new().add_to_diagnostic(e); }; diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index fa75670b2ed82..7a9f01a223749 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -1,3 +1,5 @@ +use crate::errors::{MultipleWhereClauses, UnexpectedSelfInGenericParameters}; + use super::{ForceCollect, Parser, TrailingToken}; use rustc_ast::token; @@ -118,12 +120,9 @@ impl<'a> Parser<'a> { if this.eat_keyword_noexpect(kw::SelfUpper) { // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing // as if `Self` never existed. - this.struct_span_err( - this.prev_token.span, - "unexpected keyword `Self` in generic parameters", - ) - .note("you cannot use `Self` as a generic parameter because it is reserved for associated items") - .emit(); + this.sess.emit_err(UnexpectedSelfInGenericParameters { + span: this.prev_token.span, + }); this.eat(&token::Comma); } @@ -295,16 +294,11 @@ impl<'a> Parser<'a> { let ate_comma = self.eat(&token::Comma); if self.eat_keyword_noexpect(kw::Where) { - let msg = "cannot define duplicate `where` clauses on an item"; - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(lo, "previous `where` clause starts here"); - err.span_suggestion_verbose( - prev_token.shrink_to_hi().to(self.prev_token.span), - "consider joining the two `where` clauses into one", - ",", - Applicability::MaybeIncorrect, - ); - err.emit(); + self.sess.emit_err(MultipleWhereClauses { + span: self.token.span, + previous: lo, + between: prev_token.shrink_to_hi().to(self.prev_token.span), + }); } else if !ate_comma { break; } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4d2882050bfa8..496364f1c751b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,4 +1,13 @@ -use crate::errors::{DocCommentDoesNotDocumentAnything, UseEmptyBlockNotSemi}; +use crate::errors::{ + AmbiguousMissingKwForItemSub, AssociatedStaticItemNotAllowed, AsyncFnIn2015, + BoundsNotAllowedOnTraitAliases, ConstGlobalCannotBeMutable, ConstLetMutuallyExclusive, + DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive, + ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg, + ExternItemCannotBeConst, MissingConstType, MissingForInTraitImpl, + MissingKeywordForItemDefinition, MissingTraitInTraitImpl, NonItemInItemList, + NonItemInItemListSub, SelfArgumentPointer, TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, + UnexpectedTokenAfterStructName, UseEmptyBlockNotSemi, VisibilityNotFollowedByItem, +}; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; @@ -17,8 +26,8 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{ - struct_span_err, AddToDiagnostic, Applicability, HelpUseLatestEdition, IntoDiagnostic, PResult, - StashKey, + struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, HelpUseLatestEdition, + IntoDiagnostic, PResult, StashKey, }; use rustc_span::edition::Edition; use rustc_span::lev_distance::lev_distance; @@ -167,35 +176,18 @@ impl<'a> Parser<'a> { } // At this point, we have failed to parse an item. - self.error_on_unmatched_vis(&vis); - self.error_on_unmatched_defaultness(def); - if !attrs_allowed { - self.recover_attrs_no_item(&attrs)?; + if !matches!(vis.kind, VisibilityKind::Inherited) { + self.sess.emit_err(VisibilityNotFollowedByItem { span: vis.span, vis }); } - Ok(None) - } - /// Error in-case a non-inherited visibility was parsed but no item followed. - fn error_on_unmatched_vis(&self, vis: &Visibility) { - if let VisibilityKind::Inherited = vis.kind { - return; + if let Defaultness::Default(span) = def { + self.sess.emit_err(DefaultNotFollowedByItem { span }); } - let vs = pprust::vis_to_string(&vis); - let vs = vs.trim_end(); - self.struct_span_err(vis.span, &format!("visibility `{vs}` is not followed by an item")) - .span_label(vis.span, "the visibility") - .help(&format!("you likely meant to define an item, e.g., `{vs} fn foo() {{}}`")) - .emit(); - } - /// Error in-case a `default` was parsed but no item followed. - fn error_on_unmatched_defaultness(&self, def: Defaultness) { - if let Defaultness::Default(sp) = def { - self.struct_span_err(sp, "`default` is not followed by an item") - .span_label(sp, "the `default` qualifier") - .note("only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`") - .emit(); + if !attrs_allowed { + self.recover_attrs_no_item(&attrs)?; } + Ok(None) } /// Error in-case `default` was parsed in an in-appropriate context. @@ -388,86 +380,72 @@ impl<'a> Parser<'a> { let sp = self.prev_token.span.between(self.token.span); let full_sp = self.prev_token.span.to(self.token.span); let ident_sp = self.token.span; - if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) { + + let ident = if self.look_ahead(1, |t| { + [ + token::Lt, + token::OpenDelim(Delimiter::Brace), + token::OpenDelim(Delimiter::Parenthesis), + ] + .contains(&t.kind) + }) { + self.parse_ident().unwrap() + } else { + return Ok(()); + }; + + let mut found_generics = false; + if self.check(&token::Lt) { + found_generics = true; + self.eat_to_tokens(&[&token::Gt]); + self.bump(); // `>` + } + + let err = if self.check(&token::OpenDelim(Delimiter::Brace)) { // possible public struct definition where `struct` was forgotten - let ident = self.parse_ident().unwrap(); - let msg = format!("add `struct` here to parse `{ident}` as a public struct"); - let mut err = self.struct_span_err(sp, "missing `struct` for struct definition"); - err.span_suggestion_short( - sp, - &msg, - " struct ", - Applicability::MaybeIncorrect, // speculative - ); - Err(err) - } else if self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)) { - let ident = self.parse_ident().unwrap(); + Some(MissingKeywordForItemDefinition::Struct { span: sp, ident }) + } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { + // possible public function or tuple struct definition where `fn`/`struct` was + // forgotten self.bump(); // `(` - let kw_name = self.recover_first_param(); + let is_method = self.recover_self_param(); + self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes); - let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { + + let err = if self.check(&token::RArrow) + || self.check(&token::OpenDelim(Delimiter::Brace)) + { self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]); self.bump(); // `{` - ("fn", kw_name, false) - } else if self.check(&token::OpenDelim(Delimiter::Brace)) { - self.bump(); // `{` - ("fn", kw_name, false) + self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); + if is_method { + MissingKeywordForItemDefinition::Method { span: sp, ident } + } else { + MissingKeywordForItemDefinition::Function { span: sp, ident } + } } else if self.check(&token::Semi) { - let kw = "struct"; - (kw, kw, false) + MissingKeywordForItemDefinition::Struct { span: sp, ident } } else { - ("fn` or `struct", "function or struct", true) + MissingKeywordForItemDefinition::Ambiguous { + span: sp, + subdiag: if found_generics { + None + } else if let Ok(snippet) = self.span_to_snippet(ident_sp) { + Some(AmbiguousMissingKwForItemSub::SuggestMacro { span: full_sp, snippet }) + } else { + Some(AmbiguousMissingKwForItemSub::HelpMacro) + }, + } }; + Some(err) + } else if found_generics { + Some(MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None }) + } else { + None + }; - let msg = format!("missing `{kw}` for {kw_name} definition"); - let mut err = self.struct_span_err(sp, &msg); - if !ambiguous { - self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); - let suggestion = - format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"); - err.span_suggestion_short( - sp, - &suggestion, - format!(" {kw} "), - Applicability::MachineApplicable, - ); - } else if let Ok(snippet) = self.span_to_snippet(ident_sp) { - err.span_suggestion( - full_sp, - "if you meant to call a macro, try", - format!("{}!", snippet), - // this is the `ambiguous` conditional branch - Applicability::MaybeIncorrect, - ); - } else { - err.help( - "if you meant to call a macro, remove the `pub` \ - and add a trailing `!` after the identifier", - ); - } - Err(err) - } else if self.look_ahead(1, |t| *t == token::Lt) { - let ident = self.parse_ident().unwrap(); - self.eat_to_tokens(&[&token::Gt]); - self.bump(); // `>` - let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(Delimiter::Parenthesis)) { - ("fn", self.recover_first_param(), false) - } else if self.check(&token::OpenDelim(Delimiter::Brace)) { - ("struct", "struct", false) - } else { - ("fn` or `struct", "function or struct", true) - }; - let msg = format!("missing `{kw}` for {kw_name} definition"); - let mut err = self.struct_span_err(sp, &msg); - if !ambiguous { - err.span_suggestion_short( - sp, - &format!("add `{kw}` here to parse `{ident}` as a public {kw_name}"), - format!(" {} ", kw), - Applicability::MachineApplicable, - ); - } - Err(err) + if let Some(err) = err { + Err(err.into_diagnostic(&self.sess.span_diagnostic)) } else { Ok(()) } @@ -516,16 +494,13 @@ impl<'a> Parser<'a> { let mut err = self.struct_span_err(end.span, msg); if end.is_doc_comment() { err.span_label(end.span, "this doc comment doesn't document anything"); - } - if end.meta_kind().is_some() { - if self.token.kind == TokenKind::Semi { - err.span_suggestion_verbose( - self.token.span, - "consider removing this semicolon", - "", - Applicability::MaybeIncorrect, - ); - } + } else if self.token.kind == TokenKind::Semi { + err.span_suggestion_verbose( + self.token.span, + "consider removing this semicolon", + "", + Applicability::MaybeIncorrect, + ); } if let [.., penultimate, _] = attrs { err.span_label(start.span.to(penultimate.span), "other attributes here"); @@ -592,20 +567,9 @@ impl<'a> Parser<'a> { let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt) { let span = self.prev_token.span.between(self.token.span); - self.struct_span_err(span, "missing trait in a trait impl") - .span_suggestion( - span, - "add a trait here", - " Trait ", - Applicability::HasPlaceholders, - ) - .span_suggestion( - span.to(self.token.span), - "for an inherent impl, drop this `for`", - "", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess + .emit_err(MissingTraitInTraitImpl { span, for_span: span.to(self.token.span) }); + P(Ty { kind: TyKind::Path(None, err_path(span)), span, @@ -638,14 +602,7 @@ impl<'a> Parser<'a> { Some(ty_second) => { // impl Trait for Type if !has_for { - self.struct_span_err(missing_for_span, "missing `for` in a trait impl") - .span_suggestion_short( - missing_for_span, - "add `for` here", - " for ", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(MissingForInTraitImpl { span: missing_for_span }); } let ty_first = ty_first.into_inner(); @@ -653,7 +610,8 @@ impl<'a> Parser<'a> { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, _ => { - self.struct_span_err(ty_first.span, "expected a trait, found type").emit(); + self.sess + .emit_err(ExpectedTraitInTraitImplFoundType { span: ty_first.span }); err_path(ty_first.span) } }; @@ -745,29 +703,22 @@ impl<'a> Parser<'a> { let non_item_span = self.token.span; let is_let = self.token.is_keyword(kw::Let); - let mut err = self.struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); - if is_let { - err.span_suggestion( - non_item_span, - "consider using `const` instead of `let` for associated const", - "const", - Applicability::MachineApplicable, - ); - } else { - err.span_label(open_brace_span, "item list starts here") - .span_label(non_item_span, "non-item starts here") - .span_label(self.prev_token.span, "item list ends here"); - } - if is_unnecessary_semicolon { - err.span_suggestion( - semicolon_span, - "consider removing this semicolon", - "", - Applicability::MaybeIncorrect, - ); - } - err.emit(); + + self.sess.emit_err(NonItemInItemList { + span: non_item_span, + sub: if is_let { + NonItemInItemListSub::Let { span: non_item_span } + } else { + NonItemInItemListSub::Other { + list_start: open_brace_span, + non_item: non_item_span, + list_end: self.prev_token.span, + } + }, + remove_semicolon: is_unnecessary_semicolon.then_some(semicolon_span), + }); + break; } Ok(Some(item)) => items.extend(item), @@ -787,6 +738,7 @@ impl<'a> Parser<'a> { fn recover_doc_comment_before_brace(&mut self) -> bool { if let token::DocComment(..) = self.token.kind { if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) { + // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585) struct_span_err!( self.diagnostic(), self.token.span, @@ -853,7 +805,7 @@ impl<'a> Parser<'a> { // It's a trait alias. if had_colon { let span = span_at_colon.to(span_before_eq); - self.struct_span_err(span, "bounds are not allowed on trait aliases").emit(); + self.sess.emit_err(BoundsNotAllowedOnTraitAliases { span }); } let bounds = self.parse_generic_bounds(None)?; @@ -862,12 +814,10 @@ impl<'a> Parser<'a> { let whole_span = lo.to(self.prev_token.span); if is_auto == IsAuto::Yes { - let msg = "trait aliases cannot be `auto`"; - self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); + self.sess.emit_err(TraitAliasCannotBeAuto { span: whole_span }); } if let Unsafe::Yes(_) = unsafety { - let msg = "trait aliases cannot be `unsafe`"; - self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit(); + self.sess.emit_err(TraitAliasCannotBeUnsafe { span: whole_span }); } self.sess.gated_spans.gate(sym::trait_alias, whole_span); @@ -913,8 +863,7 @@ impl<'a> Parser<'a> { Ok(kind) => kind, Err(kind) => match kind { ItemKind::Static(a, _, b) => { - self.struct_span_err(span, "associated `static` items are not allowed") - .emit(); + self.sess.emit_err(AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Defaultness::Final, a, b) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), @@ -1088,41 +1037,37 @@ impl<'a> Parser<'a> { } fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> { - let error_msg = "crate name using dashes are not valid in `extern crate` statements"; - let suggestion_msg = "if the original crate name uses dashes you need to use underscores \ - in the code"; - let mut ident = if self.token.is_keyword(kw::SelfLower) { + let ident = if self.token.is_keyword(kw::SelfLower) { self.parse_path_segment_ident() } else { self.parse_ident() }?; - let mut idents = vec![]; - let mut replacement = vec![]; - let mut fixed_crate_name = false; - // Accept `extern crate name-like-this` for better diagnostics. + let dash = token::BinOp(token::BinOpToken::Minus); - if self.token == dash { - // Do not include `-` as part of the expected tokens list. - while self.eat(&dash) { - fixed_crate_name = true; - replacement.push((self.prev_token.span, "_".to_string())); - idents.push(self.parse_ident()?); - } + if self.token != dash { + return Ok(ident); } - if fixed_crate_name { - let fixed_name_sp = ident.span.to(idents.last().unwrap().span); - let mut fixed_name = ident.name.to_string(); - for part in idents { - write!(fixed_name, "_{}", part.name).unwrap(); - } - ident = Ident::from_str_and_span(&fixed_name, fixed_name_sp); - self.struct_span_err(fixed_name_sp, error_msg) - .span_label(fixed_name_sp, "dash-separated idents are not valid") - .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) - .emit(); + // Accept `extern crate name-like-this` for better diagnostics. + let mut dashes = vec![]; + let mut idents = vec![]; + while self.eat(&dash) { + dashes.push(self.prev_token.span); + idents.push(self.parse_ident()?); } - Ok(ident) + + let fixed_name_sp = ident.span.to(idents.last().unwrap().span); + let mut fixed_name = ident.name.to_string(); + for part in idents { + write!(fixed_name, "_{}", part.name).unwrap(); + } + + self.sess.emit_err(ExternCrateNameWithDashes { + span: fixed_name_sp, + sugg: ExternCrateNameWithDashesSugg { dashes }, + }); + + Ok(Ident::from_str_and_span(&fixed_name, fixed_name_sp)) } /// Parses `extern` for foreign ABIs modules. @@ -1170,7 +1115,10 @@ impl<'a> Parser<'a> { Ok(kind) => kind, Err(kind) => match kind { ItemKind::Const(_, a, b) => { - self.error_on_foreign_const(span, ident); + self.sess.emit_err(ExternItemCannotBeConst { + ident_span: ident.span, + const_span: span.with_hi(ident.span.lo()), + }); ForeignItemKind::Static(a, Mutability::Not, b) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1182,6 +1130,7 @@ impl<'a> Parser<'a> { } fn error_bad_item_kind(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option { + // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`) let span = self.sess.source_map().guess_head_span(span); let descr = kind.descr(); self.struct_span_err(span, &format!("{descr} is not supported in {ctx}")) @@ -1190,18 +1139,6 @@ impl<'a> Parser<'a> { None } - fn error_on_foreign_const(&self, span: Span, ident: Ident) { - self.struct_span_err(ident.span, "extern items cannot be `const`") - .span_suggestion( - span.with_hi(ident.span.lo()), - "try using a static value", - "static ", - Applicability::MachineApplicable, - ) - .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") - .emit(); - } - fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) @@ -1229,25 +1166,10 @@ impl<'a> Parser<'a> { fn recover_const_mut(&mut self, const_span: Span) { if self.eat_keyword(kw::Mut) { let span = self.prev_token.span; - self.struct_span_err(span, "const globals cannot be mutable") - .span_label(span, "cannot be mutable") - .span_suggestion( - const_span, - "you might want to declare a static instead", - "static", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(ConstGlobalCannotBeMutable { ident_span: span, const_span }); } else if self.eat_keyword(kw::Let) { let span = self.prev_token.span; - self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive") - .span_suggestion( - const_span.to(span), - "remove `let`", - "const", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(ConstLetMutuallyExclusive { span: const_span.to(span) }); } } @@ -1332,13 +1254,8 @@ impl<'a> Parser<'a> { }; let span = self.prev_token.span.shrink_to_hi(); - let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item")); - err.span_suggestion( - span, - "provide a type for the item", - format!("{colon} "), - Applicability::HasPlaceholders, - ); + let err: DiagnosticBuilder<'_, ErrorGuaranteed> = + MissingConstType { span, colon, kind }.into_diagnostic(&self.sess.span_diagnostic); err.stash(span, StashKey::ItemNoType); // The user intended that the type be inferred, @@ -1350,18 +1267,12 @@ impl<'a> Parser<'a> { fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { if self.token.is_keyword(kw::Struct) { let span = self.prev_token.span.to(self.token.span); - let mut err = self.struct_span_err(span, "`enum` and `struct` are mutually exclusive"); - err.span_suggestion( - span, - "replace `enum struct` with", - "enum", - Applicability::MachineApplicable, - ); + let err = EnumStructMutuallyExclusive { span }; if self.look_ahead(1, |t| t.is_ident()) { self.bump(); - err.emit(); + self.sess.emit_err(err); } else { - return Err(err); + return Err(err.into_diagnostic(&self.sess.span_diagnostic)); } } @@ -1489,13 +1400,8 @@ impl<'a> Parser<'a> { self.expect_semi()?; body } else { - let token_str = super::token_descr(&self.token); - let msg = &format!( - "expected `where`, `{{`, `(`, or `;` after struct name, found {token_str}" - ); - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name"); - return Err(err); + let err = UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone()); + return Err(err.into_diagnostic(&self.sess.span_diagnostic)); }; Ok((class_name, ItemKind::Struct(vdata, generics))) @@ -2325,7 +2231,9 @@ impl<'a> Parser<'a> { let ext = self.parse_extern(case); if let Async::Yes { span, .. } = asyncness { - self.ban_async_in_2015(span); + if span.rust_2015() { + self.sess.emit_err(AsyncFnIn2015 { span, help: HelpUseLatestEdition::new() }); + } } if !self.eat_keyword_case(kw::Fn, case) { @@ -2435,19 +2343,6 @@ impl<'a> Parser<'a> { Ok(FnHeader { constness, unsafety, asyncness, ext }) } - /// We are parsing `async fn`. If we are on Rust 2015, emit an error. - fn ban_async_in_2015(&self, span: Span) { - if span.rust_2015() { - let diag = self.diagnostic(); - - let mut e = - struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015"); - e.span_label(span, "to use `async fn`, switch to Rust 2018 or later"); - HelpUseLatestEdition::new().add_to_diagnostic(&mut e); - e.emit(); - } - } - /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, @@ -2590,9 +2485,7 @@ impl<'a> Parser<'a> { }; // Recover for the grammar `*self`, `*const self`, and `*mut self`. let recover_self_ptr = |this: &mut Self| { - let msg = "cannot pass `self` by raw pointer"; - let span = this.token.span; - this.struct_span_err(span, msg).span_label(span, msg).emit(); + self.sess.emit_err(SelfArgumentPointer { span: this.token.span }); Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span)) }; @@ -2673,14 +2566,14 @@ impl<'a> Parser<'a> { && self.look_ahead(offset + 1, |t| t == &token::Colon) } - fn recover_first_param(&mut self) -> &'static str { + fn recover_self_param(&mut self) -> bool { match self .parse_outer_attributes() .and_then(|_| self.parse_self_param()) .map_err(|e| e.cancel()) { - Ok(Some(_)) => "method", - _ => "function", + Ok(Some(_)) => true, + _ => false, } } } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 239ed79ce2ffb..7a4d53ed8bbe0 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -2,9 +2,11 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token}; use rustc_ast::HasTokens; use rustc_ast_pretty::pprust; +use rustc_errors::IntoDiagnostic; use rustc_errors::PResult; use rustc_span::symbol::{kw, Ident}; +use crate::errors::UnexpectedNonterminal; use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle}; @@ -113,7 +115,8 @@ impl<'a> Parser<'a> { NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { Some(item) => token::NtItem(item), None => { - return Err(self.struct_span_err(self.token.span, "expected an item keyword")); + return Err(UnexpectedNonterminal::Item(self.token.span) + .into_diagnostic(&self.sess.span_diagnostic)); } }, NonterminalKind::Block => { @@ -124,7 +127,8 @@ impl<'a> Parser<'a> { NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { Some(s) => token::NtStmt(P(s)), None => { - return Err(self.struct_span_err(self.token.span, "expected a statement")); + return Err(UnexpectedNonterminal::Statement(self.token.span) + .into_diagnostic(&self.sess.span_diagnostic)); } }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => { @@ -160,9 +164,10 @@ impl<'a> Parser<'a> { token::NtIdent(ident, is_raw) } NonterminalKind::Ident => { - let token_str = pprust::token_to_string(&self.token); - let msg = &format!("expected ident, found {}", &token_str); - return Err(self.struct_span_err(self.token.span, msg)); + return Err(UnexpectedNonterminal::Ident { + span: self.token.span, + token: self.token.clone(), + }.into_diagnostic(&self.sess.span_diagnostic)); } NonterminalKind::Path => token::NtPath( P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), @@ -175,9 +180,10 @@ impl<'a> Parser<'a> { if self.check_lifetime() { token::NtLifetime(self.expect_lifetime().ident) } else { - let token_str = pprust::token_to_string(&self.token); - let msg = &format!("expected a lifetime, found `{}`", &token_str); - return Err(self.struct_span_err(self.token.span, msg)); + return Err(UnexpectedNonterminal::Lifetime { + span: self.token.span, + token: self.token.clone(), + }.into_diagnostic(&self.sess.span_diagnostic)); } } }; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0b057f2f577fe..ef275bafe7280 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,5 +1,13 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; -use crate::errors::RemoveLet; +use crate::errors::{ + AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, + DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, + ExpectedCommaAfterPatternField, ExtraEqInInclusiveRangePattern, + InclusiveRangePatternWithoutEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, + RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, TopLevelOrPatternNotAllowed, + TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedLifetimeInPattern, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, +}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -9,7 +17,9 @@ use rustc_ast::{ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; +use rustc_errors::{ + fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, +}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; @@ -54,6 +64,12 @@ enum EatOrResult { None, } +/// The syntax location of a given pattern. Used for diagnostics. +pub(super) enum PatternLocation { + LetBinding, + FunctionParameter, +} + impl<'a> Parser<'a> { /// Parses a pattern. /// @@ -167,7 +183,7 @@ impl<'a> Parser<'a> { &mut self, expected: Expected, rc: RecoverComma, - syntax_loc: &str, + syntax_loc: PatternLocation, ) -> PResult<'a, (P, bool)> { // We use `parse_pat_allow_top_alt` regardless of whether we actually want top-level // or-patterns so that we can detect when a user tries to use it. This allows us to print a @@ -181,27 +197,41 @@ impl<'a> Parser<'a> { let colon = self.eat(&token::Colon); if let PatKind::Or(pats) = &pat.kind { - let msg = format!("top-level or-patterns are not allowed in {}", syntax_loc); - let (help, fix) = if pats.len() == 1 { - // If all we have is a leading vert, then print a special message. This is the case - // if `parse_pat_allow_top_alt` returns an or-pattern with one variant. - let msg = "remove the `|`"; - let fix = pprust::pat_to_string(&pat); - (msg, fix) - } else { - let msg = "wrap the pattern in parentheses"; - let fix = format!("({})", pprust::pat_to_string(&pat)); - (msg, fix) - }; + let span = pat.span; if trailing_vert { // We already emitted an error and suggestion to remove the trailing vert. Don't // emit again. - self.sess.span_diagnostic.delay_span_bug(pat.span, &msg); + + // FIXME(#100717): pass `TopLevelOrPatternNotAllowed::* { sub: None }` to + // `delay_span_bug()` instead of fluent message + self.sess.span_diagnostic.delay_span_bug( + span, + match syntax_loc { + PatternLocation::LetBinding => { + fluent::parse_or_pattern_not_allowed_in_let_binding + } + PatternLocation::FunctionParameter => { + fluent::parse_or_pattern_not_allowed_in_fn_parameters + } + }, + ); } else { - self.struct_span_err(pat.span, &msg) - .span_suggestion(pat.span, help, fix, Applicability::MachineApplicable) - .emit(); + let pat = pprust::pat_to_string(&pat); + let sub = if pats.len() == 1 { + Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat }) + } else { + Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) + }; + + self.sess.emit_err(match syntax_loc { + PatternLocation::LetBinding => { + TopLevelOrPatternNotAllowed::LetBinding { span, sub } + } + PatternLocation::FunctionParameter => { + TopLevelOrPatternNotAllowed::FunctionParameter { span, sub } + } + }); } } @@ -218,15 +248,15 @@ impl<'a> Parser<'a> { // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that // separately. if let token::OrOr = self.token.kind { - let span = self.token.span; - let mut err = self.struct_span_err(span, "unexpected `||` before function parameter"); - err.span_suggestion(span, "remove the `||`", "", Applicability::MachineApplicable); - err.note("alternatives in or-patterns are separated with `|`, not `||`"); - err.emit(); + self.sess.emit_err(UnexpectedVertVertBeforeFunctionParam { span: self.token.span }); self.bump(); } - self.parse_pat_before_ty(PARAM_EXPECTED, RecoverComma::No, "function parameters") + self.parse_pat_before_ty( + PARAM_EXPECTED, + RecoverComma::No, + PatternLocation::FunctionParameter, + ) } /// Eat the or-pattern `|` separator. @@ -236,7 +266,7 @@ impl<'a> Parser<'a> { EatOrResult::TrailingVert } else if matches!(self.token.kind, token::OrOr) { // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(lo); + self.sess.emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo }); self.bump(); EatOrResult::AteOr } else if self.eat(&token::BinOp(token::Or)) { @@ -270,7 +300,13 @@ impl<'a> Parser<'a> { }); match (is_end_ahead, &self.token.kind) { (true, token::BinOp(token::Or) | token::OrOr) => { - self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern"); + // A `|` or possibly `||` token shouldn't be here. Ban it. + self.sess.emit_err(TrailingVertNotAllowed { + span: self.token.span, + start: lo, + token: self.token.clone(), + note_double_vert: matches!(self.token.kind, token::OrOr).then_some(()), + }); self.bump(); true } @@ -278,40 +314,6 @@ impl<'a> Parser<'a> { } } - /// We have parsed `||` instead of `|`. Error and suggest `|` instead. - fn ban_unexpected_or_or(&mut self, lo: Option) { - let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern"); - err.span_suggestion( - self.token.span, - "use a single `|` to separate multiple alternative patterns", - "|", - Applicability::MachineApplicable, - ); - if let Some(lo) = lo { - err.span_label(lo, WHILE_PARSING_OR_MSG); - } - err.emit(); - } - - /// A `|` or possibly `||` token shouldn't be here. Ban it. - fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { - let span = self.token.span; - let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx)); - err.span_suggestion( - span, - &format!("remove the `{}`", pprust::token_to_string(&self.token)), - "", - Applicability::MachineApplicable, - ); - if let Some(lo) = lo { - err.span_label(lo, WHILE_PARSING_OR_MSG); - } - if let token::OrOr = self.token.kind { - err.note("alternatives in or-patterns are separated with `|`, not `||`"); - } - err.emit(); - } - /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -454,15 +456,7 @@ impl<'a> Parser<'a> { self.bump(); // `...` // The user probably mistook `...` for a rest pattern `..`. - self.struct_span_err(lo, "unexpected `...`") - .span_label(lo, "not a valid pattern") - .span_suggestion_short( - lo, - "for a rest pattern, use `..` instead of `...`", - "..", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(DotDotDotRestPattern { span: lo }); PatKind::Rest } @@ -487,7 +481,7 @@ impl<'a> Parser<'a> { // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` let mut rhs = self.parse_pat_no_top_alt(None)?; - let sp = lhs.span.to(rhs.span); + let whole_span = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, sub @ None) = &mut rhs.kind { // The user inverted the order, so help them fix that. @@ -496,27 +490,23 @@ impl<'a> Parser<'a> { // The RHS is now the full pattern. *sub = Some(lhs); - self.struct_span_err(sp, "pattern on wrong side of `@`") - .span_label(lhs_span, "pattern on the left, should be on the right") - .span_label(rhs.span, "binding on the right, should be on the left") - .span_suggestion( - sp, - "switch the order", - pprust::pat_to_string(&rhs), - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(PatternOnWrongSideOfAt { + whole_span, + whole_pat: pprust::pat_to_string(&rhs), + pattern: lhs_span, + binding: rhs.span, + }); } else { // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. rhs.kind = PatKind::Wild; - self.struct_span_err(sp, "left-hand side of `@` must be a binding") - .span_label(lhs.span, "interpreted as a pattern, not a binding") - .span_label(rhs.span, "also a pattern") - .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`") - .emit(); + self.sess.emit_err(ExpectedBindingLeftOfAt { + whole_span, + lhs: lhs.span, + rhs: rhs.span, + }); } - rhs.span = sp; + rhs.span = whole_span; Ok(rhs) } @@ -531,35 +521,23 @@ impl<'a> Parser<'a> { _ => return, } - self.struct_span_err(pat.span, "the range pattern here has ambiguous interpretation") - .span_suggestion( - pat.span, - "add parentheses to clarify the precedence", - format!("({})", pprust::pat_to_string(&pat)), - // "ambiguous interpretation" implies that we have to be guessing - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess + .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(&pat) }); } /// Parse `&pat` / `&mut pat`. fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> { self.expect_and()?; - self.recover_lifetime_in_deref_pat(); - let mutbl = self.parse_mutability(); - let subpat = self.parse_pat_with_range_pat(false, expected)?; - Ok(PatKind::Ref(subpat, mutbl)) - } - - fn recover_lifetime_in_deref_pat(&mut self) { if let token::Lifetime(name) = self.token.kind { self.bump(); // `'a` - let span = self.prev_token.span; - self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name)) - .span_suggestion(span, "remove the lifetime", "", Applicability::MachineApplicable) - .emit(); + self.sess + .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name }); } + + let mutbl = self.parse_mutability(); + let subpat = self.parse_pat_with_range_pat(false, expected)?; + Ok(PatKind::Ref(subpat, mutbl)) } /// Parse a tuple or parenthesis pattern. @@ -587,7 +565,8 @@ impl<'a> Parser<'a> { let mut_span = self.prev_token.span; if self.eat_keyword(kw::Ref) { - return self.recover_mut_ref_ident(mut_span); + self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) }); + return self.parse_pat_ident(BindingAnnotation::REF_MUT); } self.recover_additional_muts(); @@ -617,22 +596,6 @@ impl<'a> Parser<'a> { Ok(pat.into_inner().kind) } - /// Recover on `mut ref? ident @ pat` and suggest - /// that the order of `mut` and `ref` is incorrect. - fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> { - let mutref_span = lo.to(self.prev_token.span); - self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") - .span_suggestion( - mutref_span, - "try switching the order", - "ref mut", - Applicability::MachineApplicable, - ) - .emit(); - - self.parse_pat_ident(BindingAnnotation::REF_MUT) - } - /// Turn all by-value immutable bindings in a pattern into mutable bindings. /// Returns `true` if any change was made. fn make_all_value_bindings_mutable(pat: &mut P) -> bool { @@ -657,16 +620,13 @@ impl<'a> Parser<'a> { /// Error on `mut $pat` where `$pat` is not an ident. fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { let span = lo.to(pat.span); - let fix = pprust::pat_to_string(&pat); - let (problem, suggestion) = if changed_any_binding { - ("`mut` must be attached to each individual binding", "add `mut` to each binding") + let pat = pprust::pat_to_string(&pat); + + self.sess.emit_err(if changed_any_binding { + InvalidMutInPattern::NestedIdent { span, pat } } else { - ("`mut` must be followed by a named binding", "remove the `mut` prefix") - }; - self.struct_span_err(span, problem) - .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable) - .note("`mut` may be followed by `variable` and `variable @ pattern`") - .emit(); + InvalidMutInPattern::NonIdent { span, pat } + }); } /// Eat any extraneous `mut`s and error + recover if we ate any. @@ -677,15 +637,7 @@ impl<'a> Parser<'a> { return; } - let span = lo.to(self.prev_token.span); - self.struct_span_err(span, "`mut` on a binding may not be repeated") - .span_suggestion( - span, - "remove the additional `mut`s", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(RepeatedMutInPattern { span: lo.to(self.prev_token.span) }); } /// Parse macro invocation @@ -768,26 +720,12 @@ impl<'a> Parser<'a> { let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); } - self.error_inclusive_range_with_extra_equals(span_with_eq); + self.sess.emit_err(ExtraEqInInclusiveRangePattern { span: span_with_eq }); } else { - self.error_inclusive_range_with_no_end(span); + self.sess.emit_err(InclusiveRangePatternWithoutEnd { span }); } } - fn error_inclusive_range_with_extra_equals(&self, span: Span) { - self.struct_span_err(span, "unexpected `=` after inclusive range") - .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect) - .note("inclusive ranges end with a single equals sign (`..=`)") - .emit(); - } - - fn error_inclusive_range_with_no_end(&self, span: Span) { - struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") - .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable) - .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)") - .emit(); - } - /// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed. /// /// The form `...X` is prohibited to reduce confusion with the potential @@ -796,14 +734,7 @@ impl<'a> Parser<'a> { let end = self.parse_pat_range_end()?; if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node { *syn = RangeSyntax::DotDotEq; - self.struct_span_err(re.span, "range-to patterns with `...` are not allowed") - .span_suggestion_short( - re.span, - "use `..=` instead", - "..=", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span }); } Ok(PatKind::Range(None, Some(end), re)) } @@ -879,8 +810,8 @@ impl<'a> Parser<'a> { // binding mode then we do not end up here, because the lookahead // will direct us over to `parse_enum_variant()`. if self.token == token::OpenDelim(Delimiter::Parenthesis) { - return Err(self - .struct_span_err(self.prev_token.span, "expected identifier, found enum pattern")); + return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span } + .into_diagnostic(&self.sess.span_diagnostic)); } Ok(PatKind::Ident(binding_annotation, ident, sub)) @@ -997,7 +928,8 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { - let err = self.struct_span_err(self.token.span, "expected `,`"); + let err = ExpectedCommaAfterPatternField { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); if let Some(mut delayed) = delayed_err { delayed.emit(); } @@ -1110,14 +1042,7 @@ impl<'a> Parser<'a> { return; } - self.struct_span_err(self.token.span, "expected field pattern, found `...`") - .span_suggestion( - self.token.span, - "to omit remaining fields, use one fewer `.`", - "..", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(DotDotDotForRemainingFields { span: self.token.span }); } fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 0daae457d3022..a68a7139aceeb 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -1,7 +1,7 @@ use super::attr::InnerAttrForbiddenReason; use super::diagnostics::AttemptLocalParseRecovery; use super::expr::LhsExpr; -use super::pat::RecoverComma; +use super::pat::{PatternLocation, RecoverComma}; use super::path::PathStyle; use super::TrailingToken; use super::{ @@ -269,7 +269,8 @@ impl<'a> Parser<'a> { } self.report_invalid_identifier_error()?; - let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?; + let (pat, colon) = + self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?; let (err, ty) = if colon { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/test/ui/track-diagnostics/track4.stderr b/src/test/ui/track-diagnostics/track4.stderr index c4668444c4bbb..9ebf222ee342f 100644 --- a/src/test/ui/track-diagnostics/track4.stderr +++ b/src/test/ui/track-diagnostics/track4.stderr @@ -3,7 +3,7 @@ error: missing `struct` for struct definition | LL | pub onion { | ^ --Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/diagnostics.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/item.rs:LL:CC | help: add `struct` here to parse `onion` as a public struct | From e4e17a38282c51f2fc45dd412f0ba870b3083ff1 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 8 Nov 2022 22:03:17 +0100 Subject: [PATCH 17/30] Convert rustc_parse::parser::pat::Expected to enum This is required in order to support translatable diagnostics. --- .../rustc_parse/src/parser/diagnostics.rs | 4 +- compiler/rustc_parse/src/parser/expr.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 48 ++++++++++++------- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b3231f55bc6e6..9d5bc67ed7c6e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2007,7 +2007,7 @@ impl<'a> Parser<'a> { } pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { - let pat = self.parse_pat_no_top_alt(Some("argument name"))?; + let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName))?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -2352,7 +2352,7 @@ impl<'a> Parser<'a> { pub(crate) fn maybe_recover_colon_colon_in_pat_typo( &mut self, mut first_pat: P, - expected: Expected, + expected: Option, ) -> P { if token::Colon != self.token.kind { return first_pat; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9c20d0cd20fdc..7cb80a197831c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,5 +1,5 @@ use super::diagnostics::SnapshotParser; -use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; +use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, @@ -2175,7 +2175,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { - let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?; + let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName))?; let ty = if this.eat(&token::Colon) { this.parse_ty()? } else { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index ef275bafe7280..f91081c450e33 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -24,10 +24,26 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -pub(super) type Expected = Option<&'static str>; +#[derive(PartialEq, Copy, Clone)] +pub enum Expected { + ParameterName, + ArgumentName, + Identifier, + BindingPattern, +} -/// `Expected` for function and lambda parameter patterns. -pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); +impl Expected { + // FIXME(#100717): migrate users of this to proper localization + fn to_string_or_fallback(expected: Option) -> &'static str { + match expected { + Some(Expected::ParameterName) => "parameter name", + Some(Expected::ArgumentName) => "argument name", + Some(Expected::Identifier) => "identifier", + Some(Expected::BindingPattern) => "binding pattern", + None => "pattern", + } + } +} const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; @@ -76,7 +92,7 @@ impl<'a> Parser<'a> { /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns /// at the top level. Used when parsing the parameters of lambda expressions, /// functions, function pointers, and `pat` macro fragments. - pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P> { + pub fn parse_pat_no_top_alt(&mut self, expected: Option) -> PResult<'a, P> { self.parse_pat_with_range_pat(true, expected) } @@ -90,7 +106,7 @@ impl<'a> Parser<'a> { /// simplify the grammar somewhat. pub fn parse_pat_allow_top_alt( &mut self, - expected: Expected, + expected: Option, rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, @@ -102,7 +118,7 @@ impl<'a> Parser<'a> { /// recovered). fn parse_pat_allow_top_alt_inner( &mut self, - expected: Expected, + expected: Option, rc: RecoverComma, ra: RecoverColon, rt: CommaRecoveryMode, @@ -181,7 +197,7 @@ impl<'a> Parser<'a> { /// otherwise). pub(super) fn parse_pat_before_ty( &mut self, - expected: Expected, + expected: Option, rc: RecoverComma, syntax_loc: PatternLocation, ) -> PResult<'a, (P, bool)> { @@ -253,7 +269,7 @@ impl<'a> Parser<'a> { } self.parse_pat_before_ty( - PARAM_EXPECTED, + Some(Expected::ParameterName), RecoverComma::No, PatternLocation::FunctionParameter, ) @@ -319,7 +335,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_range_pat( &mut self, allow_range_pat: bool, - expected: Expected, + expected: Option, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -415,7 +431,7 @@ impl<'a> Parser<'a> { let lt = self.expect_lifetime(); let (lit, _) = self.recover_unclosed_char(lt.ident, Parser::mk_token_lit_char, |self_| { - let expected = expected.unwrap_or("pattern"); + let expected = Expected::to_string_or_fallback(expected); let msg = format!( "expected {}, found {}", expected, @@ -526,7 +542,7 @@ impl<'a> Parser<'a> { } /// Parse `&pat` / `&mut pat`. - fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> { + fn parse_pat_deref(&mut self, expected: Option) -> PResult<'a, PatKind> { self.expect_and()?; if let token::Lifetime(name) = self.token.kind { self.bump(); // `'a` @@ -579,7 +595,7 @@ impl<'a> Parser<'a> { } // Parse the pattern we hope to be an identifier. - let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?; + let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier))?; // If we don't have `mut $ident (@ pat)?`, error. if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind @@ -651,11 +667,11 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, err: DiagnosticBuilder<'a, ErrorGuaranteed>, - expected: Expected, + expected: Option, ) -> PResult<'a, P> { err.cancel(); - let expected = expected.unwrap_or("pattern"); + let expected = Expected::to_string_or_fallback(expected); let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token)); let mut err = self.struct_span_err(self.token.span, &msg); @@ -799,7 +815,7 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) } else { None }; @@ -893,7 +909,7 @@ impl<'a> Parser<'a> { // We cannot use `parse_pat_ident()` since it will complain `box` // is not an identifier. let sub = if self.eat(&token::At) { - Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) + Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern))?) } else { None }; From 5167ca8c5cb2f70ff3aafb641b29b165b905e084 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 18 Oct 2022 18:03:12 +0200 Subject: [PATCH 18/30] migrate parser::ty to diagnostic structs --- .../locales/en-US/parse.ftl | 35 +++++ compiler/rustc_parse/src/errors.rs | 103 +++++++++++++++ compiler/rustc_parse/src/parser/ty.rs | 123 ++++++------------ 3 files changed, 176 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 18590a95b3845..56b17b35dd4b6 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -525,3 +525,38 @@ parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `...` .suggestion = to omit remaining fields, use one fewer `.` parse_expected_comma_after_pattern_field = expected `,` + +parse_return_types_use_thin_arrow = return types are denoted using `->` + .suggestion = use `->` instead + +parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+` + +parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type + .suggestion = add `mut` or `const` here + +parse_lifetime_after_mut = lifetime must precede `mut` + .suggestion = place the lifetime before `mut` + +parse_dyn_after_mut = `mut` must precede `dyn` + .suggestion = place `mut` before `dyn` + +parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const` + .label = `const` because of this + .suggestion = remove the `const` qualifier + +parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async` + .label = `async` because of this + .suggestion = remove the `async` qualifier + +parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type + +parse_invalid_dyn_keyword = invalid `dyn` keyword + .help = `dyn` is only needed at the start of a trait `+`-separated list + .suggestion = remove this keyword + +parse_negative_bounds_not_supported = negative bounds are not supported + .label = negative bounds are not supported + .suggestion = {$num_bounds -> + [one] remove the bound + *[other] remove the bounds + } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index abcb203e57d0b..f292665f91c62 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1770,3 +1770,106 @@ pub(crate) struct ExpectedCommaAfterPatternField { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_return_types_use_thin_arrow)] +pub(crate) struct ReturnTypesUseThinArrow { + #[primary_span] + #[suggestion(style = "short", code = "->", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_need_plus_after_trait_object_lifetime)] +pub(crate) struct NeedPlusAfterTraitObjectLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_mut_or_const_in_raw_pointer_type)] +pub(crate) struct ExpectedMutOrConstInRawPointerType { + #[primary_span] + pub span: Span, + #[suggestion(code("mut ", "const "), applicability = "has-placeholders")] + pub after_asterisk: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_lifetime_after_mut)] +pub(crate) struct LifetimeAfterMut { + #[primary_span] + pub span: Span, + #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")] + pub suggest_lifetime: Option, + pub snippet: String, +} + +#[derive(Diagnostic)] +#[diag(parse_dyn_after_mut)] +pub(crate) struct DynAfterMut { + #[primary_span] + #[suggestion(code = "&mut dyn", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_fn_pointer_cannot_be_const)] +pub(crate) struct FnPointerCannotBeConst { + #[primary_span] + pub span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + #[label] + pub qualifier: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_fn_pointer_cannot_be_async)] +pub(crate) struct FnPointerCannotBeAsync { + #[primary_span] + pub span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + #[label] + pub qualifier: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_nested_c_variadic_type, code = "E0743")] +pub(crate) struct NestedCVariadicType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_invalid_dyn_keyword)] +#[help] +pub(crate) struct InvalidDynKeyword { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_negative_bounds_not_supported)] +pub(crate) struct NegativeBoundsNotSupported { + #[primary_span] + pub negative_bounds: Vec, + #[label] + pub last_span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + suggestion, + style = "tool-only", + code = "{fixed}", + applicability = "machine-applicable" +)] +pub(crate) struct NegativeBoundsNotSupportedSugg { + #[primary_span] + pub bound_list: Span, + pub num_bounds: usize, + pub fixed: String, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a6f702e542869..ed47b421a44af 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,6 +1,12 @@ use super::{Parser, PathStyle, TokenType}; -use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg}; +use crate::errors::{ + DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, + FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg, + InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, + NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType, + ReturnTypesUseThinArrow, +}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use ast::DUMMY_NODE_ID; @@ -11,7 +17,7 @@ use rustc_ast::{ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, }; -use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; @@ -217,14 +223,7 @@ impl<'a> Parser<'a> { // Don't `eat` to prevent `=>` from being added as an expected token which isn't // actually expected and could only confuse users self.bump(); - self.struct_span_err(self.prev_token.span, "return types are denoted using `->`") - .span_suggestion_short( - self.prev_token.span, - "use `->` instead", - "->", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span }); let ty = self.parse_ty_common( allow_plus, AllowCVariadic::No, @@ -310,7 +309,7 @@ impl<'a> Parser<'a> { } else { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - self.error_illegal_c_varadic_ty(lo); + self.sess.emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); TyKind::Err } } else { @@ -372,8 +371,7 @@ impl<'a> Parser<'a> { let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); let bounds = self.parse_generic_bounds_common(allow_plus, None)?; if lt_no_plus { - self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`") - .emit(); + self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo }); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } @@ -407,14 +405,10 @@ impl<'a> Parser<'a> { fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { let span = self.prev_token.span; - self.struct_span_err(span, "expected `mut` or `const` keyword in raw pointer type") - .span_suggestions( - span.shrink_to_hi(), - "add `mut` or `const` here", - ["mut ".to_string(), "const ".to_string()], - Applicability::HasPlaceholders, - ) - .emit(); + self.sess.emit_err(ExpectedMutOrConstInRawPointerType { + span, + after_asterisk: span.shrink_to_hi(), + }); Mutability::Not }); let ty = self.parse_ty_no_plus()?; @@ -469,16 +463,13 @@ impl<'a> Parser<'a> { let lifetime_span = self.token.span; let span = and_span.to(lifetime_span); - let mut err = self.struct_span_err(span, "lifetime must precede `mut`"); - if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { - err.span_suggestion( - span, - "place the lifetime before `mut`", - format!("&{} mut", lifetime_src), - Applicability::MaybeIncorrect, - ); - } - err.emit(); + let (suggest_lifetime, snippet) = + if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { + (Some(span), lifetime_src) + } else { + (None, String::new()) + }; + self.sess.emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet }); opt_lifetime = Some(self.expect_lifetime()); } @@ -488,14 +479,7 @@ impl<'a> Parser<'a> { { // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`. let span = and_span.to(self.look_ahead(1, |t| t.span)); - let mut err = self.struct_span_err(span, "`mut` must precede `dyn`"); - err.span_suggestion( - span, - "place `mut` before `dyn`", - "&mut dyn", - Applicability::MachineApplicable, - ); - err.emit(); + self.sess.emit_err(DynAfterMut { span }); // Recovery mutbl = Mutability::Mut; @@ -549,10 +533,10 @@ impl<'a> Parser<'a> { // If we ever start to allow `const fn()`, then update // feature gating for `#![feature(const_extern_fn)]` to // cover it. - self.error_fn_ptr_bad_qualifier(whole_span, span, "const"); + self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span }); } if let ast::Async::Yes { span, .. } = asyncness { - self.error_fn_ptr_bad_qualifier(whole_span, span, "async"); + self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span }); } let decl_span = span_start.to(self.token.span); Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span }))) @@ -600,19 +584,6 @@ impl<'a> Parser<'a> { Ok(()) } - /// Emit an error for the given bad function pointer qualifier. - fn error_fn_ptr_bad_qualifier(&self, span: Span, qual_span: Span, qual: &str) { - self.struct_span_err(span, &format!("an `fn` pointer type cannot be `{}`", qual)) - .span_label(qual_span, format!("`{}` because of this", qual)) - .span_suggestion_short( - qual_span, - &format!("remove the `{}` qualifier", qual), - "", - Applicability::MaybeIncorrect, - ) - .emit(); - } - /// Parses an `impl B0 + ... + Bn` type. fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { // Always parse bounds greedily for better error recovery. @@ -699,16 +670,6 @@ impl<'a> Parser<'a> { } } - fn error_illegal_c_varadic_ty(&self, lo: Span) { - struct_span_err!( - self.sess.span_diagnostic, - lo.to(self.prev_token.span), - E0743, - "C-variadic type `...` may not be nested inside another type", - ) - .emit(); - } - pub(super) fn parse_generic_bounds( &mut self, colon_span: Option, @@ -736,15 +697,7 @@ impl<'a> Parser<'a> { { if self.token.is_keyword(kw::Dyn) { // Account for `&dyn Trait + dyn Other`. - self.struct_span_err(self.token.span, "invalid `dyn` keyword") - .help("`dyn` is only needed at the start of a trait `+`-separated list") - .span_suggestion( - self.token.span, - "remove this keyword", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(InvalidDynKeyword { span: self.token.span }); self.bump(); } match self.parse_generic_bound()? { @@ -781,11 +734,7 @@ impl<'a> Parser<'a> { bounds: &[GenericBound], negative_bounds: Vec, ) { - let negative_bounds_len = negative_bounds.len(); - let last_span = *negative_bounds.last().expect("no negative bounds, but still error?"); - let mut err = self.struct_span_err(negative_bounds, "negative bounds are not supported"); - err.span_label(last_span, "negative bounds are not supported"); - if let Some(bound_list) = colon_span { + let sub = if let Some(bound_list) = colon_span { let bound_list = bound_list.to(self.prev_token.span); let mut new_bound_list = String::new(); if !bounds.is_empty() { @@ -796,14 +745,18 @@ impl<'a> Parser<'a> { } new_bound_list = new_bound_list.replacen(" +", ":", 1); } - err.tool_only_span_suggestion( + + Some(NegativeBoundsNotSupportedSugg { bound_list, - &format!("remove the bound{}", pluralize!(negative_bounds_len)), - new_bound_list, - Applicability::MachineApplicable, - ); - } - err.emit(); + num_bounds: negative_bounds.len(), + fixed: new_bound_list, + }) + } else { + None + }; + + let last_span = *negative_bounds.last().expect("no negative bounds, but still error?"); + self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub }); } /// Parses a bound according to the grammar: From a37ff4cc1f459bba343d27de387a21e94432a844 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 13 Dec 2022 18:57:41 +0100 Subject: [PATCH 19/30] rustc_parse: revert conversion of "non-item in item list" diagnostic #[derive(Subdiagnostic)] does not allow multiple subdiagnostics on one variant, as in NonItemInItemListSub::Other. --- compiler/rustc_parse/src/errors.rs | 32 ------------------ compiler/rustc_parse/src/parser/item.rs | 43 ++++++++++++++----------- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index f292665f91c62..a2aad02bc0b43 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1353,38 +1353,6 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_non_item_in_item_list)] -pub(crate) struct NonItemInItemList { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sub: NonItemInItemListSub, - #[suggestion(suggestion_remove_semicolon, code = "", applicability = "maybe-incorrect")] - pub remove_semicolon: Option, -} - -#[derive(Subdiagnostic)] -pub(crate) enum NonItemInItemListSub { - #[suggestion( - suggestion_use_const_not_let, - code = "const", - applicability = "machine-applicable" - )] - Let { - #[primary_span] - span: Span, - }, - Other { - #[label(label_list_start)] - list_start: Span, - #[label(label_non_item)] - non_item: Span, - #[label(label_list_end)] - list_end: Span, - }, -} - #[derive(Diagnostic)] #[diag(parse_bounds_not_allowed_on_trait_aliases)] pub(crate) struct BoundsNotAllowedOnTraitAliases { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 496364f1c751b..3d249aef2f1f7 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -4,9 +4,9 @@ use crate::errors::{ DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive, ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg, ExternItemCannotBeConst, MissingConstType, MissingForInTraitImpl, - MissingKeywordForItemDefinition, MissingTraitInTraitImpl, NonItemInItemList, - NonItemInItemListSub, SelfArgumentPointer, TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, - UnexpectedTokenAfterStructName, UseEmptyBlockNotSemi, VisibilityNotFollowedByItem, + MissingKeywordForItemDefinition, MissingTraitInTraitImpl, SelfArgumentPointer, + TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, UnexpectedTokenAfterStructName, + UseEmptyBlockNotSemi, VisibilityNotFollowedByItem, }; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; @@ -703,22 +703,29 @@ impl<'a> Parser<'a> { let non_item_span = self.token.span; let is_let = self.token.is_keyword(kw::Let); + let mut err = self.struct_span_err(non_item_span, "non-item in item list"); self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes); - - self.sess.emit_err(NonItemInItemList { - span: non_item_span, - sub: if is_let { - NonItemInItemListSub::Let { span: non_item_span } - } else { - NonItemInItemListSub::Other { - list_start: open_brace_span, - non_item: non_item_span, - list_end: self.prev_token.span, - } - }, - remove_semicolon: is_unnecessary_semicolon.then_some(semicolon_span), - }); - + if is_let { + err.span_suggestion( + non_item_span, + "consider using `const` instead of `let` for associated const", + "const", + Applicability::MachineApplicable, + ); + } else { + err.span_label(open_brace_span, "item list starts here") + .span_label(non_item_span, "non-item starts here") + .span_label(self.prev_token.span, "item list ends here"); + } + if is_unnecessary_semicolon { + err.span_suggestion( + semicolon_span, + "consider removing this semicolon", + "", + Applicability::MaybeIncorrect, + ); + } + err.emit(); break; } Ok(Some(item)) => items.extend(item), From 02141b609837245768841f81711b896dd57eb923 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 28 Dec 2022 23:21:04 +0100 Subject: [PATCH 20/30] Make "use latest edition" subdiagnostic translatable --- .../locales/en-US/hir_typeck.ftl | 4 ++ .../locales/en-US/parse.ftl | 4 ++ compiler/rustc_errors/src/diagnostic.rs | 37 ------------------- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 27 +++++++++++++- compiler/rustc_hir_typeck/src/expr.rs | 4 +- compiler/rustc_parse/src/errors.rs | 26 +++++++++++-- compiler/rustc_parse/src/parser/expr.rs | 20 +++++----- compiler/rustc_parse/src/parser/item.rs | 6 +-- 9 files changed, 73 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl index 0612dbae0b630..2f3eced0db926 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_typeck.ftl @@ -46,3 +46,7 @@ hir_typeck_add_missing_parentheses_in_range = you must surround the range in par hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters + +hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` +hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` +hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index 56b17b35dd4b6..741a99839172f 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -560,3 +560,7 @@ parse_negative_bounds_not_supported = negative bounds are not supported [one] remove the bound *[other] remove the bounds } + +parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` +parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` +parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9fe295f1f0db9..62ca79c3e9b2f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; -use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; @@ -1052,39 +1051,3 @@ impl PartialEq for Diagnostic { self.keys() == other.keys() } } - -pub enum HelpUseLatestEdition { - Cargo, - Standalone, -} - -impl HelpUseLatestEdition { - pub fn new() -> Self { - if std::env::var_os("CARGO").is_some() { Self::Cargo } else { Self::Standalone } - } -} - -impl AddToDiagnostic for HelpUseLatestEdition { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - let msg = f( - diag, - match self { - Self::Cargo => { - format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION) - } - Self::Standalone => { - format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION) - } - } - .into(), - ); - diag.help(msg); - - let msg = - f(diag, "for more on editions, read https://doc.rust-lang.org/edition-guide".into()); - diag.note(msg); - } -} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f9f7ca56b3741..b4d23e96f8f45 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -370,7 +370,7 @@ pub struct GoodPathBug; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, - DiagnosticStyledString, HelpUseLatestEdition, IntoDiagnosticArg, SubDiagnostic, + DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList}; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 507272fdec5d7..345a69678dda1 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -2,7 +2,11 @@ use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; -use rustc_span::{symbol::Ident, Span}; +use rustc_span::{ + edition::{Edition, LATEST_STABLE_EDITION}, + symbol::Ident, + Span, +}; #[derive(Diagnostic)] #[diag(hir_typeck_field_multiply_specified_in_initializer, code = "E0062")] @@ -172,3 +176,24 @@ impl AddToDiagnostic for TypeMismatchFruTypo { ); } } + +#[derive(Subdiagnostic)] +pub enum HelpUseLatestEdition { + #[help(hir_typeck_help_set_edition_cargo)] + #[note(hir_typeck_note_edition_guide)] + Cargo { edition: Edition }, + #[help(hir_typeck_help_set_edition_standalone)] + #[note(hir_typeck_note_edition_guide)] + Standalone { edition: Edition }, +} + +impl HelpUseLatestEdition { + pub fn new() -> Self { + let edition = LATEST_STABLE_EDITION; + if std::env::var_os("CARGO").is_some() { + Self::Cargo { edition } + } else { + Self::Standalone { edition } + } + } +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 42966b7720bcd..0058d8d024c50 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -8,7 +8,7 @@ use crate::coercion::DynamicCoerceMany; use crate::errors::TypeMismatchFruTypo; use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use crate::errors::{ - FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, + FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, YieldExprOutsideOfGenerator, }; use crate::fatally_break_rust; @@ -24,7 +24,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, - DiagnosticId, ErrorGuaranteed, HelpUseLatestEdition, StashKey, + DiagnosticId, ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a2aad02bc0b43..5fd491dcfffef 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,10 +1,9 @@ use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; -use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, EmissionGuarantee, HelpUseLatestEdition, IntoDiagnostic, -}; +use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; +use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; @@ -1841,3 +1840,24 @@ pub(crate) struct NegativeBoundsNotSupportedSugg { pub num_bounds: usize, pub fixed: String, } + +#[derive(Subdiagnostic)] +pub enum HelpUseLatestEdition { + #[help(parse_help_set_edition_cargo)] + #[note(parse_note_edition_guide)] + Cargo { edition: Edition }, + #[help(parse_help_set_edition_standalone)] + #[note(parse_note_edition_guide)] + Standalone { edition: Edition }, +} + +impl HelpUseLatestEdition { + pub fn new() -> Self { + let edition = LATEST_STABLE_EDITION; + if std::env::var_os("CARGO").is_some() { + Self::Cargo { edition } + } else { + Self::Standalone { edition } + } + } +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7cb80a197831c..551fe449529bc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -11,14 +11,14 @@ use crate::errors::{ ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, - FoundExprWouldBeStmt, IfExpressionMissingCondition, IfExpressionMissingThenBlock, - IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, - InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, - InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, - LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, - MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, - MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, - MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator, + FoundExprWouldBeStmt, HelpUseLatestEdition, IfExpressionMissingCondition, + IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, + InvalidComparisonOperator, InvalidComparisonOperatorSub, InvalidInterpolatedExpression, + InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator, InvalidLogicalOperatorSub, + LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, LifetimeInBorrowExpression, + MacroInvocationWithQualifiedPath, MalformedLoopLabel, MatchArmBodyWithoutBraces, + MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, + MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere, StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf, @@ -39,8 +39,8 @@ use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, R use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - HelpUseLatestEdition, IntoDiagnostic, PResult, StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, + PResult, StashKey, }; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3d249aef2f1f7..484e9ecf0594d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3,7 +3,7 @@ use crate::errors::{ BoundsNotAllowedOnTraitAliases, ConstGlobalCannotBeMutable, ConstLetMutuallyExclusive, DefaultNotFollowedByItem, DocCommentDoesNotDocumentAnything, EnumStructMutuallyExclusive, ExpectedTraitInTraitImplFoundType, ExternCrateNameWithDashes, ExternCrateNameWithDashesSugg, - ExternItemCannotBeConst, MissingConstType, MissingForInTraitImpl, + ExternItemCannotBeConst, HelpUseLatestEdition, MissingConstType, MissingForInTraitImpl, MissingKeywordForItemDefinition, MissingTraitInTraitImpl, SelfArgumentPointer, TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, UnexpectedTokenAfterStructName, UseEmptyBlockNotSemi, VisibilityNotFollowedByItem, @@ -26,8 +26,8 @@ use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, Visibility use rustc_ast::{MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; use rustc_errors::{ - struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, HelpUseLatestEdition, - IntoDiagnostic, PResult, StashKey, + struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, + StashKey, }; use rustc_span::edition::Edition; use rustc_span::lev_distance::lev_distance; From c364d329ddda2ae2b7a553bf684a3e247977c003 Mon Sep 17 00:00:00 2001 From: Fabian Hintringer Date: Mon, 9 Jan 2023 13:19:41 +0100 Subject: [PATCH 21/30] Relocate changes --- library/core/src/iter/traits/iterator.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 53d353802b9f4..353cb147f108f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1495,18 +1495,6 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// - /// Flattening works on any `IntoIterator` type, including `Option` and `Result`: - /// - /// ``` - /// let options = vec![Some(123), Some(321), None, Some(231)]; - /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); - /// assert_eq!(flattened_options, vec![123, 321, 231]); - /// - /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; - /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); - /// assert_eq!(flattened_results, vec![123, 321, 231]); - /// ``` - /// /// You can also rewrite this in terms of [`flat_map()`], which is preferable /// in this case since it conveys intent more clearly: /// @@ -1520,6 +1508,18 @@ pub trait Iterator { /// assert_eq!(merged, "alphabetagamma"); /// ``` /// + /// Flattening works on any `IntoIterator` type, including `Option` and `Result`: + /// + /// ``` + /// let options = vec![Some(123), Some(321), None, Some(231)]; + /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); + /// assert_eq!(flattened_options, vec![123, 321, 231]); + /// + /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; + /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); + /// assert_eq!(flattened_results, vec![123, 321, 231]); + /// ``` + /// /// Flattening only removes one level of nesting at a time: /// /// ``` From 31099ee3840f26c59b5f9057001fd656284deb81 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 9 Jan 2023 17:13:14 +0100 Subject: [PATCH 22/30] update test for inductive canonical cycles --- .../inductive-canonical-cycle.rs | 75 ++++++++++++++----- .../inductive-canonical-cycle.stderr | 26 ------- 2 files changed, 58 insertions(+), 43 deletions(-) delete mode 100644 src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs index a3bb76d7e3b73..5449f5f00d52a 100644 --- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs +++ b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.rs @@ -1,28 +1,69 @@ -// known-bug +// check-pass + +// This test checks that we're correctly dealing with inductive cycles +// with canonical inference variables. -// This should compile but fails with the current solver. -// -// This checks that the new solver uses `Ambiguous` when hitting the -// inductive cycle here when proving `exists<^0, ^1> (): Trait<^0, ^1>` -// which requires proving `Trait` but that has the same -// canonical representation. trait Trait {} -impl Trait for () +trait IsNotU32 {} +impl IsNotU32 for i32 {} +impl Trait for () // impl 1 where - (): Trait, - T: OtherTrait, + (): Trait {} -trait OtherTrait {} -impl OtherTrait for u32 {} +impl Trait for () {} // impl 2 + +// If we now check whether `(): Trait` holds this has to +// result in ambiguity as both `for (): Trait` and `(): Trait` +// applies. The remainder of this test asserts that. + +// If we were to error on inductive cycles with canonical inference variables +// this would be wrong: -fn require_trait() +// (): Trait +// - impl 1 +// - ?0: IsNotU32 // ambig +// - (): Trait // canonical cycle -> err +// - ERR +// - impl 2 +// - OK ?0 == u32 +// +// Result: OK ?0 == u32. + +// (): Trait +// - impl 1 +// - i32: IsNotU32 // ok +// - (): Trait +// - impl 1 +// - u32: IsNotU32 // err +// - ERR +// - impl 2 +// - OK +// - OK +// - impl 2 (trivial ERR) +// +// Result OK + +// This would mean that `(): Trait` is not complete, +// which is unsound if we're in coherence. + +fn implements_trait() -> (T, U) where - (): Trait -{} + (): Trait, +{ + todo!() +} + +// A hack to only constrain the infer vars after first checking +// the `(): Trait<_, _>`. +trait Constrain {} +impl Constrain for T {} +fn constrain, U>(_: U) {} fn main() { - require_trait::<_, _>(); - //~^ ERROR overflow evaluating + let (x, y) = implements_trait::<_, _>(); + + constrain::(x); + constrain::(y); } diff --git a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr b/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr deleted file mode 100644 index e4b84e07822d2..0000000000000 --- a/src/test/ui/traits/solver-cycles/inductive-canonical-cycle.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0275]: overflow evaluating the requirement `_: Sized` - --> $DIR/inductive-canonical-cycle.rs:26:5 - | -LL | require_trait::<_, _>(); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_canonical_cycle`) -note: required for `()` to implement `Trait<_, _>` - --> $DIR/inductive-canonical-cycle.rs:11:12 - | -LL | impl Trait for () - | ^^^^^^^^^^^ ^^ - = note: 128 redundant requirements hidden - = note: required for `()` to implement `Trait<_, _>` -note: required by a bound in `require_trait` - --> $DIR/inductive-canonical-cycle.rs:22:9 - | -LL | fn require_trait() - | ------------- required by a bound in this -LL | where -LL | (): Trait - | ^^^^^^^^^^^ required by this bound in `require_trait` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0275`. From 42aa0753109c44bea94f68802d3970d700f4ae13 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Mon, 9 Jan 2023 10:22:08 -0500 Subject: [PATCH 23/30] Accept old spelling of Fuchsia target triples Because the old spelling is widely used, some projects may need time to migrate their uses to the new triple spelling. The old spelling may eventually be removed altogether. --- compiler/rustc_target/src/spec/aarch64_fuchsia.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 6 +++++- compiler/rustc_target/src/spec/x86_64_fuchsia.rs | 1 + src/doc/rustc/src/platform-support.md | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/spec/aarch64_fuchsia.rs create mode 100644 compiler/rustc_target/src/spec/x86_64_fuchsia.rs diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs new file mode 100644 index 0000000000000..ddecbb1a8c4a4 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs @@ -0,0 +1 @@ +pub use crate::spec::aarch64_unknown_fuchsia::target; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index dd56037a272c2..d4543bce3496e 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -981,7 +981,7 @@ impl fmt::Display for StackProtector { } macro_rules! supported_targets { - ( $(($triple:literal, $module:ident ),)+ ) => { + ( $(($triple:literal, $module:ident),)+ ) => { $(mod $module;)+ /// List of supported targets @@ -1109,7 +1109,11 @@ supported_targets! { ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), + // FIXME(fuchsia): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia + ("aarch64-fuchsia", aarch64_fuchsia), ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), + // FIXME(fuchsia): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia + ("x86_64-fuchsia", x86_64_fuchsia), ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs new file mode 100644 index 0000000000000..96fed09756667 --- /dev/null +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -0,0 +1 @@ +pub use crate::spec::x86_64_unknown_fuchsia::target; diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 7ff26e420f1b3..16057048259bf 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -124,6 +124,7 @@ target | std | notes -------|:---:|------- `aarch64-apple-ios` | ✓ | ARM64 iOS [`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64 +`aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia` `aarch64-unknown-fuchsia` | ✓ | ARM64 Fuchsia [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat @@ -177,6 +178,7 @@ target | std | notes `wasm32-wasi` | ✓ | WebAssembly with WASI `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX +`x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` `x86_64-unknown-fuchsia` | ✓ | 64-bit Fuchsia [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos From a51a592866304b9c640411e7dca203586b6d4943 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 8 Jan 2023 23:21:46 +0000 Subject: [PATCH 24/30] Render missing generics suggestion verbosely --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- ...lp-with-err-generic-is-not-function.stderr | 9 ++++--- src/test/ui/issues/issue-58712.stderr | 9 ++++--- src/test/ui/issues/issue-77919.stderr | 9 ++++--- src/test/ui/issues/issue-86756.stderr | 7 +++-- .../ui/parser/dyn-trait-compatibility.stderr | 27 ++++++++++++------- .../type-not-found-in-adt-field.stderr | 7 +++-- src/test/ui/traits/issue-50480.stderr | 27 ++++++++++++------- src/test/ui/traits/issue-75627.stderr | 9 ++++--- src/test/ui/traits/issue-78372.stderr | 9 ++++--- .../unknown_dst.stderr | 8 +++--- .../unknown_src.stderr | 8 +++--- .../autoderef-with-param-env-error.stderr | 8 +++--- src/test/ui/typeck/issue-104513-ice.stderr | 7 +++-- 14 files changed, 97 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 37771693417b3..b4eee5488c160 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -164,7 +164,7 @@ impl<'a> Resolver<'a> { ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { - err.span_suggestion(span, msg, sugg, appl); + err.span_suggestion_verbose(span, msg, sugg, appl); err.emit(); } else if let [segment] = path.as_slice() && is_call { err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod); diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr index 26bdf460f5e4d..9d4ea01152cc9 100644 --- a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr +++ b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13 | LL | impl Struct - | - ^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl Struct + | +++ error[E0412]: cannot find type `T` in this scope --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5 diff --git a/src/test/ui/issues/issue-58712.stderr b/src/test/ui/issues/issue-58712.stderr index 87c16aa993b67..f4bd4d1e826a0 100644 --- a/src/test/ui/issues/issue-58712.stderr +++ b/src/test/ui/issues/issue-58712.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `DeviceId` in this scope --> $DIR/issue-58712.rs:6:20 | LL | impl AddrVec { - | - ^^^^^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, DeviceId` + | ^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl AddrVec { + | ++++++++++ error[E0412]: cannot find type `DeviceId` in this scope --> $DIR/issue-58712.rs:8:29 diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index ca256847b1f3b..d154bfe0cb553 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -13,9 +13,12 @@ error[E0412]: cannot find type `VAL` in this scope --> $DIR/issue-77919.rs:11:63 | LL | impl TypeVal for Multiply where N: TypeVal {} - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, VAL` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl TypeVal for Multiply where N: TypeVal {} + | +++++ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/issue-77919.rs:11:1 diff --git a/src/test/ui/issues/issue-86756.stderr b/src/test/ui/issues/issue-86756.stderr index 6c5917bdf6ece..e0f37129fd2ed 100644 --- a/src/test/ui/issues/issue-86756.stderr +++ b/src/test/ui/issues/issue-86756.stderr @@ -9,10 +9,13 @@ LL | trait Foo {} error[E0412]: cannot find type `dyn` in this scope --> $DIR/issue-86756.rs:5:10 | -LL | fn eq() { - | - help: you might be missing a type parameter: `, dyn` LL | eq:: | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn eq() { + | +++++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-86756.rs:5:15 diff --git a/src/test/ui/parser/dyn-trait-compatibility.stderr b/src/test/ui/parser/dyn-trait-compatibility.stderr index 9218ae9d5daa3..6a946ea2ae098 100644 --- a/src/test/ui/parser/dyn-trait-compatibility.stderr +++ b/src/test/ui/parser/dyn-trait-compatibility.stderr @@ -26,17 +26,23 @@ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:5:15 | LL | type A2 = dyn; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | type A2 = dyn; + | +++++ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:5:20 | LL | type A2 = dyn; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | type A2 = dyn; + | +++++ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:11 @@ -48,9 +54,12 @@ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:16 | LL | type A3 = dyn<::dyn>; - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | type A3 = dyn<::dyn>; + | +++++ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.stderr b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr index e990fb5ba1210..934ba87bbaa88 100644 --- a/src/test/ui/suggestions/type-not-found-in-adt-field.stderr +++ b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr @@ -7,10 +7,13 @@ LL | m: Vec>, error[E0412]: cannot find type `K` in this scope --> $DIR/type-not-found-in-adt-field.rs:6:8 | -LL | struct OtherStruct { - | - help: you might be missing a type parameter: `` LL | m: K, | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct OtherStruct { + | +++ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/issue-50480.stderr b/src/test/ui/traits/issue-50480.stderr index 0bb1f9ae03500..aa8384e980539 100644 --- a/src/test/ui/traits/issue-50480.stderr +++ b/src/test/ui/traits/issue-50480.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | -^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo(N, NotDefined, ::Item, Vec, String); + | +++ error[E0412]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 @@ -16,17 +19,23 @@ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:3:12 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | -^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo(N, NotDefined, ::Item, Vec, String); + | +++ error[E0412]: cannot find type `NotDefined` in this scope --> $DIR/issue-50480.rs:3:15 | LL | struct Foo(N, NotDefined, ::Item, Vec, String); - | - ^^^^^^^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct Foo(N, NotDefined, ::Item, Vec, String); + | ++++++++++++ error[E0412]: cannot find type `N` in this scope --> $DIR/issue-50480.rs:12:18 diff --git a/src/test/ui/traits/issue-75627.stderr b/src/test/ui/traits/issue-75627.stderr index 432ddf2dcdbdc..1675edc9ff0b9 100644 --- a/src/test/ui/traits/issue-75627.stderr +++ b/src/test/ui/traits/issue-75627.stderr @@ -2,9 +2,12 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/issue-75627.rs:3:26 | LL | unsafe impl Send for Foo {} - | - ^ not found in this scope - | | - | help: you might be missing a type parameter: `` + | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | unsafe impl Send for Foo {} + | +++ error: aborting due to previous error diff --git a/src/test/ui/traits/issue-78372.stderr b/src/test/ui/traits/issue-78372.stderr index 7e781016e1f0f..8e7fd5f255710 100644 --- a/src/test/ui/traits/issue-78372.stderr +++ b/src/test/ui/traits/issue-78372.stderr @@ -30,9 +30,12 @@ error[E0412]: cannot find type `MISC` in this scope --> $DIR/issue-78372.rs:3:34 | LL | impl DispatchFromDyn> for T {} - | - ^^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, MISC` + | ^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl DispatchFromDyn> for T {} + | ++++++ error[E0658]: use of unstable library feature 'dispatch_from_dyn' --> $DIR/issue-78372.rs:1:5 diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr index 85087282d3a6e..b4591778f8e7b 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `Dst` in this scope --> $DIR/unknown_dst.rs:20:36 | -LL | fn should_gracefully_handle_unknown_dst() { - | - help: you might be missing a type parameter: `` -... LL | assert::is_transmutable::(); | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn should_gracefully_handle_unknown_dst() { + | +++++ error: aborting due to previous error diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr index 9bedbe87c3f7f..a55d71d806824 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `Src` in this scope --> $DIR/unknown_src.rs:20:31 | -LL | fn should_gracefully_handle_unknown_src() { - | - help: you might be missing a type parameter: `` -... LL | assert::is_transmutable::(); | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn should_gracefully_handle_unknown_src() { + | +++++ error: aborting due to previous error diff --git a/src/test/ui/typeck/autoderef-with-param-env-error.stderr b/src/test/ui/typeck/autoderef-with-param-env-error.stderr index cde800336dd3d..182612d5ee70e 100644 --- a/src/test/ui/typeck/autoderef-with-param-env-error.stderr +++ b/src/test/ui/typeck/autoderef-with-param-env-error.stderr @@ -1,11 +1,13 @@ error[E0412]: cannot find type `T` in this scope --> $DIR/autoderef-with-param-env-error.rs:3:5 | -LL | fn foo() - | - help: you might be missing a type parameter: `` -LL | where LL | T: Send, | ^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn foo() + | +++ error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-104513-ice.stderr b/src/test/ui/typeck/issue-104513-ice.stderr index 2b3b1b9efdfae..5561673f3c672 100644 --- a/src/test/ui/typeck/issue-104513-ice.stderr +++ b/src/test/ui/typeck/issue-104513-ice.stderr @@ -1,10 +1,13 @@ error[E0405]: cannot find trait `Oops` in this scope --> $DIR/issue-104513-ice.rs:3:19 | -LL | fn f() { - | - help: you might be missing a type parameter: `` LL | let _: S = S; | ^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | fn f() { + | ++++++ error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-104513-ice.rs:3:14 From 5132e13f137ee343a7a64649fa3795560f69216b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 Dec 2022 21:30:15 +0000 Subject: [PATCH 25/30] No need to take opaques in check_type_bounds --- .../src/check/compare_impl_item.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 0d3391bbc1efb..17f9106e7e0b8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -424,7 +424,7 @@ fn compare_asyncness<'tcx>( ty::Alias(ty::Opaque, ..) => { // allow both `async fn foo()` and `fn foo() -> impl Future` } - ty::Error(rustc_errors::ErrorGuaranteed { .. }) => { + ty::Error(_) => { // We don't know if it's ok, but at least it's already an error. } _ => { @@ -1971,22 +1971,6 @@ pub(super) fn check_type_bounds<'tcx>( &outlives_environment, )?; - let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - for (key, value) in constraints { - infcx - .err_ctxt() - .report_mismatched_types( - &ObligationCause::misc( - value.hidden_type.span, - tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()), - ), - tcx.mk_opaque(key.def_id.to_def_id(), key.substs), - value.hidden_type.ty, - TypeError::Mismatch, - ) - .emit(); - } - Ok(()) } From 7c2dff0be4e08917bc0818607fb498e022ffa230 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 8 Jan 2023 23:27:22 +0000 Subject: [PATCH 26/30] Don't suggest dyn as parameter to add --- compiler/rustc_resolve/src/late/diagnostics.rs | 6 +++++- src/test/ui/issues/issue-86756.stderr | 5 ----- src/test/ui/parser/dyn-trait-compatibility.stderr | 15 --------------- src/tools/clippy/tests/ui/crashes/ice-6252.stderr | 9 ++++++--- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 74522f185422d..8303efae2ec28 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2054,7 +2054,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { path: &[Segment], ) -> Option<(Span, &'static str, String, Applicability)> { let (ident, span) = match path { - [segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => { + [segment] + if !segment.has_generic_args + && segment.ident.name != kw::SelfUpper + && segment.ident.name != kw::Dyn => + { (segment.ident.to_string(), segment.ident.span) } _ => return None, diff --git a/src/test/ui/issues/issue-86756.stderr b/src/test/ui/issues/issue-86756.stderr index e0f37129fd2ed..bfa7459ab4a39 100644 --- a/src/test/ui/issues/issue-86756.stderr +++ b/src/test/ui/issues/issue-86756.stderr @@ -11,11 +11,6 @@ error[E0412]: cannot find type `dyn` in this scope | LL | eq:: | ^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | fn eq() { - | +++++ warning: trait objects without an explicit `dyn` are deprecated --> $DIR/issue-86756.rs:5:15 diff --git a/src/test/ui/parser/dyn-trait-compatibility.stderr b/src/test/ui/parser/dyn-trait-compatibility.stderr index 6a946ea2ae098..0cae01bd1e329 100644 --- a/src/test/ui/parser/dyn-trait-compatibility.stderr +++ b/src/test/ui/parser/dyn-trait-compatibility.stderr @@ -27,22 +27,12 @@ error[E0412]: cannot find type `dyn` in this scope | LL | type A2 = dyn; | ^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | type A2 = dyn; - | +++++ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:5:20 | LL | type A2 = dyn; | ^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | type A2 = dyn; - | +++++ error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:11 @@ -55,11 +45,6 @@ error[E0412]: cannot find type `dyn` in this scope | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope - | -help: you might be missing a type parameter - | -LL | type A3 = dyn<::dyn>; - | +++++ error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index 638e4a5484932..efdd56dd47d39 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -17,9 +17,12 @@ error[E0412]: cannot find type `VAL` in this scope --> $DIR/ice-6252.rs:10:63 | LL | impl TypeVal for Multiply where N: TypeVal {} - | - ^^^ not found in this scope - | | - | help: you might be missing a type parameter: `, VAL` + | ^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl TypeVal for Multiply where N: TypeVal {} + | +++++ error[E0046]: not all trait items implemented, missing: `VAL` --> $DIR/ice-6252.rs:10:1 From 1d66a675bb61c21555dcb848ed7378b6f2848de7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 9 Jan 2023 18:07:34 +0000 Subject: [PATCH 27/30] review comment --- compiler/rustc_resolve/src/diagnostics.rs | 11 +++++------ compiler/rustc_resolve/src/imports.rs | 10 ++++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c8b96aae7a699..7d62d67d64f07 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -161,7 +161,7 @@ impl<'a> Resolver<'a> { found_use, DiagnosticMode::Normal, path, - None, + "", ); err.emit(); } else if let Some((span, msg, sugg, appl)) = suggestion { @@ -691,7 +691,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Pattern, vec![], - None, + "", ); } err @@ -1346,7 +1346,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Normal, vec![], - None, + "", ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -2328,7 +2328,7 @@ pub(crate) fn import_candidates( use_placement_span: Option, candidates: &[ImportSuggestion], mode: DiagnosticMode, - append: Option<&str>, + append: &str, ) { show_candidates( session, @@ -2358,12 +2358,11 @@ fn show_candidates( found_use: FoundUse, mode: DiagnosticMode, path: Vec, - append: Option<&str>, + append: &str, ) { if candidates.is_empty() { return; } - let append = append.unwrap_or(""); let mut accessible_path_strings: Vec<(String, &str, Option, &Option)> = Vec::new(); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0a2a737e1a453..00f65ac37b6a8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -554,7 +554,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Some(err.span), &candidates, DiagnosticMode::Import, - (source != target).then(|| format!(" as {target}")).as_deref(), + (source != target) + .then(|| format!(" as {target}")) + .as_deref() + .unwrap_or(""), ), ImportKind::Single { nested: true, source, target, .. } => { import_candidates( @@ -564,7 +567,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { None, &candidates, DiagnosticMode::Normal, - (source != target).then(|| format!(" as {target}")).as_deref(), + (source != target) + .then(|| format!(" as {target}")) + .as_deref() + .unwrap_or(""), ); } _ => {} From 1c766d03a7ad534bfba62b61c65c2c1216a64264 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 9 Jan 2023 11:09:19 -0700 Subject: [PATCH 28/30] rustdoc: merge common CSS for `a` --- src/librustdoc/html/static/css/rustdoc.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 77401e8b76e80..8ec4631f7d087 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -253,6 +253,7 @@ h1 a, a { color: var(--link-color); + text-decoration: none; } ol, ul { @@ -662,10 +663,6 @@ nav.sub { margin: 0 0 15px 0; } -a { - text-decoration: none; -} - .small-section-header { /* fields use tags, but should get their own lines */ display: block; From f769d34291e489db19d3c972348ddb24b6b32481 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 9 Jan 2023 18:14:28 +0000 Subject: [PATCH 29/30] Assert defining anchor is set in take_opaque_types --- compiler/rustc_borrowck/src/region_infer/opaque_types.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_const_eval/src/util/compare_types.rs | 2 +- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 3 +-- compiler/rustc_infer/src/infer/canonical/query_response.rs | 5 +---- compiler/rustc_infer/src/infer/mod.rs | 6 ++++++ compiler/rustc_infer/src/infer/opaque_types/table.rs | 5 ----- compiler/rustc_trait_selection/src/traits/mod.rs | 3 --- compiler/rustc_traits/src/codegen.rs | 2 +- 10 files changed, 13 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d82d4cc39fb1c..4fe14c7af2faa 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -318,7 +318,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // This is still required for many(half of the tests in ui/type-alias-impl-trait) // tests to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); if errors.is_empty() { definition_ty diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 247607ff29e20..d9c1986456e89 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -208,7 +208,7 @@ pub(crate) fn type_check<'mir, 'tcx>( ); translate_outlives_facts(&mut checker); - let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let opaque_type_values = infcx.take_opaque_types(); let opaque_type_values = opaque_type_values .into_iter() diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index be786569cde3f..f5f3d5de6b5a2 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -58,6 +58,6 @@ pub fn is_subtype<'tcx>( // even if they're constrained in our current function. // // It seems very unlikely that this hides any bugs. - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); errors.is_empty() } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 28cd18bbb8e85..13b3d53ca368e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -475,7 +475,7 @@ fn check_opaque_meets_bounds<'tcx>( } } // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); } fn is_enum_of_nonnullable_ptr<'tcx>( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index bb956ddc78042..8c24b6006444a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -534,8 +534,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_opaque_types(&mut self) { - let opaque_types = - self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let opaque_types = self.fcx.infcx.take_opaque_types(); for (opaque_type_key, decl) in opaque_types { let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span); let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index a722613e3310e..d85af830de86e 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -156,10 +156,7 @@ impl<'tcx> InferCtxt<'tcx> { /// As the new solver does canonicalization slightly differently, this is also used there /// for now. This should hopefully change fairly soon. pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { - self.inner - .borrow_mut() - .opaque_type_storage - .take_opaque_types() + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a9de74d78cb61..192addb59d924 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1338,6 +1338,12 @@ impl<'tcx> InferCtxt<'tcx> { var_infos } + #[instrument(level = "debug", skip(self), ret)] + pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { + debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error); + std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index c146902d594af..ae4b85c8799ef 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } - #[instrument(level = "debug", ret)] - pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { - std::mem::take(&mut self.opaque_types) - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c30531fa90664..58d83d57d4304 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -450,9 +450,6 @@ pub fn impossible_predicates<'tcx>( } let errors = ocx.select_all_or_error(); - // Clean up after ourselves - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - let result = !errors.is_empty(); debug!("impossible_predicates = {:?}", result); result diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index f8f74b732efd3..f127ef8343f91 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -82,7 +82,7 @@ pub fn codegen_select_candidate<'tcx>( // Opaque types may have gotten their hidden types constrained, but we can ignore them safely // as they will get constrained elsewhere, too. // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + let _ = infcx.take_opaque_types(); Ok(&*tcx.arena.alloc(impl_source)) } From 9c23629158d863068f51a7f316dbe15a76d7e602 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 9 Jan 2023 13:23:50 -0500 Subject: [PATCH 30/30] Add issue number to FIXMEs --- compiler/rustc_target/src/spec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d4543bce3496e..2c3aa67201138 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1109,10 +1109,10 @@ supported_targets! { ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), - // FIXME(fuchsia): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia + // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia ("aarch64-fuchsia", aarch64_fuchsia), ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), - // FIXME(fuchsia): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia + // FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia ("x86_64-fuchsia", x86_64_fuchsia), ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),