I agree its still lossy unless we track function path separately from module path. But I favor the simplicity of the current implementation. And it's not a big deal to do this. I need it for autotrace, and it's already done. :-)

Thanks for helping me think through these corner cases. For clarification of how a loss of information could happen, I added this test case. If you think of other cases that could be ambiguous, let me know and I'll add test cases for them too.

    // and the symmetric case, where mod are duplicated:
    // If we got back only mod_path!() == "outer::M" and func!() == "c"
    //  we would not know whether outer::a::M::c was called,        
    //  or outer::b::M::c was called.
mod outer {                                                                                                                                               
        pub fn a() -> &str {
            pub mod M {
                pub fn c() -> &str { func!() }
            }
            M::c()
        }
        pub fn b() -> (&str, &str) {
            pub mod M {
                pub fn c() -> &str { func!() }
            }
            M::c()
        }
    }

    let oamc = outer::a();
    let obmc = outer::b();
    println(fmt!("oamc is %s", oamc));
    println(fmt!("obmc is %s", obmc));
    assert!(oamc.ends_with("main::outer::a::M::c"));
    assert!(obmc.ends_with("main::outer::b::M::c"));