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

Take a range's type from the end that has one, and scan every branch

`for i in 0..self.netsize` was typed from the literal `0`, so the loop
variable came out `i32` against a `usize` bound. A bare bound says only what
Rust defaults to; the other end decides, and the literal is re-lowered to
match -- without which Nim compares an `int32` against a `uint`.

`startpos = i` is a peer as plainly as a comparison is, and the scan for peers
now looks in `else` branches and `match` arms as well as `then`. That last
omission was the whole of why `best` stayed `i32`.

With these, `color_quant` compiles: Rust through rustnim to Nim that `nim c`
accepts, 685 lines and 84 items. It is the first of libcosmic's dependencies
to go the whole way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-20T10:43:21-07:00 Browse files
e28de7f parent: 2693452
modified src/lower.rs +46 -2
@@ -4082,8 +4082,35 @@ impl Lowerer {
40824082 Expr::If(i) => {
40834083 self.find_peer_expr(name, &i.cond, out);
40844084 self.find_peer(name, &i.then_branch.stmts, out);
4085+ if let Some((_, els)) = &i.else_branch {
4086+ self.find_peer_expr(name, els, out);
4087+ }
4088+ }
4089+ Expr::Match(mt) => {
4090+ for arm in &mt.arms {
4091+ self.find_peer_expr(name, &arm.body, out);
4092+ }
4093+ }
4094+ Expr::Assign(a) => {
4095+ // `startpos = i` says what `startpos` is as plainly as a
4096+ // comparison does.
4097+ if names(&a.left) && !is_bare_literal(&a.right) {
4098+ if let Some(t) = self.pushed_ty(&a.right) {
4099+ *out = Some(t);
4100+ return;
4101+ }
4102+ if let Expr::Path(p) = strip_parens(&a.right) {
4103+ if p.path.segments.len() == 1 {
4104+ let n = p.path.segments[0].ident.to_string();
4105+ if let Some(t) = self.pending_lets.get(&n).cloned() {
4106+ *out = Some(t);
4107+ return;
4108+ }
4109+ }
4110+ }
4111+ }
4112+ self.find_peer_expr(name, &a.right, out)
40854113 }
4086- Expr::Assign(a) => self.find_peer_expr(name, &a.right, out),
40874114 Expr::Index(ix) => {
40884115 // `xs[i]` makes `i` an index, which says nothing about width.
40894116 self.find_peer_expr(name, &ix.expr, out);
@@ -4815,7 +4842,24 @@ impl Lowerer {
48154842 return Err("a `for` over an unbounded range would not terminate".into())
48164843 }
48174844 };
4818- let ty = lo.ty.clone().or(hi.ty.clone());
4845+ // `0..n` is `n`'s type, not the literal's. A bare bound says
4846+ // only what Rust defaults to, so the other end decides -- and
4847+ // the literal is then re-lowered to match, or Nim compares an
4848+ // `int32` against a `uint`.
4849+ let lo_bare = r.start.as_deref().is_some_and(is_bare_literal);
4850+ let hi_bare = r.end.as_deref().is_some_and(is_bare_literal);
4851+ let ty = match (lo_bare, hi_bare) {
4852+ (true, false) => hi.ty.clone().or(lo.ty.clone()),
4853+ _ => lo.ty.clone().or(hi.ty.clone()),
4854+ };
4855+ let lo = match (&ty, r.start.as_deref()) {
4856+ (Some(t), Some(e)) if lo_bare => self.expr_at(e, Some(t))?,
4857+ _ => lo,
4858+ };
4859+ let hi = match (&ty, r.end.as_deref()) {
4860+ (Some(t), Some(e)) if hi_bare && !lo_bare => self.expr_at(e, Some(t))?,
4861+ _ => hi,
4862+ };
48194863 Ok(Iter::Range {
48204864 lo: lo.code,
48214865 hi: hi.code,
@@ -4082,8 +4082,35 @@ impl Lowerer {
4082 Expr::If(i) => {4082 Expr::If(i) => {
4083 self.find_peer_expr(name, &i.cond, out);4083 self.find_peer_expr(name, &i.cond, out);
4084 self.find_peer(name, &i.then_branch.stmts, out);4084 self.find_peer(name, &i.then_branch.stmts, out);
4085+ if let Some((_, els)) = &i.else_branch {
4086+ self.find_peer_expr(name, els, out);
4087+ }
4088+ }
4089+ Expr::Match(mt) => {
4090+ for arm in &mt.arms {
4091+ self.find_peer_expr(name, &arm.body, out);
4092+ }
4093+ }
4094+ Expr::Assign(a) => {
4095+ // `startpos = i` says what `startpos` is as plainly as a
4096+ // comparison does.
4097+ if names(&a.left) && !is_bare_literal(&a.right) {
4098+ if let Some(t) = self.pushed_ty(&a.right) {
4099+ *out = Some(t);
4100+ return;
4101+ }
4102+ if let Expr::Path(p) = strip_parens(&a.right) {
4103+ if p.path.segments.len() == 1 {
4104+ let n = p.path.segments[0].ident.to_string();
4105+ if let Some(t) = self.pending_lets.get(&n).cloned() {
4106+ *out = Some(t);
4107+ return;
4108+ }
4109+ }
4110+ }
4111+ }
4112+ self.find_peer_expr(name, &a.right, out)
4085 }4113 }
4086- Expr::Assign(a) => self.find_peer_expr(name, &a.right, out),
4087 Expr::Index(ix) => {4114 Expr::Index(ix) => {
4088 // `xs[i]` makes `i` an index, which says nothing about width.4115 // `xs[i]` makes `i` an index, which says nothing about width.
4089 self.find_peer_expr(name, &ix.expr, out);4116 self.find_peer_expr(name, &ix.expr, out);
@@ -4815,7 +4842,24 @@ impl Lowerer {
4815 return Err("a `for` over an unbounded range would not terminate".into())4842 return Err("a `for` over an unbounded range would not terminate".into())
4816 }4843 }
4817 };4844 };
4818- let ty = lo.ty.clone().or(hi.ty.clone());4845+ // `0..n` is `n`'s type, not the literal's. A bare bound says
4846+ // only what Rust defaults to, so the other end decides -- and
4847+ // the literal is then re-lowered to match, or Nim compares an
4848+ // `int32` against a `uint`.
4849+ let lo_bare = r.start.as_deref().is_some_and(is_bare_literal);
4850+ let hi_bare = r.end.as_deref().is_some_and(is_bare_literal);
4851+ let ty = match (lo_bare, hi_bare) {
4852+ (true, false) => hi.ty.clone().or(lo.ty.clone()),
4853+ _ => lo.ty.clone().or(hi.ty.clone()),
4854+ };
4855+ let lo = match (&ty, r.start.as_deref()) {
4856+ (Some(t), Some(e)) if lo_bare => self.expr_at(e, Some(t))?,
4857+ _ => lo,
4858+ };
4859+ let hi = match (&ty, r.end.as_deref()) {
4860+ (Some(t), Some(e)) if hi_bare && !lo_bare => self.expr_at(e, Some(t))?,
4861+ _ => hi,
4862+ };
4819 Ok(Iter::Range {4863 Ok(Iter::Range {
4820 lo: lo.code,4864 lo: lo.code,
4821 hi: hi.code,4865 hi: hi.code,