@@ -32,29 +32,27 @@ defmodule Module.Types.Pattern do
3232 dynamic = dynamic ( )
3333 expected_types = Enum . map ( patterns , fn _ -> dynamic end )
3434
35- with { :ok , _trees , types , context } <-
36- of_pattern_args ( patterns , expected_types , stack , context ) do
37- { _ , context } = Enum . map_reduce ( guards , context , & of_guard ( & 1 , @ guard , & 1 , stack , & 2 ) )
38- { :ok , types , context }
39- end
35+ { _trees , types , context } = of_pattern_args ( patterns , expected_types , stack , context )
36+ { _ , context } = Enum . map_reduce ( guards , context , & of_guard ( & 1 , @ guard , & 1 , stack , & 2 ) )
37+ { :ok , types , context }
4038 end
4139
4240 defp of_pattern_args ( [ ] , [ ] , _stack , context ) do
43- { :ok , [ ] , context }
41+ { [ ] , [ ] , context }
4442 end
4543
46- defp of_pattern_args ( patterns , expected_types , stack , init_context ) do
47- context = % { init_context | pattern_info: { % { } , % { } } , failed: false }
44+ defp of_pattern_args ( patterns , expected_types , stack , context ) do
45+ context = % { context | pattern_info: { % { } , % { } } }
4846 changed = :lists . seq ( 0 , length ( patterns ) - 1 )
4947
5048 { trees , context } = of_pattern_args_index ( patterns , expected_types , 0 , [ ] , stack , context )
5149
52- with { :ok , types , context } <-
53- of_pattern_recur ( expected_types , changed , stack , context , fn types , changed , context ->
54- of_pattern_args_tree ( trees , types , changed , 0 , [ ] , stack , context )
55- end ) do
56- { :ok , trees , types , merge_failed ( init_context , context ) }
57- end
50+ { types , context } =
51+ of_pattern_recur ( expected_types , changed , stack , context , fn types , changed , context ->
52+ of_pattern_args_tree ( trees , types , changed , 0 , [ ] , stack , context )
53+ end )
54+
55+ { trees , types , context }
5856 end
5957
6058 defp of_pattern_args_index (
@@ -107,80 +105,86 @@ defmodule Module.Types.Pattern do
107105 Return the type and typing context of a pattern expression with
108106 the given expected and expr or an error in case of a typing conflict.
109107 """
110- def of_match ( pattern , expected , expr , stack , init_context ) do
111- context = % { init_context | pattern_info: { % { } , % { } } , failed: false }
108+ def of_match ( pattern , expected , expr , stack , context ) do
109+ context = % { context | pattern_info: { % { } , % { } } }
112110 { tree , context } = of_pattern ( pattern , [ { :arg , 0 , expected , expr } ] , stack , context )
113111
114- with { :ok , [ type ] , context } <-
115- of_pattern_recur ( [ expected ] , [ 0 ] , stack , context , fn [ type ] , [ 0 ] , context ->
116- with { :ok , type , context } <- of_pattern_intersect ( tree , type , expr , stack , context ) do
117- { :ok , [ type ] , context }
118- end
119- end ) do
120- { type , merge_failed ( init_context , context ) }
121- else
122- { :error , context } -> { error_type ( ) , context }
123- end
112+ { [ type ] , context } =
113+ of_pattern_recur ( [ expected ] , [ 0 ] , stack , context , fn [ type ] , [ 0 ] , context ->
114+ with { :ok , type , context } <- of_pattern_intersect ( tree , type , expr , stack , context ) do
115+ { :ok , [ type ] , context }
116+ end
117+ end )
118+
119+ { type , context }
124120 end
125121
126122 defp of_pattern_recur ( types , changed , stack , context , callback ) do
127123 % { pattern_info: { pattern_vars , pattern_args } } = context
128124 context = % { context | pattern_info: nil }
129125 pattern_vars = Map . to_list ( pattern_vars )
130126 of_pattern_recur ( types , changed , pattern_vars , pattern_args , stack , context , callback )
127+ catch
128+ { types , context } -> { types , context }
131129 end
132130
133131 defp of_pattern_recur ( types , [ ] , _vars , _args , _stack , context , _callback ) do
134- { :ok , types , context }
135- end
136-
137- defp of_pattern_recur ( _types , _ , _vars , _args , _stack , % { failed: true } = context , _callback ) do
138- { :error , context }
132+ { types , context }
139133 end
140134
141135 defp of_pattern_recur ( types , changed , vars , args , stack , context , callback ) do
142- with { :ok , types , % { vars: context_vars } = context } <- callback . ( types , changed , context ) do
143- { changed , context } =
144- Enum . reduce ( vars , { [ ] , context } , fn { version , paths } , { changed , context } ->
145- current_type = context_vars [ version ] [ :type ]
146-
147- { var_changed? , context } =
148- Enum . reduce ( paths , { false , context } , fn
149- [ var , { :arg , index , expected , expr } | path ] , { var_changed? , context } ->
150- actual = Enum . fetch! ( types , index )
151-
152- case of_pattern_var ( path , actual ) do
153- { :ok , type } ->
154- { type , context } = Of . refine_var ( var , type , expr , stack , context )
155- { var_changed? or current_type != type , context }
156-
157- :error ->
158- { var_changed? , Of . incompatible_error ( expr , expected , actual , stack , context ) }
159- end
160- end )
161-
162- case var_changed? do
163- false ->
164- { changed , context }
165-
166- true ->
167- case paths do
168- # A single change, check if there are other variables in this index.
169- [ [ _var , { :arg , index , _ , _ } | _ ] ] ->
170- case args do
171- % { ^ index => true } -> { [ index | changed ] , context }
172- % { ^ index => false } -> { changed , context }
136+ case callback . ( types , changed , context ) do
137+ { :ok , types , % { vars: context_vars } = context } ->
138+ { changed , context } =
139+ Enum . reduce ( vars , { [ ] , context } , fn { version , paths } , { changed , context } ->
140+ current_type = context_vars [ version ] [ :type ]
141+
142+ { var_changed? , context } =
143+ Enum . reduce ( paths , { false , context } , fn
144+ [ var , { :arg , index , expected , expr } | path ] , { var_changed? , context } ->
145+ actual = Enum . fetch! ( types , index )
146+
147+ case of_pattern_var ( path , actual ) do
148+ { :ok , type } ->
149+ case Of . refine_var ( var , type , expr , stack , context ) do
150+ { :ok , type , context } ->
151+ { var_changed? or current_type != type , context }
152+
153+ { :error , _type , context } ->
154+ throw ( { types , context } )
155+ end
156+
157+ :error ->
158+ context = Of . incompatible_error ( expr , expected , actual , stack , context )
159+ throw ( { types , context } )
173160 end
161+ end )
162+
163+ case var_changed? do
164+ false ->
165+ { changed , context }
166+
167+ true ->
168+ case paths do
169+ # A single change, check if there are other variables in this index.
170+ [ [ _var , { :arg , index , _ , _ } | _ ] ] ->
171+ case args do
172+ % { ^ index => true } -> { [ index | changed ] , context }
173+ % { ^ index => false } -> { changed , context }
174+ end
175+
176+ # Several changes, we have to recompute all indexes.
177+ _ ->
178+ var_changed = Enum . map ( paths , fn [ _var , { :arg , index , _ , _ } | _ ] -> index end )
179+ { var_changed ++ changed , context }
180+ end
181+ end
182+ end )
174183
175- # Several changes, we have to recompute all indexes.
176- _ ->
177- var_changed = Enum . map ( paths , fn [ _var , { :arg , index , _ , _ } | _ ] -> index end )
178- { var_changed ++ changed , context }
179- end
180- end
181- end )
184+ of_pattern_recur ( types , :lists . usort ( changed ) , vars , args , stack , context , callback )
182185
183- of_pattern_recur ( types , :lists . usort ( changed ) , vars , args , stack , context , callback )
186+ { :error , context } ->
187+ { types , context }
184188 end
185189 end
186190
@@ -284,7 +288,8 @@ defmodule Module.Types.Pattern do
284288 end
285289
286290 def of_match_var ( var , expected , expr , stack , context ) when is_var ( var ) do
287- Of . refine_var ( var , expected , expr , stack , context )
291+ { _ok? , type , context } = Of . refine_var ( var , expected , expr , stack , context )
292+ { type , context }
288293 end
289294
290295 def of_match_var ( ast , expected , expr , stack , context ) do
@@ -657,9 +662,6 @@ defmodule Module.Types.Pattern do
657662
658663 ## Helpers
659664
660- defp merge_failed ( % { failed: false } , % { failed: false } = post ) , do: post
661- defp merge_failed ( _pre , post ) , do: % { post | failed: true }
662-
663665 def format_diagnostic ( { :invalid_pattern , expr , context } ) do
664666 traces = collect_traces ( expr , context )
665667
0 commit comments