@@ -178,16 +178,34 @@ defmodule Module.Types.Expr do
178178 of_expr ( post , stack , context )
179179 end
180180
181- # TODO: cond do pat -> expr end
182181 def of_expr ( { :cond , _meta , [ [ { :do , clauses } ] ] } , stack , context ) do
183- context =
184- Enum . reduce ( clauses , context , fn { :-> , _meta , [ head , body ] } , context ->
185- { _ , context } = of_expr ( head , stack , context )
186- { _ , context } = of_expr ( body , stack , context )
187- context
188- end )
182+ clauses
183+ |> reduce_non_empty ( { none ( ) , context } , fn
184+ { :-> , meta , [ [ head ] , body ] } , { acc , context } , last? ->
185+ { head_type , context } = of_expr ( head , stack , context )
189186
190- { dynamic ( ) , context }
187+ context =
188+ if stack . mode == :infer do
189+ context
190+ else
191+ case truthness ( head_type ) do
192+ :always_true when not last? ->
193+ warning = { :badcond , "always match" , head_type , head , context }
194+ warn ( __MODULE__ , warning , meta , stack , context )
195+
196+ :always_false ->
197+ warning = { :badcond , "never match" , head_type , head , context }
198+ warn ( __MODULE__ , warning , meta , stack , context )
199+
200+ _ ->
201+ context
202+ end
203+ end
204+
205+ { body_type , context } = of_expr ( body , stack , context )
206+ { union ( body_type , acc ) , context }
207+ end )
208+ |> dynamic_unless_static ( stack )
191209 end
192210
193211 # TODO: case expr do pat -> expr end
@@ -459,6 +477,15 @@ defmodule Module.Types.Expr do
459477 { Enum . reduce ( returns , & union / 2 ) , context }
460478 end
461479
480+ defp reduce_non_empty ( [ last ] , acc , fun ) ,
481+ do: fun . ( last , acc , true )
482+
483+ defp reduce_non_empty ( [ head | tail ] , acc , fun ) ,
484+ do: reduce_non_empty ( tail , fun . ( head , acc , false ) , fun )
485+
486+ defp dynamic_unless_static ( { _ , _ } = output , % { mode: :static } ) , do: output
487+ defp dynamic_unless_static ( { type , context } , % { mode: _ } ) , do: { dynamic ( type ) , context }
488+
462489 defp of_clauses ( clauses , stack , context ) do
463490 Enum . reduce ( clauses , context , fn { :-> , meta , [ head , body ] } , context ->
464491 { patterns , guards } = extract_head ( head )
@@ -480,13 +507,8 @@ defmodule Module.Types.Expr do
480507 { other , [ ] }
481508 end
482509
483- defp flatten_when ( { :when , _meta , [ left , right ] } ) do
484- [ left | flatten_when ( right ) ]
485- end
486-
487- defp flatten_when ( other ) do
488- [ other ]
489- end
510+ defp flatten_when ( { :when , _meta , [ left , right ] } ) , do: [ left | flatten_when ( right ) ]
511+ defp flatten_when ( other ) , do: [ other ]
490512
491513 defp of_expr_context ( expr , stack , context ) do
492514 { _type , context } = of_expr ( expr , stack , context )
@@ -582,4 +604,25 @@ defmodule Module.Types.Expr do
582604 ] )
583605 }
584606 end
607+
608+ def format_diagnostic ( { :badcond , explain , type , expr , context } ) do
609+ traces = collect_traces ( expr , context )
610+
611+ % {
612+ details: % { typing_traces: traces } ,
613+ message:
614+ IO . iodata_to_binary ( [
615+ """
616+ this clause in cond will #{ explain } :
617+
618+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
619+
620+ since it has type:
621+
622+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
623+ """ ,
624+ format_traces ( traces )
625+ ] )
626+ }
627+ end
585628end
0 commit comments