Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Int+ instantiated when upcasting integer to Steppable #11131

Open
HertzDevil opened this issue Aug 24, 2021 · 0 comments
Open

Int+ instantiated when upcasting integer to Steppable #11131

HertzDevil opened this issue Aug 24, 2021 · 0 comments

Comments

@HertzDevil
Copy link
Contributor

HertzDevil commented Aug 24, 2021

The following:

puts 1.as(Steppable)

fails with:

In test.cr:1:1

 1 | puts 1.as(Steppable)
     ^---
Error: instantiating 'puts(Steppable)'


In src/kernel.cr:386:10

 386 | STDOUT.puts *objects
              ^---
Error: instantiating 'IO::FileDescriptor#puts(Tuple(Steppable))'


In src/io.cr:231:10

 231 | self << obj
            ^-
Error: instantiating 'IO::FileDescriptor#<<(Steppable)'


In src/io.cr:174:9

 174 | obj.to_s self
           ^---
Error: instantiating 'Steppable#to_s(IO::FileDescriptor)'


In src/int.cr:714:7

 714 | internal_to_s(base, precision, upcase) do |ptr, count, negative|
       ^------------
Error: instantiating 'internal_to_s(Int32, Int32, Bool)'


In src/int.cr:739:30

 739 | ptr.value = digits[num.remainder(base).abs]
                              ^--------
Error: instantiating 'Int+#remainder(Int32)'


In src/int.cr:180:5

 180 | {% begin %}
       ^
Error: expanding macro


There was a problem expanding macro 'macro_139621983084256'

Called macro defined in src/int.cr:180:5

 180 | {% begin %}

Which expanded to:

 >  1 | 
 >  2 |       if other == 0
 >  3 |         raise DivisionByZeroError.new
 >  4 |       elsif self < 0 && self == Int::MIN && other == -1
 >  5 |         self.class.new(0)
 >  6 |       else
 >  7 |         unsafe_mod other
 >  8 |       end
 >  9 |     
Error: undefined constant Int::MIN

It appears that #remainder is instantiated with the virtual type Int+ as the receiver. Reduced:

module Foo
end

abstract struct Int
  include Foo

  def foo
    {% p @type %} # => UInt128 Int128 UInt64 Int64 UInt32 Int32 UInt16 Int16 UInt8 Int8 Int
    remainder(2)
  end
end

1.as(Foo).foo # Error: undefined constant Int::MIN

Normally this is expected behaviour:

module Foo
end

abstract class Bar
  include Foo

  def foo
    {% p @type %} # => Bar
  end
end

class Baz < Bar
end

Baz.new.as(Bar).foo

But Int is special because it cannot be used as the type of a variable; there is simply no way to call Int+#remainder during runtime, so the compiler should never have to instantiate this overload. (However, if remainder were a class method then it is still possible to call Int+.remainder.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant