-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Improve newtype_index macro to handle description and constants consistently #45110
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,9 +402,11 @@ pub enum BorrowKind { | |
/////////////////////////////////////////////////////////////////////////// | ||
// Variables and temps | ||
|
||
newtype_index!(Local, "_"); | ||
|
||
pub const RETURN_POINTER: Local = Local(0); | ||
newtype_index!(Local, | ||
const { | ||
DESCRIPTION = "_", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I don't think I would include newtype_index!(Local {
DESCRIPTION = "_",
RETURN_POINTER = 0,
}); Alternatively, put the newtype_index!(Local {
DESCRIPTION = "_",
const RETURN_POINTER = 0,
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And we could even lowercase the non constants ... newtype_index!(Local {
debug_name = "_",
const RETURN_POINTER = 0,
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we go with something like newtype_index!(Local {
DESCRIPTION = "_",
const RETURN_POINTER = 0,
}); Can we add the restriction that @spastorino I would still keep them all caps since their values don't change. I think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For clarification, the challenge comes in defining the macro expression to parse the entire list. Something like { $($(const)* $idents:ident = $constants:expr),+ } Fails with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Definitely. This is an internal macro, so it doesn't have to be particularly flexible. I'd say make it so that MAX / DEBUG_NAME must come first and in a particular order. (Incidentally, usually when I have to struct macros like this, I have a kind of "consume loop" where it peels off tokens from the front and then recursively calls itself on the remaining tokens. But I guess that's what you were trying to avoid.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Somehow I missed this comment and in the meantime implemented a version that does work and is less lines. It doesn't enforce MAX and DEBUG_NAME coming first, though. Should I still add that restriction in? |
||
RETURN_POINTER = 0, | ||
}); | ||
|
||
/// Classifies locals into categories. See `Mir::local_kind`. | ||
#[derive(PartialEq, Eq, Debug)] | ||
|
@@ -538,7 +540,7 @@ pub struct UpvarDecl { | |
/////////////////////////////////////////////////////////////////////////// | ||
// BasicBlock | ||
|
||
newtype_index!(BasicBlock, "bb"); | ||
newtype_index!(BasicBlock, const { DESCRIPTION = "bb" }); | ||
|
||
/////////////////////////////////////////////////////////////////////////// | ||
// BasicBlockData and Terminator | ||
|
@@ -1118,7 +1120,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx> | |
/// and the index is a local. | ||
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; | ||
|
||
newtype_index!(Field, "field"); | ||
newtype_index!(Field, const { DESCRIPTION = "field" }); | ||
|
||
impl<'tcx> Lvalue<'tcx> { | ||
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> { | ||
|
@@ -1183,8 +1185,11 @@ impl<'tcx> Debug for Lvalue<'tcx> { | |
/////////////////////////////////////////////////////////////////////////// | ||
// Scopes | ||
|
||
newtype_index!(VisibilityScope, "scope"); | ||
pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0); | ||
newtype_index!(VisibilityScope, | ||
const { | ||
DESCRIPTION = "scope", | ||
ARGUMENT_VISIBILITY_SCOPE = 0, | ||
}); | ||
|
||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | ||
pub struct VisibilityScopeData { | ||
|
@@ -1509,7 +1514,7 @@ pub struct Constant<'tcx> { | |
pub literal: Literal<'tcx>, | ||
} | ||
|
||
newtype_index!(Promoted, "promoted"); | ||
newtype_index!(Promoted, const { DESCRIPTION = "promoted" }); | ||
|
||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] | ||
pub enum Literal<'tcx> { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,39 +40,86 @@ impl Idx for u32 { | |
|
||
#[macro_export] | ||
macro_rules! newtype_index { | ||
($name:ident) => ( | ||
newtype_index!($name, unsafe { ::std::intrinsics::type_name::<$name>() }); | ||
); | ||
// ---- private rules ---- | ||
|
||
($name:ident, $debug_name:expr) => ( | ||
// Base case, user-defined constants (if any) have already been defined | ||
(@type[$type:ident] @max[$max:expr] @descr[$descr:expr]) => ( | ||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, | ||
RustcEncodable, RustcDecodable)] | ||
pub struct $name(u32); | ||
|
||
impl $name { | ||
// HACK use for constants | ||
#[allow(unused)] | ||
const fn const_new(x: u32) -> Self { | ||
$name(x) | ||
} | ||
} | ||
RustcEncodable, RustcDecodable)] | ||
pub struct $type(u32); | ||
|
||
impl Idx for $name { | ||
impl Idx for $type { | ||
fn new(value: usize) -> Self { | ||
assert!(value < (::std::u32::MAX) as usize); | ||
$name(value as u32) | ||
assert!(value < ($max) as usize); | ||
$type(value as u32) | ||
} | ||
fn index(self) -> usize { | ||
self.0 as usize | ||
} | ||
} | ||
|
||
impl ::std::fmt::Debug for $name { | ||
impl ::std::fmt::Debug for $type { | ||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||
write!(fmt, "{}{}", $debug_name, self.0) | ||
write!(fmt, "{}{}", $descr, self.0) | ||
} | ||
} | ||
) | ||
); | ||
|
||
// Replace existing default for max (as final param) | ||
(@type[$type:ident] @max[$_max:expr] @descr[$descr:expr] MAX = $max:expr) => ( | ||
newtype_index!(@type[$type] @max[$max] @descr[$descr]); | ||
); | ||
|
||
// Replace existing default for max | ||
(@type[$type:ident] @max[$_max:expr] @descr[$descr:expr] MAX = $max:expr, $($idents:ident = $constants:expr),*) => ( | ||
newtype_index!(@type[$type] @max[$max] @descr[$descr]); | ||
); | ||
|
||
// Replace existing default for description (as final param) | ||
(@type[$type:ident] @max[$max:expr] @descr[$_descr:expr] DESCRIPTION = $descr:expr) => ( | ||
newtype_index!(@type[$type] @max[$max] @descr[$descr]); | ||
); | ||
|
||
// Replace existing default for description | ||
(@type[$type:ident] @max[$max:expr] @descr[$_descr:expr] DESCRIPTION = $descr:expr, $($idents:ident = $constants:expr),*) => ( | ||
newtype_index!(@type[$type] @max[$max] @descr[$descr] $($idents = $constants),*); | ||
); | ||
|
||
// Assign a user-defined constant (as final param) | ||
(@type[$type:ident] @max[$max:expr] @descr[$descr:expr] $name:ident = $constant:expr) => ( | ||
pub const $name: $type = $type($constant); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm making all
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see a need for private constants, personally. We can always change it later I guess. |
||
newtype_index!(@type[$type] @max[$max] @descr[$descr]); | ||
); | ||
|
||
// Assign a user-defined constant | ||
(@type[$type:ident] @max[$max:expr] @descr[$descr:expr] $name:ident = $constant:expr, $($idents:ident = $constants:expr),*) => ( | ||
pub const $name: $type = $type($constant); | ||
newtype_index!(@type[$type] @max[$max] @descr[$descr] $($idents = $constants),*); | ||
); | ||
|
||
// ---- public rules ---- | ||
|
||
// Use default constants | ||
($name:ident) => ( | ||
newtype_index!( | ||
@type[$name] | ||
@max[::std::u32::MAX] | ||
@descr[unsafe {::std::intrinsics::type_name::<$name>() }]); | ||
); | ||
|
||
// Define any constants | ||
($name:ident, const { $($idents:ident = $constants:expr,)+ }) => ( | ||
newtype_index!( | ||
@type[$name] | ||
@max[::std::u32::MAX] | ||
@descr[unsafe {::std::intrinsics::type_name::<$name>() }] | ||
$($idents = $constants),+); | ||
); | ||
|
||
// Rewrite missing trailing comma in const to version with trailing comma | ||
($name:ident, const { $($idents:ident = $constants:expr),+ }) => ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I would prefer to start with the PUBLIC rules. I always find it easier to read top-down -- that is, start from the public starting point, then gradually come to the details. |
||
newtype_index!($name, const { $($idents = $constants,)+ }); | ||
); | ||
} | ||
|
||
#[derive(Clone, PartialEq, Eq)] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikomatsakis this design is based on a conversation I had with @spastorino. So
MAX
andDESCRIPTION
are handled as special cases, but all other items in this block are constant. Did I interpret this correctly or was there some other nuance I missed?