Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Using the first type of a union type as the type of the result of
`Enumerable#sum()` call can cause runtime failures.  A safer alternative
is to flag the use of union types with `Enumerable#sum()` and suggest
the use of `Enumerable#sum(initial)` with an initial value of the
expected type of the `sum` call.
  • Loading branch information
rvprasad committed Dec 22, 2024
1 parent b6b190f commit 430f811
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
13 changes: 13 additions & 0 deletions spec/std/enumerable_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "spec"
require "spec/helpers/iterate"
require "../spec_helper"

module SomeInterface; end

Expand Down Expand Up @@ -1364,6 +1365,18 @@ describe "Enumerable" do
it { [1, 2, 3].sum(4.5).should eq(10.5) }
it { (1..3).sum { |x| x * 2 }.should eq(12) }
it { (1..3).sum(1.5) { |x| x * 2 }.should eq(13.5) }
it { [1, 3_u64].sum(0_i32).should eq(4) }
it { [1, 3].sum(0_u64).should eq(4) }
it { [1, 10000000000_u64].sum(0_u64).should eq(10000000001) }
it "raises if union types are summed" do
exc = assert_error <<-CRYSTAL,
require "prelude"
[1, 10000000000_u64].sum
CRYSTAL
"Enumerable#sum() does support Union types. Instead, " +
"use Enumerable#sum(initial) with an initial value of " +
"the expected type of the sum call."
end

it "uses additive_identity from type" do
typeof([1, 2, 3].sum).should eq(Int32)
Expand Down
6 changes: 5 additions & 1 deletion src/enumerable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2292,7 +2292,11 @@ module Enumerable(T)
# if the type is a union.
def self.first
{% if X.union? %}
{{X.union_types.first}}
{{
raise("Enumerable#sum() does support Union types. Instead, " +
"use Enumerable#sum(initial) with an initial value of " +
"the expected type of the sum call.")
}}
{% else %}
X
{% end %}
Expand Down

0 comments on commit 430f811

Please sign in to comment.