Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3513,6 +3513,8 @@ infer-test: $(SPINEL) $(SP_RT_LIB)
grep -E '^#define _SP_HCR' "$$tmp/lahc.c" | grep -q 'lv_cur\b' && { echo "infer-test: FAIL (an array local the loop reassigns was read through a cached header)"; ok=0; }; \
grep -E '^#define _SP_HCR' "$$tmp/lahc.c" | grep -q 'self->iv_v\b' && { echo "infer-test: FAIL (an ivar the loop writes was read through a cached header)"; ok=0; }; \
grep -qE '^#define _SP_HCR[0-9]+\(\) .*lv_qv.*lv_qk.*lv_qs' "$$tmp/lahc.c" || { echo "infer-test: FAIL (a class test on a scalar kept a loop from caching its arrays' headers)"; ok=0; }; \
$(SPINEL) test/poly_user_relop_no_coerce.rb -c --no-line-map -o "$$tmp/urn.c" >/dev/null 2>&1 || { echo "infer-test: FAIL (poly_user_relop_no_coerce: -c)"; ok=0; }; \
grep -q 'SP_INSTALL_HOOK(sp_user_binop_hook, sp_user_binop_dispatch);' "$$tmp/urn.c" || { echo "infer-test: FAIL (a class ordering itself with < and no coerce has no binop table for a boxed comparison)"; ok=0; }; \
$(SPINEL) test/loop_bounded_index_read.rb -c --no-line-map -o "$$tmp/lbi.c" >/dev/null 2>&1 || { echo "infer-test: FAIL (loop_bounded_index_read: -c)"; ok=0; }; \
grep -qE '_hcd[0-9]+_[0-9]+\[lv_i\]' "$$tmp/lbi.c" && grep -qE '_hcd[0-9]+_[0-9]+\[lv_j\]' "$$tmp/lbi.c" || { echo "infer-test: FAIL (a read bounded by its loop's own i < a.length test still tests its index)"; ok=0; }; \
grep -qE '_hcd[0-9]+_[0-9]+\[lv_(m|q|r|w|x|y|z)\]' "$$tmp/lbi.c" && { echo "infer-test: FAIL (a read whose index the loop does not keep in range lost its bounds test)"; ok=0; }; \
Expand Down
4 changes: 4 additions & 0 deletions src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -16615,6 +16615,10 @@ char *codegen_program(const NodeTable *nt) {
if (!c->classes[k].instantiated && !breopen) continue;
for (int u = 0; uops[u]; u++)
if (comp_method_in_chain(c, k, uops[u], NULL) >= 0) { g_has_user_binop = 1; break; }
/* A class's own <, >, <= or >= reaches a boxed receiver through the
table even without coerce; sp_poly_cmp cannot supply its ordering. */
for (int u = 0; cops[u] && !g_has_user_binop; u++)
if (is_cmp_op(cops[u]) && comp_method_in_chain(c, k, cops[u], NULL) >= 0) g_has_user_binop = 1;
/* a `<=>` with no `==` is Comparable's equality, which the table
derives: a boxed `m == n` (a block parameter, a hash value, a
`when FIVE`) reaches it only through the table */
Expand Down
24 changes: 24 additions & 0 deletions test/poly_user_relop_no_coerce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# A class that defines its own <, >, <= or >= -- and no coerce -- orders its
# instances when they arrive boxed (out of a mixed Array, a poly local or
# parameter): the comparison reaches the user method through the binop
# table, as `+` and `==` always did, where it raised "comparison of Money
# with Money failed". Numbers beside them keep comparing as numbers, and a
# subclass answers through the method it inherits.
class Money
attr_reader :c
def initialize(c)
@c = c
end
def <(o) = c < o.c
def >(o) = c > o.c
def <=(o) = c <= o.c ? :le : nil
def >=(o) = c >= o.c
end
class Euro < Money; end

vals = [Money.new(1), 3, Euro.new(5), 2.5]
p vals[0] < vals[2], vals[2] > vals[0], vals[0] <= vals[2], vals[2] <= vals[0], vals[2] >= Money.new(5)
p vals[1] < vals[3], vals[3] > vals[1]
def lt(a, b) = a < b
p lt(vals[0], vals[2]), lt(vals[1], 4)
p vals.select { |v| v.is_a?(Money) }.sort { |a, b| a > b ? -1 : 1 }.map(&:c)
10 changes: 10 additions & 0 deletions test/poly_user_relop_no_coerce.rb.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
true
true
:le
nil
true
false
false
true
true
[5, 1]
Loading