@@ -1981,6 +1981,94 @@ defmodule Module.Types.Descr do
19811981    end ) 
19821982  end 
19831983
1984+   def  tuple_values ( descr )  do 
1985+     case  :maps . take ( :dynamic ,  descr )  do 
1986+       :error  -> 
1987+         if  tuple_only? ( descr )  do 
1988+           process_tuples_values ( Map . get ( descr ,  :tuple ,  [ ] ) ) 
1989+         else 
1990+           :badtuple 
1991+         end 
1992+ 
1993+       { dynamic ,  static }  -> 
1994+         if  tuple_only? ( static )  and  descr_key? ( dynamic ,  :tuple )  do 
1995+           dynamic ( process_tuples_values ( Map . get ( dynamic ,  :tuple ,  [ ] ) ) ) 
1996+           |>  union ( process_tuples_values ( Map . get ( static ,  :tuple ,  [ ] ) ) ) 
1997+         else 
1998+           :badtuple 
1999+         end 
2000+     end 
2001+   end 
2002+ 
2003+   defp  process_tuples_values ( dnf )  do 
2004+     Enum . reduce ( dnf ,  none ( ) ,  fn  { tag ,  elements ,  negs } ,  acc  -> 
2005+       union ( tuple_values ( tag ,  elements ,  negs ) ,  acc ) 
2006+     end ) 
2007+   end 
2008+ 
2009+   defp  tuple_values ( tag ,  elements ,  [ ] )  do 
2010+     cond  do 
2011+       Enum . any? ( elements ,  & empty? / 1 )  ->  none ( ) 
2012+       tag  ==  :open  ->  term ( ) 
2013+       tag  ==  :closed  ->  Enum . reduce ( elements ,  none ( ) ,  & union / 2 ) 
2014+     end 
2015+   end 
2016+ 
2017+   defp  tuple_values ( _tag ,  _elements ,  [ { :open ,  [ ] }  |  _ ] ) ,  do:  none ( ) 
2018+ 
2019+   defp  tuple_values ( tag ,  elements ,  [ { neg_tag ,  neg_elements }  |  negs ] )  do 
2020+     n  =  length ( elements ) 
2021+     m  =  length ( neg_elements ) 
2022+ 
2023+     if  ( tag  ==  :closed  and  n  <  m )  or  ( neg_tag  ==  :closed  and  n  >  m )  do 
2024+       tuple_values ( tag ,  elements ,  negs ) 
2025+     else 
2026+       # Those two functions eliminate the negations, transforming into 
2027+       # a union of tuples to compute their values. 
2028+       values_elements ( [ ] ,  tag ,  elements ,  neg_elements ,  negs ) 
2029+       |>  union ( values_size ( n ,  m ,  tag ,  elements ,  neg_tag ,  negs ) ) 
2030+     end 
2031+   end 
2032+ 
2033+   # This means that there are no more neg_elements to subtract -- end the recursion. 
2034+   defp  values_elements ( _acc ,  _tag ,  _elements ,  [ ] ,  _ ) ,  do:  none ( ) 
2035+ 
2036+   # Eliminates negations according to tuple content. 
2037+   # Subtracts each element of a negative tuple to build a new tuple with the difference. 
2038+   # Example: {number(), atom()} and not {float(), :foo} contains types {integer(), :foo} 
2039+   # as well as {float(), atom() and not :foo} 
2040+   # Same process as tuple_elements_empty? 
2041+   defp  values_elements ( acc ,  tag ,  elements ,  [ neg_type  |  neg_elements ] ,  negs )  do 
2042+     { ty ,  elements }  =  List . pop_at ( elements ,  0 ,  term ( ) ) 
2043+     diff  =  difference ( ty ,  neg_type ) 
2044+ 
2045+     if  empty? ( diff )  do 
2046+       none ( ) 
2047+     else 
2048+       tuple_values ( tag ,  Enum . reverse ( acc ,  [ diff  |  elements ] ) ,  negs ) 
2049+     end 
2050+     |>  union ( values_elements ( [ ty  |  acc ] ,  tag ,  elements ,  neg_elements ,  negs ) ) 
2051+   end 
2052+ 
2053+   # Eliminates negations according to size 
2054+   # Example: {integer(), ...} and not {term(), term(), ...} contains {integer()} 
2055+   defp  values_size ( n ,  m ,  tag ,  elements ,  neg_tag ,  negs )  do 
2056+     if  tag  ==  :closed  do 
2057+       none ( ) 
2058+     else 
2059+       n .. ( m  -  1 ) // 1 
2060+       |>  Enum . map ( & tuple_values ( :closed ,  tuple_fill ( elements ,  & 1 ) ,  negs ) ) 
2061+       |>  Enum . reduce ( none ( ) ,  & union / 2 ) 
2062+       |>  union ( 
2063+         if  neg_tag  ==  :open  do 
2064+           none ( ) 
2065+         else 
2066+           tuple_values ( tag ,  tuple_fill ( elements ,  m  +  1 ) ,  negs ) 
2067+         end 
2068+       ) 
2069+     end 
2070+   end 
2071+ 
19842072  defp  tuple_pop_index ( tag ,  elements ,  index )  do 
19852073    case  List . pop_at ( elements ,  index )  do 
19862074      { nil ,  _ }  ->  { tag_to_type ( tag ) ,  % { tuple:  [ { tag ,  elements ,  [ ] } ] } } 
0 commit comments