Fix handling of const params defaults that ref Self & generalize diag

We used to lower such bad defaulted const args in trait object types to
`{type error}`; now correctly lower them to `{const error}`.

The added tests used to ICE prior to this change.
This commit is contained in:
León Orell Valerian Liehr 2026-01-07 16:32:14 +01:00
parent baba337869
commit 233a45c41a
No known key found for this signature in database
GPG key ID: D17A07215F68E713
14 changed files with 139 additions and 108 deletions

View file

@ -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}

View file

@ -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<String>,
pub missing_type_params: Vec<Symbol>,
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::<Vec<_>>()
.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<Type>`.
// 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</* Term */>`.
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::<Vec<_>>()
.join(", ")
),

View file

@ -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,

View file

@ -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<Symbol>,
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,
});
}

View file

@ -1,6 +0,0 @@
//@ known-bug: #136063
#![feature(generic_const_exprs)]
trait A<const B: u8 = X> {}
impl A<1> for bool {}
fn bar(arg : &dyn A<x>) { bar(true) }
pub fn main() {}

View file

@ -1,11 +0,0 @@
//@ known-bug: #137260
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait Iter<const N: usize = { 1 + true }> {}
fn needs_iter<const N: usize, T: Iter<N>>() {}
fn test() {
needs_iter::<1, dyn Iter<()>>();
}

View file

@ -1,9 +0,0 @@
//@ known-bug: #137514
//@ needs-rustc-debug-assertions
#![feature(generic_const_exprs)]
trait Bar<const N: usize> {}
trait BB = Bar<{ 1i32 + 1 }>;
fn foo(x: &dyn BB) {}

View file

@ -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<const N: usize = { <Self as Y>::N }> {}
trait Y {
#[type_const]
const N: usize;
}
impl<T: ?Sized> Y for T {
#[type_const]
const N: usize = 1;
}
fn main() {
let _: dyn X; //~ ERROR the const parameter `N` must be explicitly specified
}

View file

@ -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<const N: usize = { <Self as Y>::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</* N */>;
| +++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0393`.

View file

@ -7,11 +7,11 @@ LL | trait A<C = <Self as D>::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<C> = &();
| +++
LL | let B: &dyn A</* C */> = &();
| +++++++++
error: aborting due to 1 previous error

View file

@ -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<T>) {}
| +++
LL | fn together_we_will_rule_the_galaxy(son: &dyn A</* T */>) {}
| +++++++++
error: aborting due to 1 previous error

View file

@ -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<T>) {}
| +++
LL | fn f(a: &dyn A</* T */>) {}
| +++++++++
error: aborting due to 1 previous error

View file

@ -97,7 +97,7 @@ LL | pub trait Bar<X=usize, A=Self> {
LL | let e = Bar::<usize>::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

View file

@ -7,11 +7,11 @@ LL | trait Foo<T=Self> {
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<T>) { }
| +++
LL | fn foo(x: &dyn Foo</* T */>) { }
| +++++++++
error: aborting due to 1 previous error