Accept an associated const, and a braced expression, as an array length
`[u8; { ObjectIdentifier::MAX_SIZE }]` is two things at once: a braced const
expression, which is how rustc's expanded output writes one, and a qualified
path naming an associated const. Both are folded now -- the const under the
flattened `Type_CONST` name the lowering already emits it as.
A lowercase qualifier is a module path rather than a type, and carries no name
of its own, so it is still dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>3ba74c0 parent: 4cebd9c modified
src/lower.rs +1 -1 | @@ -53,7 +53,7 @@ enum OpaqueKey { | ||
| 53 | 53 | Method(String, String), |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | -fn ident(name: &str) -> String { | |
| 56 | +pub(crate) fn ident(name: &str) -> String { | |
| 57 | 57 | if NIM_KEYWORDS.contains(&name) || NIM_SHADOWED.contains(&name) { |
| 58 | 58 | return format!("{name}_r"); |
| 59 | 59 | } |
| @@ -53,7 +53,7 @@ enum OpaqueKey { | |||
| 53 | Method(String, String), | 53 | Method(String, String), |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | -fn ident(name: &str) -> String { | 56 | +pub(crate) fn ident(name: &str) -> String { |
| 57 | if NIM_KEYWORDS.contains(&name) || NIM_SHADOWED.contains(&name) { | 57 | if NIM_KEYWORDS.contains(&name) || NIM_SHADOWED.contains(&name) { |
| 58 | return format!("{name}_r"); | 58 | return format!("{name}_r"); |
| 59 | } | 59 | } |
modified
src/ty.rs +18 -4 | @@ -540,13 +540,27 @@ pub fn const_expr(e: &syn::Expr) -> Result<String, String> { | ||
| 540 | 540 | Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(i), .. }) => Ok(i.base10_digits().to_string()), |
| 541 | 541 | Expr::Paren(p) => Ok(format!("({})", const_expr(&p.expr)?)), |
| 542 | 542 | Expr::Group(g) => const_expr(&g.expr), |
| 543 | + // A braced const expression -- `[u8; { T::MAX_SIZE }]`, which is how | |
| 544 | + // rustc's expanded output writes one. | |
| 545 | + Expr::Block(b) => match b.block.stmts.last() { | |
| 546 | + Some(syn::Stmt::Expr(e, None)) => const_expr(e), | |
| 547 | + _ => Err("empty block in an array length".into()), | |
| 548 | + }, | |
| 543 | 549 | Expr::Path(p) => { |
| 544 | - let seg = p | |
| 545 | - .path | |
| 546 | - .segments | |
| 550 | + let segs: Vec<String> = | |
| 551 | + p.path.segments.iter().map(|s| s.ident.to_string()).collect(); | |
| 552 | + let last = segs | |
| 547 | 553 | .last() |
| 548 | 554 | .ok_or_else(|| "empty path in an array length".to_string())?; |
| 549 | - Ok(seg.ident.to_string()) | |
| 555 | + // `Type::CONST` is an associated const, which the lowering emits | |
| 556 | + // under the flattened name `Type_CONST`. A lowercase qualifier is | |
| 557 | + // a module path instead, and carries no name of its own. | |
| 558 | + if let Some(q) = segs.iter().rev().nth(1) { | |
| 559 | + if q.starts_with(char::is_uppercase) { | |
| 560 | + return Ok(crate::lower::ident(&format!("{q}_{last}"))); | |
| 561 | + } | |
| 562 | + } | |
| 563 | + Ok(last.clone()) | |
| 550 | 564 | } |
| 551 | 565 | Expr::Binary(b) => { |
| 552 | 566 | let op = match b.op { |
| @@ -540,13 +540,27 @@ pub fn const_expr(e: &syn::Expr) -> Result<String, String> { | |||
| 540 | Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(i), .. }) => Ok(i.base10_digits().to_string()), | 540 | Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(i), .. }) => Ok(i.base10_digits().to_string()), |
| 541 | Expr::Paren(p) => Ok(format!("({})", const_expr(&p.expr)?)), | 541 | Expr::Paren(p) => Ok(format!("({})", const_expr(&p.expr)?)), |
| 542 | Expr::Group(g) => const_expr(&g.expr), | 542 | Expr::Group(g) => const_expr(&g.expr), |
| 543 | + // A braced const expression -- `[u8; { T::MAX_SIZE }]`, which is how | ||
| 544 | + // rustc's expanded output writes one. | ||
| 545 | + Expr::Block(b) => match b.block.stmts.last() { | ||
| 546 | + Some(syn::Stmt::Expr(e, None)) => const_expr(e), | ||
| 547 | + _ => Err("empty block in an array length".into()), | ||
| 548 | + }, | ||
| 543 | Expr::Path(p) => { | 549 | Expr::Path(p) => { |
| 544 | - let seg = p | 550 | + let segs: Vec<String> = |
| 545 | - .path | 551 | + p.path.segments.iter().map(|s| s.ident.to_string()).collect(); |
| 546 | - .segments | 552 | + let last = segs |
| 547 | .last() | 553 | .last() |
| 548 | .ok_or_else(|| "empty path in an array length".to_string())?; | 554 | .ok_or_else(|| "empty path in an array length".to_string())?; |
| 549 | - Ok(seg.ident.to_string()) | 555 | + // `Type::CONST` is an associated const, which the lowering emits |
| 556 | + // under the flattened name `Type_CONST`. A lowercase qualifier is | ||
| 557 | + // a module path instead, and carries no name of its own. | ||
| 558 | + if let Some(q) = segs.iter().rev().nth(1) { | ||
| 559 | + if q.starts_with(char::is_uppercase) { | ||
| 560 | + return Ok(crate::lower::ident(&format!("{q}_{last}"))); | ||
| 561 | + } | ||
| 562 | + } | ||
| 563 | + Ok(last.clone()) | ||
| 550 | } | 564 | } |
| 551 | Expr::Binary(b) => { | 565 | Expr::Binary(b) => { |
| 552 | let op = match b.op { | 566 | let op = match b.op { |
modified
tests/cases/052-const-array-len.rs +11 -0 | @@ -4,6 +4,12 @@ | ||
| 4 | 4 | const BLOCK: usize = 4; |
| 5 | 5 | const DOUBLE: usize = BLOCK * 2; |
| 6 | 6 | |
| 7 | +struct Oid; | |
| 8 | + | |
| 9 | +impl Oid { | |
| 10 | + const MAX_SIZE: usize = 5; | |
| 11 | +} | |
| 12 | + | |
| 7 | 13 | struct Buf { |
| 8 | 14 | data: [u8; BLOCK], |
| 9 | 15 | wide: [u8; DOUBLE], |
| @@ -34,4 +40,9 @@ fn main() { | ||
| 34 | 40 | // get the answer from the same C ABI. |
| 35 | 41 | let w: [u8; core::mem::size_of::<u32>()] = [5u8; core::mem::size_of::<u32>()]; |
| 36 | 42 | println!("{} {}", w.len(), sum(&w)); |
| 43 | + | |
| 44 | + // An associated const as a length, and in the braces rustc's expanded | |
| 45 | + // output writes it with. | |
| 46 | + let q: [u8; { Oid::MAX_SIZE }] = [2u8; Oid::MAX_SIZE]; | |
| 47 | + println!("{} {}", q.len(), sum(&q)); | |
| 37 | 48 | } |
| @@ -4,6 +4,12 @@ | |||
| 4 | const BLOCK: usize = 4; | 4 | const BLOCK: usize = 4; |
| 5 | const DOUBLE: usize = BLOCK * 2; | 5 | const DOUBLE: usize = BLOCK * 2; |
| 6 | 6 | ||
| 7 | +struct Oid; | ||
| 8 | + | ||
| 9 | +impl Oid { | ||
| 10 | + const MAX_SIZE: usize = 5; | ||
| 11 | +} | ||
| 12 | + | ||
| 7 | struct Buf { | 13 | struct Buf { |
| 8 | data: [u8; BLOCK], | 14 | data: [u8; BLOCK], |
| 9 | wide: [u8; DOUBLE], | 15 | wide: [u8; DOUBLE], |
| @@ -34,4 +40,9 @@ fn main() { | |||
| 34 | // get the answer from the same C ABI. | 40 | // get the answer from the same C ABI. |
| 35 | let w: [u8; core::mem::size_of::<u32>()] = [5u8; core::mem::size_of::<u32>()]; | 41 | let w: [u8; core::mem::size_of::<u32>()] = [5u8; core::mem::size_of::<u32>()]; |
| 36 | println!("{} {}", w.len(), sum(&w)); | 42 | println!("{} {}", w.len(), sum(&w)); |
| 43 | + | ||
| 44 | + // An associated const as a length, and in the braces rustc's expanded | ||
| 45 | + // output writes it with. | ||
| 46 | + let q: [u8; { Oid::MAX_SIZE }] = [2u8; Oid::MAX_SIZE]; | ||
| 47 | + println!("{} {}", q.len(), sum(&q)); | ||
| 37 | } | 48 | } |