Make it possible to derive Lift/TypeVisitable/TypeFoldable in rustc_type_ir

This commit is contained in:
Michael Goulet 2024-05-10 20:30:24 -04:00
parent 78a7751270
commit d5797e938a
10 changed files with 218 additions and 331 deletions

View File

@ -4837,9 +4837,20 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"rustc_type_ir_macros",
"smallvec",
]
[[package]]
name = "rustc_type_ir_macros"
version = "0.0.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.62",
"synstructure",
]
[[package]]
name = "rustc_version"
version = "0.4.0"

View File

@ -11,6 +11,7 @@ rustc_ast_ir = { path = "../rustc_ast_ir" }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
rustc_serialize = { path = "../rustc_serialize", optional = true }
rustc_span = { path = "../rustc_span", optional = true }
smallvec = { version = "1.8.1" }

View File

@ -1,20 +1,25 @@
use rustc_ast_ir::try_visit;
use rustc_ast_ir::visit::VisitorResult;
#[cfg(feature = "nightly")]
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt;
use std::hash::Hash;
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::inherent::*;
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::{Interner, UniverseIndex};
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))]
#[derivative(
Clone(bound = "V: Clone"),
Hash(bound = "V: Hash"),
PartialEq(bound = "V: PartialEq"),
Eq(bound = "V: Eq"),
Debug(bound = "V: fmt::Debug"),
Copy(bound = "V: Copy")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub struct Canonical<I: Interner, V> {
pub value: V,
@ -64,18 +69,6 @@ impl<I: Interner, V> Canonical<I, V> {
}
}
impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
fn eq(&self, other: &Self) -> bool {
let Self { value, max_universe, variables, defining_opaque_types } = self;
*value == other.value
&& *max_universe == other.max_universe
&& *variables == other.variables
&& *defining_opaque_types == other.defining_opaque_types
}
}
impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { value, max_universe, variables, defining_opaque_types } = self;
@ -86,84 +79,25 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
}
}
impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { value, max_universe, variables, defining_opaque_types } = self;
f.debug_struct("Canonical")
.field("value", &value)
.field("max_universe", &max_universe)
.field("variables", &variables)
.field("defining_opaque_types", &defining_opaque_types)
.finish()
}
}
impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
where
I::CanonicalVars: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(Canonical {
value: self.value.try_fold_with(folder)?,
max_universe: self.max_universe.try_fold_with(folder)?,
variables: self.variables.try_fold_with(folder)?,
defining_opaque_types: self.defining_opaque_types,
})
}
}
impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
where
I::CanonicalVars: TypeVisitable<I>,
{
fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> F::Result {
let Self { value, max_universe, variables, defining_opaque_types } = self;
try_visit!(value.visit_with(folder));
try_visit!(max_universe.visit_with(folder));
try_visit!(defining_opaque_types.visit_with(folder));
variables.visit_with(folder)
}
}
/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
Debug(bound = ""),
Eq(bound = ""),
PartialEq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct CanonicalVarInfo<I: Interner> {
pub kind: CanonicalVarKind<I>,
}
impl<I: Interner> PartialEq for CanonicalVarInfo<I> {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl<I: Interner> Eq for CanonicalVarInfo<I> {}
impl<I: Interner> TypeVisitable<I> for CanonicalVarInfo<I>
where
I::Ty: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
self.kind.visit_with(visitor)
}
}
impl<I: Interner> TypeFoldable<I> for CanonicalVarInfo<I>
where
I::Ty: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(CanonicalVarInfo { kind: self.kind.try_fold_with(folder)? })
}
}
impl<I: Interner> CanonicalVarInfo<I> {
pub fn universe(self) -> UniverseIndex {
self.kind.universe()
@ -216,6 +150,7 @@ impl<I: Interner> CanonicalVarInfo<I> {
/// that analyzes type-like values.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum CanonicalVarKind<I: Interner> {
/// Some kind of type inference variable.
@ -258,51 +193,6 @@ impl<I: Interner> PartialEq for CanonicalVarKind<I> {
}
}
impl<I: Interner> Eq for CanonicalVarKind<I> {}
impl<I: Interner> TypeVisitable<I> for CanonicalVarKind<I>
where
I::Ty: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
match self {
CanonicalVarKind::Ty(_)
| CanonicalVarKind::PlaceholderTy(_)
| CanonicalVarKind::Region(_)
| CanonicalVarKind::PlaceholderRegion(_)
| CanonicalVarKind::Effect => V::Result::output(),
CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => {
ty.visit_with(visitor)
}
}
}
}
impl<I: Interner> TypeFoldable<I> for CanonicalVarKind<I>
where
I::Ty: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(match self {
CanonicalVarKind::Ty(kind) => CanonicalVarKind::Ty(kind),
CanonicalVarKind::Region(kind) => CanonicalVarKind::Region(kind),
CanonicalVarKind::Const(kind, ty) => {
CanonicalVarKind::Const(kind, ty.try_fold_with(folder)?)
}
CanonicalVarKind::PlaceholderTy(placeholder) => {
CanonicalVarKind::PlaceholderTy(placeholder)
}
CanonicalVarKind::PlaceholderRegion(placeholder) => {
CanonicalVarKind::PlaceholderRegion(placeholder)
}
CanonicalVarKind::PlaceholderConst(placeholder, ty) => {
CanonicalVarKind::PlaceholderConst(placeholder, ty.try_fold_with(folder)?)
}
CanonicalVarKind::Effect => CanonicalVarKind::Effect,
})
}
}
impl<I: Interner> CanonicalVarKind<I> {
pub fn universe(self) -> UniverseIndex {
match self {
@ -355,6 +245,7 @@ impl<I: Interner> CanonicalVarKind<I> {
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.

View File

@ -10,7 +10,7 @@ use self::ConstKind::*;
/// Represents a constant in Rust.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum ConstKind<I: Interner> {
/// A const generic parameter.
@ -58,8 +58,6 @@ impl<I: Interner> PartialEq for ConstKind<I> {
}
}
impl<I: Interner> Eq for ConstKind<I> {}
impl<I: Interner> fmt::Debug for ConstKind<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
WithInfcx::with_no_infcx(self).fmt(f)

View File

@ -1,17 +1,15 @@
use rustc_ast_ir::try_visit;
use rustc_ast_ir::visit::VisitorResult;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt;
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::Interner;
/// A clause is something that can appear in where bounds or be inferred
/// by implied bounds.
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum ClauseKind<I: Interner> {
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
@ -55,61 +53,6 @@ impl<I: Interner> PartialEq for ClauseKind<I> {
}
}
impl<I: Interner> Eq for ClauseKind<I> {}
impl<I: Interner> TypeFoldable<I> for ClauseKind<I>
where
I::Ty: TypeFoldable<I>,
I::Const: TypeFoldable<I>,
I::GenericArg: TypeFoldable<I>,
I::TraitPredicate: TypeFoldable<I>,
I::ProjectionPredicate: TypeFoldable<I>,
I::TypeOutlivesPredicate: TypeFoldable<I>,
I::RegionOutlivesPredicate: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(match self {
ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?),
ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?),
ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?),
ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?),
ClauseKind::ConstArgHasType(c, t) => {
ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?)
}
ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?),
ClauseKind::ConstEvaluatable(p) => {
ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?)
}
})
}
}
impl<I: Interner> TypeVisitable<I> for ClauseKind<I>
where
I::Ty: TypeVisitable<I>,
I::Const: TypeVisitable<I>,
I::GenericArg: TypeVisitable<I>,
I::TraitPredicate: TypeVisitable<I>,
I::ProjectionPredicate: TypeVisitable<I>,
I::TypeOutlivesPredicate: TypeVisitable<I>,
I::RegionOutlivesPredicate: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
match self {
ClauseKind::Trait(p) => p.visit_with(visitor),
ClauseKind::RegionOutlives(p) => p.visit_with(visitor),
ClauseKind::TypeOutlives(p) => p.visit_with(visitor),
ClauseKind::Projection(p) => p.visit_with(visitor),
ClauseKind::ConstArgHasType(c, t) => {
try_visit!(c.visit_with(visitor));
t.visit_with(visitor)
}
ClauseKind::WellFormed(p) => p.visit_with(visitor),
ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor),
}
}
}
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
@ -118,6 +61,7 @@ where
PartialEq(bound = ""),
Eq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum PredicateKind<I: Interner> {
/// Prove a clause
@ -167,69 +111,6 @@ pub enum PredicateKind<I: Interner> {
AliasRelate(I::Term, I::Term, AliasRelationDirection),
}
impl<I: Interner> TypeFoldable<I> for PredicateKind<I>
where
I::DefId: TypeFoldable<I>,
I::Const: TypeFoldable<I>,
I::GenericArgs: TypeFoldable<I>,
I::Term: TypeFoldable<I>,
I::CoercePredicate: TypeFoldable<I>,
I::SubtypePredicate: TypeFoldable<I>,
I::NormalizesTo: TypeFoldable<I>,
ClauseKind<I>: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(match self {
PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?),
PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?),
PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?),
PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?),
PredicateKind::ConstEquate(a, b) => {
PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?)
}
PredicateKind::Ambiguous => PredicateKind::Ambiguous,
PredicateKind::NormalizesTo(p) => PredicateKind::NormalizesTo(p.try_fold_with(folder)?),
PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate(
a.try_fold_with(folder)?,
b.try_fold_with(folder)?,
d.try_fold_with(folder)?,
),
})
}
}
impl<I: Interner> TypeVisitable<I> for PredicateKind<I>
where
I::DefId: TypeVisitable<I>,
I::Const: TypeVisitable<I>,
I::GenericArgs: TypeVisitable<I>,
I::Term: TypeVisitable<I>,
I::CoercePredicate: TypeVisitable<I>,
I::SubtypePredicate: TypeVisitable<I>,
I::NormalizesTo: TypeVisitable<I>,
ClauseKind<I>: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
match self {
PredicateKind::Clause(p) => p.visit_with(visitor),
PredicateKind::ObjectSafe(d) => d.visit_with(visitor),
PredicateKind::Subtype(s) => s.visit_with(visitor),
PredicateKind::Coerce(s) => s.visit_with(visitor),
PredicateKind::ConstEquate(a, b) => {
try_visit!(a.visit_with(visitor));
b.visit_with(visitor)
}
PredicateKind::Ambiguous => V::Result::output(),
PredicateKind::NormalizesTo(p) => p.visit_with(visitor),
PredicateKind::AliasRelate(a, b, d) => {
try_visit!(a.visit_with(visitor));
try_visit!(b.visit_with(visitor));
d.visit_with(visitor)
}
}
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, Encodable, Decodable))]
pub enum AliasRelationDirection {

View File

@ -115,7 +115,7 @@ use self::RegionKind::*;
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
pub enum RegionKind<I: Interner> {
/// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
@ -208,9 +208,6 @@ impl<I: Interner> PartialEq for RegionKind<I> {
}
}
// This is manually implemented because a derive would require `I: Eq`
impl<I: Interner> Eq for RegionKind<I> {}
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,

View File

@ -1,9 +1,7 @@
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::inherent::*;
use crate::lift::Lift;
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::Interner;
/// A complete reference to a trait. These take numerous guises in syntax,
@ -25,6 +23,7 @@ use crate::Interner;
PartialEq(bound = ""),
Eq(bound = "")
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct TraitRef<I: Interner> {
pub def_id: I::DefId,
@ -68,42 +67,3 @@ impl<I: Interner> TraitRef<I> {
self.args.type_at(0)
}
}
// FIXME(compiler-errors): Make this into a `Lift_Generic` impl.
impl<I: Interner, U: Interner> Lift<U> for TraitRef<I>
where
I::DefId: Lift<U, Lifted = U::DefId>,
I::GenericArgs: Lift<U, Lifted = U::GenericArgs>,
{
type Lifted = TraitRef<U>;
fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
Some(TraitRef {
def_id: self.def_id.lift_to_tcx(tcx)?,
args: self.args.lift_to_tcx(tcx)?,
_use_trait_ref_new_instead: (),
})
}
}
impl<I: Interner> TypeVisitable<I> for TraitRef<I>
where
I::GenericArgs: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
self.args.visit_with(visitor)
}
}
impl<I: Interner> TypeFoldable<I> for TraitRef<I>
where
I::GenericArgs: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(TraitRef {
def_id: self.def_id,
args: self.args.try_fold_with(folder)?,
_use_trait_ref_new_instead: (),
})
}
}

View File

@ -1,14 +1,12 @@
use rustc_ast_ir::try_visit;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")]
use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use std::fmt;
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::Interner;
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
@ -65,7 +63,7 @@ impl AliasKind {
/// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
#[derive(derivative::Derivative)]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum TyKind<I: Interner> {
/// The primitive boolean type. Written as `bool`.
@ -341,9 +339,6 @@ impl<I: Interner> PartialEq for TyKind<I> {
}
}
// This is manually implemented because a derive would require `I: Eq`
impl<I: Interner> Eq for TyKind<I> {}
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: WithInfcx<'_, Infcx, &Self>,
@ -804,29 +799,8 @@ impl<I: Interner> DebugWithInfcx<I> for InferTy {
Debug(bound = "")
)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
pub struct TypeAndMut<I: Interner> {
pub ty: I::Ty,
pub mutbl: Mutability,
}
impl<I: Interner> TypeFoldable<I> for TypeAndMut<I>
where
I::Ty: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(TypeAndMut {
ty: self.ty.try_fold_with(folder)?,
mutbl: self.mutbl.try_fold_with(folder)?,
})
}
}
impl<I: Interner> TypeVisitable<I> for TypeAndMut<I>
where
I::Ty: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
try_visit!(self.ty.visit_with(visitor));
self.mutbl.visit_with(visitor)
}
}

View File

@ -0,0 +1,15 @@
[package]
name = "rustc_type_ir_macros"
version = "0.0.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
# tidy-alphabetical-start
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0.9", features = ["full"] }
synstructure = "0.13.0"
# tidy-alphabetical-end

View File

@ -0,0 +1,159 @@
use synstructure::decl_derive;
use quote::quote;
use syn::{parse_quote, visit_mut::VisitMut};
decl_derive!(
[TypeFoldable_Generic] => type_foldable_derive
);
decl_derive!(
[TypeVisitable_Generic] => type_visitable_derive
);
decl_derive!(
[Lift_Generic] => lift_derive
);
fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
panic!("cannot derive on union")
}
if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
s.add_impl_generic(parse_quote! { I });
}
s.add_where_predicate(parse_quote! { I: Interner });
s.add_bounds(synstructure::AddBounds::Fields);
s.bind_with(|_| synstructure::BindStyle::Move);
let body_fold = s.each_variant(|vi| {
let bindings = vi.bindings();
vi.construct(|_, index| {
let bind = &bindings[index];
quote! {
::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)?
}
})
});
s.bound_impl(
quote!(::rustc_type_ir::fold::TypeFoldable<I>),
quote! {
fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder<I>>(
self,
__folder: &mut __F
) -> Result<Self, __F::Error> {
Ok(match self { #body_fold })
}
},
)
}
fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
panic!("cannot derive on union")
}
if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
s.add_impl_generic(parse_quote! { I });
}
s.add_bounds(synstructure::AddBounds::None);
s.add_where_predicate(parse_quote! { I: Interner });
s.add_impl_generic(parse_quote! { J });
s.add_where_predicate(parse_quote! { J: Interner });
let mut wc = vec![];
s.bind_with(|_| synstructure::BindStyle::Move);
let body_fold = s.each_variant(|vi| {
let bindings = vi.bindings();
vi.construct(|field, index| {
let ty = field.ty.clone();
let lifted_ty = lift(ty.clone());
wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift<J, Lifted = #lifted_ty> });
let bind = &bindings[index];
quote! {
#bind.lift_to_tcx(interner)?
}
})
});
for wc in wc {
s.add_where_predicate(wc);
}
let (_, ty_generics, _) = s.ast().generics.split_for_impl();
let name = s.ast().ident.clone();
let self_ty: syn::Type = parse_quote! { #name #ty_generics };
let lifted_ty = lift(self_ty);
s.bound_impl(
quote!(::rustc_type_ir::lift::Lift<J>),
quote! {
type Lifted = #lifted_ty;
fn lift_to_tcx(
self,
interner: J,
) -> Option<Self::Lifted> {
Some(match self { #body_fold })
}
},
)
}
fn lift(mut ty: syn::Type) -> syn::Type {
struct ItoJ;
impl VisitMut for ItoJ {
fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) {
if i.qself.is_none() {
if let Some(first) = i.path.segments.first_mut() {
if first.ident == "I" {
*first = parse_quote! { J };
}
}
}
syn::visit_mut::visit_type_path_mut(self, i);
}
}
ItoJ.visit_type_mut(&mut ty);
ty
}
fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
panic!("cannot derive on union")
}
if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
s.add_impl_generic(parse_quote! { I });
}
s.add_where_predicate(parse_quote! { I: Interner });
s.add_bounds(synstructure::AddBounds::Fields);
let body_visit = s.each(|bind| {
quote! {
match ::rustc_ast_ir::visit::VisitorResult::branch(
::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor)
) {
::core::ops::ControlFlow::Continue(()) => {},
::core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
},
}
}
});
s.bind_with(|_| synstructure::BindStyle::Move);
s.bound_impl(
quote!(::rustc_type_ir::visit::TypeVisitable<I>),
quote! {
fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>(
&self,
__visitor: &mut __V
) -> __V::Result {
match *self { #body_visit }
<__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output()
}
},
)
}