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 8778a19eeda1b..7a3db191f0c66 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -209,7 +209,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_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 3401978caf5f0..741a99839172f 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -368,3 +368,199 @@ 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 `,` + +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 + } + +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 e19a6fe0ee9bf..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; @@ -555,18 +554,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. 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/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 { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ef563360c4ceb..43795cfba3fd8 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_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index b260b929bebdb..7af89934d1420 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. } _ => { @@ -1972,22 +1972,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(()) } 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 b08b22108c8ce..e379ceed3af2c 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; @@ -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, 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_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 108011013f58b..3d49182f0b817 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 31b546581e424..6bef3f000a5ac 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_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/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, _) diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 574591529f331..5fd491dcfffef 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,8 +1,9 @@ use rustc_ast::token::Token; -use rustc_ast::Path; +use rustc_ast::{Path, Visibility}; 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}; @@ -1237,3 +1238,626 @@ 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_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, +} + +#[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, +} + +#[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/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index d9fa3e31db972..57ca16eaf7747 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2015,7 +2015,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()?; @@ -2360,7 +2360,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 9f436783ceda6..551fe449529bc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,25 +1,25 @@ 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, 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, 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, UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses, @@ -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, IntoDiagnostic, + PResult, StashKey, }; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; @@ -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 { @@ -2873,8 +2873,8 @@ 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(); + AsyncBlockIn2015 { span }.add_to_diagnostic(e); + HelpUseLatestEdition::new().add_to_diagnostic(e); }; while self.token != token::CloseDelim(close_delim) { 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 a958c294930ef..484e9ecf0594d 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, HelpUseLatestEdition, MissingConstType, MissingForInTraitImpl, + MissingKeywordForItemDefinition, MissingTraitInTraitImpl, SelfArgumentPointer, + TraitAliasCannotBeAuto, TraitAliasCannotBeUnsafe, UnexpectedTokenAfterStructName, + UseEmptyBlockNotSemi, VisibilityNotFollowedByItem, +}; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; @@ -16,12 +25,16 @@ 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, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, + StashKey, +}; use rustc_span::edition::Edition; 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; @@ -163,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. @@ -384,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) - } else if self.check(&token::Colon) { - let kw = "struct"; - (kw, kw, 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 { 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) + if is_method { + MissingKeywordForItemDefinition::Method { span: sp, ident } + } else { + MissingKeywordForItemDefinition::Function { span: sp, ident } + } + } else if self.check(&token::Semi) { + 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) + }, + } }; - 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) + Some(err) + } else if found_generics { + Some(MissingKeywordForItemDefinition::Ambiguous { span: sp, subdiag: None }) + } else { + None + }; + + if let Some(err) = err { + Err(err.into_diagnostic(&self.sess.span_diagnostic)) } else { Ok(()) } @@ -512,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"); @@ -588,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, @@ -634,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(); @@ -649,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) } }; @@ -783,6 +745,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, @@ -849,7 +812,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)?; @@ -858,12 +821,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); @@ -909,8 +870,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"), @@ -1084,41 +1044,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 { - fixed_name.push_str(&format!("_{}", part.name)); - } - 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. @@ -1166,7 +1122,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"), @@ -1178,6 +1137,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}")) @@ -1186,18 +1146,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]) @@ -1225,25 +1173,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) }); } } @@ -1328,13 +1261,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, @@ -1346,18 +1274,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)); } } @@ -1485,13 +1407,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))) @@ -2321,7 +2238,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) { @@ -2431,17 +2350,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(); - 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(); - } - } - /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, @@ -2584,9 +2492,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)) }; @@ -2667,14 +2573,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..f91081c450e33 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,15 +17,33 @@ 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}; -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"; @@ -54,13 +80,19 @@ 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. /// /// 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) } @@ -74,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, @@ -86,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, @@ -165,9 +197,9 @@ impl<'a> Parser<'a> { /// otherwise). pub(super) fn parse_pat_before_ty( &mut self, - expected: Expected, + expected: Option, 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 +213,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 +264,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( + Some(Expected::ParameterName), + RecoverComma::No, + PatternLocation::FunctionParameter, + ) } /// Eat the or-pattern `|` separator. @@ -236,7 +282,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 +316,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,46 +330,12 @@ 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( &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); @@ -413,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, @@ -454,15 +472,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 +497,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 +506,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 +537,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> { + fn parse_pat_deref(&mut self, expected: Option) -> 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 +581,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(); @@ -600,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 @@ -617,22 +612,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 +636,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 +653,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 @@ -699,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); @@ -768,26 +736,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 +750,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)) } @@ -868,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 }; @@ -879,8 +826,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)) @@ -962,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 }; @@ -997,7 +944,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 +1058,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/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: diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 37771693417b3..3897816d64b3e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -161,10 +161,11 @@ impl<'a> Resolver<'a> { found_use, DiagnosticMode::Normal, path, + "", ); 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); @@ -690,6 +691,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Pattern, vec![], + "", ); } err @@ -1344,6 +1346,7 @@ impl<'a> Resolver<'a> { FoundUse::Yes, DiagnosticMode::Normal, vec![], + "", ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { @@ -2309,7 +2312,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 +2327,8 @@ pub(crate) fn import_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], + mode: DiagnosticMode, + append: &str, ) { show_candidates( session, @@ -2333,8 +2338,9 @@ pub(crate) fn import_candidates( candidates, Instead::Yes, FoundUse::Yes, - DiagnosticMode::Import, + mode, vec![], + append, ); } @@ -2352,6 +2358,7 @@ fn show_candidates( found_use: FoundUse, mode: DiagnosticMode, path: Vec, + append: &str, ) { if candidates.is_empty() { return; @@ -2416,7 +2423,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 4d896b055268e..00f65ac37b6a8 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> { @@ -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 { @@ -494,10 +489,12 @@ 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 `::` 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); } @@ -538,14 +545,36 @@ impl<'a, 'b> ImportResolver<'a, 'b> { diag.multipart_suggestion(&msg, suggestions, applicability); } - if let Some(candidate) = &err.candidate { - import_candidates( - self.r.session, - &self.r.untracked.source_span, - &mut diag, - Some(err.span), - &candidate, - ) + if let Some(candidates) = &err.candidates { + match &import.kind { + 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() + .unwrap_or(""), + ), + ImportKind::Single { nested: true, source, target, .. } => { + import_candidates( + self.r.session, + &self.r.untracked.source_span, + &mut diag, + None, + &candidates, + DiagnosticMode::Normal, + (source != target) + .then(|| format!(" as {target}")) + .as_deref() + .unwrap_or(""), + ); + } + _ => {} + } } } @@ -707,14 +736,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); @@ -761,7 +790,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { )), note: None, suggestion: None, - candidate: None, + candidates: None, }); } } @@ -873,7 +902,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() { @@ -943,7 +972,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/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/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/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() } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0fafa52a45b66..1e80b8b759db4 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(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia + ("aarch64-fuchsia", aarch64_fuchsia), ("aarch64-unknown-fuchsia", aarch64_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), ("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/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2bab380dba011..37b40a2f75adc 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_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 3f14491f8032f..2615e2622821d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2377,6 +2377,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/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)) } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index fc4d4bff24f33..99aaf798e411f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1514,6 +1514,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: /// /// ``` 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 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; 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`. 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/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/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/imports/bad-import-in-nested.rs b/src/test/ui/imports/bad-import-in-nested.rs new file mode 100644 index 0000000000000..2e95480ad412e --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.rs @@ -0,0 +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 { + pub mod D {} +} + +mod B { + use crate::C::{self, 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 new file mode 100644 index 0000000000000..855b1e637e97f --- /dev/null +++ b/src/test/ui/imports/bad-import-in-nested.stderr @@ -0,0 +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: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 3 previous errors + +For more information about this error, try `rustc --explain E0432`. 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/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..bfa7459ab4a39 100644 --- a/src/test/ui/issues/issue-86756.stderr +++ b/src/test/ui/issues/issue-86756.stderr @@ -9,8 +9,6 @@ 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 diff --git a/src/test/ui/parser/dyn-trait-compatibility.stderr b/src/test/ui/parser/dyn-trait-compatibility.stderr index 9218ae9d5daa3..0cae01bd1e329 100644 --- a/src/test/ui/parser/dyn-trait-compatibility.stderr +++ b/src/test/ui/parser/dyn-trait-compatibility.stderr @@ -26,17 +26,13 @@ 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 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 error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:9:11 @@ -48,9 +44,7 @@ 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 error: aborting due to 8 previous errors diff --git a/src/test/ui/pub/pub-ident-fn-3.rs b/src/test/ui/pub/pub-ident-fn-3.rs deleted file mode 100644 index fdbea7cf487eb..0000000000000 --- a/src/test/ui/pub/pub-ident-fn-3.rs +++ /dev/null @@ -1,8 +0,0 @@ -// #60115 - -mod foo { - pub bar(); - //~^ ERROR missing `fn` or `struct` for function or 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 deleted file mode 100644 index 6d3d4e592c8ed..0000000000000 --- a/src/test/ui/pub/pub-ident-fn-3.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/pub-ident-fn-3.rs:4:8 - | -LL | pub bar(); - | ---^--- help: if you meant to call a macro, try: `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 deleted file mode 100644 index 8f67cdd293342..0000000000000 --- a/src/test/ui/pub/pub-ident-fn-or-struct-2.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub S(); -//~^ ERROR missing `fn` or `struct` for function or 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 deleted file mode 100644 index 047e66b18d8cd..0000000000000 --- a/src/test/ui/pub/pub-ident-fn-or-struct-2.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/pub-ident-fn-or-struct-2.rs:1:4 - | -LL | pub S(); - | ---^- help: if you meant to call a macro, try: `S!` - -error: aborting due to previous error - diff --git a/src/test/ui/pub/pub-ident-struct-2.rs b/src/test/ui/pub/pub-ident-struct-2.rs new file mode 100644 index 0000000000000..50db4039d4fc1 --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-2.rs @@ -0,0 +1,8 @@ +// #60115 + +mod foo { + pub bar(); + //~^ ERROR missing `struct` for struct definition +} + +fn main() {} diff --git a/src/test/ui/pub/pub-ident-struct-2.stderr b/src/test/ui/pub/pub-ident-struct-2.stderr new file mode 100644 index 0000000000000..6969a376a5e76 --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-2.stderr @@ -0,0 +1,13 @@ +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct-2.rs:4:8 + | +LL | pub 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-struct-3.rs b/src/test/ui/pub/pub-ident-struct-3.rs new file mode 100644 index 0000000000000..dfa6cf2ee1e87 --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-3.rs @@ -0,0 +1,4 @@ +pub S(); +//~^ ERROR missing `struct` for struct definition + +fn main() {} diff --git a/src/test/ui/pub/pub-ident-struct-3.stderr b/src/test/ui/pub/pub-ident-struct-3.stderr new file mode 100644 index 0000000000000..d94198a6b6deb --- /dev/null +++ b/src/test/ui/pub/pub-ident-struct-3.stderr @@ -0,0 +1,13 @@ +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct-3.rs:1:4 + | +LL | pub 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 + 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/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr index 0c16ecd4c862e..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,14 +10,10 @@ 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; - | ~~~~~~~~~~~ +LL | use test::test as y; + | ~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors 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 | 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/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/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`. 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 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`. 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