Account for structs that have unused params in nested types in fields
This commit is contained in:
parent
a0a251a688
commit
c02d0de871
@ -553,6 +553,7 @@ hir_analysis_unused_generic_parameter =
|
|||||||
{$param_def_kind} `{$param_name}` is never used
|
{$param_def_kind} `{$param_name}` is never used
|
||||||
.label = unused {$param_def_kind}
|
.label = unused {$param_def_kind}
|
||||||
.const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
|
.const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
|
||||||
|
.usage_spans = `{$param_name}` is named here, but is likely unused in the containing type
|
||||||
|
|
||||||
hir_analysis_unused_generic_parameter_adt_help =
|
hir_analysis_unused_generic_parameter_adt_help =
|
||||||
consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
|
consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
|
||||||
|
@ -1572,6 +1572,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
|
|||||||
param_name,
|
param_name,
|
||||||
param_def_kind: tcx.def_descr(param.def_id),
|
param_def_kind: tcx.def_descr(param.def_id),
|
||||||
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
||||||
|
usage_spans: vec![],
|
||||||
const_param_help,
|
const_param_help,
|
||||||
});
|
});
|
||||||
diag.code(E0091);
|
diag.code(E0091);
|
||||||
|
@ -1921,33 +1921,102 @@ fn report_bivariance<'tcx>(
|
|||||||
item,
|
item,
|
||||||
);
|
);
|
||||||
|
|
||||||
if usage_spans.is_empty() {
|
if !usage_spans.is_empty() {
|
||||||
let const_param_help =
|
// First, check if the ADT is (probably) cyclical. We say probably here, since
|
||||||
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
|
// we're not actually looking into substitutions, just walking through fields.
|
||||||
.then_some(());
|
// And we only recurse into the fields of ADTs, and not the hidden types of
|
||||||
|
// opaques or anything else fancy.
|
||||||
|
let item_def_id = item.owner_id.to_def_id();
|
||||||
|
let is_probably_cyclical = if matches!(
|
||||||
|
tcx.def_kind(item_def_id),
|
||||||
|
DefKind::Struct | DefKind::Union | DefKind::Enum
|
||||||
|
) {
|
||||||
|
IsProbablyCyclical { tcx, adt_def_id: item_def_id, seen: Default::default() }
|
||||||
|
.visit_all_fields(tcx.adt_def(item_def_id))
|
||||||
|
.is_break()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
// If the ADT is cyclical, then if at least one usage of the type parameter or
|
||||||
|
// the `Self` alias is present in the, then it's probably a cyclical struct, and
|
||||||
|
// we should call those parameter usages recursive rather than just saying they're
|
||||||
|
// unused...
|
||||||
|
//
|
||||||
|
// We currently report *all* of the parameter usages, since computing the exact
|
||||||
|
// subset is very involved, and the fact we're mentioning recursion at all is
|
||||||
|
// likely to guide the user in the right direction.
|
||||||
|
if is_probably_cyclical {
|
||||||
|
let diag = tcx.dcx().create_err(errors::RecursiveGenericParameter {
|
||||||
|
spans: usage_spans,
|
||||||
|
param_span: param.span,
|
||||||
|
param_name,
|
||||||
|
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
||||||
|
help,
|
||||||
|
note: (),
|
||||||
|
});
|
||||||
|
return diag.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
|
let const_param_help =
|
||||||
span: param.span,
|
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
|
||||||
param_name,
|
.then_some(());
|
||||||
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
|
||||||
help,
|
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
|
||||||
const_param_help,
|
span: param.span,
|
||||||
});
|
param_name,
|
||||||
diag.code(E0392);
|
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
||||||
diag.emit()
|
usage_spans,
|
||||||
} else {
|
help,
|
||||||
let diag = tcx.dcx().create_err(errors::RecursiveGenericParameter {
|
const_param_help,
|
||||||
spans: usage_spans,
|
});
|
||||||
param_span: param.span,
|
diag.code(E0392);
|
||||||
param_name,
|
diag.emit()
|
||||||
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
}
|
||||||
help,
|
|
||||||
note: (),
|
/// Detects cases where an ADT is trivially cyclical -- we want to detect this so
|
||||||
});
|
/// /we only mention that its parameters are used cyclically if the ADT is truly
|
||||||
diag.emit()
|
/// cyclical.
|
||||||
|
///
|
||||||
|
/// Notably, we don't consider substitutions here, so this may have false positives.
|
||||||
|
struct IsProbablyCyclical<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
adt_def_id: DefId,
|
||||||
|
seen: FxHashSet<DefId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> IsProbablyCyclical<'tcx> {
|
||||||
|
fn visit_all_fields(&mut self, adt_def: ty::AdtDef<'tcx>) -> ControlFlow<(), ()> {
|
||||||
|
for field in adt_def.all_fields() {
|
||||||
|
self.tcx.type_of(field.did).instantiate_identity().visit_with(self)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> {
|
||||||
|
type Result = ControlFlow<(), ()>;
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||||
|
if let Some(adt_def) = t.ty_adt_def() {
|
||||||
|
if adt_def.did() == self.adt_def_id {
|
||||||
|
return ControlFlow::Break(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.seen.insert(adt_def.did()) {
|
||||||
|
self.visit_all_fields(adt_def)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collect usages of the `param_def_id` and `Res::SelfTyAlias` in the HIR.
|
||||||
|
///
|
||||||
|
/// This is used to report places where the user has used parameters in a
|
||||||
|
/// non-variance-constraining way for better bivariance errors.
|
||||||
struct CollectUsageSpans<'a> {
|
struct CollectUsageSpans<'a> {
|
||||||
spans: &'a mut Vec<Span>,
|
spans: &'a mut Vec<Span>,
|
||||||
param_def_id: DefId,
|
param_def_id: DefId,
|
||||||
|
@ -1597,6 +1597,8 @@ pub(crate) struct UnusedGenericParameter {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub param_name: Ident,
|
pub param_name: Ident,
|
||||||
pub param_def_kind: &'static str,
|
pub param_def_kind: &'static str,
|
||||||
|
#[label(hir_analysis_usage_spans)]
|
||||||
|
pub usage_spans: Vec<Span>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub help: UnusedGenericParameterHelp,
|
pub help: UnusedGenericParameterHelp,
|
||||||
#[help(hir_analysis_const_param_help)]
|
#[help(hir_analysis_const_param_help)]
|
||||||
|
@ -4,27 +4,27 @@ error[E0275]: overflow evaluating the requirement `Loop == _`
|
|||||||
LL | impl Loop {}
|
LL | impl Loop {}
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: type parameter `T` is only used recursively
|
error[E0392]: type parameter `T` is never used
|
||||||
--> $DIR/inherent-impls-overflow.rs:14:24
|
--> $DIR/inherent-impls-overflow.rs:14:12
|
||||||
|
|
|
|
||||||
LL | type Poly0<T> = Poly1<(T,)>;
|
LL | type Poly0<T> = Poly1<(T,)>;
|
||||||
| - ^
|
| ^ - `T` is named here, but is likely unused in the containing type
|
||||||
| |
|
| |
|
||||||
| type parameter must be used non-recursively in the definition
|
| unused type parameter
|
||||||
|
|
|
|
||||||
= help: consider removing `T` or referring to it in the body of the type alias
|
= help: consider removing `T` or referring to it in the body of the type alias
|
||||||
= note: all type parameters must be used in a non-recursive way in order to constrain their variance
|
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||||
|
|
||||||
error: type parameter `T` is only used recursively
|
error[E0392]: type parameter `T` is never used
|
||||||
--> $DIR/inherent-impls-overflow.rs:17:24
|
--> $DIR/inherent-impls-overflow.rs:17:12
|
||||||
|
|
|
|
||||||
LL | type Poly1<T> = Poly0<(T,)>;
|
LL | type Poly1<T> = Poly0<(T,)>;
|
||||||
| - ^
|
| ^ - `T` is named here, but is likely unused in the containing type
|
||||||
| |
|
| |
|
||||||
| type parameter must be used non-recursively in the definition
|
| unused type parameter
|
||||||
|
|
|
|
||||||
= help: consider removing `T` or referring to it in the body of the type alias
|
= help: consider removing `T` or referring to it in the body of the type alias
|
||||||
= note: all type parameters must be used in a non-recursive way in order to constrain their variance
|
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||||
|
|
||||||
error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
|
error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
|
||||||
--> $DIR/inherent-impls-overflow.rs:21:6
|
--> $DIR/inherent-impls-overflow.rs:21:6
|
||||||
@ -36,4 +36,5 @@ LL | impl Poly0<()> {}
|
|||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0275`.
|
Some errors have detailed explanations: E0275, E0392.
|
||||||
|
For more information about an error, try `rustc --explain E0275`.
|
||||||
|
@ -13,10 +13,10 @@ impl Loop {}
|
|||||||
|
|
||||||
type Poly0<T> = Poly1<(T,)>;
|
type Poly0<T> = Poly1<(T,)>;
|
||||||
//[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
|
//[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
|
||||||
//[next]~^^ ERROR type parameter `T` is only used recursively
|
//[next]~^^ ERROR type parameter `T` is never used
|
||||||
type Poly1<T> = Poly0<(T,)>;
|
type Poly1<T> = Poly0<(T,)>;
|
||||||
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
|
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
|
||||||
//[next]~^^ ERROR type parameter `T` is only used recursively
|
//[next]~^^ ERROR type parameter `T` is never used
|
||||||
|
|
||||||
impl Poly0<()> {}
|
impl Poly0<()> {}
|
||||||
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
|
//[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
|
||||||
|
@ -28,4 +28,9 @@ struct WithWhereBounds<T> where T: Sized {}
|
|||||||
struct WithOutlivesBounds<T: 'static> {}
|
struct WithOutlivesBounds<T: 'static> {}
|
||||||
//~^ ERROR parameter `T` is never used
|
//~^ ERROR parameter `T` is never used
|
||||||
|
|
||||||
|
struct DoubleNothing<T> {
|
||||||
|
//~^ ERROR parameter `T` is never used
|
||||||
|
s: SomeStruct<T>,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -62,6 +62,18 @@ LL | struct WithOutlivesBounds<T: 'static> {}
|
|||||||
|
|
|
|
||||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
error[E0392]: type parameter `T` is never used
|
||||||
|
--> $DIR/variance-unused-type-param.rs:31:22
|
||||||
|
|
|
||||||
|
LL | struct DoubleNothing<T> {
|
||||||
|
| ^ unused type parameter
|
||||||
|
LL |
|
||||||
|
LL | s: SomeStruct<T>,
|
||||||
|
| - `T` is named here, but is likely unused in the containing type
|
||||||
|
|
|
||||||
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0392`.
|
For more information about this error, try `rustc --explain E0392`.
|
||||||
|
Loading…
Reference in New Issue
Block a user