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:
parent
baba337869
commit
233a45c41a
14 changed files with 139 additions and 108 deletions
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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(", ")
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
@ -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<()>>();
|
||||
}
|
||||
|
|
@ -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) {}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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`.
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue