nandi/rustnimpublic Fork
⑂ e534fb9
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

Register length-bearing names before any type is mapped

The previous commit moved associated consts into `collect_impl`, which was
still too late: a struct field's type can be `[u8; T::MAX_SIZE]`, and field
types are mapped in the same pass that collects the `impl T` carrying the
const. Whether the name resolved came down to which appeared first in the
file -- the same order-dependence as the enum discriminants, one pass earlier.

A pass before all the others now registers just the names an array length can
refer to: associated consts, and the variants of C-like enums. Failures there
are ignored on purpose, since it runs before the tables a type needs are
filled; anything it cannot map yet is left to the pass that can.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T10:54:56-07:00 Browse files
e534fb9 parent: 2687049
modified src/lower.rs +72 -0
@@ -524,6 +524,20 @@ impl Lowerer {
524524 }
525525 }
526526
527+ // Pass 0.5: associated consts and enum variant names.
528+ //
529+ // A struct field's type can be `[u8; T::MAX_SIZE]`, and field types
530+ // are mapped in pass 1 -- which is also when the `impl T` carrying
531+ // that const is collected. Whether the name resolved therefore
532+ // depended on which came first in the file. Registering the names on
533+ // their own, before anything is mapped, removes the ordering.
534+ for (m, f) in files {
535+ self.cur_mod = m.clone();
536+ for item in &f.items {
537+ self.precollect(item);
538+ }
539+ }
540+
527541 // Pass 1: signatures and struct shapes, so that a call can be typed
528542 // regardless of declaration order (Rust has no forward declarations).
529543 for (m, f) in files {
@@ -711,6 +725,64 @@ impl Lowerer {
711725 }
712726 }
713727
728+ /// Register the names an array length may refer to, before any type is
729+ /// mapped. Names only -- everything else waits for the ordinary passes.
730+ ///
731+ /// Failures are ignored rather than reported: this runs before the tables
732+ /// a type needs are filled, so a const whose own type is not yet mappable
733+ /// is simply left to the pass that can map it.
734+ fn precollect(&mut self, item: &Item) {
735+ match item {
736+ Item::Mod(m) => {
737+ if let Some((_, items)) = &m.content {
738+ for i in items {
739+ self.precollect(i);
740+ }
741+ }
742+ }
743+ Item::Const(c) => {
744+ if let Some(items) = derive_item_block(c) {
745+ for i in &items {
746+ self.precollect(i);
747+ }
748+ }
749+ }
750+ Item::Enum(e) => {
751+ // Only the variant names, and only for a C-like enum: those
752+ // are the ones that can appear in a length.
753+ if e.variants.iter().all(|v| v.fields.is_empty()) {
754+ let name = e.ident.to_string();
755+ self.enums.entry(name.clone()).or_insert_with(|| EnumDef {
756+ name: name.clone(),
757+ simple: true,
758+ variants: e
759+ .variants
760+ .iter()
761+ .map(|v| Variant {
762+ name: v.ident.to_string(),
763+ discriminant: None,
764+ disc_expr: None,
765+ fields: Vec::new(),
766+ })
767+ .collect(),
768+ });
769+ }
770+ }
771+ Item::Impl(im) => {
772+ let Ok(self_ty) = self.map_ty(&im.self_ty) else { return };
773+ let tyn = type_name(&self_ty);
774+ for it in &im.items {
775+ let syn::ImplItem::Const(c) = it else { continue };
776+ let Ok(t) = self.map_ty(&c.ty) else { continue };
777+ let n = ident(&format!("{}_{}", tyn, c.ident));
778+ self.assoc_consts
779+ .insert((tyn.clone(), c.ident.to_string()), (n, t.owned()));
780+ }
781+ }
782+ _ => {}
783+ }
784+ }
785+
714786 fn collect(&mut self, item: &Item) -> Result<(), String> {
715787 // A `#[cfg(..)]` item exists only under some feature set. Dropping it
716788 // silently would change what the program does; picking a feature set
@@ -524,6 +524,20 @@ impl Lowerer {
524 }524 }
525 }525 }
526 526
527+ // Pass 0.5: associated consts and enum variant names.
528+ //
529+ // A struct field's type can be `[u8; T::MAX_SIZE]`, and field types
530+ // are mapped in pass 1 -- which is also when the `impl T` carrying
531+ // that const is collected. Whether the name resolved therefore
532+ // depended on which came first in the file. Registering the names on
533+ // their own, before anything is mapped, removes the ordering.
534+ for (m, f) in files {
535+ self.cur_mod = m.clone();
536+ for item in &f.items {
537+ self.precollect(item);
538+ }
539+ }
540+
527 // Pass 1: signatures and struct shapes, so that a call can be typed541 // Pass 1: signatures and struct shapes, so that a call can be typed
528 // regardless of declaration order (Rust has no forward declarations).542 // regardless of declaration order (Rust has no forward declarations).
529 for (m, f) in files {543 for (m, f) in files {
@@ -711,6 +725,64 @@ impl Lowerer {
711 }725 }
712 }726 }
713 727
728+ /// Register the names an array length may refer to, before any type is
729+ /// mapped. Names only -- everything else waits for the ordinary passes.
730+ ///
731+ /// Failures are ignored rather than reported: this runs before the tables
732+ /// a type needs are filled, so a const whose own type is not yet mappable
733+ /// is simply left to the pass that can map it.
734+ fn precollect(&mut self, item: &Item) {
735+ match item {
736+ Item::Mod(m) => {
737+ if let Some((_, items)) = &m.content {
738+ for i in items {
739+ self.precollect(i);
740+ }
741+ }
742+ }
743+ Item::Const(c) => {
744+ if let Some(items) = derive_item_block(c) {
745+ for i in &items {
746+ self.precollect(i);
747+ }
748+ }
749+ }
750+ Item::Enum(e) => {
751+ // Only the variant names, and only for a C-like enum: those
752+ // are the ones that can appear in a length.
753+ if e.variants.iter().all(|v| v.fields.is_empty()) {
754+ let name = e.ident.to_string();
755+ self.enums.entry(name.clone()).or_insert_with(|| EnumDef {
756+ name: name.clone(),
757+ simple: true,
758+ variants: e
759+ .variants
760+ .iter()
761+ .map(|v| Variant {
762+ name: v.ident.to_string(),
763+ discriminant: None,
764+ disc_expr: None,
765+ fields: Vec::new(),
766+ })
767+ .collect(),
768+ });
769+ }
770+ }
771+ Item::Impl(im) => {
772+ let Ok(self_ty) = self.map_ty(&im.self_ty) else { return };
773+ let tyn = type_name(&self_ty);
774+ for it in &im.items {
775+ let syn::ImplItem::Const(c) = it else { continue };
776+ let Ok(t) = self.map_ty(&c.ty) else { continue };
777+ let n = ident(&format!("{}_{}", tyn, c.ident));
778+ self.assoc_consts
779+ .insert((tyn.clone(), c.ident.to_string()), (n, t.owned()));
780+ }
781+ }
782+ _ => {}
783+ }
784+ }
785+
714 fn collect(&mut self, item: &Item) -> Result<(), String> {786 fn collect(&mut self, item: &Item) -> Result<(), String> {
715 // A `#[cfg(..)]` item exists only under some feature set. Dropping it787 // A `#[cfg(..)]` item exists only under some feature set. Dropping it
716 // silently would change what the program does; picking a feature set788 // silently would change what the program does; picking a feature set