Skip to content

Tighten semantics of numeric#32

Merged
liufengyun merged 47 commits into
mainfrom
numeric
Jun 18, 2026
Merged

Tighten semantics of numeric#32
liufengyun merged 47 commits into
mainfrom
numeric

Conversation

@liufengyun

@liufengyun liufengyun commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

The type Int is currently up to platform interpretation, it creates portability concerns similar to C.

What has changed

  • Standardize Int to 32 bits
  • Introduce Long for 64 bits
  • Standardize truncating semantics of / and % (matters when negative numbers involved)
  • Change Byte to be unsigned (same as in C#)
  • Added ~ for Int and Long

Alternative

We could follow Ruby/Python to make infinite precision integer as the default, and introduce int32 and int64 separately. That is a reasonable design for usability.

However, it makes language interoperability for Java/JS complex: an int literal 3 is no longer the default type of the target platform. Given that the use case of infinite precision arithmetic is rare, we need to optimize for platform interoperability here.

Testing

  • Added / updated tests under tests/pos/ or tests/warn/
  • Ran ./ci locally and all tests pass
  • Docs updated if the change affects user-visible behavior
  • All commits are signed off (why?)
How to sign off commits

Use git commit -s to add the Signed-off-by line automatically:

To add a sign-off to the last commit retroactively:

git commit --amend -s --no-edit

To add sign-off to the last 3 commits:

git rebase --signoff HEAD~3

Security impact

No

@liufengyun

Copy link
Copy Markdown
Contributor Author

@Radeonares32 This PR fixes the semantics of / and %. Would you like to take a look?

@Radeonares32

Copy link
Copy Markdown
Contributor

Thanks, this is a nice cleanup. I found a couple of backend issues before approval:

  1. Python/Ruby class tests need to handle Long. Long is represented as Python int / Ruby Integer, but ClassTest currently maps only Int/Byte/Char to those runtime types. Since Long is documented as usable in union types, x is Long / union matching can miscompile on Python and Ruby.

  2. Ruby Long division reuses the compiled receiver and argument expressions in (a - a.remainder(b)).div(b). If either operand has side effects, Ruby will evaluate it more than once. This should bind operands to temporaries or otherwise preserve single evaluation.

Minor: lib/Long.jo says 1 << 31 is the most-negative Long value; that should be 1 << 63.

@liufengyun

Copy link
Copy Markdown
Contributor Author

Thank you very much, @Radeonares32 . I've addressed your feedback and added tests to prevent regression.

Comment thread lib/Int.jo Outdated
Comment thread stack-lang/ruby/Printer.scala
Comment thread stack-lang/ruby/RubyCodeGen.scala
@liufengyun liufengyun merged commit bd14b0f into main Jun 18, 2026
3 checks passed
@liufengyun liufengyun deleted the numeric branch June 18, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants