@@ -3252,50 +3252,32 @@ defmodule Module.Types.Descr do
32523252 # and whether the key is optional.
32533253 defp map_dnf_fetch_static ( dnf , key ) do
32543254 Enum . reduce ( dnf , { none ( ) , false } , fn
3255- # Optimization: if there are no negatives
3256- { tag , fields , [ ] } , acc ->
3257- field =
3258- case fields_find ( key , fields ) do
3259- { :ok , field } -> field
3260- :error when tag == :open -> throw ( :open )
3261- :error -> map_key_tag_to_field ( tag )
3262- end
3263-
3264- field_opt_union ( field , acc , % { } )
3265-
32663255 { tag , fields , negs } , acc ->
32673256 { field , bdd } = map_pop_key_bdd ( tag , fields , key )
32683257
3269- case map_split_negative_pairs_key ( negs , key ) do
3270- :empty ->
3271- acc
3272-
3273- negative ->
3274- field =
3275- if map_pair_projection_keeps_full_fst? ( negative , bdd ) do
3276- field
3277- else
3278- negs
3279- |> map_split_negative_key ( key , field , bdd )
3280- |> Enum . reduce ( { none ( ) , false } , fn { field , _ } , acc ->
3281- field_opt_union ( field , acc , % { } )
3282- end )
3283- end
3284-
3258+ # First: if a map has a none() field, then fetching from it is none() too
3259+ # Then: if there is a negative open_map(), map type is empty
3260+ with false <- map_empty? ( bdd , % { } ) ,
3261+ negative when negative != :empty <- map_split_negative_pairs_key ( negs , key ) do
3262+ if map_pair_projection_keeps_full_fst? ( negative , bdd ) do
32853263 field_opt_union ( field , acc , % { } )
3264+ else
3265+ negative
3266+ |> map_remove_negative ( field , bdd )
3267+ |> Enum . reduce ( acc , fn { field , _ } , acc ->
3268+ field_opt_union ( field , acc , % { } )
3269+ end )
3270+ end
3271+ else
3272+ _ -> acc
32863273 end
32873274 end )
3288- catch
3289- :open -> { term ( ) , true }
32903275 end
32913276
32923277 defp map_split_negative_pairs_key ( negs , key ) do
32933278 Enum . reduce_while ( negs , [ ] , fn
3294- bdd_leaf ( :open , [ ] ) , _acc ->
3295- { :halt , :empty }
3296-
3297- bdd_leaf ( tag , fields ) , neg_acc ->
3298- { :cont , [ map_pop_key_bdd ( tag , fields , key ) | neg_acc ] }
3279+ bdd_leaf ( :open , [ ] ) , _acc -> { :halt , :empty }
3280+ bdd_leaf ( tag , fields ) , neg_acc -> { :cont , [ map_pop_key_bdd ( tag , fields , key ) | neg_acc ] }
32993281 end )
33003282 end
33013283
@@ -3322,64 +3304,33 @@ defmodule Module.Types.Descr do
33223304 not field_empty? ( field_difference ( field , neg_field ) )
33233305 end
33243306
3325- defp map_split_negative_key ( negs , key , value , bdd ) do
3326- map_split_negative ( negs , value , bdd , fn neg_tag , neg_fields ->
3327- case fields_take ( key , neg_fields ) do
3328- { neg_field , neg_fields } ->
3329- { true , neg_field , map_new ( neg_tag , neg_fields ) }
3330-
3331- :error ->
3332- { false , map_key_tag_to_field ( neg_tag ) , map_new ( neg_tag , neg_fields ) }
3333- end
3334- end )
3335- end
3336-
33373307 # Remove negatives:
33383308 # {t, s} \ {t₁, s₁} = {t \ t₁, s} ∪ {t ∩ t₁, s \ s₁}
3339- defp map_split_negative ( negs , value , bdd , take_fun ) do
3340- Enum . reduce ( negs , [ { value , bdd } ] , fn
3341- bdd_leaf ( :open , [ ] ) , _acc ->
3342- throw ( :empty )
3343-
3344- bdd_leaf ( neg_tag , neg_fields ) , acc ->
3345- { found? , neg_field , neg_bdd } = take_fun . ( neg_tag , neg_fields )
3346-
3347- if not found? and neg_tag == :open do
3348- # In case the map is open, t \ t₁ is always empty,
3349- # t ∩ t₁ is always t, so we just need to deal with the bdd.
3350- Enum . reduce ( acc , [ ] , fn { field , bdd } , acc ->
3309+ defp map_remove_negative ( negative , value , bdd ) do
3310+ Enum . reduce ( negative , [ { value , bdd } ] , fn { neg_field , neg_bdd } , acc ->
3311+ Enum . reduce ( acc , [ ] , fn { field , bdd } , acc ->
3312+ # If the negative tag is closed, then they are likely disjoint,
3313+ # so we can drastically cut down the amount of operations.
3314+ if match? ( bdd_leaf ( :closed , _ ) , neg_bdd ) and
3315+ map_empty? ( map_intersection ( bdd , neg_bdd ) , % { } ) do
3316+ [ { field , bdd } | acc ]
3317+ else
3318+ intersection_field = field_intersection ( field , neg_field )
3319+
3320+ if field_empty? ( intersection_field ) do
3321+ [ { field , bdd } | acc ]
3322+ else
33513323 diff_bdd = map_difference ( bdd , neg_bdd )
33523324
33533325 if map_empty? ( diff_bdd , % { } ) do
3354- acc
3326+ prepend_map_pair_unless_empty_diff ( field , neg_field , bdd , acc )
33553327 else
3356- [ { field , diff_bdd } | acc ]
3357- end
3358- end )
3359- else
3360- Enum . reduce ( acc , [ ] , fn { field , bdd } , acc ->
3361- # If the negative tag is closed, then they are likely disjoint,
3362- # so we can drastically cut down the amount of operations.
3363- if neg_tag == :closed and map_empty? ( map_intersection ( bdd , neg_bdd ) , % { } ) do
3364- [ { field , bdd } | acc ]
3365- else
3366- intersection_field = field_intersection ( field , neg_field )
3367-
3368- if field_empty? ( intersection_field ) do
3369- [ { field , bdd } | acc ]
3370- else
3371- diff_bdd = map_difference ( bdd , neg_bdd )
3372-
3373- if map_empty? ( diff_bdd , % { } ) do
3374- prepend_map_pair_unless_empty_diff ( field , neg_field , bdd , acc )
3375- else
3376- acc = [ { intersection_field , diff_bdd } | acc ]
3377- prepend_map_pair_unless_empty_diff ( field , neg_field , bdd , acc )
3378- end
3379- end
3328+ acc = [ { intersection_field , diff_bdd } | acc ]
3329+ prepend_map_pair_unless_empty_diff ( field , neg_field , bdd , acc )
33803330 end
3381- end )
3331+ end
33823332 end
3333+ end )
33833334 end )
33843335 catch
33853336 :empty -> [ ]
@@ -3797,7 +3748,7 @@ defmodule Module.Types.Descr do
37973748 pairs =
37983749 if keep_fst? and keep_snd? ,
37993750 do: [ ] ,
3800- else: map_split_negative_key ( negs , key , fst , snd )
3751+ else: map_remove_negative ( negative , fst , snd )
38013752
38023753 { maybe_field_opt_union ( field , fn ->
38033754 if keep_fst? do
0 commit comments