Skip to content

Commit

Permalink
Rollup merge of rust-lang#106648 - Nilstrieb:poly-cleanup, r=compiler…
Browse files Browse the repository at this point in the history
…-errors

Polymorphization cleanup

Split out of rust-lang#106233

Use a newtype instead of a bitset directly. This makes the code way easier to read and easier to adapt for future changes.
  • Loading branch information
Nilstrieb committed Jan 11, 2023
2 parents c962b07 + a4b859e commit 6e0c404
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 79 deletions.
3 changes: 1 addition & 2 deletions compiler/rustc_const_eval/src/interpret/util.rs
Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Expand Up @@ -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);
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/mod.rs
Expand Up @@ -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 `{}`",
Expand Down
38 changes: 36 additions & 2 deletions compiler/rustc_middle/src/ty/instance.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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..
Expand All @@ -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),

Expand Down Expand Up @@ -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()
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/parameterized.rs
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/query.rs
Expand Up @@ -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;
Expand All @@ -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};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_monomorphize/src/errors.rs
Expand Up @@ -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,
Expand Down
83 changes: 18 additions & 65 deletions compiler/rustc_monomorphize/src/polymorphize.rs
Expand Up @@ -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},
Expand All @@ -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) {
Expand All @@ -36,31 +35,30 @@ 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);
debug!(?generics);

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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -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> {
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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 })
Expand Down Expand Up @@ -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),
}
}
}

0 comments on commit 6e0c404

Please sign in to comment.