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

Publish `Self` apart from the const-name map

Putting the current `Self` in that map's cache key undid the caching entirely:
`self_ty` changes with every impl, so the key changed on nearly every call and
the whole map was rebuilt each time. A hundred crates went back from forty
seconds to over twenty minutes -- the exact cost the cache was added to remove,
reintroduced by the commit after it.

`Self` is a single string, so it is published on its own and substituted at
lookup. The map stays keyed on real type names and rebuilds only when the
tables it reads have grown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T12:41:16-07:00 Browse files
51929ac parent: 8e6b002
modified src/lower.rs +10 -10
@@ -348,7 +348,7 @@ pub struct Lowerer {
348348 /// parameter is the same thing: a generic parameter that is a value.
349349 const_gens: HashMap<String, String>,
350350 /// Combined table size when `CONST_NAMES` was last rebuilt.
351- const_names_at: std::cell::RefCell<Option<(usize, String)>>,
351+ const_names_at: std::cell::Cell<Option<usize>>,
352352 /// Bodies of functions whose return type is a return-position `impl
353353 /// Trait`, keyed the same way as `fns`/`methods`, so `resolve_opaque` can
354354 /// read the concrete type back off the body.
@@ -437,7 +437,7 @@ impl Lowerer {
437437 emitted_local: std::collections::HashSet::new(),
438438 emitted_assoc: std::collections::HashSet::new(),
439439 const_gens: HashMap::new(),
440- const_names_at: std::cell::RefCell::new(None),
440+ const_names_at: std::cell::Cell::new(None),
441441 opaque_fns: Vec::new(),
442442 opaque_ret: HashMap::new(),
443443 opaque_hint: None,
@@ -1289,14 +1289,17 @@ impl Lowerer {
12891289 // their combined size is enough to tell whether anything has been
12901290 // added since the last refill -- without it, a 357-crate run spends
12911291 // essentially all of its time rebuilding this map.
1292- // `Self::CONST` resolves against whichever impl is being walked, so
1293- // the current `Self` is part of what the map depends on.
1294- let me = self.self_ty.as_ref().map(type_name).unwrap_or_default();
1292+ // `Self` is published separately: it changes with every impl, and
1293+ // making it part of this map's key rebuilt the map on nearly every
1294+ // call, which is the cost this cache exists to avoid.
1295+ ty::CURRENT_SELF.with(|c| {
1296+ *c.borrow_mut() = self.self_ty.as_ref().map(type_name).unwrap_or_default()
1297+ });
12951298 let size = self.enums.len() + self.assoc_consts.len();
1296- if self.const_names_at.borrow().as_ref() == Some(&(size, me.clone())) {
1299+ if self.const_names_at.get() == Some(size) {
12971300 return;
12981301 }
1299- *self.const_names_at.borrow_mut() = Some((size, me.clone()));
1302+ self.const_names_at.set(Some(size));
13001303 ty::CONST_NAMES.with(|m| {
13011304 let mut m = m.borrow_mut();
13021305 m.clear();
@@ -1310,9 +1313,6 @@ impl Lowerer {
13101313 }
13111314 for ((owner, name), (nim, _)) in &self.assoc_consts {
13121315 m.insert(format!("{owner}::{name}"), nim.clone());
1313- if !me.is_empty() && owner == &me {
1314- m.insert(format!("Self::{name}"), nim.clone());
1315- }
13161316 }
13171317 });
13181318 }
@@ -348,7 +348,7 @@ pub struct Lowerer {
348 /// parameter is the same thing: a generic parameter that is a value.348 /// parameter is the same thing: a generic parameter that is a value.
349 const_gens: HashMap<String, String>,349 const_gens: HashMap<String, String>,
350 /// Combined table size when `CONST_NAMES` was last rebuilt.350 /// Combined table size when `CONST_NAMES` was last rebuilt.
351- const_names_at: std::cell::RefCell<Option<(usize, String)>>,351+ const_names_at: std::cell::Cell<Option<usize>>,
352 /// Bodies of functions whose return type is a return-position `impl352 /// Bodies of functions whose return type is a return-position `impl
353 /// Trait`, keyed the same way as `fns`/`methods`, so `resolve_opaque` can353 /// Trait`, keyed the same way as `fns`/`methods`, so `resolve_opaque` can
354 /// read the concrete type back off the body.354 /// read the concrete type back off the body.
@@ -437,7 +437,7 @@ impl Lowerer {
437 emitted_local: std::collections::HashSet::new(),437 emitted_local: std::collections::HashSet::new(),
438 emitted_assoc: std::collections::HashSet::new(),438 emitted_assoc: std::collections::HashSet::new(),
439 const_gens: HashMap::new(),439 const_gens: HashMap::new(),
440- const_names_at: std::cell::RefCell::new(None),440+ const_names_at: std::cell::Cell::new(None),
441 opaque_fns: Vec::new(),441 opaque_fns: Vec::new(),
442 opaque_ret: HashMap::new(),442 opaque_ret: HashMap::new(),
443 opaque_hint: None,443 opaque_hint: None,
@@ -1289,14 +1289,17 @@ impl Lowerer {
1289 // their combined size is enough to tell whether anything has been1289 // their combined size is enough to tell whether anything has been
1290 // added since the last refill -- without it, a 357-crate run spends1290 // added since the last refill -- without it, a 357-crate run spends
1291 // essentially all of its time rebuilding this map.1291 // essentially all of its time rebuilding this map.
1292- // `Self::CONST` resolves against whichever impl is being walked, so1292+ // `Self` is published separately: it changes with every impl, and
1293- // the current `Self` is part of what the map depends on.1293+ // making it part of this map's key rebuilt the map on nearly every
1294- let me = self.self_ty.as_ref().map(type_name).unwrap_or_default();1294+ // call, which is the cost this cache exists to avoid.
1295+ ty::CURRENT_SELF.with(|c| {
1296+ *c.borrow_mut() = self.self_ty.as_ref().map(type_name).unwrap_or_default()
1297+ });
1295 let size = self.enums.len() + self.assoc_consts.len();1298 let size = self.enums.len() + self.assoc_consts.len();
1296- if self.const_names_at.borrow().as_ref() == Some(&(size, me.clone())) {1299+ if self.const_names_at.get() == Some(size) {
1297 return;1300 return;
1298 }1301 }
1299- *self.const_names_at.borrow_mut() = Some((size, me.clone()));1302+ self.const_names_at.set(Some(size));
1300 ty::CONST_NAMES.with(|m| {1303 ty::CONST_NAMES.with(|m| {
1301 let mut m = m.borrow_mut();1304 let mut m = m.borrow_mut();
1302 m.clear();1305 m.clear();
@@ -1310,9 +1313,6 @@ impl Lowerer {
1310 }1313 }
1311 for ((owner, name), (nim, _)) in &self.assoc_consts {1314 for ((owner, name), (nim, _)) in &self.assoc_consts {
1312 m.insert(format!("{owner}::{name}"), nim.clone());1315 m.insert(format!("{owner}::{name}"), nim.clone());
1313- if !me.is_empty() && owner == &me {
1314- m.insert(format!("Self::{name}"), nim.clone());
1315- }
1316 }1316 }
1317 });1317 });
1318 }1318 }
modified src/ty.rs +17 -0
@@ -546,7 +546,24 @@ thread_local! {
546546 std::cell::RefCell::new(std::collections::HashMap::new());
547547 }
548548
549+thread_local! {
550+ /// The type `Self` currently names. Kept apart from `CONST_NAMES` on
551+ /// purpose: it changes with every impl, and folding it into that map
552+ /// would rebuild the whole thing on nearly every call.
553+ pub static CURRENT_SELF: std::cell::RefCell<String> =
554+ const { std::cell::RefCell::new(String::new()) };
555+}
556+
549557 fn known_const(q: &str, n: &str) -> Option<String> {
558+ let q = if q == "Self" {
559+ let me = CURRENT_SELF.with(|c| c.borrow().clone());
560+ if me.is_empty() {
561+ return None;
562+ }
563+ me
564+ } else {
565+ q.to_string()
566+ };
550567 CONST_NAMES.with(|m| m.borrow().get(&format!("{q}::{n}")).cloned())
551568 }
552569
@@ -546,7 +546,24 @@ thread_local! {
546 std::cell::RefCell::new(std::collections::HashMap::new());546 std::cell::RefCell::new(std::collections::HashMap::new());
547 }547 }
548 548
549+thread_local! {
550+ /// The type `Self` currently names. Kept apart from `CONST_NAMES` on
551+ /// purpose: it changes with every impl, and folding it into that map
552+ /// would rebuild the whole thing on nearly every call.
553+ pub static CURRENT_SELF: std::cell::RefCell<String> =
554+ const { std::cell::RefCell::new(String::new()) };
555+}
556+
549 fn known_const(q: &str, n: &str) -> Option<String> {557 fn known_const(q: &str, n: &str) -> Option<String> {
558+ let q = if q == "Self" {
559+ let me = CURRENT_SELF.with(|c| c.borrow().clone());
560+ if me.is_empty() {
561+ return None;
562+ }
563+ me
564+ } else {
565+ q.to_string()
566+ };
550 CONST_NAMES.with(|m| m.borrow().get(&format!("{q}::{n}")).cloned())567 CONST_NAMES.with(|m| m.borrow().get(&format!("{q}::{n}")).cloned())
551 }568 }
552 569