@@ -105,15 +105,15 @@ defmodule Module.Types.Pattern do
105105
106106 { :error , _old_type , error_context } ->
107107 if match_error? ( var , new_type ) do
108- throw ( badpattern_error ( var , expr , stack , context ) )
108+ throw ( badmatch_error ( var , expr , stack , context ) )
109109 else
110110 throw ( badvar_error ( var , old_type , new_type , stack , error_context ) )
111111 end
112112 end
113113 end
114114
115115 :error ->
116- throw ( badpattern_error ( var , expr , stack , context ) )
116+ throw ( badmatch_error ( var , expr , stack , context ) )
117117 end
118118 end )
119119 catch
@@ -228,7 +228,7 @@ defmodule Module.Types.Pattern do
228228 { expected , context } = expected_fun . ( of_pattern_tree ( tree , stack , context ) , context )
229229
230230 args = [ { tree , expected , expr } ]
231- tag = { :match , expected }
231+ tag = { :match , expr , expected }
232232
233233 with { :ok , types } <- of_pattern_intersect ( args , 0 , [ ] , pattern_info , tag , stack , context ) ,
234234 { [ type ] , changed , context } <-
@@ -350,29 +350,25 @@ defmodule Module.Types.Pattern do
350350 error ( __MODULE__ , error , error_meta ( var , stack ) , stack , context )
351351 end
352352
353- defp badpattern_error ( var , expr , stack , context ) do
353+ defp badmatch_error ( var , expr , stack , context ) do
354354 meta = error_meta ( expr , stack )
355355 context = Of . error_var ( var , context )
356- error = { :badpattern , meta , expr , nil , :default , context }
356+ error = { :badmatch , meta , expr , context }
357357 error ( __MODULE__ , error , meta , stack , context )
358358 end
359359
360- @ doc """
361- Marks a badpattern error.
362- """
363- def badpattern_error ( expr , index , tag , stack , context ) do
360+ defp badpattern_error ( expr , index , tag , stack , context ) do
364361 meta = error_meta ( expr , stack )
365- error = { :badpattern , meta , expr , index , tag , context }
362+ error = { :badpattern , meta , index , tag , context }
366363 error ( __MODULE__ , error , meta , stack , context )
367364 end
368365
369366 @ doc """
370- Marks a badpattern warnings .
367+ Warns on redundant clause .
371368 """
372- def badpattern_warn ( expr , tag , stack , context ) do
373- meta = error_meta ( expr , stack )
374- error = { :badpattern , meta , expr , nil , tag , context }
375- warn ( __MODULE__ , error , meta , stack , context )
369+ def redundant_warn ( { :-> , meta , [ head , _ ] } , previous , stack , context ) do
370+ warning = { :redundant_clause , head , previous , context }
371+ warn ( __MODULE__ , warning , meta , stack , context )
376372 end
377373
378374 defp error_meta ( expr , stack ) do
@@ -1313,6 +1309,27 @@ defmodule Module.Types.Pattern do
13131309
13141310 ## Helpers
13151311
1312+ def format_diagnostic ( { :badstruct , type , expr , context } ) do
1313+ traces = collect_traces ( expr , context )
1314+
1315+ % {
1316+ details: % { typing_traces: traces } ,
1317+ message:
1318+ IO . iodata_to_binary ( [
1319+ """
1320+ expected an atom as struct name:
1321+
1322+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
1323+
1324+ got type:
1325+
1326+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
1327+ """ ,
1328+ format_traces ( traces )
1329+ ] )
1330+ }
1331+ end
1332+
13161333 def format_diagnostic ( { :badguard , type , expr , context } ) do
13171334 traces = collect_traces ( expr , context )
13181335
@@ -1351,39 +1368,54 @@ defmodule Module.Types.Pattern do
13511368 }
13521369 end
13531370
1354- def format_diagnostic ( { :badstruct , type , expr , context } ) do
1355- traces = collect_traces ( expr , context )
1371+ def format_diagnostic ( { :redundant_clause , args , previous , context } ) do
1372+ traces = collect_traces ( args , context )
13561373
13571374 % {
13581375 details: % { typing_traces: traces } ,
13591376 message:
13601377 IO . iodata_to_binary ( [
13611378 """
1362- expected an atom as struct name :
1379+ the following clause is redundant :
13631380
1364- #{ expr_to_string ( expr ) |> indent ( 4 ) }
1381+ #{ args_to_string ( args ) |> indent ( 4 ) } ->
13651382
1366- got type :
1383+ previous clauses have already matched on the following types :
13671384
1368- #{ to_quoted_string ( type ) |> indent ( 4 ) }
1385+ #{ previous_to_string ( previous ) }
13691386 """ ,
13701387 format_traces ( traces )
13711388 ] )
13721389 }
13731390 end
13741391
1375- # $ type tag = head_pattern() or match_pattern()
1392+ def format_diagnostic ( { :badmatch , _meta , pattern , context } ) do
1393+ traces = collect_traces ( pattern , context )
1394+
1395+ % {
1396+ details: % { typing_traces: traces } ,
1397+ message:
1398+ IO . iodata_to_binary ( [
1399+ """
1400+ the following pattern will never match:
1401+
1402+ #{ expr_to_string ( pattern ) |> indent ( 4 ) }
1403+ """ ,
1404+ format_traces ( traces )
1405+ ] )
1406+ }
1407+ end
1408+
1409+ # $ type tag = {:def, kind, fun, args, guards, types} or clause_pattern() or match_pattern()
13761410 #
1377- # $ typep head_pattern =
1378- # :fn or :default or
1379- # {{:case | :try_else, meta, expr, type}, [arg], [previous]} or
1380- # {:for_reduce | :receive | :try_catch | :with_else | :fn, [arg], [previous]}
1411+ # $ typep clause_pattern =
1412+ # {{:case | :try_else, meta, expr, type}, [arg], [previous]} or
1413+ # {:for_reduce | :receive | :try_catch | :with_else | :fn, [arg], [previous]}
13811414 #
13821415 # $ typep match_pattern =
1383- # :with or :for or {:match, type}
1384- def format_diagnostic ( { :badpattern , meta , pattern_or_expr , index , tag , context } ) do
1385- # TODO: stop passing pattern_or_expr as argument
1386- { to_trace , message } = badpattern ( tag , pattern_or_expr , index )
1416+ # {:with or :for or :match, pattern, type}
1417+ def format_diagnostic ( { :badpattern , meta , index , tag , context } ) do
1418+ { to_trace , message } = badpattern ( tag , index )
13871419 traces = collect_traces ( to_trace , context )
13881420
13891421 hints =
@@ -1398,7 +1430,35 @@ defmodule Module.Types.Pattern do
13981430 }
13991431 end
14001432
1401- defp badpattern ( { { op , meta , expr , type } , args , previous } , _ , _ ) when op in [ :case , :try_else ] do
1433+ defp badpattern ( { :def , _kind , _fun , args , _guards , types } , index )
1434+ when is_integer ( index ) do
1435+ arg = Enum . fetch! ( args , index )
1436+ type = Enum . fetch! ( types , index )
1437+
1438+ if type == dynamic ( ) do
1439+ { arg ,
1440+ """
1441+ the #{ integer_to_ordinal ( index + 1 ) } pattern in clause will never match:
1442+
1443+ #{ expr_to_string ( arg ) |> indent ( 4 ) }
1444+ """ }
1445+ else
1446+ # This can only happen in protocol implementations for now
1447+ { arg ,
1448+ """
1449+ the #{ integer_to_ordinal ( index + 1 ) } pattern in clause will never match:
1450+
1451+ #{ expr_to_string ( arg ) |> indent ( 4 ) }
1452+
1453+ because it is expected to receive type:
1454+
1455+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
1456+ """ }
1457+ end
1458+ end
1459+
1460+ defp badpattern ( { { op , meta , expr , type } , args , previous } , _index )
1461+ when op in [ :case , :try_else ] do
14021462 type_check = meta [ :type_check ]
14031463
14041464 cond do
@@ -1485,7 +1545,7 @@ defmodule Module.Types.Pattern do
14851545 #{ to_quoted_string ( type ) |> indent ( 4 ) }
14861546 """ }
14871547
1488- args_subtype? ( [ type ] , previous ) ->
1548+ true ->
14891549 { args ,
14901550 """
14911551 the following clause cannot match because the previous clauses already matched all possible values:
@@ -1500,80 +1560,42 @@ defmodule Module.Types.Pattern do
15001560
15011561 #{ to_quoted_string ( type ) |> indent ( 4 ) }
15021562 """ }
1503-
1504- true ->
1505- { args ,
1506- """
1507- the following clause is redundant:
1508-
1509- #{ args_to_string ( args ) |> indent ( 4 ) } ->
1510-
1511- previous clauses have already matched on the following types:
1512-
1513- #{ previous_to_string ( previous ) }
1514- """ }
15151563 end
15161564 end
15171565
1518- defp badpattern ( { op , args , previous } , _ , _ )
1519- when op in [ :receive , :try_catch , :for_reduce , :with_else , :fn ] do
1520- { args ,
1521- """
1522- the following clause is redundant:
1523-
1524- #{ args_to_string ( args ) |> indent ( 4 ) } ->
1525-
1526- previous clauses have already matched on the following types:
1566+ defp badpattern ( { op , args , _previous } , index )
1567+ when op in [ :for_reduce , :receive , :try_catch , :with_else , :fn ] do
1568+ arg = Enum . fetch! ( args , index )
15271569
1528- #{ previous_to_string ( previous ) }
1529- """ }
1530- end
1531-
1532- defp badpattern ( { :match , type } , expr , _ ) do
1533- { expr ,
1570+ { arg ,
15341571 """
15351572 the following pattern will never match:
15361573
1537- #{ expr_to_string ( expr ) |> indent ( 4 ) }
1538-
1539- because the right-hand side has type:
1540-
1541- #{ to_quoted_string ( type ) |> indent ( 4 ) }
1574+ #{ expr_to_string ( arg ) |> indent ( 4 ) }
15421575 """ }
15431576 end
15441577
1545- defp badpattern ( { :infer , types } , pattern_or_expr , index ) when is_integer ( index ) do
1546- type = Enum . fetch! ( types , index )
1578+ defp badpattern ( { op , pattern , type } , _index ) when op in [ :match , :for , :with ] do
1579+ message =
1580+ if type == dynamic ( ) do
1581+ """
1582+ the following pattern will never match:
15471583
1548- if type == dynamic ( ) do
1549- { pattern_or_expr ,
1550- """
1551- the #{ integer_to_ordinal ( index + 1 ) } pattern in clause will never match:
1552-
1553- #{ expr_to_string ( pattern_or_expr ) |> indent ( 4 ) }
1554- """ }
1555- else
1556- # This can only happen in protocol implementations
1557- { pattern_or_expr ,
1558- """
1559- the #{ integer_to_ordinal ( index + 1 ) } pattern in clause will never match:
1560-
1561- #{ expr_to_string ( pattern_or_expr ) |> indent ( 4 ) }
1584+ #{ expr_to_string ( pattern ) |> indent ( 4 ) }
1585+ """
1586+ else
1587+ """
1588+ the following pattern will never match:
15621589
1563- because it is expected to receive type:
1590+ #{ expr_to_string ( pattern ) |> indent ( 4 ) }
15641591
1565- #{ to_quoted_string ( type ) |> indent ( 4 ) }
1566- """ }
1567- end
1568- end
1592+ because the right-hand side has type:
15691593
1570- defp badpattern ( _ , pattern_or_expr , _ ) do
1571- { pattern_or_expr ,
1572- """
1573- the following pattern will never match:
1594+ #{ to_quoted_string ( type ) |> indent ( 4 ) }
1595+ """
1596+ end
15741597
1575- #{ expr_to_string ( pattern_or_expr ) |> indent ( 4 ) }
1576- """ }
1598+ { pattern , message }
15771599 end
15781600
15791601 defp args_to_string ( args ) do
0 commit comments