@@ -408,6 +408,11 @@ defmodule Module.Types.Pattern do
408408 end )
409409 end
410410
411+ defp match_var do
412+ version = make_ref ( )
413+ { version , { :match , [ version: version ] , __MODULE__ } }
414+ end
415+
411416 defp match_error? ( { :match , _ , __MODULE__ } , _type ) , do: true
412417 defp match_error? ( _var , type ) , do: empty? ( type )
413418
@@ -651,8 +656,8 @@ defmodule Module.Types.Pattern do
651656 |> Enum . split_while ( & ( not is_versioned_var ( & 1 ) ) )
652657 |> case do
653658 { matches , [ ] } ->
654- version = make_ref ( )
655- { true , matches , version , { :match , [ version: version ] , __MODULE__ } }
659+ { version , var } = match_var ( )
660+ { true , matches , version , var }
656661
657662 { pre , [ { _ , meta , _ } = var | post ] } ->
658663 version = Keyword . fetch! ( meta , :version )
@@ -1018,7 +1023,8 @@ defmodule Module.Types.Pattern do
10181023 guard_context: :andalso ,
10191024 parent_version: nil ,
10201025 vars: vars ,
1021- changed: % { }
1026+ changed: % { } ,
1027+ subpatterns: % { }
10221028 } )
10231029
10241030 { precise? , context } = of_guards ( guards , stack , context )
@@ -1064,7 +1070,7 @@ defmodule Module.Types.Pattern do
10641070 { false , context }
10651071
10661072 { true , maybe_or_always } ->
1067- { maybe_or_always == :always , context }
1073+ { maybe_or_always == :always and context . pattern_info . subpatterns == % { } , context }
10681074
10691075 _false_tuple_or_none ->
10701076 error = { :badguard , type , guard , context }
@@ -1315,6 +1321,42 @@ defmodule Module.Types.Pattern do
13151321 end
13161322 end
13171323
1324+ # We cannot track precision for lists, so we assign match variables
1325+ # to hd/tl and refine them accordingly.
1326+ defp of_remote (
1327+ fun ,
1328+ [ arg ] ,
1329+ call ,
1330+ expected ,
1331+ stack ,
1332+ % { pattern_info: % { subpatterns: subpatterns } } = context
1333+ )
1334+ when fun in [ :hd , :tl ] do
1335+ arg_key =
1336+ Macro . prewalk ( arg , fn
1337+ { left , meta , right } -> { left , Keyword . take ( meta , [ :version ] ) , right }
1338+ node -> node
1339+ end )
1340+
1341+ subpattern_key = { fun , arg_key }
1342+
1343+ { var , context } =
1344+ case subpatterns do
1345+ % { ^ subpattern_key => var } ->
1346+ { var , context }
1347+
1348+ % { } ->
1349+ { type , context } =
1350+ Apply . remote ( :erlang , fun , [ arg ] , expected , call , stack , context , & of_guard / 5 )
1351+
1352+ { _ , var } = match_var ( )
1353+ context = Of . declare_var ( var , type , context )
1354+ { var , put_in ( context . pattern_info . subpatterns [ subpattern_key ] , var ) }
1355+ end
1356+
1357+ of_guard ( var , expected , call , stack , context )
1358+ end
1359+
13181360 defp of_remote ( fun , args , call , expected , stack , context ) do
13191361 Apply . remote ( :erlang , fun , args , expected , call , stack , context , & of_guard / 5 )
13201362 end
0 commit comments