Skip to content
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let param_env = self.infcx.param_env;
// Upcast to a `Clause`, then to a `Predicate`.
let predicate = clause.upcast(self.tcx()).upcast(self.tcx());
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
let _: Result<(), ErrorGuaranteed> = self.fully_perform_op(
locations,
category,
param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
Expand Down
144 changes: 82 additions & 62 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, sym};
use rustc_structures::{CrateType, Limit};
use rustc_type_ir::TyKind::*;
pub use rustc_type_ir::lift::Lift;
use rustc_type_ir::{CollectAndApply, WithCachedTypeInfo, elaborate, search_graph};
use rustc_type_ir::{
CollectAndApply, PlaceholderType, WithCachedTypeInfo, elaborate, search_graph,
};
use tracing::{debug, instrument};

use crate::arena::Arena;
Expand Down Expand Up @@ -284,28 +286,22 @@ impl<'tcx> CtxtInterners<'tcx> {
// For these preinterned values, an alternative would be to have
// variable-length vectors that grow as needed. But that turned out to be
// slightly more complex and no faster.
//
// All numbers have been chosen based on profiling data.

const NUM_PREINTERNED_INFER_TY_VARS: u32 = 512;
const NUM_PREINTERNED_INFER_FRESH_TYS: u32 = 20;
const NUM_PREINTERNED_INFER_FRESH_INT_TYS: u32 = 3;
const NUM_PREINTERNED_INFER_FRESH_FLOAT_TYS: u32 = 3;
const NUM_PREINTERNED_BOUND_BOUND_ANONS_I: u32 = 3;
const NUM_PREINTERNED_BOUND_BOUND_ANONS_V: u32 = 20;
const NUM_PREINTERNED_BOUND_CANONICAL_ANONS: u32 = 128;
const NUM_PREINTERNED_PLACEHOLDER_ROOT_ANONS: u32 = 128;

const NUM_PREINTERNED_TY_VARS: u32 = 100;
const NUM_PREINTERNED_FRESH_TYS: u32 = 20;
const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3;
const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3;
const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3;

// From general profiling of the *max vars during canonicalization* of a value:
// - about 90% of the time, there are no canonical vars
// - about 9% of the time, there is only one canonical var
// - there are rarely more than 3-5 canonical vars (with exceptions in particularly pathological
// cases)
// This may not match the number of bound vars found in `for`s.
// Given that this is all heap interned, it seems likely that interning fewer
// vars here won't make an appreciable difference. Though, if we were to inline the data (in an
// array), we may want to consider reducing the number for canonicalized vars down to 4 or so.
const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20;

// This number may seem high, but it is reached in all but the smallest crates.
const NUM_PREINTERNED_RE_VARS: u32 = 500;
const NUM_PREINTERNED_ANON_RE_BOUNDS_I: u32 = 3;
const NUM_PREINTERNED_ANON_RE_BOUNDS_V: u32 = 20;
const NUM_PREINTERNED_RE_BOUND_BOUND_ANONS_I: u32 = 3;
const NUM_PREINTERNED_RE_BOUND_BOUND_ANONS_V: u32 = 20;
const NUM_PREINTERNED_RE_BOUND_CANONICAL_ANONS: u32 = 20;

pub struct CommonTypes<'tcx> {
pub unit: Ty<'tcx>,
Expand Down Expand Up @@ -360,26 +356,37 @@ pub struct CommonTypes<'tcx> {
pub trait_object_dummy_self: Ty<'tcx>,

/// Pre-interned `Infer(ty::TyVar(n))` for small values of `n`.
pub ty_vars: Vec<Ty<'tcx>>,
pub infer_ty_vars: Vec<Ty<'tcx>>,

/// Pre-interned `Infer(ty::FreshTy(n))` for small values of `n`.
pub fresh_tys: Vec<Ty<'tcx>>,
pub infer_fresh_tys: Vec<Ty<'tcx>>,

/// Pre-interned `Infer(ty::FreshIntTy(n))` for small values of `n`.
pub fresh_int_tys: Vec<Ty<'tcx>>,
pub infer_fresh_int_tys: Vec<Ty<'tcx>>,

/// Pre-interned `Infer(ty::FreshFloatTy(n))` for small values of `n`.
pub fresh_float_tys: Vec<Ty<'tcx>>,
pub infer_fresh_float_tys: Vec<Ty<'tcx>>,

/// Pre-interned values of the form:
/// `Bound(
/// BoundVarIndexKind::Bound(DebruijnIndex(i)),
/// BoundTy { var: v, kind: BoundTyKind::Anon }
/// )`
/// for small values of `i` and `v`.
pub bound_bound_anons: Vec<Vec<Ty<'tcx>>>,

/// Pre-interned values of the form:
/// `Bound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundTy { var: v, kind:
/// BoundTyKind::Anon})` for small values of `i` and `v`.
pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>,

// Pre-interned values of the form:
// `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })`
// for small values of `v`.
pub anon_canonical_bound_tys: Vec<Ty<'tcx>>,
/// `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })`
/// for small values of `v`.
pub bound_canonical_anons: Vec<Ty<'tcx>>,

/// Pre-interned values of the form:
/// `Placeholder(Placeholder {
/// universe: UniverseIndex::ROOT,
/// bound: BoundTy { var: v, kind: BoundTyKind::Anon }
/// })`
/// for small values of `v`.
pub placeholder_root_anons: Vec<Ty<'tcx>>,
}

pub struct CommonLifetimes<'tcx> {
Expand All @@ -389,18 +396,18 @@ pub struct CommonLifetimes<'tcx> {
/// Erased region, used outside of type inference.
pub re_erased: Region<'tcx>,

/// Pre-interned `ReVar(ty::RegionVar(n))` for small values of `n`.
/// Pre-interned `ReVar(ty::RegionVid(n))` for small values of `n`.
pub re_vars: Vec<Region<'tcx>>,

/// Pre-interned values of the form:
/// `ReBound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
/// for small values of `i` and `v`.
pub anon_re_bounds: Vec<Vec<Region<'tcx>>>,
pub re_bound_bound_anons: Vec<Vec<Region<'tcx>>>,

// Pre-interned values of the form:
// `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })`
// for small values of `v`.
pub anon_re_canonical_bounds: Vec<Region<'tcx>>,
/// Pre-interned values of the form:
/// `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })`
/// for small values of `v`.
pub re_bound_canonical_anons: Vec<Region<'tcx>>,
}

pub struct CommonConsts<'tcx> {
Expand All @@ -415,18 +422,21 @@ impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
let mk = |ty| interners.intern_ty(ty);

let ty_vars =
(0..NUM_PREINTERNED_TY_VARS).map(|n| mk(Infer(ty::TyVar(TyVid::from(n))))).collect();
let fresh_tys: Vec<_> =
(0..NUM_PREINTERNED_FRESH_TYS).map(|n| mk(Infer(ty::FreshTy(n)))).collect();
let fresh_int_tys: Vec<_> =
(0..NUM_PREINTERNED_FRESH_INT_TYS).map(|n| mk(Infer(ty::FreshIntTy(n)))).collect();
let fresh_float_tys: Vec<_> =
(0..NUM_PREINTERNED_FRESH_FLOAT_TYS).map(|n| mk(Infer(ty::FreshFloatTy(n)))).collect();
let infer_ty_vars = (0..NUM_PREINTERNED_INFER_TY_VARS)
.map(|n| mk(Infer(ty::TyVar(TyVid::from(n)))))
.collect();
let infer_fresh_tys: Vec<_> =
(0..NUM_PREINTERNED_INFER_FRESH_TYS).map(|n| mk(Infer(ty::FreshTy(n)))).collect();
let infer_fresh_int_tys: Vec<_> = (0..NUM_PREINTERNED_INFER_FRESH_INT_TYS)
.map(|n| mk(Infer(ty::FreshIntTy(n))))
.collect();
let infer_fresh_float_tys: Vec<_> = (0..NUM_PREINTERNED_INFER_FRESH_FLOAT_TYS)
.map(|n| mk(Infer(ty::FreshFloatTy(n))))
.collect();

let anon_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_I)
let bound_bound_anons = (0..NUM_PREINTERNED_BOUND_BOUND_ANONS_I)
.map(|i| {
(0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
(0..NUM_PREINTERNED_BOUND_BOUND_ANONS_V)
.map(|v| {
mk(ty::Bound(
ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
Expand All @@ -437,7 +447,7 @@ impl<'tcx> CommonTypes<'tcx> {
})
.collect();

let anon_canonical_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
let bound_canonical_anons = (0..NUM_PREINTERNED_BOUND_CANONICAL_ANONS)
.map(|v| {
mk(ty::Bound(
ty::BoundVarIndexKind::Canonical,
Expand All @@ -446,6 +456,15 @@ impl<'tcx> CommonTypes<'tcx> {
})
.collect();

let placeholder_root_anons = (0..NUM_PREINTERNED_PLACEHOLDER_ROOT_ANONS)
.map(|v| {
mk(ty::Placeholder(PlaceholderType::new_anon(
ty::UniverseIndex::ROOT,
ty::BoundVar::from(v),
)))
})
.collect();

CommonTypes {
unit: mk(Tuple(List::empty())),
bool: mk(Bool),
Expand All @@ -470,14 +489,15 @@ impl<'tcx> CommonTypes<'tcx> {
str_: mk(Str),
self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),

trait_object_dummy_self: fresh_tys[0],
trait_object_dummy_self: infer_fresh_tys[0],

ty_vars,
fresh_tys,
fresh_int_tys,
fresh_float_tys,
anon_bound_tys,
anon_canonical_bound_tys,
infer_ty_vars,
infer_fresh_tys,
infer_fresh_int_tys,
infer_fresh_float_tys,
bound_bound_anons,
bound_canonical_anons,
placeholder_root_anons,
}
}
}
Expand All @@ -493,9 +513,9 @@ impl<'tcx> CommonLifetimes<'tcx> {
let re_vars =
(0..NUM_PREINTERNED_RE_VARS).map(|n| mk(ty::ReVar(ty::RegionVid::from(n)))).collect();

let anon_re_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_I)
let re_bound_bound_anons = (0..NUM_PREINTERNED_RE_BOUND_BOUND_ANONS_I)
.map(|i| {
(0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
(0..NUM_PREINTERNED_RE_BOUND_BOUND_ANONS_V)
.map(|v| {
mk(ty::ReBound(
ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
Expand All @@ -509,7 +529,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
})
.collect();

let anon_re_canonical_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
let re_bound_canonical_anons = (0..NUM_PREINTERNED_RE_BOUND_CANONICAL_ANONS)
.map(|v| {
mk(ty::ReBound(
ty::BoundVarIndexKind::Canonical,
Expand All @@ -522,8 +542,8 @@ impl<'tcx> CommonLifetimes<'tcx> {
re_static: mk(ty::ReStatic),
re_erased: mk(ty::ReErased),
re_vars,
anon_re_bounds,
anon_re_canonical_bounds,
re_bound_bound_anons,
re_bound_canonical_anons,
}
}
}
Expand Down
27 changes: 2 additions & 25 deletions compiler/rustc_middle/src/ty/context/impl_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
ty::AliasConstKind::Anon { .. } => None,
}
}
fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind {
self.anon_const_kind(def_id)
}

fn def_span(self, def_id: DefId) -> Span {
self.def_span(def_id)
Expand Down Expand Up @@ -494,10 +491,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
}

fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool {
self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item))
}

fn is_default_trait(self, def_id: DefId) -> bool {
self.is_default_trait(def_id)
}
Expand Down Expand Up @@ -604,10 +597,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.trait_def(trait_def_id).safety.is_unsafe()
}

fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
self.is_impl_trait_in_trait(def_id)
}

fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string())
}
Expand Down Expand Up @@ -683,18 +672,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
})
}

fn get_anon_re_bounds_lifetime(self, idx: usize, var_idx: usize) -> Option<Region<'tcx>> {
if let Some(inner) = self.lifetimes.anon_re_bounds.get(idx) {
inner.get(var_idx).copied()
} else {
None
}
}

fn get_anon_re_canonical_bounds_lifetime(self, idx: usize) -> Option<Region<'tcx>> {
self.lifetimes.anon_re_canonical_bounds.get(idx).copied()
}

fn get_re_static_lifetime(self) -> Region<'tcx> {
self.lifetimes.re_static
}
Expand All @@ -719,7 +696,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
) -> Region<'tcx> {
// Use a pre-interned one when possible.
if let ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon } = bound_region
&& let Some(inner) = self.lifetimes.anon_re_bounds.get(debruijn.as_usize())
&& let Some(inner) = self.lifetimes.re_bound_bound_anons.get(debruijn.as_usize())
&& let Some(re) = inner.get(var.as_usize()).copied()
{
re
Expand All @@ -730,7 +707,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {

fn intern_canonical_bound(self, var: BoundVar) -> Region<'tcx> {
// Use a pre-interned one when possible.
if let Some(re) = self.lifetimes.anon_re_canonical_bounds.get(var.as_usize()).copied() {
if let Some(re) = self.lifetimes.re_bound_canonical_anons.get(var.as_usize()).copied() {
re
} else {
self.intern_region(ty::ReBound(
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::TyVid) -> Ty<'tcx> {
// Use a pre-interned one when possible.
tcx.types
.ty_vars
.infer_ty_vars
.get(v.as_usize())
.copied()
.unwrap_or_else(|| Ty::new(tcx, Infer(TyVar(v))))
Expand All @@ -398,7 +398,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_fresh(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
// Use a pre-interned one when possible.
tcx.types
.fresh_tys
.infer_fresh_tys
.get(n as usize)
.copied()
.unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshTy(n)))
Expand All @@ -408,7 +408,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_fresh_int(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
// Use a pre-interned one when possible.
tcx.types
.fresh_int_tys
.infer_fresh_int_tys
.get(n as usize)
.copied()
.unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshIntTy(n)))
Expand All @@ -418,7 +418,7 @@ impl<'tcx> Ty<'tcx> {
pub fn new_fresh_float(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
// Use a pre-interned one when possible.
tcx.types
.fresh_float_tys
.infer_fresh_float_tys
.get(n as usize)
.copied()
.unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshFloatTy(n)))
Expand All @@ -437,7 +437,7 @@ impl<'tcx> Ty<'tcx> {
) -> Ty<'tcx> {
// Use a pre-interned one when possible.
if let ty::BoundTy { var, kind: ty::BoundTyKind::Anon } = bound_ty
&& let Some(inner) = tcx.types.anon_bound_tys.get(index.as_usize())
&& let Some(inner) = tcx.types.bound_bound_anons.get(index.as_usize())
&& let Some(ty) = inner.get(var.as_usize()).copied()
{
ty
Expand All @@ -449,7 +449,7 @@ impl<'tcx> Ty<'tcx> {
#[inline]
pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> {
// Use a pre-interned one when possible.
if let Some(ty) = tcx.types.anon_canonical_bound_tys.get(var.as_usize()).copied() {
if let Some(ty) = tcx.types.bound_canonical_anons.get(var.as_usize()).copied() {
ty
} else {
Ty::new(
Expand All @@ -464,7 +464,15 @@ impl<'tcx> Ty<'tcx> {

#[inline]
pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType<'tcx>) -> Ty<'tcx> {
Ty::new(tcx, Placeholder(placeholder))
if placeholder.universe.is_root()
&& placeholder.bound.kind == ty::BoundTyKind::Anon
&& let Some(ty) =
tcx.types.placeholder_root_anons.get(placeholder.bound.var.as_usize()).copied()
{
ty
} else {
Ty::new(tcx, Placeholder(placeholder))
}
}

#[inline]
Expand Down
Loading
Loading