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:
nils 2023-01-11 17:30:55 +01:00 committed by GitHub
commit 6e0c404f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 66 additions and 79 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 `{}`",

View File

@ -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()
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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};

View File

@ -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,

View File

@ -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),
}
}
}