2014-12-31 04:25:18 +00:00
|
|
|
//! The compiler code necessary to implement the `#[derive]` extensions.
|
2012-11-20 02:05:50 +00:00
|
|
|
|
2020-04-27 17:56:11 +00:00
|
|
|
use rustc_ast as ast;
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast::ptr::P;
|
2022-06-22 06:34:43 +00:00
|
|
|
use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
|
2020-03-09 17:50:12 +00:00
|
|
|
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
|
2020-04-19 11:00:18 +00:00
|
|
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
2019-12-31 17:15:40 +00:00
|
|
|
use rustc_span::Span;
|
2022-11-22 05:32:08 +00:00
|
|
|
use thin_vec::ThinVec;
|
2014-05-16 07:16:13 +00:00
|
|
|
|
2017-12-06 18:50:55 +00:00
|
|
|
macro path_local($x:ident) {
|
2020-07-14 05:05:26 +00:00
|
|
|
generic::ty::Path::new_local(sym::$x)
|
2014-09-07 20:58:41 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 04:59:39 +00:00
|
|
|
macro pathvec_std($($rest:ident)::+) {{
|
2020-07-14 05:05:26 +00:00
|
|
|
vec![ $( sym::$rest ),+ ]
|
2017-12-06 18:50:55 +00:00
|
|
|
}}
|
2014-09-07 21:57:26 +00:00
|
|
|
|
2017-12-06 18:50:55 +00:00
|
|
|
macro path_std($($x:tt)*) {
|
|
|
|
generic::ty::Path::new( pathvec_std!( $($x)* ) )
|
2014-09-07 21:57:26 +00:00
|
|
|
}
|
|
|
|
|
2014-04-30 09:26:50 +00:00
|
|
|
pub mod bounds;
|
2013-03-28 10:50:10 +00:00
|
|
|
pub mod clone;
|
2015-10-18 16:03:42 +00:00
|
|
|
pub mod debug;
|
2013-04-09 01:53:39 +00:00
|
|
|
pub mod decodable;
|
2013-09-12 04:51:13 +00:00
|
|
|
pub mod default;
|
2013-04-10 23:31:51 +00:00
|
|
|
pub mod encodable;
|
2014-02-22 05:33:23 +00:00
|
|
|
pub mod hash;
|
2012-11-20 02:05:50 +00:00
|
|
|
|
2013-03-30 14:58:05 +00:00
|
|
|
#[path = "cmp/eq.rs"]
|
|
|
|
pub mod eq;
|
|
|
|
#[path = "cmp/ord.rs"]
|
|
|
|
pub mod ord;
|
2015-04-02 16:14:53 +00:00
|
|
|
#[path = "cmp/partial_eq.rs"]
|
|
|
|
pub mod partial_eq;
|
|
|
|
#[path = "cmp/partial_ord.rs"]
|
|
|
|
pub mod partial_ord;
|
2013-03-30 14:58:05 +00:00
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
pub mod generic;
|
|
|
|
|
2022-09-20 11:55:07 +00:00
|
|
|
pub(crate) type BuiltinDeriveFn =
|
|
|
|
fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
|
|
|
|
|
|
|
|
pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
|
2019-06-06 20:21:44 +00:00
|
|
|
|
|
|
|
impl MultiItemModifier for BuiltinDerive {
|
|
|
|
fn expand(
|
|
|
|
&self,
|
|
|
|
ecx: &mut ExtCtxt<'_>,
|
|
|
|
span: Span,
|
|
|
|
meta_item: &MetaItem,
|
|
|
|
item: Annotatable,
|
2022-09-20 11:55:07 +00:00
|
|
|
is_derive_const: bool,
|
2020-03-09 17:50:12 +00:00
|
|
|
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
|
2019-08-21 18:28:22 +00:00
|
|
|
// FIXME: Built-in derives often forget to give spans contexts,
|
|
|
|
// so we are doing it here in a centralized way.
|
|
|
|
let span = ecx.with_def_site_ctxt(span);
|
2019-06-06 20:21:44 +00:00
|
|
|
let mut items = Vec::new();
|
2020-11-23 00:32:39 +00:00
|
|
|
match item {
|
|
|
|
Annotatable::Stmt(stmt) => {
|
|
|
|
if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
|
2022-09-20 11:55:07 +00:00
|
|
|
(self.0)(
|
|
|
|
ecx,
|
|
|
|
span,
|
|
|
|
meta_item,
|
|
|
|
&Annotatable::Item(item),
|
|
|
|
&mut |a| {
|
|
|
|
// Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx'
|
|
|
|
// to the function
|
|
|
|
items.push(Annotatable::Stmt(P(ast::Stmt {
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
kind: ast::StmtKind::Item(a.expect_item()),
|
|
|
|
span,
|
|
|
|
})));
|
|
|
|
},
|
|
|
|
is_derive_const,
|
|
|
|
);
|
2020-11-23 00:32:39 +00:00
|
|
|
} else {
|
|
|
|
unreachable!("should have already errored on non-item statement")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2022-09-20 11:55:07 +00:00
|
|
|
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const);
|
2020-11-23 00:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-09 17:50:12 +00:00
|
|
|
ExpandResult::Ready(items)
|
2019-06-06 20:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 05:31:19 +00:00
|
|
|
/// Constructs an expression that calls an intrinsic
|
2019-02-04 12:49:54 +00:00
|
|
|
fn call_intrinsic(
|
|
|
|
cx: &ExtCtxt<'_>,
|
2019-06-16 21:31:46 +00:00
|
|
|
span: Span,
|
2020-07-08 01:04:10 +00:00
|
|
|
intrinsic: Symbol,
|
2022-11-23 00:55:16 +00:00
|
|
|
args: ThinVec<P<ast::Expr>>,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Expr> {
|
2019-08-21 18:28:22 +00:00
|
|
|
let span = cx.with_def_site_ctxt(span);
|
2020-07-08 01:04:10 +00:00
|
|
|
let path = cx.std_path(&[sym::intrinsics, intrinsic]);
|
2020-10-11 00:00:00 +00:00
|
|
|
cx.expr_call_global(span, path, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs an expression that calls the `unreachable` intrinsic.
|
|
|
|
fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
|
|
|
|
let span = cx.with_def_site_ctxt(span);
|
|
|
|
let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
|
2022-11-23 00:55:16 +00:00
|
|
|
let call = cx.expr_call_global(span, path, ThinVec::new());
|
2016-03-10 05:31:19 +00:00
|
|
|
|
|
|
|
cx.expr_block(P(ast::Block {
|
2016-06-23 09:51:18 +00:00
|
|
|
stmts: vec![cx.stmt_expr(call)],
|
2016-03-10 05:31:19 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
|
2017-08-07 05:54:09 +00:00
|
|
|
span,
|
2020-08-21 21:52:52 +00:00
|
|
|
tokens: None,
|
2021-09-02 18:34:03 +00:00
|
|
|
could_be_bare_literal: false,
|
2016-07-19 17:32:06 +00:00
|
|
|
}))
|
2016-03-10 05:31:19 +00:00
|
|
|
}
|
2019-10-17 08:54:37 +00:00
|
|
|
|
|
|
|
// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
|
|
|
|
// does *not* add `where T: Structural` for parameters `T` in `...`.
|
|
|
|
// (That's the main reason we cannot use TraitDef here.)
|
|
|
|
fn inject_impl_of_structural_trait(
|
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
span: Span,
|
|
|
|
item: &Annotatable,
|
2020-07-14 05:05:26 +00:00
|
|
|
structural_path: generic::ty::Path,
|
2019-10-17 08:54:37 +00:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
|
|
|
) {
|
2022-12-06 13:22:36 +00:00
|
|
|
let Annotatable::Item(item) = item else {
|
2022-02-18 23:48:49 +00:00
|
|
|
unreachable!();
|
2019-10-17 08:54:37 +00:00
|
|
|
};
|
|
|
|
|
2022-12-06 13:22:36 +00:00
|
|
|
let generics = match &item.kind {
|
|
|
|
ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
|
2019-10-17 08:54:37 +00:00
|
|
|
// Do not inject `impl Structural for Union`. (`PartialEq` does not
|
|
|
|
// support unions, so we will see error downstream.)
|
|
|
|
ItemKind::Union(..) => return,
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Create generics param list for where clauses and impl headers
|
|
|
|
let mut generics = generics.clone();
|
|
|
|
|
2022-10-15 14:33:20 +00:00
|
|
|
let ctxt = span.ctxt();
|
|
|
|
|
2019-10-17 08:54:37 +00:00
|
|
|
// Create the type of `self`.
|
|
|
|
//
|
2022-02-05 09:45:50 +00:00
|
|
|
// in addition, remove defaults from generic params (impls cannot have them).
|
2019-10-17 08:54:37 +00:00
|
|
|
let self_params: Vec<_> = generics
|
|
|
|
.params
|
|
|
|
.iter_mut()
|
|
|
|
.map(|param| match &mut param.kind {
|
2022-10-15 14:33:20 +00:00
|
|
|
ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
|
|
|
|
cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
|
|
|
|
),
|
2019-10-17 08:54:37 +00:00
|
|
|
ast::GenericParamKind::Type { default } => {
|
|
|
|
*default = None;
|
2022-10-15 14:33:20 +00:00
|
|
|
ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
2019-10-17 08:54:37 +00:00
|
|
|
}
|
2020-12-31 00:58:27 +00:00
|
|
|
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
|
|
|
|
*default = None;
|
2022-10-15 14:33:20 +00:00
|
|
|
ast::GenericArg::Const(
|
|
|
|
cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
|
|
|
|
)
|
2019-10-17 08:54:37 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let type_ident = item.ident;
|
|
|
|
|
|
|
|
let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
|
|
|
|
let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
|
|
|
|
|
|
|
|
// It would be nice to also encode constraint `where Self: Eq` (by adding it
|
|
|
|
// onto `generics` cloned above). Unfortunately, that strategy runs afoul of
|
|
|
|
// rust-lang/rust#48214. So we perform that additional check in the compiler
|
|
|
|
// itself, instead of encoding it here.
|
|
|
|
|
|
|
|
// Keep the lint and stability attributes of the original item, to control
|
|
|
|
// how the generated implementation is linted.
|
2022-08-17 02:34:33 +00:00
|
|
|
let mut attrs = ast::AttrVec::new();
|
2019-10-17 08:54:37 +00:00
|
|
|
attrs.extend(
|
|
|
|
item.attrs
|
|
|
|
.iter()
|
|
|
|
.filter(|a| {
|
|
|
|
[sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
|
|
|
|
.contains(&a.name_or_empty())
|
|
|
|
})
|
|
|
|
.cloned(),
|
|
|
|
);
|
2022-10-15 14:33:20 +00:00
|
|
|
// Mark as `automatically_derived` to avoid some silly lints.
|
Avoid more `MetaItem`-to-`Attribute` conversions.
There is code for converting `Attribute` (syntactic) to `MetaItem`
(semantic). There is also code for the reverse direction. The reverse
direction isn't really necessary; it's currently only used when
generating attributes, e.g. in `derive` code.
This commit adds some new functions for creating `Attributes`s directly,
without involving `MetaItem`s: `mk_attr_word`, `mk_attr_name_value_str`,
`mk_attr_nested_word`, and
`ExtCtxt::attr_{word,name_value_str,nested_word}`.
These new methods replace the old functions for creating `Attribute`s:
`mk_attr_inner`, `mk_attr_outer`, and `ExtCtxt::attribute`. Those
functions took `MetaItem`s as input, and relied on many other functions
that created `MetaItems`, which are also removed: `mk_name_value_item`,
`mk_list_item`, `mk_word_item`, `mk_nested_word_item`,
`{MetaItem,MetaItemKind,NestedMetaItem}::token_trees`,
`MetaItemKind::attr_args`, `MetaItemLit::{from_lit_kind,to_token}`,
`ExtCtxt::meta_word`.
Overall this cuts more than 100 lines of code and makes thing simpler.
2022-11-29 07:43:44 +00:00
|
|
|
attrs.push(cx.attr_word(sym::automatically_derived, span));
|
2019-12-22 22:42:04 +00:00
|
|
|
|
2019-10-17 08:54:37 +00:00
|
|
|
let newitem = cx.item(
|
|
|
|
span,
|
2021-10-17 20:20:30 +00:00
|
|
|
Ident::empty(),
|
2019-10-17 08:54:37 +00:00
|
|
|
attrs,
|
2021-11-07 08:43:49 +00:00
|
|
|
ItemKind::Impl(Box::new(Impl {
|
2020-01-30 01:42:33 +00:00
|
|
|
unsafety: ast::Unsafe::No,
|
2020-01-14 04:30:20 +00:00
|
|
|
polarity: ast::ImplPolarity::Positive,
|
|
|
|
defaultness: ast::Defaultness::Final,
|
2020-01-30 01:42:33 +00:00
|
|
|
constness: ast::Const::No,
|
2019-10-17 08:54:37 +00:00
|
|
|
generics,
|
2020-01-14 04:30:20 +00:00
|
|
|
of_trait: Some(trait_ref),
|
|
|
|
self_ty: self_type,
|
2022-11-22 05:32:08 +00:00
|
|
|
items: ThinVec::new(),
|
2021-08-05 01:53:21 +00:00
|
|
|
})),
|
2019-10-17 08:54:37 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
push(Annotatable::Item(newitem));
|
|
|
|
}
|
2022-06-22 06:34:43 +00:00
|
|
|
|
|
|
|
fn assert_ty_bounds(
|
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
stmts: &mut Vec<ast::Stmt>,
|
|
|
|
ty: P<ast::Ty>,
|
|
|
|
span: Span,
|
|
|
|
assert_path: &[Symbol],
|
|
|
|
) {
|
|
|
|
// Generate statement `let _: assert_path<ty>;`.
|
|
|
|
let span = cx.with_def_site_ctxt(span);
|
|
|
|
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
|
|
|
|
stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path)));
|
|
|
|
}
|