summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/adt.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs360
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs148
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/intern.rs227
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/keys.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs298
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/layout.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs52
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs87
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs10
38 files changed, 738 insertions, 837 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 698be7665..31d4018d2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -2,9 +2,11 @@
name = "hir-def"
version = "0.0.0"
description = "TBD"
-license = "MIT OR Apache-2.0"
-edition = "2021"
-rust-version = "1.65"
+
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+rust-version.workspace = true
[lib]
doctest = false
@@ -23,23 +25,28 @@ hashbrown = { version = "0.12.1", default-features = false }
indexmap = "1.9.1"
itertools = "0.10.5"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.15.0"
+once_cell = "1.17.0"
rustc-hash = "1.1.0"
-smallvec = "1.10.0"
+smallvec.workspace = true
tracing = "0.1.35"
-stdx = { path = "../stdx", version = "0.0.0" }
-base-db = { path = "../base-db", version = "0.0.0" }
-syntax = { path = "../syntax", version = "0.0.0" }
-profile = { path = "../profile", version = "0.0.0" }
-hir-expand = { path = "../hir-expand", version = "0.0.0" }
rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
-mbe = { path = "../mbe", version = "0.0.0" }
-cfg = { path = "../cfg", version = "0.0.0" }
-tt = { path = "../tt", version = "0.0.0" }
-limit = { path = "../limit", version = "0.0.0" }
+
+# local deps
+stdx.workspace = true
+intern.workspace = true
+base-db.workspace = true
+syntax.workspace = true
+profile.workspace = true
+hir-expand.workspace = true
+mbe.workspace = true
+cfg.workspace = true
+tt.workspace = true
+limit.workspace = true
[dev-dependencies]
-test-utils = { path = "../test-utils" }
expect-test = "1.4.0"
+
+# local deps
+test-utils.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
index db3b41948..9bc1c54a3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
@@ -3,33 +3,34 @@
use std::sync::Arc;
use base_db::CrateId;
+use cfg::CfgOptions;
use either::Either;
+
use hir_expand::{
name::{AsName, Name},
HirFileId, InFile,
};
+use intern::Interned;
use la_arena::{Arena, ArenaMap};
use rustc_abi::{Integer, IntegerType};
use syntax::ast::{self, HasName, HasVisibility};
-use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
use crate::{
body::{CfgExpander, LowerCtx},
builtin_type::{BuiltinInt, BuiltinUint},
db::DefDatabase,
- intern::Interned,
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
layout::{Align, ReprFlags, ReprOptions},
nameres::diagnostics::DefDiagnostic,
src::HasChildSource,
src::HasSource,
trace::Trace,
+ tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
type_ref::TypeRef,
visibility::RawVisibility,
EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
VariantId,
};
-use cfg::CfgOptions;
/// Note that we use `StructData` for unions as well!
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -82,7 +83,7 @@ fn repr_from_value(
fn parse_repr_tt(tt: &Subtree) -> Option<ReprOptions> {
match tt.delimiter {
- Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
+ Delimiter { kind: DelimiterKind::Parenthesis, .. } => {}
_ => return None,
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index ab5d180e1..fcd92ad33 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -1,27 +1,26 @@
//! A higher level attributes based on TokenTree, with also some shortcuts.
-use std::{fmt, hash::Hash, ops, sync::Arc};
+use std::{hash::Hash, ops, sync::Arc};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
-use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
+use hir_expand::{
+ attrs::{collect_attrs, Attr, AttrId, RawAttrs},
+ HirFileId, InFile,
+};
use itertools::Itertools;
use la_arena::{ArenaMap, Idx, RawIdx};
-use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
-use smallvec::{smallvec, SmallVec};
+use mbe::DelimiterKind;
use syntax::{
- ast::{self, AstNode, HasAttrs, IsString},
- match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
+ ast::{self, HasAttrs, IsString},
+ AstPtr, AstToken, SmolStr, TextRange, TextSize,
};
-use tt::Subtree;
use crate::{
db::DefDatabase,
- intern::Interned,
item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode},
nameres::{ModuleOrigin, ModuleSource},
- path::{ModPath, PathKind},
src::{HasChildSource, HasSource},
AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId,
VariantId,
@@ -47,12 +46,6 @@ impl From<Documentation> for String {
}
}
-/// Syntactical attributes, without filtering of `cfg_attr`s.
-#[derive(Default, Debug, Clone, PartialEq, Eq)]
-pub(crate) struct RawAttrs {
- entries: Option<Arc<[Attr]>>,
-}
-
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs(RawAttrs);
@@ -62,30 +55,21 @@ pub struct AttrsWithOwner {
owner: AttrDefId,
}
-impl ops::Deref for RawAttrs {
- type Target = [Attr];
-
- fn deref(&self) -> &[Attr] {
- match &self.entries {
- Some(it) => &*it,
- None => &[],
- }
- }
-}
impl Attrs {
pub fn get(&self, id: AttrId) -> Option<&Attr> {
(**self).iter().find(|attr| attr.id == id)
}
+
+ pub(crate) fn filter(db: &dyn DefDatabase, krate: CrateId, raw_attrs: RawAttrs) -> Attrs {
+ Attrs(raw_attrs.filter(db.upcast(), krate))
+ }
}
impl ops::Deref for Attrs {
type Target = [Attr];
fn deref(&self) -> &[Attr] {
- match &self.0.entries {
- Some(it) => &*it,
- None => &[],
- }
+ &self.0
}
}
@@ -97,114 +81,6 @@ impl ops::Deref for AttrsWithOwner {
}
}
-impl RawAttrs {
- pub(crate) const EMPTY: Self = Self { entries: None };
-
- pub(crate) fn new(db: &dyn DefDatabase, owner: &dyn ast::HasAttrs, hygiene: &Hygiene) -> Self {
- let entries = collect_attrs(owner)
- .filter_map(|(id, attr)| match attr {
- Either::Left(attr) => {
- attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id))
- }
- Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
- id,
- input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
- path: Interned::new(ModPath::from(hir_expand::name!(doc))),
- }),
- })
- .collect::<Arc<_>>();
-
- Self { entries: if entries.is_empty() { None } else { Some(entries) } }
- }
-
- fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::HasAttrs>) -> Self {
- let hygiene = Hygiene::new(db.upcast(), owner.file_id);
- Self::new(db, owner.value, &hygiene)
- }
-
- pub(crate) fn merge(&self, other: Self) -> Self {
- // FIXME: This needs to fixup `AttrId`s
- match (&self.entries, other.entries) {
- (None, None) => Self::EMPTY,
- (None, entries @ Some(_)) => Self { entries },
- (Some(entries), None) => Self { entries: Some(entries.clone()) },
- (Some(a), Some(b)) => {
- let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
- Self {
- entries: Some(
- a.iter()
- .cloned()
- .chain(b.iter().map(|it| {
- let mut it = it.clone();
- it.id.ast_index += last_ast_index;
- it
- }))
- .collect(),
- ),
- }
- }
- }
- }
-
- /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
- pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
- let has_cfg_attrs = self.iter().any(|attr| {
- attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr])
- });
- if !has_cfg_attrs {
- return Attrs(self);
- }
-
- let crate_graph = db.crate_graph();
- let new_attrs = self
- .iter()
- .flat_map(|attr| -> SmallVec<[_; 1]> {
- let is_cfg_attr =
- attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]);
- if !is_cfg_attr {
- return smallvec![attr.clone()];
- }
-
- let subtree = match attr.token_tree_value() {
- Some(it) => it,
- _ => return smallvec![attr.clone()],
- };
-
- // Input subtree is: `(cfg, $(attr),+)`
- // Split it up into a `cfg` subtree and the `attr` subtrees.
- // FIXME: There should be a common API for this.
- let mut parts = subtree.token_trees.split(|tt| {
- matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))
- });
- let cfg = match parts.next() {
- Some(it) => it,
- None => return smallvec![],
- };
- let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
- let cfg = CfgExpr::parse(&cfg);
- let index = attr.id;
- let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
- let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
- // FIXME hygiene
- let hygiene = Hygiene::new_unhygienic();
- Attr::from_tt(db, &tree, &hygiene, index)
- });
-
- let cfg_options = &crate_graph[krate].cfg_options;
- if cfg_options.check(&cfg) == Some(false) {
- smallvec![]
- } else {
- cov_mark::hit!(cfg_attr_active);
-
- attrs.collect()
- }
- })
- .collect();
-
- Attrs(RawAttrs { entries: Some(new_attrs) })
- }
-}
-
impl Attrs {
pub const EMPTY: Self = Self(RawAttrs::EMPTY);
@@ -251,19 +127,18 @@ impl Attrs {
let enum_ = &item_tree[loc.id.value];
let cfg_options = &crate_graph[krate].cfg_options;
- let variant = 'tri: loop {
- let mut idx = 0;
- for variant in enum_.variants.clone() {
- let attrs = item_tree.attrs(db, krate, variant.into());
- if attrs.is_cfg_enabled(cfg_options) {
- if it.local_id == Idx::from_raw(RawIdx::from(idx)) {
- break 'tri variant;
- }
- idx += 1;
- }
- }
+
+ let Some(variant) = enum_.variants.clone().filter(|variant| {
+ let attrs = item_tree.attrs(db, krate, (*variant).into());
+ attrs.is_cfg_enabled(cfg_options)
+ })
+ .zip(0u32..)
+ .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx)))
+ .map(|(variant, _idx)| variant)
+ else {
return Arc::new(res);
};
+
(item_tree[variant].fields.clone(), item_tree, krate)
}
VariantId::StructId(it) => {
@@ -358,7 +233,7 @@ impl Attrs {
pub fn has_doc_hidden(&self) -> bool {
self.by_key("doc").tt_values().any(|tt| {
- tt.delimiter_kind() == Some(DelimiterKind::Parenthesis) &&
+ tt.delimiter.kind == DelimiterKind::Parenthesis &&
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden")
})
}
@@ -403,7 +278,7 @@ impl AttrsWithOwner {
.raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
.clone(),
ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner(
- db,
+ db.upcast(),
InFile::new(block.file_id, block.to_node(db.upcast()))
.as_ref()
.map(|it| it as &dyn ast::HasAttrs),
@@ -439,7 +314,7 @@ impl AttrsWithOwner {
GenericParamId::ConstParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
- db,
+ db.upcast(),
src.with_value(src.value[it.local_id()].as_ref().either(
|it| match it {
ast::TypeOrConstParam::Type(it) => it as _,
@@ -452,7 +327,7 @@ impl AttrsWithOwner {
GenericParamId::TypeParamId(it) => {
let src = it.parent().child_source(db);
RawAttrs::from_attrs_owner(
- db,
+ db.upcast(),
src.with_value(src.value[it.local_id()].as_ref().either(
|it| match it {
ast::TypeOrConstParam::Type(it) => it as _,
@@ -464,14 +339,14 @@ impl AttrsWithOwner {
}
GenericParamId::LifetimeParamId(it) => {
let src = it.parent.child_source(db);
- RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
+ RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id]))
}
},
AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
};
- let attrs = raw_attrs.filter(db, def.krate(db));
- Self { attrs, owner: def }
+ let attrs = raw_attrs.filter(db.upcast(), def.krate(db));
+ Self { attrs: Attrs(attrs), owner: def }
}
pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
@@ -627,40 +502,6 @@ fn doc_indent(attrs: &Attrs) -> usize {
.unwrap_or(0)
}
-fn inner_attributes(
- syntax: &SyntaxNode,
-) -> Option<impl Iterator<Item = Either<ast::Attr, ast::Comment>>> {
- let node = match_ast! {
- match syntax {
- ast::SourceFile(_) => syntax.clone(),
- ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(),
- ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(),
- ast::Impl(it) => it.assoc_item_list()?.syntax().clone(),
- ast::Module(it) => it.item_list()?.syntax().clone(),
- ast::BlockExpr(it) => {
- use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT};
- // Block expressions accept outer and inner attributes, but only when they are the outer
- // expression of an expression statement or the final expression of another block expression.
- let may_carry_attributes = matches!(
- it.syntax().parent().map(|it| it.kind()),
- Some(BLOCK_EXPR | EXPR_STMT)
- );
- if !may_carry_attributes {
- return None
- }
- syntax.clone()
- },
- _ => return None,
- }
- };
-
- let attrs = ast::AttrDocCommentIter::from_syntax_node(&node).filter(|el| match el {
- Either::Left(attr) => attr.kind().is_inner(),
- Either::Right(comment) => comment.is_inner(),
- });
- Some(attrs)
-}
-
#[derive(Debug)]
pub struct AttrSourceMap {
source: Vec<Either<ast::Attr, ast::Comment>>,
@@ -703,7 +544,7 @@ impl AttrSourceMap {
}
fn source_of_id(&self, id: AttrId) -> InFile<&Either<ast::Attr, ast::Comment>> {
- let ast_idx = id.ast_index as usize;
+ let ast_idx = id.ast_index();
let file_id = match self.mod_def_site_file_id {
Some((file_id, def_site_cut)) if def_site_cut <= ast_idx => file_id,
_ => self.file_id,
@@ -779,128 +620,6 @@ fn get_doc_string_in_attr(it: &ast::Attr) -> Option<ast::String> {
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct AttrId {
- pub(crate) ast_index: u32,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Attr {
- pub(crate) id: AttrId,
- pub(crate) path: Interned<ModPath>,
- pub(crate) input: Option<Interned<AttrInput>>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum AttrInput {
- /// `#[attr = "string"]`
- Literal(SmolStr),
- /// `#[attr(subtree)]`
- TokenTree(tt::Subtree, mbe::TokenMap),
-}
-
-impl fmt::Display for AttrInput {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()),
- AttrInput::TokenTree(subtree, _) => subtree.fmt(f),
- }
- }
-}
-
-impl Attr {
- fn from_src(
- db: &dyn DefDatabase,
- ast: ast::Meta,
- hygiene: &Hygiene,
- id: AttrId,
- ) -> Option<Attr> {
- let path = Interned::new(ModPath::from_src(db.upcast(), ast.path()?, hygiene)?);
- let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
- let value = match lit.kind() {
- ast::LiteralKind::String(string) => string.value()?.into(),
- _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
- };
- Some(Interned::new(AttrInput::Literal(value)))
- } else if let Some(tt) = ast.token_tree() {
- let (tree, map) = syntax_node_to_token_tree(tt.syntax());
- Some(Interned::new(AttrInput::TokenTree(tree, map)))
- } else {
- None
- };
- Some(Attr { id, path, input })
- }
-
- fn from_tt(
- db: &dyn DefDatabase,
- tt: &tt::Subtree,
- hygiene: &Hygiene,
- id: AttrId,
- ) -> Option<Attr> {
- let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem);
- let ast = ast::Meta::cast(parse.syntax_node())?;
-
- Self::from_src(db, ast, hygiene, id)
- }
-
- pub fn path(&self) -> &ModPath {
- &self.path
- }
-}
-
-impl Attr {
- /// #[path = "string"]
- pub fn string_value(&self) -> Option<&SmolStr> {
- match self.input.as_deref()? {
- AttrInput::Literal(it) => Some(it),
- _ => None,
- }
- }
-
- /// #[path(ident)]
- pub fn single_ident_value(&self) -> Option<&tt::Ident> {
- match self.input.as_deref()? {
- AttrInput::TokenTree(subtree, _) => match &*subtree.token_trees {
- [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident),
- _ => None,
- },
- _ => None,
- }
- }
-
- /// #[path TokenTree]
- pub fn token_tree_value(&self) -> Option<&Subtree> {
- match self.input.as_deref()? {
- AttrInput::TokenTree(subtree, _) => Some(subtree),
- _ => None,
- }
- }
-
- /// Parses this attribute as a token tree consisting of comma separated paths.
- pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
- let args = self.token_tree_value()?;
-
- if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
- return None;
- }
- let paths = args
- .token_trees
- .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
- .filter_map(|tts| {
- if tts.is_empty() {
- return None;
- }
- let segments = tts.iter().filter_map(|tt| match tt {
- tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
- _ => None,
- });
- Some(ModPath::from_segments(PathKind::Plain, segments))
- });
-
- Some(paths)
- }
-}
-
#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'attr> {
attrs: &'attr Attrs,
@@ -908,7 +627,7 @@ pub struct AttrQuery<'attr> {
}
impl<'attr> AttrQuery<'attr> {
- pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
+ pub fn tt_values(self) -> impl Iterator<Item = &'attr crate::tt::Subtree> {
self.attrs().filter_map(|attr| attr.token_tree_value())
}
@@ -953,21 +672,6 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
tree.raw_attrs(mod_item.into()).clone()
}
-fn collect_attrs(
- owner: &dyn ast::HasAttrs,
-) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
- let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
- let outer_attrs =
- ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
- Either::Left(attr) => attr.kind().is_outer(),
- Either::Right(comment) => comment.is_outer(),
- });
- outer_attrs
- .chain(inner_attrs)
- .enumerate()
- .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr))
-}
-
pub(crate) fn variants_attrs_source_map(
db: &dyn DefDatabase,
def: EnumId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 78fbaa9d7..8fd9255b8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -12,15 +12,17 @@ use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use drop_bomb::DropBomb;
use either::Either;
-use hir_expand::{hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId};
+use hir_expand::{
+ attrs::RawAttrs, hygiene::Hygiene, ExpandError, ExpandResult, HirFileId, InFile, MacroCallId,
+};
use la_arena::{Arena, ArenaMap};
use limit::Limit;
use profile::Count;
use rustc_hash::FxHashMap;
-use syntax::{ast, AstPtr, SyntaxNodePtr};
+use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr};
use crate::{
- attr::{Attrs, RawAttrs},
+ attr::Attrs,
db::DefDatabase,
expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId},
item_scope::BuiltinShadowMode,
@@ -49,7 +51,8 @@ pub struct Expander {
def_map: Arc<DefMap>,
current_file_id: HirFileId,
module: LocalModuleId,
- recursion_limit: usize,
+ /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
+ recursion_depth: usize,
}
impl CfgExpander {
@@ -64,7 +67,7 @@ impl CfgExpander {
}
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
- RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
+ Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene))
}
pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
@@ -82,7 +85,7 @@ impl Expander {
def_map,
current_file_id,
module: module.local_id,
- recursion_limit: 0,
+ recursion_depth: 0,
}
}
@@ -91,31 +94,37 @@ impl Expander {
db: &dyn DefDatabase,
macro_call: ast::MacroCall,
) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
- if self.recursion_limit(db).check(self.recursion_limit + 1).is_err() {
- cov_mark::hit!(your_stack_belongs_to_me);
- return Ok(ExpandResult::only_err(ExpandError::Other(
- "reached recursion limit during macro expansion".into(),
- )));
+ let mut unresolved_macro_err = None;
+
+ let result = self.within_limit(db, |this| {
+ let macro_call = InFile::new(this.current_file_id, &macro_call);
+
+ let resolver =
+ |path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
+
+ let mut err = None;
+ let call_id = match macro_call.as_call_id_with_errors(
+ db,
+ this.def_map.krate(),
+ resolver,
+ &mut |e| {
+ err.get_or_insert(e);
+ },
+ ) {
+ Ok(call_id) => call_id,
+ Err(resolve_err) => {
+ unresolved_macro_err = Some(resolve_err);
+ return ExpandResult { value: None, err: None };
+ }
+ };
+ ExpandResult { value: call_id.ok(), err }
+ });
+
+ if let Some(err) = unresolved_macro_err {
+ Err(err)
+ } else {
+ Ok(result)
}
-
- let macro_call = InFile::new(self.current_file_id, &macro_call);
-
- let resolver =
- |path| self.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
-
- let mut err = None;
- let call_id =
- macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| {
- err.get_or_insert(e);
- })?;
- let call_id = match call_id {
- Ok(it) => it,
- Err(_) => {
- return Ok(ExpandResult { value: None, err });
- }
- };
-
- Ok(self.enter_expand_inner(db, call_id, err))
}
pub fn enter_expand_id<T: ast::AstNode>(
@@ -123,15 +132,14 @@ impl Expander {
db: &dyn DefDatabase,
call_id: MacroCallId,
) -> ExpandResult<Option<(Mark, T)>> {
- self.enter_expand_inner(db, call_id, None)
+ self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
}
- fn enter_expand_inner<T: ast::AstNode>(
- &mut self,
+ fn enter_expand_inner(
db: &dyn DefDatabase,
call_id: MacroCallId,
mut err: Option<ExpandError>,
- ) -> ExpandResult<Option<(Mark, T)>> {
+ ) -> ExpandResult<Option<(HirFileId, SyntaxNode)>> {
if err.is_none() {
err = db.macro_expand_error(call_id);
}
@@ -152,29 +160,21 @@ impl Expander {
}
};
- let node = match T::cast(raw_node) {
- Some(it) => it,
- None => {
- // This can happen without being an error, so only forward previous errors.
- return ExpandResult { value: None, err };
- }
- };
-
- tracing::debug!("macro expansion {:#?}", node.syntax());
-
- self.recursion_limit += 1;
- let mark =
- Mark { file_id: self.current_file_id, bomb: DropBomb::new("expansion mark dropped") };
- self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
- self.current_file_id = file_id;
-
- ExpandResult { value: Some((mark, node)), err }
+ ExpandResult { value: Some((file_id, raw_node)), err }
}
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
self.current_file_id = mark.file_id;
- self.recursion_limit -= 1;
+ if self.recursion_depth == usize::MAX {
+ // Recursion limit has been reached somewhere in the macro expansion tree. Reset the
+ // depth only when we get out of the tree.
+ if !self.current_file_id.is_macro() {
+ self.recursion_depth = 0;
+ }
+ } else {
+ self.recursion_depth -= 1;
+ }
mark.bomb.defuse();
}
@@ -213,6 +213,50 @@ impl Expander {
#[cfg(test)]
return Limit::new(std::cmp::min(32, limit));
}
+
+ fn within_limit<F, T: ast::AstNode>(
+ &mut self,
+ db: &dyn DefDatabase,
+ op: F,
+ ) -> ExpandResult<Option<(Mark, T)>>
+ where
+ F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
+ {
+ if self.recursion_depth == usize::MAX {
+ // Recursion limit has been reached somewhere in the macro expansion tree. We should
+ // stop expanding other macro calls in this tree, or else this may result in
+ // exponential number of macro expansions, leading to a hang.
+ //
+ // The overflow error should have been reported when it occurred (see the next branch),
+ // so don't return overflow error here to avoid diagnostics duplication.
+ cov_mark::hit!(overflow_but_not_me);
+ return ExpandResult::only_err(ExpandError::RecursionOverflowPosioned);
+ } else if self.recursion_limit(db).check(self.recursion_depth + 1).is_err() {
+ self.recursion_depth = usize::MAX;
+ cov_mark::hit!(your_stack_belongs_to_me);
+ return ExpandResult::only_err(ExpandError::Other(
+ "reached recursion limit during macro expansion".into(),
+ ));
+ }
+
+ let ExpandResult { value, err } = op(self);
+ let Some(call_id) = value else {
+ return ExpandResult { value: None, err };
+ };
+
+ Self::enter_expand_inner(db, call_id, err).map(|value| {
+ value.and_then(|(new_file_id, node)| {
+ let node = T::cast(node)?;
+
+ self.recursion_depth += 1;
+ self.cfg_expander.hygiene = Hygiene::new(db.upcast(), new_file_id);
+ let old_file_id = std::mem::replace(&mut self.current_file_id, new_file_id);
+ let mark =
+ Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
+ Some((mark, node))
+ })
+ })
+ }
}
#[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index e8da24e3a..04b1c4f01 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -10,6 +10,7 @@ use hir_expand::{
name::{name, AsName, Name},
AstId, ExpandError, HirFileId, InFile,
};
+use intern::Interned;
use la_arena::Arena;
use once_cell::unsync::OnceCell;
use profile::Count;
@@ -33,7 +34,6 @@ use crate::{
Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
Statement,
},
- intern::Interned,
item_scope::BuiltinShadowMode,
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
@@ -67,9 +67,9 @@ impl<'a> LowerCtx<'a> {
Path::from_src(ast, self)
}
- pub(crate) fn ast_id<N: AstNode>(&self, db: &dyn DefDatabase, item: &N) -> Option<AstId<N>> {
+ pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<AstId<N>> {
let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
- let ast_id_map = ast_id_map.get_or_init(|| db.ast_id_map(file_id));
+ let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id));
Some(InFile::new(file_id, ast_id_map.ast_id(item)))
}
}
@@ -624,6 +624,10 @@ impl ExprCollector<'_> {
krate: *krate,
});
}
+ Some(ExpandError::RecursionOverflowPosioned) => {
+ // Recursion limit has been reached in the macro expansion tree, but not in
+ // this very macro call. Don't add diagnostics to avoid duplication.
+ }
Some(err) => {
self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
node: InFile::new(outer_file, syntax_ptr),
@@ -636,6 +640,8 @@ impl ExprCollector<'_> {
match res.value {
Some((mark, expansion)) => {
+ // Keep collecting even with expansion errors so we can provide completions and
+ // other services in incomplete macro expressions.
self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id);
let prev_ast_id_map = mem::replace(
&mut self.ast_id_map,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 10b9b26bb..4b4664a1c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -80,7 +80,7 @@ impl<'a> Write for Printer<'a> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for line in s.split_inclusive('\n') {
if self.needs_indent {
- match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
+ match self.buf.chars().rev().find(|ch| *ch != ' ') {
Some('\n') | None => {}
_ => self.buf.push('\n'),
}
@@ -113,7 +113,7 @@ impl<'a> Printer<'a> {
}
fn newline(&mut self) {
- match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
+ match self.buf.chars().rev().find(|ch| *ch != ' ') {
Some('\n') | None => {}
_ => writeln!(self).unwrap(),
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index c9601f855..edee2c7ff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -62,6 +62,19 @@ fn main() { n_nuple!(1,2,3); }
}
#[test]
+fn your_stack_belongs_to_me2() {
+ cov_mark::check!(overflow_but_not_me);
+ lower(
+ r#"
+macro_rules! foo {
+ () => {{ foo!(); foo!(); }}
+}
+fn main() { foo!(); }
+"#,
+ );
+}
+
+#[test]
fn recursion_limit() {
cov_mark::check!(your_stack_belongs_to_me);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index bb1316525..19d2fe956 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -117,7 +117,7 @@ impl ChildBySource for ItemScope {
let adt = ast_id.to_node(db.upcast());
calls.for_each(|(attr_id, call_id, calls)| {
if let Some(Either::Left(attr)) =
- adt.doc_comments_and_attrs().nth(attr_id.ast_index as usize)
+ adt.doc_comments_and_attrs().nth(attr_id.ast_index())
{
res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into()));
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index e6b05f27a..c3c1dfd39 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -3,6 +3,7 @@
use std::sync::Arc;
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
+use intern::Interned;
use smallvec::SmallVec;
use syntax::ast;
@@ -10,7 +11,6 @@ use crate::{
attr::Attrs,
body::{Expander, Mark},
db::DefDatabase,
- intern::Interned,
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
nameres::{
attr_resolution::ResolvedAttr,
@@ -142,7 +142,7 @@ impl FunctionData {
}
}
-fn parse_rustc_legacy_const_generics(tt: &tt::Subtree) -> Box<[u32]> {
+fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
let mut indices = Vec::new();
for args in tt.token_trees.chunks(2) {
match &args[0] {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 431c82554..b23427a73 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -4,8 +4,9 @@ use std::sync::Arc;
use base_db::{salsa, CrateId, SourceDatabase, Upcast};
use either::Either;
use hir_expand::{db::AstDatabase, HirFileId};
+use intern::Interned;
use la_arena::ArenaMap;
-use syntax::{ast, AstPtr, SmolStr};
+use syntax::{ast, AstPtr};
use crate::{
adt::{EnumData, StructData},
@@ -17,9 +18,8 @@ use crate::{
},
generics::GenericParams,
import_map::ImportMap,
- intern::Interned,
item_tree::{AttrOwner, ItemTree},
- lang_item::{LangItemTarget, LangItems},
+ lang_item::{LangItem, LangItemTarget, LangItems},
nameres::{diagnostics::DefDiagnostic, DefMap},
visibility::{self, Visibility},
AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId,
@@ -183,7 +183,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
#[salsa::invoke(LangItems::lang_item_query)]
- fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;
+ fn lang_item(&self, start_crate: CrateId, item: LangItem) -> Option<LangItemTarget>;
#[salsa::invoke(ImportMap::import_map_query)]
fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index 7b6569421..48028b7c6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -15,11 +15,11 @@
use std::fmt;
use hir_expand::name::Name;
+use intern::Interned;
use la_arena::{Idx, RawIdx};
use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
- intern::Interned,
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
BlockId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index ddd7ad99e..3f4392320 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -811,7 +811,7 @@ pub struct S;
fn prelude() {
check_found_path(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
$0
//- /std.rs crate:std
pub mod prelude {
@@ -852,7 +852,7 @@ pub mod prelude {
fn imported_prelude() {
check_found_path(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
use S;
$0
//- /std.rs crate:std
@@ -872,7 +872,7 @@ pub mod prelude {
#[test]
fn enum_variant_from_prelude() {
let code = r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
$0
//- /std.rs crate:std
pub mod prelude {
@@ -1273,7 +1273,7 @@ fn f() {
fn prelude_with_inner_items() {
check_found_path(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
fn f() {
fn inner() {}
$0
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index f74559f5d..b2ab0c30e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -9,6 +9,7 @@ use hir_expand::{
name::{AsName, Name},
ExpandResult, HirFileId, InFile,
};
+use intern::Interned;
use la_arena::{Arena, ArenaMap, Idx};
use once_cell::unsync::Lazy;
use std::ops::DerefMut;
@@ -20,7 +21,6 @@ use crate::{
child_by_source::ChildBySource,
db::DefDatabase,
dyn_map::DynMap,
- intern::Interned,
keys,
src::{HasChildSource, HasSource},
type_ref::{LifetimeRef, TypeBound, TypeRef},
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/intern.rs b/src/tools/rust-analyzer/crates/hir-def/src/intern.rs
deleted file mode 100644
index f08521a34..000000000
--- a/src/tools/rust-analyzer/crates/hir-def/src/intern.rs
+++ /dev/null
@@ -1,227 +0,0 @@
-//! Global `Arc`-based object interning infrastructure.
-//!
-//! Eventually this should probably be replaced with salsa-based interning.
-
-use std::{
- fmt::{self, Debug, Display},
- hash::{BuildHasherDefault, Hash, Hasher},
- ops::Deref,
- sync::Arc,
-};
-
-use dashmap::{DashMap, SharedValue};
-use hashbrown::HashMap;
-use once_cell::sync::OnceCell;
-use rustc_hash::FxHasher;
-
-use crate::generics::GenericParams;
-
-type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
-type Guard<T> = dashmap::RwLockWriteGuard<
- 'static,
- HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>,
->;
-
-pub struct Interned<T: Internable + ?Sized> {
- arc: Arc<T>,
-}
-
-impl<T: Internable> Interned<T> {
- pub fn new(obj: T) -> Self {
- match Interned::lookup(&obj) {
- Ok(this) => this,
- Err(shard) => {
- let arc = Arc::new(obj);
- Self::alloc(arc, shard)
- }
- }
- }
-}
-
-impl<T: Internable + ?Sized> Interned<T> {
- fn lookup(obj: &T) -> Result<Self, Guard<T>> {
- let storage = T::storage().get();
- let shard_idx = storage.determine_map(obj);
- let shard = &storage.shards()[shard_idx];
- let shard = shard.write();
-
- // Atomically,
- // - check if `obj` is already in the map
- // - if so, clone its `Arc` and return it
- // - if not, box it up, insert it, and return a clone
- // This needs to be atomic (locking the shard) to avoid races with other thread, which could
- // insert the same object between us looking it up and inserting it.
-
- // FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when
- // hashbrown can be plugged into dashmap)
- match shard.get_key_value(obj) {
- Some((arc, _)) => Ok(Self { arc: arc.clone() }),
- None => Err(shard),
- }
- }
-
- fn alloc(arc: Arc<T>, mut shard: Guard<T>) -> Self {
- let arc2 = arc.clone();
-
- shard.insert(arc2, SharedValue::new(()));
-
- Self { arc }
- }
-}
-
-impl Interned<str> {
- pub fn new_str(s: &str) -> Self {
- match Interned::lookup(s) {
- Ok(this) => this,
- Err(shard) => {
- let arc = Arc::<str>::from(s);
- Self::alloc(arc, shard)
- }
- }
- }
-}
-
-impl<T: Internable + ?Sized> Drop for Interned<T> {
- #[inline]
- fn drop(&mut self) {
- // When the last `Ref` is dropped, remove the object from the global map.
- if Arc::strong_count(&self.arc) == 2 {
- // Only `self` and the global map point to the object.
-
- self.drop_slow();
- }
- }
-}
-
-impl<T: Internable + ?Sized> Interned<T> {
- #[cold]
- fn drop_slow(&mut self) {
- let storage = T::storage().get();
- let shard_idx = storage.determine_map(&self.arc);
- let shard = &storage.shards()[shard_idx];
- let mut shard = shard.write();
-
- // FIXME: avoid double lookup
- let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely");
-
- if Arc::strong_count(arc) != 2 {
- // Another thread has interned another copy
- return;
- }
-
- shard.remove(&self.arc);
-
- // Shrink the backing storage if the shard is less than 50% occupied.
- if shard.len() * 2 < shard.capacity() {
- shard.shrink_to_fit();
- }
- }
-}
-
-/// Compares interned `Ref`s using pointer equality.
-impl<T: Internable> PartialEq for Interned<T> {
- // NOTE: No `?Sized` because `ptr_eq` doesn't work right with trait objects.
-
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- Arc::ptr_eq(&self.arc, &other.arc)
- }
-}
-
-impl<T: Internable> Eq for Interned<T> {}
-
-impl PartialEq for Interned<str> {
- fn eq(&self, other: &Self) -> bool {
- Arc::ptr_eq(&self.arc, &other.arc)
- }
-}
-
-impl Eq for Interned<str> {}
-
-impl<T: Internable + ?Sized> Hash for Interned<T> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- // NOTE: Cast disposes vtable pointer / slice/str length.
- state.write_usize(Arc::as_ptr(&self.arc) as *const () as usize)
- }
-}
-
-impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
- #[inline]
- fn as_ref(&self) -> &T {
- &self.arc
- }
-}
-
-impl<T: Internable + ?Sized> Deref for Interned<T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- &self.arc
- }
-}
-
-impl<T: Internable + ?Sized> Clone for Interned<T> {
- fn clone(&self) -> Self {
- Self { arc: self.arc.clone() }
- }
-}
-
-impl<T: Debug + Internable + ?Sized> Debug for Interned<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- (*self.arc).fmt(f)
- }
-}
-
-impl<T: Display + Internable + ?Sized> Display for Interned<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- (*self.arc).fmt(f)
- }
-}
-
-pub struct InternStorage<T: ?Sized> {
- map: OnceCell<InternMap<T>>,
-}
-
-impl<T: ?Sized> InternStorage<T> {
- pub const fn new() -> Self {
- Self { map: OnceCell::new() }
- }
-}
-
-impl<T: Internable + ?Sized> InternStorage<T> {
- fn get(&self) -> &InternMap<T> {
- self.map.get_or_init(DashMap::default)
- }
-}
-
-pub trait Internable: Hash + Eq + 'static {
- fn storage() -> &'static InternStorage<Self>;
-}
-
-/// Implements `Internable` for a given list of types, making them usable with `Interned`.
-#[macro_export]
-#[doc(hidden)]
-macro_rules! _impl_internable {
- ( $($t:path),+ $(,)? ) => { $(
- impl Internable for $t {
- fn storage() -> &'static InternStorage<Self> {
- static STORAGE: InternStorage<$t> = InternStorage::new();
- &STORAGE
- }
- }
- )+ };
-}
-
-pub use crate::_impl_internable as impl_internable;
-
-impl_internable!(
- crate::type_ref::TypeRef,
- crate::type_ref::TraitRef,
- crate::type_ref::TypeBound,
- crate::path::ModPath,
- crate::path::GenericArgs,
- crate::attr::AttrInput,
- GenericParams,
- str,
-);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index c7b213b7e..53a4173ff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -4,7 +4,7 @@
use std::collections::hash_map::Entry;
use base_db::CrateId;
-use hir_expand::{name::Name, AstId, MacroCallId};
+use hir_expand::{attrs::AttrId, name::Name, AstId, MacroCallId};
use itertools::Itertools;
use once_cell::sync::Lazy;
use profile::Count;
@@ -14,8 +14,8 @@ use stdx::format_to;
use syntax::ast;
use crate::{
- attr::AttrId, db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType,
- ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
+ db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, HasModule,
+ ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
};
#[derive(Copy, Clone, Debug)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 80297f8ad..19d01630e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -48,10 +48,12 @@ use base_db::CrateId;
use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
+ attrs::RawAttrs,
hygiene::Hygiene,
name::{name, AsName, Name},
ExpandTo, HirFileId, InFile,
};
+use intern::Interned;
use la_arena::{Arena, Idx, IdxRange, RawIdx};
use profile::Count;
use rustc_hash::FxHashMap;
@@ -60,10 +62,9 @@ use stdx::never;
use syntax::{ast, match_ast, SyntaxKind};
use crate::{
- attr::{Attrs, RawAttrs},
+ attr::Attrs,
db::DefDatabase,
generics::GenericParams,
- intern::Interned,
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
@@ -110,7 +111,8 @@ impl ItemTree {
Some(node) => node,
None => return Default::default(),
};
- if never!(syntax.kind() == SyntaxKind::ERROR) {
+ if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax)
+ {
// FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
return Default::default();
}
@@ -120,7 +122,7 @@ impl ItemTree {
let mut item_tree = match_ast! {
match syntax {
ast::SourceFile(file) => {
- top_attrs = Some(RawAttrs::new(db, &file, ctx.hygiene()));
+ top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.hygiene()));
ctx.lower_module_items(&file)
},
ast::MacroItems(items) => {
@@ -132,7 +134,7 @@ impl ItemTree {
ctx.lower_macro_stmts(stmts)
},
_ => {
- panic!("cannot create item tree from {syntax:?} {syntax}");
+ panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
},
}
};
@@ -152,7 +154,11 @@ impl ItemTree {
/// Returns the inner attributes of the source file.
pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
- self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone().filter(db, krate)
+ Attrs::filter(
+ db,
+ krate,
+ self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(),
+ )
}
pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
@@ -160,7 +166,7 @@ impl ItemTree {
}
pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
- self.raw_attrs(of).clone().filter(db, krate)
+ Attrs::filter(db, krate, self.raw_attrs(of).clone())
}
pub fn pretty_print(&self) -> String {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index b25274bcc..d4d3c5ef1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -99,7 +99,7 @@ impl<'a> Ctx<'a> {
}
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> {
- let attrs = RawAttrs::new(self.db, item, self.hygiene());
+ let attrs = RawAttrs::new(self.db.upcast(), item, self.hygiene());
let item: ModItem = match item {
ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
ast::Item::Union(ast) => self.lower_union(ast)?.into(),
@@ -173,7 +173,7 @@ impl<'a> Ctx<'a> {
for field in fields.fields() {
if let Some(data) = self.lower_record_field(&field) {
let idx = self.data().fields.alloc(data);
- self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, self.hygiene()));
+ self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), &field, self.hygiene()));
}
}
let end = self.next_field_idx();
@@ -194,7 +194,7 @@ impl<'a> Ctx<'a> {
for (i, field) in fields.fields().enumerate() {
let data = self.lower_tuple_field(i, &field);
let idx = self.data().fields.alloc(data);
- self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, self.hygiene()));
+ self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), &field, self.hygiene()));
}
let end = self.next_field_idx();
IdxRange::new(start..end)
@@ -239,7 +239,10 @@ impl<'a> Ctx<'a> {
for variant in variants.variants() {
if let Some(data) = self.lower_variant(&variant) {
let idx = self.data().variants.alloc(data);
- self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, self.hygiene()));
+ self.add_attrs(
+ idx.into(),
+ RawAttrs::new(self.db.upcast(), &variant, self.hygiene()),
+ );
}
}
let end = self.next_variant_idx();
@@ -283,7 +286,10 @@ impl<'a> Ctx<'a> {
};
let ty = Interned::new(self_type);
let idx = self.data().params.alloc(Param::Normal(None, ty));
- self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, self.hygiene()));
+ self.add_attrs(
+ idx.into(),
+ RawAttrs::new(self.db.upcast(), &self_param, self.hygiene()),
+ );
has_self_param = true;
}
for param in param_list.params() {
@@ -307,7 +313,7 @@ impl<'a> Ctx<'a> {
self.data().params.alloc(Param::Normal(name, ty))
}
};
- self.add_attrs(idx.into(), RawAttrs::new(self.db, &param, self.hygiene()));
+ self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), &param, self.hygiene()));
}
}
let end_param = self.next_param_idx();
@@ -442,7 +448,7 @@ impl<'a> Ctx<'a> {
let items = trait_def.assoc_item_list().map(|list| {
list.assoc_items()
.filter_map(|item| {
- let attrs = RawAttrs::new(self.db, &item, self.hygiene());
+ let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene());
self.lower_assoc_item(&item).map(|item| {
self.add_attrs(ModItem::from(item).into(), attrs);
item
@@ -471,7 +477,7 @@ impl<'a> Ctx<'a> {
.flat_map(|it| it.assoc_items())
.filter_map(|item| {
let assoc = self.lower_assoc_item(&item)?;
- let attrs = RawAttrs::new(self.db, &item, self.hygiene());
+ let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene());
self.add_attrs(ModItem::from(assoc).into(), attrs);
Some(assoc)
})
@@ -541,7 +547,7 @@ impl<'a> Ctx<'a> {
// (in other words, the knowledge that they're in an extern block must not be used).
// This is because an extern block can contain macros whose ItemTree's top-level items
// should be considered to be in an extern block too.
- let attrs = RawAttrs::new(self.db, &item, self.hygiene());
+ let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene());
let id: ModItem = match item {
ast::ExternItem::Fn(ast) => self.lower_function(&ast)?.into(),
ast::ExternItem::Static(ast) => self.lower_static(&ast)?.into(),
@@ -653,15 +659,16 @@ fn desugar_future_path(orig: TypeRef) -> Path {
let path = path![core::future::Future];
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
- let mut last = GenericArgs::empty();
let binding = AssociatedTypeBinding {
name: name![Output],
args: None,
type_ref: Some(orig),
- bounds: Vec::new(),
+ bounds: Box::default(),
};
- last.bindings.push(binding);
- generic_args.push(Some(Interned::new(last)));
+ generic_args.push(Some(Interned::new(GenericArgs {
+ bindings: Box::new([binding]),
+ ..GenericArgs::empty()
+ })));
Path::from_known_path(path, generic_args)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 48c40df22..8f230b87d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -3,7 +3,6 @@
use std::fmt::{self, Write};
use crate::{
- attr::RawAttrs,
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
pretty::{print_path, print_type_bounds, print_type_ref},
visibility::RawVisibility,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/keys.rs
index c5cb9a2af..72beec818 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/keys.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/keys.rs
@@ -2,12 +2,11 @@
use std::marker::PhantomData;
-use hir_expand::MacroCallId;
+use hir_expand::{attrs::AttrId, MacroCallId};
use rustc_hash::FxHashMap;
use syntax::{ast, AstNode, AstPtr};
use crate::{
- attr::AttrId,
dyn_map::{DynMap, Policy},
ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id,
MacroRulesId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 877850184..ab9bc615d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -8,19 +8,21 @@ use rustc_hash::FxHashMap;
use syntax::SmolStr;
use crate::{
- db::DefDatabase, AdtId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId, ImplId,
- ModuleDefId, StaticId, StructId, TraitId,
+ db::DefDatabase, AdtId, AssocItemId, AttrDefId, CrateId, EnumId, EnumVariantId, FunctionId,
+ ImplId, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LangItemTarget {
EnumId(EnumId),
- FunctionId(FunctionId),
- ImplDefId(ImplId),
- StaticId(StaticId),
- StructId(StructId),
- TraitId(TraitId),
- EnumVariantId(EnumVariantId),
+ Function(FunctionId),
+ ImplDef(ImplId),
+ Static(StaticId),
+ Struct(StructId),
+ Union(UnionId),
+ TypeAlias(TypeAliasId),
+ Trait(TraitId),
+ EnumVariant(EnumVariantId),
}
impl LangItemTarget {
@@ -33,42 +35,42 @@ impl LangItemTarget {
pub fn as_function(self) -> Option<FunctionId> {
match self {
- LangItemTarget::FunctionId(id) => Some(id),
+ LangItemTarget::Function(id) => Some(id),
_ => None,
}
}
pub fn as_impl_def(self) -> Option<ImplId> {
match self {
- LangItemTarget::ImplDefId(id) => Some(id),
+ LangItemTarget::ImplDef(id) => Some(id),
_ => None,
}
}
pub fn as_static(self) -> Option<StaticId> {
match self {
- LangItemTarget::StaticId(id) => Some(id),
+ LangItemTarget::Static(id) => Some(id),
_ => None,
}
}
pub fn as_struct(self) -> Option<StructId> {
match self {
- LangItemTarget::StructId(id) => Some(id),
+ LangItemTarget::Struct(id) => Some(id),
_ => None,
}
}
pub fn as_trait(self) -> Option<TraitId> {
match self {
- LangItemTarget::TraitId(id) => Some(id),
+ LangItemTarget::Trait(id) => Some(id),
_ => None,
}
}
pub fn as_enum_variant(self) -> Option<EnumVariantId> {
match self {
- LangItemTarget::EnumVariantId(id) => Some(id),
+ LangItemTarget::EnumVariant(id) => Some(id),
_ => None,
}
}
@@ -76,12 +78,12 @@ impl LangItemTarget {
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct LangItems {
- items: FxHashMap<SmolStr, LangItemTarget>,
+ items: FxHashMap<LangItem, LangItemTarget>,
}
impl LangItems {
- pub fn target(&self, item: &str) -> Option<LangItemTarget> {
- self.items.get(item).copied()
+ pub fn target(&self, item: LangItem) -> Option<LangItemTarget> {
+ self.items.get(&item).copied()
}
/// Salsa query. This will look for lang items in a specific crate.
@@ -94,16 +96,27 @@ impl LangItems {
for (_, module_data) in crate_def_map.modules() {
for impl_def in module_data.scope.impls() {
- lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDefId)
+ lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
+ for assoc in db.impl_data(impl_def).items.iter().copied() {
+ match assoc {
+ AssocItemId::FunctionId(f) => {
+ lang_items.collect_lang_item(db, f, LangItemTarget::Function)
+ }
+ AssocItemId::TypeAliasId(t) => {
+ lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias)
+ }
+ AssocItemId::ConstId(_) => (),
+ }
+ }
}
for def in module_data.scope.declarations() {
match def {
ModuleDefId::TraitId(trait_) => {
- lang_items.collect_lang_item(db, trait_, LangItemTarget::TraitId);
+ lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait);
db.trait_data(trait_).items.iter().for_each(|&(_, assoc_id)| {
- if let crate::AssocItemId::FunctionId(f) = assoc_id {
- lang_items.collect_lang_item(db, f, LangItemTarget::FunctionId);
+ if let AssocItemId::FunctionId(f) = assoc_id {
+ lang_items.collect_lang_item(db, f, LangItemTarget::Function);
}
});
}
@@ -113,18 +126,24 @@ impl LangItems {
lang_items.collect_lang_item(
db,
EnumVariantId { parent: e, local_id },
- LangItemTarget::EnumVariantId,
+ LangItemTarget::EnumVariant,
);
});
}
ModuleDefId::AdtId(AdtId::StructId(s)) => {
- lang_items.collect_lang_item(db, s, LangItemTarget::StructId);
+ lang_items.collect_lang_item(db, s, LangItemTarget::Struct);
+ }
+ ModuleDefId::AdtId(AdtId::UnionId(u)) => {
+ lang_items.collect_lang_item(db, u, LangItemTarget::Union);
}
ModuleDefId::FunctionId(f) => {
- lang_items.collect_lang_item(db, f, LangItemTarget::FunctionId);
+ lang_items.collect_lang_item(db, f, LangItemTarget::Function);
}
ModuleDefId::StaticId(s) => {
- lang_items.collect_lang_item(db, s, LangItemTarget::StaticId);
+ lang_items.collect_lang_item(db, s, LangItemTarget::Static);
+ }
+ ModuleDefId::TypeAliasId(t) => {
+ lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias);
}
_ => {}
}
@@ -139,7 +158,7 @@ impl LangItems {
pub(crate) fn lang_item_query(
db: &dyn DefDatabase,
start_crate: CrateId,
- item: SmolStr,
+ item: LangItem,
) -> Option<LangItemTarget> {
let _p = profile::span("lang_item_query");
let lang_items = db.crate_lang_items(start_crate);
@@ -150,7 +169,7 @@ impl LangItems {
db.crate_graph()[start_crate]
.dependencies
.iter()
- .find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
+ .find_map(|dep| db.lang_item(dep.crate_id, item))
}
fn collect_lang_item<T>(
@@ -162,8 +181,8 @@ impl LangItems {
T: Into<AttrDefId> + Copy,
{
let _p = profile::span("collect_lang_item");
- if let Some(lang_item_name) = lang_attr(db, item) {
- self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
+ if let Some(lang_item) = lang_attr(db, item).and_then(|it| LangItem::from_str(&it)) {
+ self.items.entry(lang_item).or_insert_with(|| constructor(item));
}
}
}
@@ -172,3 +191,224 @@ pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Opt
let attrs = db.attrs(item.into());
attrs.by_key("lang").string_value().cloned()
}
+
+pub enum GenericRequirement {
+ None,
+ Minimum(usize),
+ Exact(usize),
+}
+
+macro_rules! language_item_table {
+ (
+ $( $(#[$attr:meta])* $variant:ident, $name:ident, $method:ident, $target:expr, $generics:expr; )*
+ ) => {
+
+ /// A representation of all the valid language items in Rust.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub enum LangItem {
+ $(
+ #[doc = concat!("The `", stringify!($name), "` lang item.")]
+ $(#[$attr])*
+ $variant,
+ )*
+ }
+
+ impl LangItem {
+ pub fn name(self) -> SmolStr {
+ match self {
+ $( LangItem::$variant => SmolStr::new(stringify!($name)), )*
+ }
+ }
+
+ /// Opposite of [`LangItem::name`]
+ pub fn from_name(name: &hir_expand::name::Name) -> Option<Self> {
+ Self::from_str(name.as_str()?)
+ }
+
+ /// Opposite of [`LangItem::name`]
+ pub fn from_str(name: &str) -> Option<Self> {
+ match name {
+ $( stringify!($name) => Some(LangItem::$variant), )*
+ _ => None,
+ }
+ }
+ }
+ }
+}
+
+language_item_table! {
+// Variant name, Name, Getter method name, Target Generic requirements;
+ Sized, sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
+ Unsize, unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
+ /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
+ StructuralPeq, structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None;
+ /// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize).
+ StructuralTeq, structural_teq, structural_teq_trait, Target::Trait, GenericRequirement::None;
+ Copy, copy, copy_trait, Target::Trait, GenericRequirement::Exact(0);
+ Clone, clone, clone_trait, Target::Trait, GenericRequirement::None;
+ Sync, sync, sync_trait, Target::Trait, GenericRequirement::Exact(0);
+ DiscriminantKind, discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None;
+ /// The associated item of the [`DiscriminantKind`] trait.
+ Discriminant, discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None;
+
+ PointeeTrait, pointee_trait, pointee_trait, Target::Trait, GenericRequirement::None;
+ Metadata, metadata_type, metadata_type, Target::AssocTy, GenericRequirement::None;
+ DynMetadata, dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
+
+ Freeze, freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
+
+ Drop, drop, drop_trait, Target::Trait, GenericRequirement::None;
+ Destruct, destruct, destruct_trait, Target::Trait, GenericRequirement::None;
+
+ CoerceUnsized, coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
+ DispatchFromDyn, dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
+
+ // language items relating to transmutability
+ TransmuteOpts, transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0);
+ TransmuteTrait, transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3);
+
+ Add, add, add_trait, Target::Trait, GenericRequirement::Exact(1);
+ Sub, sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
+ Mul, mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);
+ Div, div, div_trait, Target::Trait, GenericRequirement::Exact(1);
+ Rem, rem, rem_trait, Target::Trait, GenericRequirement::Exact(1);
+ Neg, neg, neg_trait, Target::Trait, GenericRequirement::Exact(0);
+ Not, not, not_trait, Target::Trait, GenericRequirement::Exact(0);
+ BitXor, bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAnd, bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOr, bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shl, shl, shl_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shr, shr, shr_trait, Target::Trait, GenericRequirement::Exact(1);
+ AddAssign, add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ SubAssign, sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ MulAssign, mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ DivAssign, div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ RemAssign, rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitXorAssign, bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAndAssign, bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOrAssign, bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShlAssign, shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShrAssign, shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ Index, index, index_trait, Target::Trait, GenericRequirement::Exact(1);
+ IndexMut, index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+
+ UnsafeCell, unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
+ VaList, va_list, va_list, Target::Struct, GenericRequirement::None;
+
+ Deref, deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
+ DerefMut, deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
+ DerefTarget, deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
+ Receiver, receiver, receiver_trait, Target::Trait, GenericRequirement::None;
+
+ Fn, fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnMut, fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnOnce, fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
+
+ FnOnceOutput, fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
+
+ Future, future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
+ GeneratorState, generator_state, gen_state, Target::Enum, GenericRequirement::None;
+ Generator, generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
+ Unpin, unpin, unpin_trait, Target::Trait, GenericRequirement::None;
+ Pin, pin, pin_type, Target::Struct, GenericRequirement::None;
+
+ PartialEq, eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialOrd, partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
+
+ // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
+ // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
+ //
+ // The `begin_unwind` lang item has a predefined symbol name and is sort of a "weak lang item"
+ // in the sense that a crate is not required to have it defined to use it, but a final product
+ // is required to define it somewhere. Additionally, there are restrictions on crates that use
+ // a weak lang item, but do not have it defined.
+ Panic, panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
+ PanicNounwind, panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0);
+ PanicFmt, panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
+ PanicDisplay, panic_display, panic_display, Target::Fn, GenericRequirement::None;
+ ConstPanicFmt, const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
+ PanicBoundsCheck, panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
+ PanicInfo, panic_info, panic_info, Target::Struct, GenericRequirement::None;
+ PanicLocation, panic_location, panic_location, Target::Struct, GenericRequirement::None;
+ PanicImpl, panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
+ PanicCannotUnwind, panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
+ /// libstd panic entry point. Necessary for const eval to be able to catch it
+ BeginPanic, begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
+
+ ExchangeMalloc, exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
+ BoxFree, box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
+ DropInPlace, drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
+ AllocLayout, alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;
+
+ Start, start, start_fn, Target::Fn, GenericRequirement::Exact(1);
+
+ EhPersonality, eh_personality, eh_personality, Target::Fn, GenericRequirement::None;
+ EhCatchTypeinfo, eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
+
+ OwnedBox, owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
+
+ PhantomData, phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1);
+
+ ManuallyDrop, manually_drop, manually_drop, Target::Struct, GenericRequirement::None;
+
+ MaybeUninit, maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None;
+
+ /// Align offset for stride != 1; must not panic.
+ AlignOffset, align_offset, align_offset_fn, Target::Fn, GenericRequirement::None;
+
+ Termination, termination, termination, Target::Trait, GenericRequirement::None;
+
+ Try, Try, try_trait, Target::Trait, GenericRequirement::None;
+
+ Tuple, tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0);
+
+ SliceLen, slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
+
+ // Language items from AST lowering
+ TryTraitFromResidual, from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ TryTraitFromOutput, from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ TryTraitBranch, branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ TryTraitFromYeet, from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
+
+ PointerSized, pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0);
+
+ Poll, Poll, poll, Target::Enum, GenericRequirement::None;
+ PollReady, Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
+ PollPending, Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
+
+ // FIXME(swatinem): the following lang items are used for async lowering and
+ // should become obsolete eventually.
+ ResumeTy, ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
+ IdentityFuture, identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
+ GetContext, get_context, get_context_fn, Target::Fn, GenericRequirement::None;
+
+ Context, Context, context, Target::Struct, GenericRequirement::None;
+ FuturePoll, poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+
+ FromFrom, from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+
+ OptionSome, Some, option_some_variant, Target::Variant, GenericRequirement::None;
+ OptionNone, None, option_none_variant, Target::Variant, GenericRequirement::None;
+
+ ResultOk, Ok, result_ok_variant, Target::Variant, GenericRequirement::None;
+ ResultErr, Err, result_err_variant, Target::Variant, GenericRequirement::None;
+
+ ControlFlowContinue, Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
+ ControlFlowBreak, Break, cf_break_variant, Target::Variant, GenericRequirement::None;
+
+ IntoFutureIntoFuture, into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ IntoIterIntoIter, into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ IteratorNext, next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
+
+ PinNewUnchecked, new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
+
+ RangeFrom, RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None;
+ RangeFull, RangeFull, range_full_struct, Target::Struct, GenericRequirement::None;
+ RangeInclusiveStruct, RangeInclusive, range_inclusive_struct, Target::Struct, GenericRequirement::None;
+ RangeInclusiveNew, range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent), GenericRequirement::None;
+ Range, Range, range_struct, Target::Struct, GenericRequirement::None;
+ RangeToInclusive, RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
+ RangeTo, RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
+
+ String, String, string, Target::Struct, GenericRequirement::None;
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/layout.rs b/src/tools/rust-analyzer/crates/hir-def/src/layout.rs
index 6bb4cd94f..49b1190ad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/layout.rs
@@ -90,6 +90,7 @@ impl IntegerExt for Integer {
pub enum LayoutError {
UserError(String),
SizeOverflow,
+ TargetLayoutNotAvailable,
HasPlaceholder,
NotImplemented,
Unknown,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 8267ef09c..d07c5fb67 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -28,7 +28,6 @@ pub mod dyn_map;
pub mod keys;
pub mod item_tree;
-pub mod intern;
pub mod adt;
pub mod data;
@@ -61,10 +60,10 @@ use std::{
sync::Arc,
};
-use attr::Attr;
use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind};
use hir_expand::{
ast_id_map::FileAstId,
+ attrs::{Attr, AttrId, AttrInput},
builtin_attr_macro::BuiltinAttrExpander,
builtin_derive_macro::BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
@@ -80,9 +79,10 @@ use nameres::DefMap;
use stdx::impl_from;
use syntax::ast;
+use ::tt::token_id as tt;
+
use crate::{
adt::VariantData,
- attr::AttrId,
builtin_type::BuiltinType,
item_tree::{
Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem,
@@ -292,6 +292,7 @@ pub struct Macro2Loc {
pub container: ModuleId,
pub id: ItemTreeId<MacroDef>,
pub expander: MacroExpander,
+ pub allow_internal_unsafe: bool,
}
impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
@@ -301,8 +302,9 @@ pub struct MacroRulesId(salsa::InternId);
pub struct MacroRulesLoc {
pub container: ModuleId,
pub id: ItemTreeId<MacroRules>,
- pub local_inner: bool,
pub expander: MacroExpander,
+ pub allow_internal_unsafe: bool,
+ pub local_inner: bool,
}
impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macro_rules);
@@ -896,6 +898,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
}
},
local_inner: false,
+ allow_internal_unsafe: loc.allow_internal_unsafe,
}
}
MacroId::MacroRulesId(it) => {
@@ -920,6 +923,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
}
},
local_inner: loc.local_inner,
+ allow_internal_unsafe: loc.allow_internal_unsafe,
}
}
MacroId::ProcMacroId(it) => {
@@ -935,6 +939,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
InFile::new(loc.id.file_id(), makro.ast_id),
),
local_inner: false,
+ allow_internal_unsafe: false,
}
}
}
@@ -943,7 +948,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId {
fn derive_macro_as_call_id(
db: &dyn db::DefDatabase,
item_attr: &AstIdWithPath<ast::Adt>,
- derive_attr: AttrId,
+ derive_attr_index: AttrId,
derive_pos: u32,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
@@ -956,7 +961,7 @@ fn derive_macro_as_call_id(
MacroCallKind::Derive {
ast_id: item_attr.ast_id,
derive_index: derive_pos,
- derive_attr_index: derive_attr.ast_index,
+ derive_attr_index,
},
);
Ok((macro_id, def_id, call_id))
@@ -970,23 +975,33 @@ fn attr_macro_as_call_id(
def: MacroDefId,
is_derive: bool,
) -> MacroCallId {
- let mut arg = match macro_attr.input.as_deref() {
- Some(attr::AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()),
- _ => Default::default(),
+ let arg = match macro_attr.input.as_deref() {
+ Some(AttrInput::TokenTree(tt, map)) => (
+ {
+ let mut tt = tt.clone();
+ tt.delimiter = tt::Delimiter::UNSPECIFIED;
+ tt
+ },
+ map.clone(),
+ ),
+ _ => (tt::Subtree::empty(), Default::default()),
};
- // The parentheses are always disposed here.
- arg.0.delimiter = None;
-
- let res = def.as_lazy_macro(
+ def.as_lazy_macro(
db.upcast(),
krate,
MacroCallKind::Attr {
ast_id: item_attr.ast_id,
attr_args: Arc::new(arg),
- invoc_attr_index: macro_attr.id.ast_index,
+ invoc_attr_index: macro_attr.id,
is_derive,
},
- );
- res
-}
+ )
+}
+intern::impl_internable!(
+ crate::type_ref::TypeRef,
+ crate::type_ref::TraitRef,
+ crate::type_ref::TypeBound,
+ crate::path::GenericArgs,
+ generics::GenericParams,
+);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
index 79c85d118..5ab90d92d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs
@@ -30,7 +30,7 @@ use syntax::{
SyntaxKind::{self, COMMENT, EOF, IDENT, LIFETIME_IDENT},
SyntaxNode, TextRange, T,
};
-use tt::{Subtree, TokenId};
+use tt::token_id::{Subtree, TokenId};
use crate::{
db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
@@ -97,7 +97,9 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
let ast_id = AstId::new(source.file_id, file_ast_id.upcast());
let kind = MacroDefKind::Declarative(ast_id);
- let macro_def = db.macro_def(MacroDefId { krate, kind, local_inner: false }).unwrap();
+ let macro_def = db
+ .macro_def(MacroDefId { krate, kind, local_inner: false, allow_internal_unsafe: false })
+ .unwrap();
if let TokenExpander::DeclarativeMacro { mac, def_site_token_map } = &*macro_def {
let tt = match &macro_ {
ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
@@ -251,9 +253,9 @@ fn extract_id_ranges(ranges: &mut Vec<(TextRange, TokenId)>, map: &TokenMap, tre
tree.token_trees.iter().for_each(|tree| match tree {
tt::TokenTree::Leaf(leaf) => {
let id = match leaf {
- tt::Leaf::Literal(it) => it.id,
- tt::Leaf::Punct(it) => it.id,
- tt::Leaf::Ident(it) => it.id,
+ tt::Leaf::Literal(it) => it.span,
+ tt::Leaf::Punct(it) => it.span,
+ tt::Leaf::Ident(it) => it.span,
};
ranges.extend(map.ranges_by_token(id, SyntaxKind::ERROR).map(|range| (range, id)));
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 2d5f2a692..7a3e8c3b0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -97,6 +97,41 @@ fn#19 main#20(#21)#21 {#22
"##]],
);
}
+#[test]
+fn float_field_acces_macro_input() {
+ check(
+ r#"
+macro_rules! foo {
+ ($expr:expr) => {
+ fn foo() {
+ $expr;
+ }
+ };
+}
+foo!(x .0.1);
+foo!(x .2. 3);
+foo!(x .4 .5);
+"#,
+ expect![[r#"
+macro_rules! foo {
+ ($expr:expr) => {
+ fn foo() {
+ $expr;
+ }
+ };
+}
+fn foo() {
+ (x.0.1);
+}
+fn foo() {
+ (x.2.3);
+}
+fn foo() {
+ (x.4.5);
+}
+"#]],
+ );
+}
#[test]
fn mbe_smoke_test() {
@@ -1441,7 +1476,7 @@ macro_rules! m {
/* parse error: expected identifier */
/* parse error: expected SEMICOLON */
/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
+/* parse error: expected expression, item or let statement */
fn f() {
K::(C("0"));
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index d2505e7ca..8358a46f0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -830,8 +830,7 @@ macro_rules! rgb_color {
/* parse error: expected COMMA */
/* parse error: expected R_ANGLE */
/* parse error: expected SEMICOLON */
-/* parse error: expected SEMICOLON */
-/* parse error: expected expression */
+/* parse error: expected expression, item or let statement */
pub fn new() {
let _ = 0as u32<<(8+8);
}
@@ -848,21 +847,21 @@ pub fn new() {
// BLOCK_EXPR@10..31
// STMT_LIST@10..31
// L_CURLY@10..11 "{"
-// LET_STMT@11..27
+// LET_STMT@11..28
// LET_KW@11..14 "let"
// WILDCARD_PAT@14..15
// UNDERSCORE@14..15 "_"
// EQ@15..16 "="
-// CAST_EXPR@16..27
+// CAST_EXPR@16..28
// LITERAL@16..17
// INT_NUMBER@16..17 "0"
// AS_KW@17..19 "as"
-// PATH_TYPE@19..27
-// PATH@19..27
-// PATH_SEGMENT@19..27
+// PATH_TYPE@19..28
+// PATH@19..28
+// PATH_SEGMENT@19..28
// NAME_REF@19..22
// IDENT@19..22 "u32"
-// GENERIC_ARG_LIST@22..27
+// GENERIC_ARG_LIST@22..28
// L_ANGLE@22..23 "<"
// TYPE_ARG@23..27
// DYN_TRAIT_TYPE@23..27
@@ -877,9 +876,9 @@ pub fn new() {
// ERROR@25..26
// INT_NUMBER@25..26 "8"
// PLUS@26..27 "+"
-// EXPR_STMT@27..28
-// LITERAL@27..28
-// INT_NUMBER@27..28 "8"
+// CONST_ARG@27..28
+// LITERAL@27..28
+// INT_NUMBER@27..28 "8"
// ERROR@28..29
// R_PAREN@28..29 ")"
// SEMICOLON@29..30 ";"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index 118c14ed8..822bdcc12 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -104,7 +104,7 @@ macro_rules! id {
$($t)*
};
}
-id /*+errors*/! {
+id! {
#[proc_macros::identity]
impl Foo for WrapBj {
async fn foo(&self) {
@@ -113,18 +113,17 @@ id /*+errors*/! {
}
}
"#,
- expect![[r##"
+ expect![[r#"
macro_rules! id {
($($t:tt)*) => {
$($t)*
};
}
-/* parse error: expected SEMICOLON */
#[proc_macros::identity] impl Foo for WrapBj {
async fn foo(&self ) {
self .0.id().await ;
}
}
-"##]],
+"#]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
index 3650204ee..79cabeb0f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs
@@ -1,10 +1,9 @@
//! Post-nameres attribute resolution.
-use hir_expand::MacroCallId;
+use hir_expand::{attrs::Attr, MacroCallId};
use syntax::{ast, SmolStr};
use crate::{
- attr::Attr,
attr_macro_as_call_id, builtin_attr,
db::DefDatabase,
item_scope::BuiltinShadowMode,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 160203b77..4b39a20d8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -10,6 +10,7 @@ use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
+ attrs::{Attr, AttrId},
builtin_attr_macro::find_builtin_attr,
builtin_derive_macro::find_builtin_derive,
builtin_fn_macro::find_builtin_macro,
@@ -26,7 +27,7 @@ use stdx::always;
use syntax::{ast, SmolStr};
use crate::{
- attr::{Attr, AttrId, Attrs},
+ attr::Attrs,
attr_macro_as_call_id,
db::DefDatabase,
derive_macro_as_call_id,
@@ -45,6 +46,7 @@ use crate::{
},
path::{ImportAlias, ModPath, PathKind},
per_ns::PerNs,
+ tt,
visibility::{RawVisibility, Visibility},
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
@@ -82,7 +84,8 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
.enumerate()
.map(|(idx, it)| {
// FIXME: a hacky way to create a Name from string.
- let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
+ let name =
+ tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
(
name.as_name(),
ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
@@ -450,8 +453,11 @@ impl DefCollector<'_> {
directive.module_id,
MacroCallKind::Attr {
ast_id: ast_id.ast_id,
- attr_args: Default::default(),
- invoc_attr_index: attr.id.ast_index,
+ attr_args: std::sync::Arc::new((
+ tt::Subtree::empty(),
+ Default::default(),
+ )),
+ invoc_attr_index: attr.id,
is_derive: false,
},
attr.path().clone(),
@@ -1406,7 +1412,7 @@ impl DefCollector<'_> {
directive.module_id,
MacroCallKind::Derive {
ast_id: ast_id.ast_id,
- derive_attr_index: derive_attr.ast_index,
+ derive_attr_index: *derive_attr,
derive_index: *derive_pos as u32,
},
ast_id.path.clone(),
@@ -1599,17 +1605,15 @@ impl ModCollector<'_, '_> {
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
- if self.def_collector.is_proc_macro {
- if self.module_id == def_map.root {
- if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
- let crate_root = def_map.module_id(def_map.root);
- self.def_collector.export_proc_macro(
- proc_macro,
- ItemTreeId::new(self.tree_id, id),
- fn_id,
- crate_root,
- );
- }
+ if self.def_collector.is_proc_macro && self.module_id == def_map.root {
+ if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
+ let crate_root = def_map.module_id(def_map.root);
+ self.def_collector.export_proc_macro(
+ proc_macro,
+ ItemTreeId::new(self.tree_id, id),
+ fn_id,
+ crate_root,
+ );
}
}
@@ -1948,7 +1952,8 @@ impl ModCollector<'_, '_> {
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
Some(it) => {
// FIXME: a hacky way to create a Name from string.
- name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
+ name =
+ tt::Ident { text: it.clone(), span: tt::TokenId::unspecified() }.as_name();
&name
}
None => {
@@ -1983,11 +1988,13 @@ impl ModCollector<'_, '_> {
// Case 2: normal `macro_rules!` macro
MacroExpander::Declarative
};
+ let allow_internal_unsafe = attrs.by_key("allow_internal_unsafe").exists();
let macro_id = MacroRulesLoc {
container: module,
id: ItemTreeId::new(self.tree_id, id),
local_inner,
+ allow_internal_unsafe,
expander,
}
.intern(self.def_collector.db);
@@ -2047,10 +2054,15 @@ impl ModCollector<'_, '_> {
// Case 2: normal `macro`
MacroExpander::Declarative
};
+ let allow_internal_unsafe = attrs.by_key("allow_internal_unsafe").exists();
- let macro_id =
- Macro2Loc { container: module, id: ItemTreeId::new(self.tree_id, id), expander }
- .intern(self.def_collector.db);
+ let macro_id = Macro2Loc {
+ container: module,
+ id: ItemTreeId::new(self.tree_id, id),
+ expander,
+ allow_internal_unsafe,
+ }
+ .intern(self.def_collector.db);
self.def_collector.define_macro_def(
self.module_id,
mac.name.clone(),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 066142291..b024d7c67 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -2,12 +2,11 @@
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
-use hir_expand::MacroCallKind;
+use hir_expand::{attrs::AttrId, MacroCallKind};
use la_arena::Idx;
use syntax::ast::{self, AnyHasAttrs};
use crate::{
- attr::AttrId,
item_tree::{self, ItemTreeId},
nameres::LocalModuleId,
path::ModPath,
@@ -32,9 +31,9 @@ pub enum DefDiagnosticKind {
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
- InvalidDeriveTarget { ast: AstId<ast::Item>, id: u32 },
+ InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
- MalformedDerive { ast: AstId<ast::Adt>, id: u32 },
+ MalformedDerive { ast: AstId<ast::Adt>, id: usize },
}
#[derive(Debug, PartialEq, Eq)]
@@ -120,7 +119,7 @@ impl DefDiagnostic {
) -> Self {
Self {
in_module: container,
- kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index },
+ kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index() },
}
}
@@ -131,7 +130,7 @@ impl DefDiagnostic {
) -> Self {
Self {
in_module: container,
- kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index },
+ kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index() },
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index 4c263846d..51c565fe1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -7,7 +7,7 @@ use syntax::SmolStr;
use crate::{db::DefDatabase, HirFileId};
-const MOD_DEPTH_LIMIT: Limit = Limit::new(32);
+static MOD_DEPTH_LIMIT: Limit = Limit::new(32);
#[derive(Clone, Debug)]
pub(super) struct ModDir {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
index 06b23392c..caad4a1f3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs
@@ -1,9 +1,9 @@
//! Nameres-specific procedural macro data and helpers.
use hir_expand::name::{AsName, Name};
-use tt::{Leaf, TokenTree};
use crate::attr::Attrs;
+use crate::tt::{Leaf, TokenTree};
#[derive(Debug, PartialEq, Eq)]
pub struct ProcMacroDef {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 0d90047c2..8a27c60df 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -476,7 +476,7 @@ pub struct Bar;
fn no_std_prelude() {
check(
r#"
- //- /main.rs crate:main deps:core,std
+ //- /main.rs edition:2018 crate:main deps:core,std
#![cfg_attr(not(never), no_std)]
use Rust;
@@ -544,7 +544,7 @@ fn edition_specific_preludes() {
fn std_prelude_takes_precedence_above_core_prelude() {
check(
r#"
-//- /main.rs crate:main deps:core,std
+//- /main.rs edition:2018 crate:main deps:core,std
use {Foo, Bar};
//- /std.rs crate:std deps:core
@@ -574,7 +574,7 @@ pub mod prelude {
fn cfg_not_test() {
check(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
use {Foo, Bar, Baz};
//- /lib.rs crate:std
@@ -602,7 +602,7 @@ pub mod prelude {
fn cfg_test() {
check(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
use {Foo, Bar, Baz};
//- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index fe0ad4f38..a4ccd14cb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -264,7 +264,7 @@ fn prelude_is_macro_use() {
cov_mark::check!(prelude_is_macro_use);
check(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
structs!(Foo);
structs_priv!(Bar);
structs_outside!(Out);
@@ -634,7 +634,7 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
// From std
check(
r#"
-//- /main.rs crate:main deps:std
+//- /main.rs edition:2018 crate:main deps:std
foo!();
//- /std.rs crate:std deps:core
@@ -1034,7 +1034,7 @@ structs!(Foo);
fn macro_in_prelude() {
check(
r#"
-//- /lib.rs crate:lib deps:std
+//- /lib.rs edition:2018 crate:lib deps:std
global_asm!();
//- /std.rs crate:std
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 592223f7d..36d4c36a2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -8,10 +8,10 @@ use std::{
use crate::{
body::LowerCtx,
- intern::Interned,
type_ref::{ConstScalarOrPath, LifetimeRef},
};
use hir_expand::name::Name;
+use intern::Interned;
use syntax::ast;
use crate::type_ref::{TypeBound, TypeRef};
@@ -38,18 +38,18 @@ impl Display for ImportAlias {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
/// Type based path like `<T>::foo`.
- /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
+ /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
type_anchor: Option<Interned<TypeRef>>,
mod_path: Interned<ModPath>,
- /// Invariant: the same len as `self.mod_path.segments`
- generic_args: Box<[Option<Interned<GenericArgs>>]>,
+ /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
+ generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
}
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
- pub args: Vec<GenericArg>,
+ pub args: Box<[GenericArg]>,
/// This specifies whether the args contain a Self type as the first
/// element. This is the case for path segments like `<T as Trait>`, where
/// `T` is actually a type parameter for the path `Trait` specifying the
@@ -57,7 +57,7 @@ pub struct GenericArgs {
/// is left out.
pub has_self_type: bool,
/// Associated type bindings like in `Iterator<Item = T>`.
- pub bindings: Vec<AssociatedTypeBinding>,
+ pub bindings: Box<[AssociatedTypeBinding]>,
/// Whether these generic args were desugared from `Trait(Arg) -> Output`
/// parenthesis notation typically used for the `Fn` traits.
pub desugared_from_fn: bool,
@@ -77,7 +77,7 @@ pub struct AssociatedTypeBinding {
/// Bounds for the associated type, like in `Iterator<Item:
/// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
/// feature.)
- pub bounds: Vec<Interned<TypeBound>>,
+ pub bounds: Box<[Interned<TypeBound>]>,
}
/// A single generic argument.
@@ -102,7 +102,7 @@ impl Path {
) -> Path {
let generic_args = generic_args.into();
assert_eq!(path.len(), generic_args.len());
- Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
+ Path { type_anchor: None, mod_path: Interned::new(path), generic_args: Some(generic_args) }
}
pub fn kind(&self) -> &PathKind {
@@ -114,7 +114,14 @@ impl Path {
}
pub fn segments(&self) -> PathSegments<'_> {
- PathSegments { segments: self.mod_path.segments(), generic_args: &self.generic_args }
+ let s = PathSegments {
+ segments: self.mod_path.segments(),
+ generic_args: self.generic_args.as_deref(),
+ };
+ if let Some(generic_args) = s.generic_args {
+ assert_eq!(s.segments.len(), generic_args.len());
+ }
+ s
}
pub fn mod_path(&self) -> &ModPath {
@@ -131,13 +138,15 @@ impl Path {
self.mod_path.kind,
self.mod_path.segments()[..self.mod_path.segments().len() - 1].iter().cloned(),
)),
- generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec().into(),
+ generic_args: self.generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
};
Some(res)
}
pub fn is_self_type(&self) -> bool {
- self.type_anchor.is_none() && *self.generic_args == [None] && self.mod_path.is_Self()
+ self.type_anchor.is_none()
+ && self.generic_args.as_deref().is_none()
+ && self.mod_path.is_Self()
}
}
@@ -149,11 +158,11 @@ pub struct PathSegment<'a> {
pub struct PathSegments<'a> {
segments: &'a [Name],
- generic_args: &'a [Option<Interned<GenericArgs>>],
+ generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
}
impl<'a> PathSegments<'a> {
- pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
+ pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: None };
pub fn is_empty(&self) -> bool {
self.len() == 0
}
@@ -167,26 +176,29 @@ impl<'a> PathSegments<'a> {
self.get(self.len().checked_sub(1)?)
}
pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
- assert_eq!(self.segments.len(), self.generic_args.len());
let res = PathSegment {
name: self.segments.get(idx)?,
- args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
+ args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
};
Some(res)
}
pub fn skip(&self, len: usize) -> PathSegments<'a> {
- assert_eq!(self.segments.len(), self.generic_args.len());
- PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
+ PathSegments {
+ segments: &self.segments.get(len..).unwrap_or(&[]),
+ generic_args: self.generic_args.and_then(|it| it.get(len..)),
+ }
}
pub fn take(&self, len: usize) -> PathSegments<'a> {
- assert_eq!(self.segments.len(), self.generic_args.len());
- PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
+ PathSegments {
+ segments: &self.segments.get(..len).unwrap_or(&self.segments),
+ generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)),
+ }
}
pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
- self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
- name,
- args_and_bindings: args.as_ref().map(|it| &**it),
- })
+ self.segments
+ .iter()
+ .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
+ .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
}
}
@@ -200,9 +212,9 @@ impl GenericArgs {
pub(crate) fn empty() -> GenericArgs {
GenericArgs {
- args: Vec::new(),
+ args: Box::default(),
has_self_type: false,
- bindings: Vec::new(),
+ bindings: Box::default(),
desugared_from_fn: false,
}
}
@@ -213,7 +225,7 @@ impl From<Name> for Path {
Path {
type_anchor: None,
mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
- generic_args: Box::new([None]),
+ generic_args: None,
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index cfa3a6baa..c85a11db6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -1,9 +1,12 @@
//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
-use crate::{intern::Interned, type_ref::ConstScalarOrPath};
+use std::iter;
+
+use crate::type_ref::ConstScalarOrPath;
use either::Either;
use hir_expand::name::{name, AsName};
+use intern::Interned;
use syntax::ast::{self, AstNode, HasTypeBounds};
use super::AssociatedTypeBinding;
@@ -44,8 +47,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
)
})
.map(Interned::new);
+ if let Some(_) = args {
+ generic_args.resize(segments.len(), None);
+ generic_args.push(args);
+ }
segments.push(name);
- generic_args.push(args)
}
Either::Right(crate_id) => {
kind = PathKind::DollarCrate(crate_id);
@@ -55,7 +61,6 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
}
ast::PathSegmentKind::SelfTypeKw => {
segments.push(name![Self]);
- generic_args.push(None)
}
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
assert!(path.qualifier().is_none()); // this can only occur at the first segment
@@ -76,18 +81,33 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
kind = mod_path.kind;
segments.extend(mod_path.segments().iter().cloned().rev());
- generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
+ if let Some(path_generic_args) = path_generic_args {
+ generic_args.resize(segments.len() - num_segments, None);
+ generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
+ } else {
+ generic_args.resize(segments.len(), None);
+ }
+
+ let self_type = GenericArg::Type(self_type);
// Insert the type reference (T in the above example) as Self parameter for the trait
- let last_segment =
- generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
- let mut args_inner = match last_segment {
- Some(it) => it.as_ref().clone(),
- None => GenericArgs::empty(),
- };
- args_inner.has_self_type = true;
- args_inner.args.insert(0, GenericArg::Type(self_type));
- *last_segment = Some(Interned::new(args_inner));
+ let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
+ *last_segment = Some(Interned::new(match last_segment.take() {
+ Some(it) => GenericArgs {
+ args: iter::once(self_type)
+ .chain(it.args.iter().cloned())
+ .collect(),
+
+ has_self_type: true,
+ bindings: it.bindings.clone(),
+ desugared_from_fn: it.desugared_from_fn,
+ },
+ None => GenericArgs {
+ args: Box::new([self_type]),
+ has_self_type: true,
+ ..GenericArgs::empty()
+ },
+ }));
}
}
}
@@ -114,7 +134,10 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
};
}
segments.reverse();
- generic_args.reverse();
+ if !generic_args.is_empty() {
+ generic_args.resize(segments.len(), None);
+ generic_args.reverse();
+ }
if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() {
// plain empty paths don't exist, this means we got a single `self` segment as our path
@@ -134,7 +157,11 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option<Path
}
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
- return Some(Path { type_anchor, mod_path, generic_args: generic_args.into() });
+ return Some(Path {
+ type_anchor,
+ mod_path,
+ generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
+ });
fn qualifier(path: &ast::Path) -> Option<ast::Path> {
if let Some(q) = path.qualifier() {
@@ -173,7 +200,7 @@ pub(super) fn lower_generic_args(
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
.collect()
} else {
- Vec::new()
+ Box::default()
};
bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
}
@@ -194,7 +221,12 @@ pub(super) fn lower_generic_args(
if args.is_empty() && bindings.is_empty() {
return None;
}
- Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: false })
+ Some(GenericArgs {
+ args: args.into_boxed_slice(),
+ has_self_type: false,
+ bindings: bindings.into_boxed_slice(),
+ desugared_from_fn: false,
+ })
}
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
@@ -204,33 +236,30 @@ fn lower_generic_args_from_fn_path(
params: Option<ast::ParamList>,
ret_type: Option<ast::RetType>,
) -> Option<GenericArgs> {
- let mut args = Vec::new();
- let mut bindings = Vec::new();
let params = params?;
let mut param_types = Vec::new();
for param in params.params() {
let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
param_types.push(type_ref);
}
- let arg = GenericArg::Type(TypeRef::Tuple(param_types));
- args.push(arg);
- if let Some(ret_type) = ret_type {
+ let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
+ let bindings = if let Some(ret_type) = ret_type {
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
- bindings.push(AssociatedTypeBinding {
+ Box::new([AssociatedTypeBinding {
name: name![Output],
args: None,
type_ref: Some(type_ref),
- bounds: Vec::new(),
- });
+ bounds: Box::default(),
+ }])
} else {
// -> ()
let type_ref = TypeRef::Tuple(Vec::new());
- bindings.push(AssociatedTypeBinding {
+ Box::new([AssociatedTypeBinding {
name: name![Output],
args: None,
type_ref: Some(type_ref),
- bounds: Vec::new(),
- });
- }
+ bounds: Box::default(),
+ }])
+ };
Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: true })
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index befd0c5ff..2d45c8c8d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -3,10 +3,10 @@
use std::fmt::{self, Write};
use hir_expand::mod_path::PathKind;
+use intern::Interned;
use itertools::Itertools;
use crate::{
- intern::Interned,
path::{GenericArg, GenericArgs, Path},
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
};
@@ -71,7 +71,7 @@ pub(crate) fn print_generic_args(generics: &GenericArgs, buf: &mut dyn Write) ->
first = false;
print_generic_arg(arg, buf)?;
}
- for binding in &generics.bindings {
+ for binding in generics.bindings.iter() {
if !first {
write!(buf, ", ")?;
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 1ef7f9577..86958e3da 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -4,6 +4,7 @@ use std::{hash::BuildHasherDefault, sync::Arc};
use base_db::CrateId;
use hir_expand::name::{name, Name};
use indexmap::IndexMap;
+use intern::Interned;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
@@ -13,7 +14,6 @@ use crate::{
db::DefDatabase,
expr::{ExprId, LabelId, PatId},
generics::{GenericParams, TypeOrConstParamData},
- intern::Interned,
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
nameres::DefMap,
path::{ModPath, PathKind},
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs
index f8bb78ddc..9652b01b9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs
@@ -7,13 +7,13 @@ use hir_expand::{
name::{AsName, Name},
AstId,
};
+use intern::Interned;
use syntax::ast::{self, HasName};
use crate::{
body::LowerCtx,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
expr::Literal,
- intern::Interned,
path::Path,
};
@@ -240,7 +240,7 @@ impl TypeRef {
TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
}
ast::Type::MacroType(mt) => match mt.macro_call() {
- Some(mc) => ctx.ast_id(ctx.db, &mc).map(TypeRef::Macro).unwrap_or(TypeRef::Error),
+ Some(mc) => ctx.ast_id(&mc).map(TypeRef::Macro).unwrap_or(TypeRef::Error),
None => TypeRef::Error,
},
}
@@ -292,7 +292,7 @@ impl TypeRef {
}
for segment in path.segments().iter() {
if let Some(args_and_bindings) = segment.args_and_bindings {
- for arg in &args_and_bindings.args {
+ for arg in args_and_bindings.args.iter() {
match arg {
crate::path::GenericArg::Type(type_ref) => {
go(type_ref, f);
@@ -301,11 +301,11 @@ impl TypeRef {
| crate::path::GenericArg::Lifetime(_) => {}
}
}
- for binding in &args_and_bindings.bindings {
+ for binding in args_and_bindings.bindings.iter() {
if let Some(type_ref) = &binding.type_ref {
go(type_ref, f);
}
- for bound in &binding.bounds {
+ for bound in binding.bounds.iter() {
match bound.as_ref() {
TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
go_path(path, f)