Rollup merge of #117586 - compiler-errors:the-canonicalizer, r=lcnr

Uplift the (new solver) canonicalizer into `rustc_next_trait_solver`

Uplifts the new trait solver's canonicalizer into a new crate called `rustc_next_trait_solver`.

The crate name is literally a bikeshed-avoidance name, so let's not block this PR on that -- renames are welcome later.

There are a host of other changes that were required to make this possible:
* Expose a `ConstTy` trait to get the `Interner::Ty` from a `Interner::Const`.
* Expose some constructor methods to construct `Bound` variants. These are currently methods defined on the interner themselves, but they could be pulled into traits later.
* Expose a `IntoKind` trait to turn a `Ty`/`Const`/`Region` into their corresponding `*Kind`s.
* Some minor tweaks to other APIs in `rustc_type_ir`.

The canonicalizer code itself is best reviewed **with whitespace ignored.**

r? ``@lcnr``
This commit is contained in:
Matthias Krüger 2023-12-08 23:15:11 +01:00 committed by GitHub
commit 4df6134f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 478 additions and 262 deletions

View File

@ -4303,6 +4303,13 @@ dependencies = [
"tracing",
]
[[package]]
name = "rustc_next_trait_solver"
version = "0.0.0"
dependencies = [
"rustc_type_ir",
]
[[package]]
name = "rustc_parse"
version = "0.0.0"
@ -4571,6 +4578,7 @@ dependencies = [
"rustc_infer",
"rustc_macros",
"rustc_middle",
"rustc_next_trait_solver",
"rustc_parse_format",
"rustc_query_system",
"rustc_session",

View File

@ -345,37 +345,61 @@ pub struct InferCtxt<'tcx> {
impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
type Interner = TyCtxt<'tcx>;
fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
use InferTy::*;
match ty {
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
// ty infers will give you the universe of the var it resolved to not the universe
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
// try to print out `?0.1` it will just print `?0`.
TyVar(ty_vid) => match self.probe_ty_var(ty_vid) {
Err(universe) => Some(universe),
Ok(_) => None,
},
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => None,
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn universe_of_ty(&self, vid: TyVid) -> Option<ty::UniverseIndex> {
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
// ty infers will give you the universe of the var it resolved to not the universe
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
// try to print out `?0.1` it will just print `?0`.
match self.probe_ty_var(vid) {
Err(universe) => Some(universe),
Ok(_) => None,
}
}
fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
use ty::InferConst::*;
match ct {
// Same issue as with `universe_of_ty`
Var(ct_vid) => match self.probe_const_var(ct_vid) {
Err(universe) => Some(universe),
Ok(_) => None,
},
EffectVar(_) => None,
Fresh(_) => None,
fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
// Same issue as with `universe_of_ty`
match self.probe_const_var(ct) {
Err(universe) => Some(universe),
Ok(_) => None,
}
}
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
Some(self.universe_of_region_vid(lt))
}
fn root_ty_var(&self, vid: TyVid) -> TyVid {
self.root_var(vid)
}
fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
self.probe_ty_var(vid).ok()
}
fn root_lt_var(&self, vid: ty::RegionVid) -> ty::RegionVid {
self.root_region_var(vid)
}
fn probe_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
let re = self
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.tcx, vid);
if re.is_var() { None } else { Some(re) }
}
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
self.root_const_var(vid)
}
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
self.probe_const_var(vid).ok()
}
}
/// See the `error_reporting` module for more details.
@ -1347,6 +1371,10 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
pub fn root_region_var(&self, var: ty::RegionVid) -> ty::RegionVid {
self.inner.borrow_mut().unwrap_region_constraints().root_var(var)
}
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
self.inner.borrow_mut().const_unification_table().find(var).vid
}

View File

@ -623,6 +623,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
pub fn root_var(&mut self, vid: ty::RegionVid) -> ty::RegionVid {
let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
ut.find(vid).vid
}
fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
match t {
Glb => &mut self.glbs,

View File

@ -7,7 +7,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_macros::HashStable;
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo};
mod int;
mod kind;
@ -26,6 +26,20 @@ use super::sty::ConstKind;
#[rustc_pass_by_value]
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
impl<'tcx> IntoKind for Const<'tcx> {
type Kind = ConstKind<'tcx>;
fn kind(self) -> ConstKind<'tcx> {
self.kind().clone()
}
}
impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
fn ty(self) -> Ty<'tcx> {
self.ty()
}
}
/// Typed constant value.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
pub struct ConstData<'tcx> {

View File

@ -131,6 +131,31 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
) -> (Self::Ty, ty::Mutability) {
(ty, mutbl)
}
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos)
}
fn mk_bound_ty(self, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self::Ty {
Ty::new_bound(self, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
}
fn mk_bound_region(self, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self::Region {
Region::new_bound(
self,
debruijn,
ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon },
)
}
fn mk_bound_const(
self,
debruijn: ty::DebruijnIndex,
var: ty::BoundVar,
ty: Self::Ty,
) -> Self::Const {
Const::new_bound(self, debruijn, var, ty)
}
}
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;

View File

@ -65,15 +65,10 @@ use std::ops::ControlFlow;
use std::{fmt, str};
pub use crate::ty::diagnostics::*;
pub use rustc_type_ir::AliasKind::*;
pub use rustc_type_ir::ConstKind::{
Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt,
Placeholder as PlaceholderCt, Unevaluated, Value,
};
pub use rustc_type_ir::DynKind::*;
pub use rustc_type_ir::InferTy::*;
pub use rustc_type_ir::RegionKind::*;
pub use rustc_type_ir::TyKind::*;
pub use rustc_type_ir::*;
pub use self::binding::BindingMode;
@ -474,6 +469,14 @@ pub struct CReaderCacheKey {
#[rustc_pass_by_value]
pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
impl<'tcx> IntoKind for Ty<'tcx> {
type Kind = TyKind<'tcx>;
fn kind(self) -> TyKind<'tcx> {
self.kind().clone()
}
}
impl EarlyParamRegion {
/// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`).
@ -1545,34 +1548,42 @@ pub struct Placeholder<T> {
pub type PlaceholderRegion = Placeholder<BoundRegion>;
impl rustc_type_ir::Placeholder for PlaceholderRegion {
fn universe(&self) -> UniverseIndex {
impl PlaceholderLike for PlaceholderRegion {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(&self) -> BoundVar {
fn var(self) -> BoundVar {
self.bound.var
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::BrAnon } }
}
}
pub type PlaceholderType = Placeholder<BoundTy>;
impl rustc_type_ir::Placeholder for PlaceholderType {
fn universe(&self) -> UniverseIndex {
impl PlaceholderLike for PlaceholderType {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(&self) -> BoundVar {
fn var(self) -> BoundVar {
self.bound.var
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
@ -1584,18 +1595,22 @@ pub struct BoundConst<'tcx> {
pub type PlaceholderConst = Placeholder<BoundVar>;
impl rustc_type_ir::Placeholder for PlaceholderConst {
fn universe(&self) -> UniverseIndex {
impl PlaceholderLike for PlaceholderConst {
fn universe(self) -> UniverseIndex {
self.universe
}
fn var(&self) -> BoundVar {
fn var(self) -> BoundVar {
self.bound
}
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
Placeholder { universe: ui, ..self }
}
fn new(ui: UniverseIndex, var: BoundVar) -> Self {
Placeholder { universe: ui, bound: var }
}
}
/// When type checking, we use the `ParamEnv` to track

View File

@ -6,7 +6,7 @@ use crate::infer::canonical::Canonical;
use crate::ty::visit::ValidateBoundVars;
use crate::ty::InferTy::*;
use crate::ty::{
self, AdtDef, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
self, AdtDef, Discr, IntoKind, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor,
};
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
@ -1477,6 +1477,14 @@ impl ParamConst {
#[rustc_pass_by_value]
pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
impl<'tcx> IntoKind for Region<'tcx> {
type Kind = RegionKind<'tcx>;
fn kind(self) -> RegionKind<'tcx> {
*self
}
}
impl<'tcx> Region<'tcx> {
#[inline]
pub fn new_early_param(

View File

@ -0,0 +1,13 @@
[package]
name = "rustc_next_trait_solver"
version = "0.0.0"
edition = "2021"
[dependencies]
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
[features]
default = ["nightly"]
nightly = [
"rustc_type_ir/nightly",
]

View File

@ -1,17 +1,10 @@
use std::cmp::Ordering;
use crate::infer::InferCtxt;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::infer::canonical::CanonicalTyVarKind;
use rustc_middle::infer::canonical::CanonicalVarInfo;
use rustc_middle::infer::canonical::CanonicalVarInfos;
use rustc_middle::infer::canonical::CanonicalVarKind;
use rustc_middle::ty::BoundRegionKind::BrAnon;
use rustc_middle::ty::BoundTyKind;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::{
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, ConstTy,
InferCtxtLike, Interner, IntoKind, PlaceholderLike,
};
/// Whether we're canonicalizing a query input or the query response.
///
@ -42,23 +35,22 @@ pub enum CanonicalizeMode {
},
}
pub struct Canonicalizer<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
infcx: &'a Infcx,
canonicalize_mode: CanonicalizeMode,
variables: &'a mut Vec<ty::GenericArg<'tcx>>,
primitive_var_infos: Vec<CanonicalVarInfo<'tcx>>,
variables: &'a mut Vec<I::GenericArg>,
primitive_var_infos: Vec<CanonicalVarInfo<I>>,
binder_index: ty::DebruijnIndex,
}
impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
#[instrument(level = "debug", skip(infcx), ret)]
pub fn canonicalize<T: TypeFoldable<TyCtxt<'tcx>>>(
infcx: &'a InferCtxt<'tcx>,
impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> {
pub fn canonicalize<T: TypeFoldable<I>>(
infcx: &'a Infcx,
canonicalize_mode: CanonicalizeMode,
variables: &'a mut Vec<ty::GenericArg<'tcx>>,
variables: &'a mut Vec<I::GenericArg>,
value: T,
) -> Canonical<'tcx, T> {
) -> ty::Canonical<I, T> {
let mut canonicalizer = Canonicalizer {
infcx,
canonicalize_mode,
@ -69,15 +61,16 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
};
let value = value.fold_with(&mut canonicalizer);
assert!(!value.has_infer(), "unexpected infer in {value:?}");
assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
// FIXME: Restore these assertions. Should we uplift type flags?
// assert!(!value.has_infer(), "unexpected infer in {value:?}");
// assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
let (max_universe, variables) = canonicalizer.finalize();
Canonical { max_universe, variables, value }
}
fn finalize(self) -> (ty::UniverseIndex, CanonicalVarInfos<'tcx>) {
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
let mut var_infos = self.primitive_var_infos;
// See the rustc-dev-guide section about how we deal with universes
// during canonicalization in the new solver.
@ -105,7 +98,7 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
.max()
.unwrap_or(ty::UniverseIndex::ROOT);
let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos);
let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos);
return (max_universe, var_infos);
}
}
@ -131,7 +124,7 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
let mut existential_in_new_uv = false;
let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
while let Some(orig_uv) = next_orig_uv.take() {
let mut update_uv = |var: &mut CanonicalVarInfo<'tcx>, orig_uv, is_existential| {
let mut update_uv = |var: &mut CanonicalVarInfo<I>, orig_uv, is_existential| {
let uv = var.universe();
match uv.cmp(&orig_uv) {
Ordering::Less => (), // Already updated
@ -187,19 +180,22 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
}
}
let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos);
let var_infos = self.infcx.interner().mk_canonical_var_infos(&var_infos);
(curr_compressed_uv, var_infos)
}
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
for Canonicalizer<'_, Infcx, I>
{
fn interner(&self) -> I {
self.infcx.interner()
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
where
T: TypeFoldable<TyCtxt<'tcx>>,
T: TypeFoldable<I>,
I::Binder<T>: TypeSuperFoldable<I>,
{
self.binder_index.shift_in(1);
let t = t.super_fold_with(self);
@ -207,21 +203,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
t
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReVar(vid) = *r {
let resolved_region = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid);
assert_eq!(
r, resolved_region,
"region var should have been resolved, {r} -> {resolved_region}"
);
}
let kind = match *r {
fn fold_region(&mut self, r: I::Region) -> I::Region {
let kind = match r.kind() {
ty::ReBound(..) => return r,
// We may encounter `ReStatic` in item signatures or the hidden type
@ -237,9 +220,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
CanonicalizeMode::Response { .. } => return r,
},
ty::ReLateParam(_) | ty::ReEarlyParam(_) => match self.canonicalize_mode {
ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"),
CanonicalizeMode::Response { .. } => {
panic!("unexpected region in response: {r:?}")
}
},
ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
@ -248,20 +233,32 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
CanonicalizeMode::Response { max_input_universe } => {
// If we have a placeholder region inside of a query, it must be from
// a new universe.
if max_input_universe.can_name(placeholder.universe) {
bug!("new placeholder in universe {max_input_universe:?}: {r:?}");
if max_input_universe.can_name(placeholder.universe()) {
panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
}
CanonicalVarKind::PlaceholderRegion(placeholder)
}
},
ty::ReVar(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => {
CanonicalVarKind::Region(self.infcx.universe_of_region(r))
}
},
ty::ReVar(vid) => {
assert_eq!(
self.infcx.root_lt_var(vid),
vid,
"region vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_lt_var(vid),
None,
"region vid should have been resolved fully before canonicalization"
);
match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => {
CanonicalVarKind::Region(self.infcx.universe_of_lt(vid).unwrap())
}
}
}
ty::ReError(_) => return r,
};
@ -271,55 +268,60 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from)
}
};
let var = existing_bound_var.unwrap_or_else(|| {
let var = ty::BoundVar::from(self.variables.len());
self.variables.push(r.into());
self.primitive_var_infos.push(CanonicalVarInfo { kind });
var
});
let br = ty::BoundRegion { var, kind: BrAnon };
ty::Region::new_bound(self.interner(), self.binder_index, br)
self.interner().mk_bound_region(self.binder_index, var)
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
let kind = match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved");
let Err(ui) = self.infcx.probe_ty_var(vid) else {
bug!("ty var should have been resolved: {t}");
};
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui))
}
ty::Infer(ty::IntVar(vid)) => {
assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t);
CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
}
ty::Infer(ty::FloatVar(vid)) => {
assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t);
CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
}
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("fresh var during canonicalization: {t:?}")
}
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
where
I::Ty: TypeSuperFoldable<I>,
{
let kind = match t.kind() {
ty::Infer(i) => match i {
ty::TyVar(vid) => {
assert_eq!(
self.infcx.root_ty_var(vid),
vid,
"ty vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ty_var(vid),
None,
"ty vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Ty(CanonicalTyVarKind::General(
self.infcx
.universe_of_ty(vid)
.unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
))
}
ty::IntVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Int),
ty::FloatVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Float),
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
todo!()
}
},
ty::Placeholder(placeholder) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder {
universe: placeholder.universe,
bound: ty::BoundTy {
var: ty::BoundVar::from_usize(self.variables.len()),
kind: ty::BoundTyKind::Anon,
},
}),
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(PlaceholderLike::new(
placeholder.universe(),
self.variables.len().into(),
)),
CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
},
ty::Param(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder {
universe: ty::UniverseIndex::ROOT,
bound: ty::BoundTy {
var: ty::BoundVar::from_usize(self.variables.len()),
kind: ty::BoundTyKind::Anon,
},
}),
CanonicalizeMode::Response { .. } => bug!("param ty in response: {t:?}"),
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(PlaceholderLike::new(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
)),
CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"),
},
ty::Bool
| ty::Char
@ -354,44 +356,38 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
var
}),
);
let bt = ty::BoundTy { var, kind: BoundTyKind::Anon };
Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
self.interner().mk_bound_ty(self.binder_index, var)
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
fn fold_const(&mut self, c: I::Const) -> I::Const
where
I::Const: TypeSuperFoldable<I>,
{
let kind = match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
assert_eq!(
self.infcx.root_const_var(vid),
vid,
"const var should have been resolved"
);
let Err(ui) = self.infcx.probe_const_var(vid) else {
bug!("const var should have been resolved");
};
// FIXME: we should fold this ty eventually
CanonicalVarKind::Const(ui, c.ty())
}
ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
assert_eq!(
self.infcx.root_effect_var(vid),
vid,
"effect var should have been resolved"
);
let None = self.infcx.probe_effect_var(vid) else {
bug!("effect var should have been resolved");
};
CanonicalVarKind::Effect
}
ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
bug!("fresh var during canonicalization: {c:?}")
ty::ConstKind::Infer(i) => {
// FIXME: we should fold the ty too eventually
match i {
ty::InferConst::Var(vid) => {
assert_eq!(
self.infcx.root_ct_var(vid),
vid,
"region vid should have been resolved fully before canonicalization"
);
assert_eq!(
self.infcx.probe_ct_var(vid),
None,
"region vid should have been resolved fully before canonicalization"
);
CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), c.ty())
}
ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect,
ty::InferConst::Fresh(_) => todo!(),
}
}
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
ty::Placeholder {
universe: placeholder.universe,
bound: ty::BoundVar::from(self.variables.len()),
},
PlaceholderLike::new(placeholder.universe(), self.variables.len().into()),
c.ty(),
),
CanonicalizeMode::Response { .. } => {
@ -400,13 +396,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
},
ty::ConstKind::Param(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst(
ty::Placeholder {
universe: ty::UniverseIndex::ROOT,
bound: ty::BoundVar::from(self.variables.len()),
},
PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()),
c.ty(),
),
CanonicalizeMode::Response { .. } => bug!("param ty in response: {c:?}"),
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
},
ty::ConstKind::Bound(_, _)
| ty::ConstKind::Unevaluated(_)
@ -423,6 +416,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
var
}),
);
ty::Const::new_bound(self.infcx.tcx, self.binder_index, var, c.ty())
self.interner().mk_bound_const(self.binder_index, var, c.ty())
}
}

View File

@ -0,0 +1 @@
pub mod canonicalizer;

View File

@ -15,6 +15,7 @@ rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }

View File

@ -9,7 +9,6 @@
//!
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
use crate::solve::{
inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response,
};
@ -27,6 +26,7 @@ use rustc_middle::traits::solve::{
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
use rustc_span::DUMMY_SP;
use std::iter;
use std::ops::Deref;

View File

@ -30,7 +30,6 @@ use rustc_middle::ty::{
mod alias_relate;
mod assembly;
mod canonicalize;
mod eval_ctxt;
mod fulfill;
pub mod inspect;

View File

@ -4,7 +4,7 @@ use std::ops::ControlFlow;
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::{Interner, Placeholder, UniverseIndex};
use crate::{Interner, PlaceholderLike, UniverseIndex};
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
@ -157,7 +157,7 @@ where
}
impl<I: Interner> CanonicalVarInfo<I> {
pub fn universe(&self) -> UniverseIndex {
pub fn universe(self) -> UniverseIndex {
self.kind.universe()
}
@ -305,11 +305,11 @@ where
}
impl<I: Interner> CanonicalVarKind<I> {
pub fn universe(&self) -> UniverseIndex {
pub fn universe(self) -> UniverseIndex {
match self {
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => *ui,
CanonicalVarKind::Region(ui) => *ui,
CanonicalVarKind::Const(ui, _) => *ui,
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::Const(ui, _) => ui,
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(),
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(),
CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe(),

View File

@ -81,7 +81,7 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
match this.data {
Param(param) => write!(f, "{param:?}"),
Infer(var) => write!(f, "{:?}", &this.wrap(var)),
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
Unevaluated(uv) => {
write!(f, "{:?}", &this.wrap(uv))
@ -146,15 +146,15 @@ impl<I: Interner> DebugWithInfcx<I> for InferConst {
this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
match this.infcx.universe_of_ct(*this.data) {
None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data {
InferConst::Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
InferConst::EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
InferConst::Fresh(_) => {
unreachable!()
}
match *this.data {
InferConst::Var(vid) => match this.infcx.universe_of_ct(vid) {
None => write!(f, "{:?}", this.data),
Some(universe) => write!(f, "?{}_{}c", vid.index(), universe.index()),
},
InferConst::EffectVar(vid) => write!(f, "?{}e", vid.index()),
InferConst::Fresh(_) => {
unreachable!()
}
}
}
}

View File

@ -1,35 +1,50 @@
use crate::{InferConst, InferTy, Interner, UniverseIndex};
use crate::{ConstVid, InferCtxtLike, Interner, TyVid, UniverseIndex};
use core::fmt;
use std::marker::PhantomData;
pub trait InferCtxtLike {
type Interner: Interner;
fn universe_of_ty(&self, ty: InferTy) -> Option<UniverseIndex>;
fn universe_of_lt(
&self,
lt: <Self::Interner as Interner>::InferRegion,
) -> Option<UniverseIndex>;
fn universe_of_ct(&self, ct: InferConst) -> Option<UniverseIndex>;
}
pub struct NoInfcx<I>(PhantomData<I>);
impl<I: Interner> InferCtxtLike for NoInfcx<I> {
type Interner = I;
fn universe_of_ty(&self, _ty: InferTy) -> Option<UniverseIndex> {
fn interner(&self) -> Self::Interner {
unreachable!()
}
fn universe_of_ty(&self, _ty: TyVid) -> Option<UniverseIndex> {
None
}
fn universe_of_ct(&self, _ct: InferConst) -> Option<UniverseIndex> {
fn universe_of_lt(&self, _lt: I::InferRegion) -> Option<UniverseIndex> {
None
}
fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
fn universe_of_ct(&self, _ct: ConstVid) -> Option<UniverseIndex> {
None
}
fn root_ty_var(&self, vid: TyVid) -> TyVid {
vid
}
fn probe_ty_var(&self, _vid: TyVid) -> Option<I::Ty> {
None
}
fn root_lt_var(&self, vid: I::InferRegion) -> I::InferRegion {
vid
}
fn probe_lt_var(&self, _vid: I::InferRegion) -> Option<I::Region> {
None
}
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
vid
}
fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
None
}
}

View File

@ -0,0 +1,40 @@
use crate::{ConstVid, Interner, TyVid, UniverseIndex};
pub trait InferCtxtLike {
type Interner: Interner;
fn interner(&self) -> Self::Interner;
fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
/// Resolve `TyVid` to its root `TyVid`.
fn root_ty_var(&self, vid: TyVid) -> TyVid;
/// Resolve `TyVid` to its inferred type, if it has been equated with a non-infer type.
fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>;
fn universe_of_lt(
&self,
lt: <Self::Interner as Interner>::InferRegion,
) -> Option<UniverseIndex>;
/// Resolve `InferRegion` to its root `InferRegion`.
fn root_lt_var(
&self,
vid: <Self::Interner as Interner>::InferRegion,
) -> <Self::Interner as Interner>::InferRegion;
/// Resolve `InferRegion` to its inferred region, if it has been equated with a non-infer region.
fn probe_lt_var(
&self,
vid: <Self::Interner as Interner>::InferRegion,
) -> Option<<Self::Interner as Interner>::Region>;
fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
/// Resolve `ConstVid` to its root `ConstVid`.
fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
/// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;
}

View File

@ -2,75 +2,113 @@ use smallvec::SmallVec;
use std::fmt::Debug;
use std::hash::Hash;
use crate::{BoundVar, DebugWithInfcx, Mutability, UniverseIndex};
use crate::{
BoundVar, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, Mutability, RegionKind,
TyKind, UniverseIndex,
};
pub trait Interner: Sized {
type DefId: Clone + Debug + Hash + Ord;
type AdtDef: Clone + Debug + Hash + Ord;
type DefId: Copy + Debug + Hash + Ord;
type AdtDef: Copy + Debug + Hash + Ord;
type GenericArgs: Clone
type GenericArgs: Copy
+ DebugWithInfcx<Self>
+ Hash
+ Ord
+ IntoIterator<Item = Self::GenericArg>;
type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord;
type Term: Clone + Debug + Hash + Ord;
type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
type Term: Copy + Debug + Hash + Ord;
type Binder<T>;
type TypeAndMut: Clone + Debug + Hash + Ord;
type CanonicalVars: Clone + Debug + Hash + Eq;
type TypeAndMut: Copy + Debug + Hash + Ord;
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
// Kinds of tys
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
type Tys: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
type ParamTy: Clone + Debug + Hash + Ord;
type BoundTy: Clone + Debug + Hash + Ord;
type PlaceholderTy: Clone + Debug + Hash + Ord + Placeholder;
type Ty: Copy
+ DebugWithInfcx<Self>
+ Hash
+ Ord
+ Into<Self::GenericArg>
+ IntoKind<Kind = TyKind<Self>>;
type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord;
type ParamTy: Copy + Debug + Hash + Ord;
type BoundTy: Copy + Debug + Hash + Ord;
type PlaceholderTy: Copy + Debug + Hash + Ord + PlaceholderLike;
// Things stored inside of tys
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
type BoundExistentialPredicates: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord;
type AllocId: Clone + Debug + Hash + Ord;
type ErrorGuaranteed: Copy + Debug + Hash + Ord;
type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Ord;
type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Ord;
type AllocId: Copy + Debug + Hash + Ord;
// Kinds of consts
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderConst: Clone + Debug + Hash + Ord + Placeholder;
type ParamConst: Clone + Debug + Hash + Ord;
type BoundConst: Clone + Debug + Hash + Ord;
type ValueConst: Clone + Debug + Hash + Ord;
type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
type Const: Copy
+ DebugWithInfcx<Self>
+ Hash
+ Ord
+ Into<Self::GenericArg>
+ IntoKind<Kind = ConstKind<Self>>
+ ConstTy<Self>;
type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike;
type ParamConst: Copy + Debug + Hash + Ord;
type BoundConst: Copy + Debug + Hash + Ord;
type ValueConst: Copy + Debug + Hash + Ord;
type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
// Kinds of regions
type Region: Clone + DebugWithInfcx<Self> + Hash + Ord;
type EarlyParamRegion: Clone + Debug + Hash + Ord;
type BoundRegion: Clone + Debug + Hash + Ord;
type LateParamRegion: Clone + Debug + Hash + Ord;
type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderRegion: Clone + Debug + Hash + Ord + Placeholder;
type Region: Copy
+ DebugWithInfcx<Self>
+ Hash
+ Ord
+ Into<Self::GenericArg>
+ IntoKind<Kind = RegionKind<Self>>;
type EarlyParamRegion: Copy + Debug + Hash + Ord;
type LateParamRegion: Copy + Debug + Hash + Ord;
type BoundRegion: Copy + Debug + Hash + Ord;
type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Ord;
type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike;
// Predicates
type Predicate: Clone + Debug + Hash + Eq;
type TraitPredicate: Clone + Debug + Hash + Eq;
type RegionOutlivesPredicate: Clone + Debug + Hash + Eq;
type TypeOutlivesPredicate: Clone + Debug + Hash + Eq;
type ProjectionPredicate: Clone + Debug + Hash + Eq;
type NormalizesTo: Clone + Debug + Hash + Eq;
type SubtypePredicate: Clone + Debug + Hash + Eq;
type CoercePredicate: Clone + Debug + Hash + Eq;
type ClosureKind: Clone + Debug + Hash + Eq;
type Predicate: Copy + Debug + Hash + Eq;
type TraitPredicate: Copy + Debug + Hash + Eq;
type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
type ProjectionPredicate: Copy + Debug + Hash + Eq;
type NormalizesTo: Copy + Debug + Hash + Eq;
type SubtypePredicate: Copy + Debug + Hash + Eq;
type CoercePredicate: Copy + Debug + Hash + Eq;
type ClosureKind: Copy + Debug + Hash + Eq;
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability);
fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
// FIXME: We should not have all these constructors on `Interner`, but as functions on some trait.
fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty;
fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region;
fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const;
}
/// Common capabilities of placeholder kinds
pub trait Placeholder {
fn universe(&self) -> UniverseIndex;
fn var(&self) -> BoundVar;
pub trait PlaceholderLike {
fn universe(self) -> UniverseIndex;
fn var(self) -> BoundVar;
fn with_updated_universe(self, ui: UniverseIndex) -> Self;
fn new(ui: UniverseIndex, var: BoundVar) -> Self;
}
pub trait IntoKind {
type Kind;
fn kind(self) -> Self::Kind;
}
pub trait ConstTy<I: Interner> {
fn ty(self) -> I::Ty;
}
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`

View File

@ -4,6 +4,7 @@
)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::usage_of_ty_tykind)]
#![cfg_attr(feature = "nightly", allow(internal_features))]
#[cfg(feature = "nightly")]
@ -35,6 +36,7 @@ mod canonical;
mod const_kind;
mod debug;
mod flags;
mod infcx;
mod interner;
mod predicate_kind;
mod region_kind;
@ -43,13 +45,19 @@ pub use canonical::*;
#[cfg(feature = "nightly")]
pub use codec::*;
pub use const_kind::*;
pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
pub use debug::{DebugWithInfcx, WithInfcx};
pub use flags::*;
pub use infcx::InferCtxtLike;
pub use interner::*;
pub use predicate_kind::*;
pub use region_kind::*;
pub use ty_info::*;
pub use ty_kind::*;
pub use AliasKind::*;
pub use DynKind::*;
pub use InferTy::*;
pub use RegionKind::*;
pub use TyKind::*;
rustc_index::newtype_index! {
/// A [De Bruijn index][dbi] is a standard means of representing
@ -337,6 +345,12 @@ impl UniverseIndex {
}
}
impl Default for UniverseIndex {
fn default() -> Self {
Self::ROOT
}
}
rustc_index::newtype_index! {
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
#[encodable]

View File

@ -1,5 +1,3 @@
#![allow(rustc::usage_of_ty_tykind)]
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")]
@ -394,7 +392,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
Float(float) => write!(f, "{float:?}"),
Adt(d, s) => {
write!(f, "{d:?}")?;
let mut s = s.clone().into_iter();
let mut s = s.into_iter();
let first = s.next();
match first {
Some(first) => write!(f, "<{:?}", first)?,
@ -412,7 +410,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
RawPtr(p) => {
let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone());
let (ty, mutbl) = I::ty_and_mut_to_parts(*p);
match mutbl {
Mutability::Mut => write!(f, "*mut "),
Mutability::Not => write!(f, "*const "),
@ -442,7 +440,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
Tuple(t) => {
write!(f, "(")?;
let mut count = 0;
for ty in t.clone() {
for ty in *t {
if count > 0 {
write!(f, ", ")?;
}
@ -820,15 +818,15 @@ impl<I: Interner> DebugWithInfcx<I> for InferTy {
this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
use InferTy::*;
match this.infcx.universe_of_ty(*this.data) {
None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data {
TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => {
unreachable!()
match this.data {
InferTy::TyVar(vid) => {
if let Some(universe) = this.infcx.universe_of_ty(*vid) {
write!(f, "?{}_{}t", vid.index(), universe.index())
} else {
write!(f, "{:?}", this.data)
}
},
}
_ => write!(f, "{:?}", this.data),
}
}
}