summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-def
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/adt.rs244
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs362
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs1
21 files changed, 629 insertions, 240 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index e8cff2f3e..4ad8e7597 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -15,17 +15,17 @@ arrayvec = "0.7.2"
bitflags = "1.3.2"
cov-mark = "2.0.0-pre.1"
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
-dashmap = { version = "=5.3.4", features = ["raw-api"] }
+dashmap = { version = "=5.4.0", features = ["raw-api"] }
drop_bomb = "0.1.5"
either = "1.7.0"
fst = { version = "0.4.7", default-features = false }
hashbrown = { version = "0.12.1", default-features = false }
indexmap = "1.9.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.12.0"
+once_cell = "1.15.0"
rustc-hash = "1.1.0"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
tracing = "0.1.35"
stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
index 277135d6d..938db032f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
@@ -1,12 +1,12 @@
//! Defines hir-level representation of structs, enums and unions
-use std::sync::Arc;
+use std::{num::NonZeroU32, sync::Arc};
use base_db::CrateId;
use either::Either;
use hir_expand::{
name::{AsName, Name},
- InFile,
+ HirFileId, InFile,
};
use la_arena::{Arena, ArenaMap};
use syntax::ast::{self, HasName, HasVisibility};
@@ -14,15 +14,18 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
use crate::{
body::{CfgExpander, LowerCtx},
+ builtin_type::{BuiltinInt, BuiltinUint},
db::DefDatabase,
intern::Interned,
- item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
+ item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
+ nameres::diagnostics::DefDiagnostic,
src::HasChildSource,
src::HasSource,
trace::Trace,
type_ref::TypeRef,
visibility::RawVisibility,
- EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
+ EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
+ VariantId,
};
use cfg::CfgOptions;
@@ -31,7 +34,7 @@ use cfg::CfgOptions;
pub struct StructData {
pub name: Name,
pub variant_data: Arc<VariantData>,
- pub repr: Option<ReprKind>,
+ pub repr: Option<ReprData>,
pub visibility: RawVisibility,
}
@@ -39,6 +42,7 @@ pub struct StructData {
pub struct EnumData {
pub name: Name,
pub variants: Arena<EnumVariantData>,
+ pub repr: Option<ReprData>,
pub visibility: RawVisibility,
}
@@ -63,10 +67,19 @@ pub struct FieldData {
pub visibility: RawVisibility,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum ReprKind {
- Packed,
- Other,
+ C,
+ BuiltinInt { builtin: Either<BuiltinInt, BuiltinUint>, is_c: bool },
+ Transparent,
+ Default,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct ReprData {
+ pub kind: ReprKind,
+ pub packed: bool,
+ pub align: Option<NonZeroU32>,
}
fn repr_from_value(
@@ -74,25 +87,71 @@ fn repr_from_value(
krate: CrateId,
item_tree: &ItemTree,
of: AttrOwner,
-) -> Option<ReprKind> {
+) -> Option<ReprData> {
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
}
-fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
+fn parse_repr_tt(tt: &Subtree) -> Option<ReprData> {
match tt.delimiter {
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
_ => return None,
}
- let mut it = tt.token_trees.iter();
- match it.next()? {
- TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
- _ => Some(ReprKind::Other),
+ let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
+
+ let mut tts = tt.token_trees.iter().peekable();
+ while let Some(tt) = tts.next() {
+ if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
+ match &*ident.text {
+ "packed" => {
+ data.packed = true;
+ if let Some(TokenTree::Subtree(_)) = tts.peek() {
+ tts.next();
+ }
+ }
+ "align" => {
+ if let Some(TokenTree::Subtree(tt)) = tts.peek() {
+ tts.next();
+ if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
+ if let Ok(align) = lit.text.parse() {
+ data.align = Some(align);
+ }
+ }
+ }
+ }
+ "C" => {
+ if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
+ *is_c = true;
+ } else {
+ data.kind = ReprKind::C;
+ }
+ }
+ "transparent" => data.kind = ReprKind::Transparent,
+ repr => {
+ let is_c = matches!(data.kind, ReprKind::C);
+ if let Some(builtin) = BuiltinInt::from_suffix(repr)
+ .map(Either::Left)
+ .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
+ {
+ data.kind = ReprKind::BuiltinInt { builtin, is_c };
+ }
+ }
+ }
+ }
}
+
+ Some(data)
}
impl StructData {
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
+ db.struct_data_with_diagnostics(id).0
+ }
+
+ pub(crate) fn struct_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ id: StructId,
+ ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
let loc = id.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
@@ -100,15 +159,35 @@ impl StructData {
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
let strukt = &item_tree[loc.id.value];
- let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
- Arc::new(StructData {
- name: strukt.name.clone(),
- variant_data: Arc::new(variant_data),
- repr,
- visibility: item_tree[strukt.visibility].clone(),
- })
+ let (variant_data, diagnostics) = lower_fields(
+ db,
+ krate,
+ loc.id.file_id(),
+ loc.container.local_id,
+ &item_tree,
+ &cfg_options,
+ &strukt.fields,
+ None,
+ );
+ (
+ Arc::new(StructData {
+ name: strukt.name.clone(),
+ variant_data: Arc::new(variant_data),
+ repr,
+ visibility: item_tree[strukt.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
+
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
+ db.union_data_with_diagnostics(id).0
+ }
+
+ pub(crate) fn union_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ id: UnionId,
+ ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
let loc = id.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
@@ -116,56 +195,98 @@ impl StructData {
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
let union = &item_tree[loc.id.value];
- let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
-
- Arc::new(StructData {
- name: union.name.clone(),
- variant_data: Arc::new(variant_data),
- repr,
- visibility: item_tree[union.visibility].clone(),
- })
+ let (variant_data, diagnostics) = lower_fields(
+ db,
+ krate,
+ loc.id.file_id(),
+ loc.container.local_id,
+ &item_tree,
+ &cfg_options,
+ &union.fields,
+ None,
+ );
+ (
+ Arc::new(StructData {
+ name: union.name.clone(),
+ variant_data: Arc::new(variant_data),
+ repr,
+ visibility: item_tree[union.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
}
impl EnumData {
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
+ db.enum_data_with_diagnostics(e).0
+ }
+
+ pub(crate) fn enum_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ e: EnumId,
+ ) -> (Arc<EnumData>, Arc<[DefDiagnostic]>) {
let loc = e.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+ let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let enum_ = &item_tree[loc.id.value];
let mut variants = Arena::new();
+ let mut diagnostics = Vec::new();
for tree_id in enum_.variants.clone() {
- if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
- let var = &item_tree[tree_id];
- let var_data = lower_fields(
+ let attrs = item_tree.attrs(db, krate, tree_id.into());
+ let var = &item_tree[tree_id];
+ if attrs.is_cfg_enabled(&cfg_options) {
+ let (var_data, field_diagnostics) = lower_fields(
db,
krate,
+ loc.id.file_id(),
+ loc.container.local_id,
&item_tree,
&cfg_options,
&var.fields,
Some(enum_.visibility),
);
+ diagnostics.extend(field_diagnostics);
variants.alloc(EnumVariantData {
name: var.name.clone(),
variant_data: Arc::new(var_data),
});
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ loc.container.local_id,
+ InFile::new(loc.id.file_id(), var.ast_id.upcast()),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- Arc::new(EnumData {
- name: enum_.name.clone(),
- variants,
- visibility: item_tree[enum_.visibility].clone(),
- })
+ (
+ Arc::new(EnumData {
+ name: enum_.name.clone(),
+ variants,
+ repr,
+ visibility: item_tree[enum_.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
Some(id)
}
+
+ pub fn variant_body_type(&self) -> Either<BuiltinInt, BuiltinUint> {
+ match self.repr {
+ Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
+ _ => Either::Left(BuiltinInt::Isize),
+ }
+ }
}
impl HasChildSource<LocalEnumVariantId> for EnumId {
@@ -324,31 +445,64 @@ fn lower_struct(
fn lower_fields(
db: &dyn DefDatabase,
krate: CrateId,
+ current_file_id: HirFileId,
+ container: LocalModuleId,
item_tree: &ItemTree,
cfg_options: &CfgOptions,
fields: &Fields,
override_visibility: Option<RawVisibilityId>,
-) -> VariantData {
+) -> (VariantData, Vec<DefDiagnostic>) {
+ let mut diagnostics = Vec::new();
match fields {
Fields::Record(flds) => {
let mut arena = Arena::new();
for field_id in flds.clone() {
- if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
- arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+ let attrs = item_tree.attrs(db, krate, field_id.into());
+ let field = &item_tree[field_id];
+ if attrs.is_cfg_enabled(cfg_options) {
+ arena.alloc(lower_field(item_tree, field, override_visibility));
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ container,
+ InFile::new(
+ current_file_id,
+ match field.ast_id {
+ FieldAstId::Record(it) => it.upcast(),
+ FieldAstId::Tuple(it) => it.upcast(),
+ },
+ ),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- VariantData::Record(arena)
+ (VariantData::Record(arena), diagnostics)
}
Fields::Tuple(flds) => {
let mut arena = Arena::new();
for field_id in flds.clone() {
- if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
- arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+ let attrs = item_tree.attrs(db, krate, field_id.into());
+ let field = &item_tree[field_id];
+ if attrs.is_cfg_enabled(cfg_options) {
+ arena.alloc(lower_field(item_tree, field, override_visibility));
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ container,
+ InFile::new(
+ current_file_id,
+ match field.ast_id {
+ FieldAstId::Record(it) => it.upcast(),
+ FieldAstId::Tuple(it) => it.upcast(),
+ },
+ ),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- VariantData::Tuple(arena)
+ (VariantData::Tuple(arena), diagnostics)
}
- Fields::Unit => VariantData::Unit,
+ Fields::Unit => (VariantData::Unit, diagnostics),
}
}
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 22f5fb992..759f3b8c0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -27,7 +27,7 @@ use crate::{
macro_id_to_def_id,
nameres::DefMap,
path::{ModPath, Path},
- src::HasSource,
+ src::{HasChildSource, HasSource},
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
UnresolvedMacro,
};
@@ -311,7 +311,20 @@ impl Body {
DefWithBodyId::FunctionId(f) => {
let f = f.lookup(db);
let src = f.source(db);
- params = src.value.param_list();
+ params = src.value.param_list().map(|param_list| {
+ let item_tree = f.id.item_tree(db);
+ let func = &item_tree[f.id.value];
+ let krate = f.container.module(db).krate;
+ let crate_graph = db.crate_graph();
+ (
+ param_list,
+ func.params.clone().map(move |param| {
+ item_tree
+ .attrs(db, krate, param.into())
+ .is_cfg_enabled(&crate_graph[krate].cfg_options)
+ }),
+ )
+ });
(src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
}
DefWithBodyId::ConstId(c) => {
@@ -324,10 +337,17 @@ impl Body {
let src = s.source(db);
(src.file_id, s.module(db), src.value.body())
}
+ DefWithBodyId::VariantId(v) => {
+ let e = v.parent.lookup(db);
+ let src = v.parent.child_source(db);
+ let variant = &src.value[v.local_id];
+ (src.file_id, e.container, variant.expr())
+ }
};
let expander = Expander::new(db, file_id, module);
let (mut body, source_map) = Body::new(db, expander, params, body);
body.shrink_to_fit();
+
(Arc::new(body), Arc::new(source_map))
}
@@ -364,7 +384,7 @@ impl Body {
fn new(
db: &dyn DefDatabase,
expander: Expander,
- params: Option<ast::ParamList>,
+ params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
lower::lower(db, expander, params, body)
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 3b3297f78..ccc01c3ef 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
@@ -29,8 +29,9 @@ use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
db::DefDatabase,
expr::{
- dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
- Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+ dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
+ Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
+ Statement,
},
intern::Interned,
item_scope::BuiltinShadowMode,
@@ -76,7 +77,7 @@ impl<'a> LowerCtx<'a> {
pub(super) fn lower(
db: &dyn DefDatabase,
expander: Expander,
- params: Option<ast::ParamList>,
+ params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
ExprCollector {
@@ -97,6 +98,7 @@ pub(super) fn lower(
name_to_pat_grouping: Default::default(),
is_lowering_inside_or_pat: false,
is_lowering_assignee_expr: false,
+ is_lowering_generator: false,
}
.collect(params, body)
}
@@ -111,16 +113,19 @@ struct ExprCollector<'a> {
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
is_lowering_inside_or_pat: bool,
is_lowering_assignee_expr: bool,
+ is_lowering_generator: bool,
}
impl ExprCollector<'_> {
fn collect(
mut self,
- param_list: Option<ast::ParamList>,
+ param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
- if let Some(param_list) = param_list {
- if let Some(self_param) = param_list.self_param() {
+ if let Some((param_list, mut attr_enabled)) = param_list {
+ if let Some(self_param) =
+ param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+ {
let ptr = AstPtr::new(&self_param);
let param_pat = self.alloc_pat(
Pat::Bind {
@@ -136,7 +141,11 @@ impl ExprCollector<'_> {
self.body.params.push(param_pat);
}
- for pat in param_list.params().filter_map(|param| param.pat()) {
+ for pat in param_list
+ .params()
+ .zip(attr_enabled)
+ .filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
+ {
let param_pat = self.collect_pat(pat);
self.body.params.push(param_pat);
}
@@ -358,6 +367,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
}
ast::Expr::YieldExpr(e) => {
+ self.is_lowering_generator = true;
let expr = e.expr().map(|e| self.collect_expr(e));
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
}
@@ -459,13 +469,31 @@ impl ExprCollector<'_> {
.ret_type()
.and_then(|r| r.ty())
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+
+ let prev_is_lowering_generator = self.is_lowering_generator;
+ self.is_lowering_generator = false;
+
let body = self.collect_expr_opt(e.body());
+
+ let closure_kind = if self.is_lowering_generator {
+ let movability = if e.static_token().is_some() {
+ Movability::Static
+ } else {
+ Movability::Movable
+ };
+ ClosureKind::Generator(movability)
+ } else {
+ ClosureKind::Closure
+ };
+ self.is_lowering_generator = prev_is_lowering_generator;
+
self.alloc_expr(
Expr::Closure {
args: args.into(),
arg_types: arg_types.into(),
ret_type,
body,
+ closure_kind,
},
syntax_ptr,
)
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 f2fed9544..162d173d5 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,8 +2,10 @@
use std::fmt::{self, Write};
+use syntax::ast::HasName;
+
use crate::{
- expr::{Array, BindingAnnotation, Literal, Statement},
+ expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
};
@@ -32,6 +34,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
};
format!("const {} = ", name)
}
+ DefWithBodyId::VariantId(it) => {
+ needs_semi = false;
+ let src = it.parent.child_source(db);
+ let variant = &src.value[it.local_id];
+ let name = match &variant.name() {
+ Some(name) => name.to_string(),
+ None => "_".to_string(),
+ };
+ format!("{}", name)
+ }
};
let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
@@ -350,7 +362,10 @@ impl<'a> Printer<'a> {
self.print_expr(*index);
w!(self, "]");
}
- Expr::Closure { args, arg_types, ret_type, body } => {
+ Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
+ if let ClosureKind::Generator(Movability::Static) = closure_kind {
+ w!(self, "static ");
+ }
w!(self, "|");
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
if i != 0 {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
index 0e7ce5f85..39581b33a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
@@ -379,7 +379,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
- rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
gated!(
alloc_error_handler, Normal, template!(Word), WarnFollowing,
experimental!(alloc_error_handler)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index 5b1435e8f..bb1316525 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -198,6 +198,10 @@ impl ChildBySource for EnumId {
impl ChildBySource for DefWithBodyId {
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
let body = db.body(*self);
+ if let &DefWithBodyId::VariantId(v) = self {
+ VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
+ }
+
for (_, def_map) in body.blocks(db) {
// All block expressions are merged into the same map, because they logically all add
// inner items to the containing `DefWithBodyId`.
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 631ae3cf1..2dc69b00a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -219,7 +219,7 @@ impl TraitData {
pub(crate) fn trait_data_with_diagnostics_query(
db: &dyn DefDatabase,
tr: TraitId,
- ) -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>) {
+ ) -> (Arc<TraitData>, Arc<[DefDiagnostic]>) {
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
@@ -251,7 +251,7 @@ impl TraitData {
visibility,
skip_array_during_method_dispatch,
}),
- Arc::new(diagnostics),
+ diagnostics.into(),
)
}
@@ -299,7 +299,7 @@ impl ImplData {
pub(crate) fn impl_data_with_diagnostics_query(
db: &dyn DefDatabase,
id: ImplId,
- ) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>) {
+ ) -> (Arc<ImplData>, Arc<[DefDiagnostic]>) {
let _p = profile::span("impl_data_with_diagnostics_query");
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
@@ -318,7 +318,7 @@ impl ImplData {
(
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
- Arc::new(diagnostics),
+ diagnostics.into(),
)
}
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 40b2f734b..431c82554 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -97,24 +97,33 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
#[salsa::invoke(StructData::struct_data_query)]
fn struct_data(&self, id: StructId) -> Arc<StructData>;
+ #[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
+ fn struct_data_with_diagnostics(&self, id: StructId)
+ -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(StructData::union_data_query)]
fn union_data(&self, id: UnionId) -> Arc<StructData>;
+ #[salsa::invoke(StructData::union_data_with_diagnostics_query)]
+ fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(EnumData::enum_data_query)]
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
+ #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
+ fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc<EnumData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(ImplData::impl_data_query)]
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
#[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
- fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>);
+ fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<[DefDiagnostic]>);
#[salsa::invoke(TraitData::trait_data_query)]
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
#[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
- fn trait_data_with_diagnostics(&self, tr: TraitId)
- -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>);
+ fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>);
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index 419d3feec..162646550 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -198,6 +198,7 @@ pub enum Expr {
arg_types: Box<[Option<Interned<TypeRef>>]>,
ret_type: Option<Interned<TypeRef>>,
body: ExprId,
+ closure_kind: ClosureKind,
},
Tuple {
exprs: Box<[ExprId]>,
@@ -211,6 +212,18 @@ pub enum Expr {
Underscore,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ClosureKind {
+ Closure,
+ Generator(Movability),
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Movability {
+ Static,
+ Movable,
+}
+
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Array {
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
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 89e961f84..c70e6fdcc 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
@@ -1,6 +1,6 @@
//! An algorithm to find a path to refer to a certain item.
-use std::iter;
+use std::{cmp::Ordering, iter};
use hir_expand::name::{known, AsName, Name};
use rustc_hash::FxHashSet;
@@ -16,9 +16,14 @@ use crate::{
/// Find a path that can be used to refer to a certain item. This can depend on
/// *from where* you're referring to the item, hence the `from` parameter.
-pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
+pub fn find_path(
+ db: &dyn DefDatabase,
+ item: ItemInNs,
+ from: ModuleId,
+ prefer_no_std: bool,
+) -> Option<ModPath> {
let _p = profile::span("find_path");
- find_path_inner(db, item, from, None)
+ find_path_inner(db, item, from, None, prefer_no_std)
}
pub fn find_path_prefixed(
@@ -26,47 +31,14 @@ pub fn find_path_prefixed(
item: ItemInNs,
from: ModuleId,
prefix_kind: PrefixKind,
+ prefer_no_std: bool,
) -> Option<ModPath> {
let _p = profile::span("find_path_prefixed");
- find_path_inner(db, item, from, Some(prefix_kind))
+ find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
}
const MAX_PATH_LEN: usize = 15;
-trait ModPathExt {
- fn starts_with_std(&self) -> bool;
- fn can_start_with_std(&self) -> bool;
-}
-
-impl ModPathExt for ModPath {
- fn starts_with_std(&self) -> bool {
- self.segments().first() == Some(&known::std)
- }
-
- // Can we replace the first segment with `std::` and still get a valid, identical path?
- fn can_start_with_std(&self) -> bool {
- let first_segment = self.segments().first();
- first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
- }
-}
-
-fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
- if item == ItemInNs::Types(from.into()) {
- // - if the item is the module we're in, use `self`
- Some(ModPath::from_segments(PathKind::Super(0), None))
- } else if let Some(parent_id) = def_map[from.local_id].parent {
- // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
- let parent_id = def_map.module_id(parent_id);
- if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
- Some(ModPath::from_segments(PathKind::Super(1), None))
- } else {
- None
- }
- } else {
- None
- }
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PrefixKind {
/// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
@@ -94,135 +66,247 @@ impl PrefixKind {
self == &PrefixKind::ByCrate
}
}
+
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
fn find_path_inner(
db: &dyn DefDatabase,
item: ItemInNs,
from: ModuleId,
prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
) -> Option<ModPath> {
- // FIXME: Do fast path for std/core libs?
+ // - if the item is a builtin, it's in scope
+ if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
+ return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
+ }
- let mut visited_modules = FxHashSet::default();
let def_map = from.def_map(db);
- find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
+ let crate_root = def_map.crate_root(db);
+ // - 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();
+ return find_path_for_module(
+ db,
+ &def_map,
+ &mut visited_modules,
+ crate_root,
+ from,
+ module_id,
+ MAX_PATH_LEN,
+ prefixed,
+ prefer_no_std || db.crate_supports_no_std(crate_root.krate),
+ );
+ }
+
+ // - if the item is already in scope, return the name under which it is
+ let scope_name = find_in_scope(db, &def_map, from, item);
+ if prefixed.is_none() {
+ if let Some(scope_name) = scope_name {
+ return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
+ }
+ }
+
+ // - if the item is in the prelude, return the name from there
+ if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
+ return value;
+ }
+
+ if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
+ // - if the item is an enum variant, refer to it via the enum
+ if let Some(mut path) = find_path_inner(
+ db,
+ ItemInNs::Types(variant.parent.into()),
+ from,
+ prefixed,
+ prefer_no_std,
+ ) {
+ let data = db.enum_data(variant.parent);
+ path.push_segment(data.variants[variant.local_id].name.clone());
+ return Some(path);
+ }
+ // If this doesn't work, it seems we have no way of referring to the
+ // enum; that's very weird, but there might still be a reexport of the
+ // variant somewhere
+ }
+
+ let mut visited_modules = FxHashSet::default();
+
+ calculate_best_path(
+ db,
+ &def_map,
+ &mut visited_modules,
+ crate_root,
+ MAX_PATH_LEN,
+ item,
+ from,
+ prefixed,
+ prefer_no_std || db.crate_supports_no_std(crate_root.krate),
+ scope_name,
+ )
}
-fn find_path_inner_(
+fn find_path_for_module(
db: &dyn DefDatabase,
def_map: &DefMap,
+ visited_modules: &mut FxHashSet<ModuleId>,
+ crate_root: ModuleId,
from: ModuleId,
- item: ItemInNs,
+ module_id: ModuleId,
max_len: usize,
- mut prefixed: Option<PrefixKind>,
- visited_modules: &mut FxHashSet<ModuleId>,
+ prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
) -> Option<ModPath> {
if max_len == 0 {
return None;
}
// Base cases:
-
// - if the item is already in scope, return the name under which it is
- let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
- def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
- });
+ 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)));
}
}
- // - if the item is a builtin, it's in scope
- if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
- return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
- }
-
// - if the item is the crate root, return `crate`
- let crate_root = def_map.crate_root(db);
- if item == ItemInNs::Types(ModuleDefId::ModuleId(crate_root)) {
+ if module_id == crate_root {
return Some(ModPath::from_segments(PathKind::Crate, None));
}
+ // - 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(_) = check_self_super(&def_map, item, from) {
+ if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
return modpath;
}
}
// - 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);
- if let ItemInNs::Types(ModuleDefId::ModuleId(item)) = item {
- for (name, &def_id) in root_def_map.extern_prelude() {
- if item == def_id {
- let name = scope_name.unwrap_or_else(|| name.clone());
-
- let name_already_occupied_in_type_ns = def_map
- .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
- def_map[local_id]
- .scope
- .type_(&name)
- .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
- })
- .is_some();
- let kind = if name_already_occupied_in_type_ns {
- cov_mark::hit!(ambiguous_crate_start);
- PathKind::Abs
- } else {
- PathKind::Plain
- };
- return Some(ModPath::from_segments(kind, Some(name)));
- }
+ for (name, &def_id) in root_def_map.extern_prelude() {
+ if module_id == def_id {
+ let name = scope_name.unwrap_or_else(|| name.clone());
+
+ let name_already_occupied_in_type_ns = def_map
+ .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map[local_id]
+ .scope
+ .type_(&name)
+ .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
+ })
+ .is_some();
+ let kind = if name_already_occupied_in_type_ns {
+ cov_mark::hit!(ambiguous_crate_start);
+ PathKind::Abs
+ } else {
+ PathKind::Plain
+ };
+ return Some(ModPath::from_segments(kind, Some(name)));
}
}
- // - if the item is in the prelude, return the name from there
+ if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
+ {
+ return value;
+ }
+ calculate_best_path(
+ db,
+ def_map,
+ visited_modules,
+ crate_root,
+ max_len,
+ ItemInNs::Types(module_id.into()),
+ from,
+ prefixed,
+ prefer_no_std,
+ scope_name,
+ )
+}
+
+fn find_in_scope(
+ db: &dyn DefDatabase,
+ def_map: &DefMap,
+ from: ModuleId,
+ item: ItemInNs,
+) -> Option<Name> {
+ def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
+ })
+}
+
+fn find_in_prelude(
+ db: &dyn DefDatabase,
+ root_def_map: &DefMap,
+ item: ItemInNs,
+ from: ModuleId,
+) -> Option<Option<ModPath>> {
if let Some(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;
if let Some((name, vis)) = prelude_scope.name_of(item) {
if vis.is_visible_from(db, from) {
- return Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())));
+ return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
}
}
}
+ None
+}
- // Recursive case:
- // - if the item is an enum variant, refer to it via the enum
- if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
- if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
- let data = db.enum_data(variant.parent);
- path.push_segment(data.variants[variant.local_id].name.clone());
- return Some(path);
+fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
+ if item == from {
+ // - if the item is the module we're in, use `self`
+ Some(ModPath::from_segments(PathKind::Super(0), None))
+ } else if let Some(parent_id) = def_map[from.local_id].parent {
+ // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
+ let parent_id = def_map.module_id(parent_id);
+ if item == parent_id {
+ Some(ModPath::from_segments(PathKind::Super(1), None))
+ } else {
+ None
}
- // If this doesn't work, it seems we have no way of referring to the
- // enum; that's very weird, but there might still be a reexport of the
- // variant somewhere
+ } else {
+ None
}
+}
- // - otherwise, look for modules containing (reexporting) it and import it from one of those
- let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
+fn calculate_best_path(
+ db: &dyn DefDatabase,
+ def_map: &DefMap,
+ visited_modules: &mut FxHashSet<ModuleId>,
+ crate_root: ModuleId,
+ max_len: usize,
+ item: ItemInNs,
+ from: ModuleId,
+ mut prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
+ scope_name: Option<Name>,
+) -> Option<ModPath> {
+ if max_len <= 1 {
+ return None;
+ }
let mut best_path = None;
- let mut best_path_len = max_len;
-
+ // Recursive case:
+ // - otherwise, look for modules containing (reexporting) it and import it from one of those
if item.krate(db) == Some(from.krate) {
+ let mut best_path_len = max_len;
// Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case.
- // FIXME: this should have a fast path that doesn't look through the prelude again?
for (module_id, name) in find_local_import_locations(db, item, from) {
if !visited_modules.insert(module_id) {
cov_mark::hit!(recursive_imports);
continue;
}
- if let Some(mut path) = find_path_inner_(
+ if let Some(mut path) = find_path_for_module(
db,
def_map,
+ visited_modules,
+ crate_root,
from,
- ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
+ module_id,
best_path_len - 1,
prefixed,
- visited_modules,
+ prefer_no_std,
) {
path.push_segment(name);
@@ -245,14 +329,16 @@ fn find_path_inner_(
import_map.import_info_for(item).and_then(|info| {
// 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_inner_(
+ let mut path = find_path_for_module(
db,
def_map,
+ visited_modules,
+ crate_root,
from,
- ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
- best_path_len - 1,
+ info.container,
+ max_len - 1,
prefixed,
- visited_modules,
+ prefer_no_std,
)?;
cov_mark::hit!(partially_imported);
path.push_segment(info.path.segments.last()?.clone());
@@ -268,16 +354,12 @@ fn find_path_inner_(
best_path = Some(new_path);
}
}
-
- // If the item is declared inside a block expression, don't use a prefix, as we don't handle
- // that correctly (FIXME).
- if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
- if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
+ if let Some(module) = item.module(db) {
+ if module.def_map(db).block_id().is_some() && prefixed.is_some() {
cov_mark::hit!(prefixed_in_block_expression);
prefixed = Some(PrefixKind::Plain);
}
}
-
match prefixed.map(PrefixKind::prefix) {
Some(prefix) => best_path.or_else(|| {
scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
@@ -287,29 +369,48 @@ fn find_path_inner_(
}
fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
- if old_path.starts_with_std() && new_path.can_start_with_std() {
- if prefer_no_std {
- cov_mark::hit!(prefer_no_std_paths);
- new_path
- } else {
- cov_mark::hit!(prefer_std_paths);
- old_path
+ const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
+ match (old_path.segments().first(), new_path.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 {
+ name if name == &known::core => 0,
+ name if name == &known::alloc => 0,
+ name if name == &known::std => 1,
+ _ => unreachable!(),
+ },
+ true => |name: &Name| match name {
+ name if name == &known::core => 2,
+ name if name == &known::alloc => 1,
+ name if name == &known::std => 0,
+ _ => unreachable!(),
+ },
+ };
+ let nrank = rank(new);
+ let orank = rank(old);
+ match nrank.cmp(&orank) {
+ Ordering::Less => old_path,
+ Ordering::Equal => {
+ if new_path.len() < old_path.len() {
+ new_path
+ } else {
+ old_path
+ }
+ }
+ Ordering::Greater => new_path,
+ }
}
- } else if new_path.starts_with_std() && old_path.can_start_with_std() {
- if prefer_no_std {
- cov_mark::hit!(prefer_no_std_paths);
- old_path
- } else {
- cov_mark::hit!(prefer_std_paths);
- new_path
+ _ => {
+ if new_path.len() < old_path.len() {
+ new_path
+ } else {
+ old_path
+ }
}
- } else if new_path.len() < old_path.len() {
- new_path
- } else {
- old_path
}
}
+// FIXME: Remove allocations
/// Finds locations in `from.krate` from which `item` can be imported by `from`.
fn find_local_import_locations(
db: &dyn DefDatabase,
@@ -428,7 +529,8 @@ mod tests {
.take_types()
.unwrap();
- let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
+ let found_path =
+ find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
}
@@ -468,8 +570,8 @@ $0
"#,
"E::A",
"E::A",
- "E::A",
- "E::A",
+ "crate::E::A",
+ "self::E::A",
);
}
@@ -788,7 +890,6 @@ pub use super::foo;
#[test]
fn prefer_std_paths_over_alloc() {
- cov_mark::check!(prefer_std_paths);
check_found_path(
r#"
//- /main.rs crate:main deps:alloc,std
@@ -813,7 +914,6 @@ pub mod sync {
#[test]
fn prefer_core_paths_over_std() {
- cov_mark::check!(prefer_no_std_paths);
check_found_path(
r#"
//- /main.rs crate:main deps:core,std
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 a11a92204..7721221c4 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
@@ -18,7 +18,7 @@ use crate::{
ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
};
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub(crate) enum ImportType {
Glob,
Named,
@@ -302,13 +302,13 @@ impl ItemScope {
$changed = true;
}
Entry::Occupied(mut entry)
- if $glob_imports.$field.contains(&$lookup)
- && matches!($def_import_type, ImportType::Named) =>
+ if matches!($def_import_type, ImportType::Named) =>
{
- cov_mark::hit!(import_shadowed);
- $glob_imports.$field.remove(&$lookup);
- entry.insert(fld);
- $changed = true;
+ if $glob_imports.$field.remove(&$lookup) {
+ cov_mark::hit!(import_shadowed);
+ entry.insert(fld);
+ $changed = true;
+ }
}
_ => {}
}
@@ -457,8 +457,15 @@ impl ItemInNs {
/// Returns the crate defining this item (or `None` if `self` is built-in).
pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
match self {
- ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
+ ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
ItemInNs::Macros(id) => Some(id.module(db).krate),
}
}
+
+ pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
+ match self {
+ ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
+ ItemInNs::Macros(id) => Some(id.module(db)),
+ }
+ }
}
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 3342d4db4..570344596 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
@@ -943,6 +943,7 @@ impl AssocItem {
pub struct Variant {
pub name: Name,
pub fields: Fields,
+ pub ast_id: FileAstId<ast::Variant>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -952,10 +953,17 @@ pub enum Fields {
Unit,
}
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FieldAstId {
+ Record(FileAstId<ast::RecordField>),
+ Tuple(FileAstId<ast::TupleField>),
+}
+
/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub visibility: RawVisibilityId,
+ pub ast_id: FieldAstId,
}
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 7f2551e94..077a1b619 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
@@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
let name = field.name()?.as_name();
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
- let res = Field { name, type_ref, visibility };
+ let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
+ let res = Field { name, type_ref, visibility, ast_id };
Some(res)
}
@@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
- Field { name, type_ref, visibility }
+ let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
+ Field { name, type_ref, visibility, ast_id }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
@@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
let name = variant.name()?.as_name();
let fields = self.lower_fields(&variant.kind());
- let res = Variant { name, fields };
+ let ast_id = self.source_ast_id_map.ast_id(variant);
+ let res = Variant { name, fields, ast_id };
Some(res)
}
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 34dd817fd..da1643152 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
@@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
w!(self, "{{");
self.indented(|this| {
for field in fields.clone() {
- let Field { visibility, name, type_ref } = &this.tree[field];
+ let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
this.print_attrs_of(field);
this.print_visibility(*visibility);
w!(this, "{}: ", name);
@@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
w!(self, "(");
self.indented(|this| {
for field in fields.clone() {
- let Field { visibility, name, type_ref } = &this.tree[field];
+ let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
this.print_attrs_of(field);
this.print_visibility(*visibility);
w!(this, "{}: ", name);
@@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for variant in variants.clone() {
- let Variant { name, fields } = &this.tree[variant];
+ let Variant { name, fields, ast_id: _ } = &this.tree[variant];
this.print_attrs_of(variant);
w!(this, "{}", name);
this.print_fields(fields);
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 32ebfda4f..5c7aa7234 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -474,16 +474,24 @@ pub enum DefWithBodyId {
FunctionId(FunctionId),
StaticId(StaticId),
ConstId(ConstId),
+ VariantId(EnumVariantId),
}
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
+impl From<EnumVariantId> for DefWithBodyId {
+ fn from(id: EnumVariantId) -> Self {
+ DefWithBodyId::VariantId(id)
+ }
+}
+
impl DefWithBodyId {
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
match self {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(c) => Some(c.into()),
+ DefWithBodyId::VariantId(c) => Some(c.into()),
}
}
}
@@ -681,6 +689,7 @@ impl HasModule for DefWithBodyId {
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
+ DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
}
}
}
@@ -691,6 +700,7 @@ impl DefWithBodyId {
DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
+ DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index 6819e9114..fafcde25a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
#[derive(Copy)]
struct Foo;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo;
-impl < > core::marker::Copy for Foo< > {}"##]],
+impl < > core::marker::Copy for Foo< > {}"#]],
);
}
@@ -33,7 +33,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro derive {}
#[rustc_builtin_macro]
@@ -41,7 +41,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
-impl < > crate ::marker::Copy for Foo< > {}"##]],
+impl < > crate ::marker::Copy for Foo< > {}"#]],
);
}
@@ -53,11 +53,11 @@ fn test_copy_expand_with_type_params() {
#[derive(Copy)]
struct Foo<A, B>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo<A, B>;
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
);
}
@@ -70,11 +70,11 @@ fn test_copy_expand_with_lifetimes() {
#[derive(Copy)]
struct Foo<A, B, 'a, 'b>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo<A, B, 'a, 'b>;
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
);
}
@@ -86,10 +86,26 @@ fn test_clone_expand() {
#[derive(Clone)]
struct Foo<A, B>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Clone)]
struct Foo<A, B>;
-impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
+impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
+ );
+}
+
+#[test]
+fn test_clone_expand_with_const_generics() {
+ check(
+ r#"
+//- minicore: derive, clone
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+"#,
+ expect![[r#"
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+
+impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
);
}
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 4f626105a..c04cd1651 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
@@ -93,12 +93,12 @@ macro_rules! option_env {() => {}}
fn main() { option_env!("TEST_ENV_VAR"); }
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! option_env {() => {}}
-fn main() { std::option::Option::None:: < &str>; }
-"##]],
+fn main() { $crate::option::Option::None:: < &str>; }
+"#]],
);
}
@@ -191,7 +191,7 @@ fn main() {
format_args!("{} {:?}", arg1(a, b, c), arg2);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -199,9 +199,9 @@ macro_rules! format_args {
}
fn main() {
- std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
+ $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
@@ -219,7 +219,7 @@ fn main() {
format_args!("{} {:?}", a::<A,B>(), b);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -227,9 +227,9 @@ macro_rules! format_args {
}
fn main() {
- std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
+ $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
@@ -248,7 +248,7 @@ fn main() {
format_args!/*+errors*/("{} {:?}", a.);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -258,9 +258,9 @@ macro_rules! format_args {
fn main() {
let _ =
/* parse error: expected field name or number */
-std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
+$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
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 495bbe457..9ffc21881 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
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
match per_ns.types {
Some((ModuleDefId::ModuleId(m), _)) => {
self.def_map.prelude = Some(m);
+ break;
}
types => {
tracing::debug!(
@@ -2121,7 +2122,7 @@ impl ModCollector<'_, '_> {
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
let ast_id = item.ast_id(self.item_tree);
- let ast_id = InFile::new(self.file_id(), ast_id);
+ let ast_id = InFile::new(self.file_id(), ast_id.upcast());
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id,
ast_id,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index ed7e920fd..066142291 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -4,7 +4,7 @@ use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use hir_expand::MacroCallKind;
use la_arena::Idx;
-use syntax::ast;
+use syntax::ast::{self, AnyHasAttrs};
use crate::{
attr::AttrId,
@@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
- UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
+ UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
@@ -75,7 +75,7 @@ impl DefDiagnostic {
pub fn unconfigured_code(
container: LocalModuleId,
- ast: AstId<ast::Item>,
+ ast: AstId<ast::AnyHasAttrs>,
cfg: CfgExpr,
opts: CfgOptions,
) -> Self {
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 8aa5973ca..070f68371 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -839,6 +839,7 @@ impl HasResolver for DefWithBodyId {
DefWithBodyId::ConstId(c) => c.resolver(db),
DefWithBodyId::FunctionId(f) => f.resolver(db),
DefWithBodyId::StaticId(s) => s.resolver(db),
+ DefWithBodyId::VariantId(v) => v.parent.resolver(db),
}
}
}