Auto merge of #45605 - Nashenas88:derive-newtype, r=nikomatsakis

Add derive and doc comment capabilities to newtype_index macro

This moves `RustcDecodable` and `RustcEncodable` out of the macro definition and into the macro uses. They were conflicting with `CrateNum`'s impls of `serialize::UseSpecializedEncodable` and `serialize::UseSpecializedDecodable`, and now it's not :). `CrateNum` is now defined with the `newtype_index` macro. I also added support for doc comments on constant definitions and allowed a type to remove the pub specification on the tuple param (otherwise a LOT of code would refuse to compile for `CrateNum`). I was getting dozens of errors like this if `CrateNum` was defined as `pub struct CrateNum(pub u32)`:
```
error[E0530]: match bindings cannot shadow tuple structs
   --> src/librustc/dep_graph/dep_node.rs:624:25
    |
63  | use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
    |                   -------- a tuple struct `CrateNum` is imported here
...
624 |     [] MissingLangItems(CrateNum),
    |                         ^^^^^^^^ cannot be named the same as a tuple struct
```

I also cleaned up the formatting of the macro bodies as they were getting impossibly long. Should I go back and fix the matching rules to this style too?

I also want to see what the test results look like because `CrateNum` used to just derive `Debug`, but the `newtype_index` macro has a custom implementation. This might require further pushes.

Feel free to bikeshed on the macro language, I have no preference here.
This commit is contained in:
bors 2017-11-04 10:24:20 +00:00
commit a6885cb853
4 changed files with 252 additions and 53 deletions

View File

@ -16,30 +16,23 @@ use serialize::{self, Encoder, Decoder};
use std::fmt;
use std::u32;
#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)]
pub struct CrateNum(u32);
newtype_index!(CrateNum
{
derive[Debug]
ENCODABLE = custom
impl Idx for CrateNum {
fn new(value: usize) -> Self {
assert!(value < (u32::MAX) as usize);
CrateNum(value as u32)
}
/// Item definitions in the currently-compiled crate would have the CrateNum
/// LOCAL_CRATE in their DefId.
const LOCAL_CRATE = 0,
fn index(self) -> usize {
self.0 as usize
}
}
/// Virtual crate for builtin macros
// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get
// `CrateNum`s.
const BUILTIN_MACROS_CRATE = u32::MAX,
/// Item definitions in the currently-compiled crate would have the CrateNum
/// LOCAL_CRATE in their DefId.
pub const LOCAL_CRATE: CrateNum = CrateNum(0);
/// Virtual crate for builtin macros
// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s.
pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(u32::MAX);
/// A CrateNum value that indicates that something is wrong.
pub const INVALID_CRATE: CrateNum = CrateNum(u32::MAX - 1);
/// A CrateNum value that indicates that something is wrong.
const INVALID_CRATE = u32::MAX - 1,
});
impl CrateNum {
pub fn new(x: usize) -> CrateNum {

View File

@ -158,8 +158,8 @@ pub struct BlockRemainder {
newtype_index!(FirstStatementIndex
{
DEBUG_FORMAT = "{}",
MAX = SCOPE_DATA_REMAINDER_MAX,
pub idx
MAX = SCOPE_DATA_REMAINDER_MAX
});
impl From<ScopeData> for Scope {

View File

@ -1552,6 +1552,7 @@ pub struct Constant<'tcx> {
newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
Value {

View File

@ -45,38 +45,62 @@ macro_rules! newtype_index {
// Use default constants
($name:ident) => (
newtype_index!(
@type[$name]
@max[::std::u32::MAX]
@debug_format["{}"]);
// Leave out derives marker so we can use its absence to ensure it comes first
@type [$name]
@max [::std::u32::MAX]
@debug_format ["{}"]);
);
// Define any constants
($name:ident { $($tokens:tt)+ }) => (
newtype_index!(
@type[$name]
@max[::std::u32::MAX]
@debug_format["{}"]
$($tokens)+);
// Leave out derives marker so we can use its absence to ensure it comes first
@type [$name]
@max [::std::u32::MAX]
@debug_format ["{}"]
$($tokens)+);
);
// ---- private rules ----
// Base case, user-defined constants (if any) have already been defined
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
RustcEncodable, RustcDecodable)]
pub struct $type(pub u32);
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
pub struct $type($($pub)* u32);
impl Idx for $type {
fn new(value: usize) -> Self {
assert!(value < ($max) as usize);
$type(value as u32)
}
fn index(self) -> usize {
self.0 as usize
}
}
newtype_index!(
@handle_debug
@derives [$($derives,)*]
@type [$type]
@debug_format [$debug_format]);
);
// base case for handle_debug where format is custom. No Debug implementation is emitted.
(@handle_debug
@derives [$($_derives:ident,)*]
@type [$type:ident]
@debug_format [custom]) => ();
// base case for handle_debug, no debug overrides found, so use default
(@handle_debug
@derives []
@type [$type:ident]
@debug_format [$debug_format:expr]) => (
impl ::std::fmt::Debug for $type {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(fmt, $debug_format, self.0)
@ -84,38 +108,219 @@ macro_rules! newtype_index {
}
);
// Debug is requested for derive, don't generate any Debug implementation.
(@handle_debug
@derives [Debug, $($derives:ident,)*]
@type [$type:ident]
@debug_format [$debug_format:expr]) => ();
// It's not Debug, so just pop it off the front of the derives stack and check the rest.
(@handle_debug
@derives [$_derive:ident, $($derives:ident,)*]
@type [$type:ident]
@debug_format [$debug_format:expr]) => (
newtype_index!(
@handle_debug
@derives [$($derives,)*]
@type [$type]
@debug_format [$debug_format]);
);
// Handle the case where someone wants to make the internal field public
(@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
pub idx
$($tokens:tt)*) => (
newtype_index!(
@pub [pub]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// The default case is that the internal field is private
(@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
$($tokens:tt)*) => (
newtype_index!(
@pub []
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// Append comma to end of derives list if it's missing
(@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
derive [$($derives:ident),*]
$($tokens:tt)*) => (
newtype_index!(
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
derive [$($derives,)*]
$($tokens)*);
);
// By not including the @derives marker in this list nor in the default args, we can force it
// to come first if it exists. When encodable is custom, just use the derives list as-is.
(@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
derive [$($derives:ident,)+]
ENCODABLE = custom
$($tokens:tt)*) => (
newtype_index!(
@derives [$($derives,)+]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// By not including the @derives marker in this list nor in the default args, we can force it
// to come first if it exists. When encodable isn't custom, add serialization traits by default.
(@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
derive [$($derives:ident,)+]
$($tokens:tt)*) => (
newtype_index!(
@derives [$($derives,)+ RustcDecodable, RustcEncodable,]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// The case where no derives are added, but encodable is overriden. Don't
// derive serialization traits
(@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
ENCODABLE = custom
$($tokens:tt)*) => (
newtype_index!(
@derives []
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// The case where no derives are added, add serialization derives by default
(@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
$($tokens:tt)*) => (
newtype_index!(
@derives [RustcDecodable, RustcEncodable,]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// Rewrite final without comma to one that includes comma
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
$name:ident = $constant:expr) => (
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $name = $constant,);
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
$name:ident = $constant:expr) => (
newtype_index!(
@derives [$($derives,)*]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$name = $constant,);
);
// Rewrite final const without comma to one that includes comma
(@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
const $name:ident = $constant:expr) => (
newtype_index!(@type[$type]
@max[$max]
@debug_format[$debug_format]
const $name = $constant,);
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$_max:expr]
@debug_format [$debug_format:expr]
$(#[doc = $doc:expr])*
const $name:ident = $constant:expr) => (
newtype_index!(
@derives [$($derives,)*]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$(#[doc = $doc])* const $name = $constant,);
);
// Replace existing default for max
(@type[$type:ident] @max[$_max:expr] @debug_format[$debug_format:expr]
MAX = $max:expr, $($tokens:tt)*) => (
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$_max:expr]
@debug_format [$debug_format:expr]
MAX = $max:expr,
$($tokens:tt)*) => (
newtype_index!(
@derives [$($derives,)*]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// Replace existing default for debug_format
(@type[$type:ident] @max[$max:expr] @debug_format[$_debug_format:expr]
DEBUG_FORMAT = $debug_format:expr, $($tokens:tt)*) => (
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$_debug_format:expr]
DEBUG_FORMAT = $debug_format:expr,
$($tokens:tt)*) => (
newtype_index!(
@derives [$($derives,)*]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
// Assign a user-defined constant (as final param)
(@type[$type:ident] @max[$max:expr] @debug_format[$debug_format:expr]
const $name:ident = $constant:expr, $($tokens:tt)*) => (
// Assign a user-defined constant
(@derives [$($derives:ident,)*]
@pub [$($pub:tt)*]
@type [$type:ident]
@max [$max:expr]
@debug_format [$debug_format:expr]
$(#[doc = $doc:expr])*
const $name:ident = $constant:expr,
$($tokens:tt)*) => (
$(#[doc = $doc])*
pub const $name: $type = $type($constant);
newtype_index!(@type[$type] @max[$max] @debug_format[$debug_format] $($tokens)*);
newtype_index!(
@derives [$($derives,)*]
@pub [$($pub)*]
@type [$type]
@max [$max]
@debug_format [$debug_format]
$($tokens)*);
);
}