mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rollup merge of #106648 - Nilstrieb:poly-cleanup, r=compiler-errors
Polymorphization cleanup Split out of #106233 Use a newtype instead of a bitset directly. This makes the code way easier to read and easier to adapt for future changes.
This commit is contained in:
commit
6e0c404f76
@ -40,12 +40,11 @@ where
|
||||
let index = index
|
||||
.try_into()
|
||||
.expect("more generic parameters than can fit into a `u32`");
|
||||
let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
|
||||
// Only recurse when generic parameters in fns, closures and generators
|
||||
// are used and require substitution.
|
||||
// Just in case there are closures or generators within this subst,
|
||||
// recurse.
|
||||
if is_used && subst.needs_subst() {
|
||||
if unused_params.is_used(index) && subst.needs_subst() {
|
||||
return subst.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
@ -1429,7 +1429,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
let instance =
|
||||
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
if !unused.is_empty() {
|
||||
if !unused.all_used() {
|
||||
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
|
||||
use rustc_hir::definitions::DefKey;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::{BitSet, FiniteBitSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::metadata::ModChild;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, ReprOptions, Ty};
|
||||
use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
|
||||
use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
|
||||
use rustc_serialize::opaque::FileEncoder;
|
||||
use rustc_session::config::SymbolManglingVersion;
|
||||
@ -384,7 +384,7 @@ define_tables! {
|
||||
trait_item_def_id: Table<DefIndex, RawDefId>,
|
||||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
|
||||
unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
|
||||
unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
|
||||
params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
|
||||
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
|
||||
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
||||
|
@ -1839,7 +1839,7 @@ rustc_queries! {
|
||||
desc { "getting codegen unit `{sym}`" }
|
||||
}
|
||||
|
||||
query unused_generic_params(key: ty::InstanceDef<'tcx>) -> FiniteBitSet<u32> {
|
||||
query unused_generic_params(key: ty::InstanceDef<'tcx>) -> UnusedGenericParams {
|
||||
cache_on_disk_if { key.def_id().is_local() }
|
||||
desc {
|
||||
|tcx| "determining which generic parameters are unused by `{}`",
|
||||
|
@ -6,6 +6,7 @@ use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::FiniteBitSet;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
|
||||
use rustc_span::Symbol;
|
||||
@ -711,7 +712,7 @@ fn polymorphize<'tcx>(
|
||||
}
|
||||
|
||||
InternalSubsts::for_item(tcx, def_id, |param, _| {
|
||||
let is_unused = unused.contains(param.index).unwrap_or(false);
|
||||
let is_unused = unused.is_unused(param.index);
|
||||
debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
|
||||
match param.kind {
|
||||
// Upvar case: If parameter is a type parameter..
|
||||
@ -733,7 +734,7 @@ fn polymorphize<'tcx>(
|
||||
// Simple case: If parameter is a const or type parameter..
|
||||
ty::GenericParamDefKind::Const { .. } | ty::GenericParamDefKind::Type { .. } if
|
||||
// ..and is within range and unused..
|
||||
unused.contains(param.index).unwrap_or(false) =>
|
||||
unused.is_unused(param.index) =>
|
||||
// ..then use the identity for this parameter.
|
||||
tcx.mk_param_from_def(param),
|
||||
|
||||
@ -774,3 +775,36 @@ fn needs_fn_once_adapter_shim(
|
||||
(ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce, _) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
// Set bits represent unused generic parameters.
|
||||
// An empty set indicates that all parameters are used.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)]
|
||||
pub struct UnusedGenericParams(FiniteBitSet<u32>);
|
||||
|
||||
impl UnusedGenericParams {
|
||||
pub fn new_all_unused(amount: u32) -> Self {
|
||||
let mut bitset = FiniteBitSet::new_empty();
|
||||
bitset.set_range(0..amount);
|
||||
Self(bitset)
|
||||
}
|
||||
|
||||
pub fn new_all_used() -> Self {
|
||||
Self(FiniteBitSet::new_empty())
|
||||
}
|
||||
|
||||
pub fn mark_used(&mut self, idx: u32) {
|
||||
self.0.clear(idx);
|
||||
}
|
||||
|
||||
pub fn is_unused(&self, idx: u32) -> bool {
|
||||
self.0.contains(idx).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_used(&self, idx: u32) -> bool {
|
||||
!self.is_unused(idx)
|
||||
}
|
||||
|
||||
pub fn all_used(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ pub use self::context::{
|
||||
tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
|
||||
TyCtxtFeed,
|
||||
};
|
||||
pub use self::instance::{Instance, InstanceDef, ShortInstance};
|
||||
pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
|
||||
pub use self::list::List;
|
||||
pub use self::parameterized::ParameterizedOverTcx;
|
||||
pub use self::rvalue_scopes::RvalueScopes;
|
||||
|
@ -60,6 +60,7 @@ trivially_parameterized_over_tcx! {
|
||||
ty::ImplPolarity,
|
||||
ty::ReprOptions,
|
||||
ty::TraitDef,
|
||||
ty::UnusedGenericParams,
|
||||
ty::Visibility<DefIndex>,
|
||||
ty::adjustment::CoerceUnsizedInfo,
|
||||
ty::fast_reject::SimplifiedType,
|
||||
|
@ -34,7 +34,7 @@ use crate::ty::layout::TyAndLayout;
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::GeneratorDiagnosticData;
|
||||
use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
|
||||
use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_attr as attr;
|
||||
@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
use rustc_hir::lang_items::{LangItem, LanguageItems};
|
||||
use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
|
||||
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
|
||||
use rustc_session::cstore::{CrateDepKind, CrateSource};
|
||||
use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
|
||||
|
@ -32,13 +32,13 @@ pub struct TypeLengthLimit {
|
||||
pub type_length: usize,
|
||||
}
|
||||
|
||||
pub struct UnusedGenericParams {
|
||||
pub struct UnusedGenericParamsHint {
|
||||
pub span: Span,
|
||||
pub param_spans: Vec<Span>,
|
||||
pub param_names: Vec<String>,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for UnusedGenericParams {
|
||||
impl IntoDiagnostic<'_> for UnusedGenericParamsHint {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
|
@ -6,7 +6,6 @@
|
||||
//! for their size, offset of a field, etc.).
|
||||
|
||||
use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
|
||||
use rustc_index::bit_set::FiniteBitSet;
|
||||
use rustc_middle::mir::{
|
||||
self,
|
||||
visit::{TyContext, Visitor},
|
||||
@ -17,12 +16,12 @@ use rustc_middle::ty::{
|
||||
query::Providers,
|
||||
subst::SubstsRef,
|
||||
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
||||
Const, Ty, TyCtxt,
|
||||
Const, Ty, TyCtxt, UnusedGenericParams,
|
||||
};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::errors::UnusedGenericParams;
|
||||
use crate::errors::UnusedGenericParamsHint;
|
||||
|
||||
/// Provide implementations of queries relating to polymorphization analysis.
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
@ -36,16 +35,16 @@ pub fn provide(providers: &mut Providers) {
|
||||
fn unused_generic_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
) -> FiniteBitSet<u32> {
|
||||
) -> UnusedGenericParams {
|
||||
if !tcx.sess.opts.unstable_opts.polymorphize {
|
||||
// If polymorphization disabled, then all parameters are used.
|
||||
return FiniteBitSet::new_empty();
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let def_id = instance.def_id();
|
||||
// Exit early if this instance should not be polymorphized.
|
||||
if !should_polymorphize(tcx, def_id, instance) {
|
||||
return FiniteBitSet::new_empty();
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
@ -53,14 +52,13 @@ fn unused_generic_params<'tcx>(
|
||||
|
||||
// Exit early when there are no parameters to be unused.
|
||||
if generics.count() == 0 {
|
||||
return FiniteBitSet::new_empty();
|
||||
return UnusedGenericParams::new_all_used();
|
||||
}
|
||||
|
||||
// Create a bitset with N rightmost ones for each parameter.
|
||||
let generics_count: u32 =
|
||||
generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
|
||||
let mut unused_parameters = FiniteBitSet::<u32>::new_empty();
|
||||
unused_parameters.set_range(0..generics_count);
|
||||
let mut unused_parameters = UnusedGenericParams::new_all_unused(generics_count);
|
||||
debug!(?unused_parameters, "(start)");
|
||||
|
||||
mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
|
||||
@ -78,7 +76,7 @@ fn unused_generic_params<'tcx>(
|
||||
debug!(?unused_parameters, "(end)");
|
||||
|
||||
// Emit errors for debugging and testing if enabled.
|
||||
if !unused_parameters.is_empty() {
|
||||
if !unused_parameters.all_used() {
|
||||
emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
|
||||
}
|
||||
|
||||
@ -136,13 +134,13 @@ fn mark_used_by_default_parameters<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &mut FiniteBitSet<u32>,
|
||||
unused_parameters: &mut UnusedGenericParams,
|
||||
) {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Closure | DefKind::Generator => {
|
||||
for param in &generics.params {
|
||||
debug!(?param, "(closure/gen)");
|
||||
unused_parameters.clear(param.index);
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
DefKind::Mod
|
||||
@ -178,7 +176,7 @@ fn mark_used_by_default_parameters<'tcx>(
|
||||
for param in &generics.params {
|
||||
debug!(?param, "(other)");
|
||||
if let ty::GenericParamDefKind::Lifetime = param.kind {
|
||||
unused_parameters.clear(param.index);
|
||||
unused_parameters.mark_used(param.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,7 +194,7 @@ fn emit_unused_generic_params_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
generics: &'tcx ty::Generics,
|
||||
unused_parameters: &FiniteBitSet<u32>,
|
||||
unused_parameters: &UnusedGenericParams,
|
||||
) {
|
||||
let base_def_id = tcx.typeck_root_def_id(def_id);
|
||||
if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
|
||||
@ -213,7 +211,7 @@ fn emit_unused_generic_params_error<'tcx>(
|
||||
let mut next_generics = Some(generics);
|
||||
while let Some(generics) = next_generics {
|
||||
for param in &generics.params {
|
||||
if unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
if unused_parameters.is_unused(param.index) {
|
||||
debug!(?param);
|
||||
let def_span = tcx.def_span(param.def_id);
|
||||
param_spans.push(def_span);
|
||||
@ -224,14 +222,14 @@ fn emit_unused_generic_params_error<'tcx>(
|
||||
next_generics = generics.parent.map(|did| tcx.generics_of(did));
|
||||
}
|
||||
|
||||
tcx.sess.emit_err(UnusedGenericParams { span: fn_span, param_spans, param_names });
|
||||
tcx.sess.emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
|
||||
}
|
||||
|
||||
/// Visitor used to aggregate generic parameter uses.
|
||||
struct MarkUsedGenericParams<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
unused_parameters: &'a mut FiniteBitSet<u32>,
|
||||
unused_parameters: &'a mut UnusedGenericParams,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
|
||||
@ -244,7 +242,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
|
||||
debug!(?self.unused_parameters, ?unused);
|
||||
for (i, arg) in substs.iter().enumerate() {
|
||||
let i = i.try_into().unwrap();
|
||||
if !unused.contains(i).unwrap_or(false) {
|
||||
if unused.is_used(i) {
|
||||
arg.visit_with(self);
|
||||
}
|
||||
}
|
||||
@ -308,7 +306,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.clear(param.index);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
|
||||
@ -342,55 +340,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
}
|
||||
ty::Param(param) => {
|
||||
debug!(?param);
|
||||
self.unused_parameters.clear(param.index);
|
||||
self.unused_parameters.mark_used(param.index);
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor used to check if a generic parameter is used.
|
||||
struct HasUsedGenericParams<'a> {
|
||||
unused_parameters: &'a FiniteBitSet<u32>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
|
||||
type BreakTy = ();
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !c.has_non_region_param() {
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match c.kind() {
|
||||
ty::ConstKind::Param(param) => {
|
||||
if self.unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ControlFlow::BREAK
|
||||
}
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !ty.has_non_region_param() {
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
ty::Param(param) => {
|
||||
if self.unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ControlFlow::BREAK
|
||||
}
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user