@@ -3576,6 +3576,22 @@ defmodule Module.Types.ExprTest do
35763576 assert typecheck! ( [ enum , other ] , for ( x <- enum , do: x , into: other ) ) == dynamic ( )
35773577 end
35783578
3579+ test ":into bitstrings" do
3580+ assert typecheck! ( [ items ] , for ( _ <- items , into: << 0 :: 4 >> , do: << 1 :: 4 >> ) ) == bitstring ( )
3581+
3582+ assert typecheck! (
3583+ [ items ] ,
3584+ (
3585+ bits = for _ <- items , into: << 0 :: 4 >> , do: << 1 :: 4 >>
3586+
3587+ case bits do
3588+ x when is_binary ( x ) -> :binary
3589+ _ -> :bits
3590+ end
3591+ )
3592+ ) == atom ( [ :binary , :bits ] )
3593+ end
3594+
35793595 test ":into unions" do
35803596 assert typecheck! (
35813597 [ binary ] ,
@@ -3595,22 +3611,18 @@ defmodule Module.Types.ExprTest do
35953611 dynamic (
35963612 opt_union ( opt_union ( bitstring ( ) , empty_list ( ) ) , list ( bitstring_no_binary ( ) ) )
35973613 )
3598- end
3599-
3600- test ":into bitstrings" do
3601- assert typecheck! ( [ items ] , for ( _ <- items , into: << 0 :: 4 >> , do: << 1 :: 4 >> ) ) == bitstring ( )
36023614
36033615 assert typecheck! (
3604- [ items ] ,
3616+ [ value ] ,
36053617 (
3606- bits = for _ <- items , into: << 0 :: 4 >> , do: << 1 :: 4 >>
3607-
3608- case bits do
3609- x when is_binary ( x ) -> :binary
3610- _ -> :bits
3611- end
3618+ into = if :rand . uniform ( ) > 0.5 , do: [ ] , else: ""
3619+ for ( _ <- [ 1 ] , do: value , into: into )
3620+ )
3621+ ) ==
3622+ opt_union (
3623+ dynamic ( opt_union ( bitstring_no_binary ( ) , non_empty_list ( term ( ) ) ) ) ,
3624+ opt_union ( binary ( ) , empty_list ( ) )
36123625 )
3613- ) == atom ( [ :binary , :bits ] )
36143626 end
36153627
36163628 test ":into inference" do
@@ -3647,6 +3659,77 @@ defmodule Module.Types.ExprTest do
36473659 # from: types_test.ex:LINE
36483660 <<x>>
36493661 """
3662+
3663+ # In static mode the body must be a bitstring whenever the target may be a binary
3664+ assert typeerror! (
3665+ [ flag ] ,
3666+ (
3667+ into = if flag , do: [ ] , else: ""
3668+ value = if flag , do: :ok , else: "ok"
3669+ for ( _ <- [ 1 ] , do: value , into: into )
3670+ )
3671+ ) =~ ~l"""
3672+ expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring):
3673+
3674+ value
3675+
3676+ but got type:
3677+
3678+ :ok or binary()
3679+ """
3680+
3681+ assert typeerror! (
3682+ [ flag ] ,
3683+ (
3684+ into = if flag , do: [ ] , else: ""
3685+ for ( _ <- [ 1 ] , do: :ok , into: into )
3686+ )
3687+ ) =~ ~l"""
3688+ expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring):
3689+
3690+ :ok
3691+
3692+ but got type:
3693+
3694+ :ok
3695+ """
3696+
3697+ assert typeerror! (
3698+ [ flag ] ,
3699+ (
3700+ value = if flag , do: :ok , else: "ok"
3701+ for ( _ <- [ 1 ] , do: value , into: "" )
3702+ )
3703+ ) =~ ~l"""
3704+ expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring):
3705+
3706+ value
3707+
3708+ but got type:
3709+
3710+ :ok or binary()
3711+ """
3712+ end
3713+
3714+ test ":into dynamic" do
3715+ # In dynamic mode the list path may succeed, so the body is not restricted
3716+ # to bitstrings and the list result keeps the full element type
3717+ assert typedyn! (
3718+ [ flag ] ,
3719+ (
3720+ into = if flag , do: [ ] , else: ""
3721+ value = if flag , do: :ok , else: "ok"
3722+ for ( _ <- [ 1 ] , do: value , into: into )
3723+ )
3724+ ) == dynamic ( opt_union ( binary ( ) , list ( opt_union ( atom ( [ :ok ] ) , binary ( ) ) ) ) )
3725+
3726+ assert typedyn! (
3727+ [ flag ] ,
3728+ (
3729+ into = if flag , do: [ ] , else: ""
3730+ for ( _ <- [ 1 ] , do: :ok , into: into )
3731+ )
3732+ ) == dynamic ( opt_union ( binary ( ) , list ( atom ( [ :ok ] ) ) ) )
36503733 end
36513734
36523735 test ":into with non-returning collectable" do
0 commit comments