Skip to main content

rustc_builtin_macros/deriving/generic/
ty.rs

1//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
2//! when specifying impls to be derived.
3
4pub(crate) use Ty::*;
5use rustc_ast::{self as ast, GenericArg, GenericParamKind, Generics, TyKind};
6use rustc_expand::base::ExtCtxt;
7use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
8use thin_vec::ThinVec;
9
10/// A path, e.g., `::std::option::Option::<i32>` (global). Has support
11/// for type parameters.
12#[derive(#[automatically_derived]
impl ::core::clone::Clone for Path {
    #[inline]
    fn clone(&self) -> Path {
        Path {
            path: ::core::clone::Clone::clone(&self.path),
            params: ::core::clone::Clone::clone(&self.params),
            kind: ::core::clone::Clone::clone(&self.kind),
        }
    }
}Clone)]
13pub(crate) struct Path {
14    path: Vec<Symbol>,
15    params: Vec<Box<Ty>>,
16    kind: PathKind,
17}
18
19#[derive(#[automatically_derived]
impl ::core::clone::Clone for PathKind {
    #[inline]
    fn clone(&self) -> PathKind {
        match self {
            PathKind::Local => PathKind::Local,
            PathKind::Std => PathKind::Std,
        }
    }
}Clone)]
20pub(crate) enum PathKind {
21    Local,
22    Std,
23}
24
25impl Path {
26    pub(crate) fn new(path: Vec<Symbol>) -> Path {
27        Path::new_(path, Vec::new(), PathKind::Std)
28    }
29    pub(crate) fn new_local(path: Symbol) -> Path {
30        Path::new_(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [path]))vec![path], Vec::new(), PathKind::Local)
31    }
32    pub(crate) fn new_(path: Vec<Symbol>, params: Vec<Box<Ty>>, kind: PathKind) -> Path {
33        Path { path, params, kind }
34    }
35
36    pub(crate) fn to_path(
37        &self,
38        cx: &ExtCtxt<'_>,
39        span: Span,
40        self_ty: Ident,
41        self_generics: &Generics,
42    ) -> ast::Path {
43        let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect::<Vec<_>>();
44        let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
45        let params = tys.map(GenericArg::Type).collect();
46
47        if let PathKind::Std = self.kind {
48            let def_site = cx.with_def_site_ctxt(DUMMY_SP);
49            idents.insert(0, Ident::new(kw::DollarCrate, def_site));
50        }
51        cx.path_all(span, false, idents, params)
52    }
53}
54
55/// A type. Supports pointers, Self, literals, unit or an arbitrary AST path.
56#[derive(#[automatically_derived]
impl ::core::clone::Clone for Ty {
    #[inline]
    fn clone(&self) -> Ty {
        match self {
            Ty::Self_ => Ty::Self_,
            Ty::Ref(__self_0, __self_1) =>
                Ty::Ref(::core::clone::Clone::clone(__self_0),
                    ::core::clone::Clone::clone(__self_1)),
            Ty::Path(__self_0) =>
                Ty::Path(::core::clone::Clone::clone(__self_0)),
            Ty::Unit => Ty::Unit,
            Ty::AstTy(__self_0) =>
                Ty::AstTy(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone)]
57pub(crate) enum Ty {
58    Self_,
59    /// A reference.
60    Ref(Box<Ty>, ast::Mutability),
61    /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
62    /// parameter, and things like `i32`
63    Path(Path),
64    /// For () return types.
65    Unit,
66    /// An arbitrary type.
67    AstTy(Box<ast::Ty>),
68}
69
70pub(crate) fn self_ref() -> Ty {
71    Ref(Box::new(Self_), ast::Mutability::Not)
72}
73
74impl Ty {
75    pub(crate) fn to_ty(
76        &self,
77        cx: &ExtCtxt<'_>,
78        span: Span,
79        self_ty: Ident,
80        self_generics: &Generics,
81    ) -> Box<ast::Ty> {
82        match self {
83            Ref(ty, mutbl) => {
84                let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
85                cx.ty_ref(span, raw_ty, None, *mutbl)
86            }
87            Path(p) => cx.ty_path(p.to_path(cx, span, self_ty, self_generics)),
88            Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
89            Unit => {
90                let ty = ast::TyKind::Tup(ThinVec::new());
91                cx.ty(span, ty)
92            }
93            AstTy(ty) => ty.clone(),
94        }
95    }
96
97    pub(crate) fn to_path(
98        &self,
99        cx: &ExtCtxt<'_>,
100        span: Span,
101        self_ty: Ident,
102        generics: &Generics,
103    ) -> ast::Path {
104        match self {
105            Self_ => {
106                let params: Vec<_> = generics
107                    .params
108                    .iter()
109                    .map(|param| match param.kind {
110                        GenericParamKind::Lifetime => {
111                            GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
112                        }
113                        GenericParamKind::Type { .. } => {
114                            GenericArg::Type(cx.ty_ident(span, param.ident))
115                        }
116                        GenericParamKind::Const { .. } => {
117                            GenericArg::Const(cx.const_ident(span, param.ident))
118                        }
119                    })
120                    .collect();
121
122                cx.path_all(span, false, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [self_ty]))vec![self_ty], params)
123            }
124            Path(p) => p.to_path(cx, span, self_ty, generics),
125            AstTy(ty) => match &ty.kind {
126                TyKind::Path(_, path) => path.clone(),
127                _ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"),
128            },
129            Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
130            Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
131        }
132    }
133}
134
135fn mk_ty_param(
136    cx: &ExtCtxt<'_>,
137    span: Span,
138    name: Symbol,
139    bounds: &[Path],
140    self_ident: Ident,
141    self_generics: &Generics,
142) -> ast::GenericParam {
143    let bounds = bounds
144        .iter()
145        .map(|b| {
146            let path = b.to_path(cx, span, self_ident, self_generics);
147            cx.trait_bound(path, false)
148        })
149        .collect();
150    cx.typaram(span, Ident::new(name, span), bounds, None)
151}
152
153/// Bounds on type parameters.
154#[derive(#[automatically_derived]
impl ::core::clone::Clone for Bounds {
    #[inline]
    fn clone(&self) -> Bounds {
        Bounds { bounds: ::core::clone::Clone::clone(&self.bounds) }
    }
}Clone)]
155pub(crate) struct Bounds {
156    pub bounds: Vec<(Symbol, Vec<Path>)>,
157}
158
159impl Bounds {
160    pub(crate) fn empty() -> Bounds {
161        Bounds { bounds: Vec::new() }
162    }
163    pub(crate) fn to_generics(
164        &self,
165        cx: &ExtCtxt<'_>,
166        span: Span,
167        self_ty: Ident,
168        self_generics: &Generics,
169    ) -> Generics {
170        let params = self
171            .bounds
172            .iter()
173            .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, bounds, self_ty, self_generics))
174            .collect();
175
176        Generics {
177            params,
178            where_clause: ast::WhereClause {
179                has_where_token: false,
180                predicates: ThinVec::new(),
181                span,
182            },
183            span,
184        }
185    }
186}