Builtin derives are hygienic

This commit is contained in:
Lukas Wirth 2024-01-08 10:37:09 +01:00
parent af40101841
commit 7dd9f20ce3
8 changed files with 112 additions and 159 deletions

View file

@ -1,6 +1,5 @@
//! Builtin derives.
use base_db::{CrateOrigin, LangCrateOrigin};
use itertools::izip;
use rustc_hash::FxHashSet;
use span::{MacroCallId, Span};
@ -10,6 +9,7 @@ use tracing::debug;
use crate::{
hygiene::span_with_def_site_ctxt,
name::{AsName, Name},
quote::dollar_crate,
span_map::SpanMapRef,
tt,
};
@ -38,7 +38,7 @@ macro_rules! register_builtin {
let span = db.lookup_intern_macro_call(id).call_site;
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, span, tt, token_map)
expander(span, tt, token_map)
}
fn find_by_name(name: &name::Name) -> Option<Self> {
@ -398,41 +398,13 @@ fn expand_simple_derive(
ExpandResult::ok(expanded)
}
fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId, span: Span) -> tt::TokenTree {
// FIXME: make hygiene works for builtin derive macro
// such that $crate can be used here.
let cg = db.crate_graph();
let krate = db.lookup_intern_macro_call(id).krate;
let tt = if matches!(cg[krate].origin, CrateOrigin::Lang(LangCrateOrigin::Core)) {
cov_mark::hit!(test_copy_expand_in_core);
quote! {span => crate }
} else {
quote! {span => core }
};
tt.token_trees[0].clone()
}
fn copy_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn copy_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::marker::Copy }, |_| quote! {span =>})
}
fn clone_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn clone_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::clone::Clone }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span };
@ -482,14 +454,8 @@ fn and_and(span: Span) -> tt::Subtree {
quote! {span => #and& }
}
fn default_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn default_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::default::Default }, |adt| {
let body = match &adt.shape {
AdtShape::Struct(fields) => {
@ -527,14 +493,8 @@ fn default_expand(
})
}
fn debug_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn debug_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::fmt::Debug }, |adt| {
let for_variant = |name: String, v: &VariantShape| match v {
VariantShape::Struct(fields) => {
@ -605,14 +565,8 @@ fn debug_expand(
})
}
fn hash_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn hash_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::hash::Hash }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here
@ -658,25 +612,13 @@ fn hash_expand(
})
}
fn eq_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>})
}
fn partial_eq_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = find_builtin_crate(db, id, span);
fn partial_eq_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialEq }, |adt| {
if matches!(adt.shape, AdtShape::Union) {
// FIXME: Return expand error here
@ -747,17 +689,11 @@ fn self_and_other_patterns(
(self_patterns, other_patterns)
}
fn ord_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::Ord }, |adt| {
fn compare(
krate: &tt::TokenTree,
krate: &tt::Ident,
left: tt::Subtree,
right: tt::Subtree,
rest: tt::Subtree,
@ -811,17 +747,11 @@ fn ord_expand(
})
}
fn partial_ord_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
span: Span,
tt: &ast::Adt,
tm: SpanMapRef<'_>,
) -> ExpandResult<tt::Subtree> {
let krate = &find_builtin_crate(db, id, span);
fn partial_ord_expand(span: Span, tt: &ast::Adt, tm: SpanMapRef<'_>) -> ExpandResult<tt::Subtree> {
let krate = &dollar_crate(span);
expand_simple_derive(span, tt, tm, quote! {span => #krate::cmp::PartialOrd }, |adt| {
fn compare(
krate: &tt::TokenTree,
krate: &tt::Ident,
left: tt::Subtree,
right: tt::Subtree,
rest: tt::Subtree,

View file

@ -6,16 +6,14 @@ use either::Either;
use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use syntax::{
ast::{self, AstToken},
SmolStr,
};
use syntax::ast::{self, AstToken};
use crate::{
db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name::{self, known},
quote,
quote::dollar_crate,
tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, MacroCallId,
};
@ -205,7 +203,7 @@ fn assert_expand(
) -> ExpandResult<tt::Subtree> {
let call_site_span = span_with_call_site_ctxt(db, span, id);
let args = parse_exprs_with_sep(tt, ',', call_site_span);
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let expanded = match &*args {
[cond, panic_args @ ..] => {
let comma = tt::Subtree {
@ -300,7 +298,7 @@ fn asm_expand(
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
{
let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_krate = dollar_crate(span);
literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
}
_ => break,
@ -345,7 +343,7 @@ fn panic_expand(
tt: &tt::Subtree,
span: Span,
) -> ExpandResult<tt::Subtree> {
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac =
@ -371,7 +369,7 @@ fn unreachable_expand(
tt: &tt::Subtree,
span: Span,
) -> ExpandResult<tt::Subtree> {
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let dollar_crate = dollar_crate(span);
let call_site_span = span_with_call_site_ctxt(db, span, id);
let mac = if use_panic_2021(db, call_site_span) {
@ -763,10 +761,10 @@ fn option_env_expand(
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
}
};
// FIXME: Use `DOLLAR_CRATE` when that works in eager macros.
let dollar_crate = dollar_crate(span);
let expanded = match get_env_inner(db, arg_id, &key) {
None => quote! {span => ::core::option::Option::None::<&str> },
Some(s) => quote! {span => ::core::option::Option::Some(#s) },
None => quote! {span => #dollar_crate::option::Option::None::<&str> },
Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) },
};
ExpandResult::ok(expanded)

View file

@ -4,6 +4,10 @@ use span::Span;
use crate::name::Name;
pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
tt::Ident { text: syntax::SmolStr::new_inline("$crate"), span }
}
// A helper macro quote macro
// FIXME:
// 1. Not all puncts are handled