Open
Description
My hunch is that most of the edition-dependent features don't have a documented bit of text that we use to figure out what edition they are-- and that we don't have tests for that logic. We should clarify this and document the "edition span" in the Edition Migration Guide, and then make tests that check that it works correctly.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
m-ou-se commentedon Jun 22, 2021
I did some digging through the implementations. These are the spans used by each of the edition-dependent behaviours:
std::panic!(..)
span.dyn
. E.g.T
in&T
....
token.|a, b| a + b
span.into_iter
token.$x:pat
including the$
and:pat
.SyntaxContext::root
andExpnId::root
#85708)TokenStream::from_str
in a proc macro: The edition of the proc macro crate, the macro definition site.I have no clue what happens if we somehow manage to make a
std::panic!(..)
or$x:pat
or|| a
expression where the first and last tokens have different editions. (Would be very weird, but it's possible with a proc macro.) I think many diagnostics would break very badly if they point into different crates. But the metadata like the edition is probably taken from exactly one of these tokens. I'll investigate.m-ou-se commentedon Jun 22, 2021
I made a proc macro that allows changing the edition of a single token and did some experiments:
The span of
std::panic!(..)
carries the edition of juststd
, not of the other parts. The span ofpanic!(..)
carries the edition ofpanic
. It always seems to be the first token of the path. Same for::
in::std::panic!(..)
. (I think it rarely matters, but we could modify this to look at the last part, so thepanic
token. (Or whatever name you imported it as withuse std::panic as something;
) Or the!
token maybe.)The span of
$x:pat
carries the edition of justpat
. Seems good, but it doesn't really work when the macro comes from another crate, due to how the workaround in Use correct edition when parsing:pat
matchers #85709 works. However, I cannot reproduce this problem. Even across crates it seems to follow exactly the edition of thepat
span. This is great, but I'm not sure why or how this works. (:m-ou-se commentedon Jun 22, 2021
For closures:
The span of
|..| body
is made withlo.to(body.span)
, wherelo
is the span of the first token (move
orasync
orstatic
or||
or|
). TheSpan::to
code has multiple FIXMEs and the behaviour when macros and multiple contexts are involved is not very obvious at all:rust/compiler/rustc_span/src/lib.rs
Lines 657 to 671 in 75ed342
The logic of
Span::to
is to avoid confusing diagnostics. But its behaviour isn't really great for edition tracking.m-ou-se commentedon Jun 22, 2021
The same
first_token.span.to(last_token.span)
logic is used for paths like::std::panic
or&path::to::Trait
for the panic and dyn edition behaviours.danielhenrymantilla commentedon Jun 22, 2021
Impressive investigation! Note that mixing spans can also be done by
macro_rules!
macros, although it would be more convoluted:petrochenkov commentedon Jun 22, 2021
Similar existing issue - #50122.
m-ou-se commentedon Jun 22, 2021
This is an example I just posted on Zulip:
An
std::panic
path with either thestd
orpanic
token from a 2021 macro resolves to the 2021 panic, becauseSpan::to
prefers macros. But when both come from a macro, it just picks the first token instead.HashMap<Pulse, u64>
cannot be built from #135669