Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax-bridge/src/lib.rs')
-rw-r--r--crates/syntax-bridge/src/lib.rs318
1 files changed, 150 insertions, 168 deletions
diff --git a/crates/syntax-bridge/src/lib.rs b/crates/syntax-bridge/src/lib.rs
index 4e525be3fe..0dcf18a4ad 100644
--- a/crates/syntax-bridge/src/lib.rs
+++ b/crates/syntax-bridge/src/lib.rs
@@ -1,10 +1,15 @@
//! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
-use std::{fmt, hash::Hash};
+#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_driver as _;
+
+use std::{collections::VecDeque, fmt, hash::Hash};
use intern::Symbol;
use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Edition, SpanAnchor, SpanData, SpanMap};
+use span::{Edition, Span, SpanAnchor, SpanMap, SyntaxContext};
use stdx::{format_to, never};
use syntax::{
AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement,
@@ -24,21 +29,18 @@ pub use ::parser::TopEntryPoint;
#[cfg(test)]
mod tests;
-pub trait SpanMapper<S> {
- fn span_for(&self, range: TextRange) -> S;
+pub trait SpanMapper {
+ fn span_for(&self, range: TextRange) -> Span;
}
-impl<S> SpanMapper<SpanData<S>> for SpanMap<S>
-where
- SpanData<S>: Copy,
-{
- fn span_for(&self, range: TextRange) -> SpanData<S> {
+impl SpanMapper for SpanMap {
+ fn span_for(&self, range: TextRange) -> Span {
self.span_at(range.start())
}
}
-impl<S: Copy, SM: SpanMapper<S>> SpanMapper<S> for &SM {
- fn span_for(&self, range: TextRange) -> S {
+impl<SM: SpanMapper> SpanMapper for &SM {
+ fn span_for(&self, range: TextRange) -> Span {
SM::span_for(self, range)
}
}
@@ -64,7 +66,7 @@ pub mod dummy_test_span_utils {
pub struct DummyTestSpanMap;
- impl SpanMapper<Span> for DummyTestSpanMap {
+ impl SpanMapper for DummyTestSpanMap {
fn span_for(&self, range: syntax::TextRange) -> Span {
Span {
range,
@@ -92,36 +94,39 @@ pub enum DocCommentDesugarMode {
/// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
/// subtree's spans.
-pub fn syntax_node_to_token_tree<Ctx, SpanMap>(
+pub fn syntax_node_to_token_tree<SpanMap>(
node: &SyntaxNode,
map: SpanMap,
- span: SpanData<Ctx>,
+ span: Span,
mode: DocCommentDesugarMode,
-) -> tt::TopSubtree<SpanData<Ctx>>
+) -> tt::TopSubtree
where
- SpanData<Ctx>: Copy + fmt::Debug,
- SpanMap: SpanMapper<SpanData<Ctx>>,
+ SpanMap: SpanMapper,
{
- let mut c = Converter::new(node, map, Default::default(), Default::default(), span, mode);
+ let mut c =
+ Converter::new(node, map, Default::default(), Default::default(), span, mode, |_, _| {
+ (true, Vec::new())
+ });
convert_tokens(&mut c)
}
/// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
/// subtree's spans. Additionally using the append and remove parameters, the additional tokens can
/// be injected or hidden from the output.
-pub fn syntax_node_to_token_tree_modified<Ctx, SpanMap>(
+pub fn syntax_node_to_token_tree_modified<SpanMap, OnEvent>(
node: &SyntaxNode,
map: SpanMap,
- append: FxHashMap<SyntaxElement, Vec<tt::Leaf<SpanData<Ctx>>>>,
+ append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
remove: FxHashSet<SyntaxElement>,
- call_site: SpanData<Ctx>,
+ call_site: Span,
mode: DocCommentDesugarMode,
-) -> tt::TopSubtree<SpanData<Ctx>>
+ on_enter: OnEvent,
+) -> tt::TopSubtree
where
- SpanMap: SpanMapper<SpanData<Ctx>>,
- SpanData<Ctx>: Copy + fmt::Debug,
+ SpanMap: SpanMapper,
+ OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
{
- let mut c = Converter::new(node, map, append, remove, call_site, mode);
+ let mut c = Converter::new(node, map, append, remove, call_site, mode, on_enter);
convert_tokens(&mut c)
}
@@ -139,19 +144,18 @@ where
/// Converts a [`tt::Subtree`] back to a [`SyntaxNode`].
/// The produced `SpanMap` contains a mapping from the syntax nodes offsets to the subtree's spans.
-pub fn token_tree_to_syntax_node<Ctx>(
- tt: &tt::TopSubtree<SpanData<Ctx>>,
+pub fn token_tree_to_syntax_node(
+ tt: &tt::TopSubtree,
entry_point: parser::TopEntryPoint,
- span_to_edition: &mut dyn FnMut(Ctx) -> Edition,
- top_edition: Edition,
-) -> (Parse<SyntaxNode>, SpanMap<Ctx>)
+ span_to_edition: &mut dyn FnMut(SyntaxContext) -> Edition,
+) -> (Parse<SyntaxNode>, SpanMap)
where
- Ctx: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash,
+ SyntaxContext: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash,
{
let buffer = tt.view().strip_invisible();
let parser_input = to_parser_input(buffer, span_to_edition);
// It matters what edition we parse with even when we escape all identifiers correctly.
- let parser_output = entry_point.parse(&parser_input, top_edition);
+ let parser_output = entry_point.parse(&parser_input);
let mut tree_sink = TtTreeSink::new(buffer.cursor());
for event in parser_output.iter() {
match event {
@@ -171,16 +175,12 @@ where
/// Convert a string to a `TokenTree`. The spans of the subtree will be anchored to the provided
/// anchor with the given context.
-pub fn parse_to_token_tree<Ctx>(
+pub fn parse_to_token_tree(
edition: Edition,
anchor: SpanAnchor,
- ctx: Ctx,
+ ctx: SyntaxContext,
text: &str,
-) -> Option<tt::TopSubtree<SpanData<Ctx>>>
-where
- SpanData<Ctx>: Copy + fmt::Debug,
- Ctx: Copy,
-{
+) -> Option<tt::TopSubtree> {
let lexed = parser::LexedStr::new(edition, text);
if lexed.errors().next().is_some() {
return None;
@@ -191,14 +191,11 @@ where
}
/// Convert a string to a `TokenTree`. The passed span will be used for all spans of the produced subtree.
-pub fn parse_to_token_tree_static_span<S>(
+pub fn parse_to_token_tree_static_span(
edition: Edition,
- span: S,
+ span: Span,
text: &str,
-) -> Option<tt::TopSubtree<S>>
-where
- S: Copy + fmt::Debug,
-{
+) -> Option<tt::TopSubtree> {
let lexed = parser::LexedStr::new(edition, text);
if lexed.errors().next().is_some() {
return None;
@@ -208,10 +205,9 @@ where
Some(convert_tokens(&mut conv))
}
-fn convert_tokens<S, C>(conv: &mut C) -> tt::TopSubtree<S>
+fn convert_tokens<C>(conv: &mut C) -> tt::TopSubtree
where
- C: TokenConverter<S>,
- S: Copy + fmt::Debug,
+ C: TokenConverter,
C::Token: fmt::Debug,
{
let mut builder =
@@ -227,7 +223,7 @@ where
spacing: _,
})) => {
let found_expected_delimiter =
- builder.expected_delimiters().enumerate().find(|(_, delim)| match delim.kind {
+ builder.expected_delimiters().enumerate().find(|(_, delim)| match delim {
tt::DelimiterKind::Parenthesis => char == ')',
tt::DelimiterKind::Brace => char == '}',
tt::DelimiterKind::Bracket => char == ']',
@@ -261,13 +257,11 @@ where
}
kind if kind.is_punct() && kind != UNDERSCORE => {
let found_expected_delimiter =
- builder.expected_delimiters().enumerate().find(|(_, delim)| {
- match delim.kind {
- tt::DelimiterKind::Parenthesis => kind == T![')'],
- tt::DelimiterKind::Brace => kind == T!['}'],
- tt::DelimiterKind::Bracket => kind == T![']'],
- tt::DelimiterKind::Invisible => false,
- }
+ builder.expected_delimiters().enumerate().find(|(_, delim)| match delim {
+ tt::DelimiterKind::Parenthesis => kind == T![')'],
+ tt::DelimiterKind::Brace => kind == T!['}'],
+ tt::DelimiterKind::Bracket => kind == T![']'],
+ tt::DelimiterKind::Invisible => false,
});
// Current token is a closing delimiter that we expect, fix up the closing span
@@ -315,7 +309,7 @@ where
.into()
};
}
- let leaf: tt::Leaf<_> = match kind {
+ let leaf: tt::Leaf = match kind {
k if k.is_any_identifier() => {
let text = token.to_text(conv);
tt::Ident::new(&text, conv.span_for(abs_range)).into()
@@ -423,11 +417,11 @@ pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (Sym
}
}
-fn convert_doc_comment<S: Copy>(
+fn convert_doc_comment(
token: &syntax::SyntaxToken,
- span: S,
+ span: Span,
mode: DocCommentDesugarMode,
- builder: &mut tt::TopSubtreeBuilder<S>,
+ builder: &mut tt::TopSubtreeBuilder,
) {
let Some(comment) = ast::Comment::cast(token.clone()) else { return };
let Some(doc) = comment.kind().doc else { return };
@@ -448,7 +442,7 @@ fn convert_doc_comment<S: Copy>(
text = &text[0..text.len() - 2];
}
let (text, kind) = desugar_doc_comment_text(text, mode);
- let lit = tt::Literal { symbol: text, span, kind, suffix: None };
+ let lit = tt::Literal { text_and_suffix: text, span, kind, suffix_len: 0 };
tt::Leaf::from(lit)
};
@@ -467,92 +461,84 @@ fn convert_doc_comment<S: Copy>(
}
/// A raw token (straight from lexer) converter
-struct RawConverter<'a, Ctx> {
+struct RawConverter<'a> {
lexed: parser::LexedStr<'a>,
pos: usize,
anchor: SpanAnchor,
- ctx: Ctx,
+ ctx: SyntaxContext,
mode: DocCommentDesugarMode,
}
/// A raw token (straight from lexer) converter that gives every token the same span.
-struct StaticRawConverter<'a, S> {
+struct StaticRawConverter<'a> {
lexed: parser::LexedStr<'a>,
pos: usize,
- span: S,
+ span: Span,
mode: DocCommentDesugarMode,
}
-trait SrcToken<Ctx, S> {
+trait SrcToken<Ctx> {
fn kind(&self, ctx: &Ctx) -> SyntaxKind;
fn to_char(&self, ctx: &Ctx) -> Option<char>;
fn to_text(&self, ctx: &Ctx) -> SmolStr;
- fn as_leaf(&self) -> Option<&tt::Leaf<S>> {
+ fn as_leaf(&self) -> Option<&tt::Leaf> {
None
}
}
-trait TokenConverter<S>: Sized {
- type Token: SrcToken<Self, S>;
+trait TokenConverter: Sized {
+ type Token: SrcToken<Self>;
fn convert_doc_comment(
&self,
token: &Self::Token,
- span: S,
- builder: &mut tt::TopSubtreeBuilder<S>,
+ span: Span,
+ builder: &mut tt::TopSubtreeBuilder,
);
fn bump(&mut self) -> Option<(Self::Token, TextRange)>;
fn peek(&self) -> Option<Self::Token>;
- fn span_for(&self, range: TextRange) -> S;
+ fn span_for(&self, range: TextRange) -> Span;
- fn call_site(&self) -> S;
+ fn call_site(&self) -> Span;
}
-impl<S, Ctx> SrcToken<RawConverter<'_, Ctx>, S> for usize {
- fn kind(&self, ctx: &RawConverter<'_, Ctx>) -> SyntaxKind {
+impl SrcToken<RawConverter<'_>> for usize {
+ fn kind(&self, ctx: &RawConverter<'_>) -> SyntaxKind {
ctx.lexed.kind(*self)
}
- fn to_char(&self, ctx: &RawConverter<'_, Ctx>) -> Option<char> {
+ fn to_char(&self, ctx: &RawConverter<'_>) -> Option<char> {
ctx.lexed.text(*self).chars().next()
}
- fn to_text(&self, ctx: &RawConverter<'_, Ctx>) -> SmolStr {
+ fn to_text(&self, ctx: &RawConverter<'_>) -> SmolStr {
ctx.lexed.text(*self).into()
}
}
-impl<S: Copy> SrcToken<StaticRawConverter<'_, S>, S> for usize {
- fn kind(&self, ctx: &StaticRawConverter<'_, S>) -> SyntaxKind {
+impl SrcToken<StaticRawConverter<'_>> for usize {
+ fn kind(&self, ctx: &StaticRawConverter<'_>) -> SyntaxKind {
ctx.lexed.kind(*self)
}
- fn to_char(&self, ctx: &StaticRawConverter<'_, S>) -> Option<char> {
+ fn to_char(&self, ctx: &StaticRawConverter<'_>) -> Option<char> {
ctx.lexed.text(*self).chars().next()
}
- fn to_text(&self, ctx: &StaticRawConverter<'_, S>) -> SmolStr {
+ fn to_text(&self, ctx: &StaticRawConverter<'_>) -> SmolStr {
ctx.lexed.text(*self).into()
}
}
-impl<Ctx: Copy> TokenConverter<SpanData<Ctx>> for RawConverter<'_, Ctx>
-where
- SpanData<Ctx>: Copy,
-{
+impl TokenConverter for RawConverter<'_> {
type Token = usize;
- fn convert_doc_comment(
- &self,
- &token: &usize,
- span: SpanData<Ctx>,
- builder: &mut tt::TopSubtreeBuilder<SpanData<Ctx>>,
- ) {
+ fn convert_doc_comment(&self, &token: &usize, span: Span, builder: &mut tt::TopSubtreeBuilder) {
let text = self.lexed.text(token);
convert_doc_comment(&doc_comment(text), span, self.mode, builder);
}
@@ -576,22 +562,19 @@ where
Some(self.pos)
}
- fn span_for(&self, range: TextRange) -> SpanData<Ctx> {
- SpanData { range, anchor: self.anchor, ctx: self.ctx }
+ fn span_for(&self, range: TextRange) -> Span {
+ Span { range, anchor: self.anchor, ctx: self.ctx }
}
- fn call_site(&self) -> SpanData<Ctx> {
- SpanData { range: TextRange::empty(0.into()), anchor: self.anchor, ctx: self.ctx }
+ fn call_site(&self) -> Span {
+ Span { range: TextRange::empty(0.into()), anchor: self.anchor, ctx: self.ctx }
}
}
-impl<S> TokenConverter<S> for StaticRawConverter<'_, S>
-where
- S: Copy,
-{
+impl TokenConverter for StaticRawConverter<'_> {
type Token = usize;
- fn convert_doc_comment(&self, &token: &usize, span: S, builder: &mut tt::TopSubtreeBuilder<S>) {
+ fn convert_doc_comment(&self, &token: &usize, span: Span, builder: &mut tt::TopSubtreeBuilder) {
let text = self.lexed.text(token);
convert_doc_comment(&doc_comment(text), span, self.mode, builder);
}
@@ -615,39 +598,44 @@ where
Some(self.pos)
}
- fn span_for(&self, _: TextRange) -> S {
+ fn span_for(&self, _: TextRange) -> Span {
self.span
}
- fn call_site(&self) -> S {
+ fn call_site(&self) -> Span {
self.span
}
}
-struct Converter<SpanMap, S> {
+struct Converter<SpanMap, OnEvent> {
current: Option<SyntaxToken>,
- current_leaves: Vec<tt::Leaf<S>>,
+ current_leaves: VecDeque<tt::Leaf>,
preorder: PreorderWithTokens,
range: TextRange,
punct_offset: Option<(SyntaxToken, TextSize)>,
/// Used to make the emitted text ranges in the spans relative to the span anchor.
map: SpanMap,
- append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
+ append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
remove: FxHashSet<SyntaxElement>,
- call_site: S,
+ call_site: Span,
mode: DocCommentDesugarMode,
+ on_event: OnEvent,
}
-impl<SpanMap, S> Converter<SpanMap, S> {
+impl<SpanMap, OnEvent> Converter<SpanMap, OnEvent>
+where
+ OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
+{
fn new(
node: &SyntaxNode,
map: SpanMap,
- append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
+ append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
remove: FxHashSet<SyntaxElement>,
- call_site: S,
+ call_site: Span,
mode: DocCommentDesugarMode,
+ on_enter: OnEvent,
) -> Self {
- let mut this = Converter {
+ let mut converter = Converter {
current: None,
preorder: node.preorder_with_tokens(),
range: node.text_range(),
@@ -656,16 +644,21 @@ impl<SpanMap, S> Converter<SpanMap, S> {
append,
remove,
call_site,
- current_leaves: vec![],
+ current_leaves: VecDeque::new(),
mode,
+ on_event: on_enter,
};
- let first = this.next_token();
- this.current = first;
- this
+ converter.current = converter.next_token();
+ converter
}
fn next_token(&mut self) -> Option<SyntaxToken> {
while let Some(ev) = self.preorder.next() {
+ let (keep_event, insert_leaves) = (self.on_event)(&mut self.preorder, &ev);
+ self.current_leaves.extend(insert_leaves);
+ if !keep_event {
+ continue;
+ }
match ev {
WalkEvent::Enter(token) => {
if self.remove.contains(&token) {
@@ -675,10 +668,9 @@ impl<SpanMap, S> Converter<SpanMap, S> {
}
node => {
self.preorder.skip_subtree();
- if let Some(mut v) = self.append.remove(&node) {
- v.reverse();
+ if let Some(v) = self.append.remove(&node) {
self.current_leaves.extend(v);
- return None;
+ continue;
}
}
}
@@ -687,10 +679,9 @@ impl<SpanMap, S> Converter<SpanMap, S> {
}
}
WalkEvent::Leave(ele) => {
- if let Some(mut v) = self.append.remove(&ele) {
- v.reverse();
+ if let Some(v) = self.append.remove(&ele) {
self.current_leaves.extend(v);
- return None;
+ continue;
}
}
}
@@ -700,13 +691,13 @@ impl<SpanMap, S> Converter<SpanMap, S> {
}
#[derive(Debug)]
-enum SynToken<S> {
+enum SynToken {
Ordinary(SyntaxToken),
Punct { token: SyntaxToken, offset: usize },
- Leaf(tt::Leaf<S>),
+ Leaf(tt::Leaf),
}
-impl<S> SynToken<S> {
+impl SynToken {
fn token(&self) -> &SyntaxToken {
match self {
SynToken::Ordinary(it) | SynToken::Punct { token: it, offset: _ } => it,
@@ -715,8 +706,8 @@ impl<S> SynToken<S> {
}
}
-impl<SpanMap, S> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
- fn kind(&self, _ctx: &Converter<SpanMap, S>) -> SyntaxKind {
+impl<SpanMap, OnEvent> SrcToken<Converter<SpanMap, OnEvent>> for SynToken {
+ fn kind(&self, _ctx: &Converter<SpanMap, OnEvent>) -> SyntaxKind {
match self {
SynToken::Ordinary(token) => token.kind(),
SynToken::Punct { token, offset: i } => {
@@ -728,14 +719,14 @@ impl<SpanMap, S> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
}
}
}
- fn to_char(&self, _ctx: &Converter<SpanMap, S>) -> Option<char> {
+ fn to_char(&self, _ctx: &Converter<SpanMap, OnEvent>) -> Option<char> {
match self {
SynToken::Ordinary(_) => None,
SynToken::Punct { token: it, offset: i } => it.text().chars().nth(*i),
SynToken::Leaf(_) => None,
}
}
- fn to_text(&self, _ctx: &Converter<SpanMap, S>) -> SmolStr {
+ fn to_text(&self, _ctx: &Converter<SpanMap, OnEvent>) -> SmolStr {
match self {
SynToken::Ordinary(token) | SynToken::Punct { token, offset: _ } => token.text().into(),
SynToken::Leaf(_) => {
@@ -744,7 +735,7 @@ impl<SpanMap, S> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
}
}
}
- fn as_leaf(&self) -> Option<&tt::Leaf<S>> {
+ fn as_leaf(&self) -> Option<&tt::Leaf> {
match self {
SynToken::Ordinary(_) | SynToken::Punct { .. } => None,
SynToken::Leaf(it) => Some(it),
@@ -752,17 +743,17 @@ impl<SpanMap, S> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
}
}
-impl<S, SpanMap> TokenConverter<S> for Converter<SpanMap, S>
+impl<SpanMap, OnEvent> TokenConverter for Converter<SpanMap, OnEvent>
where
- S: Copy,
- SpanMap: SpanMapper<S>,
+ SpanMap: SpanMapper,
+ OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
{
- type Token = SynToken<S>;
+ type Token = SynToken;
fn convert_doc_comment(
&self,
token: &Self::Token,
- span: S,
- builder: &mut tt::TopSubtreeBuilder<S>,
+ span: Span,
+ builder: &mut tt::TopSubtreeBuilder,
) {
convert_doc_comment(token.token(), span, self.mode, builder);
}
@@ -781,10 +772,7 @@ where
));
}
- if let Some(leaf) = self.current_leaves.pop() {
- if self.current_leaves.is_empty() {
- self.current = self.next_token();
- }
+ if let Some(leaf) = self.current_leaves.pop_front() {
return Some((SynToken::Leaf(leaf), TextRange::empty(TextSize::new(0))));
}
@@ -829,30 +817,24 @@ where
Some(token)
}
- fn span_for(&self, range: TextRange) -> S {
+ fn span_for(&self, range: TextRange) -> Span {
self.map.span_for(range)
}
- fn call_site(&self) -> S {
+ fn call_site(&self) -> Span {
self.call_site
}
}
-struct TtTreeSink<'a, Ctx>
-where
- SpanData<Ctx>: Copy,
-{
+struct TtTreeSink<'a> {
buf: String,
- cursor: Cursor<'a, SpanData<Ctx>>,
+ cursor: Cursor<'a>,
text_pos: TextSize,
inner: SyntaxTreeBuilder,
- token_map: SpanMap<Ctx>,
+ token_map: SpanMap,
}
-impl<'a, Ctx> TtTreeSink<'a, Ctx>
-where
- SpanData<Ctx>: Copy,
-{
- fn new(cursor: Cursor<'a, SpanData<Ctx>>) -> Self {
+impl<'a> TtTreeSink<'a> {
+ fn new(cursor: Cursor<'a>) -> Self {
TtTreeSink {
buf: String::new(),
cursor,
@@ -862,7 +844,7 @@ where
}
}
- fn finish(mut self) -> (Parse<SyntaxNode>, SpanMap<Ctx>) {
+ fn finish(mut self) -> (Parse<SyntaxNode>, SpanMap) {
self.token_map.finish();
(self.inner.finish(), self.token_map)
}
@@ -880,21 +862,15 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> {
Some(&texts[idx..texts.len() - (1 - idx)])
}
-impl<Ctx> TtTreeSink<'_, Ctx>
-where
- SpanData<Ctx>: Copy + fmt::Debug,
- Ctx: PartialEq,
-{
+impl TtTreeSink<'_> {
/// Parses a float literal as if it was a one to two name ref nodes with a dot inbetween.
/// This occurs when a float literal is used as a field access.
fn float_split(&mut self, has_pseudo_dot: bool) {
- let (text, span) = match self.cursor.token_tree() {
- Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
- symbol: text,
- span,
- kind: tt::LitKind::Float,
- suffix: _,
- }))) => (text.as_str(), *span),
+ let token_tree = self.cursor.token_tree();
+ let (text, span) = match &token_tree {
+ Some(tt::TokenTree::Leaf(tt::Leaf::Literal(
+ lit @ tt::Literal { span, kind: tt::LitKind::Float, .. },
+ ))) => (lit.text(), *span),
tt => unreachable!("{tt:?}"),
};
// FIXME: Span splitting
@@ -953,9 +929,15 @@ where
self.buf.push_str("r#");
self.text_pos += TextSize::of("r#");
}
- let r = (ident.sym.as_str(), ident.span);
+ let text = ident.sym.as_str();
+ self.buf += text;
+ self.text_pos += TextSize::of(text);
+ combined_span = match combined_span {
+ None => Some(ident.span),
+ Some(prev_span) => Some(Self::merge_spans(prev_span, ident.span)),
+ };
self.cursor.bump();
- r
+ continue 'tokens;
}
tt::Leaf::Punct(punct) => {
assert!(punct.char.is_ascii());
@@ -1035,10 +1017,10 @@ where
self.inner.error(error, self.text_pos)
}
- fn merge_spans(a: SpanData<Ctx>, b: SpanData<Ctx>) -> SpanData<Ctx> {
+ fn merge_spans(a: Span, b: Span) -> Span {
// We don't do what rustc does exactly, rustc does something clever when the spans have different syntax contexts
// but this runs afoul of our separation between `span` and `hir-expand`.
- SpanData {
+ Span {
range: if a.ctx == b.ctx && a.anchor == b.anchor {
TextRange::new(
std::cmp::min(a.range.start(), b.range.start()),