Skip to content

Commit c20f80b

Browse files
author
Lillian Zhang
committed
Call divmod when coercion to Float fails for sleep
`sleep': can't convert ActiveSupport::Duration into Float Is the TypeError TruffleRuby gives when the follow is run: ``` require "active_support/core_ext/numeric/time" p sleep(0.2.second) ``` In contrast, this prints 0 in MRI 2.6.5 and 2.7.1 (though weirdly prints 1 in 3.0.0). This is because when the argument to sleep is not a fixnum, float, or bignum, it will call .divmod(1) (https://github.com/ruby/ruby/blob/master/time.c#L2556-L2627). This PR calls divmod instead of to_f (and thus NumericToFloatNode can be removed).
1 parent 7b18925 commit c20f80b

File tree

3 files changed

+21
-70
lines changed

3 files changed

+21
-70
lines changed

src/main/java/org/truffleruby/core/cast/DurationToMillisecondsNode.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,24 @@
99
*/
1010
package org.truffleruby.core.cast;
1111

12+
import com.oracle.truffle.api.CompilerDirectives;
13+
import com.oracle.truffle.api.dsl.Cached;
1214
import org.truffleruby.language.Nil;
1315
import org.truffleruby.language.RubyContextSourceNode;
1416
import org.truffleruby.language.NotProvided;
1517
import org.truffleruby.language.RubyDynamicObject;
1618
import org.truffleruby.language.RubyNode;
1719
import org.truffleruby.language.control.RaiseException;
1820

19-
import com.oracle.truffle.api.CompilerDirectives;
2021
import com.oracle.truffle.api.dsl.NodeChild;
2122
import com.oracle.truffle.api.dsl.Specialization;
2223
import com.oracle.truffle.api.profiles.ConditionProfile;
24+
import org.truffleruby.language.dispatch.DispatchNode;
2325

2426
@NodeChild(value = "duration", type = RubyNode.class)
2527
public abstract class DurationToMillisecondsNode extends RubyContextSourceNode {
2628

27-
@Child NumericToFloatNode floatCastNode;
29+
@Child private DispatchNode durationToMilliseconds;
2830

2931
private final ConditionProfile durationLessThanZeroProfile = ConditionProfile.create();
3032
private final boolean acceptsNil;
@@ -65,12 +67,17 @@ protected long durationNil(Nil duration) {
6567
}
6668

6769
@Specialization
68-
protected long duration(RubyDynamicObject duration) {
69-
if (floatCastNode == null) {
70+
protected Object duration(RubyDynamicObject duration,
71+
@Cached ToLongNode toLongNode) {
72+
if (durationToMilliseconds == null) {
7073
CompilerDirectives.transferToInterpreterAndInvalidate();
71-
floatCastNode = insert(NumericToFloatNodeGen.create());
74+
durationToMilliseconds = insert(DispatchNode.create());
7275
}
73-
return duration(floatCastNode.executeDouble(duration));
76+
77+
return toLongNode.execute(durationToMilliseconds.call(
78+
coreLibrary().truffleKernelOperationsModule,
79+
"convert_duration_to_milliseconds",
80+
duration));
7481
}
7582

7683
private long validate(long durationInMillis) {

src/main/java/org/truffleruby/core/cast/NumericToFloatNode.java

Lines changed: 0 additions & 64 deletions
This file was deleted.

src/main/ruby/truffleruby/core/truffle/kernel_operations.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ def self.to_enum_with_size(enum, method, size_method)
2222
enum.to_enum(method) { enum.send(size_method) }
2323
end
2424

25+
def self.convert_duration_to_milliseconds(duration)
26+
unless duration.respond_to?(:divmod)
27+
raise TypeError, "can't convert #{duration.class} into time interval"
28+
end
29+
a,b = duration.divmod(1)
30+
((a + b) * 1000)
31+
end
32+
2533
def self.define_hooked_variable(name, getter, setter, defined = proc { 'global-variable' })
2634
define_hooked_variable_with_is_defined(name, getter, setter, defined)
2735
end

0 commit comments

Comments
 (0)