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, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind};
6use rustc_expand::base::ExtCtxt;
7use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan};
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_ty(
37        &self,
38        cx: &ExtCtxt<'_>,
39        span: Span,
40        self_ty: Ident,
41        self_generics: &Generics,
42    ) -> Box<ast::Ty> {
43        cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
44    }
45    pub(crate) fn to_path(
46        &self,
47        cx: &ExtCtxt<'_>,
48        span: Span,
49        self_ty: Ident,
50        self_generics: &Generics,
51    ) -> ast::Path {
52        let mut idents = self.path.iter().map(|s| Ident::new(*s, span)).collect();
53        let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics));
54        let params = tys.map(GenericArg::Type).collect();
55
56        match self.kind {
57            PathKind::Local => cx.path_all(span, false, idents, params),
58            PathKind::Std => {
59                let def_site = cx.with_def_site_ctxt(DUMMY_SP);
60                idents.insert(0, Ident::new(kw::DollarCrate, def_site));
61                cx.path_all(span, false, idents, params)
62            }
63        }
64    }
65}
66
67/// A type. Supports pointers, Self, literals, unit or an arbitrary AST path.
68#[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)]
69pub(crate) enum Ty {
70    Self_,
71    /// A reference.
72    Ref(Box<Ty>, ast::Mutability),
73    /// `mod::mod::Type<[lifetime], [Params...]>`, including a plain type
74    /// parameter, and things like `i32`
75    Path(Path),
76    /// For () return types.
77    Unit,
78    /// An arbitrary type.
79    AstTy(Box<ast::Ty>),
80}
81
82pub(crate) fn self_ref() -> Ty {
83    Ref(Box::new(Self_), ast::Mutability::Not)
84}
85
86impl Ty {
87    pub(crate) fn to_ty(
88        &self,
89        cx: &ExtCtxt<'_>,
90        span: Span,
91        self_ty: Ident,
92        self_generics: &Generics,
93    ) -> Box<ast::Ty> {
94        match self {
95            Ref(ty, mutbl) => {
96                let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
97                cx.ty_ref(span, raw_ty, None, *mutbl)
98            }
99            Path(p) => p.to_ty(cx, span, self_ty, self_generics),
100            Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
101            Unit => {
102                let ty = ast::TyKind::Tup(ThinVec::new());
103                cx.ty(span, ty)
104            }
105            AstTy(ty) => ty.clone(),
106        }
107    }
108
109    pub(crate) fn to_path(
110        &self,
111        cx: &ExtCtxt<'_>,
112        span: Span,
113        self_ty: Ident,
114        generics: &Generics,
115    ) -> ast::Path {
116        match self {
117            Self_ => {
118                let params: Vec<_> = generics
119                    .params
120                    .iter()
121                    .map(|param| match param.kind {
122                        GenericParamKind::Lifetime { .. } => {
123                            GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
124                        }
125                        GenericParamKind::Type { .. } => {
126                            GenericArg::Type(cx.ty_ident(span, param.ident))
127                        }
128                        GenericParamKind::Const { .. } => {
129                            GenericArg::Const(cx.const_ident(span, param.ident))
130                        }
131                    })
132                    .collect();
133
134                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)
135            }
136            Path(p) => p.to_path(cx, span, self_ty, generics),
137            AstTy(ty) => match &ty.kind {
138                TyKind::Path(_, path) => path.clone(),
139                _ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"),
140            },
141            Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
142            Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
143        }
144    }
145}
146
147fn mk_ty_param(
148    cx: &ExtCtxt<'_>,
149    span: Span,
150    name: Symbol,
151    bounds: &[Path],
152    self_ident: Ident,
153    self_generics: &Generics,
154) -> ast::GenericParam {
155    let bounds = bounds
156        .iter()
157        .map(|b| {
158            let path = b.to_path(cx, span, self_ident, self_generics);
159            cx.trait_bound(path, false)
160        })
161        .collect();
162    cx.typaram(span, Ident::new(name, span), bounds, None)
163}
164
165/// Bounds on type parameters.
166#[derive(#[automatically_derived]
impl ::core::clone::Clone for Bounds {
    #[inline]
    fn clone(&self) -> Bounds {
        Bounds { bounds: ::core::clone::Clone::clone(&self.bounds) }
    }
}Clone)]
167pub(crate) struct Bounds {
168    pub bounds: Vec<(Symbol, Vec<Path>)>,
169}
170
171impl Bounds {
172    pub(crate) fn empty() -> Bounds {
173        Bounds { bounds: Vec::new() }
174    }
175    pub(crate) fn to_generics(
176        &self,
177        cx: &ExtCtxt<'_>,
178        span: Span,
179        self_ty: Ident,
180        self_generics: &Generics,
181    ) -> Generics {
182        let params = self
183            .bounds
184            .iter()
185            .map(|&(name, ref bounds)| mk_ty_param(cx, span, name, bounds, self_ty, self_generics))
186            .collect();
187
188        Generics {
189            params,
190            where_clause: ast::WhereClause {
191                has_where_token: false,
192                predicates: ThinVec::new(),
193                span,
194            },
195            span,
196        }
197    }
198}
199
200pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box<Expr>, ast::ExplicitSelf) {
201    // This constructs a fresh `self` path.
202    let self_path = cx.expr_self(span);
203    let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
204    (self_path, self_ty)
205}