diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
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), } } } |