| @@ -370,6 +370,10 @@ pub struct Lowerer { |
| 370 | /// function in it is untranslatable answers a question nobody asked. The | 370 | /// function in it is untranslatable answers a question nobody asked. The |
| 371 | /// error belongs at the call site, and that is where it is raised. | 371 | /// error belongs at the call site, and that is where it is raised. |
| 372 | untranslatable: HashMap<String, String>, | 372 | untranslatable: HashMap<String, String>, |
| | 373 | + /// Which input declared each enum, so the pass that lowers discriminants |
| | 374 | + /// -- which runs after all the files, not inside one -- can say where a |
| | 375 | + /// failure came from. |
| | 376 | + enum_module: HashMap<String, String>, |
| 373 | /// Bounds discovered while rewriting `impl Trait` parameters. `rewrite_apit` | 377 | /// Bounds discovered while rewriting `impl Trait` parameters. `rewrite_apit` |
| 374 | /// runs from `&self`, so they are parked here and folded into `bounds` by | 378 | /// runs from `&self`, so they are parked here and folded into `bounds` by |
| 375 | /// whoever called it. | 379 | /// whoever called it. |
| @@ -471,6 +475,7 @@ impl Lowerer { |
| 471 | trait_methods: HashMap::new(), | 475 | trait_methods: HashMap::new(), |
| 472 | fn_blankets: HashMap::new(), | 476 | fn_blankets: HashMap::new(), |
| 473 | untranslatable: HashMap::new(), | 477 | untranslatable: HashMap::new(), |
| | 478 | + enum_module: HashMap::new(), |
| 474 | pending_apit_bounds: std::cell::RefCell::new(Vec::new()), | 479 | pending_apit_bounds: std::cell::RefCell::new(Vec::new()), |
| 475 | bounds: HashMap::new(), | 480 | bounds: HashMap::new(), |
| 476 | const_names_at: std::cell::Cell::new(None), | 481 | const_names_at: std::cell::Cell::new(None), |
| @@ -1049,6 +1054,7 @@ impl Lowerer { |
| 1049 | .or_default() | 1054 | .or_default() |
| 1050 | .push(name.clone()); | 1055 | .push(name.clone()); |
| 1051 | } | 1056 | } |
| | 1057 | + self.enum_module.insert(name.clone(), self.cur_mod.clone()); |
| 1052 | self.enums.insert( | 1058 | self.enums.insert( |
| 1053 | name.clone(), | 1059 | name.clone(), |
| 1054 | EnumDef { | 1060 | EnumDef { |
| @@ -2201,13 +2207,22 @@ impl Lowerer { |
| 2201 | | 2207 | |
| 2202 | /// Lower every enum discriminant, after all signatures are collected. | 2208 | /// Lower every enum discriminant, after all signatures are collected. |
| 2203 | fn resolve_discriminants(&mut self) -> Result<(), String> { | 2209 | fn resolve_discriminants(&mut self) -> Result<(), String> { |
| 2204 | - let names: Vec<String> = self.enums.keys().cloned().collect(); | 2210 | + // Sorted: a `HashMap`'s order is not defined, and with three hundred |
| | 2211 | + // enums that decides *which* failure gets reported. An error that |
| | 2212 | + // moves between runs is not one anybody can chase. |
| | 2213 | + let mut names: Vec<String> = self.enums.keys().cloned().collect(); |
| | 2214 | + names.sort(); |
| 2205 | for n in names { | 2215 | for n in names { |
| 2206 | let Some(def) = self.enums.get(&n).cloned() else { continue }; | 2216 | let Some(def) = self.enums.get(&n).cloned() else { continue }; |
| 2207 | let mut out = def.clone(); | 2217 | let mut out = def.clone(); |
| | 2218 | + self.cur_mod = self.enum_module.get(&n).cloned().unwrap_or_default(); |
| 2208 | for (i, v) in def.variants.iter().enumerate() { | 2219 | for (i, v) in def.variants.iter().enumerate() { |
| 2209 | let Some(e) = &v.disc_expr else { continue }; | 2220 | let Some(e) = &v.disc_expr else { continue }; |
| 2210 | - out.variants[i].discriminant = Some(self.expr(e)?.code); | 2221 | + let code = self |
| | 2222 | + .expr(e) |
| | 2223 | + .map_err(|err| self.where_(&format!("`enum {n}`: {err}")))? |
| | 2224 | + .code; |
| | 2225 | + out.variants[i].discriminant = Some(code); |
| 2211 | } | 2226 | } |
| 2212 | self.enums.insert(n, out); | 2227 | self.enums.insert(n, out); |
| 2213 | } | 2228 | } |
| @@ -5204,13 +5219,10 @@ impl Lowerer { |
| 5204 | } | 5219 | } |
| 5205 | } | 5220 | } |
| 5206 | } | 5221 | } |
| 5207 | - if self.structs.get(&name).is_some_and(|f| f.is_empty()) { | | |
| 5208 | - return Ok(Val::new( | | |
| 5209 | - format!("{}()", ident(&name)), | | |
| 5210 | - Some(Nim::Named(name.clone(), vec![])), | | |
| 5211 | - )); | | |
| 5212 | - } | | |
| 5213 | // A unit enum variant used as a value: `Error::InvalidLength`. | 5222 | // A unit enum variant used as a value: `Error::InvalidLength`. |
| | 5223 | + // Before the unit-struct case below, which matches on the last |
| | 5224 | + // segment alone: `State::Horizontal` is that enum's variant, |
| | 5225 | + // whatever some other crate calls a struct of its own. |
| 5214 | if let Some((def, v)) = self.resolve_variant(&p.path) { | 5226 | if let Some((def, v)) = self.resolve_variant(&p.path) { |
| 5215 | let (ty, targs) = self.variant_type(&def, expect)?; | 5227 | let (ty, targs) = self.variant_type(&def, expect)?; |
| 5216 | return Ok(if def.simple && targs.is_empty() { | 5228 | return Ok(if def.simple && targs.is_empty() { |
| @@ -5224,6 +5236,12 @@ impl Lowerer { |
| 5224 | ) | 5236 | ) |
| 5225 | }); | 5237 | }); |
| 5226 | } | 5238 | } |
| | 5239 | + if self.structs.get(&name).is_some_and(|f| f.is_empty()) { |
| | 5240 | + return Ok(Val::new( |
| | 5241 | + format!("{}()", ident(&name)), |
| | 5242 | + Some(Nim::Named(name.clone(), vec![])), |
| | 5243 | + )); |
| | 5244 | + } |
| 5227 | // A `for` binding that stands for an element of the container | 5245 | // A `for` binding that stands for an element of the container |
| 5228 | // it came from: using it must read (and assigning through it | 5246 | // it came from: using it must read (and assigning through it |
| 5229 | // must write) that element, not a copy. | 5247 | // must write) that element, not a copy. |