@@ -30,17 +30,26 @@ defmodule Module.Types do
3030 @ modes [ :static , :dynamic , :infer , :traversal ]
3131
3232 # These functions are not inferred because they are added/managed by the compiler
33- @ no_infer [ __protocol__: 1 , behaviour_info: 1 ]
33+ @ no_infer [ behaviour_info: 1 ]
3434
3535 @ doc false
36- def infer ( module , file , defs , private , used_private , env , { _ , cache } ) do
37- infer_signatures? = :elixir_config . get ( :infer_signatures ) and cache != nil
36+ def infer ( module , file , attrs , defs , private , used_private , env , { _ , cache } ) do
37+ # We don't care about inferring signatures for protocols,
38+ # those will be replaced anyway. There is also nothing to
39+ # infer if there is no cache system, we only do traversals.
40+ infer_signatures? =
41+ :elixir_config . get ( :infer_signatures ) and cache != nil and not protocol? ( attrs )
42+
43+ impl = impl_for ( attrs )
3844
3945 finder =
4046 fn fun_arity ->
4147 case :lists . keyfind ( fun_arity , 1 , defs ) do
42- { _ , kind , _ , _ } = clause -> { infer_mode ( kind , infer_signatures? ) , clause }
43- false -> false
48+ { _ , kind , _ , _ } = clause ->
49+ { infer_mode ( kind , infer_signatures? ) , clause , default_domain ( fun_arity , impl ) }
50+
51+ false ->
52+ false
4453 end
4554 end
4655
@@ -67,7 +76,11 @@ defmodule Module.Types do
6776 kind in [ :def , :defmacro ] ,
6877 reduce: { [ ] , context ( ) } do
6978 { types , context } ->
70- finder = fn _ -> { infer_mode ( kind , infer_signatures? ) , def } end
79+ # Optimized version of finder, since we already the definition
80+ finder = fn _ ->
81+ { infer_mode ( kind , infer_signatures? ) , def , default_domain ( fun_arity , impl ) }
82+ end
83+
7184 { _kind , inferred , context } = local_handler ( meta , fun_arity , stack , context , finder )
7285
7386 if infer_signatures? and kind == :def and fun_arity not in @ no_infer do
@@ -111,6 +124,25 @@ defmodule Module.Types do
111124 if infer_signatures? and kind in [ :def , :defp ] , do: :infer , else: :traversal
112125 end
113126
127+ defp protocol? ( attrs ) do
128+ List . keymember? ( attrs , :__protocol__ , 0 )
129+ end
130+
131+ defp impl_for ( attrs ) do
132+ case List . keyfind ( attrs , :__impl__ , 0 ) do
133+ { :__impl__ , [ protocol: _ , for: for ] } -> for
134+ _ -> nil
135+ end
136+ end
137+
138+ defp default_domain ( { fun , arity } , impl ) when impl != nil and fun != :__impl__ and arity >= 1 do
139+ [ Module.Types.Of . impl ( impl ) | List . duplicate ( Descr . dynamic ( ) , arity - 1 ) ]
140+ end
141+
142+ defp default_domain ( { _ , arity } , _ ) do
143+ List . duplicate ( Descr . dynamic ( ) , arity )
144+ end
145+
114146 defp undefined_function! ( reason , meta , { fun , arity } , stack , env ) do
115147 env = % { env | function: stack . function , file: stack . file }
116148 tuple = { reason , { fun , arity } , stack . module }
@@ -159,10 +191,12 @@ defmodule Module.Types do
159191 end
160192
161193 @ doc false
162- def warnings ( module , file , defs , no_warn_undefined , cache ) do
194+ def warnings ( module , file , attrs , defs , no_warn_undefined , cache ) do
195+ impl = impl_for ( attrs )
196+
163197 finder = fn fun_arity ->
164198 case :lists . keyfind ( fun_arity , 1 , defs ) do
165- { _ , _ , _ , _ } = clause -> { :dynamic , clause }
199+ { _ , _ , _ , _ } = clause -> { :dynamic , clause , default_domain ( fun_arity , impl ) }
166200 false -> false
167201 end
168202 end
@@ -172,7 +206,8 @@ defmodule Module.Types do
172206
173207 context =
174208 Enum . reduce ( defs , context ( ) , fn { fun_arity , _kind , meta , _clauses } = def , context ->
175- finder = fn _ -> { :dynamic , def } end
209+ # Optimized version of finder, since we already the definition
210+ finder = fn _ -> { :dynamic , def , default_domain ( fun_arity , impl ) } end
176211 { _kind , _inferred , context } = local_handler ( meta , fun_arity , stack , context , finder )
177212 context
178213 end )
@@ -211,11 +246,11 @@ defmodule Module.Types do
211246
212247 local_sigs ->
213248 case finder . ( fun_arity ) do
214- { mode , { fun_arity , kind , meta , clauses } } ->
249+ { mode , { fun_arity , kind , meta , clauses } , expected } ->
215250 context = put_in ( context . local_sigs , Map . put ( local_sigs , fun_arity , kind ) )
216251
217252 { inferred , mapping , context } =
218- local_handler ( fun_arity , kind , meta , clauses , mode , stack , context )
253+ local_handler ( fun_arity , kind , meta , clauses , expected , mode , stack , context )
219254
220255 context =
221256 update_in ( context . local_sigs , & Map . put ( & 1 , fun_arity , { kind , inferred , mapping } ) )
@@ -228,8 +263,8 @@ defmodule Module.Types do
228263 end
229264 end
230265
231- defp local_handler ( { fun , arity } = fun_arity , kind , meta , clauses , mode , stack , context ) do
232- expected = List . duplicate ( Descr . dynamic ( ) , arity )
266+ defp local_handler ( fun_arity , kind , meta , clauses , expected , mode , stack , context ) do
267+ { fun , _arity } = fun_arity
233268 stack = stack |> fresh_stack ( mode , fun_arity ) |> with_file_meta ( meta )
234269
235270 { _ , _ , mapping , clauses_types , clauses_context } =
0 commit comments