Skip to content

syntax_pos::symbol::Symbol::gensym() is incompatible with stable hashing. #49300

Closed

Description

@michaelwoerister

The current scheme for "gensym"ing names via Symbol::gensym() is rather clever and elegant but unfortunately it defies being hashed in a stable way as is needed for incremental compilation. So far, incr. comp. has erroneously treated differing Symbols with equal string contents as being the same. Now situations are starting to arise where this leads to problems (#48923, #49065).

I consider this a somewhat urgent issue.

cc @rust-lang/compiler, esp. @petrochenkov & @jseyfried

Activity

  1. added
    A-syntaxextArea: Syntax extensions
    A-resolveArea: Name/path resolution done by `rustc_resolve` specifically
    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
    A-incr-compArea: Incremental compilation
    C-bugCategory: This is a bug.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Mar 23, 2018
  2. eddyb commented on Mar 23, 2018

    @eddyb
    Contributor

    I generally consider gensym problematic and would prefer it if all hygiene was done through Span.
    There are maybe a few non-hygiene uses but they should probably be done in other ways.

  3. petrochenkov commented on Mar 23, 2018

    @petrochenkov
    Contributor

    We should investigate implementing gensyms via SyntaxContext (which means via Span after #49154).
    In theory, every situation when symbol != gensym(symbol) makes sense should include hygiene into comparison as well.
    If "gensymness" is kept in SyntaxContext side tables somehow, then symbol1 == symbol2 will always be equivalent to string_content(symbol1) == string_content(symbol2), that also looks like a simplification of the mental model to me.

  4. petrochenkov commented on Mar 30, 2018

    @petrochenkov
    Contributor

    Blocked on removing emulation of hygiene with gensyms (can't emulate gensyms with hygiene if we are doing exactly the opposite thing right now!) (https://github.com/petrochenkov/rust/tree/spident2, in progress), which in its turn is waiting for #49154 and #49718.

  5. oli-obk commented on Apr 12, 2018

    @oli-obk
    Contributor

    Could gensym generate a name with a stable prefix (proc macro crate name + version), a stable ID (proc macro invocation local) and some character that is illegal in names, so noone can name it? Maybe even throw in the stable hash of the code it is invoked upon?

  6. nikomatsakis commented on May 10, 2018

    @nikomatsakis
    Contributor

    Categorizing as P-high so that this keeps annoying us, even though we don't have anyone assigned to it or actively working on it.

  7. michaelwoerister commented on May 25, 2018

    @michaelwoerister
    MemberAuthor

    We've been coming back to this issue in the @rust-lang/compiler meeting without progress for a few weeks in a row now. It would be great if we could come up with some action items. @petrochenkov , the two blocking PRs you mentioned above have be merged in the meantime. What would be the next steps? Or broader question: Do we know what to do and just need to implement it or are there still open questions about how this can be solved?

  8. 10 remaining items

  9. michaelwoerister commented on Jul 13, 2018

    @michaelwoerister
    MemberAuthor

    Thanks for the awesome work so far, @petrochenkov!

    The current situation is that we don't use gensym anymore but we are still not hashing things properly: #51492 (comment)

    I haven't had time to think about the various solution strategies yet.

  10. pnkfelix commented on Aug 2, 2018

    @pnkfelix
    Contributor

    visiting for triage. No progress yet. Should consider either reassigning or lowering priority if we are still stalled next week.

  11. nikomatsakis commented on Aug 9, 2018

    @nikomatsakis
    Contributor

    The problem remains, but at least we have some kind of assertion that should catch problems related to it. Going to downgrade to P-medium for now.

  12. added and removed
    P-highHigh priority
    on Aug 9, 2018
  13. michaelwoerister commented on Aug 9, 2018

    @michaelwoerister
    MemberAuthor

    ... but at least we have some kind of assertion that should catch problems related to it

    In particular, this one:

    // If the following assertion triggers, it can have two reasons:
    // 1. Something is wrong with DepNode creation, either here or
    // in DepGraph::try_mark_green()
    // 2. Two distinct query keys get mapped to the same DepNode
    // (see for example #48923)
    assert!(!self.dep_graph.dep_node_exists(&dep_node),
    "Forcing query with already existing DepNode.\n\
    - query-key: {:?}\n\
    - dep-node: {:?}",
    key, dep_node);

  14. petrochenkov commented on Aug 28, 2019

    @petrochenkov
    Contributor

    I haven't seen this written out explicitly, but expansion/hygiene data can be stored in metadata/incremental-data in a stable way using the same DefPath approach as other things.

    The basic thing to encode here is ExpnId and it has a well-defined parent DefIndex (currently available through the Definitions::invocation_parents table).
    If multiple expansions share the parent def-path, then, I think, they should be able to just get local disambuguators.

    mod m {
        fn foo() { // def-path: m::foo
            // Here's how the closures' `NodeId`s get a stable representation.
            let closure1 = || {}; // m::foo(1)
            let closure2 = || {}; // m::foo(2)
    
            // Same idea, but for macro invocations and their `ExpnId`s instead of `NodeId`s
            mac1!(); // m::foo!(1)
            mac2!(); // m::foo!(2)
        }
    }

    If we can encode ExpnId, then we can encode SyntaxContext as well (a chain of ExpnIds), then Span and everything else.
    ExpnId is the only ID-like thing in this area, other components of hygiene structures are plain data.


    #63919 should be one of few last steps in the removal of gensyms, after that we'll only have hygiene, which should be encodable as described above, if I'm not missing anything.

  15. michaelwoerister commented on Aug 28, 2019

    @michaelwoerister
    MemberAuthor

    Hm, making macro invocations a regular DefPath component... I haven't thought about this deeply yet but it might be genius :) Then DefPath could already be assigned during parsing, with macros just adding more of them without conflicts. cc @eddyb @nikomatsakis

  16. eddyb commented on Aug 28, 2019

    @eddyb
    Contributor

    @michaelwoerister Yeah, that's also roughly my vision for moving incremental further back, I think I discussed it with @nikomatsakis before.

    I was supposed to write about this months ago but other things came up.

    In short, there'd be "Def" layer that parsing, expansion and cross-crate metadata would all interact with, with AST/HIR remaining mainly for the intra-definition syntactic categories and miscellaneous syntax.

    A first step could be splitting HIR into "HIR Def" and "everything else", but moving def paths by themselves further back would also make sense.

  17. petrochenkov commented on Aug 28, 2019

    @petrochenkov
    Contributor

    Def paths are currently created during expansion, when a freshly expanded AST fragment is integrated into the partially built AST.
    That's already early enough for representing expansions with def paths.

  18. added a commit that references this issue on Oct 15, 2019
    af3d9e5
  19. michaelwoerister commented on Oct 21, 2019

    @michaelwoerister
    MemberAuthor

    🎉 🎉 🎉 🎉 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

A-incr-compArea: Incremental compilationA-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-resolveArea: Name/path resolution done by `rustc_resolve` specificallyA-syntaxextArea: Syntax extensionsC-bugCategory: This is a bug.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions