@@ -63,7 +63,7 @@ export @traitor, supertrait, betray!
6363using  Cassette
6464
6565#  A context for doing nothing
66- Cassette. @context  RoundTrip 
66+ Cassette. @context  DoNothingCtx 
6767
6868
6969""" 
@@ -124,6 +124,9 @@ is returns their common supertype (or else throws an error).
124124        end 
125125        (Tb isa  Union) ||  break 
126126    end 
127+     if  traitclass ==  Any
128+         error (" $T  does not have a supertrait." 
129+     end 
127130    return  traitclass
128131end 
129132supertrait (t) =  error (" Unknown trait $t " 
@@ -190,6 +193,11 @@ if necessary, the first time it is called) the table joining the traits to
190193the submethods 
191194""" 
192195@generated  function  get_trait_table (f:: Function , :: Type{Signature} ) where  {Signature <:  Tuple }
196+     #  This is a questionable usage of a generated function. The idea is that it's an 'elegant' way
197+     #  to create an independant global dictionary for each method specification which can later be mutated.
198+     #  The problem is that if this generated function gets recompiled for some reason (which the compiler
199+     #  is allowed to do!) then the dictionary will be replaced with a new empty dict, deleting our trait
200+     #  table.
193201    d =  Dict {Any, Function} ()
194202    return  quote 
195203        $ (Expr (:meta , :inline ))
@@ -267,25 +275,24 @@ macro traitor(ex)
267275
268276    dispatchname =  gensym (Symbol (funcname, :_dispatched ))
269277
270-     #  Traitor.trait_dispatch,Tuple{Base.Dict{Any, Function}, Type{Tuple{Int64}}}
271-     #  Traitor.supertrait, Tuple{Type{Main.Small}}
272- 
273278    ex =  quote 
274279        $ Traitor. @generated  function  $funcname ($ (args... )) 
275280            dict =  Traitor. get_trait_table ($ funcname, $ (Expr (:curly , :Tuple , argtypes... )))
276281            thunk =  () ->  Traitor. trait_dispatch (dict, $ (Expr (:curly , :Tuple , argnames... )))
277282
278-             #  This cassette overdub pass literally does nothing. I can't figure out why this
279-             #  doesn't work without it
280-             $ dispatchname =  $ Cassette. overdub ($ RoundTrip (), thunk)
283+             #  This cassette overdub pass literally does nothing other than normal evaluation.
284+             #  However, if I don't use it, the backedge attachment later on doesn't appear
285+             #  to have the desired effect.
286+             $ dispatchname =  $ Cassette. overdub ($ DoNothingCtx (), thunk)
281287            # $dispatchname = thunk()
282288            ex =  (Expr (:call , $ dispatchname, $ (QuoteNode .(argnames)... )))
283- 
289+   
284290            #  Create a codeinfo
285291            ci =  $ expr_to_codeinfo ($ (__module__), [Symbol (" #self#" $ (quotednames... )], [], (), ex)
286292
287-             # Make it so that anything that'd cause the trait_dispatch function to recompile, also
288-             # causes this function to recompile
293+             #  Attached edges from MethodInstrances of the `supertrait` function to to this CodeInfo.
294+             #  This should make it so that adding members to a trait relevant to this function
295+             #  triggers recompilation, fixing the #265 equivalent for trait methods.
289296            ci. edges =  $ Core. MethodInstance[]
290297            for  TT in  [$ (traits... )]
291298                for  T in  TT. parameters
@@ -305,8 +312,29 @@ macro traitor(ex)
305312    esc (ex)
306313end 
307314
315+ """ 
316+     expr_to_codeinfo(m::Module, argnames, spnames, sp, e::Expr) 
317+ 
318+ Take an expr (usually a generated function generator) and convert it into a CodeInfo object  
319+ (Julia's internal, linear representation of code).  
320+ 
321+ `m` is the module that the CodeInfo should be generated from (used for name resolution) 
308322
309- function  expr_to_codeinfo (m, argnames, spnames, sp, e)
323+ `argnames` must be an iterable container of symbols describing the CodeInfo's input arguments.  
324+ NOTE: the first argument should be given as `Symbol("#self#")`. So if the function is `f(x) = x + 1`, 
325+ then `argnames = [Symbol("#self#"), :x]` 
326+ 
327+ `spnames` should be an iterable container of the names of the static parameters to the CodeInfo body 
328+ (e.g.) in `f(x::T) where {T <: Int} = ...`, `T` is a static parameter, so `spnames` should be `[:T]`  
329+ 
330+ `sp` should be an iterable container of the static parameters to the CodeInfo body themselves (as  
331+ opposed to their names) (e.g.) in `f(x::T) where {T <: Int} = ...`, `T` is a static parameter,  
332+ so `sp` should be `[T]`  
333+ 
334+ `e` is the actual expression to lower to CodeInfo. This must be 'pure' in the same sense as generated 
335+ function bodies. 
336+ """ 
337+ function  expr_to_codeinfo (m:: Module , argnames, spnames, sp, e:: Expr )
310338    lam =  Expr (:lambda , argnames,
311339               Expr (Symbol (" scope-block" 
312340                    Expr (:block ,
@@ -323,12 +351,11 @@ function expr_to_codeinfo(m, argnames, spnames, sp, e)
323351    #  Get the code-info for the generatorbody in order to use it for generating a dummy
324352    #  code info object.
325353    ci =  ccall (:jl_expand_and_resolve , Any, (Any, Any, Core. SimpleVector), ex, m, Core. svec (sp... ))
326-     @assert  ci isa  Core. CodeInfo " Failed to compile @staged function . This might mean it contains a closure or comprehension?" 
354+     @assert  ci isa  Core. CodeInfo " Failed to create a CodeInfo from the given expression . This might mean it contains a closure or comprehension?\n  Offending expression:  $e " 
327355    ci
328356end 
329357
330358
331- 
332359""" 
333360This function deterimines the dispatch on the traits. Each instance of 
334361this generated function is specialized on the (standard) signature of the 
0 commit comments