-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
How to determine hygienic context for "non-atomic" code fragments #50122
Comments
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. |
@CAD97 |
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. |
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. |
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 |
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. |
Do not provide suggestions when the spans come from expanded code that doesn't point at user code Hide invalid proc-macro suggestions and track spans coming from proc-macros pointing at attribute. Effectively, unless the proc-macro keeps user spans, suggestions will not be produced for the code they produce. r? `@ghost` Fix rust-lang#107113, fix rust-lang#107976, fix rust-lang#107977, fix rust-lang#108748, fix rust-lang#106720, fix rust-lang#90557. Could potentially address rust-lang#50141, rust-lang#67373, rust-lang#55146, rust-lang#78862, rust-lang#74043, rust-lang#88514, rust-lang#83320, rust-lang#91520, rust-lang#104071. CC rust-lang#50122, rust-lang#76360.
Do not provide suggestions when the spans come from expanded code that doesn't point at user code Hide invalid proc-macro suggestions and track spans coming from proc-macros pointing at attribute. Effectively, unless the proc-macro keeps user spans, suggestions will not be produced for the code they produce. r? ``@ghost`` Fix rust-lang#107113, fix rust-lang#107976, fix rust-lang#107977, fix rust-lang#108748, fix rust-lang#106720, fix rust-lang#90557. Could potentially address rust-lang#50141, rust-lang#67373, rust-lang#55146, rust-lang#78862, rust-lang#74043, rust-lang#88514, rust-lang#83320, rust-lang#91520, rust-lang#104071. CC rust-lang#50122, rust-lang#76360.
Update: the compiler eventually converged on the "span of expression" approach, because it's something natural to implement when you don't know anything about this issue. So I'm going to close this issue in favor of #126763 which is supposed to give spans to "complex" code fragments in a more systematic way. Without "characteristic tokens" contexts for fragments built from tokens with "heterogeneous" spans, coming from unrelated macros, will not be well defined. |
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 macrom
andb
'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
println
macro 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 }
fieldsfieldN
whereN > 2
are checked for privacy in the context of..rest
fragment, 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..$rest
mentioned 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).The text was updated successfully, but these errors were encountered: