Skip to content

Commit e320004

Browse files
committed
Remove tt -> ast -> tt round trips in attrs lowering
1 parent f090205 commit e320004

File tree

7 files changed

+95
-73
lines changed

7 files changed

+95
-73
lines changed

crates/cfg/src/cfg_expr.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,6 @@ pub enum CfgAtom {
1818
KeyValue { key: SmolStr, value: SmolStr },
1919
}
2020

21-
impl CfgAtom {
22-
/// Returns `true` when the atom comes from the target specification.
23-
///
24-
/// If this returns `true`, then changing this atom requires changing the compilation target. If
25-
/// it returns `false`, the atom might come from a build script or the build system.
26-
pub fn is_target_defined(&self) -> bool {
27-
match self {
28-
CfgAtom::Flag(flag) => matches!(&**flag, "unix" | "windows"),
29-
CfgAtom::KeyValue { key, value: _ } => matches!(
30-
&**key,
31-
"target_arch"
32-
| "target_os"
33-
| "target_env"
34-
| "target_family"
35-
| "target_endian"
36-
| "target_pointer_width"
37-
| "target_vendor" // NOTE: `target_feature` is left out since it can be configured via `-Ctarget-feature`
38-
),
39-
}
40-
}
41-
}
42-
4321
impl fmt::Display for CfgAtom {
4422
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4523
match self {

crates/cfg/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,9 @@ impl CfgDiff {
131131
/// of both.
132132
pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> {
133133
let mut occupied = FxHashSet::default();
134-
for item in enable.iter().chain(disable.iter()) {
135-
if !occupied.insert(item) {
136-
// was present
137-
return None;
138-
}
134+
if enable.iter().chain(disable.iter()).any(|item| occupied.insert(item)) {
135+
// was present
136+
return None;
139137
}
140138

141139
Some(CfgDiff { enable, disable })

crates/hir-def/src/attr.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::{
3232
VariantId,
3333
};
3434

35+
/// Desugared attributes of an item post `cfg_attr` expansion.
3536
#[derive(Default, Debug, Clone, PartialEq, Eq)]
3637
pub struct Attrs(RawAttrs);
3738

@@ -228,7 +229,6 @@ pub enum DocAtom {
228229
KeyValue { key: SmolStr, value: SmolStr },
229230
}
230231

231-
// Adapted from `CfgExpr` parsing code
232232
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
233233
pub enum DocExpr {
234234
Invalid,
@@ -448,10 +448,7 @@ impl AttrsWithOwner {
448448
let map = db.fields_attrs_source_map(id.parent);
449449
let file_id = id.parent.file_id(db);
450450
let root = db.parse_or_expand(file_id);
451-
let owner = match &map[id.local_id] {
452-
Either::Left(it) => ast::AnyHasAttrs::new(it.to_node(&root)),
453-
Either::Right(it) => ast::AnyHasAttrs::new(it.to_node(&root)),
454-
};
451+
let owner = ast::AnyHasAttrs::new(map[id.local_id].to_node(&root));
455452
InFile::new(file_id, owner)
456453
}
457454
AttrDefId::AdtId(adt) => match adt {
@@ -634,7 +631,7 @@ fn attrs_from_item_tree_assoc<'db, N: ItemTreeModItemNode>(
634631
pub(crate) fn fields_attrs_source_map(
635632
db: &dyn DefDatabase,
636633
def: VariantId,
637-
) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> {
634+
) -> Arc<ArenaMap<LocalFieldId, AstPtr<Either<ast::TupleField, ast::RecordField>>>> {
638635
let mut res = ArenaMap::default();
639636
let child_source = def.child_source(db);
640637

@@ -643,7 +640,7 @@ pub(crate) fn fields_attrs_source_map(
643640
idx,
644641
variant
645642
.as_ref()
646-
.either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))),
643+
.either(|l| AstPtr::new(l).wrap_left(), |r| AstPtr::new(r).wrap_right()),
647644
);
648645
}
649646

crates/hir-def/src/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
194194
fn fields_attrs_source_map(
195195
&self,
196196
def: VariantId,
197-
) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>>;
197+
) -> Arc<ArenaMap<LocalFieldId, AstPtr<Either<ast::TupleField, ast::RecordField>>>>;
198198

199199
#[salsa::invoke(AttrsWithOwner::attrs_query)]
200200
fn attrs(&self, def: AttrDefId) -> Attrs;

crates/hir-expand/src/attrs.rs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,10 @@ impl RawAttrs {
117117
None => return smallvec![attr.clone()],
118118
};
119119
let index = attr.id;
120-
let attrs =
121-
parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| {
122-
let tree = Subtree {
123-
delimiter: tt::Delimiter::invisible_spanned(attr.first()?.first_span()),
124-
token_trees: attr.to_vec(),
125-
};
126-
Attr::from_tt(db, &tree, index.with_cfg_attr(idx))
127-
});
120+
let attrs = parts
121+
.enumerate()
122+
.take(1 << AttrId::CFG_ATTR_BITS)
123+
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
128124

129125
let cfg_options = &crate_graph[krate].cfg_options;
130126
let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
@@ -222,12 +218,41 @@ impl Attr {
222218
Some(Attr { id, path, input, span })
223219
}
224220

225-
fn from_tt(db: &dyn ExpandDatabase, tt: &tt::Subtree, id: AttrId) -> Option<Attr> {
226-
// FIXME: Unecessary roundtrip tt -> ast -> tt
227-
let (parse, map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem);
228-
let ast = ast::Meta::cast(parse.syntax_node())?;
229-
230-
Self::from_src(db, ast, SpanMapRef::ExpansionSpanMap(&map), id)
221+
fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
222+
dbg!(tt);
223+
let span = tt.first()?.first_span();
224+
let path_end = tt
225+
.iter()
226+
.position(|tt| {
227+
!matches!(
228+
tt,
229+
tt::TokenTree::Leaf(
230+
tt::Leaf::Punct(tt::Punct { char: ':' | '$', .. }) | tt::Leaf::Ident(_),
231+
)
232+
)
233+
})
234+
.unwrap_or_else(|| tt.len());
235+
236+
let (path, input) = tt.split_at(path_end);
237+
let path = Interned::new(ModPath::from_tt(db, path)?);
238+
239+
let input = match input.get(0) {
240+
Some(tt::TokenTree::Subtree(tree)) => {
241+
Some(Interned::new(AttrInput::TokenTree(Box::new(tree.clone()))))
242+
}
243+
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => {
244+
let input = match input.get(1) {
245+
Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text, .. }))) => {
246+
//FIXME the trimming here isn't quite right, raw strings are not handled
247+
Some(Interned::new(AttrInput::Literal(text.trim_matches('"').into())))
248+
}
249+
_ => None,
250+
};
251+
input
252+
}
253+
_ => None,
254+
};
255+
Some(Attr { id, path, input, span })
231256
}
232257

233258
pub fn path(&self) -> &ModPath {
@@ -277,29 +302,8 @@ impl Attr {
277302
.token_trees
278303
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
279304
.filter_map(move |tts| {
280-
if tts.is_empty() {
281-
return None;
282-
}
283-
// FIXME: This is necessarily a hack. It'd be nice if we could avoid allocation
284-
// here or maybe just parse a mod path from a token tree directly
285-
let subtree = tt::Subtree {
286-
delimiter: tt::Delimiter::invisible_spanned(tts.first()?.first_span()),
287-
token_trees: tts.to_vec(),
288-
};
289-
let (parse, span_map) =
290-
mbe::token_tree_to_syntax_node(&subtree, mbe::TopEntryPoint::MetaItem);
291-
let meta = ast::Meta::cast(parse.syntax_node())?;
292-
// Only simple paths are allowed.
293-
if meta.eq_token().is_some() || meta.expr().is_some() || meta.token_tree().is_some()
294-
{
295-
return None;
296-
}
297-
let path = meta.path()?;
298-
let call_site = span_map.span_at(path.syntax().text_range().start());
299-
Some((
300-
ModPath::from_src(db, path, SpanMapRef::ExpansionSpanMap(&span_map))?,
301-
call_site,
302-
))
305+
let span = tts.first()?.first_span();
306+
Some((ModPath::from_tt(db, tts)?, span))
303307
});
304308

305309
Some(paths)

crates/hir-expand/src/mod_path.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
hygiene::{marks_rev, SyntaxContextExt, Transparency},
1111
name::{known, AsName, Name},
1212
span_map::SpanMapRef,
13+
tt,
1314
};
1415
use base_db::CrateId;
1516
use smallvec::SmallVec;
@@ -53,6 +54,10 @@ impl ModPath {
5354
convert_path(db, None, path, span_map)
5455
}
5556

57+
pub fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModPath> {
58+
convert_path_tt(db, tt)
59+
}
60+
5661
pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
5762
let segments = segments.into_iter().collect();
5863
ModPath { kind, segments }
@@ -281,6 +286,46 @@ fn convert_path(
281286
Some(mod_path)
282287
}
283288

289+
fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option<ModPath> {
290+
let mut leafs = tt.iter().filter_map(|tt| match tt {
291+
tt::TokenTree::Leaf(leaf) => Some(leaf),
292+
tt::TokenTree::Subtree(_) => None,
293+
});
294+
let mut segments = smallvec::smallvec![];
295+
let kind = match leafs.next()? {
296+
tt::Leaf::Punct(tt::Punct { char: ':', .. }) => match leafs.next()? {
297+
tt::Leaf::Punct(tt::Punct { char: ':', .. }) => PathKind::Abs,
298+
_ => return None,
299+
},
300+
tt::Leaf::Ident(tt::Ident { text, span }) if text == "$crate" => {
301+
resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate)
302+
}
303+
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::Super(0),
304+
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => {
305+
let mut deg = 1;
306+
while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leafs.next() {
307+
if text != "super" {
308+
segments.push(Name::new_text_dont_use(text.clone()));
309+
break;
310+
}
311+
deg += 1;
312+
}
313+
PathKind::Super(deg)
314+
}
315+
tt::Leaf::Ident(tt::Ident { text, .. }) if text == "crate" => PathKind::Crate,
316+
tt::Leaf::Ident(ident) => {
317+
segments.push(Name::new_text_dont_use(ident.text.clone()));
318+
PathKind::Plain
319+
}
320+
_ => return None,
321+
};
322+
segments.extend(leafs.filter_map(|leaf| match leaf {
323+
::tt::Leaf::Ident(ident) => Some(Name::new_text_dont_use(ident.text.clone())),
324+
_ => None,
325+
}));
326+
Some(ModPath { kind, segments })
327+
}
328+
284329
pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) -> Option<CrateId> {
285330
// When resolving `$crate` from a `macro_rules!` invoked in a `macro`,
286331
// we don't want to pretend that the `macro_rules!` definition is in the `macro`

crates/proc-macro-srv/src/server/token_id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl server::TokenStream for TokenIdServer {
206206
stream: if subtree.token_trees.is_empty() {
207207
None
208208
} else {
209-
Some(subtree.token_trees.into_iter().collect())
209+
Some(subtree.token_trees)
210210
},
211211
span: bridge::DelimSpan::from_single(subtree.delimiter.open),
212212
}),

0 commit comments

Comments
 (0)