@@ -873,7 +873,7 @@ defmodule Module.Types.Pattern do
873873 Of . refine_body_var ( var , expected , expr , stack , context )
874874 end
875875
876- defp of_remote ( fun , _meta , [ left , right ] , call , expected , stack , context )
876+ defp of_remote ( fun , _meta , _args , call , expected , stack , context )
877877 when fun in [ :and , :or , :andalso , :orelse ] do
878878 { both_domain , abort_domain , always_rhs? } =
879879 case fun do
@@ -883,29 +883,39 @@ defmodule Module.Types.Pattern do
883883 :or -> { @ atom_false , @ atom_true , true }
884884 end
885885
886+ # If we have multiple operations in a row,
887+ # we unpack them into a single pass, to avoid
888+ # building nested conditional environments.
889+ [ left | right ] = unpack_op ( call , fun , [ ] )
890+
886891 # For example, if the expected type is true for andalso, then it can
887892 # only be true if both clauses are executed, so we know the first
888893 # argument has to be true and the second has to be expected.
889894 if subtype? ( expected , both_domain ) do
890- of_logical_both ( left , both_domain , right , expected , abort_domain , call , stack , context )
895+ of_logical_all ( [ left | right ] , true , both_domain , abort_domain , stack , context )
891896 else
892897 cond_context = % { context | conditional_vars: % { } }
893898
894899 # Compute the sure types, which are stored directly in the context
895- { _type , context } = of_guard ( left , boolean ( ) , call , stack , context )
900+ { _type , context } = of_guard ( left , boolean ( ) , left , stack , context )
896901
897902 # andalso/orelse may not execute the rhs, so we cannot get sure types from it
898903 context =
899904 case always_rhs? do
900905 true ->
901- { _ , context } = of_guard ( right , boolean ( ) , call , stack , context )
902- context
906+ Enum . reduce ( right , context , fn expr , context ->
907+ { _ , context } = of_guard ( expr , boolean ( ) , expr , stack , context )
908+ context
909+ end )
903910
904911 false ->
905912 context
906913 end
907914
908- of_logical_cond ( left , right , expected , abort_domain , call , stack , context , cond_context )
915+ { type , vars_conds } =
916+ of_logical_cond ( [ left | right ] , true , expected , abort_domain , stack , cond_context , [ ] )
917+
918+ { type , of_cond_vars ( vars_conds , call , stack , context ) }
909919 end
910920 end
911921
@@ -919,33 +929,50 @@ defmodule Module.Types.Pattern do
919929 Apply . remote_apply ( info , :erlang , fun , args_types , call , stack , context )
920930 end
921931
922- defp of_logical_both ( left , left_domain , right , right_domain , to_abort , call , stack , context ) do
923- { left_type , context } = of_guard ( left , left_domain , call , stack , context )
924- { right_type , context } = of_guard ( right , right_domain , call , stack , context )
932+ defp unpack_op ( { { :. , _ , [ :erlang , fun ] } , _ , [ left , right ] } , fun , acc ) do
933+ unpack_op ( left , fun , unpack_op ( right , fun , acc ) )
934+ end
925935
926- if disjoint? ( left_type , to_abort ) do
927- { right_type , context }
928- else
929- { union ( to_abort , right_type ) , context }
936+ defp unpack_op ( other , _fun , acc ) do
937+ [ other | acc ]
938+ end
939+
940+ defp of_logical_all ( [ head ] , disjoint? , expected , to_abort , stack , context ) do
941+ { type , context } = of_guard ( head , expected , head , stack , context )
942+
943+ case disjoint? do
944+ true -> { type , context }
945+ false -> { union ( to_abort , type ) , context }
930946 end
931947 end
932948
933- defp of_logical_cond ( left , right , expected , to_abort , call , stack , context , cond_context ) do
934- { left_type , left_context } = of_guard ( left , expected , call , stack , cond_context )
935- { right_type , right_context } = of_guard ( right , expected , call , stack , cond_context )
949+ defp of_logical_all ( [ head | tail ] , disjoint? , expected , to_abort , stack , context ) do
950+ { type , context } = of_guard ( head , expected , head , stack , context )
951+ disjoint? = disjoint? and disjoint? ( type , to_abort )
952+ of_logical_all ( tail , disjoint? , expected , to_abort , stack , context )
953+ end
954+
955+ defp of_logical_cond ( [ head ] , disjoint? , expected , to_abort , stack , context , acc ) do
956+ { type , % { vars: vars , conditional_vars: cond_vars } } =
957+ of_guard ( head , expected , head , stack , context )
936958
937- % { vars: left_vars , conditional_vars: left_cond } = left_context
938- % { vars: right_vars , conditional_vars: right_cond } = right_context
939- vars_conds = [ { left_vars , left_cond } , { right_vars , right_cond } ]
940- context = of_cond_vars ( vars_conds , call , stack , context )
959+ acc = [ { vars , cond_vars } | acc ]
941960
942- if disjoint? ( left_type , to_abort ) do
943- { right_type , context }
944- else
945- { union ( to_abort , right_type ) , context }
961+ case disjoint? do
962+ true -> { type , acc }
963+ false -> { union ( to_abort , type ) , acc }
946964 end
947965 end
948966
967+ defp of_logical_cond ( [ head | tail ] , disjoint? , expected , to_abort , stack , context , acc ) do
968+ { type , % { vars: vars , conditional_vars: cond_vars } } =
969+ of_guard ( head , expected , head , stack , context )
970+
971+ disjoint? = disjoint? and disjoint? ( type , to_abort )
972+ acc = [ { vars , cond_vars } | acc ]
973+ of_logical_cond ( tail , disjoint? , expected , to_abort , stack , context , acc )
974+ end
975+
949976 defp of_cond_vars ( [ { vars , cond } | vars_conds ] , expr , stack , context ) do
950977 Enum . reduce ( Map . keys ( cond ) , context , fn version , context ->
951978 if Enum . all? ( vars_conds , fn { _vars , cond } -> is_map_key ( cond , version ) end ) do
0 commit comments