Remove gensyms from built-in derives

Also make them generally more hygienic with name resolution.
This commit is contained in:
Matthew Jasper 2019-08-11 14:16:12 +01:00
parent 0280e8ffcc
commit 3296d0ed6d
10 changed files with 188 additions and 86 deletions

View File

@ -43,17 +43,18 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt<'_>,
}
pub fn ordering_collapsed(cx: &mut ExtCtxt<'_>,
span: Span,
self_arg_tags: &[ast::Ident])
-> P<ast::Expr> {
pub fn ordering_collapsed(
cx: &mut ExtCtxt<'_>,
span: Span,
self_arg_tags: &[ast::Ident],
) -> P<ast::Expr> {
let lft = cx.expr_ident(span, self_arg_tags[0]);
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt])
cx.expr_method_call(span, lft, ast::Ident::new(sym::cmp, span), vec![rgt])
}
pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
let test_id = cx.ident_of("cmp").gensym();
let test_id = ast::Ident::new(sym::cmp, span);
let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
@ -75,34 +76,34 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
// match new {
// ::std::cmp::Ordering::Equal => old,
// cmp => cmp
// }
// match new {
// ::std::cmp::Ordering::Equal => old,
// cmp => cmp
// }
let new = {
let other_f = match other_fs {
[o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
};
let new = {
let other_f = match other_fs {
[o_f] => o_f,
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
};
let args = vec![
cx.expr_addr_of(span, self_f),
cx.expr_addr_of(span, other_f.clone()),
];
let args = vec![
cx.expr_addr_of(span, self_f),
cx.expr_addr_of(span, other_f.clone()),
];
cx.expr_call_global(span, cmp_path.clone(), args)
};
cx.expr_call_global(span, cmp_path.clone(), args)
};
let eq_arm = cx.arm(span,
vec![cx.pat_path(span, equals_path.clone())],
old);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
cx.expr_ident(span, test_id));
let eq_arm = cx.arm(span,
vec![cx.pat_path(span, equals_path.clone())],
old);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
cx.expr_ident(span, test_id));
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
cx.expr_match(span, new, vec![eq_arm, neq_arm])
},
cx.expr_path(equals_path.clone()),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {

View File

@ -94,11 +94,12 @@ pub enum OrderingOp {
GeOp,
}
pub fn some_ordering_collapsed(cx: &mut ExtCtxt<'_>,
span: Span,
op: OrderingOp,
self_arg_tags: &[ast::Ident])
-> P<ast::Expr> {
pub fn some_ordering_collapsed(
cx: &mut ExtCtxt<'_>,
span: Span,
op: OrderingOp,
self_arg_tags: &[ast::Ident],
) -> P<ast::Expr> {
let lft = cx.expr_ident(span, self_arg_tags[0]);
let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
let op_str = match op {
@ -108,11 +109,11 @@ pub fn some_ordering_collapsed(cx: &mut ExtCtxt<'_>,
GtOp => "gt",
GeOp => "ge",
};
cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt])
cx.expr_method_call(span, lft, ast::Ident::from_str_and_span(op_str, span), vec![rgt])
}
pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
let test_id = cx.ident_of("cmp").gensym();
let test_id = ast::Ident::new(sym::cmp, span);
let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let ordering_expr = cx.expr_path(ordering.clone());
let equals_expr = cx.expr_some(span, ordering_expr);

View File

@ -62,7 +62,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
// We want to make sure we have the ctxt set so that we can use unstable methods
let span = span.with_ctxt(cx.backtrace());
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
let builder = Ident::from_str("debug_trait_builder").gensym();
let builder = Ident::from_str_and_span("debug_trait_builder", span);
let builder_expr = cx.expr_ident(span, builder.clone());
let fmt = substr.nonself_args[0].clone();
@ -73,7 +73,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
// tuple struct/"normal" variant
let expr =
cx.expr_method_call(span, fmt, Ident::from_str("debug_tuple"), vec![name]);
stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
stmts.push(cx.stmt_let(span, true, builder, expr));
for field in fields {
// Use double indirection to make sure this works for unsized types
@ -82,7 +82,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let expr = cx.expr_method_call(span,
builder_expr.clone(),
Ident::with_dummy_span(sym::field),
Ident::new(sym::field, span),
vec![field]);
// Use `let _ = expr;` to avoid triggering the
@ -106,7 +106,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let field = cx.expr_addr_of(field.span, field);
let expr = cx.expr_method_call(span,
builder_expr.clone(),
Ident::with_dummy_span(sym::field),
Ident::new(sym::field, span),
vec![name, field]);
stmts.push(stmt_let_undescore(cx, span, expr));
}

View File

@ -1,6 +1,6 @@
//! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more.
//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more.
use crate::deriving::{self, pathvec_std};
use crate::deriving::pathvec_std;
use crate::deriving::generic::*;
use crate::deriving::generic::ty::*;
@ -17,7 +17,7 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt<'_>,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
let krate = "rustc_serialize";
let typaram = &*deriving::hygienic_type_parameter(item, "__D");
let typaram = "__D";
let trait_def = TraitDef {
span,

View File

@ -1,11 +1,12 @@
//! The compiler code necessary to implement the `#[derive(Encodable)]`
//! (and `Decodable`, in `decodable.rs`) extension. The idea here is that
//! type-defining items may be tagged with `#[derive(Encodable, Decodable)]`.
//! The compiler code necessary to implement the `#[derive(RustcEncodable)]`
//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that
//! type-defining items may be tagged with
//! `#[derive(RustcEncodable, RustcDecodable)]`.
//!
//! For example, a type like:
//!
//! ```
//! #[derive(Encodable, Decodable)]
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Node { id: usize }
//! ```
//!
@ -40,15 +41,17 @@
//! references other non-built-in types. A type definition like:
//!
//! ```
//! # #[derive(Encodable, Decodable)] struct Span;
//! #[derive(Encodable, Decodable)]
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! #[derive(RustcEncodable, RustcDecodable)]
//! struct Spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```
//! # #[derive(Encodable, Decodable)] struct Span;
//! # #[derive(RustcEncodable, RustcDecodable)]
//! # struct Span;
//! # struct Spanned<T> { node: T, span: Span }
//! impl<
//! S: Encoder<E>,
@ -82,7 +85,7 @@
//! }
//! ```
use crate::deriving::{self, pathvec_std};
use crate::deriving::pathvec_std;
use crate::deriving::generic::*;
use crate::deriving::generic::ty::*;
@ -98,7 +101,7 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt<'_>,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable)) {
let krate = "rustc_serialize";
let typaram = &*deriving::hygienic_type_parameter(item, "__S");
let typaram = "__S";
let trait_def = TraitDef {
span,

View File

@ -890,7 +890,7 @@ impl<'a> MethodDef<'a> {
for (ty, name) in self.args.iter() {
let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
let ident = cx.ident_of(name).gensym();
let ident = ast::Ident::from_str_and_span(name, trait_.span);
arg_tys.push((ident, ast_ty));
let arg_expr = cx.expr_ident(trait_.span, ident);
@ -1210,7 +1210,7 @@ impl<'a> MethodDef<'a> {
let vi_idents = self_arg_names.iter()
.map(|name| {
let vi_suffix = format!("{}_vi", &name[..]);
cx.ident_of(&vi_suffix[..]).gensym()
ast::Ident::from_str_and_span(&vi_suffix[..], trait_.span)
})
.collect::<Vec<ast::Ident>>();
@ -1387,7 +1387,10 @@ impl<'a> MethodDef<'a> {
let variant_value =
deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]);
let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
let target_ty = cx.ty_ident(
sp,
ast::Ident::from_str_and_span(target_type_name, sp),
);
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
index_let_stmts.push(let_stmt);
@ -1588,7 +1591,7 @@ impl<'a> TraitDef<'a> {
let mut ident_exprs = Vec::new();
for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = struct_field.span.with_ctxt(self.span.ctxt());
let ident = cx.ident_of(&format!("{}_{}", prefix, i)).gensym();
let ident = ast::Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
paths.push(ident.with_span_pos(sp));
let val = cx.expr_path(cx.path_ident(sp, ident));
let val = if use_temporaries {

View File

@ -72,7 +72,7 @@ impl<'a> Path<'a> {
self_ty: Ident,
self_generics: &Generics)
-> ast::Path {
let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
let mut idents = self.path.iter().map(|s| Ident::from_str_and_span(*s, span)).collect();
let lt = mk_lifetimes(cx, span, &self.lifetime);
let tys: Vec<P<ast::Ty>> =
self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
@ -209,7 +209,7 @@ fn mk_ty_param(cx: &ExtCtxt<'_>,
cx.trait_bound(path)
})
.collect();
cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
cx.typaram(span, ast::Ident::from_str_and_span(name, span), attrs.to_owned(), bounds, None)
}
fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {

View File

@ -16,7 +16,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>,
let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std);
let typaram = &*deriving::hygienic_type_parameter(item, "__H");
let typaram = "__H";
let arg = Path::new_local(typaram);
let hash_trait_def = TraitDef {

View File

@ -54,33 +54,6 @@ impl MultiItemModifier for BuiltinDerive {
}
}
/// Construct a name for the inner type parameter that can't collide with any type parameters of
/// the item. This is achieved by starting with a base and then concatenating the names of all
/// other type parameters.
// FIXME(aburka): use real hygiene when that becomes possible
fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
let mut typaram = String::from(base);
if let Annotatable::Item(ref item) = *item {
match item.node {
ast::ItemKind::Struct(_, ast::Generics { ref params, .. }) |
ast::ItemKind::Enum(_, ast::Generics { ref params, .. }) => {
for param in params {
match param.kind {
ast::GenericParamKind::Type { .. } => {
typaram.push_str(&param.ident.as_str());
}
_ => {}
}
}
}
_ => {}
}
}
typaram
}
/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt<'_>,
span: Span,

View File

@ -0,0 +1,121 @@
// Make sure that built-in derives don't rely on the user not declaring certain
// names to work properly.
// check-pass
#![allow(nonstandard_style)]
#![feature(decl_macro)]
use std::prelude::v1::test as inline;
static f: () = ();
static cmp: () = ();
static other: () = ();
static state: () = ();
static __self_0_0: () = ();
static __self_1_0: () = ();
static __self_vi: () = ();
static __arg_1_0: () = ();
static debug_trait_builder: () = ();
struct isize;
trait i16 {}
trait MethodsInDerives: Sized {
fn debug_tuple(self) {}
fn debug_struct(self) {}
fn field(self) {}
fn finish(self) {}
fn clone(self) {}
fn cmp(self) {}
fn partial_cmp(self) {}
fn eq(self) {}
fn ne(self) {}
fn le(self) {}
fn lt(self) {}
fn ge(self) {}
fn gt(self) {}
fn hash(self) {}
}
trait GenericAny<T, U> {}
impl<S, T, U> GenericAny<T, U> for S {}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum __H { V(i32), }
#[repr(i16)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum W { A, B }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct X<A: GenericAny<A, self::X<i32>>> {
A: A,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct Y<B>(B)
where
B: From<B>;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum Z<C> {
C(C),
B { C: C },
}
// Make sure that we aren't using `self::` in paths, since it doesn't work in
// non-module scopes.
const NON_MODULE: () = {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum __H { V(i32), }
#[repr(i16)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum W { A, B }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct X<A: Fn(A) -> self::X<i32>> {
A: A,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct Y<B>(B)
where
B: From<B>;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum Z<C> {
C(C),
B { C: C },
}
};
macro m() {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum __H { V(i32), }
#[repr(i16)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum W { A, B }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct X<A: GenericAny<A, self::X<i32>>> {
A: A,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
struct Y<B>(B)
where
B: From<B>;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
enum Z<C> {
C(C),
B { C: C },
}
}
m!();
fn main() {}