@@ -122,9 +122,8 @@ defmodule Module.Types.Expr do
122122 end
123123
124124 # <<...>>>
125- def of_expr ( { :<<>> , _meta , args } , _expected , _expr , stack , context ) do
126- context = Of . binary ( args , :expr , stack , context )
127- { binary ( ) , context }
125+ def of_expr ( { :<<>> , meta , args } , _expected , _expr , stack , context ) do
126+ Of . bitstring ( meta , args , :expr , stack , context )
128127 end
129128
130129 def of_expr ( { :__CALLER__ , _meta , var_context } , _expected , _expr , _stack , context )
@@ -315,7 +314,7 @@ defmodule Module.Types.Expr do
315314 |> dynamic_unless_static ( stack )
316315 end
317316
318- # TODO: fn pat -> expr end
317+ # fn pat -> expr end
319318 def of_expr ( { :fn , _meta , clauses } , _expected , _expr , stack , context ) do
320319 [ { :-> , _ , [ head , _ ] } | _ ] = clauses
321320 { patterns , _guards } = extract_head ( head )
@@ -416,20 +415,26 @@ defmodule Module.Types.Expr do
416415 else
417416 # TODO: Use the collectable protocol for the output
418417 into = Keyword . get ( opts , :into , [ ] )
419- { into_wrapper , gradual? , context } = for_into ( into , meta , stack , context )
418+ { into_type , into_kind , context } = for_into ( into , meta , stack , context )
420419 { block_type , context } = of_expr ( block , @ pending , block , stack , context )
421420
422- for_type =
423- for type <- into_wrapper do
424- case type do
425- :binary -> binary ( )
426- :list -> list ( block_type )
427- :term -> term ( )
421+ case into_kind do
422+ :bitstring ->
423+ case compatible_intersection ( block_type , bitstring ( ) ) do
424+ { :ok , intersection } ->
425+ { return_union ( into_type , intersection , stack ) , context }
426+
427+ { :error , _ } ->
428+ error = { :badbitbody , block_type , block , context }
429+ { error_type ( ) , error ( __MODULE__ , error , meta , stack , context ) }
428430 end
429- end
430- |> Enum . reduce ( & union / 2 )
431431
432- { if ( gradual? , do: dynamic ( for_type ) , else: for_type ) , context }
432+ :non_empty_list ->
433+ { return_union ( into_type , non_empty_list ( block_type ) , stack ) , context }
434+
435+ :none ->
436+ { into_type , context }
437+ end
433438 end
434439 end
435440
@@ -469,7 +474,7 @@ defmodule Module.Types.Expr do
469474 apply_many ( mods , name , args , expected , call , stack , context )
470475 end
471476
472- # TODO: &Foo.bar/1
477+ # &Foo.bar/1
473478 def of_expr (
474479 { :& , _ , [ { :/ , _ , [ { { :. , _ , [ remote , name ] } , meta , [ ] } , arity ] } ] } = call ,
475480 _expected ,
@@ -483,7 +488,7 @@ defmodule Module.Types.Expr do
483488 Apply . remote_capture ( mods , name , arity , meta , stack , context )
484489 end
485490
486- # TODO: &foo/1
491+ # &foo/1
487492 def of_expr ( { :& , _meta , [ { :/ , _ , [ { fun , meta , _ } , arity ] } ] } , _expected , _expr , stack , context ) do
488493 Apply . local_capture ( fun , arity , meta , stack , context )
489494 end
@@ -577,13 +582,13 @@ defmodule Module.Types.Expr do
577582 end
578583
579584 defp for_clause ( { :<<>> , _ , [ { :<- , meta , [ left , right ] } ] } = expr , stack , context ) do
580- { right_type , context } = of_expr ( right , binary ( ) , expr , stack , context )
581- context = Pattern . of_generator ( left , [ ] , binary ( ) , :for , expr , stack , context )
585+ { right_type , context } = of_expr ( right , bitstring ( ) , expr , stack , context )
586+ context = Pattern . of_generator ( left , [ ] , bitstring ( ) , :for , expr , stack , context )
582587
583- if compatible? ( right_type , binary ( ) ) do
588+ if compatible? ( right_type , bitstring ( ) ) do
584589 context
585590 else
586- error = { :badbinary , right_type , right , context }
591+ error = { :badbitgenerator , right_type , right , context }
587592 error ( __MODULE__ , error , meta , stack , context )
588593 end
589594 end
@@ -593,13 +598,13 @@ defmodule Module.Types.Expr do
593598 context
594599 end
595600
596- @ into_compile union ( binary ( ) , empty_list ( ) )
601+ @ into_compile union ( bitstring ( ) , empty_list ( ) )
597602
598603 defp for_into ( [ ] , _meta , _stack , context ) ,
599- do: { [ :list ] , false , context }
604+ do: { empty_list ( ) , :non_empty_list , context }
600605
601606 defp for_into ( binary , _meta , _stack , context ) when is_binary ( binary ) ,
602- do: { [ : binary] , false , context }
607+ do: { binary ( ) , :bitstring , context }
603608
604609 defp for_into ( into , meta , stack , context ) do
605610 meta =
@@ -616,21 +621,33 @@ defmodule Module.Types.Expr do
616621 { type , context } = of_expr ( into , domain , expr , stack , context )
617622
618623 # We use subtype? instead of compatible because we want to handle
619- # only binary /list, even if a dynamic with something else is given.
624+ # only bitstring /list, even if a dynamic with something else is given.
620625 if subtype? ( type , @ into_compile ) do
621- case { binary_type? ( type ) , empty_list_type? ( type ) } do
622- { false , true } -> { [ :list ] , gradual? ( type ) , context }
623- { true , false } -> { [ :binary ] , gradual? ( type ) , context }
624- { _ , _ } -> { [ :binary , :list ] , gradual? ( type ) , context }
626+ case { bitstring_type? ( type ) , empty_list_type? ( type ) } do
627+ # If they can be both be true, then we don't know
628+ # what the contents of the block are for
629+ { true , true } ->
630+ type = union ( bitstring ( ) , list ( term ( ) ) )
631+ { if ( gradual? ( type ) , do: dynamic ( type ) , else: type ) , :none , context }
632+
633+ { false , true } ->
634+ { type , :non_empty_list , context }
635+
636+ { true , false } ->
637+ { type , :bitstring , context }
625638 end
626639 else
627640 { _type , context } =
628641 Apply . remote_apply ( info , Collectable , :into , [ type ] , expr , stack , context )
629642
630- { [ :term ] , true , context }
643+ { dynamic ( ) , :none , context }
631644 end
632645 end
633646
647+ defp return_union ( left , right , stack ) do
648+ Apply . return ( union ( left , right ) , [ left , right ] , stack )
649+ end
650+
634651 ## With
635652
636653 defp with_clause ( { :<- , _meta , [ left , right ] } = expr , stack , context ) do
@@ -866,15 +883,36 @@ defmodule Module.Types.Expr do
866883 }
867884 end
868885
869- def format_diagnostic ( { :badbinary , type , expr , context } ) do
886+ def format_diagnostic ( { :badbitgenerator , type , expr , context } ) do
887+ traces = collect_traces ( expr , context )
888+
889+ % {
890+ details: % { typing_traces: traces } ,
891+ message:
892+ IO . iodata_to_binary ( [
893+ """
894+ expected the right side of <- in a binary generator to be a binary (or bitstring):
895+
896+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
897+
898+ but got type:
899+
900+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
901+ """ ,
902+ format_traces ( traces )
903+ ] )
904+ }
905+ end
906+
907+ def format_diagnostic ( { :badbitbody , type , expr , context } ) do
870908 traces = collect_traces ( expr , context )
871909
872910 % {
873911 details: % { typing_traces: traces } ,
874912 message:
875913 IO . iodata_to_binary ( [
876914 """
877- expected the right side of <- in a binary generator to be a binary:
915+ expected the body of a for-comprehension with into: binary() (or bitstring()) to be a binary (or bitstring) :
878916
879917 #{ expr_to_string ( expr ) |> indent ( 4 ) }
880918
0 commit comments