Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tagging causing inconsistent behavior #133

Open
jarredbarber opened this issue Jun 20, 2019 · 4 comments
Open

Tagging causing inconsistent behavior #133

jarredbarber opened this issue Jun 20, 2019 · 4 comments

Comments

@jarredbarber
Copy link

jarredbarber commented Jun 20, 2019

The following code should produce the same output twice. However, when tagging is enabled, wildly different code branches seem to be taken, and the tagging version fails with a MethodError

Code:

# Minimialist example of tagging bug
using Cassette
using Cassette: tag, untag, @context, metadatatype, metadata, hasmetadata, enabletagging, overdub, recurse

@context TagCtx

Cassette.metadatatype(ctx::Type{<:TagCtx}, ::Type) = Type
Cassette.metadatatype(ctx::Type{<:TagCtx}, ::DataType) = Type

function Cassette.overdub(ctx::TagCtx, fn, args...)
    Core.println("fn: $fn")
    val = recurse(ctx, fn, args...)
    hasmetadata(val, ctx) ? val : tag(val, ctx, typeof(val))
end

@context IdentityCtx
function Cassette.overdub(ctx::IdentityCtx, fn, args...)
    Core.println("fn: $fn")
    recurse(ctx, fn, args...)
end

function fn()
    Main.println("help")
end

println("Identity ctx:")
overdub(IdentityCtx(), fn)
println("Tagging ctx:")
overdub(enabletagging(TagCtx(), fn), fn)

When IdentityCtx runs (first 20 lines):

Identity ctx:
fn: fn
fn: println
fn: typeassert
fn: tuple
fn: println
fn: tuple
fn: tuple
fn: print
fn: lock
fn: lock
fn: current_task
fn: ==
fn: ===
fn: ===
fn: setproperty!
fn: typeof
fn: fieldtype
fn: convert
fn: setfield!                                                                                          

When the TaggingCtx runs (first 20 lines)j:

Tagging ctx:
fn: fn
fn: println
fn: iterate
fn: iterate
fn: <=
fn: length
fn: nfields
fn: <=
fn: getindex
fn: +
fn: iterate
fn: <=
fn: length
fn: nfields
fn: <=
fn: iterate
fn: iterate
fn: <=
fn: length

The IdentityCtx case runs to the end, but the tagging one fails after some number of lines, with a very deep stack trace (43 entries):

fn: notify                                                                                                         
fn: Base.#notify#442                                                                                               
fn: notify                                                                                                         
fn: getproperty                                                                                                    
fn: length                                                                                                         
fn: getproperty                                                                                                    
fn: iterate                                                                                                        
fn: iterate                                                                                                        
fn: rem                                                                                                            
fn: -                                                                                                              
fn: Base.promote_typeof                                                                                            
fn: typeof                                                                                                         
fn: Base.promote_typeof                                                                                            
fn: typeof                                                                                                         
fn: promote_type                                                                                                   
fn: rem                                                                                                            
ERROR: LoadError: MethodError: no method matching rem(::UInt64, ::TypeVar)                                         
Closest candidates are:                                                                                            
  rem(::Any, ::Any, !Matched::RoundingMode{:ToZero}) at math.jl:739                                                
  rem(::Any, ::Any, !Matched::RoundingMode{:Down}) at math.jl:740                                                  
  rem(::Any, ::Any, !Matched::RoundingMode{:Up}) at math.jl:741                                                    
  ...                                                                                                              
Stacktrace:                                                                                                        
 [1] call at /home/jarred/.julia/dev/Cassette/src/context.jl:448 [inlined]                                         
 [2] fallback at /home/jarred/.julia/dev/Cassette/src/context.jl:445 [inlined]                                     
 [3] recurse(::Cassette.Context{nametype(TagCtx),Nothing,Cassette.Tag{nametype(TagCtx),0x33c08e1374a2590a,Nothing},g
etfield(Cassette, Symbol("##PassType#365")),IdDict{Module,Dict{Symbol,Cassette.BindingMeta}},Nothing}, ::typeof(rem)
, ::Cassette.Tagged{Cassette.Tag{nametype(TagCtx),0x33c08e1374a2590a,Nothing},UInt64,Type,Cassette.NoMetaMeta,Casset
te.Context{nametype(TagCtx),Nothing,Cassette.Tag{nametype(TagCtx),0x33c08e1374a2590a,Nothing},getfield(Cassette, Sym
bol("##PassType#365")),IdDict{Module,Dict{Symbol,Cassette.BindingMeta}},Nothing}}, ::Cassette.Tagged{Cassette.Tag{na
metype(TagCtx),0x33c08e1374a2590a,Nothing},TypeVar,Type,NamedTuple{(:name, :lb, :ub),Tuple{Cassette.Mutable{Cassette
.Meta{Type,Cassette.NoMetaMeta}},Cassette.Mutable{Cassette.Meta},Cassette.Mutable{Cassette.Meta}}},Cassette.Context{
nametype(TagCtx),Nothing,Cassette.Tag{nametype(TagCtx),0x33c08e1374a2590a,Nothing},getfield(Cassette, Symbol("##Pass
Type#365")),IdDict{Module,Dict{Symbol,Cassette.BindingMeta}},Nothing}}) at /home/jarred/.julia/dev/Cassette/src/over
dub.jl:481                       
@femtomc
Copy link

femtomc commented Jun 23, 2019

Note that Core.println actually throws a different error:

ArgumentError: nothing should not be printed; use show, repr, or custom output instead.

I still don't really understand the difference between Main.println and Core.println but this might be related to the async IO comments on the Julia slack.

@vchuravy
Copy link
Member

Notes from my exploration today. You shouldn't need to untag yourself. recurse should to that, but we seem to put something into a tuple instead of splatting it.

@femtomc
Copy link

femtomc commented Jun 24, 2019

Looks like the ntuple-ing on L448 in context.jl:

@inline call(context::ContextTagged, f, args...) = untag(f, context)(ntuple(i -> untag(args[i], context), Val(nfields(args)))...)

Will try a few things if I have time today.

@jarredbarber
Copy link
Author

@vchuravy I edited the example to not manually untag things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants