-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Fix macro interpreter Number type of arithmetic expressions #5972
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome 👍
Though it seems CI failed... |
That's odd... need to investigate. |
src/compiler/crystal/syntax/ast.cr
Outdated
@@ -228,6 +228,24 @@ module Crystal | |||
|
|||
def_equals value.to_f64, kind | |||
def_hash value, kind | |||
|
|||
def self.kind_from_number(number : Number) | |||
case number.class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this just need to get rid of the .class
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, doing number.class
causes it to raise:
# with case number.class
kind_from_number 1_u64 # => Unsupported Number type for NumberLiteral: UInt64 (Exception)
# with case number
kind_from_number(1_u64) # => :uint64
@@ -214,8 +214,8 @@ module Crystal | |||
def initialize(@value : String, @kind = :i32) | |||
end | |||
|
|||
def initialize(value : Number, @kind = :i32) | |||
@value = value.to_s | |||
def self.new(value : Number) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not continue to accept .new(Number, kind: Symbol)
, but have .new(Number)
take the type of the number. This way you don't need the to_s
additions above (they all have explicit kind anyway).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this would be that useful. It's a simple API now: If the constructor receives a Number
, it deduces kind
accordingly. Otherwise you need to specify value
(as string) and kind
explicitly.
@@ -228,6 +228,24 @@ module Crystal | |||
|
|||
def_equals value.to_f64, kind | |||
def_hash value, kind | |||
|
|||
def self.kind_from_number(number : Number) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the only usage of kind_from_number
? or there are plans to reuse it somewhere else?
Asking this because either make it protected/private or add :nodoc:
.
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Atm it is the only usage, I don't know if it there is a different use case.
Compiler types and methods are not really documented anyway, so there is not much gain from adding :nodoc:
.
I don't think there are any particular guidelines about this for the compiler.
Seems like this change struck something else... might be a hidden bug? I don't know anything about Crystal's codegen. |
You'll have to dump the LL and see what's going on. This PR probably broke something. When that breaks the compiler it's nightmare debugging time. Good luck :-) |
I had to disable LLVM module validation in order to dump the IR, otherwise it would fail during validation and don't output anything. Then I used a modified compiler including this patch to compare it's LLVM IR of an empty crystal file to the compiler v0.24.2. It looks like this patch added explicit type information to int values which were previously omitted. For example, with this patch, the IR for ; v0.24.2:
%2 = add i32 %1, 12, !dbg !413
; this patch:
%2 = add i32 %1, i64 12, !dbg !1624 |
It seems like the error was caused by Setting But in general, shouldn't the codegen step identify such mismatching types in operations and convert them? |
e621329
to
3b67c54
Compare
@@ -699,7 +699,7 @@ module Crystal | |||
end | |||
|
|||
if value | |||
NumberLiteral.new(value) | |||
NumberLiteral.new(value.to_s, :i32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few line above the value is converted to an Int64
(@value.to_i64?
), it feels weird to 'cast' it to :i32
here, is it intentional ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is intentional as far as this prevents codegen to fail. 🤷♂️ It's only a workaround, though.
In fact, this isn't even a change: it implicitly was :i32
before, now it's just explicit.
But yes, it should probably be adjusted, however we need to fix the codegen bug first.
@@ -2469,7 +2469,7 @@ module Crystal | |||
# (useful for sizeof inside as a generic type argument, but also | |||
# to make it easier for LLVM to optimize things) | |||
if !node.exp.is_a?(TypeOf) | |||
expanded = NumberLiteral.new(@program.size_of(type.sizeof_type)) | |||
expanded = NumberLiteral.new(@program.size_of(type.sizeof_type).to_s, :i32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment to explain why it's important to make them :i32
here?
(and ditto below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't even really know, why exactly this is necessary. 😅 The type restriction can be removed when codegen bug is fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no codegen bug. It was working previously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's no bug, why are the second and third commit necessary? Maybe I'm missing something... but it feels to me that these types should automatically be adjusted.
The reason for this seems to be that at the codegen stage there is no explicit enforcement of operand types for numerical operations such as
Example: {{ -1_i64 }} * 12_u8 # => -12_i64
12_u8 * {{ -1_i64 }} # => 244_u8 This PR doesn't even fix the example (yet), it only treated the symptoms in some places. The condition for this bug is that the first operand is a primitive and the seconds operand (call argument) is a I'll try to fix it by adding an additional type check (and conversion, if necessary) in Actually, there is already |
|
@asterite Yes, such large sizes don't make much sense. But why does But regardless of the kind used in the |
yeah |
@straight-shoota Oh, I think I understand now what you think is a compiler bug. Note this line:
Here the compiler is basically "inferring" (or hardcoding) the type of Does that make sense? |
Ah, okay that type is then passed to |
So, then it's probably good to merge? |
Yes, but travis doesn't agree |
Just ignore travis 😁 It seems to be an unrelated memory issue. Or trigger a re-run. |
@straight-shoota nope, now it's related to recently merged #5954 (see https://travis-ci.org/crystal-lang/crystal/jobs/369805514#L543-L548). |
Oh, that's different now. The question is: Why does this only raise on travis 64-bit? Or rather, why does this raise at all? This PR hasn't even been rebased to include #5954! |
I guess it's because the CI script tries to run the master's spec at some point (.. huh no I don't know) Can you rebase? |
3b67c54
to
f1570f9
Compare
Rebased |
@straight-shoota can you fix the conflicts? |
f1570f9
to
4f66593
Compare
NumberLiteral
constructor receiving the value as aNumber
now uses the number type to determine it'skind
. The few cases where a specific other type is required are changed to use the constructor receivingString
plus explicitkind
.Fixes #5971