diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr index 12f3c79dff01..ee0d4c9728c6 100644 --- a/spec/compiler/macro/macro_methods_spec.cr +++ b/spec/compiler/macro/macro_methods_spec.cr @@ -637,6 +637,18 @@ module Crystal assert_macro %({{"1234".to_i(16)}}), %(4660) end + it "adds correct number kind on to_i (#16467)" do + assert_macro %({{"0".to_i.kind}}), %(:i32) + assert_macro %({{"2147483647".to_i.kind}}), %(:i32) + assert_macro %({{"2147483648".to_i.kind}}), %(:i64) + assert_macro %({{"123456789012345".to_i.kind}}), %(:i64) + assert_macro %({{"7fffffffffffffff".to_i(16).kind}}), %(:i64) + assert_macro %({{"-2147483648".to_i.kind}}), %(:i32) + assert_macro %({{"-2147483649".to_i.kind}}), %(:i64) + assert_macro %({{"-123456789012345".to_i.kind}}), %(:i64) + assert_macro %({{"-8000000000000000".to_i(16).kind}}), %(:i64) + end + it "executes string includes? char (true)" do assert_macro %({{"spice".includes?('s')}}), %(true) assert_macro %({{"spice".includes?('p')}}), %(true) diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr index 6e1c269e33af..1cd14daeb0c1 100644 --- a/src/compiler/crystal/macros.cr +++ b/src/compiler/crystal/macros.cr @@ -102,8 +102,12 @@ private macro def_string_methods(klass) def titleize : {{klass}} end - # Similar to `String#to_i`. - def to_i(base = 10) + # Similar to `String#to_i64`. + # + # The returned `NumberLiteral` has the `:i32` kind if it fits into `Int32`'s + # range, and the `:i64` kind otherwise. This matches the behavior of + # suffix-less number literals in Crystal. + def to_i(base : NumberLiteral = 10) : NumberLiteral end # Returns an expression that evaluates to a slice literal containing the diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr index 302216137f40..c912d1ad1b8f 100644 --- a/src/compiler/crystal/macros/methods.cr +++ b/src/compiler/crystal/macros/methods.cr @@ -900,7 +900,11 @@ module Crystal end if value - NumberLiteral.new(value.to_s, :i32) + if value.in?(Int32::MIN..Int32::MAX) + NumberLiteral.new(value.to_s, :i32) + else + NumberLiteral.new(value.to_s, :i64) + end else raise "StringLiteral#to_i: #{@value} is not an integer" end