@@ -236,6 +236,9 @@ defmodule Module.Types.Apply do
236236 { :erlang , :tl , [ { [ non_empty_list ( term ( ) , term ( ) ) ] , dynamic ( ) } ] } ,
237237 { :erlang , :tuple_to_list , [ { [ open_tuple ( [ ] ) ] , dynamic ( list ( term ( ) ) ) } ] } ,
238238
239+ ## Lists
240+ { :lists , :member , [ { [ term ( ) , list ( term ( ) ) ] , boolean ( ) } ] } ,
241+
239242 ## Map
240243 { Map , :from_struct , [ { [ open_map ( ) ] , open_map ( __struct__: not_set ( ) ) } ] } ,
241244 { Map , :get , [ { [ open_map ( ) , term ( ) ] , term ( ) } ] } ,
@@ -367,8 +370,8 @@ defmodule Module.Types.Apply do
367370 right_literal? = Macro . quoted_literal? ( right )
368371
369372 case { left_literal? , right_literal? } do
370- { true , false } -> literal_compare ( name , right , left , expected , expr , stack , context , of_fun )
371- { false , true } -> literal_compare ( name , left , right , expected , expr , stack , context , of_fun )
373+ { true , false } -> custom_compare ( name , right , left , expected , expr , stack , context , of_fun )
374+ { false , true } -> custom_compare ( name , left , right , expected , expr , stack , context , of_fun )
372375 { literal? , _ } -> compare ( name , left , right , literal? , expr , stack , context , of_fun )
373376 end
374377 end
@@ -479,6 +482,54 @@ defmodule Module.Types.Apply do
479482 end
480483 end
481484
485+ defp do_remote ( :lists , :member , [ arg , list ] = args , expected , expr , stack , context , of_fun )
486+ when is_list ( list ) and list != [ ] do
487+ case booleaness ( expected ) do
488+ { polarity , _maybe_or_always } ->
489+ { return , acc } =
490+ case polarity do
491+ true -> { @ atom_true , none ( ) }
492+ false -> { @ atom_false , term ( ) }
493+ end
494+
495+ { expected , singleton? , context } =
496+ Enum . reduce ( list , { acc , true , context } , fn literal , { acc , all_singleton? , context } ->
497+ { type , context } = of_fun . ( literal , term ( ) , expr , stack , context )
498+
499+ if singleton? ( type ) do
500+ acc = if polarity , do: union ( acc , type ) , else: intersection ( acc , negation ( type ) )
501+ { acc , all_singleton? , context }
502+ else
503+ acc = if polarity , do: union ( acc , type ) , else: acc
504+ { acc , false , context }
505+ end
506+ end )
507+
508+ { arg_type , context } = of_fun . ( arg , expected , expr , stack , context )
509+
510+ cond do
511+ # Return a precise result
512+ singleton? and subtype? ( arg_type , expected ) ->
513+ { return ( return , [ arg_type , expected ] , stack ) , context }
514+
515+ # Singleton types with reverse polarity are negated, so we don't check for disjoint
516+ ( singleton? and not polarity ) or not is_warning ( stack ) ->
517+ { return ( boolean ( ) , [ arg_type , expected ] , stack ) , context }
518+
519+ # Nothing in common between left and right, emit a warning
520+ disjoint? ( arg_type , expected ) ->
521+ error = { :mismatched_comparison , arg_type , list ( expected ) }
522+ remote_error ( error , :lists , :member , 2 , expr , stack , context )
523+
524+ true ->
525+ { return ( boolean ( ) , [ arg_type , expected ] , stack ) , context }
526+ end
527+
528+ _ ->
529+ remote_domain ( :lists , :member , args , expected , elem ( expr , 1 ) , stack , context )
530+ end
531+ end
532+
482533 defp do_remote ( mod , fun , args , expected , expr , stack , context , _of_fun ) do
483534 remote_domain ( mod , fun , args , expected , elem ( expr , 1 ) , stack , context )
484535 end
@@ -495,7 +546,7 @@ defmodule Module.Types.Apply do
495546 when ( fun in [ :length , :map_size ] and is_integer ( literal ) and literal >= 0 ) or
496547 ( fun in [ :tuple_size ] and literal in 0 .. 15 )
497548
498- defp literal_compare (
549+ defp custom_compare (
499550 name ,
500551 { { :. , _ , [ :erlang , fun ] } , _ , [ arg ] } = left ,
501552 literal ,
@@ -547,18 +598,14 @@ defmodule Module.Types.Apply do
547598 end
548599 end
549600
550- defp literal_compare ( name , arg , literal , expected , expr , stack , context , of_fun ) do
551- { type , context } = of_fun . ( literal , term ( ) , expr , stack , context )
552- literal_compare ( name , arg , type , singleton? ( type ) , expected , expr , stack , context , of_fun )
553- end
554-
555- def literal_compare ( name , arg , type , singleton? , expected , expr , stack , context , of_fun ) do
601+ defp custom_compare ( name , arg , literal , expected , expr , stack , context , of_fun ) do
556602 case booleaness ( expected ) do
557603 booleaness when booleaness in [ :maybe_both , :none ] ->
558- { arg_type , context } = of_fun . ( arg , term ( ) , expr , stack , context )
559- return_compare ( name , arg_type , type , boolean ( ) , false , expr , stack , context )
604+ compare ( name , arg , literal , false , expr , stack , context , of_fun )
560605
561606 { boolean , _maybe_or_always } ->
607+ { type , context } = of_fun . ( literal , term ( ) , expr , stack , context )
608+
562609 { polarity , return } =
563610 case boolean do
564611 true -> { name in [ :== , :"=:=" ] , @ atom_true }
@@ -567,7 +614,7 @@ defmodule Module.Types.Apply do
567614
568615 # This logic mirrors the code in `Pattern.of_pattern_tree`
569616 # If it is a singleton, we can always be precise
570- if singleton? do
617+ if singleton? ( type ) do
571618 expected = if polarity , do: type , else: negation ( type )
572619 { arg_type , context } = of_fun . ( arg , expected , expr , stack , context )
573620 result = if subtype? ( arg_type , expected ) , do: return , else: boolean ( )
@@ -1849,7 +1896,7 @@ defmodule Module.Types.Apply do
18491896 end
18501897
18511898 def format_diagnostic ( { { :mismatched_comparison , left , right } , mfac , expr , context } ) do
1852- { _ , name , _ , _ } = mfac
1899+ { mod , name , _ , _ } = mfac
18531900 traces = collect_traces ( expr , context )
18541901
18551902 % {
@@ -1863,7 +1910,7 @@ defmodule Module.Types.Apply do
18631910
18641911 given types:
18651912
1866- #{ type_comparison_to_string ( name , left , right ) |> indent ( 4 ) }
1913+ #{ type_comparison_to_string ( mod , name , left , right ) |> indent ( 4 ) }
18671914 """ ,
18681915 format_traces ( traces ) ,
18691916 """
@@ -1877,7 +1924,7 @@ defmodule Module.Types.Apply do
18771924 end
18781925
18791926 def format_diagnostic ( { { :struct_comparison , left , right } , mfac , expr , context } ) do
1880- { _ , name , _ , _ } = mfac
1927+ { mod , name , _ , _ } = mfac
18811928 traces = collect_traces ( expr , context )
18821929
18831930 % {
@@ -1891,7 +1938,7 @@ defmodule Module.Types.Apply do
18911938
18921939 given types:
18931940
1894- #{ type_comparison_to_string ( name , left , right ) |> indent ( 4 ) }
1941+ #{ type_comparison_to_string ( mod , name , left , right ) |> indent ( 4 ) }
18951942 """ ,
18961943 format_traces ( traces ) ,
18971944 """
@@ -1989,8 +2036,8 @@ defmodule Module.Types.Apply do
19892036
19902037 alias Inspect.Algebra , as: IA
19912038
1992- defp type_comparison_to_string ( fun , left , right ) do
1993- { _ , fun , _ , _ } = :elixir_rewrite . erl_to_ex ( :erlang , fun , [ left , right ] )
2039+ defp type_comparison_to_string ( mod , fun , left , right ) do
2040+ { _ , fun , _ , _ } = :elixir_rewrite . erl_to_ex ( mod , fun , [ left , right ] )
19942041
19952042 { fun , [ ] , [ to_quoted ( left , collapse_structs: true ) , to_quoted ( right , collapse_structs: true ) ] }
19962043 |> Code.Formatter . to_algebra ( )
0 commit comments