Use structured suggestions for unconstrained generic parameters on impl blocks

This commit is contained in:
Oli Scherer 2024-07-19 14:21:30 +00:00
parent 3d68afc9e8
commit a0db06bdeb
3 changed files with 39 additions and 56 deletions

View File

@ -519,6 +519,11 @@ hir_analysis_typeof_reserved_keyword_used =
.suggestion = consider replacing `typeof(...)` with an actual type
.label = reserved keyword
hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_name}` is not constrained by the impl trait, self type, or predicates
.label = unconstrained {$param_def_kind}
.const_param_note = expressions using a const parameter must map each value to a distinct output value
.const_param_note2 = proving the result of expressions other than the parameter are unique is not supported
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
.note = `{$name}` must be used in combination with a concrete type within the same {$what}

View File

@ -1604,6 +1604,20 @@ pub(crate) enum UnusedGenericParameterHelp {
TyAlias { param_name: Ident },
}
#[derive(Diagnostic)]
#[diag(hir_analysis_unconstrained_generic_parameter)]
pub(crate) struct UnconstrainedGenericParameter {
#[primary_span]
#[label]
pub span: Span,
pub param_name: Symbol,
pub param_def_kind: &'static str,
#[note(hir_analysis_const_param_note)]
pub const_param_note: Option<()>,
#[note(hir_analysis_const_param_note2)]
pub const_param_note2: Option<()>,
}
#[derive(Diagnostic)]
pub enum UnnamedFieldsRepr<'a> {
#[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]

View File

@ -8,15 +8,15 @@
//! specialization errors. These things can (and probably should) be
//! fixed, but for the moment it's easier to do these checks early.
use crate::constrained_generic_params as cgp;
use crate::{constrained_generic_params as cgp, errors::UnconstrainedGenericParameter};
use min_specialization::check_min_specialization;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{codes::*, struct_span_code_err};
use rustc_errors::codes::*;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use rustc_span::ErrorGuaranteed;
mod min_specialization;
@ -117,43 +117,34 @@ fn enforce_impl_params_are_constrained(
let mut res = Ok(());
for param in &impl_generics.own_params {
match param.kind {
let err = match param.kind {
// Disallow ANY unconstrained type parameters.
ty::GenericParamDefKind::Type { .. } => {
let param_ty = ty::ParamTy::for_def(param);
if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
res = Err(report_unused_parameter(
tcx,
tcx.def_span(param.def_id),
"type",
param_ty.name,
));
}
!input_parameters.contains(&cgp::Parameter::from(param_ty))
}
ty::GenericParamDefKind::Lifetime => {
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
if lifetimes_in_associated_types.contains(&param_lt) && // (*)
lifetimes_in_associated_types.contains(&param_lt) && // (*)
!input_parameters.contains(&param_lt)
{
res = Err(report_unused_parameter(
tcx,
tcx.def_span(param.def_id),
"lifetime",
param.name,
));
}
}
ty::GenericParamDefKind::Const { .. } => {
let param_ct = ty::ParamConst::for_def(param);
if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
res = Err(report_unused_parameter(
tcx,
tcx.def_span(param.def_id),
"const",
param_ct.name,
));
}
!input_parameters.contains(&cgp::Parameter::from(param_ct))
}
};
if err {
let const_param_note =
matches!(param.kind, ty::GenericParamDefKind::Const { .. }).then_some(());
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
span: tcx.def_span(param.def_id),
param_name: param.name,
param_def_kind: tcx.def_descr(param.def_id),
const_param_note,
const_param_note2: const_param_note,
});
diag.code(E0207);
res = Err(diag.emit());
}
}
res
@ -177,30 +168,3 @@ fn enforce_impl_params_are_constrained(
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
}
fn report_unused_parameter(
tcx: TyCtxt<'_>,
span: Span,
kind: &str,
name: Symbol,
) -> ErrorGuaranteed {
let mut err = struct_span_code_err!(
tcx.dcx(),
span,
E0207,
"the {} parameter `{}` is not constrained by the \
impl trait, self type, or predicates",
kind,
name
);
err.span_label(span, format!("unconstrained {kind} parameter"));
if kind == "const" {
err.note(
"expressions using a const parameter must map each value to a distinct output value",
);
err.note(
"proving the result of expressions other than the parameter are unique is not supported",
);
}
err.emit()
}