Skip to content

Commit b0abc2b

Browse files
committed
Properly track gradual types in for comprehensions :into
1 parent 1f9256a commit b0abc2b

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

lib/elixir/lib/module/types/expr.ex

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -351,20 +351,20 @@ defmodule Module.Types.Expr do
351351
{dynamic(), context}
352352
else
353353
into = Keyword.get(opts, :into, [])
354-
{into_wrapper, context} = for_into(into, meta, stack, context)
354+
{into_wrapper, gradual?, context} = for_into(into, meta, stack, context)
355355
{block_type, context} = of_expr(block, stack, context)
356356

357357
for_type =
358358
for type <- into_wrapper do
359359
case type do
360360
:binary -> binary()
361361
:list -> list(block_type)
362-
:dynamic -> dynamic()
362+
:term -> term()
363363
end
364364
end
365365
|> Enum.reduce(&union/2)
366366

367-
{for_type, context}
367+
{if(gradual?, do: dynamic(for_type), else: for_type), context}
368368
end
369369
end
370370

@@ -523,20 +523,20 @@ defmodule Module.Types.Expr do
523523
@into_compile union(binary(), empty_list())
524524

525525
defp for_into([], _meta, _stack, context),
526-
do: {[:list], context}
526+
do: {[:list], false, context}
527527

528528
defp for_into(binary, _meta, _stack, context) when is_binary(binary),
529-
do: {[:binary], context}
529+
do: {[:binary], false, context}
530530

531531
# TODO: Use the collectable protocol for the output
532532
defp for_into(into, meta, stack, context) do
533533
{type, context} = of_expr(into, stack, context)
534534

535535
if subtype?(type, @into_compile) do
536536
case {binary_type?(type), empty_list_type?(type)} do
537-
{false, true} -> {[:list], context}
538-
{true, false} -> {[:binary], context}
539-
{_, _} -> {[:binary, :list], context}
537+
{false, true} -> {[:list], gradual?(type), context}
538+
{true, false} -> {[:binary], gradual?(type), context}
539+
{_, _} -> {[:binary, :list], gradual?(type), context}
540540
end
541541
else
542542
meta =
@@ -547,7 +547,7 @@ defmodule Module.Types.Expr do
547547

548548
expr = {:__block__, [type_check: :into] ++ meta, [into]}
549549
{_type, context} = Apply.remote(Collectable, :into, [into], [type], expr, stack, context)
550-
{[:dynamic], context}
550+
{[:term], true, context}
551551
end
552552
end
553553

lib/elixir/test/elixir/module/types/expr_test.exs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,22 @@ defmodule Module.Types.ExprTest do
14431443
assert typecheck!([enum], for(x <- enum, do: x, into: [])) == list(dynamic())
14441444
assert typecheck!([enum], for(x <- enum, do: x, into: "")) == binary()
14451445
assert typecheck!([enum, other], for(x <- enum, do: x, into: other)) == dynamic()
1446+
1447+
assert typecheck!(
1448+
[binary],
1449+
(
1450+
into = if :rand.uniform() > 0.5, do: [], else: "0"
1451+
for(<<x::float <- binary>>, do: x, into: into)
1452+
)
1453+
) == union(binary(), list(float()))
1454+
1455+
assert typecheck!(
1456+
[binary, empty_list = []],
1457+
(
1458+
into = if :rand.uniform() > 0.5, do: empty_list, else: "0"
1459+
for(<<x::float <- binary>>, do: x, into: into)
1460+
)
1461+
) == dynamic(union(binary(), list(float())))
14461462
end
14471463
end
14481464

0 commit comments

Comments
 (0)