use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit as hir_visit;
use std::convert::TryInto;
use std::iter;
+use std::lazy::Lazy;
use std::ops::ControlFlow;
/// Helper type of a temporary returned by `.for_item(...)`.
for more information",
);
- err.emit()
+ err.emit();
}
}
}
"using {} as const generic parameters is forbidden",
unsupported_type
),
- )
+ );
} else {
let mut err = tcx.sess.struct_span_err(
hir_ty.span,
"more complex types are supported with `#![feature(adt_const_params)]`",
);
}
- err.emit()
+ err.emit();
}
};
identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
+ // Lazily calculated because it is only needed in case of an error.
+ let explicitly_bounded_params = Lazy::new(|| {
+ let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+ hir_generics
+ .where_clause
+ .predicates
+ .iter()
+ .filter_map(|predicate| match predicate {
+ hir::WherePredicate::BoundPredicate(predicate) => {
+ match icx.to_ty(predicate.bounded_ty).kind() {
+ ty::Param(data) => Some(Parameter(data.index)),
+ _ => None,
+ }
+ }
+ _ => None,
+ })
+ .collect::<FxHashSet<_>>()
+ });
+
for (index, _) in variances.iter().enumerate() {
- if constrained_parameters.contains(&Parameter(index as u32)) {
+ let parameter = Parameter(index as u32);
+
+ if constrained_parameters.contains(¶meter) {
continue;
}
match param.name {
hir::ParamName::Error => {}
- _ => report_bivariance(tcx, param),
+ _ => {
+ let has_explicit_bounds =
+ !param.bounds.is_empty() || explicitly_bounded_params.contains(¶meter);
+ report_bivariance(tcx, param, has_explicit_bounds);
+ }
}
}
}
-fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) {
+fn report_bivariance(
+ tcx: TyCtxt<'_>,
+ param: &rustc_hir::GenericParam<'_>,
+ has_explicit_bounds: bool,
+) -> ErrorReported {
let span = param.span;
let param_name = param.name.ident().name;
let mut err = error_392(tcx, span, param_name);
};
err.help(&msg);
- if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+ if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
err.help(&format!(
"if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
param_name
}
}
-fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
+fn error_392(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ param_name: Symbol,
+) -> DiagnosticBuilder<'_, ErrorReported> {
let mut err =
struct_span_err!(tcx.sess, span, E0392, "parameter `{}` is never used", param_name);
err.span_label(span, "unused parameter");