Skip to content

Commit 7ed8c6f

Browse files
ssbrcopybara-github
authored andcommitted
Allow for elided lifetimes in an RsTypeKind, so that you can create new reference types / lifetimes that didn't come from C++.
PiperOrigin-RevId: 464612959
1 parent a04bce1 commit 7ed8c6f

File tree

2 files changed

+84
-16
lines changed

2 files changed

+84
-16
lines changed

rs_bindings_from_cc/ir.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -567,11 +567,7 @@ impl From<Record> for Item {
567567
impl<'a> TryFrom<&'a Item> for &'a Rc<Record> {
568568
type Error = arc_anyhow::Error;
569569
fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
570-
if let Item::Record(r) = value {
571-
Ok(r)
572-
} else {
573-
bail!("Not a Record: {:#?}", value)
574-
}
570+
if let Item::Record(r) = value { Ok(r) } else { bail!("Not a Record: {:#?}", value) }
575571
}
576572
}
577573

@@ -601,11 +597,7 @@ impl From<Comment> for Item {
601597
impl<'a> TryFrom<&'a Item> for &'a Rc<Comment> {
602598
type Error = arc_anyhow::Error;
603599
fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
604-
if let Item::Comment(c) = value {
605-
Ok(c)
606-
} else {
607-
bail!("Not a Comment: {:#?}", value)
608-
}
600+
if let Item::Comment(c) = value { Ok(c) } else { bail!("Not a Comment: {:#?}", value) }
609601
}
610602
}
611603

rs_bindings_from_cc/src_code_gen.rs

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,6 +2155,54 @@ impl Mutability {
21552155
}
21562156
}
21572157

2158+
/// Either a known lifetime, or the magic `'_` elided lifetime.
2159+
///
2160+
/// Warning: elided lifetimes are not always valid, and sometimes named
2161+
/// lifetimes are required. In particular, this should never be used for
2162+
/// output lifetimes.
2163+
///
2164+
/// However, because output lifetimes are never elided, a lifetime that only
2165+
/// occurs in a single input position can always be elided.
2166+
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
2167+
pub enum Lifetime {
2168+
Named(LifetimeName),
2169+
Elided,
2170+
}
2171+
2172+
impl Lifetime {
2173+
/// Formats a lifetime for use as a reference lifetime parameter.
2174+
///
2175+
/// In this case, elided lifetimes are empty.
2176+
pub fn format_for_reference(&self) -> TokenStream {
2177+
match self {
2178+
Lifetime::Named(lifetime) => quote! {#lifetime},
2179+
Lifetime::Elided => quote! {},
2180+
}
2181+
}
2182+
2183+
/// Returns a lifetime ID, if this is a non-elided lifetime. Otherwise
2184+
/// returns None.
2185+
pub fn id(&self) -> Option<LifetimeId> {
2186+
match self {
2187+
Lifetime::Named(lifetime) => Some(lifetime.id),
2188+
Lifetime::Elided => None,
2189+
}
2190+
}
2191+
}
2192+
2193+
/// Formats a lifetime for use anywhere.
2194+
///
2195+
/// For the specific context of references, prefer `format_for_reference`, as it
2196+
/// gives a more idiomatic formatting for elided lifetimes.
2197+
impl ToTokens for Lifetime {
2198+
fn to_tokens(&self, tokens: &mut TokenStream) {
2199+
match self {
2200+
Lifetime::Named(named) => named.to_tokens(tokens),
2201+
Lifetime::Elided => tokens.extend(quote! {'_ }),
2202+
}
2203+
}
2204+
}
2205+
21582206
#[derive(Clone, Debug, PartialEq, Eq)]
21592207
enum RsTypeKind {
21602208
Pointer {
@@ -2164,12 +2212,12 @@ enum RsTypeKind {
21642212
Reference {
21652213
referent: Rc<RsTypeKind>,
21662214
mutability: Mutability,
2167-
lifetime: LifetimeName,
2215+
lifetime: Lifetime,
21682216
},
21692217
RvalueReference {
21702218
referent: Rc<RsTypeKind>,
21712219
mutability: Mutability,
2172-
lifetime: LifetimeName,
2220+
lifetime: Lifetime,
21732221
},
21742222
FuncPtr {
21752223
abi: Rc<str>,
@@ -2257,6 +2305,7 @@ impl RsTypeKind {
22572305
pub fn format_mut_ref_as_uninitialized(&self) -> Result<TokenStream> {
22582306
match self {
22592307
RsTypeKind::Reference { referent, lifetime, mutability: Mutability::Mut } => {
2308+
let lifetime = lifetime.format_for_reference();
22602309
Ok(quote! { & #lifetime mut ::std::mem::MaybeUninit< #referent > })
22612310
}
22622311
_ => bail!("Expected reference to format as MaybeUninit, got: {:?}", self),
@@ -2286,7 +2335,7 @@ impl RsTypeKind {
22862335
} => {
22872336
referent = reference_pointee;
22882337
mutability = reference_mutability;
2289-
lifetime = quote! {#reference_lifetime};
2338+
lifetime = reference_lifetime;
22902339
}
22912340
RsTypeKind::Record { .. } => {
22922341
// This case doesn't happen for methods, but is needed for free functions mapped
@@ -2296,6 +2345,7 @@ impl RsTypeKind {
22962345
_ => bail!("Unexpected type of `self` parameter: {:?}", self),
22972346
}
22982347
let mut_ = mutability.format_for_reference();
2348+
let lifetime = lifetime.format_for_reference();
22992349
if mutability == &Mutability::Mut && !referent.is_unpin() {
23002350
// TODO(b/239661934): Add a `use ::std::pin::Pin` to the crate, and use
23012351
// `Pin`.
@@ -2367,8 +2417,8 @@ impl RsTypeKind {
23672417
/// if the same LifetimeId is used in two `type_args`).
23682418
pub fn lifetimes(&self) -> impl Iterator<Item = LifetimeId> + '_ {
23692419
self.dfs_iter().filter_map(|t| match t {
2370-
RsTypeKind::Reference { lifetime, .. } => Some(lifetime.id),
2371-
RsTypeKind::RvalueReference { lifetime, .. } => Some(lifetime.id),
2420+
RsTypeKind::Reference { lifetime, .. } => lifetime.id(),
2421+
RsTypeKind::RvalueReference { lifetime, .. } => lifetime.id(),
23722422
_ => None,
23732423
})
23742424
}
@@ -2397,6 +2447,7 @@ impl ToTokens for RsTypeKind {
23972447
}
23982448
RsTypeKind::Reference { referent, mutability, lifetime } => {
23992449
let mut_ = mutability.format_for_reference();
2450+
let lifetime = lifetime.format_for_reference();
24002451
let reference = quote! {& #lifetime #mut_ #referent};
24012452
if mutability == &Mutability::Mut && !referent.is_unpin() {
24022453
// TODO(b/239661934): Add a `use ::std::pin::Pin` to the crate, and use
@@ -2519,14 +2570,15 @@ fn rs_type_kind(db: &dyn BindingsGenerator, ty: ir::RsType) -> Result<RsTypeKind
25192570
}
25202571
Ok(Rc::new(get_type_args()?.remove(0)))
25212572
};
2522-
let get_lifetime = || -> Result<LifetimeName> {
2573+
let get_lifetime = || -> Result<Lifetime> {
25232574
if ty.lifetime_args.len() != 1 {
25242575
bail!("Missing reference lifetime (need exactly 1 lifetime argument): {:?}", ty);
25252576
}
25262577
let lifetime_id = ty.lifetime_args[0];
25272578
ir.get_lifetime(lifetime_id)
25282579
.ok_or_else(|| anyhow!("no known lifetime with id {lifetime_id:?}"))
25292580
.cloned()
2581+
.map(|lifetime| Lifetime::Named(lifetime))
25302582
};
25312583

25322584
let result = match ty.name.as_deref() {
@@ -6774,4 +6826,28 @@ mod tests {
67746826
);
67756827
Ok(())
67766828
}
6829+
6830+
#[test]
6831+
fn test_lifetime_elision_for_references() {
6832+
let type_args: &[RsTypeKind] = &[];
6833+
let referent = Rc::new(RsTypeKind::Other { name: "T".into(), type_args: type_args.into() });
6834+
let reference = RsTypeKind::Reference {
6835+
referent: referent,
6836+
mutability: Mutability::Const,
6837+
lifetime: Lifetime::Elided,
6838+
};
6839+
assert_rs_matches!(quote! {#reference}, quote! {&T});
6840+
}
6841+
6842+
#[test]
6843+
fn test_lifetime_elision_for_rvalue_references() {
6844+
let type_args: &[RsTypeKind] = &[];
6845+
let referent = Rc::new(RsTypeKind::Other { name: "T".into(), type_args: type_args.into() });
6846+
let reference = RsTypeKind::RvalueReference {
6847+
referent: referent,
6848+
mutability: Mutability::Mut,
6849+
lifetime: Lifetime::Elided,
6850+
};
6851+
assert_rs_matches!(quote! {#reference}, quote! {RvalueReference<'_, T>});
6852+
}
67776853
}

0 commit comments

Comments
 (0)