Skip to content

Commit

Permalink
Rollup merge of #127966 - oli-obk:structured_diag, r=compiler-errors
Browse files Browse the repository at this point in the history
Use structured suggestions for unconstrained generic parameters on impl blocks

I did not deduplicate with `UnusedGenericParameter`, because in contrast to type declarations, just using a generic parameter in an impl isn't enough, it must be used with the right variance and not just as part of a projection.
  • Loading branch information
matthiaskrgr authored Jul 19, 2024
2 parents 41d3cb6 + a0db06b commit a2c99cf
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 56 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,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}
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
76 changes: 20 additions & 56 deletions compiler/rustc_hir_analysis/src/impl_wf_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -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()
}

0 comments on commit a2c99cf

Please sign in to comment.