nandi/rustnimpublic Fork
⑂ abb295c
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 an enum before lowering its discriminants

Rust lets a discriminant name an earlier variant of the enum being declared.
`enumflags2` expands to exactly that -- `Popup = next_bit(Auto::Window as u128)`
-- and rustnim had no type for the sibling reference, because the enum was not
inserted until after every discriminant had been lowered. Registered in shape
first, with the real entry replacing it.

Found by re-running expanded libcosmic once `u128` stopped being a blocker.
The next halt after this one is `enumflags2::_internal::next_bit`, which is a
dependency's function rather than a language feature -- noted in DESIGN.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T09:11:45-07:00 Browse files
abb295c parent: f9ca982
modified DESIGN.md +20 -0
@@ -1190,3 +1190,23 @@ writing once per byte into the formatter.
11901190
11911191 This is the crate whose six files the transpiler in `findings/` emitted empty
11921192 output for, while exiting 0.
1193+
1194+### After 128-bit integers: where expanded libcosmic stops now
1195+
1196+Re-running the expanded crate (44,649 lines) with `u128` implemented moved the
1197+halt twice:
1198+
1199+1. `Auto::Window as u128` inside the *declaration* of `enum Auto` — a
1200+ discriminant naming an earlier variant of the enum being declared, which is
1201+ how `enumflags2` expands. The enum is now registered in shape before its
1202+ discriminants are lowered, so the sibling reference has a type. Fixed.
1203+2. `::enumflags2::_internal::next_bit` — and this one is not a language
1204+ feature at all. It is a plain function in a dependency crate, and
1205+ `-Zunpretty=expanded` expands only the crate you point it at, so the
1206+ definition is simply absent from the input. It is the dependency question
1207+ again, with the same answer as before: other people's crates are just Rust,
1208+ and the way through is to feed rustnim the dependency's source too, not to
1209+ special-case the name.
1210+
1211+So the language-feature list did bottom out here, exactly as predicted; what
1212+is left in front of libcosmic is source availability, not semantics.
@@ -1190,3 +1190,23 @@ writing once per byte into the formatter.
1190 1190
1191 This is the crate whose six files the transpiler in `findings/` emitted empty1191 This is the crate whose six files the transpiler in `findings/` emitted empty
1192 output for, while exiting 0.1192 output for, while exiting 0.
1193+
1194+### After 128-bit integers: where expanded libcosmic stops now
1195+
1196+Re-running the expanded crate (44,649 lines) with `u128` implemented moved the
1197+halt twice:
1198+
1199+1. `Auto::Window as u128` inside the *declaration* of `enum Auto` — a
1200+ discriminant naming an earlier variant of the enum being declared, which is
1201+ how `enumflags2` expands. The enum is now registered in shape before its
1202+ discriminants are lowered, so the sibling reference has a type. Fixed.
1203+2. `::enumflags2::_internal::next_bit` — and this one is not a language
1204+ feature at all. It is a plain function in a dependency crate, and
1205+ `-Zunpretty=expanded` expands only the crate you point it at, so the
1206+ definition is simply absent from the input. It is the dependency question
1207+ again, with the same answer as before: other people's crates are just Rust,
1208+ and the way through is to feed rustnim the dependency's source too, not to
1209+ special-case the name.
1210+
1211+So the language-feature list did bottom out here, exactly as predicted; what
1212+is left in front of libcosmic is source availability, not semantics.
modified src/lower.rs +31 -7
@@ -718,6 +718,37 @@ impl Lowerer {
718718 }
719719 self.type_generics
720720 .insert(name.clone(), Self::generics_of(&e.generics));
721+
722+ // Register the enum before lowering its discriminants. Rust
723+ // lets a discriminant name an earlier variant of the enum
724+ // being declared -- `Popup = next_bit(Auto::Window as u128)`
725+ // is how `enumflags2` expands -- and without this the sibling
726+ // reference has no known type. Shape only; the real entry
727+ // replaces it below.
728+ let simple = e.variants.iter().all(|v| v.fields.is_empty());
729+ for v in &e.variants {
730+ self.variant_owner
731+ .entry(v.ident.to_string())
732+ .or_default()
733+ .push(name.clone());
734+ }
735+ self.enums.insert(
736+ name.clone(),
737+ EnumDef {
738+ name: name.clone(),
739+ simple,
740+ variants: e
741+ .variants
742+ .iter()
743+ .map(|v| Variant {
744+ name: v.ident.to_string(),
745+ discriminant: None,
746+ fields: Vec::new(),
747+ })
748+ .collect(),
749+ },
750+ );
751+
721752 let mut variants = Vec::new();
722753 for v in &e.variants {
723754 let vname = v.ident.to_string();
@@ -739,13 +770,6 @@ impl Lowerer {
739770 }
740771 variants.push(Variant { name: vname, discriminant, fields });
741772 }
742- let simple = variants.iter().all(|v| v.fields.is_empty());
743- for v in &variants {
744- self.variant_owner
745- .entry(v.name.clone())
746- .or_default()
747- .push(name.clone());
748- }
749773 self.enums.insert(
750774 name.clone(),
751775 EnumDef { name, simple, variants },
@@ -718,6 +718,37 @@ impl Lowerer {
718 }718 }
719 self.type_generics719 self.type_generics
720 .insert(name.clone(), Self::generics_of(&e.generics));720 .insert(name.clone(), Self::generics_of(&e.generics));
721+
722+ // Register the enum before lowering its discriminants. Rust
723+ // lets a discriminant name an earlier variant of the enum
724+ // being declared -- `Popup = next_bit(Auto::Window as u128)`
725+ // is how `enumflags2` expands -- and without this the sibling
726+ // reference has no known type. Shape only; the real entry
727+ // replaces it below.
728+ let simple = e.variants.iter().all(|v| v.fields.is_empty());
729+ for v in &e.variants {
730+ self.variant_owner
731+ .entry(v.ident.to_string())
732+ .or_default()
733+ .push(name.clone());
734+ }
735+ self.enums.insert(
736+ name.clone(),
737+ EnumDef {
738+ name: name.clone(),
739+ simple,
740+ variants: e
741+ .variants
742+ .iter()
743+ .map(|v| Variant {
744+ name: v.ident.to_string(),
745+ discriminant: None,
746+ fields: Vec::new(),
747+ })
748+ .collect(),
749+ },
750+ );
751+
721 let mut variants = Vec::new();752 let mut variants = Vec::new();
722 for v in &e.variants {753 for v in &e.variants {
723 let vname = v.ident.to_string();754 let vname = v.ident.to_string();
@@ -739,13 +770,6 @@ impl Lowerer {
739 }770 }
740 variants.push(Variant { name: vname, discriminant, fields });771 variants.push(Variant { name: vname, discriminant, fields });
741 }772 }
742- let simple = variants.iter().all(|v| v.fields.is_empty());
743- for v in &variants {
744- self.variant_owner
745- .entry(v.name.clone())
746- .or_default()
747- .push(name.clone());
748- }
749 self.enums.insert(773 self.enums.insert(
750 name.clone(),774 name.clone(),
751 EnumDef { name, simple, variants },775 EnumDef { name, simple, variants },