summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def/src')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs187
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs476
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs89
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs184
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs85
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs502
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs477
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs91
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs61
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs438
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs85
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs52
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs82
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs230
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/src.rs19
42 files changed, 2848 insertions, 985 deletions
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 fae071118..c6454eb9e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -5,7 +5,7 @@ pub mod builtin;
#[cfg(test)]
mod tests;
-use std::{hash::Hash, ops};
+use std::{hash::Hash, ops, slice::Iter as SliceIter};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
@@ -14,12 +14,11 @@ use hir_expand::{
attrs::{collect_attrs, Attr, AttrId, RawAttrs},
HirFileId, InFile,
};
-use itertools::Itertools;
use la_arena::{ArenaMap, Idx, RawIdx};
use mbe::DelimiterKind;
use syntax::{
- ast::{self, HasAttrs, IsString},
- AstPtr, AstToken, SmolStr, TextRange, TextSize,
+ ast::{self, HasAttrs},
+ AstPtr, SmolStr,
};
use triomphe::Arc;
@@ -33,26 +32,6 @@ use crate::{
LocalFieldId, Lookup, MacroId, VariantId,
};
-/// Holds documentation
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Documentation(String);
-
-impl Documentation {
- pub fn new(s: String) -> Self {
- Documentation(s)
- }
-
- pub fn as_str(&self) -> &str {
- &self.0
- }
-}
-
-impl From<Documentation> for String {
- fn from(Documentation(string): Documentation) -> Self {
- string
- }
-}
-
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Attrs(RawAttrs);
@@ -221,33 +200,6 @@ impl Attrs {
self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
}
- pub fn docs(&self) -> Option<Documentation> {
- let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value());
- let indent = doc_indent(self);
- let mut buf = String::new();
- for doc in docs {
- // str::lines doesn't yield anything for the empty string
- if !doc.is_empty() {
- buf.extend(Itertools::intersperse(
- doc.lines().map(|line| {
- line.char_indices()
- .nth(indent)
- .map_or(line, |(offset, _)| &line[offset..])
- .trim_end()
- }),
- "\n",
- ));
- }
- buf.push('\n');
- }
- buf.pop();
- if buf.is_empty() {
- None
- } else {
- Some(Documentation(buf))
- }
- }
-
pub fn has_doc_hidden(&self) -> bool {
self.by_key("doc").tt_values().any(|tt| {
tt.delimiter.kind == DelimiterKind::Parenthesis &&
@@ -299,7 +251,6 @@ impl Attrs {
}
}
-use std::slice::Iter as SliceIter;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum DocAtom {
/// eg. `#[doc(hidden)]`
@@ -313,7 +264,6 @@ pub enum DocAtom {
// Adapted from `CfgExpr` parsing code
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-// #[cfg_attr(test, derive(derive_arbitrary::Arbitrary))]
pub enum DocExpr {
Invalid,
/// eg. `#[doc(hidden)]`, `#[doc(alias = "x")]`
@@ -431,12 +381,10 @@ impl AttrsWithOwner {
.item_tree(db)
.raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
.clone(),
- ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner(
- db.upcast(),
- InFile::new(block.file_id, block.to_node(db.upcast()))
- .as_ref()
- .map(|it| it as &dyn ast::HasAttrs),
- ),
+ ModuleOrigin::BlockExpr { id, .. } => {
+ let tree = db.block_item_tree_query(id);
+ tree.raw_attrs(AttrOwner::TopLevel).clone()
+ }
}
}
AttrDefId::FieldId(it) => {
@@ -576,62 +524,6 @@ impl AttrsWithOwner {
AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
}
-
- pub fn docs_with_rangemap(
- &self,
- db: &dyn DefDatabase,
- ) -> Option<(Documentation, DocsRangeMap)> {
- let docs =
- self.by_key("doc").attrs().filter_map(|attr| attr.string_value().map(|s| (s, attr.id)));
- let indent = doc_indent(self);
- let mut buf = String::new();
- let mut mapping = Vec::new();
- for (doc, idx) in docs {
- if !doc.is_empty() {
- let mut base_offset = 0;
- for raw_line in doc.split('\n') {
- let line = raw_line.trim_end();
- let line_len = line.len();
- let (offset, line) = match line.char_indices().nth(indent) {
- Some((offset, _)) => (offset, &line[offset..]),
- None => (0, line),
- };
- let buf_offset = buf.len();
- buf.push_str(line);
- mapping.push((
- TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
- idx,
- TextRange::at(
- (base_offset + offset).try_into().ok()?,
- line_len.try_into().ok()?,
- ),
- ));
- buf.push('\n');
- base_offset += raw_line.len() + 1;
- }
- } else {
- buf.push('\n');
- }
- }
- buf.pop();
- if buf.is_empty() {
- None
- } else {
- Some((Documentation(buf), DocsRangeMap { mapping, source_map: self.source_map(db) }))
- }
- }
-}
-
-fn doc_indent(attrs: &Attrs) -> usize {
- attrs
- .by_key("doc")
- .attrs()
- .filter_map(|attr| attr.string_value())
- .flat_map(|s| s.lines())
- .filter(|line| !line.chars().all(|c| c.is_whitespace()))
- .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
- .min()
- .unwrap_or(0)
}
#[derive(Debug)]
@@ -675,7 +567,7 @@ impl AttrSourceMap {
self.source_of_id(attr.id)
}
- fn source_of_id(&self, id: AttrId) -> InFile<&Either<ast::Attr, ast::Comment>> {
+ pub fn source_of_id(&self, id: AttrId) -> InFile<&Either<ast::Attr, ast::Comment>> {
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,
@@ -689,69 +581,6 @@ impl AttrSourceMap {
}
}
-/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
-#[derive(Debug)]
-pub struct DocsRangeMap {
- source_map: AttrSourceMap,
- // (docstring-line-range, attr_index, attr-string-range)
- // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
- // the original (untrimmed) syntax doc line
- mapping: Vec<(TextRange, AttrId, TextRange)>,
-}
-
-impl DocsRangeMap {
- /// Maps a [`TextRange`] relative to the documentation string back to its AST range
- pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
- let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
- let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
- if !line_docs_range.contains_range(range) {
- return None;
- }
-
- let relative_range = range - line_docs_range.start();
-
- let InFile { file_id, value: source } = self.source_map.source_of_id(idx);
- match source {
- Either::Left(attr) => {
- let string = get_doc_string_in_attr(attr)?;
- let text_range = string.open_quote_text_range()?;
- let range = TextRange::at(
- text_range.end() + original_line_src_range.start() + relative_range.start(),
- string.syntax().text_range().len().min(range.len()),
- );
- Some(InFile { file_id, value: range })
- }
- Either::Right(comment) => {
- let text_range = comment.syntax().text_range();
- let range = TextRange::at(
- text_range.start()
- + TextSize::try_from(comment.prefix().len()).ok()?
- + original_line_src_range.start()
- + relative_range.start(),
- text_range.len().min(range.len()),
- );
- Some(InFile { file_id, value: range })
- }
- }
- }
-}
-
-fn get_doc_string_in_attr(it: &ast::Attr) -> Option<ast::String> {
- match it.expr() {
- // #[doc = lit]
- Some(ast::Expr::Literal(lit)) => match lit.kind() {
- ast::LiteralKind::String(it) => Some(it),
- _ => None,
- },
- // #[cfg_attr(..., doc = "", ...)]
- None => {
- // FIXME: See highlight injection for what to do here
- None
- }
- _ => None,
- }
-}
-
#[derive(Debug, Clone, Copy)]
pub struct AttrQuery<'attr> {
attrs: &'attr Attrs,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index cead64a33..152f05b2c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -8,7 +8,8 @@
//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
//! ease updating.
-use once_cell::sync::OnceCell;
+use std::sync::OnceLock;
+
use rustc_hash::FxHashMap;
/// Ignored attribute namespaces used by tools.
@@ -29,7 +30,7 @@ pub struct AttributeTemplate {
}
pub fn find_builtin_attr_idx(name: &str) -> Option<usize> {
- static BUILTIN_LOOKUP_TABLE: OnceCell<FxHashMap<&'static str, usize>> = OnceCell::new();
+ static BUILTIN_LOOKUP_TABLE: OnceLock<FxHashMap<&'static str, usize>> = OnceLock::new();
BUILTIN_LOOKUP_TABLE
.get_or_init(|| {
INERT_ATTRIBUTES.iter().map(|attr| attr.name).enumerate().map(|(a, b)| (b, a)).collect()
@@ -239,7 +240,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
experimental!(no_sanitize)
),
- gated!(no_coverage, Normal, template!(Word), WarnFollowing, experimental!(no_coverage)),
+ gated!(coverage, Normal, template!(Word, List: "on|off"), WarnFollowing, experimental!(coverage)),
ungated!(
doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
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 f8d492d0e..c0baf6011 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -65,6 +65,8 @@ pub type LabelSource = InFile<LabelPtr>;
pub type FieldPtr = AstPtr<ast::RecordExprField>;
pub type FieldSource = InFile<FieldPtr>;
+pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
+pub type PatFieldSource = InFile<PatFieldPtr>;
/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
@@ -90,8 +92,8 @@ pub struct BodySourceMap {
/// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
/// Instead, we use id of expression (`92`) to identify the field.
- field_map: FxHashMap<FieldSource, ExprId>,
field_map_back: FxHashMap<ExprId, FieldSource>,
+ pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
@@ -164,9 +166,10 @@ impl Body {
};
let module = def.module(db);
let expander = Expander::new(db, file_id, module);
- let (mut body, source_map) =
+ let (mut body, mut source_map) =
Body::new(db, def, expander, params, body, module.krate, is_async_fn);
body.shrink_to_fit();
+ source_map.shrink_to_fit();
(Arc::new(body), Arc::new(source_map))
}
@@ -375,9 +378,8 @@ impl BodySourceMap {
self.field_map_back[&expr].clone()
}
- pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
- let src = node.map(AstPtr::new);
- self.field_map.get(&src).cloned()
+ pub fn pat_field_syntax(&self, pat: PatId) -> PatFieldSource {
+ self.pat_field_map_back[&pat].clone()
}
pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
@@ -389,4 +391,29 @@ impl BodySourceMap {
pub fn diagnostics(&self) -> &[BodyDiagnostic] {
&self.diagnostics
}
+
+ fn shrink_to_fit(&mut self) {
+ let Self {
+ expr_map,
+ expr_map_back,
+ pat_map,
+ pat_map_back,
+ label_map,
+ label_map_back,
+ field_map_back,
+ pat_field_map_back,
+ expansions,
+ diagnostics,
+ } = self;
+ expr_map.shrink_to_fit();
+ expr_map_back.shrink_to_fit();
+ pat_map.shrink_to_fit();
+ pat_map_back.shrink_to_fit();
+ label_map.shrink_to_fit();
+ label_map_back.shrink_to_fit();
+ field_map_back.shrink_to_fit();
+ pat_field_map_back.shrink_to_fit();
+ expansions.shrink_to_fit();
+ diagnostics.shrink_to_fit();
+ }
}
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 3853a6ab3..cc02df80a 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
@@ -25,13 +25,20 @@ use triomphe::Arc;
use crate::{
body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
+ builtin_type::BuiltinUint,
data::adt::StructKind,
db::DefDatabase,
expander::Expander,
hir::{
- dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
- ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
- Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+ dummy_expr_id,
+ format_args::{
+ self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
+ FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
+ FormatPlaceholder, FormatSign, FormatTrait,
+ },
+ Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
+ Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
+ OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
@@ -42,6 +49,8 @@ use crate::{
AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
};
+type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
+
pub(super) fn lower(
db: &dyn DefDatabase,
owner: DefWithBodyId,
@@ -437,7 +446,6 @@ impl ExprCollector<'_> {
None => self.missing_expr(),
};
let src = self.expander.to_source(AstPtr::new(&field));
- self.source_map.field_map.insert(src.clone(), expr);
self.source_map.field_map_back.insert(expr, src);
Some(RecordLitField { name, expr })
})
@@ -505,6 +513,9 @@ impl ExprCollector<'_> {
let mut args = Vec::new();
let mut arg_types = Vec::new();
if let Some(pl) = e.param_list() {
+ let num_params = pl.params().count();
+ args.reserve_exact(num_params);
+ arg_types.reserve_exact(num_params);
for param in pl.params() {
let pat = this.collect_pat_top(param.pat());
let type_ref =
@@ -576,11 +587,6 @@ impl ExprCollector<'_> {
syntax_ptr,
)
}
- ast::Expr::BoxExpr(e) => {
- let expr = self.collect_expr_opt(e.expr());
- self.alloc_expr(Expr::Box { expr }, syntax_ptr)
- }
-
ast::Expr::ArrayExpr(e) => {
let kind = e.kind();
@@ -650,6 +656,16 @@ impl ExprCollector<'_> {
}
}
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
+ ast::Expr::AsmExpr(e) => {
+ let e = self.collect_expr_opt(e.expr());
+ self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr)
+ }
+ ast::Expr::OffsetOfExpr(e) => {
+ let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+ let fields = e.fields().map(|it| it.as_name()).collect();
+ self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
+ }
+ ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),
})
}
@@ -660,6 +676,7 @@ impl ExprCollector<'_> {
let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
let prev_binding_owner = self.current_binding_owner.take();
self.current_binding_owner = Some(result_expr_id);
+
(result_expr_id, prev_binding_owner)
}
@@ -741,7 +758,27 @@ impl ExprCollector<'_> {
fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
let label = e.label().map(|label| self.collect_label(label));
let body = self.collect_labelled_block_opt(label, e.loop_body());
- let condition = self.collect_expr_opt(e.condition());
+
+ // Labels can also be used in the condition expression, like this:
+ // ```
+ // fn main() {
+ // let mut optional = Some(0);
+ // 'my_label: while let Some(a) = match optional {
+ // None => break 'my_label,
+ // Some(val) => Some(val),
+ // } {
+ // println!("{}", a);
+ // optional = None;
+ // }
+ // }
+ // ```
+ let condition = match label {
+ Some(label) => {
+ self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
+ }
+ None => self.collect_expr_opt(e.condition()),
+ };
+
let break_expr =
self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone());
let if_expr = self.alloc_expr(
@@ -1100,7 +1137,9 @@ impl ExprCollector<'_> {
ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
_ => false,
});
- statement_has_item || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
+ statement_has_item
+ || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
+ || (block.may_carry_attributes() && block.attrs().next().is_some())
};
let block_id = if block_has_items {
@@ -1290,23 +1329,21 @@ impl ExprCollector<'_> {
ast::Pat::RecordPat(p) => {
let path =
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
- let args = p
- .record_pat_field_list()
- .expect("every struct should have a field list")
+ let record_pat_field_list =
+ &p.record_pat_field_list().expect("every struct should have a field list");
+ let args = record_pat_field_list
.fields()
.filter_map(|f| {
let ast_pat = f.pat()?;
let pat = self.collect_pat(ast_pat, binding_list);
let name = f.field_name()?.as_name();
+ let src = self.expander.to_source(AstPtr::new(&f));
+ self.source_map.pat_field_map_back.insert(pat, src);
Some(RecordFieldPat { name, pat })
})
.collect();
- let ellipsis = p
- .record_pat_field_list()
- .expect("every struct should have a field list")
- .rest_pat()
- .is_some();
+ let ellipsis = record_pat_field_list.rest_pat().is_some();
Pat::Record { path, args, ellipsis }
}
@@ -1526,6 +1563,401 @@ impl ExprCollector<'_> {
}
}
// endregion: labels
+
+ // region: format
+ fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
+ let m = match expr {
+ ast::Expr::MacroExpr(m) => m,
+ ast::Expr::Literal(l) => {
+ return match l.kind() {
+ ast::LiteralKind::String(s) => Some((s, true)),
+ _ => None,
+ }
+ }
+ _ => return None,
+ };
+ let e = m.macro_call()?;
+ let macro_ptr = AstPtr::new(&e);
+ let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+ expansion.and_then(|it| this.expand_macros_to_string(it))
+ })?;
+ Some((exp, false))
+ }
+
+ fn collect_format_args(
+ &mut self,
+ f: ast::FormatArgsExpr,
+ syntax_ptr: AstPtr<ast::Expr>,
+ ) -> ExprId {
+ let mut args = FormatArgumentsCollector::new();
+ f.args().for_each(|arg| {
+ args.add(FormatArgument {
+ kind: match arg.name() {
+ Some(name) => FormatArgumentKind::Named(name.as_name()),
+ None => FormatArgumentKind::Normal,
+ },
+ expr: self.collect_expr_opt(arg.expr()),
+ });
+ });
+ let template = f.template();
+ let fmt_snippet = template.as_ref().map(ToString::to_string);
+ let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
+ Some((s, is_direct_literal)) => {
+ format_args::parse(&s, fmt_snippet, args, is_direct_literal, |name| {
+ self.alloc_expr_desugared(Expr::Path(Path::from(name)))
+ })
+ }
+ None => FormatArgs { template: Default::default(), arguments: args.finish() },
+ };
+
+ // Create a list of all _unique_ (argument, format trait) combinations.
+ // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+ let mut argmap = FxIndexSet::default();
+ for piece in fmt.template.iter() {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+ if let Ok(index) = placeholder.argument.index {
+ argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
+ }
+ }
+
+ let lit_pieces =
+ fmt.template
+ .iter()
+ .enumerate()
+ .filter_map(|(i, piece)| {
+ match piece {
+ FormatArgsPiece::Literal(s) => Some(
+ self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))),
+ ),
+ &FormatArgsPiece::Placeholder(_) => {
+ // Inject empty string before placeholders when not already preceded by a literal piece.
+ if i == 0
+ || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
+ {
+ Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
+ "".into(),
+ ))))
+ } else {
+ None
+ }
+ }
+ }
+ })
+ .collect();
+ let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements: lit_pieces,
+ is_assignee_expr: false,
+ }));
+ let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
+ expr: lit_pieces,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ let format_options = {
+ // Generate:
+ // &[format_spec_0, format_spec_1, format_spec_2]
+ let elements = fmt
+ .template
+ .iter()
+ .filter_map(|piece| {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+ Some(self.make_format_spec(placeholder, &mut argmap))
+ })
+ .collect();
+ let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements,
+ is_assignee_expr: false,
+ }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: array,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ };
+ let arguments = &*fmt.arguments.arguments;
+
+ let args = if arguments.is_empty() {
+ let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements: Box::default(),
+ is_assignee_expr: false,
+ }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ } else {
+ // Generate:
+ // &match (&arg0, &arg1, &…) {
+ // args => [
+ // <core::fmt::Argument>::new_display(args.0),
+ // <core::fmt::Argument>::new_lower_hex(args.1),
+ // <core::fmt::Argument>::new_debug(args.0),
+ // …
+ // ]
+ // }
+ let args = argmap
+ .iter()
+ .map(|&(arg_index, ty)| {
+ let arg = self.alloc_expr_desugared(Expr::Ref {
+ expr: arguments[arg_index].expr,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ });
+ self.make_argument(arg, ty)
+ })
+ .collect();
+ let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
+ elements: args,
+ is_assignee_expr: false,
+ }));
+ self.alloc_expr_desugared(Expr::Ref {
+ expr: array,
+ rawness: Rawness::Ref,
+ mutability: Mutability::Shared,
+ })
+ };
+
+ // Generate:
+ // <core::fmt::Arguments>::new_v1_formatted(
+ // lit_pieces,
+ // args,
+ // format_options,
+ // unsafe { ::core::fmt::UnsafeArg::new() }
+ // )
+
+ let Some(new_v1_formatted) =
+ LangItem::FormatArguments.ty_rel_path(self.db, self.krate, name![new_v1_formatted])
+ else {
+ return self.missing_expr();
+ };
+ let Some(unsafe_arg_new) =
+ LangItem::FormatUnsafeArg.ty_rel_path(self.db, self.krate, name![new])
+ else {
+ return self.missing_expr();
+ };
+ let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
+
+ let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
+ let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
+ callee: unsafe_arg_new,
+ args: Box::default(),
+ is_assignee_expr: false,
+ });
+ let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
+ id: None,
+ statements: Box::default(),
+ tail: Some(unsafe_arg_new),
+ });
+
+ self.alloc_expr(
+ Expr::Call {
+ callee: new_v1_formatted,
+ args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
+ is_assignee_expr: false,
+ },
+ syntax_ptr,
+ )
+ }
+
+ /// Generate a hir expression for a format_args placeholder specification.
+ ///
+ /// Generates
+ ///
+ /// ```text
+ /// <core::fmt::rt::Placeholder::new(
+ /// …usize, // position
+ /// '…', // fill
+ /// <core::fmt::rt::Alignment>::…, // alignment
+ /// …u32, // flags
+ /// <core::fmt::rt::Count::…>, // width
+ /// <core::fmt::rt::Count::…>, // precision
+ /// )
+ /// ```
+ fn make_format_spec(
+ &mut self,
+ placeholder: &FormatPlaceholder,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ ) -> ExprId {
+ let position = match placeholder.argument.index {
+ Ok(arg_index) => {
+ let (i, _) =
+ argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+ self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ i as u128,
+ Some(BuiltinUint::Usize),
+ )))
+ }
+ Err(_) => self.missing_expr(),
+ };
+ let &FormatOptions {
+ ref width,
+ ref precision,
+ alignment,
+ fill,
+ sign,
+ alternate,
+ zero_pad,
+ debug_hex,
+ } = &placeholder.format_options;
+ let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
+
+ let align = {
+ let align = LangItem::FormatAlignment.ty_rel_path(
+ self.db,
+ self.krate,
+ match alignment {
+ Some(FormatAlignment::Left) => name![Left],
+ Some(FormatAlignment::Right) => name![Right],
+ Some(FormatAlignment::Center) => name![Center],
+ None => name![Unknown],
+ },
+ );
+ match align {
+ Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+ None => self.missing_expr(),
+ }
+ };
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
+ let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+ | ((sign == Some(FormatSign::Minus)) as u32) << 1
+ | (alternate as u32) << 2
+ | (zero_pad as u32) << 3
+ | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
+ | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
+ let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ flags as u128,
+ Some(BuiltinUint::U32),
+ )));
+ let precision = self.make_count(&precision, argmap);
+ let width = self.make_count(&width, argmap);
+
+ let format_placeholder_new = {
+ let format_placeholder_new =
+ LangItem::FormatPlaceholder.ty_rel_path(self.db, self.krate, name![new]);
+ match format_placeholder_new {
+ Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
+ None => self.missing_expr(),
+ }
+ };
+
+ self.alloc_expr_desugared(Expr::Call {
+ callee: format_placeholder_new,
+ args: Box::new([position, fill, align, flags, precision, width]),
+ is_assignee_expr: false,
+ })
+ }
+
+ /// Generate a hir expression for a format_args Count.
+ ///
+ /// Generates:
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Is(…)
+ /// ```
+ ///
+ /// or
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Param(…)
+ /// ```
+ ///
+ /// or
+ ///
+ /// ```text
+ /// <core::fmt::rt::Count>::Implied
+ /// ```
+ fn make_count(
+ &mut self,
+ count: &Option<FormatCount>,
+ argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ ) -> ExprId {
+ match count {
+ Some(FormatCount::Literal(n)) => {
+ match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
+ Some(count_is) => {
+ let count_is = self.alloc_expr_desugared(Expr::Path(count_is));
+ let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ *n as u128,
+ Some(BuiltinUint::Usize),
+ )));
+ self.alloc_expr_desugared(Expr::Call {
+ callee: count_is,
+ args: Box::new([args]),
+ is_assignee_expr: false,
+ })
+ }
+ None => self.missing_expr(),
+ }
+ }
+ Some(FormatCount::Argument(arg)) => {
+ if let Ok(arg_index) = arg.index {
+ let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+
+ match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) {
+ Some(count_param) => {
+ let count_param = self.alloc_expr_desugared(Expr::Path(count_param));
+ let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+ i as u128,
+ Some(BuiltinUint::Usize),
+ )));
+ self.alloc_expr_desugared(Expr::Call {
+ callee: count_param,
+ args: Box::new([args]),
+ is_assignee_expr: false,
+ })
+ }
+ None => self.missing_expr(),
+ }
+ } else {
+ self.missing_expr()
+ }
+ }
+ None => match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Implied]) {
+ Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
+ None => self.missing_expr(),
+ },
+ }
+ }
+
+ /// Generate a hir expression representing an argument to a format_args invocation.
+ ///
+ /// Generates:
+ ///
+ /// ```text
+ /// <core::fmt::Argument>::new_…(arg)
+ /// ```
+ fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
+ use ArgumentType::*;
+ use FormatTrait::*;
+ match LangItem::FormatArgument.ty_rel_path(
+ self.db,
+ self.krate,
+ match ty {
+ Format(Display) => name![new_display],
+ Format(Debug) => name![new_debug],
+ Format(LowerExp) => name![new_lower_exp],
+ Format(UpperExp) => name![new_upper_exp],
+ Format(Octal) => name![new_octal],
+ Format(Pointer) => name![new_pointer],
+ Format(Binary) => name![new_binary],
+ Format(LowerHex) => name![new_lower_hex],
+ Format(UpperHex) => name![new_upper_hex],
+ Usize => name![from_usize],
+ },
+ ) {
+ Some(new_fn) => {
+ let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn));
+ self.alloc_expr_desugared(Expr::Call {
+ callee: new_fn,
+ args: Box::new([arg]),
+ is_assignee_expr: false,
+ })
+ }
+ None => self.missing_expr(),
+ }
+ }
+ // endregion: format
}
fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
@@ -1601,3 +2033,9 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
(|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
.map_or(false, |it| it.kind() == syntax::T![,])
}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+ Format(FormatTrait),
+ Usize,
+}
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 5d71abe37..fad4d7a4d 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
@@ -2,7 +2,7 @@
use std::fmt::{self, Write};
-use hir_expand::db::ExpandDatabase;
+use itertools::Itertools;
use syntax::ast::HasName;
use crate::{
@@ -51,8 +51,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
}
};
- let mut p =
- Printer { db: db.upcast(), body, buf: header, indent_level: 0, needs_indent: false };
+ let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('(');
body.params.iter().zip(&db.function_data(it).params).for_each(|(&param, ty)| {
@@ -76,8 +75,7 @@ pub(super) fn print_expr_hir(
_owner: DefWithBodyId,
expr: ExprId,
) -> String {
- let mut p =
- Printer { db: db.upcast(), body, buf: String::new(), indent_level: 0, needs_indent: false };
+ let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false };
p.print_expr(expr);
p.buf
}
@@ -98,7 +96,7 @@ macro_rules! wln {
}
struct Printer<'a> {
- db: &'a dyn ExpandDatabase,
+ db: &'a dyn DefDatabase,
body: &'a Body,
buf: String,
indent_level: usize,
@@ -142,9 +140,14 @@ impl Printer<'_> {
}
fn newline(&mut self) {
- match self.buf.chars().rev().find(|ch| *ch != ' ') {
- Some('\n') | None => {}
- _ => writeln!(self).unwrap(),
+ match self.buf.chars().rev().find_position(|ch| *ch != ' ') {
+ Some((_, '\n')) | None => {}
+ Some((idx, _)) => {
+ if idx != 0 {
+ self.buf.drain(self.buf.len() - idx..);
+ }
+ writeln!(self).unwrap()
+ }
}
}
@@ -154,6 +157,19 @@ impl Printer<'_> {
match expr {
Expr::Missing => w!(self, "�"),
Expr::Underscore => w!(self, "_"),
+ Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
+ Expr::OffsetOf(offset_of) => {
+ w!(self, "builtin#offset_of(");
+ self.print_type_ref(&offset_of.container);
+ w!(
+ self,
+ ", {})",
+ offset_of
+ .fields
+ .iter()
+ .format_with(".", |field, f| f(&field.display(self.db.upcast())))
+ );
+ }
Expr::Path(path) => self.print_path(path),
Expr::If { condition, then_branch, else_branch } => {
w!(self, "if ");
@@ -173,7 +189,7 @@ impl Printer<'_> {
}
Expr::Loop { body, label } => {
if let Some(lbl) = label {
- w!(self, "{}: ", self.body[*lbl].name.display(self.db));
+ w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast()));
}
w!(self, "loop ");
self.print_expr(*body);
@@ -193,7 +209,7 @@ impl Printer<'_> {
}
Expr::MethodCall { receiver, method_name, args, generic_args } => {
self.print_expr(*receiver);
- w!(self, ".{}", method_name.display(self.db));
+ w!(self, ".{}", method_name.display(self.db.upcast()));
if let Some(args) = generic_args {
w!(self, "::<");
print_generic_args(self.db, args, self).unwrap();
@@ -231,13 +247,13 @@ impl Printer<'_> {
Expr::Continue { label } => {
w!(self, "continue");
if let Some(lbl) = label {
- w!(self, " {}", self.body[*lbl].name.display(self.db));
+ w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
}
}
Expr::Break { expr, label } => {
w!(self, "break");
if let Some(lbl) = label {
- w!(self, " {}", self.body[*lbl].name.display(self.db));
+ w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
}
if let Some(expr) = expr {
self.whitespace();
@@ -276,7 +292,7 @@ impl Printer<'_> {
w!(self, "{{");
self.indented(|p| {
for field in &**fields {
- w!(p, "{}: ", field.name.display(self.db));
+ w!(p, "{}: ", field.name.display(self.db.upcast()));
p.print_expr(field.expr);
wln!(p, ",");
}
@@ -293,7 +309,7 @@ impl Printer<'_> {
}
Expr::Field { expr, name } => {
self.print_expr(*expr);
- w!(self, ".{}", name.display(self.db));
+ w!(self, ".{}", name.display(self.db.upcast()));
}
Expr::Await { expr } => {
self.print_expr(*expr);
@@ -431,7 +447,8 @@ impl Printer<'_> {
}
Expr::Literal(lit) => self.print_literal(lit),
Expr::Block { id: _, statements, tail, label } => {
- let label = label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db)));
+ let label =
+ label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast())));
self.print_block(label.as_deref(), statements, tail);
}
Expr::Unsafe { id: _, statements, tail } => {
@@ -507,7 +524,7 @@ impl Printer<'_> {
w!(self, " {{");
self.indented(|p| {
for arg in args.iter() {
- w!(p, "{}: ", arg.name.display(self.db));
+ w!(p, "{}: ", arg.name.display(self.db.upcast()));
p.print_pat(arg.pat);
wln!(p, ",");
}
@@ -666,6 +683,6 @@ impl Printer<'_> {
BindingAnnotation::Ref => "ref ",
BindingAnnotation::RefMut => "ref mut ",
};
- w!(self, "{}{}", mode, name.display(self.db));
+ w!(self, "{}{}", mode, name.display(self.db.upcast()));
}
}
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 d55820116..1658757d2 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
@@ -1,13 +1,13 @@
mod block;
use base_db::{fixture::WithFixture, SourceDatabase};
-use expect_test::Expect;
+use expect_test::{expect, Expect};
use crate::{test_db::TestDB, ModuleDefId};
use super::*;
-fn lower(ra_fixture: &str) -> Arc<Body> {
+fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
let db = TestDB::with_files(ra_fixture);
let krate = db.crate_graph().iter().next().unwrap();
@@ -21,8 +21,10 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
}
}
}
+ let fn_def = fn_def.unwrap().into();
- db.body(fn_def.unwrap().into())
+ let body = db.body(fn_def);
+ (db, body, fn_def)
}
fn def_map_at(ra_fixture: &str) -> String {
@@ -138,3 +140,84 @@ mod m {
"#,
);
}
+
+#[test]
+fn desugar_builtin_format_args() {
+ // Regression test for a path resolution bug introduced with inner item handling.
+ let (db, body, def) = lower(
+ r#"
+//- minicore: fmt
+fn main() {
+ let are = "are";
+ let count = 10;
+ builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
+}
+"#,
+ );
+
+ expect![[r#"
+ fn main() {
+ let are = "are";
+ let count = 10;
+ builtin#lang(Arguments::new_v1_formatted)(
+ &[
+ "\"hello ", " ", " friends, we ", " ", "", "\"",
+ ],
+ &[
+ builtin#lang(Argument::new_display)(
+ &count,
+ ), builtin#lang(Argument::new_display)(
+ &"fancy",
+ ), builtin#lang(Argument::new_debug)(
+ &are,
+ ), builtin#lang(Argument::new_display)(
+ &"!",
+ ),
+ ],
+ &[
+ builtin#lang(Placeholder::new)(
+ 0usize,
+ ' ',
+ builtin#lang(Alignment::Unknown),
+ 8u32,
+ builtin#lang(Count::Implied),
+ builtin#lang(Count::Is)(
+ 2usize,
+ ),
+ ), builtin#lang(Placeholder::new)(
+ 1usize,
+ ' ',
+ builtin#lang(Alignment::Unknown),
+ 0u32,
+ builtin#lang(Count::Implied),
+ builtin#lang(Count::Implied),
+ ), builtin#lang(Placeholder::new)(
+ 2usize,
+ ' ',
+ builtin#lang(Alignment::Unknown),
+ 0u32,
+ builtin#lang(Count::Implied),
+ builtin#lang(Count::Implied),
+ ), builtin#lang(Placeholder::new)(
+ 1usize,
+ ' ',
+ builtin#lang(Alignment::Unknown),
+ 0u32,
+ builtin#lang(Count::Implied),
+ builtin#lang(Count::Implied),
+ ), builtin#lang(Placeholder::new)(
+ 3usize,
+ ' ',
+ builtin#lang(Alignment::Unknown),
+ 0u32,
+ builtin#lang(Count::Implied),
+ builtin#lang(Count::Implied),
+ ),
+ ],
+ unsafe {
+ builtin#lang(UnsafeArg::new)()
+ },
+ );
+ }"#]]
+ .assert_eq(&body.pretty_print(&db, def))
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
index 4e015a7fb..44eeed9e3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
@@ -38,9 +38,9 @@ fn outer() {
"#,
expect![[r#"
block scope
- CrateStruct: t
- PlainStruct: t v
- SelfStruct: t
+ CrateStruct: ti
+ PlainStruct: ti vi
+ SelfStruct: ti
Struct: v
SuperStruct: _
@@ -66,7 +66,7 @@ fn outer() {
"#,
expect![[r#"
block scope
- imported: t v
+ imported: ti vi
name: v
crate
@@ -92,9 +92,9 @@ fn outer() {
"#,
expect![[r#"
block scope
- inner1: t
+ inner1: ti
inner2: v
- outer: v
+ outer: vi
block scope
inner: v
@@ -121,7 +121,7 @@ struct Struct {}
"#,
expect![[r#"
block scope
- Struct: t
+ Struct: ti
crate
Struct: t
@@ -153,7 +153,7 @@ fn outer() {
"#,
expect![[r#"
block scope
- ResolveMe: t
+ ResolveMe: ti
block scope
m2: t
@@ -214,7 +214,7 @@ fn f() {
"#,
expect![[r#"
block scope
- ResolveMe: t
+ ResolveMe: ti
block scope
h: v
@@ -292,7 +292,7 @@ pub mod cov_mark {
nested: v
crate
- cov_mark: t
+ cov_mark: ti
f: v
"#]],
);
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 91db68058..68defa385 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -487,7 +487,7 @@ impl ExternCrateDeclData {
db.crate_def_map(loc.container.krate())
.extern_prelude()
.find(|&(prelude_name, ..)| *prelude_name == name)
- .map(|(_, root)| root.krate())
+ .map(|(_, (root, _))| root.krate())
};
Arc::new(Self {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index c8df3f3f9..224f7328f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -447,6 +447,7 @@ impl VariantData {
}
}
+ // FIXME: Linear lookup
pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
}
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 e34a6768f..31c1a7130 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -82,6 +82,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(ItemTree::file_item_tree_query)]
fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
+ #[salsa::invoke(ItemTree::block_item_tree_query)]
+ fn block_item_tree_query(&self, block_id: BlockId) -> Arc<ItemTree>;
+
#[salsa::invoke(crate_def_map_wait)]
#[salsa::transparent]
fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
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 df2af4c89..b9c5ff727 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
@@ -11,7 +11,7 @@ use crate::{
nameres::DefMap,
path::{ModPath, PathKind},
visibility::Visibility,
- ModuleDefId, ModuleId,
+ CrateRootModuleId, ModuleDefId, ModuleId,
};
/// Find a path that can be used to refer to a certain item. This can depend on
@@ -37,6 +37,20 @@ pub fn find_path_prefixed(
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
}
+#[derive(Copy, Clone, Debug)]
+enum Stability {
+ Unstable,
+ Stable,
+}
+use Stability::*;
+
+fn zip_stability(a: Stability, b: Stability) -> Stability {
+ match (a, b) {
+ (Stable, Stable) => Stable,
+ _ => Unstable,
+ }
+}
+
const MAX_PATH_LEN: usize = 15;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -81,7 +95,7 @@ fn find_path_inner(
}
let def_map = from.def_map(db);
- let crate_root = def_map.crate_root().into();
+ let crate_root = def_map.crate_root();
// - if the item is a module, jump straight to module search
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
let mut visited_modules = FxHashSet::default();
@@ -95,7 +109,8 @@ fn find_path_inner(
MAX_PATH_LEN,
prefixed,
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
- );
+ )
+ .map(|(item, _)| item);
}
// - if the item is already in scope, return the name under which it is
@@ -143,19 +158,20 @@ fn find_path_inner(
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
scope_name,
)
+ .map(|(item, _)| item)
}
fn find_path_for_module(
db: &dyn DefDatabase,
def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>,
- crate_root: ModuleId,
+ crate_root: CrateRootModuleId,
from: ModuleId,
module_id: ModuleId,
max_len: usize,
prefixed: Option<PrefixKind>,
prefer_no_std: bool,
-) -> Option<ModPath> {
+) -> Option<(ModPath, Stability)> {
if max_len == 0 {
return None;
}
@@ -165,25 +181,25 @@ fn find_path_for_module(
let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
if prefixed.is_none() {
if let Some(scope_name) = scope_name {
- return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
+ return Some((ModPath::from_segments(PathKind::Plain, Some(scope_name)), Stable));
}
}
// - if the item is the crate root, return `crate`
if module_id == crate_root {
- return Some(ModPath::from_segments(PathKind::Crate, None));
+ return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
}
// - if relative paths are fine, check if we are searching for a parent
if prefixed.filter(PrefixKind::is_absolute).is_none() {
if let modpath @ Some(_) = find_self_super(def_map, module_id, from) {
- return modpath;
+ return modpath.zip(Some(Stable));
}
}
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
let root_def_map = crate_root.def_map(db);
- for (name, def_id) in root_def_map.extern_prelude() {
+ for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude() {
if module_id == def_id {
let name = scope_name.unwrap_or_else(|| name.clone());
@@ -192,7 +208,7 @@ fn find_path_for_module(
def_map[local_id]
.scope
.type_(&name)
- .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
+ .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into()))
})
.is_some();
let kind = if name_already_occupied_in_type_ns {
@@ -201,14 +217,14 @@ fn find_path_for_module(
} else {
PathKind::Plain
};
- return Some(ModPath::from_segments(kind, Some(name)));
+ return Some((ModPath::from_segments(kind, Some(name)), Stable));
}
}
if let value @ Some(_) =
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
{
- return value;
+ return value.zip(Some(Stable));
}
calculate_best_path(
db,
@@ -224,6 +240,7 @@ fn find_path_for_module(
)
}
+// FIXME: Do we still need this now that we record import origins, and hence aliases?
fn find_in_scope(
db: &dyn DefDatabase,
def_map: &DefMap,
@@ -244,7 +261,7 @@ fn find_in_prelude(
item: ItemInNs,
from: ModuleId,
) -> Option<ModPath> {
- let prelude_module = root_def_map.prelude()?;
+ let (prelude_module, _) = root_def_map.prelude()?;
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
let prelude_def_map = prelude_module.def_map(db);
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
@@ -293,18 +310,26 @@ fn calculate_best_path(
db: &dyn DefDatabase,
def_map: &DefMap,
visited_modules: &mut FxHashSet<ModuleId>,
- crate_root: ModuleId,
+ crate_root: CrateRootModuleId,
max_len: usize,
item: ItemInNs,
from: ModuleId,
mut prefixed: Option<PrefixKind>,
prefer_no_std: bool,
scope_name: Option<Name>,
-) -> Option<ModPath> {
+) -> Option<(ModPath, Stability)> {
if max_len <= 1 {
return None;
}
let mut best_path = None;
+ let update_best_path =
+ |best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path {
+ Some((old_path, old_stability)) => {
+ *old_path = new_path.0;
+ *old_stability = zip_stability(*old_stability, new_path.1);
+ }
+ None => *best_path = Some(new_path),
+ };
// Recursive case:
// - otherwise, look for modules containing (reexporting) it and import it from one of those
if item.krate(db) == Some(from.krate) {
@@ -327,14 +352,14 @@ fn calculate_best_path(
prefixed,
prefer_no_std,
) {
- path.push_segment(name);
+ path.0.push_segment(name);
- let new_path = match best_path {
+ let new_path = match best_path.take() {
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
None => path,
};
- best_path_len = new_path.len();
- best_path = Some(new_path);
+ best_path_len = new_path.0.len();
+ update_best_path(&mut best_path, new_path);
}
}
} else {
@@ -346,9 +371,14 @@ fn calculate_best_path(
let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
let import_map = db.import_map(dep.crate_id);
import_map.import_info_for(item).and_then(|info| {
+ if info.is_doc_hidden {
+ // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
+ return None;
+ }
+
// Determine best path for containing module and append last segment from `info`.
// FIXME: we should guide this to look up the path locally, or from the same crate again?
- let mut path = find_path_for_module(
+ let (mut path, path_stability) = find_path_for_module(
db,
def_map,
visited_modules,
@@ -361,16 +391,19 @@ fn calculate_best_path(
)?;
cov_mark::hit!(partially_imported);
path.push_segment(info.name.clone());
- Some(path)
+ Some((
+ path,
+ zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
+ ))
})
});
for path in extern_paths {
- let new_path = match best_path {
+ let new_path = match best_path.take() {
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
None => path,
};
- best_path = Some(new_path);
+ update_best_path(&mut best_path, new_path);
}
}
if let Some(module) = item.module(db) {
@@ -381,15 +414,24 @@ fn calculate_best_path(
}
match prefixed.map(PrefixKind::prefix) {
Some(prefix) => best_path.or_else(|| {
- scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
+ scope_name.map(|scope_name| (ModPath::from_segments(prefix, Some(scope_name)), Stable))
}),
None => best_path,
}
}
-fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
+fn select_best_path(
+ old_path: (ModPath, Stability),
+ new_path: (ModPath, Stability),
+ prefer_no_std: bool,
+) -> (ModPath, Stability) {
+ match (old_path.1, new_path.1) {
+ (Stable, Unstable) => return old_path,
+ (Unstable, Stable) => return new_path,
+ _ => {}
+ }
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
- match (old_path.segments().first(), new_path.segments().first()) {
+ match (old_path.0.segments().first(), new_path.0.segments().first()) {
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
let rank = match prefer_no_std {
false => |name: &Name| match name {
@@ -410,7 +452,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
match nrank.cmp(&orank) {
Ordering::Less => old_path,
Ordering::Equal => {
- if new_path.len() < old_path.len() {
+ if new_path.0.len() < old_path.0.len() {
new_path
} else {
old_path
@@ -420,7 +462,7 @@ fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -
}
}
_ => {
- if new_path.len() < old_path.len() {
+ if new_path.0.len() < old_path.0.len() {
new_path
} else {
old_path
@@ -1293,4 +1335,90 @@ pub mod prelude {
"None",
);
}
+
+ #[test]
+ fn different_crate_renamed_through_dep() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:intermediate
+$0
+//- /intermediate.rs crate:intermediate deps:std
+pub extern crate std as std_renamed;
+//- /std.rs crate:std
+pub struct S;
+ "#,
+ "intermediate::std_renamed::S",
+ "intermediate::std_renamed::S",
+ "intermediate::std_renamed::S",
+ "intermediate::std_renamed::S",
+ );
+ }
+
+ #[test]
+ fn different_crate_doc_hidden() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:intermediate
+$0
+//- /intermediate.rs crate:intermediate deps:std
+#[doc(hidden)]
+pub extern crate std;
+pub extern crate std as longer;
+//- /std.rs crate:std
+pub struct S;
+ "#,
+ "intermediate::longer::S",
+ "intermediate::longer::S",
+ "intermediate::longer::S",
+ "intermediate::longer::S",
+ );
+ }
+
+ #[test]
+ fn respect_doc_hidden() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std,lazy_static
+$0
+//- /lazy_static.rs crate:lazy_static deps:core
+#[doc(hidden)]
+pub use core::ops::Deref as __Deref;
+//- /std.rs crate:std deps:core
+pub use core::ops;
+//- /core.rs crate:core
+pub mod ops {
+ pub trait Deref {}
+}
+ "#,
+ "std::ops::Deref",
+ "std::ops::Deref",
+ "std::ops::Deref",
+ "std::ops::Deref",
+ );
+ }
+
+ #[test]
+ fn respect_unstable_modules() {
+ check_found_path(
+ r#"
+//- /main.rs crate:main deps:std,core
+#![no_std]
+extern crate std;
+$0
+//- /longer.rs crate:std deps:core
+pub mod error {
+ pub use core::error::Error;
+}
+//- /core.rs crate:core
+pub mod error {
+ #![unstable(feature = "error_in_core", issue = "103765")]
+ pub trait Error {}
+}
+"#,
+ "std::error::Error",
+ "std::error::Error",
+ "std::error::Error",
+ "std::error::Error",
+ );
+ }
}
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 d7d44e413..1e2535a8a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -21,10 +21,11 @@ use crate::{
db::DefDatabase,
dyn_map::{keys, DynMap},
expander::Expander,
+ item_tree::{AttrOwner, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
src::{HasChildSource, HasSource},
- type_ref::{LifetimeRef, TypeBound, TypeRef},
+ type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@@ -48,7 +49,7 @@ pub struct LifetimeParamData {
pub struct ConstParamData {
pub name: Name,
pub ty: Interned<TypeRef>,
- pub has_default: bool,
+ pub default: Option<ConstRef>,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
@@ -75,7 +76,7 @@ impl TypeOrConstParamData {
pub fn has_default(&self) -> bool {
match self {
TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
- TypeOrConstParamData::ConstParamData(it) => it.has_default,
+ TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
}
}
@@ -154,12 +155,58 @@ impl GenericParams {
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = profile::span("generic_params_query");
+
+ let krate = def.module(db).krate;
+ let cfg_options = db.crate_graph();
+ let cfg_options = &cfg_options[krate].cfg_options;
+
+ // Returns the generic parameters that are enabled under the current `#[cfg]` options
+ let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
+ let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
+
+ // In the common case, no parameters will by disabled by `#[cfg]` attributes.
+ // Therefore, make a first pass to check if all parameters are enabled and, if so,
+ // clone the `Interned<GenericParams>` instead of recreating an identical copy.
+ let all_type_or_consts_enabled =
+ params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
+ let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
+
+ if all_type_or_consts_enabled && all_lifetimes_enabled {
+ params.clone()
+ } else {
+ Interned::new(GenericParams {
+ type_or_consts: all_type_or_consts_enabled
+ .then(|| params.type_or_consts.clone())
+ .unwrap_or_else(|| {
+ params
+ .type_or_consts
+ .iter()
+ .filter_map(|(idx, param)| {
+ enabled(idx.into()).then(|| param.clone())
+ })
+ .collect()
+ }),
+ lifetimes: all_lifetimes_enabled
+ .then(|| params.lifetimes.clone())
+ .unwrap_or_else(|| {
+ params
+ .lifetimes
+ .iter()
+ .filter_map(|(idx, param)| {
+ enabled(idx.into()).then(|| param.clone())
+ })
+ .collect()
+ }),
+ where_predicates: params.where_predicates.clone(),
+ })
+ }
+ };
macro_rules! id_to_generics {
($id:ident) => {{
let id = $id.lookup(db).id;
let tree = id.item_tree(db);
let item = &tree[id.value];
- item.generic_params.clone()
+ enabled_params(&item.generic_params, &tree)
}};
}
@@ -169,7 +216,8 @@ impl GenericParams {
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
- let mut generic_params = GenericParams::clone(&item.explicit_generic_params);
+ let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
+ let mut generic_params = GenericParams::clone(&enabled_params);
let module = loc.container.module(db);
let func_data = db.function_data(id);
@@ -198,9 +246,14 @@ impl GenericParams {
}
}
- pub(crate) fn fill(&mut self, lower_ctx: &LowerCtx<'_>, node: &dyn HasGenericParams) {
+ pub(crate) fn fill(
+ &mut self,
+ lower_ctx: &LowerCtx<'_>,
+ node: &dyn HasGenericParams,
+ add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
+ ) {
if let Some(params) = node.generic_param_list() {
- self.fill_params(lower_ctx, params)
+ self.fill_params(lower_ctx, params, add_param_attrs)
}
if let Some(where_clause) = node.where_clause() {
self.fill_where_predicates(lower_ctx, where_clause);
@@ -218,7 +271,12 @@ impl GenericParams {
}
}
- fn fill_params(&mut self, lower_ctx: &LowerCtx<'_>, params: ast::GenericParamList) {
+ fn fill_params(
+ &mut self,
+ lower_ctx: &LowerCtx<'_>,
+ params: ast::GenericParamList,
+ mut add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
+ ) {
for type_or_const_param in params.type_or_const_params() {
match type_or_const_param {
ast::TypeOrConstParam::Type(type_param) => {
@@ -232,13 +290,14 @@ impl GenericParams {
default,
provenance: TypeParamProvenance::TypeParamList,
};
- self.type_or_consts.alloc(param.into());
+ let idx = self.type_or_consts.alloc(param.into());
let type_ref = TypeRef::Path(name.into());
self.fill_bounds(
lower_ctx,
type_param.type_bound_list(),
Either::Left(type_ref),
);
+ add_param_attrs(idx.into(), ast::GenericParam::TypeParam(type_param));
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
@@ -248,9 +307,10 @@ impl GenericParams {
let param = ConstParamData {
name,
ty: Interned::new(ty),
- has_default: const_param.default_val().is_some(),
+ default: ConstRef::from_const_param(lower_ctx, &const_param),
};
- self.type_or_consts.alloc(param.into());
+ let idx = self.type_or_consts.alloc(param.into());
+ add_param_attrs(idx.into(), ast::GenericParam::ConstParam(const_param));
}
}
}
@@ -258,13 +318,14 @@ impl GenericParams {
let name =
lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(&lt));
let param = LifetimeParamData { name: name.clone() };
- self.lifetimes.alloc(param);
+ let idx = self.lifetimes.alloc(param);
let lifetime_ref = LifetimeRef::new_name(name);
self.fill_bounds(
lower_ctx,
lifetime_param.type_bound_list(),
Either::Right(lifetime_ref),
);
+ add_param_attrs(idx.into(), ast::GenericParam::LifetimeParam(lifetime_param));
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index 6591c92ac..591ee77c7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -13,6 +13,7 @@
//! See also a neighboring `body` module.
pub mod type_ref;
+pub mod format_args;
use std::fmt;
@@ -117,7 +118,6 @@ impl From<ast::LiteralKind> for Literal {
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
use ast::LiteralKind;
match ast_lit_kind {
- // FIXME: these should have actual values filled in, but unsure on perf impact
LiteralKind::IntNumber(lit) => {
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
Literal::Float(
@@ -281,6 +281,19 @@ pub enum Expr {
Array(Array),
Literal(Literal),
Underscore,
+ OffsetOf(OffsetOf),
+ InlineAsm(InlineAsm),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct OffsetOf {
+ pub container: Interned<TypeRef>,
+ pub fields: Box<[Name]>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InlineAsm {
+ pub e: ExprId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -341,7 +354,8 @@ impl Expr {
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
match self {
Expr::Missing => {}
- Expr::Path(_) => {}
+ Expr::Path(_) | Expr::OffsetOf(_) => {}
+ Expr::InlineAsm(it) => f(it.e),
Expr::If { condition, then_branch, else_branch } => {
f(*condition);
f(*then_branch);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
new file mode 100644
index 000000000..75025a984
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -0,0 +1,502 @@
+//! Parses `format_args` input.
+use std::mem;
+
+use hir_expand::name::Name;
+use rustc_parse_format as parse;
+use syntax::{
+ ast::{self, IsString},
+ AstToken, SmolStr, TextRange,
+};
+
+use crate::hir::ExprId;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgs {
+ pub template: Box<[FormatArgsPiece]>,
+ pub arguments: FormatArguments,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArguments {
+ pub arguments: Box<[FormatArgument]>,
+ pub num_unnamed_args: usize,
+ pub num_explicit_args: usize,
+ pub names: Box<[(Name, usize)]>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FormatArgsPiece {
+ Literal(Box<str>),
+ Placeholder(FormatPlaceholder),
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+ /// Index into [`FormatArgs::arguments`].
+ pub argument: FormatArgPosition,
+ /// The span inside the format string for the full `{…}` placeholder.
+ pub span: Option<TextRange>,
+ /// `{}`, `{:?}`, or `{:x}`, etc.
+ pub format_trait: FormatTrait,
+ /// `{}` or `{:.5}` or `{:-^20}`, etc.
+ pub format_options: FormatOptions,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgPosition {
+ /// Which argument this position refers to (Ok),
+ /// or would've referred to if it existed (Err).
+ pub index: Result<usize, usize>,
+ /// What kind of position this is. See [`FormatArgPositionKind`].
+ pub kind: FormatArgPositionKind,
+ /// The span of the name or number.
+ pub span: Option<TextRange>,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+ /// `{}` or `{:.*}`
+ Implicit,
+ /// `{1}` or `{:1$}` or `{:.1$}`
+ Number,
+ /// `{a}` or `{:a$}` or `{:.a$}`
+ Named,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum FormatTrait {
+ /// `{}`
+ Display,
+ /// `{:?}`
+ Debug,
+ /// `{:e}`
+ LowerExp,
+ /// `{:E}`
+ UpperExp,
+ /// `{:o}`
+ Octal,
+ /// `{:p}`
+ Pointer,
+ /// `{:b}`
+ Binary,
+ /// `{:x}`
+ LowerHex,
+ /// `{:X}`
+ UpperHex,
+}
+
+#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
+pub struct FormatOptions {
+ /// The width. E.g. `{:5}` or `{:width$}`.
+ pub width: Option<FormatCount>,
+ /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+ pub precision: Option<FormatCount>,
+ /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+ pub alignment: Option<FormatAlignment>,
+ /// The fill character. E.g. the `.` in `{:.>10}`.
+ pub fill: Option<char>,
+ /// The `+` or `-` flag.
+ pub sign: Option<FormatSign>,
+ /// The `#` flag.
+ pub alternate: bool,
+ /// The `0` flag. E.g. the `0` in `{:02x}`.
+ pub zero_pad: bool,
+ /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
+ pub debug_hex: Option<FormatDebugHex>,
+}
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatSign {
+ /// The `+` flag.
+ Plus,
+ /// The `-` flag.
+ Minus,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatDebugHex {
+ /// The `x` flag in `{:x?}`.
+ Lower,
+ /// The `X` flag in `{:X?}`.
+ Upper,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+ /// `{:<}`
+ Left,
+ /// `{:>}`
+ Right,
+ /// `{:^}`
+ Center,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+ /// `{:5}` or `{:.5}`
+ Literal(usize),
+ /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+ Argument(FormatArgPosition),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgument {
+ pub kind: FormatArgumentKind,
+ pub expr: ExprId,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum FormatArgumentKind {
+ /// `format_args(…, arg)`
+ Normal,
+ /// `format_args(…, arg = 1)`
+ Named(Name),
+ /// `format_args("… {arg} …")`
+ Captured(Name),
+}
+
+// Only used in parse_args and report_invalid_references,
+// to indicate how a referred argument was used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum PositionUsedAs {
+ Placeholder(Option<TextRange>),
+ Precision,
+ Width,
+}
+use PositionUsedAs::*;
+
+pub(crate) fn parse(
+ s: &ast::String,
+ fmt_snippet: Option<String>,
+ mut args: FormatArgumentsCollector,
+ is_direct_literal: bool,
+ mut synth: impl FnMut(Name) -> ExprId,
+) -> FormatArgs {
+ let text = s.text();
+ let str_style = match s.quote_offsets() {
+ Some(offsets) => {
+ let raw = u32::from(offsets.quotes.0.len()) - 1;
+ (raw != 0).then_some(raw as usize)
+ }
+ None => None,
+ };
+ let mut parser =
+ parse::Parser::new(text, str_style, fmt_snippet, false, parse::ParseMode::Format);
+
+ let mut pieces = Vec::new();
+ while let Some(piece) = parser.next() {
+ if !parser.errors.is_empty() {
+ break;
+ } else {
+ pieces.push(piece);
+ }
+ }
+ let is_source_literal = parser.is_source_literal;
+ if !parser.errors.is_empty() {
+ // FIXME: Diagnose
+ return FormatArgs { template: Default::default(), arguments: args.finish() };
+ }
+
+ let to_span = |inner_span: parse::InnerSpan| {
+ is_source_literal.then(|| {
+ TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
+ })
+ };
+
+ let mut used = vec![false; args.explicit_args().len()];
+ let mut invalid_refs = Vec::new();
+ let mut numeric_refences_to_named_arg = Vec::new();
+
+ enum ArgRef<'a> {
+ Index(usize),
+ Name(&'a str, Option<TextRange>),
+ }
+ let mut lookup_arg = |arg: ArgRef<'_>,
+ span: Option<TextRange>,
+ used_as: PositionUsedAs,
+ kind: FormatArgPositionKind|
+ -> FormatArgPosition {
+ let index = match arg {
+ ArgRef::Index(index) => {
+ if let Some(arg) = args.by_index(index) {
+ used[index] = true;
+ if arg.kind.ident().is_some() {
+ // This was a named argument, but it was used as a positional argument.
+ numeric_refences_to_named_arg.push((index, span, used_as));
+ }
+ Ok(index)
+ } else {
+ // Doesn't exist as an explicit argument.
+ invalid_refs.push((index, span, used_as, kind));
+ Err(index)
+ }
+ }
+ ArgRef::Name(name, _span) => {
+ let name = Name::new_text_dont_use(SmolStr::new(name));
+ if let Some((index, _)) = args.by_name(&name) {
+ // Name found in `args`, so we resolve it to its index.
+ if index < args.explicit_args().len() {
+ // Mark it as used, if it was an explicit argument.
+ used[index] = true;
+ }
+ Ok(index)
+ } else {
+ // Name not found in `args`, so we add it as an implicitly captured argument.
+ if !is_direct_literal {
+ // For the moment capturing variables from format strings expanded from macros is
+ // disabled (see RFC #2795)
+ // FIXME: Diagnose
+ }
+ Ok(args.add(FormatArgument {
+ kind: FormatArgumentKind::Captured(name.clone()),
+ // FIXME: This is problematic, we might want to synthesize a dummy
+ // expression proper and/or desugar these.
+ expr: synth(name),
+ }))
+ }
+ }
+ };
+ FormatArgPosition { index, kind, span }
+ };
+
+ let mut template = Vec::new();
+ let mut unfinished_literal = String::new();
+ let mut placeholder_index = 0;
+
+ for piece in pieces {
+ match piece {
+ parse::Piece::String(s) => {
+ unfinished_literal.push_str(s);
+ }
+ parse::Piece::NextArgument(arg) => {
+ let parse::Argument { position, position_span, format } = *arg;
+ if !unfinished_literal.is_empty() {
+ template.push(FormatArgsPiece::Literal(
+ mem::take(&mut unfinished_literal).into_boxed_str(),
+ ));
+ }
+
+ let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
+ placeholder_index += 1;
+
+ let position_span = to_span(position_span);
+ let argument = match position {
+ parse::ArgumentImplicitlyIs(i) => lookup_arg(
+ ArgRef::Index(i),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Implicit,
+ ),
+ parse::ArgumentIs(i) => lookup_arg(
+ ArgRef::Index(i),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Number,
+ ),
+ parse::ArgumentNamed(name) => lookup_arg(
+ ArgRef::Name(name, position_span),
+ position_span,
+ Placeholder(span),
+ FormatArgPositionKind::Named,
+ ),
+ };
+
+ let alignment = match format.align {
+ parse::AlignUnknown => None,
+ parse::AlignLeft => Some(FormatAlignment::Left),
+ parse::AlignRight => Some(FormatAlignment::Right),
+ parse::AlignCenter => Some(FormatAlignment::Center),
+ };
+
+ let format_trait = match format.ty {
+ "" => FormatTrait::Display,
+ "?" => FormatTrait::Debug,
+ "e" => FormatTrait::LowerExp,
+ "E" => FormatTrait::UpperExp,
+ "o" => FormatTrait::Octal,
+ "p" => FormatTrait::Pointer,
+ "b" => FormatTrait::Binary,
+ "x" => FormatTrait::LowerHex,
+ "X" => FormatTrait::UpperHex,
+ _ => {
+ // FIXME: Diagnose
+ FormatTrait::Display
+ }
+ };
+
+ let precision_span = format.precision_span.and_then(to_span);
+ let precision = match format.precision {
+ parse::CountIs(n) => Some(FormatCount::Literal(n)),
+ parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+ ArgRef::Name(name, to_span(name_span)),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Named,
+ ))),
+ parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+ ArgRef::Index(i),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Number,
+ ))),
+ parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg(
+ ArgRef::Index(i),
+ precision_span,
+ Precision,
+ FormatArgPositionKind::Implicit,
+ ))),
+ parse::CountImplied => None,
+ };
+
+ let width_span = format.width_span.and_then(to_span);
+ let width = match format.width {
+ parse::CountIs(n) => Some(FormatCount::Literal(n)),
+ parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
+ ArgRef::Name(name, to_span(name_span)),
+ width_span,
+ Width,
+ FormatArgPositionKind::Named,
+ ))),
+ parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
+ ArgRef::Index(i),
+ width_span,
+ Width,
+ FormatArgPositionKind::Number,
+ ))),
+ parse::CountIsStar(_) => unreachable!(),
+ parse::CountImplied => None,
+ };
+
+ template.push(FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument,
+ span,
+ format_trait,
+ format_options: FormatOptions {
+ fill: format.fill,
+ alignment,
+ sign: format.sign.map(|s| match s {
+ parse::Sign::Plus => FormatSign::Plus,
+ parse::Sign::Minus => FormatSign::Minus,
+ }),
+ alternate: format.alternate,
+ zero_pad: format.zero_pad,
+ debug_hex: format.debug_hex.map(|s| match s {
+ parse::DebugHex::Lower => FormatDebugHex::Lower,
+ parse::DebugHex::Upper => FormatDebugHex::Upper,
+ }),
+ precision,
+ width,
+ },
+ }));
+ }
+ }
+ }
+
+ if !unfinished_literal.is_empty() {
+ template.push(FormatArgsPiece::Literal(unfinished_literal.into_boxed_str()));
+ }
+
+ if !invalid_refs.is_empty() {
+ // FIXME: Diagnose
+ }
+
+ let unused = used
+ .iter()
+ .enumerate()
+ .filter(|&(_, used)| !used)
+ .map(|(i, _)| {
+ let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_));
+ (args.explicit_args()[i].expr, named)
+ })
+ .collect::<Vec<_>>();
+
+ if !unused.is_empty() {
+ // FIXME: Diagnose
+ }
+
+ FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct FormatArgumentsCollector {
+ arguments: Vec<FormatArgument>,
+ num_unnamed_args: usize,
+ num_explicit_args: usize,
+ names: Vec<(Name, usize)>,
+}
+
+impl FormatArgumentsCollector {
+ pub(crate) fn finish(self) -> FormatArguments {
+ FormatArguments {
+ arguments: self.arguments.into_boxed_slice(),
+ num_unnamed_args: self.num_unnamed_args,
+ num_explicit_args: self.num_explicit_args,
+ names: self.names.into_boxed_slice(),
+ }
+ }
+
+ pub fn new() -> Self {
+ Self { arguments: vec![], names: vec![], num_unnamed_args: 0, num_explicit_args: 0 }
+ }
+
+ pub fn add(&mut self, arg: FormatArgument) -> usize {
+ let index = self.arguments.len();
+ if let Some(name) = arg.kind.ident() {
+ self.names.push((name.clone(), index));
+ } else if self.names.is_empty() {
+ // Only count the unnamed args before the first named arg.
+ // (Any later ones are errors.)
+ self.num_unnamed_args += 1;
+ }
+ if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+ // This is an explicit argument.
+ // Make sure that all arguments so far are explicit.
+ assert_eq!(
+ self.num_explicit_args,
+ self.arguments.len(),
+ "captured arguments must be added last"
+ );
+ self.num_explicit_args += 1;
+ }
+ self.arguments.push(arg);
+ index
+ }
+
+ pub fn by_name(&self, name: &Name) -> Option<(usize, &FormatArgument)> {
+ let &(_, i) = self.names.iter().find(|(n, _)| n == name)?;
+ Some((i, &self.arguments[i]))
+ }
+
+ pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+ (i < self.num_explicit_args).then(|| &self.arguments[i])
+ }
+
+ pub fn unnamed_args(&self) -> &[FormatArgument] {
+ &self.arguments[..self.num_unnamed_args]
+ }
+
+ pub fn named_args(&self) -> &[FormatArgument] {
+ &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+ }
+
+ pub fn explicit_args(&self) -> &[FormatArgument] {
+ &self.arguments[..self.num_explicit_args]
+ }
+
+ pub fn all_args(&self) -> &[FormatArgument] {
+ &self.arguments[..]
+ }
+
+ pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> {
+ &mut self.arguments
+ }
+}
+
+impl FormatArgumentKind {
+ pub fn ident(&self) -> Option<&Name> {
+ match self {
+ Self::Normal => None,
+ Self::Named(id) => Some(id),
+ Self::Captured(id) => Some(id),
+ }
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index 57f023ef3..75adf21ab 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -393,6 +393,17 @@ impl ConstRef {
Self::Scalar(LiteralConstRef::Unknown)
}
+ pub(crate) fn from_const_param(
+ lower_ctx: &LowerCtx<'_>,
+ param: &ast::ConstParam,
+ ) -> Option<Self> {
+ let default = param.default_val();
+ match default {
+ Some(_) => Some(Self::from_const_arg(lower_ctx, default)),
+ None => None,
+ }
+ }
+
pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a {
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef);
impl fmt::Display for Display<'_> {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index 4b2e5041a..44b7f1b4f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -11,6 +11,7 @@ use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
use triomphe::Arc;
+use crate::item_scope::ImportOrExternCrate;
use crate::{
db::DefDatabase, item_scope::ItemInNs, nameres::DefMap, visibility::Visibility, AssocItemId,
ModuleDefId, ModuleId, TraitId,
@@ -29,6 +30,10 @@ pub struct ImportInfo {
pub container: ModuleId,
/// Whether the import is a trait associated item or not.
pub is_trait_assoc_item: bool,
+ /// Whether this item is annotated with `#[doc(hidden)]`.
+ pub is_doc_hidden: bool,
+ /// Whether this item is annotated with `#[unstable(..)]`.
+ pub is_unstable: bool,
}
/// A map from publicly exported items to its name.
@@ -109,23 +114,71 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
});
for (name, per_ns) in visible_items {
- for item in per_ns.iter_items() {
+ for (item, import) in per_ns.iter_items() {
+ let attr_id = if let Some(import) = import {
+ match import {
+ ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
+ ImportOrExternCrate::Import(id) => Some(id.import.into()),
+ }
+ } else {
+ match item {
+ ItemInNs::Types(id) | ItemInNs::Values(id) => id.try_into().ok(),
+ ItemInNs::Macros(id) => Some(id.into()),
+ }
+ };
+ let status @ (is_doc_hidden, is_unstable) =
+ attr_id.map_or((false, false), |attr_id| {
+ let attrs = db.attrs(attr_id);
+ (attrs.has_doc_hidden(), attrs.is_unstable())
+ });
+
let import_info = ImportInfo {
name: name.clone(),
container: module,
is_trait_assoc_item: false,
+ is_doc_hidden,
+ is_unstable,
};
match depth_map.entry(item) {
- Entry::Vacant(entry) => {
- entry.insert(depth);
- }
+ Entry::Vacant(entry) => _ = entry.insert((depth, status)),
Entry::Occupied(mut entry) => {
- if depth < *entry.get() {
- entry.insert(depth);
- } else {
+ let &(occ_depth, (occ_is_doc_hidden, occ_is_unstable)) = entry.get();
+ (depth, occ_depth);
+ let overwrite = match (
+ is_doc_hidden,
+ occ_is_doc_hidden,
+ is_unstable,
+ occ_is_unstable,
+ ) {
+ // no change of hiddeness or unstableness
+ (true, true, true, true)
+ | (true, true, false, false)
+ | (false, false, true, true)
+ | (false, false, false, false) => depth < occ_depth,
+
+ // either less hidden or less unstable, accept
+ (true, true, false, true)
+ | (false, true, true, true)
+ | (false, true, false, true)
+ | (false, true, false, false)
+ | (false, false, false, true) => true,
+ // more hidden or unstable, discard
+ (true, true, true, false)
+ | (true, false, true, true)
+ | (true, false, true, false)
+ | (true, false, false, false)
+ | (false, false, true, false) => false,
+
+ // exchanges doc(hidden) for unstable (and vice-versa),
+ (true, false, false, true) | (false, true, true, false) => {
+ depth < occ_depth
+ }
+ };
+ if !overwrite {
continue;
}
+ entry.insert((depth, status));
}
}
@@ -150,7 +203,7 @@ fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> FxIndexMap<ItemIn
}
}
}
-
+ map.shrink_to_fit();
map
}
@@ -162,10 +215,10 @@ fn collect_trait_assoc_items(
trait_import_info: &ImportInfo,
) {
let _p = profile::span("collect_trait_assoc_items");
- for (assoc_item_name, item) in &db.trait_data(tr).items {
+ for &(ref assoc_item_name, item) in &db.trait_data(tr).items {
let module_def_id = match item {
- AssocItemId::FunctionId(f) => ModuleDefId::from(*f),
- AssocItemId::ConstId(c) => ModuleDefId::from(*c),
+ AssocItemId::FunctionId(f) => ModuleDefId::from(f),
+ AssocItemId::ConstId(c) => ModuleDefId::from(c),
// cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias`
// qualifier, ergo no need to store it for imports in import_map
AssocItemId::TypeAliasId(_) => {
@@ -179,10 +232,13 @@ fn collect_trait_assoc_items(
ItemInNs::Values(module_def_id)
};
+ let attrs = &db.attrs(item.into());
let assoc_item_info = ImportInfo {
container: trait_import_info.container,
name: assoc_item_name.clone(),
is_trait_assoc_item: true,
+ is_doc_hidden: attrs.has_doc_hidden(),
+ is_unstable: attrs.is_unstable(),
};
map.insert(assoc_item, assoc_item_info);
}
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 873accafb..7c11fb9d1 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
@@ -6,6 +6,7 @@ use std::collections::hash_map::Entry;
use base_db::CrateId;
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
use itertools::Itertools;
+use la_arena::Idx;
use once_cell::sync::Lazy;
use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -15,16 +16,10 @@ use syntax::ast;
use crate::{
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
- ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
- UseId,
+ ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId,
+ TraitId, UseId,
};
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum ImportType {
- Glob,
- Named,
-}
-
#[derive(Debug, Default)]
pub struct PerNsGlobImports {
types: FxHashSet<(LocalModuleId, Name)>,
@@ -32,15 +27,50 @@ pub struct PerNsGlobImports {
macros: FxHashSet<(LocalModuleId, Name)>,
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ImportOrExternCrate {
+ Import(ImportId),
+ ExternCrate(ExternCrateId),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub(crate) enum ImportType {
+ Import(ImportId),
+ Glob(UseId),
+ ExternCrate(ExternCrateId),
+}
+
+impl ImportOrExternCrate {
+ pub fn into_import(self) -> Option<ImportId> {
+ match self {
+ ImportOrExternCrate::Import(it) => Some(it),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ImportOrDef {
+ Import(ImportId),
+ ExternCrate(ExternCrateId),
+ Def(ModuleDefId),
+}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct ImportId {
+ pub import: UseId,
+ pub idx: Idx<ast::UseTree>,
+}
+
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
_c: Count<Self>,
/// Defs visible in this scope. This includes `declarations`, but also
- /// imports.
- types: FxHashMap<Name, (ModuleDefId, Visibility)>,
- values: FxHashMap<Name, (ModuleDefId, Visibility)>,
- macros: FxHashMap<Name, (MacroId, Visibility)>,
+ /// imports. The imports belong to this module and can be resolved by using them on
+ /// the `use_imports_*` fields.
+ types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
+ values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
+ macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>,
unresolved: FxHashSet<Name>,
/// The defs declared in this scope. Each def has a single scope where it is
@@ -50,7 +80,14 @@ pub struct ItemScope {
impls: Vec<ImplId>,
unnamed_consts: Vec<ConstId>,
/// Traits imported via `use Trait as _;`.
- unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
+ unnamed_trait_imports: FxHashMap<TraitId, (Visibility, Option<ImportId>)>,
+
+ // the resolutions of the imports of this scope
+ use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
+ use_imports_values: FxHashMap<ImportId, ImportOrDef>,
+ use_imports_macros: FxHashMap<ImportId, ImportOrDef>,
+
+ use_decls: Vec<UseId>,
extern_crate_decls: Vec<ExternCrateId>,
/// Macros visible in current module in legacy textual scope
///
@@ -82,7 +119,7 @@ struct DeriveMacroInvocation {
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
BuiltinType::ALL
.iter()
- .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
+ .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
.collect()
});
@@ -105,11 +142,77 @@ impl ItemScope {
.chain(self.values.keys())
.chain(self.macros.keys())
.chain(self.unresolved.iter())
- .sorted()
.unique()
+ .sorted()
.map(move |name| (name, self.get(name)))
}
+ pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
+ self.use_imports_types
+ .keys()
+ .copied()
+ .filter_map(ImportOrExternCrate::into_import)
+ .chain(self.use_imports_values.keys().copied())
+ .chain(self.use_imports_macros.keys().copied())
+ .unique()
+ .sorted()
+ }
+
+ pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
+ let mut res = PerNs::none();
+
+ let mut def_map;
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_macros.get(&import) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
+ res.macros = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(def) => {
+ res.types = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_values.get(&import) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(def) => {
+ res.values = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ res
+ }
+
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
self.declarations.iter().copied()
}
@@ -121,8 +224,7 @@ impl ItemScope {
}
pub fn use_decls(&self) -> impl Iterator<Item = UseId> + ExactSizeIterator + '_ {
- // FIXME: to be implemented
- std::iter::empty()
+ self.use_decls.iter().copied()
}
pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
@@ -132,13 +234,13 @@ impl ItemScope {
pub fn values(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
- self.values.values().copied()
+ self.values.values().copied().map(|(a, b, _)| (a, b))
}
- pub fn types(
+ pub(crate) fn types(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
- self.types.values().copied()
+ self.types.values().copied().map(|(def, vis, _)| (def, vis))
}
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
@@ -165,33 +267,55 @@ impl ItemScope {
}
pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
- self.types.get(name).copied()
+ self.types.get(name).copied().map(|(a, b, _)| (a, b))
}
/// XXX: this is O(N) rather than O(1), try to not introduce new usages.
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
- let (def, mut iter) = match item {
- ItemInNs::Macros(def) => {
- return self.macros.iter().find_map(|(name, &(other_def, vis))| {
- (other_def == def).then_some((name, vis))
- });
- }
- ItemInNs::Types(def) => (def, self.types.iter()),
- ItemInNs::Values(def) => (def, self.values.iter()),
- };
- iter.find_map(|(name, &(other_def, vis))| (other_def == def).then_some((name, vis)))
+ match item {
+ ItemInNs::Macros(def) => self
+ .macros
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+ ItemInNs::Types(def) => self
+ .types
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+
+ ItemInNs::Values(def) => self
+ .values
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+ }
}
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
self.types
.values()
- .filter_map(|&(def, _)| match def {
+ .filter_map(|&(def, _, _)| match def {
ModuleDefId::TraitId(t) => Some(t),
_ => None,
})
.chain(self.unnamed_trait_imports.keys().copied())
}
+ pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
+ self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
+ self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| {
+ (
+ None,
+ PerNs::types(
+ ModuleDefId::TraitId(*tr),
+ *vis,
+ i.map(ImportOrExternCrate::Import),
+ ),
+ )
+ }),
+ )
+ }
+}
+
+impl ItemScope {
pub(crate) fn declare(&mut self, def: ModuleDefId) {
self.declarations.push(def)
}
@@ -277,12 +401,14 @@ impl ItemScope {
})
}
+ // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
- self.unnamed_trait_imports.get(&tr).copied()
+ self.unnamed_trait_imports.get(&tr).copied().map(|(a, _)| a)
}
pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
- self.unnamed_trait_imports.insert(tr, vis);
+ // FIXME: import
+ self.unnamed_trait_imports.insert(tr, (vis, None));
}
pub(crate) fn push_res_with_import(
@@ -290,51 +416,187 @@ impl ItemScope {
glob_imports: &mut PerNsGlobImports,
lookup: (LocalModuleId, Name),
def: PerNs,
- def_import_type: ImportType,
+ import: Option<ImportType>,
) -> bool {
let mut changed = false;
- macro_rules! check_changed {
- (
- $changed:ident,
- ( $this:ident / $def:ident ) . $field:ident,
- $glob_imports:ident [ $lookup:ident ],
- $def_import_type:ident
- ) => {{
- if let Some(fld) = $def.$field {
- let existing = $this.$field.entry($lookup.1.clone());
- match existing {
- Entry::Vacant(entry) => {
- match $def_import_type {
- ImportType::Glob => {
- $glob_imports.$field.insert($lookup.clone());
+ // FIXME: Document and simplify this
+
+ if let Some(mut fld) = def.types {
+ let existing = self.types.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.types.insert(lookup.clone());
+ }
+ _ => _ = glob_imports.types.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::ExternCrate(extern_crate)) => {
+ Some(ImportOrExternCrate::ExternCrate(extern_crate))
+ }
+ Some(ImportType::Import(import)) => {
+ Some(ImportOrExternCrate::Import(import))
+ }
+ None | Some(ImportType::Glob(_)) => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_types.insert(
+ import,
+ match prev {
+ Some(ImportOrExternCrate::Import(import)) => {
+ ImportOrDef::Import(import)
}
- ImportType::Named => {
- $glob_imports.$field.remove(&$lookup);
+ Some(ImportOrExternCrate::ExternCrate(import)) => {
+ ImportOrDef::ExternCrate(import)
}
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.types.remove(&lookup) {
+ let import = match import {
+ Some(ImportType::ExternCrate(extern_crate)) => {
+ Some(ImportOrExternCrate::ExternCrate(extern_crate))
+ }
+ Some(ImportType::Import(import)) => {
+ Some(ImportOrExternCrate::Import(import))
}
+ None | Some(ImportType::Glob(_)) => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_types.insert(
+ import,
+ match prev {
+ Some(ImportOrExternCrate::Import(import)) => {
+ ImportOrDef::Import(import)
+ }
+ Some(ImportOrExternCrate::ExternCrate(import)) => {
+ ImportOrDef::ExternCrate(import)
+ }
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ cov_mark::hit!(import_shadowed);
+ entry.insert(fld);
+ changed = true;
+ }
+ }
+ _ => {}
+ }
+ }
- entry.insert(fld);
- $changed = true;
+ if let Some(mut fld) = def.values {
+ let existing = self.values.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.values.insert(lookup.clone());
}
- Entry::Occupied(mut entry)
- if matches!($def_import_type, ImportType::Named) =>
- {
- if $glob_imports.$field.remove(&$lookup) {
- cov_mark::hit!(import_shadowed);
- entry.insert(fld);
- $changed = true;
- }
+ _ => _ = glob_imports.values.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_values.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.values.remove(&lookup) {
+ cov_mark::hit!(import_shadowed);
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_values.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
}
- _ => {}
+ entry.insert(fld);
+ changed = true;
}
}
- }};
+ _ => {}
+ }
}
- check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
- check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
- check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
+ if let Some(mut fld) = def.macros {
+ let existing = self.macros.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.macros.insert(lookup.clone());
+ }
+ _ => _ = glob_imports.macros.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_macros.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0.into()),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.macros.remove(&lookup) {
+ cov_mark::hit!(import_shadowed);
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_macros.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0.into()),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ }
+ _ => {}
+ }
+ }
if def.is_none() && self.unresolved.insert(lookup.1) {
changed = true;
@@ -343,27 +605,18 @@ impl ItemScope {
changed
}
- pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
- self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
- self.unnamed_trait_imports
- .iter()
- .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
- )
- }
-
/// Marks everything that is not a procedural macro as private to `this_module`.
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
self.types
.values_mut()
- .chain(self.values.values_mut())
+ .map(|(def, vis, _)| (def, vis))
+ .chain(self.values.values_mut().map(|(def, vis, _)| (def, vis)))
.map(|(_, v)| v)
- .chain(self.unnamed_trait_imports.values_mut())
+ .chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
.for_each(|vis| *vis = Visibility::Module(this_module));
- for (mac, vis) in self.macros.values_mut() {
- if let MacroId::ProcMacroId(_) = mac {
- // FIXME: Technically this is insufficient since reexports of proc macros are also
- // forbidden. Practically nobody does that.
+ for (mac, vis, import) in self.macros.values_mut() {
+ if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
continue;
}
@@ -382,14 +635,25 @@ impl ItemScope {
name.map_or("_".to_string(), |name| name.display(db).to_string())
);
- if def.types.is_some() {
+ if let Some((.., i)) = def.types {
buf.push_str(" t");
+ match i {
+ Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
+ Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
+ None => (),
+ }
}
- if def.values.is_some() {
+ if let Some((.., i)) = def.values {
buf.push_str(" v");
+ if i.is_some() {
+ buf.push('i');
+ }
}
- if def.macros.is_some() {
+ if let Some((.., i)) = def.macros {
buf.push_str(" m");
+ if i.is_some() {
+ buf.push('i');
+ }
}
if def.is_none() {
buf.push_str(" _");
@@ -415,10 +679,17 @@ impl ItemScope {
attr_macros,
derive_macros,
extern_crate_decls,
+ use_decls,
+ use_imports_values,
+ use_imports_types,
+ use_imports_macros,
} = self;
types.shrink_to_fit();
values.shrink_to_fit();
macros.shrink_to_fit();
+ use_imports_types.shrink_to_fit();
+ use_imports_values.shrink_to_fit();
+ use_imports_macros.shrink_to_fit();
unresolved.shrink_to_fit();
declarations.shrink_to_fit();
impls.shrink_to_fit();
@@ -428,32 +699,44 @@ impl ItemScope {
attr_macros.shrink_to_fit();
derive_macros.shrink_to_fit();
extern_crate_decls.shrink_to_fit();
+ use_decls.shrink_to_fit();
}
}
impl PerNs {
- pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
+ pub(crate) fn from_def(
+ def: ModuleDefId,
+ v: Visibility,
+ has_constructor: bool,
+ import: Option<ImportOrExternCrate>,
+ ) -> PerNs {
match def {
- ModuleDefId::ModuleId(_) => PerNs::types(def, v),
- ModuleDefId::FunctionId(_) => PerNs::values(def, v),
+ ModuleDefId::ModuleId(_) => PerNs::types(def, v, import),
+ ModuleDefId::FunctionId(_) => {
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ }
ModuleDefId::AdtId(adt) => match adt {
- AdtId::UnionId(_) => PerNs::types(def, v),
- AdtId::EnumId(_) => PerNs::types(def, v),
+ AdtId::UnionId(_) => PerNs::types(def, v, import),
+ AdtId::EnumId(_) => PerNs::types(def, v, import),
AdtId::StructId(_) => {
if has_constructor {
- PerNs::both(def, def, v)
+ PerNs::both(def, def, v, import)
} else {
- PerNs::types(def, v)
+ PerNs::types(def, v, import)
}
}
},
- ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
- ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
- ModuleDefId::TraitId(_) => PerNs::types(def, v),
- ModuleDefId::TraitAliasId(_) => PerNs::types(def, v),
- ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
- ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
- ModuleDefId::MacroId(mac) => PerNs::macros(mac, v),
+ ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import),
+ ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ }
+ ModuleDefId::TraitId(_) => PerNs::types(def, v, import),
+ ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import),
+ ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import),
+ ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import),
+ ModuleDefId::MacroId(mac) => {
+ PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import))
+ }
}
}
}
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 c9b0f75f1..4c812b62a 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
@@ -64,11 +64,11 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
db::DefDatabase,
- generics::GenericParams,
+ generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
- BlockId,
+ BlockId, Lookup,
};
#[derive(Copy, Clone, Eq, PartialEq)]
@@ -143,6 +143,16 @@ impl ItemTree {
Arc::new(item_tree)
}
+ pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ let loc = block.lookup(db);
+ let block = loc.ast_id.to_node(db.upcast());
+
+ let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
+ let mut item_tree = ctx.lower_block(&block);
+ item_tree.shrink_to_fit();
+ Arc::new(item_tree)
+ }
+
/// Returns an iterator over all items located at the top level of the `HirFileId` this
/// `ItemTree` was created from.
pub fn top_level_items(&self) -> &[ModItem] {
@@ -167,7 +177,7 @@ impl ItemTree {
}
pub fn pretty_print(&self, db: &dyn DefDatabase) -> String {
- pretty::print_item_tree(db.upcast(), self)
+ pretty::print_item_tree(db, self)
}
fn data(&self) -> &ItemTreeData {
@@ -178,13 +188,6 @@ impl ItemTree {
self.data.get_or_insert_with(Box::default)
}
- fn block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
- let loc = db.lookup_intern_block(block);
- let block = loc.ast_id.to_node(db.upcast());
- let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
- Arc::new(ctx.lower_block(&block))
- }
-
fn shrink_to_fit(&mut self) {
if let Some(data) = &mut self.data {
let ItemTreeData {
@@ -296,10 +299,12 @@ pub enum AttrOwner {
Variant(Idx<Variant>),
Field(Idx<Field>),
Param(Idx<Param>),
+ TypeOrConstParamData(Idx<TypeOrConstParamData>),
+ LifetimeParamData(Idx<LifetimeParamData>),
}
macro_rules! from_attrs {
- ( $( $var:ident($t:ty) ),+ ) => {
+ ( $( $var:ident($t:ty) ),+ $(,)? ) => {
$(
impl From<$t> for AttrOwner {
fn from(t: $t) -> AttrOwner {
@@ -310,7 +315,14 @@ macro_rules! from_attrs {
};
}
-from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
+from_attrs!(
+ ModItem(ModItem),
+ Variant(Idx<Variant>),
+ Field(Idx<Field>),
+ Param(Idx<Param>),
+ TypeOrConstParamData(Idx<TypeOrConstParamData>),
+ LifetimeParamData(Idx<LifetimeParamData>),
+);
/// Trait implemented by all item nodes in the item tree.
pub trait ItemTreeNode: Clone {
@@ -373,7 +385,7 @@ impl TreeId {
pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
match self.block {
- Some(block) => ItemTree::block_item_tree(db, block),
+ Some(block) => db.block_item_tree_query(block),
None => db.file_item_tree(self.file),
}
}
@@ -761,6 +773,19 @@ impl Use {
lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree");
source_map[index].clone()
}
+ /// Maps a `UseTree` contained in this import back to its AST node.
+ pub fn use_tree_source_map(
+ &self,
+ db: &dyn DefDatabase,
+ file_id: HirFileId,
+ ) -> Arena<ast::UseTree> {
+ // Re-lower the AST item and get the source map.
+ // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
+ let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast());
+ let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
+ let hygiene = Hygiene::new(db.upcast(), file_id);
+ lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree").1
+ }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -785,7 +810,7 @@ impl UseTree {
fn expand_impl(
&self,
prefix: Option<ModPath>,
- cb: &mut dyn FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
+ cb: &mut impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
) {
fn concat_mod_paths(
prefix: Option<ModPath>,
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 7b898e62d..e4702c113 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
@@ -77,6 +77,9 @@ impl<'a> Ctx<'a> {
}
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
+ self.tree
+ .attrs
+ .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.hygiene()));
self.tree.top_level = block
.statements()
.filter_map(|stmt| match stmt {
@@ -602,7 +605,21 @@ impl<'a> Ctx<'a> {
generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
}
- generics.fill(&self.body_ctx, node);
+ let add_param_attrs = |item, param| {
+ let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.hygiene());
+ // This is identical to the body of `Ctx::add_attrs()` but we can't call that here
+ // because it requires `&mut self` and the call to `generics.fill()` below also
+ // references `self`.
+ match self.tree.attrs.entry(item) {
+ Entry::Occupied(mut entry) => {
+ *entry.get_mut() = entry.get().merge(attrs);
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(attrs);
+ }
+ }
+ };
+ generics.fill(&self.body_ctx, node, add_param_attrs);
generics.shrink_to_fit();
Interned::new(generics)
@@ -763,7 +780,7 @@ impl UseTreeLowering<'_> {
}
}
-pub(super) fn lower_use_tree(
+pub(crate) fn lower_use_tree(
db: &dyn DefDatabase,
hygiene: &Hygiene,
tree: ast::UseTree,
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 da30830fe..417bd37c8 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
@@ -2,8 +2,6 @@
use std::fmt::{self, Write};
-use hir_expand::db::ExpandDatabase;
-
use crate::{
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
pretty::{print_path, print_type_bounds, print_type_ref},
@@ -12,11 +10,11 @@ use crate::{
use super::*;
-pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String {
+pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
- p.print_attrs(attrs, true);
+ p.print_attrs(attrs, true, "\n");
}
p.blank();
@@ -45,7 +43,7 @@ macro_rules! wln {
}
struct Printer<'a> {
- db: &'a dyn ExpandDatabase,
+ db: &'a dyn DefDatabase,
tree: &'a ItemTree,
buf: String,
indent_level: usize,
@@ -84,28 +82,29 @@ impl Printer<'_> {
}
}
- fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
+ fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool, separated_by: &str) {
let inner = if inner { "!" } else { "" };
for attr in &**attrs {
- wln!(
+ w!(
self,
- "#{}[{}{}]",
+ "#{}[{}{}]{}",
inner,
- attr.path.display(self.db),
+ attr.path.display(self.db.upcast()),
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
+ separated_by,
);
}
}
- fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
+ fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
if let Some(attrs) = self.tree.attrs.get(&of.into()) {
- self.print_attrs(attrs, false);
+ self.print_attrs(attrs, false, separated_by);
}
}
fn print_visibility(&mut self, vis: RawVisibilityId) {
match &self.tree[vis] {
- RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db)),
+ RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())),
RawVisibility::Public => w!(self, "pub "),
};
}
@@ -118,9 +117,9 @@ impl Printer<'_> {
self.indented(|this| {
for field in fields.clone() {
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
- this.print_attrs_of(field);
+ this.print_attrs_of(field, "\n");
this.print_visibility(*visibility);
- w!(this, "{}: ", name.display(self.db));
+ w!(this, "{}: ", name.display(self.db.upcast()));
this.print_type_ref(type_ref);
wln!(this, ",");
}
@@ -132,9 +131,9 @@ impl Printer<'_> {
self.indented(|this| {
for field in fields.clone() {
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
- this.print_attrs_of(field);
+ this.print_attrs_of(field, "\n");
this.print_visibility(*visibility);
- w!(this, "{}: ", name.display(self.db));
+ w!(this, "{}: ", name.display(self.db.upcast()));
this.print_type_ref(type_ref);
wln!(this, ",");
}
@@ -167,20 +166,20 @@ impl Printer<'_> {
fn print_use_tree(&mut self, use_tree: &UseTree) {
match &use_tree.kind {
UseTreeKind::Single { path, alias } => {
- w!(self, "{}", path.display(self.db));
+ w!(self, "{}", path.display(self.db.upcast()));
if let Some(alias) = alias {
w!(self, " as {}", alias);
}
}
UseTreeKind::Glob { path } => {
if let Some(path) = path {
- w!(self, "{}::", path.display(self.db));
+ w!(self, "{}::", path.display(self.db.upcast()));
}
w!(self, "*");
}
UseTreeKind::Prefixed { prefix, list } => {
if let Some(prefix) = prefix {
- w!(self, "{}::", prefix.display(self.db));
+ w!(self, "{}::", prefix.display(self.db.upcast()));
}
w!(self, "{{");
for (i, tree) in list.iter().enumerate() {
@@ -195,7 +194,7 @@ impl Printer<'_> {
}
fn print_mod_item(&mut self, item: ModItem) {
- self.print_attrs_of(item);
+ self.print_attrs_of(item, "\n");
match item {
ModItem::Use(it) => {
@@ -208,7 +207,7 @@ impl Printer<'_> {
ModItem::ExternCrate(it) => {
let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "extern crate {}", name.display(self.db));
+ w!(self, "extern crate {}", name.display(self.db.upcast()));
if let Some(alias) = alias {
w!(self, " as {}", alias);
}
@@ -255,13 +254,13 @@ impl Printer<'_> {
if let Some(abi) = abi {
w!(self, "extern \"{}\" ", abi);
}
- w!(self, "fn {}", name.display(self.db));
+ w!(self, "fn {}", name.display(self.db.upcast()));
self.print_generic_params(explicit_generic_params);
w!(self, "(");
if !params.is_empty() {
self.indented(|this| {
for param in params.clone() {
- this.print_attrs_of(param);
+ this.print_attrs_of(param, "\n");
match &this.tree[param] {
Param::Normal(ty) => {
if flags.contains(FnFlags::HAS_SELF_PARAM) {
@@ -289,7 +288,7 @@ impl Printer<'_> {
ModItem::Struct(it) => {
let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "struct {}", name.display(self.db));
+ w!(self, "struct {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_fields_and_where_clause(fields, generic_params);
if matches!(fields, Fields::Record(_)) {
@@ -301,7 +300,7 @@ impl Printer<'_> {
ModItem::Union(it) => {
let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "union {}", name.display(self.db));
+ w!(self, "union {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_fields_and_where_clause(fields, generic_params);
if matches!(fields, Fields::Record(_)) {
@@ -313,14 +312,14 @@ impl Printer<'_> {
ModItem::Enum(it) => {
let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "enum {}", name.display(self.db));
+ w!(self, "enum {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for variant in variants.clone() {
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
- this.print_attrs_of(variant);
- w!(this, "{}", name.display(self.db));
+ this.print_attrs_of(variant, "\n");
+ w!(this, "{}", name.display(self.db.upcast()));
this.print_fields(fields);
wln!(this, ",");
}
@@ -332,7 +331,7 @@ impl Printer<'_> {
self.print_visibility(*visibility);
w!(self, "const ");
match name {
- Some(name) => w!(self, "{}", name.display(self.db)),
+ Some(name) => w!(self, "{}", name.display(self.db.upcast())),
None => w!(self, "_"),
}
w!(self, ": ");
@@ -346,7 +345,7 @@ impl Printer<'_> {
if *mutable {
w!(self, "mut ");
}
- w!(self, "{}: ", name.display(self.db));
+ w!(self, "{}: ", name.display(self.db.upcast()));
self.print_type_ref(type_ref);
w!(self, " = _;");
wln!(self);
@@ -368,7 +367,7 @@ impl Printer<'_> {
if *is_auto {
w!(self, "auto ");
}
- w!(self, "trait {}", name.display(self.db));
+ w!(self, "trait {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
@@ -381,7 +380,7 @@ impl Printer<'_> {
ModItem::TraitAlias(it) => {
let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "trait {}", name.display(self.db));
+ w!(self, "trait {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
w!(self, " = ");
self.print_where_clause(generic_params);
@@ -414,7 +413,7 @@ impl Printer<'_> {
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
&self.tree[it];
self.print_visibility(*visibility);
- w!(self, "type {}", name.display(self.db));
+ w!(self, "type {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
if !bounds.is_empty() {
w!(self, ": ");
@@ -431,7 +430,7 @@ impl Printer<'_> {
ModItem::Mod(it) => {
let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- w!(self, "mod {}", name.display(self.db));
+ w!(self, "mod {}", name.display(self.db.upcast()));
match kind {
ModKind::Inline { items } => {
w!(self, " {{");
@@ -449,16 +448,16 @@ impl Printer<'_> {
}
ModItem::MacroCall(it) => {
let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
- wln!(self, "{}!(...);", path.display(self.db));
+ wln!(self, "{}!(...);", path.display(self.db.upcast()));
}
ModItem::MacroRules(it) => {
let MacroRules { name, ast_id: _ } = &self.tree[it];
- wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db));
+ wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast()));
}
ModItem::MacroDef(it) => {
let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
self.print_visibility(*visibility);
- wln!(self, "macro {} {{ ... }}", name.display(self.db));
+ wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast()));
}
}
@@ -484,25 +483,27 @@ impl Printer<'_> {
w!(self, "<");
let mut first = true;
- for (_, lt) in params.lifetimes.iter() {
+ for (idx, lt) in params.lifetimes.iter() {
if !first {
w!(self, ", ");
}
first = false;
- w!(self, "{}", lt.name.display(self.db));
+ self.print_attrs_of(idx, " ");
+ w!(self, "{}", lt.name.display(self.db.upcast()));
}
for (idx, x) in params.type_or_consts.iter() {
if !first {
w!(self, ", ");
}
first = false;
+ self.print_attrs_of(idx, " ");
match x {
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
- Some(name) => w!(self, "{}", name.display(self.db)),
+ Some(name) => w!(self, "{}", name.display(self.db.upcast())),
None => w!(self, "_anon_{}", idx.into_raw()),
},
TypeOrConstParamData::ConstParamData(konst) => {
- w!(self, "const {}: ", konst.name.display(self.db));
+ w!(self, "const {}: ", konst.name.display(self.db.upcast()));
self.print_type_ref(&konst.ty);
}
}
@@ -537,8 +538,8 @@ impl Printer<'_> {
wln!(
this,
"{}: {},",
- target.name.display(self.db),
- bound.name.display(self.db)
+ target.name.display(self.db.upcast()),
+ bound.name.display(self.db.upcast())
);
continue;
}
@@ -548,7 +549,7 @@ impl Printer<'_> {
if i != 0 {
w!(this, ", ");
}
- w!(this, "{}", lt.display(self.db));
+ w!(this, "{}", lt.display(self.db.upcast()));
}
w!(this, "> ");
(target, bound)
@@ -559,7 +560,7 @@ impl Printer<'_> {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeOrConstParam(id) => {
match &params.type_or_consts[*id].name() {
- Some(name) => w!(this, "{}", name.display(self.db)),
+ Some(name) => w!(this, "{}", name.display(self.db.upcast())),
None => w!(this, "_anon_{}", id.into_raw()),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 5ded4b6b2..4180f8172 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -358,3 +358,15 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
"#]],
)
}
+
+#[test]
+fn generics_with_attributes() {
+ check(
+ r#"
+struct S<#[cfg(never)] T>;
+ "#,
+ expect![[r#"
+ pub(self) struct S<#[cfg(never)] T>;
+ "#]],
+ )
+}
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 627479bb7..1ae6bd4c9 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
@@ -2,6 +2,7 @@
//!
//! This attribute to tell the compiler about semi built-in std library
//! features, such as Fn family of traits.
+use hir_expand::name::Name;
use rustc_hash::FxHashMap;
use syntax::SmolStr;
use triomphe::Arc;
@@ -238,7 +239,17 @@ impl LangItem {
pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
let t = db.lang_item(start_crate, *self)?;
- Some(Path::LangItem(t))
+ Some(Path::LangItem(t, None))
+ }
+
+ pub fn ty_rel_path(
+ &self,
+ db: &dyn DefDatabase,
+ start_crate: CrateId,
+ seg: Name,
+ ) -> Option<Path> {
+ let t = db.lang_item(start_crate, *self)?;
+ Some(Path::LangItem(t, Some(seg)))
}
}
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 1901db8a0..3f87fe62b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -109,6 +109,17 @@ impl CrateRootModuleId {
}
}
+impl PartialEq<ModuleId> for CrateRootModuleId {
+ fn eq(&self, other: &ModuleId) -> bool {
+ other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
+ }
+}
+impl PartialEq<CrateRootModuleId> for ModuleId {
+ fn eq(&self, other: &CrateRootModuleId) -> bool {
+ other == self
+ }
+}
+
impl From<CrateRootModuleId> for ModuleId {
fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
ModuleId { krate, block: None, local_id: DefMap::ROOT }
@@ -854,14 +865,36 @@ impl_from!(
ConstId,
FunctionId,
TraitId,
+ TraitAliasId,
TypeAliasId,
MacroId(Macro2Id, MacroRulesId, ProcMacroId),
ImplId,
GenericParamId,
- ExternCrateId
+ ExternCrateId,
+ UseId
for AttrDefId
);
+impl TryFrom<ModuleDefId> for AttrDefId {
+ type Error = ();
+
+ fn try_from(value: ModuleDefId) -> Result<Self, Self::Error> {
+ match value {
+ ModuleDefId::ModuleId(it) => Ok(it.into()),
+ ModuleDefId::FunctionId(it) => Ok(it.into()),
+ ModuleDefId::AdtId(it) => Ok(it.into()),
+ ModuleDefId::EnumVariantId(it) => Ok(it.into()),
+ ModuleDefId::ConstId(it) => Ok(it.into()),
+ ModuleDefId::StaticId(it) => Ok(it.into()),
+ ModuleDefId::TraitId(it) => Ok(it.into()),
+ ModuleDefId::TypeAliasId(it) => Ok(it.into()),
+ ModuleDefId::TraitAliasId(id) => Ok(id.into()),
+ ModuleDefId::MacroId(id) => Ok(id.into()),
+ ModuleDefId::BuiltinType(_) => Err(()),
+ }
+ }
+}
+
impl From<ItemContainerId> for AttrDefId {
fn from(acid: ItemContainerId) -> Self {
match acid {
@@ -872,6 +905,15 @@ impl From<ItemContainerId> for AttrDefId {
}
}
}
+impl From<AssocItemId> for AttrDefId {
+ fn from(assoc: AssocItemId) -> Self {
+ match assoc {
+ AssocItemId::FunctionId(it) => AttrDefId::FunctionId(it),
+ AssocItemId::ConstId(it) => AttrDefId::ConstId(it),
+ AssocItemId::TypeAliasId(it) => AttrDefId::TypeAliasId(it),
+ }
+ }
+}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VariantId {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index e523c2291..52781d988 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,10 +1,11 @@
//! Context for lowering paths.
+use std::cell::OnceCell;
+
use hir_expand::{
ast_id_map::{AstIdMap, AstIdNode},
hygiene::Hygiene,
AstId, HirFileId, InFile,
};
-use once_cell::unsync::OnceCell;
use syntax::ast;
use triomphe::Arc;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 1250cbb74..4aedb22c6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -23,6 +23,45 @@ fn main() { 0 as u32; }
}
#[test]
+fn test_asm_expand() {
+ check(
+ r#"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+ let i: u64 = 3;
+ let o: u64;
+ unsafe {
+ asm!(
+ "mov {0}, {1}",
+ "add {0}, 5",
+ out(reg) o,
+ in(reg) i,
+ );
+ }
+}
+"#,
+ expect![[r##"
+#[rustc_builtin_macro]
+macro_rules! asm {() => {}}
+
+fn main() {
+ let i: u64 = 3;
+ let o: u64;
+ unsafe {
+ builtin #asm ( {
+ $crate::format_args!("mov {0}, {1}");
+ $crate::format_args!("add {0}, 5");
+ }
+ );
+ }
+}
+"##]],
+ );
+}
+
+#[test]
fn test_line_expand() {
check(
r#"
@@ -201,7 +240,7 @@ macro_rules! format_args {
}
fn main() {
- ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
+ builtin #format_args ("{} {:?}", arg1(a, b, c), arg2);
}
"##]],
);
@@ -219,10 +258,10 @@ macro_rules! format_args {
fn main() {
format_args!(x = 2);
- format_args!(x =);
- format_args!(x =, x = 2);
- format_args!("{}", x =);
- format_args!(=, "{}", x =);
+ format_args!/*+errors*/(x =);
+ format_args!/*+errors*/(x =, x = 2);
+ format_args!/*+errors*/("{}", x =);
+ format_args!/*+errors*/(=, "{}", x =);
format_args!(x = 2, "{}", 5);
}
"#,
@@ -234,12 +273,19 @@ macro_rules! format_args {
}
fn main() {
- /* error: no rule matches input tokens */;
- /* error: expected expression */;
- /* error: expected expression, expected COMMA */;
- /* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]);
- /* error: expected expression, expected expression */;
- ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
+ builtin #format_args (x = 2);
+ /* parse error: expected expression */
+builtin #format_args (x = );
+ /* parse error: expected expression */
+/* parse error: expected R_PAREN */
+/* parse error: expected expression, item or let statement */
+builtin #format_args (x = , x = 2);
+ /* parse error: expected expression */
+builtin #format_args ("{}", x = );
+ /* parse error: expected expression */
+/* parse error: expected expression */
+builtin #format_args ( = , "{}", x = );
+ builtin #format_args (x = 2, "{}", 5);
}
"##]],
);
@@ -267,7 +313,7 @@ macro_rules! format_args {
}
fn main() {
- ::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
+ builtin #format_args ("{} {:?}", a::<A, B>(), b);
}
"##]],
);
@@ -300,7 +346,7 @@ macro_rules! format_args {
}
fn main() {
- ::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
+ builtin #format_args (r#"{},mismatch,"{}","{}""#, location_csv_pat(db, &analysis, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db));
}
"##]],
);
@@ -334,7 +380,7 @@ macro_rules! format_args {
}
fn main() {
- ::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
+ builtin #format_args (concat!("xxx{}y", "{:?}zzz"), 2, b);
}
"##]],
);
@@ -364,8 +410,8 @@ macro_rules! format_args {
fn main() {
let _ =
- /* error: expected field name or number *//* parse error: expected field name or number */
-::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
+ /* parse error: expected field name or number */
+builtin #format_args ("{} {:?}", a.);
}
"##]],
);
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 2170cadcf..d09062132 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
@@ -117,7 +117,7 @@ fn main(foo: ()) {
macro_rules! format_args {}
fn main(foo: ()) {
- /* error: unresolved macro identity */::core::fmt::Arguments::new_v1(&["", " ", " ", ], &[::core::fmt::ArgumentV1::new(&(::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(0), ::core::fmt::Display::fmt), ])), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(foo), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(identity!(10)), ::core::fmt::Display::fmt), ])
+ builtin #format_args ("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
}
"##]],
);
@@ -150,8 +150,8 @@ macro_rules! identity {
}
fn main(foo: ()) {
- // format_args/*+tokenids*/!("{} {} {}"#1,#3 format_args!("{}", 0#10),#12 foo#13,#14 identity!(10#18),#21 "bar"#22)
-::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 " "#4294967295,#4294967295 " "#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#42949672950#10)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#4294967295foo#13)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#429496729510#18)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295
+ // format_args/*+tokenids*/!("{} {} {}"#1,#2 format_args#3!#4("{}"#6,#7 0#8),#9 foo#10,#11 identity#12!#13(10#15),#16 "bar"#17)
+builtin#4294967295 ##4294967295format_args#4294967295 (#0"{} {} {}"#1,#2 format_args#3!#4(#5"{}"#6,#7 0#8)#5,#9 foo#10,#11 identity#12!#13(#1410#15)#14,#16 "bar"#17)#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 d8e4a4dcc..b416f45ff 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
@@ -909,3 +909,64 @@ macro_rules! with_std {
"##]],
)
}
+
+#[test]
+fn eager_regression_15403() {
+ check(
+ r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+ format_args /* +errors */ !("{}", line.1.);
+}
+
+"#,
+ expect![[r##"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+ /* parse error: expected field name or number */
+builtin #format_args ("{}", line.1.);
+}
+
+"##]],
+ );
+}
+
+#[test]
+fn eager_regression_154032() {
+ check(
+ r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+ format_args /* +errors */ !("{}", &[0 2]);
+}
+
+"#,
+ expect![[r##"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+ /* parse error: expected COMMA */
+/* parse error: expected R_BRACK */
+/* parse error: expected COMMA */
+/* parse error: expected COMMA */
+/* parse error: expected expression */
+/* parse error: expected R_PAREN */
+/* parse error: expected expression, item or let statement */
+/* parse error: expected expression, item or let statement */
+builtin #format_args ("{}", &[0 2]);
+}
+
+"##]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 7a87e61c6..8adced4e0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -131,7 +131,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
.as_call_id_with_errors(&db, krate, |path| {
resolver
.resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang))
- .map(|it| macro_id_to_def_id(&db, it))
+ .map(|(it, _)| macro_id_to_def_id(&db, it))
})
.unwrap();
let macro_call_id = res.value.unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 86818ce26..9a9fa0e02 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -60,7 +60,7 @@ mod tests;
use std::{cmp::Ord, ops::Deref};
use base_db::{CrateId, Edition, FileId, ProcMacroKind};
-use hir_expand::{name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
+use hir_expand::{ast_id_map::FileAstId, name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
use itertools::Itertools;
use la_arena::Arena;
use profile::Count;
@@ -77,8 +77,8 @@ use crate::{
path::ModPath,
per_ns::PerNs,
visibility::Visibility,
- AstId, BlockId, BlockLoc, CrateRootModuleId, FunctionId, LocalModuleId, Lookup, MacroExpander,
- MacroId, ModuleId, ProcMacroId,
+ AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, LocalModuleId, Lookup,
+ MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
};
/// Contains the results of (early) name resolution.
@@ -93,7 +93,7 @@ use crate::{
#[derive(Debug, PartialEq, Eq)]
pub struct DefMap {
_c: Count<Self>,
- /// When this is a block def map, this will hold the block id of the the block and module that
+ /// When this is a block def map, this will hold the block id of the block and module that
/// contains this block.
block: Option<BlockInfo>,
/// The modules and their data declared in this crate.
@@ -105,10 +105,11 @@ pub struct DefMap {
/// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
/// but that attribute is nightly and when used in a block, it affects resolution globally
/// so we aren't handling this correctly anyways).
- prelude: Option<ModuleId>,
+ prelude: Option<(ModuleId, Option<UseId>)>,
/// `macro_use` prelude that contains macros from `#[macro_use]`'d external crates. Note that
/// this contains all kinds of macro, not just `macro_rules!` macro.
- macro_use_prelude: FxHashMap<Name, MacroId>,
+ /// ExternCrateId being None implies it being imported from the general prelude import.
+ macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
/// attributes.
@@ -125,7 +126,7 @@ pub struct DefMap {
#[derive(Clone, Debug, PartialEq, Eq)]
struct DefMapCrateData {
/// The extern prelude which contains all root modules of external crates that are in scope.
- extern_prelude: FxHashMap<Name, CrateRootModuleId>,
+ extern_prelude: FxHashMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
/// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
@@ -217,16 +218,17 @@ pub enum ModuleOrigin {
/// Note that non-inline modules, by definition, live inside non-macro file.
File {
is_mod_rs: bool,
- declaration: AstId<ast::Module>,
+ declaration: FileAstId<ast::Module>,
declaration_tree_id: ItemTreeId<Mod>,
definition: FileId,
},
Inline {
definition_tree_id: ItemTreeId<Mod>,
- definition: AstId<ast::Module>,
+ definition: FileAstId<ast::Module>,
},
/// Pseudo-module introduced by a block scope (contains only inner items).
BlockExpr {
+ id: BlockId,
block: AstId<ast::BlockExpr>,
},
}
@@ -234,8 +236,12 @@ pub enum ModuleOrigin {
impl ModuleOrigin {
pub fn declaration(&self) -> Option<AstId<ast::Module>> {
match self {
- ModuleOrigin::File { declaration: module, .. }
- | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
+ &ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
+ Some(AstId::new(declaration_tree_id.file_id(), declaration))
+ }
+ &ModuleOrigin::Inline { definition, definition_tree_id } => {
+ Some(AstId::new(definition_tree_id.file_id(), definition))
+ }
ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
}
}
@@ -260,16 +266,17 @@ impl ModuleOrigin {
/// That is, a file or a `mod foo {}` with items.
fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
match self {
- ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
- let file_id = *definition;
- let sf = db.parse(file_id).tree();
- InFile::new(file_id.into(), ModuleSource::SourceFile(sf))
+ &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
+ let sf = db.parse(definition).tree();
+ InFile::new(definition.into(), ModuleSource::SourceFile(sf))
}
- ModuleOrigin::Inline { definition, .. } => InFile::new(
- definition.file_id,
- ModuleSource::Module(definition.to_node(db.upcast())),
+ &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
+ definition_tree_id.file_id(),
+ ModuleSource::Module(
+ AstId::new(definition_tree_id.file_id(), definition).to_node(db.upcast()),
+ ),
),
- ModuleOrigin::BlockExpr { block } => {
+ ModuleOrigin::BlockExpr { block, .. } => {
InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
}
}
@@ -314,9 +321,7 @@ impl DefMap {
}
pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
- let block: BlockLoc = db.lookup_intern_block(block_id);
-
- let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
+ let block: BlockLoc = block_id.lookup(db);
let parent_map = block.module.def_map(db);
let krate = block.module.krate;
@@ -325,8 +330,10 @@ impl DefMap {
// modules declared by blocks with items. At the moment, we don't use
// this visibility for anything outside IDE, so that's probably OK.
let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
- let module_data =
- ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
+ let module_data = ModuleData::new(
+ ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
+ visibility,
+ );
let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data);
def_map.data = parent_map.data.clone();
@@ -338,7 +345,8 @@ impl DefMap {
},
});
- let def_map = collector::collect_defs(db, def_map, tree_id);
+ let def_map =
+ collector::collect_defs(db, def_map, TreeId::new(block.ast_id.file_id, Some(block_id)));
Arc::new(def_map)
}
@@ -427,15 +435,19 @@ impl DefMap {
self.block.map(|block| block.block)
}
- pub(crate) fn prelude(&self) -> Option<ModuleId> {
+ pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
self.prelude
}
- pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, ModuleId)> + '_ {
- self.data.extern_prelude.iter().map(|(name, &def)| (name, def.into()))
+ pub(crate) fn extern_prelude(
+ &self,
+ ) -> impl Iterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ {
+ self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
}
- pub(crate) fn macro_use_prelude(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
+ pub(crate) fn macro_use_prelude(
+ &self,
+ ) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
}
@@ -638,8 +650,8 @@ impl ModuleData {
ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
definition.into()
}
- ModuleOrigin::Inline { definition, .. } => definition.file_id,
- ModuleOrigin::BlockExpr { block } => block.file_id,
+ ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id.file_id(),
+ ModuleOrigin::BlockExpr { block, .. } => block.file_id,
}
}
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 eef54fc49..2d4586146 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
@@ -33,7 +33,7 @@ use crate::{
attr_macro_as_call_id,
db::DefDatabase,
derive_macro_as_call_id,
- item_scope::{ImportType, PerNsGlobImports},
+ item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
@@ -52,10 +52,10 @@ use crate::{
tt,
visibility::{RawVisibility, Visibility},
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
- ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
- LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc,
- ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc,
- TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc,
+ ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
+ ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
+ MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
+ StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
};
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -146,8 +146,8 @@ impl PartialResolvedImport {
#[derive(Clone, Debug, Eq, PartialEq)]
enum ImportSource {
- Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> },
- ExternCrate(ItemTreeId<item_tree::ExternCrate>),
+ Use { use_tree: Idx<ast::UseTree>, id: UseId, is_prelude: bool, kind: ImportKind },
+ ExternCrate { id: ExternCrateId },
}
#[derive(Debug, Eq, PartialEq)]
@@ -155,54 +155,41 @@ struct Import {
path: ModPath,
alias: Option<ImportAlias>,
visibility: RawVisibility,
- kind: ImportKind,
source: ImportSource,
- is_prelude: bool,
- is_macro_use: bool,
}
impl Import {
fn from_use(
- db: &dyn DefDatabase,
- krate: CrateId,
tree: &ItemTree,
- id: ItemTreeId<item_tree::Use>,
+ item_tree_id: ItemTreeId<item_tree::Use>,
+ id: UseId,
+ is_prelude: bool,
mut cb: impl FnMut(Self),
) {
- let it = &tree[id.value];
- let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
+ let it = &tree[item_tree_id.value];
let visibility = &tree[it.visibility];
- let is_prelude = attrs.by_key("prelude_import").exists();
it.use_tree.expand(|idx, path, kind, alias| {
cb(Self {
path,
alias,
visibility: visibility.clone(),
- kind,
- is_prelude,
- is_macro_use: false,
- source: ImportSource::Use { id, use_tree: idx },
+ source: ImportSource::Use { use_tree: idx, id, is_prelude, kind },
});
});
}
fn from_extern_crate(
- db: &dyn DefDatabase,
- krate: CrateId,
tree: &ItemTree,
- id: ItemTreeId<item_tree::ExternCrate>,
+ item_tree_id: ItemTreeId<item_tree::ExternCrate>,
+ id: ExternCrateId,
) -> Self {
- let it = &tree[id.value];
- let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
+ let it = &tree[item_tree_id.value];
let visibility = &tree[it.visibility];
Self {
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
alias: it.alias.clone(),
visibility: visibility.clone(),
- kind: ImportKind::Plain,
- is_prelude: false,
- is_macro_use: attrs.by_key("macro_use").exists(),
- source: ImportSource::ExternCrate(id),
+ source: ImportSource::ExternCrate { id },
}
}
}
@@ -235,7 +222,7 @@ struct DefCollector<'a> {
db: &'a dyn DefDatabase,
def_map: DefMap,
deps: FxHashMap<Name, Dependency>,
- glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
+ glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
unresolved_imports: Vec<ImportDirective>,
indeterminate_imports: Vec<ImportDirective>,
unresolved_macros: Vec<MacroDirective>,
@@ -280,7 +267,7 @@ impl DefCollector<'_> {
if dep.is_prelude() {
crate_data
.extern_prelude
- .insert(name.clone(), CrateRootModuleId { krate: dep.crate_id });
+ .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
}
}
@@ -556,8 +543,12 @@ impl DefCollector<'_> {
self.def_map.resolve_path(self.db, DefMap::ROOT, &path, BuiltinShadowMode::Other, None);
match per_ns.types {
- Some((ModuleDefId::ModuleId(m), _)) => {
- self.def_map.prelude = Some(m);
+ Some((ModuleDefId::ModuleId(m), _, import)) => {
+ // FIXME: This should specifically look for a glob import somehow and record that here
+ self.def_map.prelude = Some((
+ m,
+ import.and_then(ImportOrExternCrate::into_import).map(|it| it.import),
+ ));
}
types => {
tracing::debug!(
@@ -657,9 +648,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
Visibility::Public,
- ImportType::Named,
+ None,
);
}
}
@@ -693,9 +684,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
vis,
- ImportType::Named,
+ None,
);
}
@@ -708,9 +699,9 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.declare(macro_.into());
self.update(
module_id,
- &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
+ &[(Some(name), PerNs::macros(macro_.into(), Visibility::Public, None))],
Visibility::Public,
- ImportType::Named,
+ None,
);
}
@@ -720,21 +711,29 @@ impl DefCollector<'_> {
/// Exported macros are just all macros in the root module scope.
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
/// created by `use` in the root module, ignoring the visibility of `use`.
- fn import_macros_from_extern_crate(&mut self, krate: CrateId, names: Option<Vec<Name>>) {
+ fn import_macros_from_extern_crate(
+ &mut self,
+ krate: CrateId,
+ names: Option<Vec<Name>>,
+ extern_crate: Option<ExternCrateId>,
+ ) {
let def_map = self.db.crate_def_map(krate);
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
// macros.
let root_scope = &def_map[DefMap::ROOT].scope;
- if let Some(names) = names {
- for name in names {
- // FIXME: Report diagnostic on 404.
- if let Some(def) = root_scope.get(&name).take_macros() {
- self.def_map.macro_use_prelude.insert(name, def);
+ match names {
+ Some(names) => {
+ for name in names {
+ // FIXME: Report diagnostic on 404.
+ if let Some(def) = root_scope.get(&name).take_macros() {
+ self.def_map.macro_use_prelude.insert(name, (def, extern_crate));
+ }
}
}
- } else {
- for (name, def) in root_scope.macros() {
- self.def_map.macro_use_prelude.insert(name.clone(), def);
+ None => {
+ for (name, def) in root_scope.macros() {
+ self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
+ }
}
}
}
@@ -771,48 +770,53 @@ impl DefCollector<'_> {
let _p = profile::span("resolve_import")
.detail(|| format!("{}", import.path.display(self.db.upcast())));
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
- if matches!(import.source, ImportSource::ExternCrate { .. }) {
- let name = import
- .path
- .as_ident()
- .expect("extern crate should have been desugared to one-element path");
-
- let res = self.resolve_extern_crate(name);
-
- match res {
- Some(res) => {
- PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
+ match import.source {
+ ImportSource::ExternCrate { .. } => {
+ let name = import
+ .path
+ .as_ident()
+ .expect("extern crate should have been desugared to one-element path");
+
+ let res = self.resolve_extern_crate(name);
+
+ match res {
+ Some(res) => PartialResolvedImport::Resolved(PerNs::types(
+ res.into(),
+ Visibility::Public,
+ None,
+ )),
+ None => PartialResolvedImport::Unresolved,
}
- None => PartialResolvedImport::Unresolved,
}
- } else {
- let res = self.def_map.resolve_path_fp_with_macro(
- self.db,
- ResolveMode::Import,
- module_id,
- &import.path,
- BuiltinShadowMode::Module,
- None, // An import may resolve to any kind of macro.
- );
+ ImportSource::Use { .. } => {
+ let res = self.def_map.resolve_path_fp_with_macro(
+ self.db,
+ ResolveMode::Import,
+ module_id,
+ &import.path,
+ BuiltinShadowMode::Module,
+ None, // An import may resolve to any kind of macro.
+ );
- let def = res.resolved_def;
- if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
- return PartialResolvedImport::Unresolved;
- }
+ let def = res.resolved_def;
+ if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
+ return PartialResolvedImport::Unresolved;
+ }
- if let Some(krate) = res.krate {
- if krate != self.def_map.krate {
- return PartialResolvedImport::Resolved(
- def.filter_visibility(|v| matches!(v, Visibility::Public)),
- );
+ if let Some(krate) = res.krate {
+ if krate != self.def_map.krate {
+ return PartialResolvedImport::Resolved(
+ def.filter_visibility(|v| matches!(v, Visibility::Public)),
+ );
+ }
}
- }
- // Check whether all namespaces are resolved.
- if def.is_full() {
- PartialResolvedImport::Resolved(def)
- } else {
- PartialResolvedImport::Indeterminate(def)
+ // Check whether all namespaces are resolved.
+ if def.is_full() {
+ PartialResolvedImport::Resolved(def)
+ } else {
+ PartialResolvedImport::Indeterminate(def)
+ }
}
}
}
@@ -837,8 +841,9 @@ impl DefCollector<'_> {
.resolve_visibility(self.db, module_id, &directive.import.visibility, false)
.unwrap_or(Visibility::Public);
- match import.kind {
- ImportKind::Plain | ImportKind::TypeOnly => {
+ match import.source {
+ ImportSource::ExternCrate { .. }
+ | ImportSource::Use { kind: ImportKind::Plain | ImportKind::TypeOnly, .. } => {
let name = match &import.alias {
Some(ImportAlias::Alias(name)) => Some(name),
Some(ImportAlias::Underscore) => None,
@@ -851,40 +856,44 @@ impl DefCollector<'_> {
},
};
- if import.kind == ImportKind::TypeOnly {
- def.values = None;
- def.macros = None;
- }
-
- tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
-
- // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
- if matches!(import.source, ImportSource::ExternCrate { .. })
- && self.def_map.block.is_none()
- && module_id == DefMap::ROOT
- {
- if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
- {
- if let Ok(def) = def.try_into() {
- Arc::get_mut(&mut self.def_map.data)
- .unwrap()
- .extern_prelude
- .insert(name.clone(), def);
+ let imp = match import.source {
+ // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
+ ImportSource::ExternCrate { id, .. } => {
+ if self.def_map.block.is_none() && module_id == DefMap::ROOT {
+ if let (Some(ModuleDefId::ModuleId(def)), Some(name)) =
+ (def.take_types(), name)
+ {
+ if let Ok(def) = def.try_into() {
+ Arc::get_mut(&mut self.def_map.data)
+ .unwrap()
+ .extern_prelude
+ .insert(name.clone(), (def, Some(id)));
+ }
+ }
}
+ ImportType::ExternCrate(id)
}
- }
+ ImportSource::Use { kind, id, use_tree, .. } => {
+ if kind == ImportKind::TypeOnly {
+ def.values = None;
+ def.macros = None;
+ }
+ ImportType::Import(ImportId { import: id, idx: use_tree })
+ }
+ };
+ tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
- self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named);
+ self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
}
- ImportKind::Glob => {
+ ImportSource::Use { kind: ImportKind::Glob, id, .. } => {
tracing::debug!("glob import: {:?}", import);
match def.take_types() {
Some(ModuleDefId::ModuleId(m)) => {
- if import.is_prelude {
+ if let ImportSource::Use { id, is_prelude: true, .. } = import.source {
// Note: This dodgily overrides the injected prelude. The rustc
// implementation seems to work the same though.
cov_mark::hit!(std_prelude);
- self.def_map.prelude = Some(m);
+ self.def_map.prelude = Some((m, Some(id)));
} else if m.krate != self.def_map.krate {
cov_mark::hit!(glob_across_crates);
// glob import from other crate => we can just import everything once
@@ -901,7 +910,7 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::<Vec<_>>();
- self.update(module_id, &items, vis, ImportType::Glob);
+ self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
} else {
// glob import from same crate => we do an initial
// import, and then need to propagate any further
@@ -933,11 +942,11 @@ impl DefCollector<'_> {
.filter(|(_, res)| !res.is_none())
.collect::<Vec<_>>();
- self.update(module_id, &items, vis, ImportType::Glob);
+ self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
// record the glob import in case we add further items
let glob = self.glob_imports.entry(m.local_id).or_default();
- if !glob.iter().any(|(mid, _)| *mid == module_id) {
- glob.push((module_id, vis));
+ if !glob.iter().any(|(mid, _, _)| *mid == module_id) {
+ glob.push((module_id, vis, id));
}
}
}
@@ -959,11 +968,11 @@ impl DefCollector<'_> {
.map(|(local_id, variant_data)| {
let name = variant_data.name.clone();
let variant = EnumVariantId { parent: e, local_id };
- let res = PerNs::both(variant.into(), variant.into(), vis);
+ let res = PerNs::both(variant.into(), variant.into(), vis, None);
(Some(name), res)
})
.collect::<Vec<_>>();
- self.update(module_id, &resolutions, vis, ImportType::Glob);
+ self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
}
Some(d) => {
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -983,10 +992,10 @@ impl DefCollector<'_> {
resolutions: &[(Option<Name>, PerNs)],
// Visibility this import will have
vis: Visibility,
- import_type: ImportType,
+ import: Option<ImportType>,
) {
self.db.unwind_if_cancelled();
- self.update_recursive(module_id, resolutions, vis, import_type, 0)
+ self.update_recursive(module_id, resolutions, vis, import, 0)
}
fn update_recursive(
@@ -997,7 +1006,7 @@ impl DefCollector<'_> {
// All resolutions are imported with this visibility; the visibilities in
// the `PerNs` values are ignored and overwritten
vis: Visibility,
- import_type: ImportType,
+ import: Option<ImportType>,
depth: usize,
) {
if GLOB_RECURSION_LIMIT.check(depth).is_err() {
@@ -1014,7 +1023,7 @@ impl DefCollector<'_> {
&mut self.from_glob_import,
(module_id, name.clone()),
res.with_visibility(vis),
- import_type,
+ import,
);
}
None => {
@@ -1059,7 +1068,7 @@ impl DefCollector<'_> {
.get(&module_id)
.into_iter()
.flatten()
- .filter(|(glob_importing_module, _)| {
+ .filter(|(glob_importing_module, _, _)| {
// we know all resolutions have the same visibility (`vis`), so we
// just need to check that once
vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
@@ -1067,12 +1076,12 @@ impl DefCollector<'_> {
.cloned()
.collect::<Vec<_>>();
- for (glob_importing_module, glob_import_vis) in glob_imports {
+ for (glob_importing_module, glob_import_vis, use_) in glob_imports {
self.update_recursive(
glob_importing_module,
resolutions,
glob_import_vis,
- ImportType::Glob,
+ Some(ImportType::Glob(use_)),
depth + 1,
);
}
@@ -1460,31 +1469,34 @@ impl DefCollector<'_> {
// heuristic, but it works in practice.
let mut diagnosed_extern_crates = FxHashSet::default();
for directive in &self.unresolved_imports {
- if let ImportSource::ExternCrate(krate) = directive.import.source {
- let item_tree = krate.item_tree(self.db);
- let extern_crate = &item_tree[krate.value];
+ if let ImportSource::ExternCrate { id } = directive.import.source {
+ let item_tree_id = id.lookup(self.db).id;
+ let item_tree = item_tree_id.item_tree(self.db);
+ let extern_crate = &item_tree[item_tree_id.value];
diagnosed_extern_crates.insert(extern_crate.name.clone());
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
directive.module_id,
- InFile::new(krate.file_id(), extern_crate.ast_id),
+ InFile::new(item_tree_id.file_id(), extern_crate.ast_id),
));
}
}
for directive in &self.unresolved_imports {
- if let ImportSource::Use { id: import, use_tree } = directive.import.source {
+ if let ImportSource::Use { use_tree, id, is_prelude: _, kind: _ } =
+ directive.import.source
+ {
if matches!(
(directive.import.path.segments().first(), &directive.import.path.kind),
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
) {
continue;
}
-
+ let item_tree_id = id.lookup(self.db).id;
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
directive.module_id,
- import,
+ item_tree_id,
use_tree,
));
}
@@ -1519,72 +1531,66 @@ impl ModCollector<'_, '_> {
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
// Prelude module is always considered to be `#[macro_use]`.
- if let Some(prelude_module) = self.def_collector.def_map.prelude {
+ if let Some((prelude_module, _use)) = self.def_collector.def_map.prelude {
if prelude_module.krate != krate && is_crate_root {
cov_mark::hit!(prelude_is_macro_use);
- self.def_collector.import_macros_from_extern_crate(prelude_module.krate, None);
- }
- }
-
- // This should be processed eagerly instead of deferred to resolving.
- // `#[macro_use] extern crate` is hoisted to imports macros before collecting
- // any other items.
- //
- // If we're not at the crate root, `macro_use`d extern crates are an error so let's just
- // ignore them.
- if is_crate_root {
- for &item in items {
- if let ModItem::ExternCrate(id) = item {
- self.process_macro_use_extern_crate(id);
- }
+ self.def_collector.import_macros_from_extern_crate(
+ prelude_module.krate,
+ None,
+ None,
+ );
}
}
+ let db = self.def_collector.db;
+ let module_id = self.module_id;
+ let update_def =
+ |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
+ def_collector.def_map.modules[module_id].scope.declare(id);
+ def_collector.update(
+ module_id,
+ &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor, None))],
+ vis,
+ None,
+ )
+ };
+ let resolve_vis = |def_map: &DefMap, visibility| {
+ def_map
+ .resolve_visibility(db, module_id, visibility, false)
+ .unwrap_or(Visibility::Public)
+ };
- for &item in items {
- let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
+ let mut process_mod_item = |item: ModItem| {
+ let attrs = self.item_tree.attrs(db, krate, item.into());
if let Some(cfg) = attrs.cfg() {
if !self.is_cfg_enabled(&cfg) {
self.emit_unconfigured_diagnostic(item, &cfg);
- continue;
+ return;
}
}
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
// Do not process the item. It has at least one non-builtin attribute, so the
// fixed-point algorithm is required to resolve the rest of them.
- continue;
+ return;
}
- let db = self.def_collector.db;
- let module = self.def_collector.def_map.module_id(self.module_id);
+ let module = self.def_collector.def_map.module_id(module_id);
let def_map = &mut self.def_collector.def_map;
- let update_def =
- |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
- def_collector.def_map.modules[self.module_id].scope.declare(id);
- def_collector.update(
- self.module_id,
- &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
- vis,
- ImportType::Named,
- )
- };
- let resolve_vis = |def_map: &DefMap, visibility| {
- def_map
- .resolve_visibility(db, self.module_id, visibility, false)
- .unwrap_or(Visibility::Public)
- };
match item {
ModItem::Mod(m) => self.collect_module(m, &attrs),
- ModItem::Use(import_id) => {
- let _import_id =
- UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) }
- .intern(db);
+ ModItem::Use(item_tree_id) => {
+ let id = UseLoc {
+ container: module,
+ id: ItemTreeId::new(self.tree_id, item_tree_id),
+ }
+ .intern(db);
+ let is_prelude = attrs.by_key("prelude_import").exists();
Import::from_use(
- db,
- krate,
self.item_tree,
- ItemTreeId::new(self.tree_id, import_id),
+ ItemTreeId::new(self.tree_id, item_tree_id),
+ id,
+ is_prelude,
|import| {
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
@@ -1594,22 +1600,29 @@ impl ModCollector<'_, '_> {
},
)
}
- ModItem::ExternCrate(import_id) => {
- let extern_crate_id = ExternCrateLoc {
+ ModItem::ExternCrate(item_tree_id) => {
+ let id = ExternCrateLoc {
container: module,
- id: ItemTreeId::new(self.tree_id, import_id),
+ id: ItemTreeId::new(self.tree_id, item_tree_id),
}
.intern(db);
+ if is_crate_root {
+ self.process_macro_use_extern_crate(
+ item_tree_id,
+ id,
+ attrs.by_key("macro_use").attrs(),
+ );
+ }
+
self.def_collector.def_map.modules[self.module_id]
.scope
- .define_extern_crate_decl(extern_crate_id);
+ .define_extern_crate_decl(id);
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
import: Import::from_extern_crate(
- db,
- krate,
self.item_tree,
- ItemTreeId::new(self.tree_id, import_id),
+ ItemTreeId::new(self.tree_id, item_tree_id),
+ id,
),
status: PartialResolvedImport::Unresolved,
})
@@ -1768,21 +1781,34 @@ impl ModCollector<'_, '_> {
);
}
}
+ };
+
+ // extern crates should be processed eagerly instead of deferred to resolving.
+ // `#[macro_use] extern crate` is hoisted to imports macros before collecting
+ // any other items.
+ if is_crate_root {
+ items
+ .iter()
+ .filter(|it| matches!(it, ModItem::ExternCrate(..)))
+ .copied()
+ .for_each(&mut process_mod_item);
+ items
+ .iter()
+ .filter(|it| !matches!(it, ModItem::ExternCrate(..)))
+ .copied()
+ .for_each(process_mod_item);
+ } else {
+ items.iter().copied().for_each(process_mod_item);
}
}
- fn process_macro_use_extern_crate(&mut self, extern_crate: FileItemTreeId<ExternCrate>) {
+ fn process_macro_use_extern_crate<'a>(
+ &mut self,
+ extern_crate: FileItemTreeId<ExternCrate>,
+ extern_crate_id: ExternCrateId,
+ macro_use_attrs: impl Iterator<Item = &'a Attr>,
+ ) {
let db = self.def_collector.db;
- let attrs = self.item_tree.attrs(
- db,
- self.def_collector.def_map.krate,
- ModItem::from(extern_crate).into(),
- );
- if let Some(cfg) = attrs.cfg() {
- if !self.is_cfg_enabled(&cfg) {
- return;
- }
- }
let target_crate =
match self.def_collector.resolve_extern_crate(&self.item_tree[extern_crate].name) {
@@ -1798,11 +1824,15 @@ impl ModCollector<'_, '_> {
let mut single_imports = Vec::new();
let hygiene = Hygiene::new_unhygienic();
- for attr in attrs.by_key("macro_use").attrs() {
+ for attr in macro_use_attrs {
let Some(paths) = attr.parse_path_comma_token_tree(db.upcast(), &hygiene) else {
// `#[macro_use]` (without any paths) found, forget collected names and just import
// all visible macros.
- self.def_collector.import_macros_from_extern_crate(target_crate, None);
+ self.def_collector.import_macros_from_extern_crate(
+ target_crate,
+ None,
+ Some(extern_crate_id),
+ );
return;
};
for path in paths {
@@ -1812,7 +1842,11 @@ impl ModCollector<'_, '_> {
}
}
- self.def_collector.import_macros_from_extern_crate(target_crate, Some(single_imports));
+ self.def_collector.import_macros_from_extern_crate(
+ target_crate,
+ Some(single_imports),
+ Some(extern_crate_id),
+ );
}
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
@@ -1824,7 +1858,7 @@ impl ModCollector<'_, '_> {
ModKind::Inline { items } => {
let module_id = self.push_child_module(
module.name.clone(),
- AstId::new(self.file_id(), module.ast_id),
+ module.ast_id,
None,
&self.item_tree[module.visibility],
module_id,
@@ -1862,7 +1896,7 @@ impl ModCollector<'_, '_> {
if is_enabled {
let module_id = self.push_child_module(
module.name.clone(),
- ast_id,
+ ast_id.value,
Some((file_id, is_mod_rs)),
&self.item_tree[module.visibility],
module_id,
@@ -1889,7 +1923,7 @@ impl ModCollector<'_, '_> {
Err(candidates) => {
self.push_child_module(
module.name.clone(),
- ast_id,
+ ast_id.value,
None,
&self.item_tree[module.visibility],
module_id,
@@ -1906,7 +1940,7 @@ impl ModCollector<'_, '_> {
fn push_child_module(
&mut self,
name: Name,
- declaration: AstId<ast::Module>,
+ declaration: FileAstId<ast::Module>,
definition: Option<(FileId, bool)>,
visibility: &crate::visibility::RawVisibility,
mod_tree_id: FileItemTreeId<Mod>,
@@ -1948,9 +1982,9 @@ impl ModCollector<'_, '_> {
def_map.modules[self.module_id].scope.declare(def);
self.def_collector.update(
self.module_id,
- &[(Some(name), PerNs::from_def(def, vis, false))],
+ &[(Some(name), PerNs::from_def(def, vis, false, None))],
vis,
- ImportType::Named,
+ None,
);
res
}
@@ -2198,7 +2232,7 @@ impl ModCollector<'_, '_> {
map[module].scope.get_legacy_macro(name)?.last().copied()
})
.or_else(|| def_map[self.module_id].scope.get(name).take_macros())
- .or_else(|| def_map.macro_use_prelude.get(name).copied())
+ .or_else(|| Some(def_map.macro_use_prelude.get(name).copied()?.0))
.filter(|&id| {
sub_namespace_match(
Some(MacroSubNs::from_id(db, id)),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index de22ea101..460a908b6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -15,8 +15,9 @@ use hir_expand::name::Name;
use triomphe::Arc;
use crate::{
+ data::adt::VariantData,
db::DefDatabase,
- item_scope::BUILTIN_SCOPE,
+ item_scope::{ImportOrExternCrate, BUILTIN_SCOPE},
nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs},
path::{ModPath, PathKind},
per_ns::PerNs,
@@ -65,7 +66,7 @@ impl PerNs {
db: &dyn DefDatabase,
expected: Option<MacroSubNs>,
) -> Self {
- self.macros = self.macros.filter(|&(id, _)| {
+ self.macros = self.macros.filter(|&(id, _, _)| {
let this = MacroSubNs::from_id(db, id);
sub_namespace_match(Some(this), expected)
});
@@ -196,15 +197,15 @@ impl DefMap {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
cov_mark::hit!(macro_dollar_crate_self);
- PerNs::types(self.crate_root().into(), Visibility::Public)
+ PerNs::types(self.crate_root().into(), Visibility::Public, None)
} else {
let def_map = db.crate_def_map(krate);
let module = def_map.module_id(Self::ROOT);
cov_mark::hit!(macro_dollar_crate_other);
- PerNs::types(module.into(), Visibility::Public)
+ PerNs::types(module.into(), Visibility::Public, None)
}
}
- PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public),
+ PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public, None),
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
@@ -291,7 +292,7 @@ impl DefMap {
);
}
- PerNs::types(module.into(), Visibility::Public)
+ PerNs::types(module.into(), Visibility::Public, None)
}
PathKind::Abs => {
// 2018-style absolute path -- only extern prelude
@@ -299,9 +300,13 @@ impl DefMap {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
- if let Some(&def) = self.data.extern_prelude.get(segment) {
+ if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
- PerNs::types(def.into(), Visibility::Public)
+ PerNs::types(
+ def.into(),
+ Visibility::Public,
+ extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
} else {
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
}
@@ -309,7 +314,7 @@ impl DefMap {
};
for (i, segment) in segments {
- let (curr, vis) = match curr_per_ns.take_types_vis() {
+ let (curr, vis, imp) = match curr_per_ns.take_types_full() {
Some(r) => r,
None => {
// we still have path segments left, but the path so far
@@ -364,18 +369,20 @@ impl DefMap {
Some(local_id) => {
let variant = EnumVariantId { parent: e, local_id };
match &*enum_data.variants[local_id].variant_data {
- crate::data::adt::VariantData::Record(_) => {
- PerNs::types(variant.into(), Visibility::Public)
- }
- crate::data::adt::VariantData::Tuple(_)
- | crate::data::adt::VariantData::Unit => {
- PerNs::both(variant.into(), variant.into(), Visibility::Public)
+ VariantData::Record(_) => {
+ PerNs::types(variant.into(), Visibility::Public, None)
}
+ VariantData::Tuple(_) | VariantData::Unit => PerNs::both(
+ variant.into(),
+ variant.into(),
+ Visibility::Public,
+ None,
+ ),
}
}
None => {
return ResolvePathResult::with(
- PerNs::types(e.into(), vis),
+ PerNs::types(e.into(), vis, imp),
ReachedFixedPoint::Yes,
Some(i),
Some(self.krate),
@@ -393,7 +400,7 @@ impl DefMap {
);
return ResolvePathResult::with(
- PerNs::types(s, vis),
+ PerNs::types(s, vis, imp),
ReachedFixedPoint::Yes,
Some(i),
Some(self.krate),
@@ -430,7 +437,7 @@ impl DefMap {
.filter(|&id| {
sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns)
})
- .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
+ .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public, None));
let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
let from_builtin = match self.block {
Some(_) => {
@@ -449,18 +456,27 @@ impl DefMap {
let extern_prelude = || {
if self.block.is_some() {
- // Don't resolve extern prelude in block `DefMap`s.
+ // Don't resolve extern prelude in block `DefMap`s, defer it to the crate def map so
+ // that blocks can properly shadow them
return PerNs::none();
}
- self.data
- .extern_prelude
- .get(name)
- .map_or(PerNs::none(), |&it| PerNs::types(it.into(), Visibility::Public))
+ self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
+ PerNs::types(
+ it.into(),
+ Visibility::Public,
+ extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
+ })
};
let macro_use_prelude = || {
- self.macro_use_prelude
- .get(name)
- .map_or(PerNs::none(), |&it| PerNs::macros(it.into(), Visibility::Public))
+ self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
+ PerNs::macros(
+ it.into(),
+ Visibility::Public,
+ // FIXME?
+ None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
+ })
};
let prelude = || self.resolve_in_prelude(db, name);
@@ -488,18 +504,23 @@ impl DefMap {
// Don't resolve extern prelude in block `DefMap`s.
return PerNs::none();
}
- self.data
- .extern_prelude
- .get(name)
- .copied()
- .map_or(PerNs::none(), |it| PerNs::types(it.into(), Visibility::Public))
+ self.data.extern_prelude.get(name).copied().map_or(
+ PerNs::none(),
+ |(it, extern_crate)| {
+ PerNs::types(
+ it.into(),
+ Visibility::Public,
+ extern_crate.map(ImportOrExternCrate::ExternCrate),
+ )
+ },
+ )
};
from_crate_root.or_else(from_extern_prelude)
}
fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
- if let Some(prelude) = self.prelude {
+ if let Some((prelude, _use)) = self.prelude {
let keep;
let def_map = if prelude.krate == self.krate {
self
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 dd7c3c363..e7cc44b04 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
@@ -168,7 +168,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Foo: t v
+ Foo: ti vi
foo: t
crate::foo
@@ -194,8 +194,8 @@ pub enum Quux {};
"#,
expect![[r#"
crate
- Baz: t v
- Quux: t
+ Baz: ti vi
+ Quux: ti
foo: t
crate::foo
@@ -225,11 +225,11 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: ti vi
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -274,7 +274,7 @@ use self::E::V;
expect![[r#"
crate
E: t
- V: t v
+ V: ti vi
"#]],
);
}
@@ -307,7 +307,7 @@ pub struct FromLib;
crate::foo
Bar: _
- FromLib: t v
+ FromLib: ti vi
"#]],
);
}
@@ -328,7 +328,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t
+ Baz: ti
foo: t
crate::foo
@@ -352,7 +352,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: ti vi
"#]],
);
}
@@ -375,13 +375,13 @@ pub struct Arc;
expect![[r#"
crate
alloc: t
- alloc_crate: t
+ alloc_crate: te
sync: t
crate::alloc
crate::sync
- Arc: t v
+ Arc: ti vi
"#]],
);
}
@@ -404,13 +404,13 @@ pub struct Arc;
expect![[r#"
crate
alloc: t
- alloc_crate: t
+ alloc_crate: te
sync: t
crate::alloc
crate::sync
- Arc: t v
+ Arc: ti vi
"#]],
);
}
@@ -426,7 +426,7 @@ extern crate self as bla;
"#,
expect![[r#"
crate
- bla: t
+ bla: te
"#]],
);
}
@@ -447,7 +447,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: ti vi
"#]],
);
}
@@ -465,7 +465,7 @@ pub struct Bar;
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
foo: v
"#]],
);
@@ -492,9 +492,9 @@ fn no_std_prelude() {
}
"#,
expect![[r#"
- crate
- Rust: t v
- "#]],
+ crate
+ Rust: ti vi
+ "#]],
);
}
@@ -516,9 +516,9 @@ fn edition_specific_preludes() {
}
"#,
expect![[r#"
- crate
- Rust2018: t v
- "#]],
+ crate
+ Rust2018: ti vi
+ "#]],
);
check(
r#"
@@ -533,9 +533,9 @@ fn edition_specific_preludes() {
}
"#,
expect![[r#"
- crate
- Rust2021: t v
- "#]],
+ crate
+ Rust2021: ti vi
+ "#]],
);
}
@@ -563,8 +563,8 @@ pub mod prelude {
"#,
expect![[r#"
crate
- Bar: t v
- Foo: t v
+ Bar: ti vi
+ Foo: ti vi
"#]],
);
}
@@ -590,7 +590,7 @@ pub mod prelude {
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
Baz: _
Foo: _
"#]],
@@ -619,8 +619,8 @@ pub mod prelude {
expect![[r#"
crate
Bar: _
- Baz: t v
- Foo: t v
+ Baz: ti vi
+ Foo: ti vi
"#]],
);
}
@@ -643,7 +643,7 @@ mod b {
"#,
expect![[r#"
crate
- T: t v
+ T: ti vi
a: t
b: t
@@ -816,8 +816,8 @@ fn bar() {}
expect![[r#"
crate
bar: v
- baz: v
- foo: t
+ baz: vi
+ foo: ti
"#]],
);
}
@@ -836,7 +836,7 @@ use self::m::S::{self};
"#,
expect![[r#"
crate
- S: t
+ S: ti
m: t
crate::m
@@ -860,8 +860,8 @@ pub const settings: () = ();
"#,
expect![[r#"
crate
- Settings: t v
- settings: v
+ Settings: ti vi
+ settings: vi
"#]],
)
}
@@ -890,8 +890,8 @@ pub struct Struct;
"#,
expect![[r#"
crate
- Struct: t v
- dep: t
+ Struct: ti vi
+ dep: te
"#]],
);
}
@@ -917,13 +917,13 @@ use some_module::unknown_func;
crate
other_module: t
some_module: t
- unknown_func: v
+ unknown_func: vi
crate::other_module
some_submodule: t
crate::other_module::some_submodule
- unknown_func: v
+ unknown_func: vi
crate::some_module
unknown_func: v
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index 88a3c7639..1ca74b5da 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -24,7 +24,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
Foo: t v
bar: t
@@ -237,9 +237,9 @@ pub mod baz { pub struct Bar; }
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
bar: t
- baz: t
+ baz: ti
foo: t
crate::bar
@@ -276,9 +276,9 @@ pub mod baz { pub struct Bar; }
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
bar: t
- baz: t
+ baz: ti
foo: t
crate::bar
@@ -323,7 +323,7 @@ mod d {
X: t v
crate::b
- foo: t
+ foo: ti
crate::c
foo: t
@@ -332,8 +332,8 @@ mod d {
Y: t v
crate::d
- Y: t v
- foo: t
+ Y: ti vi
+ foo: ti
"#]],
);
}
@@ -355,7 +355,7 @@ use event::Event;
"#,
expect![[r#"
crate
- Event: t
+ Event: ti
event: t
crate::event
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 40d3a1654..4a86f88e5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -212,7 +212,7 @@ pub type Ty = ();
}
for (_, res) in module_data.scope.resolutions() {
- match res.values.or(res.types).unwrap().0 {
+ match res.values.map(|(a, _, _)| a).or(res.types.map(|(a, _, _)| a)).unwrap() {
ModuleDefId::FunctionId(f) => _ = db.function_data(f),
ModuleDefId::AdtId(adt) => match adt {
AdtId::StructId(it) => _ = db.struct_data(it),
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 f4cca8d68..e64fa0b46 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
@@ -203,8 +203,8 @@ macro_rules! bar {
expect![[r#"
crate
Foo: t
- bar: m
- foo: m
+ bar: mi
+ foo: mi
"#]],
);
}
@@ -251,7 +251,7 @@ mod priv_mod {
Bar: t v
Foo: t v
bar: t
- foo: t
+ foo: te
crate::bar
Baz: t v
@@ -318,9 +318,9 @@ macro_rules! baz3 { () => { struct OkBaz3; } }
OkBaz1: t v
OkBaz2: t v
OkBaz3: t v
- all: t
- empty: t
- multiple: t
+ all: te
+ empty: te
+ multiple: te
"#]],
);
}
@@ -551,8 +551,8 @@ fn baz() {}
"#,
expect![[r#"
crate
- bar: t m
- baz: t v m
+ bar: ti mi
+ baz: ti v mi
foo: t m
"#]],
);
@@ -583,7 +583,7 @@ mod m {
crate
Alias: t v
Direct: t v
- foo: t
+ foo: te
"#]],
);
}
@@ -628,9 +628,9 @@ mod m {
m: t
crate::m
- alias1: m
- alias2: m
- alias3: m
+ alias1: mi
+ alias2: mi
+ alias3: mi
not_found: _
"#]],
);
@@ -682,11 +682,11 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Bar: t v
- Baz: t v
+ Bar: ti vi
+ Baz: ti vi
Foo: t v
- FooSelf: t v
- foo: t
+ FooSelf: ti vi
+ foo: te
m: t
crate::m
@@ -725,7 +725,7 @@ pub struct bar;
"#,
expect![[r#"
crate
- bar: t v
+ bar: ti vi
"#]],
);
}
@@ -1340,7 +1340,7 @@ pub mod prelude {
crate
Ok: t v
bar: m
- dep: t
+ dep: te
foo: m
ok: v
"#]],
@@ -1370,13 +1370,13 @@ macro_rules! mk_foo {
}
"#,
expect![[r#"
- crate
- a: t
- lib: t
+ crate
+ a: t
+ lib: te
- crate::a
- Ok: t v
- "#]],
+ crate::a
+ Ok: t v
+ "#]],
);
}
@@ -1427,8 +1427,8 @@ pub mod prelude {
expect![[r#"
crate
Ok: t v
- bar: m
- foo: m
+ bar: mi
+ foo: mi
ok: v
"#]],
);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index 81bc0ff91..1327d9aa6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -80,18 +80,18 @@ pub trait Iterator;
prelude: t
crate::iter
- Iterator: t
+ Iterator: ti
traits: t
crate::iter::traits
- Iterator: t
+ Iterator: ti
iterator: t
crate::iter::traits::iterator
Iterator: t
crate::prelude
- Iterator: t
+ Iterator: ti
"#]],
);
}
@@ -109,7 +109,7 @@ pub struct Bar;
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
foo: t
crate::foo
@@ -139,7 +139,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
r#async: t
crate::r#async
@@ -176,8 +176,8 @@ pub struct Bar;
"#,
expect![[r#"
crate
- Bar: t v
- Foo: t v
+ Bar: ti vi
+ Foo: ti vi
r#async: t
crate::r#async
@@ -207,7 +207,7 @@ pub struct Bar;
"#,
expect![[r#"
crate
- Bar: t v
+ Bar: ti vi
foo: t
crate::foo
@@ -236,7 +236,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -265,7 +265,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -292,7 +292,7 @@ use super::Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
"#]],
);
}
@@ -626,7 +626,7 @@ pub struct Baz;
"#,
expect![[r#"
crate
- Baz: t v
+ Baz: ti vi
foo: t
crate::foo
@@ -660,7 +660,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -694,7 +694,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -728,7 +728,7 @@ pub struct Baz;
foo: t
crate::foo
- Baz: t v
+ Baz: ti vi
bar: t
crate::foo::bar
@@ -868,7 +868,7 @@ pub mod hash { pub trait Hash {} }
"#,
expect![[r#"
crate
- Hash: t
+ Hash: ti
core: t
crate::core
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs
index 215e8952d..271eb1c79 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/primitives.rs
@@ -14,10 +14,10 @@ pub use i32 as int;
expect![[r#"
crate
foo: t
- int: t
+ int: ti
crate::foo
- int: t
+ int: ti
"#]],
);
}
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 06530cc7e..3894172a5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -47,7 +47,7 @@ pub enum Path {
},
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
/// links via a normal path since they might be private and not accessible in the usage place.
- LangItem(LangItemTarget),
+ LangItem(LangItemTarget, Option<Name>),
}
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -122,33 +122,40 @@ impl Path {
pub fn kind(&self) -> &PathKind {
match self {
Path::Normal { mod_path, .. } => &mod_path.kind,
- Path::LangItem(_) => &PathKind::Abs,
+ Path::LangItem(..) => &PathKind::Abs,
}
}
pub fn type_anchor(&self) -> Option<&TypeRef> {
match self {
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
- Path::LangItem(_) => None,
+ Path::LangItem(..) => None,
}
}
pub fn segments(&self) -> PathSegments<'_> {
- let Path::Normal { mod_path, generic_args, .. } = self else {
- return PathSegments { segments: &[], generic_args: None };
- };
- let s =
- PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() };
- if let Some(generic_args) = s.generic_args {
- assert_eq!(s.segments.len(), generic_args.len());
+ match self {
+ Path::Normal { mod_path, generic_args, .. } => {
+ let s = PathSegments {
+ segments: mod_path.segments(),
+ generic_args: generic_args.as_deref(),
+ };
+ if let Some(generic_args) = s.generic_args {
+ assert_eq!(s.segments.len(), generic_args.len());
+ }
+ s
+ }
+ Path::LangItem(_, seg) => PathSegments {
+ segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
+ generic_args: None,
+ },
}
- s
}
pub fn mod_path(&self) -> Option<&ModPath> {
match self {
Path::Normal { mod_path, .. } => Some(&mod_path),
- Path::LangItem(_) => None,
+ Path::LangItem(..) => None,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
index 2bc1f8e92..14890364d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
@@ -3,13 +3,24 @@
//!
//! `PerNs` (per namespace) captures this.
-use crate::{item_scope::ItemInNs, visibility::Visibility, MacroId, ModuleDefId};
+use crate::{
+ item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
+ visibility::Visibility,
+ MacroId, ModuleDefId,
+};
+
+#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
+pub enum Namespace {
+ Types,
+ Values,
+ Macros,
+}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PerNs {
- pub types: Option<(ModuleDefId, Visibility)>,
- pub values: Option<(ModuleDefId, Visibility)>,
- pub macros: Option<(MacroId, Visibility)>,
+ pub types: Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
+ pub values: Option<(ModuleDefId, Visibility, Option<ImportId>)>,
+ pub macros: Option<(MacroId, Visibility, Option<ImportId>)>,
}
impl Default for PerNs {
@@ -23,20 +34,29 @@ impl PerNs {
PerNs { types: None, values: None, macros: None }
}
- pub fn values(t: ModuleDefId, v: Visibility) -> PerNs {
- PerNs { types: None, values: Some((t, v)), macros: None }
+ pub fn values(t: ModuleDefId, v: Visibility, i: Option<ImportId>) -> PerNs {
+ PerNs { types: None, values: Some((t, v, i)), macros: None }
}
- pub fn types(t: ModuleDefId, v: Visibility) -> PerNs {
- PerNs { types: Some((t, v)), values: None, macros: None }
+ pub fn types(t: ModuleDefId, v: Visibility, i: Option<ImportOrExternCrate>) -> PerNs {
+ PerNs { types: Some((t, v, i)), values: None, macros: None }
}
- pub fn both(types: ModuleDefId, values: ModuleDefId, v: Visibility) -> PerNs {
- PerNs { types: Some((types, v)), values: Some((values, v)), macros: None }
+ pub fn both(
+ types: ModuleDefId,
+ values: ModuleDefId,
+ v: Visibility,
+ i: Option<ImportOrExternCrate>,
+ ) -> PerNs {
+ PerNs {
+ types: Some((types, v, i)),
+ values: Some((values, v, i.and_then(ImportOrExternCrate::into_import))),
+ macros: None,
+ }
}
- pub fn macros(macro_: MacroId, v: Visibility) -> PerNs {
- PerNs { types: None, values: None, macros: Some((macro_, v)) }
+ pub fn macros(macro_: MacroId, v: Visibility, i: Option<ImportId>) -> PerNs {
+ PerNs { types: None, values: None, macros: Some((macro_, v, i)) }
}
pub fn is_none(&self) -> bool {
@@ -51,7 +71,7 @@ impl PerNs {
self.types.map(|it| it.0)
}
- pub fn take_types_vis(self) -> Option<(ModuleDefId, Visibility)> {
+ pub fn take_types_full(self) -> Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)> {
self.types
}
@@ -59,24 +79,32 @@ impl PerNs {
self.values.map(|it| it.0)
}
+ pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportId>)> {
+ self.values.map(|it| (it.0, it.2))
+ }
+
pub fn take_macros(self) -> Option<MacroId> {
self.macros.map(|it| it.0)
}
+ pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportId>)> {
+ self.macros.map(|it| (it.0, it.2))
+ }
+
pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
let _p = profile::span("PerNs::filter_visibility");
PerNs {
- types: self.types.filter(|(_, v)| f(*v)),
- values: self.values.filter(|(_, v)| f(*v)),
- macros: self.macros.filter(|(_, v)| f(*v)),
+ types: self.types.filter(|&(_, v, _)| f(v)),
+ values: self.values.filter(|&(_, v, _)| f(v)),
+ macros: self.macros.filter(|&(_, v, _)| f(v)),
}
}
pub fn with_visibility(self, vis: Visibility) -> PerNs {
PerNs {
- types: self.types.map(|(it, _)| (it, vis)),
- values: self.values.map(|(it, _)| (it, vis)),
- macros: self.macros.map(|(it, _)| (it, vis)),
+ types: self.types.map(|(it, _, c)| (it, vis, c)),
+ values: self.values.map(|(it, _, c)| (it, vis, c)),
+ macros: self.macros.map(|(it, _, import)| (it, vis, import)),
}
}
@@ -96,12 +124,20 @@ impl PerNs {
}
}
- pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> {
+ pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
let _p = profile::span("PerNs::iter_items");
self.types
- .map(|it| ItemInNs::Types(it.0))
+ .map(|it| (ItemInNs::Types(it.0), it.2))
.into_iter()
- .chain(self.values.map(|it| ItemInNs::Values(it.0)).into_iter())
- .chain(self.macros.map(|it| ItemInNs::Macros(it.0)).into_iter())
+ .chain(
+ self.values
+ .map(|it| (ItemInNs::Values(it.0), it.2.map(ImportOrExternCrate::Import)))
+ .into_iter(),
+ )
+ .chain(
+ self.macros
+ .map(|it| (ItemInNs::Macros(it.0), it.2.map(ImportOrExternCrate::Import)))
+ .into_iter(),
+ )
}
}
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 11d58a6ba..f4f5541e3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -2,18 +2,54 @@
use std::fmt::{self, Write};
-use hir_expand::{db::ExpandDatabase, mod_path::PathKind};
+use hir_expand::mod_path::PathKind;
use intern::Interned;
use itertools::Itertools;
use crate::{
+ db::DefDatabase,
+ lang_item::LangItemTarget,
path::{GenericArg, GenericArgs, Path},
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
};
-pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
- if let Path::LangItem(it) = path {
- return write!(buf, "$lang_item::{it:?}");
+pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
+ if let Path::LangItem(it, s) = path {
+ write!(buf, "builtin#lang(")?;
+ match *it {
+ LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
+ LangItemTarget::EnumId(it) => {
+ write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::Function(it) => {
+ write!(buf, "{}", db.function_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::Static(it) => {
+ write!(buf, "{}", db.static_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::Struct(it) => {
+ write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::Union(it) => {
+ write!(buf, "{}", db.union_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::TypeAlias(it) => {
+ write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::Trait(it) => {
+ write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))?
+ }
+ LangItemTarget::EnumVariant(it) => write!(
+ buf,
+ "{}",
+ db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast())
+ )?,
+ }
+
+ if let Some(s) = s {
+ write!(buf, "::{}", s.display(db.upcast()))?;
+ }
+ return write!(buf, ")");
}
match path.type_anchor() {
Some(anchor) => {
@@ -44,7 +80,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
write!(buf, "::")?;
}
- write!(buf, "{}", segment.name.display(db))?;
+ write!(buf, "{}", segment.name.display(db.upcast()))?;
if let Some(generics) = segment.args_and_bindings {
write!(buf, "::<")?;
print_generic_args(db, generics, buf)?;
@@ -57,7 +93,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
}
pub(crate) fn print_generic_args(
- db: &dyn ExpandDatabase,
+ db: &dyn DefDatabase,
generics: &GenericArgs,
buf: &mut dyn Write,
) -> fmt::Result {
@@ -83,7 +119,7 @@ pub(crate) fn print_generic_args(
write!(buf, ", ")?;
}
first = false;
- write!(buf, "{}", binding.name.display(db))?;
+ write!(buf, "{}", binding.name.display(db.upcast()))?;
if !binding.bounds.is_empty() {
write!(buf, ": ")?;
print_type_bounds(db, &binding.bounds, buf)?;
@@ -97,19 +133,19 @@ pub(crate) fn print_generic_args(
}
pub(crate) fn print_generic_arg(
- db: &dyn ExpandDatabase,
+ db: &dyn DefDatabase,
arg: &GenericArg,
buf: &mut dyn Write,
) -> fmt::Result {
match arg {
GenericArg::Type(ty) => print_type_ref(db, ty, buf),
- GenericArg::Const(c) => write!(buf, "{}", c.display(db)),
- GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db)),
+ GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())),
+ GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())),
}
}
pub(crate) fn print_type_ref(
- db: &dyn ExpandDatabase,
+ db: &dyn DefDatabase,
type_ref: &TypeRef,
buf: &mut dyn Write,
) -> fmt::Result {
@@ -143,7 +179,7 @@ pub(crate) fn print_type_ref(
};
write!(buf, "&")?;
if let Some(lt) = lt {
- write!(buf, "{} ", lt.name.display(db))?;
+ write!(buf, "{} ", lt.name.display(db.upcast()))?;
}
write!(buf, "{mtbl}")?;
print_type_ref(db, pointee, buf)?;
@@ -151,7 +187,7 @@ pub(crate) fn print_type_ref(
TypeRef::Array(elem, len) => {
write!(buf, "[")?;
print_type_ref(db, elem, buf)?;
- write!(buf, "; {}]", len.display(db))?;
+ write!(buf, "; {}]", len.display(db.upcast()))?;
}
TypeRef::Slice(elem) => {
write!(buf, "[")?;
@@ -198,7 +234,7 @@ pub(crate) fn print_type_ref(
}
pub(crate) fn print_type_bounds(
- db: &dyn ExpandDatabase,
+ db: &dyn DefDatabase,
bounds: &[Interned<TypeBound>],
buf: &mut dyn Write,
) -> fmt::Result {
@@ -216,10 +252,14 @@ pub(crate) fn print_type_bounds(
print_path(db, path, buf)?;
}
TypeBound::ForLifetime(lifetimes, path) => {
- write!(buf, "for<{}> ", lifetimes.iter().map(|it| it.display(db)).format(", "))?;
+ write!(
+ buf,
+ "for<{}> ",
+ lifetimes.iter().map(|it| it.display(db.upcast())).format(", ")
+ )?;
print_path(db, path, buf)?;
}
- TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db))?,
+ TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?,
TypeBound::Error => write!(buf, "{{unknown}}")?,
}
}
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 b112c1070..50da9ed06 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -12,20 +12,21 @@ use triomphe::Arc;
use crate::{
body::scope::{ExprScopes, ScopeId},
builtin_type::BuiltinType,
+ data::ExternCrateDeclData,
db::DefDatabase,
generics::{GenericParams, TypeOrConstParamData},
hir::{BindingId, ExprId, LabelId},
- item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
+ item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
lang_item::LangItemTarget,
nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
- AdtId, AssocItemId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
- EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
- HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId,
- MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId,
- TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
+ AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
+ ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
+ ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId,
+ ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
+ TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
};
#[derive(Debug, Clone)]
@@ -100,8 +101,8 @@ pub enum TypeNs {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ResolveValueResult {
- ValueNs(ValueNs),
- Partial(TypeNs, usize),
+ ValueNs(ValueNs, Option<ImportId>),
+ Partial(TypeNs, usize, Option<ImportOrExternCrate>),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -148,56 +149,26 @@ impl Resolver {
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
}
- // FIXME: This shouldn't exist
- pub fn resolve_module_path_in_trait_assoc_items(
- &self,
- db: &dyn DefDatabase,
- path: &ModPath,
- ) -> Option<PerNs> {
- let (item_map, module) = self.item_scope();
- let (module_res, idx) =
- item_map.resolve_path(db, module, path, BuiltinShadowMode::Module, None);
- match module_res.take_types()? {
- ModuleDefId::TraitId(it) => {
- let idx = idx?;
- let unresolved = &path.segments()[idx..];
- let assoc = match unresolved {
- [it] => it,
- _ => return None,
- };
- let &(_, assoc) = db.trait_data(it).items.iter().find(|(n, _)| n == assoc)?;
- Some(match assoc {
- AssocItemId::FunctionId(it) => PerNs::values(it.into(), Visibility::Public),
- AssocItemId::ConstId(it) => PerNs::values(it.into(), Visibility::Public),
- AssocItemId::TypeAliasId(it) => PerNs::types(it.into(), Visibility::Public),
- })
- }
- _ => None,
- }
- }
-
pub fn resolve_path_in_type_ns(
&self,
db: &dyn DefDatabase,
path: &Path,
- ) -> Option<(TypeNs, Option<usize>)> {
+ ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
- Path::LangItem(l) => {
- return Some((
- match *l {
- LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
- LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
- LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
- LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
- LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
- LangItemTarget::Trait(it) => TypeNs::TraitId(it),
- LangItemTarget::Function(_)
- | LangItemTarget::ImplDef(_)
- | LangItemTarget::Static(_) => return None,
- },
- None,
- ))
+ Path::LangItem(l, seg) => {
+ let type_ns = match *l {
+ LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
+ LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
+ LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::Trait(it) => TypeNs::TraitId(it),
+ LangItemTarget::Function(_)
+ | LangItemTarget::ImplDef(_)
+ | LangItemTarget::Static(_) => return None,
+ };
+ return Some((type_ns, seg.as_ref().map(|_| 1), None));
}
};
let first_name = path.segments().first()?;
@@ -213,17 +184,17 @@ impl Resolver {
Scope::ExprScope(_) => continue,
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
- return Some((TypeNs::GenericParam(id), remaining_idx()));
+ return Some((TypeNs::GenericParam(id), remaining_idx(), None));
}
}
&Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] {
- return Some((TypeNs::SelfType(impl_), remaining_idx()));
+ return Some((TypeNs::SelfType(impl_), remaining_idx(), None));
}
}
&Scope::AdtScope(adt) => {
if first_name == &name![Self] {
- return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
+ return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None));
}
}
Scope::BlockScope(m) => {
@@ -236,12 +207,24 @@ impl Resolver {
self.module_scope.resolve_path_in_type_ns(db, path)
}
+ pub fn resolve_path_in_type_ns_fully_with_imports(
+ &self,
+ db: &dyn DefDatabase,
+ path: &Path,
+ ) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
+ let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?;
+ if unresolved.is_some() {
+ return None;
+ }
+ Some((res, imp))
+ }
+
pub fn resolve_path_in_type_ns_fully(
&self,
db: &dyn DefDatabase,
path: &Path,
) -> Option<TypeNs> {
- let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
+ let (res, unresolved, _) = self.resolve_path_in_type_ns(db, path)?;
if unresolved.is_some() {
return None;
}
@@ -263,7 +246,6 @@ impl Resolver {
RawVisibility::Public => Some(Visibility::Public),
}
}
-
pub fn resolve_path_in_value_ns(
&self,
db: &dyn DefDatabase,
@@ -271,18 +253,35 @@ impl Resolver {
) -> Option<ResolveValueResult> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
- Path::LangItem(l) => {
- return Some(ResolveValueResult::ValueNs(match *l {
- LangItemTarget::Function(it) => ValueNs::FunctionId(it),
- LangItemTarget::Static(it) => ValueNs::StaticId(it),
- LangItemTarget::Struct(it) => ValueNs::StructId(it),
- LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it),
- LangItemTarget::Union(_)
+ Path::LangItem(l, None) => {
+ return Some(ResolveValueResult::ValueNs(
+ match *l {
+ LangItemTarget::Function(it) => ValueNs::FunctionId(it),
+ LangItemTarget::Static(it) => ValueNs::StaticId(it),
+ LangItemTarget::Struct(it) => ValueNs::StructId(it),
+ LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it),
+ LangItemTarget::Union(_)
+ | LangItemTarget::ImplDef(_)
+ | LangItemTarget::TypeAlias(_)
+ | LangItemTarget::Trait(_)
+ | LangItemTarget::EnumId(_) => return None,
+ },
+ None,
+ ))
+ }
+ Path::LangItem(l, Some(_)) => {
+ let type_ns = match *l {
+ LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
+ LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
+ LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
+ LangItemTarget::Trait(it) => TypeNs::TraitId(it),
+ LangItemTarget::Function(_)
| LangItemTarget::ImplDef(_)
- | LangItemTarget::TypeAlias(_)
- | LangItemTarget::Trait(_)
- | LangItemTarget::EnumId(_) => return None,
- }))
+ | LangItemTarget::Static(_) => return None,
+ };
+ return Some(ResolveValueResult::Partial(type_ns, 1, None));
}
};
let n_segments = path.segments().len();
@@ -304,20 +303,24 @@ impl Resolver {
.find(|entry| entry.name() == first_name);
if let Some(e) = entry {
- return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(
- e.binding(),
- )));
+ return Some(ResolveValueResult::ValueNs(
+ ValueNs::LocalBinding(e.binding()),
+ None,
+ ));
}
}
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam(id);
- return Some(ResolveValueResult::ValueNs(val));
+ return Some(ResolveValueResult::ValueNs(val, None));
}
}
&Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] {
- return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)));
+ return Some(ResolveValueResult::ValueNs(
+ ValueNs::ImplSelf(impl_),
+ None,
+ ));
}
}
// bare `Self` doesn't work in the value namespace in a struct/enum definition
@@ -336,18 +339,22 @@ impl Resolver {
Scope::GenericParams { params, def } => {
if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam(id);
- return Some(ResolveValueResult::Partial(ty, 1));
+ return Some(ResolveValueResult::Partial(ty, 1, None));
}
}
&Scope::ImplDefScope(impl_) => {
if first_name == &name![Self] {
- return Some(ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1));
+ return Some(ResolveValueResult::Partial(
+ TypeNs::SelfType(impl_),
+ 1,
+ None,
+ ));
}
}
Scope::AdtScope(adt) => {
if first_name == &name![Self] {
let ty = TypeNs::AdtSelfType(*adt);
- return Some(ResolveValueResult::Partial(ty, 1));
+ return Some(ResolveValueResult::Partial(ty, 1, None));
}
}
Scope::BlockScope(m) => {
@@ -368,7 +375,7 @@ impl Resolver {
// `use core::u16;`.
if path.kind == PathKind::Plain && n_segments > 1 {
if let Some(builtin) = BuiltinType::by_name(first_name) {
- return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
+ return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None));
}
}
@@ -381,7 +388,7 @@ impl Resolver {
path: &Path,
) -> Option<ValueNs> {
match self.resolve_path_in_value_ns(db, path)? {
- ResolveValueResult::ValueNs(it) => Some(it),
+ ResolveValueResult::ValueNs(it, _) => Some(it),
ResolveValueResult::Partial(..) => None,
}
}
@@ -391,12 +398,12 @@ impl Resolver {
db: &dyn DefDatabase,
path: &ModPath,
expected_macro_kind: Option<MacroSubNs>,
- ) -> Option<MacroId> {
+ ) -> Option<(MacroId, Option<ImportId>)> {
let (item_map, module) = self.item_scope();
item_map
.resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
.0
- .take_macros()
+ .take_macros_import()
}
/// Returns a set of names available in the current scope.
@@ -456,21 +463,22 @@ impl Resolver {
def_map[module_id].scope.entries().for_each(|(name, def)| {
res.add_per_ns(name, def);
});
+
def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
})
});
- def_map.macro_use_prelude().for_each(|(name, def)| {
+ def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| {
res.add(name, ScopeDef::ModuleDef(def.into()));
});
- def_map.extern_prelude().for_each(|(name, def)| {
- res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
+ def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
+ res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
res.add_per_ns(name, def);
});
- if let Some(prelude) = def_map.prelude() {
+ if let Some((prelude, _use)) = def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
res.add_per_ns(name, def)
@@ -479,6 +487,23 @@ impl Resolver {
res.map
}
+ pub fn extern_crate_decls_in_scope<'a>(
+ &'a self,
+ db: &'a dyn DefDatabase,
+ ) -> impl Iterator<Item = Name> + 'a {
+ self.module_scope.def_map[self.module_scope.module_id]
+ .scope
+ .extern_crate_decls()
+ .map(|id| ExternCrateDeclData::extern_crate_decl_data_query(db, id).name.clone())
+ }
+
+ pub fn extern_crates_in_scope<'a>(&'a self) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
+ self.module_scope
+ .def_map
+ .extern_prelude()
+ .map(|(name, module_id)| (name.clone(), module_id.0.into()))
+ }
+
pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
// FIXME(trait_alias): Trait alias brings aliased traits in scope! Note that supertraits of
// aliased traits are NOT brought in scope (unless also aliased).
@@ -501,7 +526,7 @@ impl Resolver {
}
// Fill in the prelude traits
- if let Some(prelude) = self.module_scope.def_map.prelude() {
+ if let Some((prelude, _use)) = self.module_scope.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
traits.extend(prelude_def_map[prelude.local_id].scope.traits());
}
@@ -804,11 +829,12 @@ impl ModuleItemMap {
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
match idx {
None => {
- let value = to_value_ns(module_def)?;
- Some(ResolveValueResult::ValueNs(value))
+ let (value, import) = to_value_ns(module_def)?;
+ Some(ResolveValueResult::ValueNs(value, import))
}
Some(idx) => {
- let ty = match module_def.take_types()? {
+ let (def, _, import) = module_def.take_types_full()?;
+ let ty = match def {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it),
@@ -822,7 +848,7 @@ impl ModuleItemMap {
| ModuleDefId::MacroId(_)
| ModuleDefId::StaticId(_) => return None,
};
- Some(ResolveValueResult::Partial(ty, idx))
+ Some(ResolveValueResult::Partial(ty, idx, import))
}
}
}
@@ -831,16 +857,17 @@ impl ModuleItemMap {
&self,
db: &dyn DefDatabase,
path: &ModPath,
- ) -> Option<(TypeNs, Option<usize>)> {
+ ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
let (module_def, idx) =
self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
- let res = to_type_ns(module_def)?;
- Some((res, idx))
+ let (res, import) = to_type_ns(module_def)?;
+ Some((res, idx, import))
}
}
-fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
- let res = match per_ns.take_values()? {
+fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportId>)> {
+ let (def, import) = per_ns.take_values_import()?;
+ let res = match def {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
@@ -855,11 +882,12 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
| ModuleDefId::MacroId(_)
| ModuleDefId::ModuleId(_) => return None,
};
- Some(res)
+ Some((res, import))
}
-fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
- let res = match per_ns.take_types()? {
+fn to_type_ns(per_ns: PerNs) -> Option<(TypeNs, Option<ImportOrExternCrate>)> {
+ let (def, _, import) = per_ns.take_types_full()?;
+ let res = match def {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
@@ -875,7 +903,7 @@ fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
- Some(res)
+ Some((res, import))
}
type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
@@ -892,13 +920,13 @@ impl ScopeNames {
}
}
fn add_per_ns(&mut self, name: &Name, def: PerNs) {
- if let &Some((ty, _)) = &def.types {
+ if let &Some((ty, _, _)) = &def.types {
self.add(name, ScopeDef::ModuleDef(ty))
}
- if let &Some((def, _)) = &def.values {
+ if let &Some((def, _, _)) = &def.values {
self.add(name, ScopeDef::ModuleDef(def))
}
- if let &Some((mac, _)) = &def.macros {
+ if let &Some((mac, _, _)) = &def.macros {
self.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)))
}
if def.is_none() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
index 6047f770d..3770103cd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
@@ -5,8 +5,8 @@ use la_arena::ArenaMap;
use syntax::ast;
use crate::{
- db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Macro2Loc, MacroRulesLoc,
- ProcMacroLoc,
+ db::DefDatabase, item_tree::ItemTreeNode, AssocItemLoc, ItemLoc, Lookup, Macro2Loc,
+ MacroRulesLoc, ProcMacroLoc, UseId,
};
pub trait HasSource {
@@ -83,3 +83,18 @@ pub trait HasChildSource<ChildId> {
type Value;
fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
}
+
+impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
+ type Value = ast::UseTree;
+ fn child_source(
+ &self,
+ db: &dyn DefDatabase,
+ ) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> {
+ let loc = &self.lookup(db);
+ let use_ = &loc.id.item_tree(db)[loc.id.value];
+ InFile::new(
+ loc.id.file_id(),
+ use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(),
+ )
+ }
+}