Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upHow to determine hygienic context for "non-atomic" code fragments #50122
Comments
petrochenkov
added
the
A-macros-2.0
label
Apr 20, 2018
This comment has been minimized.
This comment has been minimized.
I think it's pretty clear that should work and expand to
Does it do so with your proposed rule? Is my intuition wrong and this shouldn't make sense? Is there a different way of composing macro imports and call locations such that it would break? My intuition is that if I name something at the call site, if the macro uses it as an item, it resolves to what it is at the call site. If I name something at the macro def site, it resolves to whatever that name means if that name had been used in a function at that source location. |
This comment has been minimized.
This comment has been minimized.
|
@CAD97 |
This comment has been minimized.
This comment has been minimized.
|
So i thought the most natural solution would be to use the call-site of the path that invoked the The second option that I currently think is natural is to use the "span of the expression" - the syntax context where the relevant expression was constructed in (is this not a valid concept in some case? this would be The above might however create some confusion (e.g. privacy in method calls - if the method name and the method call come from different scopes: what is determined by the method name, and what is determined by the method call?). The main difference between the "span of expression" and "span of characteristic token" is how you pass around expansion sites, which is by either CPS-passing a macro that constructs the expression, or using a "magic" characteristic token. |
This comment has been minimized.
This comment has been minimized.
|
In "span of expression", you can use // in mod A
macro foo($expand: ident) {
$expand!(println!("foo"));
}
// in mod B
macro expand($macro:ident ! $args:tt) {
$macro ! $args
}
foo!(expand); // this expands `println!("foo")` here.While in "span of characteristic token", you use // in mod A
macro foo($bang: tt) {
println $bang ("foo")
}
// in mod B
foo!(!); // this expands `println!("foo")` here. |
This was referenced May 1, 2018
petrochenkov
referenced this issue
May 23, 2018
Closed
don't ask what edition we are in; ask what edition a span is in #50999
This comment has been minimized.
This comment has been minimized.
|
Hmm, @petrochenkov's initial thought of a "span of characteristic token" is indeed what I initially expected, but I see the appeal of @arielb1's "span of the expresion" as well. This obviously affects the question in #50376 as well (which concerns I wanted to step back a second and try to establish what our goals are. From my perspective, we should be shooting for two things:
I was trying to think about the various things that might be tied ultimately to hygiene:
I am wondering whether these distinct uses might introduce competing demands (e.g., perhaps one gives "more natural" results with the span-of-expr approach vs span-of-characteristic-token). I suppose we must also consider |
This comment has been minimized.
This comment has been minimized.
|
Yes, @arielb1's suggestion is the primary alternative, but I think the "characteristic token" is preferable.
Simplicity, first of all! This covers both "can teach", "can specify" and also implementation complexity. Unless we a trying to assign the context to something that is never actually written in the source code like #50376, our choice should almost never matter because for In this sense characteristic token context is simpler to implement and explain because it's something "real" and visible rather than an abstract point during expansion process. (Note that
)
Privacy. |
petrochenkov commentedApr 20, 2018
Reminder: Syntactic/hygienic context is formally a "chain of expansions" and informally "the place where something is actually written". For example, in this example
a's context is inside the macromandb's - outside of the macro.With Macro 2.0 hygiene names are resolved in locations where they are "actually written".
For "atomic" tokens like identifiers or punctuation signs the context is unambiguous, but complex entities like expressions or types can be combined from tokens introduced in different contexts, look for example at this code ultimately expanding into
println!("Hello world!")So, what is the "call site" context of the
printlnmacro in this case?Where should we resolve identifiers with call-site hygiene for macros invoked like this?
Contexts of "non-atomic" entities are important for several other reason than determining call-site hygiene, for example in
Struct { field1, field2, ..rest }fieldsfieldNwhereN > 2are checked for privacy in the context of..restfragment, but that fragment may also be a Frankenstein's monster combined from pieces with different contexts.Proposed solution:
For each complex entity figure out and document an atomic entity that is "essential" for that complex entity and that serves as a source of hygienic context for the complex entity.
For example, for binary operator expressions the context may be determined by the context of the operator:
context($a + $b) = context(+), for the "remaining fields" fragment..$restmentioned above the context may be determined by the context of.., etc.I'm... not sure what that essential atomic token would be for macro invocations, probably
!for bang macros and[]for attribute macros.(Note that paired delimiters like
(),[]and{}always have the same context in a pair).