nandi/rustnimpublic Fork
⑂ 8867e55
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Resolve `Self` inside a struct's own declaration

`struct T { data: [u64; if Self::COMPRESS { 0 } else { Self::N * 2 }] }` --
`Self` there names the struct being declared, but `self_ty` was only ever set
inside an `impl`, so the field type could not be mapped.

Which in turn needed the constants declared before the object that uses them,
and `impl T` is written after `struct T`. They get their own pass ahead of the
type definitions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T13:08:24-07:00 Browse files
8867e55 parent: ab0405b
modified src/lower.rs +81 -19
@@ -568,6 +568,17 @@ impl Lowerer {
568568 self.resolve_discriminants()?;
569569 self.resolve_opaque()?;
570570
571+ // Pass 1.9: associated constants, which a type definition may mention.
572+ // `struct T { data: [u64; Self::N] }` is the case -- the constant has
573+ // to be declared before the object that uses it, and `impl T` is
574+ // written after `struct T`.
575+ for (m, f) in files {
576+ self.cur_mod = m.clone();
577+ for item in &f.items {
578+ self.emit_assoc_consts(item)?;
579+ }
580+ }
581+
571582 // Pass 2: type definitions, which every signature may mention.
572583 for (m, f) in files {
573584 self.cur_mod = m.clone();
@@ -790,6 +801,28 @@ impl Lowerer {
790801 }
791802 }
792803
804+ fn collect_struct(&mut self, s: &syn::ItemStruct) -> Result<(), String> {
805+ let g = Self::generics_of(&s.generics);
806+ // The parameters must be in scope while the field types are mapped,
807+ // so that `T` resolves to itself rather than to an unknown named type.
808+ self.type_generics.insert(s.ident.to_string(), g);
809+ let mut fields = Vec::new();
810+ for (i, f) in s.fields.iter().enumerate() {
811+ let name = match &f.ident {
812+ Some(id) => id.to_string(),
813+ None => format!("f{i}"), // tuple struct
814+ };
815+ // A field of `&[T]` / `&str` type is a borrow, and Nim's view
816+ // types allow it as an object field, so it stays a view rather
817+ // than being copied into a `seq`.
818+ let t = self.map_ty(&f.ty)?;
819+ let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() };
820+ fields.push((name, t));
821+ }
822+ self.structs.insert(s.ident.to_string(), fields);
823+ Ok(())
824+ }
825+
793826 fn collect(&mut self, item: &Item) -> Result<(), String> {
794827 // A `#[cfg(..)]` item exists only under some feature set. Dropping it
795828 // silently would change what the program does; picking a feature set
@@ -830,25 +863,15 @@ impl Lowerer {
830863 }
831864 Item::Struct(s) => {
832865 self.note_const_generics(&s.generics)?;
833- let g = Self::generics_of(&s.generics);
834- // The parameters must be in scope while the field types are
835- // mapped, so that `T` resolves to itself rather than to an
836- // unknown named type.
837- self.type_generics.insert(s.ident.to_string(), g);
838- let mut fields = Vec::new();
839- for (i, f) in s.fields.iter().enumerate() {
840- let name = match &f.ident {
841- Some(id) => id.to_string(),
842- None => format!("f{i}"), // tuple struct
843- };
844- // A field of `&[T]` / `&str` type is a borrow, and Nim's
845- // view types allow it as an object field, so it stays a
846- // view rather than being copied into a `seq`.
847- let t = self.map_ty(&f.ty)?;
848- let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() };
849- fields.push((name, t));
850- }
851- self.structs.insert(s.ident.to_string(), fields);
866+ // `Self` inside a struct's own declaration names that struct,
867+ // which is how `[u64; if Self::COMPRESS { .. }]` reads as a
868+ // field type.
869+ let outer_self = self
870+ .self_ty
871+ .replace(Nim::Named(s.ident.to_string(), Vec::new()));
872+ let r = self.collect_struct(s);
873+ self.self_ty = outer_self;
874+ return r;
852875 }
853876 Item::Macro(m) if path_name(&m.mac.path) == "bitflags" => {
854877 self.collect_bitflags(&m.mac)?;
@@ -2074,6 +2097,45 @@ impl Lowerer {
20742097 // --------------------------------------------------------------- items
20752098
20762099 /// Emit the type definitions only: they must precede every signature.
2100+ /// Write out every associated constant, ahead of the types.
2101+ fn emit_assoc_consts(&mut self, item: &Item) -> Result<(), String> {
2102+ if !self.cfg_keeps(item_attrs(item))? {
2103+ return Ok(());
2104+ }
2105+ match item {
2106+ Item::Impl(im) => {
2107+ let self_ty = self.map_ty(&im.self_ty)?;
2108+ let outer = self.self_ty.replace(self_ty.clone());
2109+ let tyname = type_name(&self_ty);
2110+ let mut r = Ok(());
2111+ for it in &im.items {
2112+ if let syn::ImplItem::Const(c) = it {
2113+ r = r.and(self.assoc_const(&tyname, c));
2114+ }
2115+ }
2116+ self.self_ty = outer;
2117+ r
2118+ }
2119+ Item::Mod(m) => {
2120+ if let Some((_, items)) = &m.content {
2121+ for i in items {
2122+ self.emit_assoc_consts(i)?;
2123+ }
2124+ }
2125+ Ok(())
2126+ }
2127+ Item::Const(c) => {
2128+ if let Some(items) = derive_item_block(c) {
2129+ for i in &items {
2130+ self.emit_assoc_consts(i)?;
2131+ }
2132+ }
2133+ Ok(())
2134+ }
2135+ _ => Ok(()),
2136+ }
2137+ }
2138+
20772139 fn item_types(&mut self, item: &Item) -> Result<(), String> {
20782140 if !self.cfg_keeps(item_attrs(item))? {
20792141 return Ok(());
@@ -568,6 +568,17 @@ impl Lowerer {
568 self.resolve_discriminants()?;568 self.resolve_discriminants()?;
569 self.resolve_opaque()?;569 self.resolve_opaque()?;
570 570
571+ // Pass 1.9: associated constants, which a type definition may mention.
572+ // `struct T { data: [u64; Self::N] }` is the case -- the constant has
573+ // to be declared before the object that uses it, and `impl T` is
574+ // written after `struct T`.
575+ for (m, f) in files {
576+ self.cur_mod = m.clone();
577+ for item in &f.items {
578+ self.emit_assoc_consts(item)?;
579+ }
580+ }
581+
571 // Pass 2: type definitions, which every signature may mention.582 // Pass 2: type definitions, which every signature may mention.
572 for (m, f) in files {583 for (m, f) in files {
573 self.cur_mod = m.clone();584 self.cur_mod = m.clone();
@@ -790,6 +801,28 @@ impl Lowerer {
790 }801 }
791 }802 }
792 803
804+ fn collect_struct(&mut self, s: &syn::ItemStruct) -> Result<(), String> {
805+ let g = Self::generics_of(&s.generics);
806+ // The parameters must be in scope while the field types are mapped,
807+ // so that `T` resolves to itself rather than to an unknown named type.
808+ self.type_generics.insert(s.ident.to_string(), g);
809+ let mut fields = Vec::new();
810+ for (i, f) in s.fields.iter().enumerate() {
811+ let name = match &f.ident {
812+ Some(id) => id.to_string(),
813+ None => format!("f{i}"), // tuple struct
814+ };
815+ // A field of `&[T]` / `&str` type is a borrow, and Nim's view
816+ // types allow it as an object field, so it stays a view rather
817+ // than being copied into a `seq`.
818+ let t = self.map_ty(&f.ty)?;
819+ let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() };
820+ fields.push((name, t));
821+ }
822+ self.structs.insert(s.ident.to_string(), fields);
823+ Ok(())
824+ }
825+
793 fn collect(&mut self, item: &Item) -> Result<(), String> {826 fn collect(&mut self, item: &Item) -> Result<(), String> {
794 // A `#[cfg(..)]` item exists only under some feature set. Dropping it827 // A `#[cfg(..)]` item exists only under some feature set. Dropping it
795 // silently would change what the program does; picking a feature set828 // silently would change what the program does; picking a feature set
@@ -830,25 +863,15 @@ impl Lowerer {
830 }863 }
831 Item::Struct(s) => {864 Item::Struct(s) => {
832 self.note_const_generics(&s.generics)?;865 self.note_const_generics(&s.generics)?;
833- let g = Self::generics_of(&s.generics);866+ // `Self` inside a struct's own declaration names that struct,
834- // The parameters must be in scope while the field types are867+ // which is how `[u64; if Self::COMPRESS { .. }]` reads as a
835- // mapped, so that `T` resolves to itself rather than to an868+ // field type.
836- // unknown named type.869+ let outer_self = self
837- self.type_generics.insert(s.ident.to_string(), g);870+ .self_ty
838- let mut fields = Vec::new();871+ .replace(Nim::Named(s.ident.to_string(), Vec::new()));
839- for (i, f) in s.fields.iter().enumerate() {872+ let r = self.collect_struct(s);
840- let name = match &f.ident {873+ self.self_ty = outer_self;
841- Some(id) => id.to_string(),874+ return r;
842- None => format!("f{i}"), // tuple struct
843- };
844- // A field of `&[T]` / `&str` type is a borrow, and Nim's
845- // view types allow it as an object field, so it stays a
846- // view rather than being copied into a `seq`.
847- let t = self.map_ty(&f.ty)?;
848- let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() };
849- fields.push((name, t));
850- }
851- self.structs.insert(s.ident.to_string(), fields);
852 }875 }
853 Item::Macro(m) if path_name(&m.mac.path) == "bitflags" => {876 Item::Macro(m) if path_name(&m.mac.path) == "bitflags" => {
854 self.collect_bitflags(&m.mac)?;877 self.collect_bitflags(&m.mac)?;
@@ -2074,6 +2097,45 @@ impl Lowerer {
2074 // --------------------------------------------------------------- items2097 // --------------------------------------------------------------- items
2075 2098
2076 /// Emit the type definitions only: they must precede every signature.2099 /// Emit the type definitions only: they must precede every signature.
2100+ /// Write out every associated constant, ahead of the types.
2101+ fn emit_assoc_consts(&mut self, item: &Item) -> Result<(), String> {
2102+ if !self.cfg_keeps(item_attrs(item))? {
2103+ return Ok(());
2104+ }
2105+ match item {
2106+ Item::Impl(im) => {
2107+ let self_ty = self.map_ty(&im.self_ty)?;
2108+ let outer = self.self_ty.replace(self_ty.clone());
2109+ let tyname = type_name(&self_ty);
2110+ let mut r = Ok(());
2111+ for it in &im.items {
2112+ if let syn::ImplItem::Const(c) = it {
2113+ r = r.and(self.assoc_const(&tyname, c));
2114+ }
2115+ }
2116+ self.self_ty = outer;
2117+ r
2118+ }
2119+ Item::Mod(m) => {
2120+ if let Some((_, items)) = &m.content {
2121+ for i in items {
2122+ self.emit_assoc_consts(i)?;
2123+ }
2124+ }
2125+ Ok(())
2126+ }
2127+ Item::Const(c) => {
2128+ if let Some(items) = derive_item_block(c) {
2129+ for i in &items {
2130+ self.emit_assoc_consts(i)?;
2131+ }
2132+ }
2133+ Ok(())
2134+ }
2135+ _ => Ok(()),
2136+ }
2137+ }
2138+
2077 fn item_types(&mut self, item: &Item) -> Result<(), String> {2139 fn item_types(&mut self, item: &Item) -> Result<(), String> {
2078 if !self.cfg_keeps(item_attrs(item))? {2140 if !self.cfg_keeps(item_attrs(item))? {
2079 return Ok(());2141 return Ok(());
modified tests/cases/052-const-array-len.rs +13 -0
@@ -29,6 +29,16 @@ impl Oid {
2929 }
3030 }
3131
32+// `Self` inside a struct's own declaration names that struct.
33+struct Table {
34+ data: [u8; if Table::WIDE { 8 } else { Table::N * 2 }],
35+}
36+
37+impl Table {
38+ const WIDE: bool = false;
39+ const N: usize = 3;
40+}
41+
3242 struct Buf {
3343 data: [u8; BLOCK],
3444 wide: [u8; DOUBLE],
@@ -62,6 +72,9 @@ fn main() {
6272
6373 // An associated const as a length, and in the braces rustc's expanded
6474 // output writes it with.
75+ let tb = Table { data: [1u8; if Table::WIDE { 8 } else { Table::N * 2 }] };
76+ println!("{} {}", tb.data.len(), sum(&tb.data));
77+
6578 let t2 = Oid::table();
6679 println!("{} {}", t2.len(), sum(&t2));
6780
@@ -29,6 +29,16 @@ impl Oid {
29 }29 }
30 }30 }
31 31
32+// `Self` inside a struct's own declaration names that struct.
33+struct Table {
34+ data: [u8; if Table::WIDE { 8 } else { Table::N * 2 }],
35+}
36+
37+impl Table {
38+ const WIDE: bool = false;
39+ const N: usize = 3;
40+}
41+
32 struct Buf {42 struct Buf {
33 data: [u8; BLOCK],43 data: [u8; BLOCK],
34 wide: [u8; DOUBLE],44 wide: [u8; DOUBLE],
@@ -62,6 +72,9 @@ fn main() {
62 72
63 // An associated const as a length, and in the braces rustc's expanded73 // An associated const as a length, and in the braces rustc's expanded
64 // output writes it with.74 // output writes it with.
75+ let tb = Table { data: [1u8; if Table::WIDE { 8 } else { Table::N * 2 }] };
76+ println!("{} {}", tb.data.len(), sum(&tb.data));
77+
65 let t2 = Oid::table();78 let t2 = Oid::table();
66 println!("{} {}", t2.len(), sum(&t2));79 println!("{} {}", t2.len(), sum(&t2));
67 80