diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index fa3c4cb05f96..9942cddcb3cd 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -330,6 +330,31 @@ hir_analysis_manual_implementation = hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous .note = this method is `async` so it expects a future to be returned +hir_analysis_missing_generic_params = + the {$descr} {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be explicitly specified + .label = {$descr} {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be specified for this + .suggestion = explicitly specify the {$descr} {$parameterCount -> + [one] parameter + *[other] parameters + } + .no_suggestion_label = missing {$parameterCount -> + [one] reference + *[other] references + } to {$parameters} + .note = because the parameter {$parameterCount -> + [one] default references + *[other] defaults reference + } `Self`, the {$parameterCount -> + [one] parameter + *[other] parameters + } must be specified on the trait object type + hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}` .label = missing one of `{$missing_items_msg}` in implementation .note = required because of this annotation @@ -346,34 +371,6 @@ hir_analysis_missing_trait_item_unstable = not all trait items implemented, miss .some_note = use of unstable library feature `{$feature}`: {$reason} .none_note = use of unstable library feature `{$feature}` -hir_analysis_missing_type_params = - the type {$parameterCount -> - [one] parameter - *[other] parameters - } {$parameters} must be explicitly specified - .label = type {$parameterCount -> - [one] parameter - *[other] parameters - } {$parameters} must be specified for this - .suggestion = set the type {$parameterCount -> - [one] parameter - *[other] parameters - } to the desired {$parameterCount -> - [one] type - *[other] types - } - .no_suggestion_label = missing {$parameterCount -> - [one] reference - *[other] references - } to {$parameters} - .note = because the parameter {$parameterCount -> - [one] default references - *[other] defaults reference - } `Self`, the {$parameterCount -> - [one] parameter - *[other] parameters - } must be specified on the object type - hir_analysis_no_variant_named = no variant named `{$ident}` found for enum `{$ty}` hir_analysis_not_supported_delegation = {$descr} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 185a822bdfa6..e513f053d336 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -4,11 +4,11 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, + MultiSpan, listify, }; use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; @@ -400,35 +400,58 @@ pub(crate) struct UnconstrainedOpaqueType { pub what: &'static str, } -pub(crate) struct MissingTypeParams { +pub(crate) struct MissingGenericParams { pub span: Span, pub def_span: Span, pub span_snippet: Option, - pub missing_type_params: Vec, + pub missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>, pub empty_generic_args: bool, } -// Manual implementation of `Diagnostic` to be able to call `span_to_snippet`. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { +// FIXME: This doesn't need to be a manual impl! +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params); + let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_generic_params); err.span(self.span); err.code(E0393); - err.arg("parameterCount", self.missing_type_params.len()); - err.arg( - "parameters", - self.missing_type_params - .iter() - .map(|n| format!("`{n}`")) - .collect::>() - .join(", "), - ); - err.span_label(self.def_span, fluent::hir_analysis_label); + enum Descr { + Generic, + Type, + Const, + } + + let mut descr = None; + for (_, kind) in &self.missing_generic_params { + descr = match (&descr, kind) { + (None, ty::GenericParamDefKind::Type { .. }) => Some(Descr::Type), + (None, ty::GenericParamDefKind::Const { .. }) => Some(Descr::Const), + (Some(Descr::Type), ty::GenericParamDefKind::Const { .. }) + | (Some(Descr::Const), ty::GenericParamDefKind::Type { .. }) => { + Some(Descr::Generic) + } + _ => continue, + } + } + + err.arg( + "descr", + match descr.unwrap() { + Descr::Generic => "generic", + Descr::Type => "type", + Descr::Const => "const", + }, + ); + err.arg("parameterCount", self.missing_generic_params.len()); + err.arg( + "parameters", + listify(&self.missing_generic_params, |(n, _)| format!("`{n}`")).unwrap(), + ); + let mut suggested = false; - // Don't suggest setting the type params if there are some already: the order is + // Don't suggest setting the generic params if there are some already: The order is // tricky to get right and the user will already know what the syntax is. if let Some(snippet) = self.span_snippet && self.empty_generic_args @@ -438,16 +461,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { // we would have to preserve the right order. For now, as clearly the user is // aware of the syntax, we do nothing. } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. + // The user wrote `Trait`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Trait`. err.span_suggestion_verbose( self.span.shrink_to_hi(), fluent::hir_analysis_suggestion, format!( "<{}>", - self.missing_type_params + self.missing_generic_params .iter() - .map(|n| n.to_string()) + .map(|(n, _)| format!("/* {n} */")) .collect::>() .join(", ") ), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index f4002396b9d8..3b4812bc9469 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -352,9 +352,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let span = *spans.first().unwrap(); - // Verify that `dummy_self` did not leak inside default type parameters. This + // Verify that `dummy_self` did not leak inside generic parameter defaults. This // could not be done at path creation, since we need to see through trait aliases. - let mut missing_type_params = vec![]; + let mut missing_generic_params = Vec::new(); let generics = tcx.generics_of(trait_ref.def_id); let args: Vec<_> = trait_ref .args @@ -365,8 +365,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|(index, arg)| { if arg.walk().any(|arg| arg == dummy_self.into()) { let param = &generics.own_params[index]; - missing_type_params.push(param.name); - Ty::new_misc_error(tcx).into() + missing_generic_params.push((param.name, param.kind.clone())); + param.to_error(tcx) } else { arg } @@ -377,8 +377,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); - self.report_missing_type_params( - missing_type_params, + self.report_missing_generic_params( + missing_generic_params, trait_ref.def_id, span, empty_generic_args, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 3a77bad3ff52..d114691b25e8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -28,31 +28,29 @@ use tracing::debug; use super::InherentAssocCandidate; use crate::errors::{ - self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, - ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits, + self, AssocItemConstraintsNotAllowedHere, ManualImplementation, ParenthesizedFnTraitExpansion, + TraitObjectDeclaredWithNoTraits, }; use crate::fluent_generated as fluent; use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer}; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// On missing type parameters, emit an E0393 error and provide a structured suggestion using - /// the type parameter's name as a placeholder. - pub(crate) fn report_missing_type_params( + pub(crate) fn report_missing_generic_params( &self, - missing_type_params: Vec, + missing_generic_params: Vec<(Symbol, ty::GenericParamDefKind)>, def_id: DefId, span: Span, empty_generic_args: bool, ) { - if missing_type_params.is_empty() { + if missing_generic_params.is_empty() { return; } - self.dcx().emit_err(MissingTypeParams { + self.dcx().emit_err(errors::MissingGenericParams { span, def_span: self.tcx().def_span(def_id), span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(), - missing_type_params, + missing_generic_params, empty_generic_args, }); } diff --git a/tests/crashes/136063.rs b/tests/crashes/136063.rs deleted file mode 100644 index 078cc59dfa28..000000000000 --- a/tests/crashes/136063.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #136063 -#![feature(generic_const_exprs)] -trait A {} -impl A<1> for bool {} -fn bar(arg : &dyn A) { bar(true) } -pub fn main() {} diff --git a/tests/crashes/137260.rs b/tests/crashes/137260.rs deleted file mode 100644 index f1fa8a660dcd..000000000000 --- a/tests/crashes/137260.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #137260 -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -trait Iter {} - -fn needs_iter>() {} - -fn test() { - needs_iter::<1, dyn Iter<()>>(); -} diff --git a/tests/crashes/137514.rs b/tests/crashes/137514.rs deleted file mode 100644 index 7ae5f29e36e6..000000000000 --- a/tests/crashes/137514.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #137514 -//@ needs-rustc-debug-assertions -#![feature(generic_const_exprs)] - -trait Bar {} - -trait BB = Bar<{ 1i32 + 1 }>; - -fn foo(x: &dyn BB) {} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.rs b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.rs new file mode 100644 index 000000000000..30e7a78c2a85 --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.rs @@ -0,0 +1,21 @@ +// Test that we force users to explicitly specify const arguments for const parameters that +// have defaults if the default mentions the `Self` type parameter. + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait X::N }> {} + +trait Y { + #[type_const] + const N: usize; +} + +impl Y for T { + #[type_const] + const N: usize = 1; +} + +fn main() { + let _: dyn X; //~ ERROR the const parameter `N` must be explicitly specified +} diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.stderr new file mode 100644 index 000000000000..d92fd620f0ea --- /dev/null +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-const-param-default-mentions-self.stderr @@ -0,0 +1,18 @@ +error[E0393]: the const parameter `N` must be explicitly specified + --> $DIR/dyn-compat-const-param-default-mentions-self.rs:20:16 + | +LL | trait X::N }> {} + | -------------------------------------------- const parameter `N` must be specified for this +... +LL | let _: dyn X; + | ^ + | + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type +help: explicitly specify the const parameter + | +LL | let _: dyn X; + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0393`. diff --git a/tests/ui/dyn-compatibility/default-param-self-projection.stderr b/tests/ui/dyn-compatibility/default-param-self-projection.stderr index ea252a99b048..86f85f4da8e6 100644 --- a/tests/ui/dyn-compatibility/default-param-self-projection.stderr +++ b/tests/ui/dyn-compatibility/default-param-self-projection.stderr @@ -7,11 +7,11 @@ LL | trait A::E> {} LL | let B: &dyn A = &(); | ^ | - = note: because the parameter default references `Self`, the parameter must be specified on the object type -help: set the type parameter to the desired type + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type +help: explicitly specify the type parameter | -LL | let B: &dyn A = &(); - | +++ +LL | let B: &dyn A = &(); + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0393.stderr b/tests/ui/error-codes/E0393.stderr index 4847aa2508da..a6991aa355fa 100644 --- a/tests/ui/error-codes/E0393.stderr +++ b/tests/ui/error-codes/E0393.stderr @@ -7,11 +7,11 @@ LL | LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} | ^ | - = note: because the parameter default references `Self`, the parameter must be specified on the object type -help: set the type parameter to the desired type + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type +help: explicitly specify the type parameter | -LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} - | +++ +LL | fn together_we_will_rule_the_galaxy(son: &dyn A) {} + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-22370.stderr b/tests/ui/issues/issue-22370.stderr index b02d867eb7dd..cd1580e844ca 100644 --- a/tests/ui/issues/issue-22370.stderr +++ b/tests/ui/issues/issue-22370.stderr @@ -7,11 +7,11 @@ LL | LL | fn f(a: &dyn A) {} | ^ | - = note: because the parameter default references `Self`, the parameter must be specified on the object type -help: set the type parameter to the desired type + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type +help: explicitly specify the type parameter | -LL | fn f(a: &dyn A) {} - | +++ +LL | fn f(a: &dyn A) {} + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr index 86b77193155d..b7d78a3284e3 100644 --- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr +++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr @@ -97,7 +97,7 @@ LL | pub trait Bar { LL | let e = Bar::::lol(); | ^^^^^^^^^^^^ missing reference to `A` | - = note: because the parameter default references `Self`, the parameter must be specified on the object type + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type error: aborting due to 5 previous errors; 5 warnings emitted diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr index 23f10c9262c7..300ad1998e42 100644 --- a/tests/ui/type/type-parameter-defaults-referencing-Self.stderr +++ b/tests/ui/type/type-parameter-defaults-referencing-Self.stderr @@ -7,11 +7,11 @@ LL | trait Foo { LL | fn foo(x: &dyn Foo) { } | ^^^ | - = note: because the parameter default references `Self`, the parameter must be specified on the object type -help: set the type parameter to the desired type + = note: because the parameter default references `Self`, the parameter must be specified on the trait object type +help: explicitly specify the type parameter | -LL | fn foo(x: &dyn Foo) { } - | +++ +LL | fn foo(x: &dyn Foo) { } + | +++++++++ error: aborting due to 1 previous error