@@ -286,6 +286,66 @@ defmodule Module.Types.Expr do
286286 of_expr ( post , expected , post , stack , context )
287287 end
288288
289+ def of_expr (
290+ { :cond , meta ,
291+ [
292+ [
293+ { :do ,
294+ [
295+ { :-> , pos_meta , [ [ pos_head ] , pos_body ] } ,
296+ { :-> , _neg_meta , [ [ neg_head ] , neg_body ] }
297+ ] }
298+ ]
299+ ] } ,
300+ expected ,
301+ expr ,
302+ stack ,
303+ acc_context
304+ )
305+ when is_atom ( neg_head ) and neg_head not in [ false , nil ] do
306+ cache_result ( meta , stack , acc_context , fn ->
307+ { pos_head_type , context } =
308+ of_expr ( pos_head , term ( ) , pos_head , % { stack | reverse_arrow: :cache } , acc_context )
309+
310+ # Reset the context vars, keep warnings, as we will infer with expected truthy
311+ context = Of . reset_vars ( context , acc_context )
312+
313+ context =
314+ maybe_always_or_never_match_cond ( pos_head_type , pos_head , pos_meta , stack , context , false )
315+
316+ { _ , truthy_context } =
317+ of_expr ( pos_head , @ truthy , pos_head , % { stack | reverse_arrow: :use } , context )
318+
319+ # Keep the context except the warnings, and compute the body
320+ context = reset_warnings ( truthy_context , context )
321+
322+ { pos_body_type , context } =
323+ of_expr ( pos_body , expected , expr , stack , context )
324+
325+ # Reset the context vars once again to compute the falsy type
326+ context = Of . reset_vars ( context , acc_context )
327+
328+ { _ , falsy_context } =
329+ of_expr ( pos_head , @ falsy , pos_head , % { stack | reverse_arrow: :use } , context )
330+
331+ context = reset_warnings ( falsy_context , context )
332+
333+ { neg_body_type , context } =
334+ of_expr ( neg_body , expected , expr , stack , context )
335+
336+ body_type = union ( pos_body_type , neg_body_type )
337+
338+ context =
339+ cond do
340+ empty? ( pos_body_type ) -> Of . reset_vars ( context , falsy_context )
341+ empty? ( neg_body_type ) -> Of . reset_vars ( context , truthy_context )
342+ true -> Of . reset_vars ( context , acc_context )
343+ end
344+
345+ dynamic_unless_static ( { body_type , context } , stack )
346+ end )
347+ end
348+
289349 def of_expr ( { :cond , meta , [ [ { :do , clauses } ] ] } , expected , expr , stack , context ) do
290350 cache_result ( meta , stack , context , fn ->
291351 { body_type , acc_context } =
@@ -298,22 +358,7 @@ defmodule Module.Types.Expr do
298358 context = Of . reset_vars ( context , acc_context )
299359
300360 context =
301- if is_warning ( stack ) do
302- case truthiness ( head_type ) do
303- :always_true when not last? ->
304- warning = { :badcond , "always match" , head_type , head , context }
305- warn ( __MODULE__ , warning , meta , stack , context )
306-
307- :always_false ->
308- warning = { :badcond , "never match" , head_type , head , context }
309- warn ( __MODULE__ , warning , meta , stack , context )
310-
311- _ ->
312- context
313- end
314- else
315- context
316- end
361+ maybe_always_or_never_match_cond ( head_type , head , meta , stack , context , last? )
317362
318363 { _ , truthy_context } =
319364 of_expr ( head , @ truthy , head , % { stack | reverse_arrow: :use } , context )
@@ -327,10 +372,17 @@ defmodule Module.Types.Expr do
327372 # Reset the context vars once again to compute the falsy type
328373 context = Of . reset_vars ( context , acc_context )
329374
330- { _ , falsy_context } =
331- of_expr ( head , @ falsy , head , % { stack | reverse_arrow: :use } , context )
375+ context =
376+ if last? do
377+ context
378+ else
379+ { _ , falsy_context } =
380+ of_expr ( head , @ falsy , head , % { stack | reverse_arrow: :use } , context )
381+
382+ reset_warnings ( falsy_context , context )
383+ end
332384
333- { union ( body_type , acc ) , reset_warnings ( falsy_context , context ) }
385+ { union ( body_type , acc ) , context }
334386 end )
335387
336388 dynamic_unless_static ( { body_type , Of . reset_vars ( acc_context , context ) } , stack )
@@ -380,7 +432,7 @@ defmodule Module.Types.Expr do
380432 reset_warnings ( context , original )
381433 end
382434
383- { expected , context }
435+ dynamic_unless_static ( { expected , context } , stack )
384436 end
385437
386438 def of_expr ( { :case , meta , [ case_expr , [ do: clauses ] ] } , expected , _expr , stack , base_context ) do
@@ -874,6 +926,25 @@ defmodule Module.Types.Expr do
874926 defp reduce_non_empty ( [ head | tail ] , acc , fun ) ,
875927 do: reduce_non_empty ( tail , fun . ( head , acc , false ) , fun )
876928
929+ defp maybe_always_or_never_match_cond ( head_type , head , meta , stack , context , last? ) do
930+ if is_warning ( stack ) do
931+ case truthiness ( head_type ) do
932+ :always_true when not last? ->
933+ warning = { :badcond , "always match" , head_type , head , context }
934+ warn ( __MODULE__ , warning , meta , stack , context )
935+
936+ :always_false ->
937+ warning = { :badcond , "never match" , head_type , head , context }
938+ warn ( __MODULE__ , warning , meta , stack , context )
939+
940+ _ ->
941+ context
942+ end
943+ else
944+ context
945+ end
946+ end
947+
877948 defp dynamic_unless_static ( { _ , _ } = output , % { mode: :static } ) , do: output
878949 defp dynamic_unless_static ( { type , context } , % { mode: _ } ) , do: { dynamic ( type ) , context }
879950
0 commit comments