diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:43 +0000 |
commit | 3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch) | |
tree | daf049b282ab10e8c3d03e409b3cd84ff3f7690c /src/tools/rust-analyzer/crates/hir-def | |
parent | Adding debian version 1.68.2+dfsg1-1. (diff) | |
download | rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip |
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
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, ¯o_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, ¯o_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, ¶m, self.hygiene())); + self.add_attrs(idx.into(), RawAttrs::new(self.db.upcast(), ¶m, 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 ¯o_ { 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) |