@@ -1186,6 +1186,96 @@ defmodule Module.Types.MapTest do
11861186 end
11871187 end
11881188
1189+ describe "Map.update/4" do
1190+ test "checking" do
1191+ assert typecheck! ( Map . update ( % { } , :key , :default , fn _ -> :value end ) ) ==
1192+ dynamic ( closed_map ( key: atom ( [ :default ] ) ) )
1193+
1194+ assert typecheck! ( Map . update ( % { key: 123 } , :key , :default , fn _ -> :value end ) ) ==
1195+ dynamic ( closed_map ( key: atom ( [ :value ] ) ) )
1196+
1197+ assert typecheck! ( [ x ] , Map . update ( x , :key , :default , fn _ -> :value end ) ) ==
1198+ dynamic ( open_map ( key: atom ( [ :value , :default ] ) ) )
1199+
1200+ # If one of them succeeds, we are still fine!
1201+ assert typecheck! (
1202+ [ condition? ] ,
1203+ Map . update ( % { foo: 123 } , if ( condition? , do: :foo , else: :bar ) , :default , fn _ ->
1204+ "123"
1205+ end )
1206+ ) ==
1207+ dynamic (
1208+ union (
1209+ closed_map ( foo: binary ( ) ) ,
1210+ closed_map ( foo: integer ( ) , bar: atom ( [ :default ] ) )
1211+ )
1212+ )
1213+
1214+ # Both succeed but different clauses
1215+ assert typecheck! (
1216+ [ condition? ] ,
1217+ Map . update (
1218+ % { key1: :foo , key2: :bar } ,
1219+ if ( condition? , do: :key1 , else: :key2 ) ,
1220+ :default ,
1221+ fn
1222+ :foo -> 123
1223+ :bar -> 123.0
1224+ end
1225+ )
1226+ ) ==
1227+ dynamic (
1228+ union (
1229+ closed_map ( key1: atom ( [ :foo ] ) , key2: float ( ) ) ,
1230+ closed_map ( key1: integer ( ) , key2: atom ( [ :bar ] ) )
1231+ )
1232+ )
1233+
1234+ assert typecheck! ( [ x ] , Map . update ( x , 123 , :default , fn _ -> 456 end ) ) == dynamic ( open_map ( ) )
1235+
1236+ integer_to_integer_float_atom =
1237+ dynamic (
1238+ closed_map ( [
1239+ { domain_key ( :integer ) , integer ( ) |> union ( float ( ) ) |> union ( atom ( [ :default ] ) ) }
1240+ ] )
1241+ )
1242+
1243+ assert typecheck! ( [ ] , Map . update ( % { 123 => 456 } , 123 , :default , fn x -> x * 1.0 end ) ) ==
1244+ integer_to_integer_float_atom
1245+
1246+ assert typecheck! ( [ ] , Map . update ( % { 123 => 456 } , 456 , :default , fn x -> x * 1.0 end ) ) ==
1247+ integer_to_integer_float_atom
1248+ end
1249+
1250+ test "inference" do
1251+ assert typecheck! (
1252+ [ x ] ,
1253+ (
1254+ _ = Map . update ( x , :key , :default , fn _ -> :value end )
1255+ x
1256+ )
1257+ ) == dynamic ( open_map ( ) )
1258+ end
1259+
1260+ test "errors" do
1261+ assert typeerror! ( Map . update ( % { key: :foo } , :key , :default , fn :bar -> :value end ) )
1262+ |> strip_ansi ( ) =~
1263+ """
1264+ incompatible types given on function call within Map.update/4:
1265+
1266+ Map.update(%{key: :foo}, :key, :default, fn :bar -> :value end)
1267+
1268+ given types:
1269+
1270+ dynamic(:foo)
1271+
1272+ but function has type:
1273+
1274+ (:bar -> dynamic(:value))
1275+ """
1276+ end
1277+ end
1278+
11891279 describe "Map.update!/3" do
11901280 test "checking" do
11911281 assert typecheck! ( Map . update! ( % { key: 123 } , :key , fn _ -> :value end ) ) ==
@@ -1219,6 +1309,9 @@ defmodule Module.Types.MapTest do
12191309
12201310 assert typecheck! ( [ ] , Map . update! ( % { 123 => 456 } , 123 , fn x -> x * 1.0 end ) ) ==
12211311 dynamic ( closed_map ( [ { domain_key ( :integer ) , union ( integer ( ) , float ( ) ) } ] ) )
1312+
1313+ assert typecheck! ( [ ] , Map . update! ( % { 123 => 456 } , 456 , fn x -> x * 1.0 end ) ) ==
1314+ dynamic ( closed_map ( [ { domain_key ( :integer ) , union ( integer ( ) , float ( ) ) } ] ) )
12221315 end
12231316
12241317 test "inference" do
0 commit comments