diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-def')
33 files changed, 890 insertions, 491 deletions
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 9bc1c54a3..b336f59ff 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs @@ -40,6 +40,7 @@ pub struct StructData { pub repr: Option<ReprOptions>, pub visibility: RawVisibility, pub rustc_has_incoherent_inherent_impls: bool, + pub fundamental: bool, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -173,10 +174,10 @@ impl StructData { let item_tree = loc.id.item_tree(db); let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let fundamental = attrs.by_key("fundamental").exists(); let strukt = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -196,6 +197,7 @@ impl StructData { repr, visibility: item_tree[strukt.visibility].clone(), rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) @@ -215,10 +217,10 @@ impl StructData { let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone(); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let fundamental = attrs.by_key("fundamental").exists(); let union = &item_tree[loc.id.value]; let (variant_data, diagnostics) = lower_fields( @@ -238,6 +240,7 @@ impl StructData { repr, visibility: item_tree[union.visibility].clone(), rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index fcd92ad33..200072c17 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -300,6 +300,7 @@ impl AttrsWithOwner { AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), }, AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), + AttrDefId::TraitAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), AttrDefId::MacroId(it) => match it { MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db), MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db), @@ -315,26 +316,14 @@ impl AttrsWithOwner { let src = it.parent().child_source(db); RawAttrs::from_attrs_owner( db.upcast(), - src.with_value(src.value[it.local_id()].as_ref().either( - |it| match it { - ast::TypeOrConstParam::Type(it) => it as _, - ast::TypeOrConstParam::Const(it) => it as _, - }, - |it| it as _, - )), + src.with_value(&src.value[it.local_id()]), ) } GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); RawAttrs::from_attrs_owner( db.upcast(), - src.with_value(src.value[it.local_id()].as_ref().either( - |it| match it { - ast::TypeOrConstParam::Type(it) => it as _, - ast::TypeOrConstParam::Const(it) => it as _, - }, - |it| it as _, - )), + src.with_value(&src.value[it.local_id()]), ) } GenericParamId::LifetimeParamId(it) => { @@ -404,6 +393,7 @@ impl AttrsWithOwner { AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), + AttrDefId::TraitAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), AttrDefId::MacroId(id) => match id { MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), @@ -412,28 +402,14 @@ impl AttrsWithOwner { }, AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new), AttrDefId::GenericParamId(id) => match id { - GenericParamId::ConstParamId(id) => { - id.parent().child_source(db).map(|source| match &source[id.local_id()] { - Either::Left(ast::TypeOrConstParam::Type(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Left(ast::TypeOrConstParam::Const(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Right(id) => ast::AnyHasAttrs::new(id.clone()), - }) - } - GenericParamId::TypeParamId(id) => { - id.parent().child_source(db).map(|source| match &source[id.local_id()] { - Either::Left(ast::TypeOrConstParam::Type(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Left(ast::TypeOrConstParam::Const(id)) => { - ast::AnyHasAttrs::new(id.clone()) - } - Either::Right(id) => ast::AnyHasAttrs::new(id.clone()), - }) - } + GenericParamId::ConstParamId(id) => id + .parent() + .child_source(db) + .map(|source| ast::AnyHasAttrs::new(source[id.local_id()].clone())), + GenericParamId::TypeParamId(id) => id + .parent() + .child_source(db) + .map(|source| ast::AnyHasAttrs::new(source[id.local_id()].clone())), GenericParamId::LifetimeParamId(id) => id .parent .child_source(db) 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 8fd9255b8..b70e658ef 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -24,7 +24,9 @@ use syntax::{ast, AstPtr, SyntaxNode, SyntaxNodePtr}; use crate::{ attr::Attrs, db::DefDatabase, - expr::{dummy_expr_id, Expr, ExprId, Label, LabelId, Pat, PatId}, + expr::{ + dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat, + }, item_scope::BuiltinShadowMode, macro_id_to_def_id, nameres::DefMap, @@ -270,7 +272,7 @@ pub struct Mark { pub struct Body { pub exprs: Arena<Expr>, pub pats: Arena<Pat>, - pub or_pats: FxHashMap<PatId, Arc<[PatId]>>, + pub bindings: Arena<Binding>, pub labels: Arena<Label>, /// The patterns for the function's parameters. While the parameter types are /// part of the function signature, the patterns are not (they don't change @@ -409,18 +411,6 @@ impl Body { .map(move |&block| (block, db.block_def_map(block).expect("block ID without DefMap"))) } - pub fn pattern_representative(&self, pat: PatId) -> PatId { - self.or_pats.get(&pat).and_then(|pats| pats.first().copied()).unwrap_or(pat) - } - - /// Retrieves all ident patterns this pattern shares the ident with. - pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] { - match self.or_pats.get(pat) { - Some(pats) => pats, - None => std::slice::from_ref(pat), - } - } - pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { pretty::print_body_hir(db, self, owner) } @@ -435,13 +425,52 @@ impl Body { } fn shrink_to_fit(&mut self) { - let Self { _c: _, body_expr: _, block_scopes, or_pats, exprs, labels, params, pats } = self; + let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats, bindings } = + self; block_scopes.shrink_to_fit(); - or_pats.shrink_to_fit(); exprs.shrink_to_fit(); labels.shrink_to_fit(); params.shrink_to_fit(); pats.shrink_to_fit(); + bindings.shrink_to_fit(); + } + + pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { + self.walk_pats(pat_id, &mut |pat| { + if let Pat::Bind { id, .. } = pat { + f(*id); + } + }); + } + + pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(&Pat)) { + let pat = &self[pat_id]; + f(pat); + match pat { + Pat::Range { .. } + | Pat::Lit(..) + | Pat::Path(..) + | Pat::ConstBlock(..) + | Pat::Wild + | Pat::Missing => {} + &Pat::Bind { subpat, .. } => { + if let Some(subpat) = subpat { + self.walk_pats(subpat, f); + } + } + Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { + args.iter().copied().for_each(|p| self.walk_pats(p, f)); + } + Pat::Ref { pat, .. } => self.walk_pats(*pat, f), + Pat::Slice { prefix, slice, suffix } => { + let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); + total_iter.copied().for_each(|p| self.walk_pats(p, f)); + } + Pat::Record { args, .. } => { + args.iter().for_each(|RecordFieldPat { pat, .. }| self.walk_pats(*pat, f)); + } + Pat::Box { inner } => self.walk_pats(*inner, f), + } } } @@ -451,7 +480,7 @@ impl Default for Body { body_expr: dummy_expr_id(), exprs: Default::default(), pats: Default::default(), - or_pats: Default::default(), + bindings: Default::default(), labels: Default::default(), params: Default::default(), block_scopes: Default::default(), @@ -484,6 +513,14 @@ impl Index<LabelId> for Body { } } +impl Index<BindingId> for Body { + type Output = Binding; + + fn index(&self, b: BindingId) -> &Binding { + &self.bindings[b] + } +} + // FIXME: Change `node_` prefix to something more reasonable. // Perhaps `expr_syntax` and `expr_id`? impl BodySourceMap { 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 04b1c4f01..fedaf3955 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 @@ -15,6 +15,7 @@ use la_arena::Arena; use once_cell::unsync::OnceCell; use profile::Count; use rustc_hash::FxHashMap; +use smallvec::SmallVec; use syntax::{ ast::{ self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind, @@ -30,14 +31,14 @@ use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, db::DefDatabase, expr::{ - dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper, - Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField, - Statement, + dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, ClosureKind, Expr, ExprId, + FloatTypeWrapper, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, + RecordFieldPat, RecordLitField, Statement, }, item_scope::BuiltinShadowMode, path::{GenericArgs, Path}, type_ref::{Mutability, Rawness, TypeRef}, - AdtId, BlockLoc, ModuleDefId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro, }; pub struct LowerCtx<'a> { @@ -87,16 +88,14 @@ pub(super) fn lower( body: Body { exprs: Arena::default(), pats: Arena::default(), + bindings: Arena::default(), labels: Arena::default(), params: Vec::new(), body_expr: dummy_expr_id(), block_scopes: Vec::new(), _c: Count::new(), - or_pats: Default::default(), }, expander, - name_to_pat_grouping: Default::default(), - is_lowering_inside_or_pat: false, is_lowering_assignee_expr: false, is_lowering_generator: false, } @@ -109,13 +108,26 @@ struct ExprCollector<'a> { ast_id_map: Arc<AstIdMap>, body: Body, source_map: BodySourceMap, - // a poor-mans union-find? - name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>, - is_lowering_inside_or_pat: bool, is_lowering_assignee_expr: bool, is_lowering_generator: bool, } +#[derive(Debug, Default)] +struct BindingList { + map: FxHashMap<Name, BindingId>, +} + +impl BindingList { + fn find( + &mut self, + ec: &mut ExprCollector<'_>, + name: Name, + mode: BindingAnnotation, + ) -> BindingId { + *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode)) + } +} + impl ExprCollector<'_> { fn collect( mut self, @@ -127,17 +139,16 @@ impl ExprCollector<'_> { 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 { - name: name![self], - mode: BindingAnnotation::new( - self_param.mut_token().is_some() && self_param.amp_token().is_none(), - false, - ), - subpat: None, - }, - Either::Right(ptr), + let binding_id = self.alloc_binding( + name![self], + BindingAnnotation::new( + self_param.mut_token().is_some() && self_param.amp_token().is_none(), + false, + ), ); + let param_pat = + self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, Either::Right(ptr)); + self.add_definition_to_binding(binding_id, param_pat); self.body.params.push(param_pat); } @@ -179,6 +190,9 @@ impl ExprCollector<'_> { id } + fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId { + self.body.bindings.alloc(Binding { name, mode, definitions: SmallVec::new() }) + } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let src = self.expander.to_source(ptr); let id = self.make_pat(pat, src.clone()); @@ -238,33 +252,32 @@ impl ExprCollector<'_> { } ast::Expr::BlockExpr(e) => match e.modifier() { Some(ast::BlockModifier::Try(_)) => { - let body = self.collect_block(e); - self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) + self.collect_block_(e, |id, statements, tail| Expr::TryBlock { + id, + statements, + tail, + }) } Some(ast::BlockModifier::Unsafe(_)) => { - let body = self.collect_block(e); - self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) + self.collect_block_(e, |id, statements, tail| Expr::Unsafe { + id, + statements, + tail, + }) } - // FIXME: we need to record these effects somewhere... Some(ast::BlockModifier::Label(label)) => { let label = self.collect_label(label); - let res = self.collect_block(e); - match &mut self.body.exprs[res] { - Expr::Block { label: block_label, .. } => { - *block_label = Some(label); - } - _ => unreachable!(), - } - res - } - Some(ast::BlockModifier::Async(_)) => { - let body = self.collect_block(e); - self.alloc_expr(Expr::Async { body }, syntax_ptr) - } - Some(ast::BlockModifier::Const(_)) => { - let body = self.collect_block(e); - self.alloc_expr(Expr::Const { body }, syntax_ptr) + self.collect_block_(e, |id, statements, tail| Expr::Block { + id, + statements, + tail, + label: Some(label), + }) } + Some(ast::BlockModifier::Async(_)) => self + .collect_block_(e, |id, statements, tail| Expr::Async { id, statements, tail }), + Some(ast::BlockModifier::Const(_)) => self + .collect_block_(e, |id, statements, tail| Expr::Const { id, statements, tail }), None => self.collect_block(e), }, ast::Expr::LoopExpr(e) => { @@ -486,6 +499,8 @@ impl ExprCollector<'_> { Movability::Movable }; ClosureKind::Generator(movability) + } else if e.async_token().is_some() { + ClosureKind::Async } else { ClosureKind::Closure }; @@ -737,6 +752,19 @@ impl ExprCollector<'_> { } fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { + self.collect_block_(block, |id, statements, tail| Expr::Block { + id, + statements, + tail, + label: None, + }) + } + + fn collect_block_( + &mut self, + block: ast::BlockExpr, + mk_block: impl FnOnce(BlockId, Box<[Statement]>, Option<ExprId>) -> Expr, + ) -> ExprId { let file_local_id = self.ast_id_map.ast_id(&block); let ast_id = AstId::new(self.expander.current_file_id, file_local_id); let block_loc = @@ -769,15 +797,8 @@ impl ExprCollector<'_> { }); let syntax_node_ptr = AstPtr::new(&block.into()); - let expr_id = self.alloc_expr( - Expr::Block { - id: block_id, - statements: statements.into_boxed_slice(), - tail, - label: None, - }, - syntax_node_ptr, - ); + let expr_id = self + .alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr); self.expander.def_map = prev_def_map; self.expander.module = prev_local_module; @@ -799,13 +820,7 @@ impl ExprCollector<'_> { } fn collect_pat(&mut self, pat: ast::Pat) -> PatId { - let pat_id = self.collect_pat_(pat); - for (_, pats) in self.name_to_pat_grouping.drain() { - let pats = Arc::<[_]>::from(pats); - self.body.or_pats.extend(pats.iter().map(|&pat| (pat, pats.clone()))); - } - self.is_lowering_inside_or_pat = false; - pat_id + self.collect_pat_(pat, &mut BindingList::default()) } fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { @@ -815,16 +830,18 @@ impl ExprCollector<'_> { } } - fn collect_pat_(&mut self, pat: ast::Pat) -> PatId { + fn collect_pat_(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId { let pattern = match &pat { ast::Pat::IdentPat(bp) => { let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); - let key = self.is_lowering_inside_or_pat.then(|| name.clone()); let annotation = BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); - let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat)); - let pattern = if annotation == BindingAnnotation::Unannotated && subpat.is_none() { + let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat, binding_list)); + + let is_simple_ident_pat = + annotation == BindingAnnotation::Unannotated && subpat.is_none(); + let (binding, pattern) = if is_simple_ident_pat { // This could also be a single-segment path pattern. To // decide that, we need to try resolving the name. let (resolved, _) = self.expander.def_map.resolve_path( @@ -834,12 +851,12 @@ impl ExprCollector<'_> { BuiltinShadowMode::Other, ); match resolved.take_values() { - Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), + Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), Some(ModuleDefId::EnumVariantId(_)) => { // this is only really valid for unit variants, but // shadowing other enum variants with a pattern is // an error anyway - Pat::Path(name.into()) + (None, Pat::Path(name.into())) } Some(ModuleDefId::AdtId(AdtId::StructId(s))) if self.db.struct_data(s).variant_data.kind() != StructKind::Record => @@ -847,30 +864,34 @@ impl ExprCollector<'_> { // Funnily enough, record structs *can* be shadowed // by pattern bindings (but unit or tuple structs // can't). - Pat::Path(name.into()) + (None, Pat::Path(name.into())) } // shadowing statics is an error as well, so we just ignore that case here - _ => Pat::Bind { name, mode: annotation, subpat }, + _ => { + let id = binding_list.find(self, name, annotation); + (Some(id), Pat::Bind { id, subpat }) + } } } else { - Pat::Bind { name, mode: annotation, subpat } + let id = binding_list.find(self, name, annotation); + (Some(id), Pat::Bind { id, subpat }) }; let ptr = AstPtr::new(&pat); let pat = self.alloc_pat(pattern, Either::Left(ptr)); - if let Some(key) = key { - self.name_to_pat_grouping.entry(key).or_default().push(pat); + if let Some(binding_id) = binding { + self.add_definition_to_binding(binding_id, pat); } return pat; } ast::Pat::TupleStructPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); - let (args, ellipsis) = self.collect_tuple_pat(p.fields()); + let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list); Pat::TupleStruct { path, args, ellipsis } } ast::Pat::RefPat(p) => { - let pat = self.collect_pat_opt(p.pat()); + let pat = self.collect_pat_opt_(p.pat(), binding_list); let mutability = Mutability::from_mutable(p.mut_token().is_some()); Pat::Ref { pat, mutability } } @@ -880,13 +901,12 @@ impl ExprCollector<'_> { path.map(Pat::Path).unwrap_or(Pat::Missing) } ast::Pat::OrPat(p) => { - self.is_lowering_inside_or_pat = true; - let pats = p.pats().map(|p| self.collect_pat_(p)).collect(); + let pats = p.pats().map(|p| self.collect_pat_(p, binding_list)).collect(); Pat::Or(pats) } - ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat()), + ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat(), binding_list), ast::Pat::TuplePat(p) => { - let (args, ellipsis) = self.collect_tuple_pat(p.fields()); + let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list); Pat::Tuple { args, ellipsis } } ast::Pat::WildcardPat(_) => Pat::Wild, @@ -899,7 +919,7 @@ impl ExprCollector<'_> { .fields() .filter_map(|f| { let ast_pat = f.pat()?; - let pat = self.collect_pat_(ast_pat); + let pat = self.collect_pat_(ast_pat, binding_list); let name = f.field_name()?.as_name(); Some(RecordFieldPat { name, pat }) }) @@ -918,9 +938,15 @@ impl ExprCollector<'_> { // FIXME properly handle `RestPat` Pat::Slice { - prefix: prefix.into_iter().map(|p| self.collect_pat_(p)).collect(), - slice: slice.map(|p| self.collect_pat_(p)), - suffix: suffix.into_iter().map(|p| self.collect_pat_(p)).collect(), + prefix: prefix + .into_iter() + .map(|p| self.collect_pat_(p, binding_list)) + .collect(), + slice: slice.map(|p| self.collect_pat_(p, binding_list)), + suffix: suffix + .into_iter() + .map(|p| self.collect_pat_(p, binding_list)) + .collect(), } } ast::Pat::LiteralPat(lit) => { @@ -943,7 +969,7 @@ impl ExprCollector<'_> { Pat::Missing } ast::Pat::BoxPat(boxpat) => { - let inner = self.collect_pat_opt_(boxpat.pat()); + let inner = self.collect_pat_opt_(boxpat.pat(), binding_list); Pat::Box { inner } } ast::Pat::ConstBlockPat(const_block_pat) => { @@ -960,7 +986,7 @@ impl ExprCollector<'_> { let src = self.expander.to_source(Either::Left(AstPtr::new(&pat))); let pat = self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { - this.collect_pat_opt_(expanded_pat) + this.collect_pat_opt_(expanded_pat, binding_list) }); self.source_map.pat_map.insert(src, pat); return pat; @@ -974,21 +1000,25 @@ impl ExprCollector<'_> { self.alloc_pat(pattern, Either::Left(ptr)) } - fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>) -> PatId { + fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId { match pat { - Some(pat) => self.collect_pat_(pat), + Some(pat) => self.collect_pat_(pat, binding_list), None => self.missing_pat(), } } - fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Box<[PatId]>, Option<usize>) { + fn collect_tuple_pat( + &mut self, + args: AstChildren<ast::Pat>, + binding_list: &mut BindingList, + ) -> (Box<[PatId]>, Option<usize>) { // Find the location of the `..`, if there is one. Note that we do not // consider the possibility of there being multiple `..` here. let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); // We want to skip the `..` pattern here, since we account for it above. let args = args .filter(|p| !matches!(p, ast::Pat::RestPat(_))) - .map(|p| self.collect_pat_(p)) + .map(|p| self.collect_pat_(p, binding_list)) .collect(); (args, ellipsis) @@ -1017,6 +1047,10 @@ impl ExprCollector<'_> { None => Some(()), } } + + fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) { + self.body.bindings[binding_id].definitions.push(pat_id); + } } impl From<ast::LiteralKind> for Literal { 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 4b4664a1c..5a9b825a2 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 @@ -5,7 +5,7 @@ use std::fmt::{self, Write}; use syntax::ast::HasName; use crate::{ - expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement}, + expr::{Array, BindingAnnotation, BindingId, ClosureKind, Literal, Movability, Statement}, pretty::{print_generic_args, print_path, print_type_ref}, type_ref::TypeRef, }; @@ -292,18 +292,6 @@ impl<'a> Printer<'a> { self.print_expr(*expr); w!(self, "?"); } - Expr::TryBlock { body } => { - w!(self, "try "); - self.print_expr(*body); - } - Expr::Async { body } => { - w!(self, "async "); - self.print_expr(*body); - } - Expr::Const { body } => { - w!(self, "const "); - self.print_expr(*body); - } Expr::Cast { expr, type_ref } => { self.print_expr(*expr); w!(self, " as "); @@ -372,8 +360,14 @@ impl<'a> Printer<'a> { w!(self, "]"); } Expr::Closure { args, arg_types, ret_type, body, closure_kind } => { - if let ClosureKind::Generator(Movability::Static) = closure_kind { - w!(self, "static "); + match closure_kind { + ClosureKind::Generator(Movability::Static) => { + w!(self, "static "); + } + ClosureKind::Async => { + w!(self, "async "); + } + _ => (), } w!(self, "|"); for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() { @@ -402,10 +396,6 @@ impl<'a> Printer<'a> { } w!(self, ")"); } - Expr::Unsafe { body } => { - w!(self, "unsafe "); - self.print_expr(*body); - } Expr::Array(arr) => { w!(self, "["); if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) { @@ -428,25 +418,47 @@ impl<'a> Printer<'a> { } Expr::Literal(lit) => self.print_literal(lit), Expr::Block { id: _, statements, tail, label } => { - self.whitespace(); - if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name); + let label = label.map(|lbl| format!("{}: ", self.body[lbl].name)); + self.print_block(label.as_deref(), statements, tail); + } + Expr::Unsafe { id: _, statements, tail } => { + self.print_block(Some("unsafe "), statements, tail); + } + Expr::TryBlock { id: _, statements, tail } => { + self.print_block(Some("try "), statements, tail); + } + Expr::Async { id: _, statements, tail } => { + self.print_block(Some("async "), statements, tail); + } + Expr::Const { id: _, statements, tail } => { + self.print_block(Some("const "), statements, tail); + } + } + } + + fn print_block( + &mut self, + label: Option<&str>, + statements: &Box<[Statement]>, + tail: &Option<la_arena::Idx<Expr>>, + ) { + self.whitespace(); + if let Some(lbl) = label { + w!(self, "{}", lbl); + } + w!(self, "{{"); + if !statements.is_empty() || tail.is_some() { + self.indented(|p| { + for stmt in &**statements { + p.print_stmt(stmt); } - w!(self, "{{"); - if !statements.is_empty() || tail.is_some() { - self.indented(|p| { - for stmt in &**statements { - p.print_stmt(stmt); - } - if let Some(tail) = tail { - p.print_expr(*tail); - } - p.newline(); - }); + if let Some(tail) = tail { + p.print_expr(*tail); } - w!(self, "}}"); - } + p.newline(); + }); } + w!(self, "}}"); } fn print_pat(&mut self, pat: PatId) { @@ -518,14 +530,8 @@ impl<'a> Printer<'a> { } Pat::Path(path) => self.print_path(path), Pat::Lit(expr) => self.print_expr(*expr), - Pat::Bind { mode, name, subpat } => { - let mode = match mode { - BindingAnnotation::Unannotated => "", - BindingAnnotation::Mutable => "mut ", - BindingAnnotation::Ref => "ref ", - BindingAnnotation::RefMut => "ref mut ", - }; - w!(self, "{}{}", mode, name); + Pat::Bind { id, subpat } => { + self.print_binding(*id); if let Some(pat) = subpat { self.whitespace(); self.print_pat(*pat); @@ -629,4 +635,15 @@ impl<'a> Printer<'a> { fn print_path(&mut self, path: &Path) { print_path(path, self).unwrap(); } + + fn print_binding(&mut self, id: BindingId) { + let Binding { name, mode, .. } = &self.body.bindings[id]; + let mode = match mode { + BindingAnnotation::Unannotated => "", + BindingAnnotation::Mutable => "mut ", + BindingAnnotation::Ref => "ref ", + BindingAnnotation::RefMut => "ref mut ", + }; + w!(self, "{}{}", mode, name); + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index 2617d4288..12fc1f116 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; use crate::{ body::Body, db::DefDatabase, - expr::{Expr, ExprId, LabelId, Pat, PatId, Statement}, + expr::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement}, BlockId, DefWithBodyId, }; @@ -23,7 +23,7 @@ pub struct ExprScopes { #[derive(Debug, PartialEq, Eq)] pub struct ScopeEntry { name: Name, - pat: PatId, + binding: BindingId, } impl ScopeEntry { @@ -31,8 +31,8 @@ impl ScopeEntry { &self.name } - pub fn pat(&self) -> PatId { - self.pat + pub fn binding(&self) -> BindingId { + self.binding } } @@ -66,6 +66,7 @@ impl ExprScopes { self.scopes[scope].label.clone() } + /// Returns the scopes in ascending order. pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { std::iter::successors(scope, move |&scope| self.scopes[scope].parent) } @@ -125,18 +126,23 @@ impl ExprScopes { }) } - fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { + fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) { + let Binding { name, .. } = &body.bindings[binding]; + let entry = ScopeEntry { name: name.clone(), binding }; + self.scopes[scope].entries.push(entry); + } + + fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { let pattern = &body[pat]; - if let Pat::Bind { name, .. } = pattern { - let entry = ScopeEntry { name: name.clone(), pat }; - self.scopes[scope].entries.push(entry); + if let Pat::Bind { id, .. } = pattern { + self.add_bindings(body, scope, *id); } - pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat)); + pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat)); } fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { - params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); + params.iter().for_each(|pat| self.add_pat_bindings(body, scope, *pat)); } fn set_scope(&mut self, node: ExprId, scope: ScopeId) { @@ -169,7 +175,7 @@ fn compute_block_scopes( } *scope = scopes.new_scope(*scope); - scopes.add_bindings(body, *scope, *pat); + scopes.add_pat_bindings(body, *scope, *pat); } Statement::Expr { expr, .. } => { compute_expr_scopes(*expr, body, scopes, scope); @@ -194,10 +200,20 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope scopes.set_scope(expr, scope); compute_block_scopes(statements, *tail, body, scopes, &mut scope); } + Expr::Unsafe { id, statements, tail } + | Expr::Async { id, statements, tail } + | Expr::Const { id, statements, tail } + | Expr::TryBlock { id, statements, tail } => { + let mut scope = scopes.new_block_scope(*scope, *id, None); + // Overwrite the old scope for the block expr, so that every block scope can be found + // via the block itself (important for blocks that only contain items, no expressions). + scopes.set_scope(expr, scope); + compute_block_scopes(statements, *tail, body, scopes, &mut scope); + } Expr::For { iterable, pat, body: body_expr, label } => { compute_expr_scopes(*iterable, body, scopes, scope); let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); - scopes.add_bindings(body, scope, *pat); + scopes.add_pat_bindings(body, scope, *pat); compute_expr_scopes(*body_expr, body, scopes, &mut scope); } Expr::While { condition, body: body_expr, label } => { @@ -218,7 +234,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope compute_expr_scopes(*expr, body, scopes, scope); for arm in arms.iter() { let mut scope = scopes.new_scope(*scope); - scopes.add_bindings(body, scope, arm.pat); + scopes.add_pat_bindings(body, scope, arm.pat); if let Some(guard) = arm.guard { scope = scopes.new_scope(scope); compute_expr_scopes(guard, body, scopes, &mut scope); @@ -237,7 +253,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope &Expr::Let { pat, expr } => { compute_expr_scopes(expr, body, scopes, scope); *scope = scopes.new_scope(*scope); - scopes.add_bindings(body, *scope, pat); + scopes.add_pat_bindings(body, *scope, pat); } e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), }; @@ -439,7 +455,7 @@ fn foo() { let function = find_function(&db, file_id); let scopes = db.expr_scopes(function.into()); - let (_body, source_map) = db.body_with_source_map(function.into()); + let (body, source_map) = db.body_with_source_map(function.into()); let expr_scope = { let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); @@ -449,7 +465,9 @@ fn foo() { }; let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap(); - let pat_src = source_map.pat_syntax(resolved.pat()).unwrap(); + let pat_src = source_map + .pat_syntax(*body.bindings[resolved.binding()].definitions.first().unwrap()) + .unwrap(); let local_name = pat_src.value.either( |it| it.syntax_node_ptr().to_node(file.syntax()), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs index 3bba08cfc..77ac221e5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs @@ -395,3 +395,25 @@ fn foo() { "#]], ) } + +#[test] +fn trailing_expr_macro_expands_stmts() { + check_at( + r#" +macro_rules! foo { + () => { const FOO: u32 = 0;const BAR: u32 = 0; }; +} +fn f() {$0 + foo!{} +}; + "#, + expect![[r#" + block scope + BAR: v + FOO: v + + crate + f: v + "#]], + ) +} 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 19d2fe956..68b57acca 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 @@ -1,7 +1,7 @@ //! When *constructing* `hir`, we start at some parent syntax node and recursively //! lower the children. //! -//! This modules allows one to go in the opposite direction: start with a syntax +//! This module allows one to go in the opposite direction: start with a syntax //! node for a *child*, and get its hir. use either::Either; @@ -145,6 +145,7 @@ impl ChildBySource for ItemScope { ModuleDefId::StaticId(id) => insert!(map[keys::STATIC].insert(id)), ModuleDefId::TypeAliasId(id) => insert!(map[keys::TYPE_ALIAS].insert(id)), ModuleDefId::TraitId(id) => insert!(map[keys::TRAIT].insert(id)), + ModuleDefId::TraitAliasId(id) => insert!(map[keys::TRAIT_ALIAS].insert(id)), ModuleDefId::AdtId(adt) => match adt { AdtId::StructId(id) => insert!(map[keys::STRUCT].insert(id)), AdtId::UnionId(id) => insert!(map[keys::UNION].insert(id)), 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 c3c1dfd39..1633a33be 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -22,7 +22,7 @@ use crate::{ visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, ProcMacroId, - StaticId, TraitId, TypeAliasId, TypeAliasLoc, + StaticId, TraitAliasId, TraitId, TypeAliasId, TypeAliasLoc, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -35,6 +35,7 @@ pub struct FunctionData { pub visibility: RawVisibility, pub abi: Option<Interned<str>>, pub legacy_const_generics_indices: Box<[u32]>, + pub rustc_allow_incoherent_impl: bool, flags: FnFlags, } @@ -84,13 +85,14 @@ impl FunctionData { } } - let legacy_const_generics_indices = item_tree - .attrs(db, krate, ModItem::from(loc.id.value).into()) + let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); + let legacy_const_generics_indices = attrs .by_key("rustc_legacy_const_generics") .tt_values() .next() .map(parse_rustc_legacy_const_generics) .unwrap_or_default(); + let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); Arc::new(FunctionData { name: func.name.clone(), @@ -108,6 +110,7 @@ impl FunctionData { abi: func.abi.clone(), legacy_const_generics_indices, flags, + rustc_allow_incoherent_impl, }) } @@ -171,6 +174,7 @@ pub struct TypeAliasData { pub visibility: RawVisibility, pub is_extern: bool, pub rustc_has_incoherent_inherent_impls: bool, + pub rustc_allow_incoherent_impl: bool, /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). pub bounds: Vec<Interned<TypeBound>>, } @@ -189,10 +193,14 @@ impl TypeAliasData { item_tree[typ.visibility].clone() }; - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) - .by_key("rustc_has_incoherent_inherent_impls") - .exists(); + let attrs = item_tree.attrs( + db, + loc.container.module(db).krate(), + ModItem::from(loc.id.value).into(), + ); + let rustc_has_incoherent_inherent_impls = + attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); + let rustc_allow_incoherent_impl = attrs.by_key("rustc_allow_incoherent_impl").exists(); Arc::new(TypeAliasData { name: typ.name.clone(), @@ -200,6 +208,7 @@ impl TypeAliasData { visibility, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), rustc_has_incoherent_inherent_impls, + rustc_allow_incoherent_impl, bounds: typ.bounds.to_vec(), }) } @@ -212,11 +221,12 @@ pub struct TraitData { pub is_auto: bool, pub is_unsafe: bool, pub rustc_has_incoherent_inherent_impls: bool, + pub skip_array_during_method_dispatch: bool, + pub fundamental: bool, pub visibility: RawVisibility, /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore /// method calls to this trait's methods when the receiver is an array and the crate edition is /// 2015 or 2018. - pub skip_array_during_method_dispatch: bool, // box it as the vec is usually empty anyways pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, } @@ -245,19 +255,12 @@ impl TraitData { attrs.by_key("rustc_skip_array_during_method_dispatch").exists(); let rustc_has_incoherent_inherent_impls = attrs.by_key("rustc_has_incoherent_inherent_impls").exists(); - let (items, attribute_calls, diagnostics) = match &tr_def.items { - Some(items) => { - let mut collector = AssocItemCollector::new( - db, - module_id, - tree_id.file_id(), - ItemContainerId::TraitId(tr), - ); - collector.collect(&item_tree, tree_id.tree_id(), items); - collector.finish() - } - None => Default::default(), - }; + let fundamental = attrs.by_key("fundamental").exists(); + let mut collector = + AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); + collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); + let (items, attribute_calls, diagnostics) = collector.finish(); + ( Arc::new(TraitData { name, @@ -268,6 +271,7 @@ impl TraitData { visibility, skip_array_during_method_dispatch, rustc_has_incoherent_inherent_impls, + fundamental, }), diagnostics.into(), ) @@ -300,6 +304,23 @@ impl TraitData { } #[derive(Debug, Clone, PartialEq, Eq)] +pub struct TraitAliasData { + pub name: Name, + pub visibility: RawVisibility, +} + +impl TraitAliasData { + pub(crate) fn trait_alias_query(db: &dyn DefDatabase, id: TraitAliasId) -> Arc<TraitAliasData> { + let loc = id.lookup(db); + let item_tree = loc.id.item_tree(db); + let alias = &item_tree[loc.id.value]; + let visibility = item_tree[alias.visibility].clone(); + + Arc::new(TraitAliasData { name: alias.name.clone(), visibility }) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ImplData { pub target_trait: Option<Interned<TraitRef>>, pub self_ty: Interned<TypeRef>, @@ -441,6 +462,7 @@ pub struct ConstData { pub name: Option<Name>, pub type_ref: Interned<TypeRef>, pub visibility: RawVisibility, + pub rustc_allow_incoherent_impl: bool, } impl ConstData { @@ -454,10 +476,16 @@ impl ConstData { item_tree[konst.visibility].clone() }; + let rustc_allow_incoherent_impl = item_tree + .attrs(db, loc.container.module(db).krate(), ModItem::from(loc.id.value).into()) + .by_key("rustc_allow_incoherent_impl") + .exists(); + Arc::new(ConstData { name: konst.name.clone(), type_ref: konst.type_ref.clone(), visibility, + rustc_allow_incoherent_impl, }) } } 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 b23427a73..9371fc14d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use base_db::{salsa, CrateId, SourceDatabase, Upcast}; use either::Either; -use hir_expand::{db::AstDatabase, HirFileId}; +use hir_expand::{db::ExpandDatabase, HirFileId}; use intern::Interned; use la_arena::ArenaMap; use syntax::{ast, AstPtr}; @@ -14,7 +14,7 @@ use crate::{ body::{scope::ExprScopes, Body, BodySourceMap}, data::{ ConstData, FunctionData, ImplData, Macro2Data, MacroRulesData, ProcMacroData, StaticData, - TraitData, TypeAliasData, + TraitAliasData, TraitData, TypeAliasData, }, generics::GenericParams, import_map::ImportMap, @@ -25,8 +25,8 @@ use crate::{ AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, - StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, - UnionId, UnionLoc, VariantId, + StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, + TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -46,6 +46,8 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_trait(&self, loc: TraitLoc) -> TraitId; #[salsa::interned] + fn intern_trait_alias(&self, loc: TraitAliasLoc) -> TraitAliasId; + #[salsa::interned] fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; #[salsa::interned] fn intern_impl(&self, loc: ImplLoc) -> ImplId; @@ -62,7 +64,7 @@ pub trait InternDatabase: SourceDatabase { } #[salsa::query_group(DefDatabaseStorage)] -pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { +pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> { #[salsa::input] fn enable_proc_attr_macros(&self) -> bool; @@ -125,6 +127,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { #[salsa::invoke(TraitData::trait_data_with_diagnostics_query)] fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>); + #[salsa::invoke(TraitAliasData::trait_alias_query)] + fn trait_alias_data(&self, e: TraitAliasId) -> Arc<TraitAliasData>; + #[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 48028b7c6..19fa6b254 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs @@ -17,6 +17,7 @@ use std::fmt; use hir_expand::name::Name; use intern::Interned; use la_arena::{Idx, RawIdx}; +use smallvec::SmallVec; use crate::{ builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, @@ -29,6 +30,8 @@ pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, Unar pub type ExprId = Idx<Expr>; +pub type BindingId = Idx<Binding>; + /// FIXME: this is a hacky function which should be removed pub(crate) fn dummy_expr_id() -> ExprId { ExprId::from_raw(RawIdx::from(u32::MAX)) @@ -52,13 +55,21 @@ pub type LabelId = Idx<Label>; // We convert float values into bits and that's how we don't need to deal with f32 and f64. // For PartialEq, bits comparison should work, as ordering is not important // https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360 -#[derive(Default, Debug, Clone, Eq, PartialEq)] +#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)] pub struct FloatTypeWrapper(u64); impl FloatTypeWrapper { pub fn new(value: f64) -> Self { Self(value.to_bits()) } + + pub fn into_f64(self) -> f64 { + f64::from_bits(self.0) + } + + pub fn into_f32(self) -> f32 { + f64::from_bits(self.0) as f32 + } } impl fmt::Display for FloatTypeWrapper { @@ -101,6 +112,26 @@ pub enum Expr { tail: Option<ExprId>, label: Option<LabelId>, }, + TryBlock { + id: BlockId, + statements: Box<[Statement]>, + tail: Option<ExprId>, + }, + Async { + id: BlockId, + statements: Box<[Statement]>, + tail: Option<ExprId>, + }, + Const { + id: BlockId, + statements: Box<[Statement]>, + tail: Option<ExprId>, + }, + Unsafe { + id: BlockId, + statements: Box<[Statement]>, + tail: Option<ExprId>, + }, Loop { body: ExprId, label: Option<LabelId>, @@ -164,15 +195,6 @@ pub enum Expr { Try { expr: ExprId, }, - TryBlock { - body: ExprId, - }, - Async { - body: ExprId, - }, - Const { - body: ExprId, - }, Cast { expr: ExprId, type_ref: Interned<TypeRef>, @@ -214,9 +236,6 @@ pub enum Expr { exprs: Box<[ExprId]>, is_assignee_expr: bool, }, - Unsafe { - body: ExprId, - }, Array(Array), Literal(Literal), Underscore, @@ -226,6 +245,7 @@ pub enum Expr { pub enum ClosureKind { Closure, Generator(Movability), + Async, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -282,13 +302,20 @@ impl Expr { Expr::Let { expr, .. } => { f(*expr); } - Expr::Block { statements, tail, .. } => { + Expr::Block { statements, tail, .. } + | Expr::TryBlock { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } + | Expr::Const { statements, tail, .. } => { for stmt in statements.iter() { match stmt { - Statement::Let { initializer, .. } => { + Statement::Let { initializer, else_branch, .. } => { if let &Some(expr) = initializer { f(expr); } + if let &Some(expr) = else_branch { + f(expr); + } } Statement::Expr { expr: expression, .. } => f(*expression), } @@ -297,10 +324,6 @@ impl Expr { f(expr); } } - Expr::TryBlock { body } - | Expr::Unsafe { body } - | Expr::Async { body } - | Expr::Const { body } => f(*body), Expr::Loop { body, .. } => f(*body), Expr::While { condition, body, .. } => { f(*condition); @@ -415,6 +438,13 @@ impl BindingAnnotation { } #[derive(Debug, Clone, Eq, PartialEq)] +pub struct Binding { + pub name: Name, + pub mode: BindingAnnotation, + pub definitions: SmallVec<[PatId; 1]>, +} + +#[derive(Debug, Clone, Eq, PartialEq)] pub struct RecordFieldPat { pub name: Name, pub pat: PatId, @@ -432,7 +462,7 @@ pub enum Pat { Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> }, Path(Box<Path>), Lit(ExprId), - Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, + Bind { id: BindingId, subpat: Option<PatId> }, TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> }, Ref { pat: PatId, mutability: Mutability }, Box { inner: PatId }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index b2ab0c30e..e4912fa8a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -187,6 +187,7 @@ impl GenericParams { GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id), GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id), GenericDefId::TraitId(id) => id_to_generics!(id), + GenericDefId::TraitAliasId(id) => id_to_generics!(id), GenericDefId::TypeAliasId(id) => id_to_generics!(id), GenericDefId::ImplId(id) => id_to_generics!(id), GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { @@ -207,12 +208,10 @@ impl GenericParams { pub(crate) fn fill_bounds( &mut self, lower_ctx: &LowerCtx<'_>, - node: &dyn ast::HasTypeBounds, + type_bounds: Option<ast::TypeBoundList>, target: Either<TypeRef, LifetimeRef>, ) { - for bound in - node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) - { + for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) { self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); } } @@ -233,7 +232,11 @@ impl GenericParams { }; self.type_or_consts.alloc(param.into()); let type_ref = TypeRef::Path(name.into()); - self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); + self.fill_bounds( + lower_ctx, + type_param.type_bound_list(), + Either::Left(type_ref), + ); } ast::TypeOrConstParam::Const(const_param) => { let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); @@ -255,7 +258,11 @@ impl GenericParams { let param = LifetimeParamData { name: name.clone() }; self.lifetimes.alloc(param); let lifetime_ref = LifetimeRef::new_name(name); - self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); + self.fill_bounds( + lower_ctx, + lifetime_param.type_bound_list(), + Either::Right(lifetime_ref), + ); } } @@ -421,6 +428,10 @@ fn file_id_and_params_of( let src = it.lookup(db).source(db); (src.file_id, src.value.generic_param_list()) } + GenericDefId::TraitAliasId(it) => { + let src = it.lookup(db).source(db); + (src.file_id, src.value.generic_param_list()) + } GenericDefId::TypeAliasId(it) => { let src = it.lookup(db).source(db); (src.file_id, src.value.generic_param_list()) @@ -435,7 +446,7 @@ fn file_id_and_params_of( } impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId { - type Value = Either<ast::TypeOrConstParam, ast::Trait>; + type Value = Either<ast::TypeOrConstParam, ast::TraitOrAlias>; fn child_source( &self, db: &dyn DefDatabase, @@ -447,11 +458,20 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId { let mut params = ArenaMap::default(); - // For traits the first type index is `Self`, we need to add it before the other params. - if let GenericDefId::TraitId(id) = *self { - let trait_ref = id.lookup(db).source(db).value; - let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(trait_ref)); + // For traits and trait aliases the first type index is `Self`, we need to add it before + // the other params. + match *self { + GenericDefId::TraitId(id) => { + let trait_ref = id.lookup(db).source(db).value; + let idx = idx_iter.next().unwrap(); + params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref))); + } + GenericDefId::TraitAliasId(id) => { + let alias = id.lookup(db).source(db).value; + let idx = idx_iter.next().unwrap(); + params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias))); + } + _ => {} } if let Some(generic_params_list) = generic_params_list { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 1ce191942..4f1f6000d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -264,6 +264,7 @@ pub enum ImportKind { Const, Static, Trait, + TraitAlias, TypeAlias, BuiltinType, AssociatedItem, @@ -459,6 +460,7 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { ModuleDefId::ConstId(_) => ImportKind::Const, ModuleDefId::StaticId(_) => ImportKind::Static, ModuleDefId::TraitId(_) => ImportKind::Trait, + ModuleDefId::TraitAliasId(_) => ImportKind::TraitAlias, ModuleDefId::TypeAliasId(_) => ImportKind::TypeAlias, ModuleDefId::BuiltinType(_) => ImportKind::BuiltinType, ModuleDefId::MacroId(_) => ImportKind::Macro, 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 53a4173ff..991e44703 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 @@ -431,6 +431,7 @@ impl PerNs { ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v), ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v), ModuleDefId::TraitId(_) => PerNs::types(def, v), + ModuleDefId::TraitAliasId(_) => PerNs::types(def, v), ModuleDefId::TypeAliasId(_) => PerNs::types(def, v), ModuleDefId::BuiltinType(_) => PerNs::types(def, v), ModuleDefId::MacroId(mac) => PerNs::macros(mac, v), 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 19d01630e..9da5b2d47 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 @@ -204,6 +204,7 @@ impl ItemTree { consts, statics, traits, + trait_aliases, impls, type_aliases, mods, @@ -226,6 +227,7 @@ impl ItemTree { consts.shrink_to_fit(); statics.shrink_to_fit(); traits.shrink_to_fit(); + trait_aliases.shrink_to_fit(); impls.shrink_to_fit(); type_aliases.shrink_to_fit(); mods.shrink_to_fit(); @@ -276,6 +278,7 @@ struct ItemTreeData { consts: Arena<Const>, statics: Arena<Static>, traits: Arena<Trait>, + trait_aliases: Arena<TraitAlias>, impls: Arena<Impl>, type_aliases: Arena<TypeAlias>, mods: Arena<Mod>, @@ -496,6 +499,7 @@ mod_items! { Const in consts -> ast::Const, Static in statics -> ast::Static, Trait in traits -> ast::Trait, + TraitAlias in trait_aliases -> ast::TraitAlias, Impl in impls -> ast::Impl, TypeAlias in type_aliases -> ast::TypeAlias, Mod in mods -> ast::Module, @@ -672,12 +676,19 @@ pub struct Trait { pub generic_params: Interned<GenericParams>, pub is_auto: bool, pub is_unsafe: bool, - /// This is [`None`] if this Trait is a trait alias. - pub items: Option<Box<[AssocItem]>>, + pub items: Box<[AssocItem]>, pub ast_id: FileAstId<ast::Trait>, } #[derive(Debug, Clone, Eq, PartialEq)] +pub struct TraitAlias { + pub name: Name, + pub visibility: RawVisibilityId, + pub generic_params: Interned<GenericParams>, + pub ast_id: FileAstId<ast::TraitAlias>, +} + +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Impl { pub generic_params: Interned<GenericParams>, pub target_trait: Option<Interned<TraitRef>>, @@ -872,6 +883,7 @@ impl ModItem { | ModItem::Enum(_) | ModItem::Static(_) | ModItem::Trait(_) + | ModItem::TraitAlias(_) | ModItem::Impl(_) | ModItem::Mod(_) | ModItem::MacroRules(_) @@ -899,6 +911,7 @@ impl ModItem { ModItem::Const(it) => tree[it.index].ast_id().upcast(), ModItem::Static(it) => tree[it.index].ast_id().upcast(), ModItem::Trait(it) => tree[it.index].ast_id().upcast(), + ModItem::TraitAlias(it) => tree[it.index].ast_id().upcast(), ModItem::Impl(it) => tree[it.index].ast_id().upcast(), ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(), ModItem::Mod(it) => tree[it.index].ast_id().upcast(), 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 d4d3c5ef1..77b186f8e 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 @@ -3,7 +3,7 @@ use std::{collections::hash_map::Entry, sync::Arc}; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; -use syntax::ast::{self, HasModuleItem}; +use syntax::ast::{self, HasModuleItem, HasTypeBounds}; use crate::{ generics::{GenericParams, TypeParamData, TypeParamProvenance}, @@ -90,6 +90,13 @@ impl<'a> Ctx<'a> { _ => None, }) .collect(); + if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() { + if let Some(call) = expr.macro_call() { + if let Some(mod_item) = self.lower_mod_item(&call.into()) { + self.tree.top_level.push(mod_item); + } + } + } self.tree } @@ -110,6 +117,7 @@ impl<'a> Ctx<'a> { ast::Item::Const(ast) => self.lower_const(ast).into(), ast::Item::Module(ast) => self.lower_module(ast)?.into(), ast::Item::Trait(ast) => self.lower_trait(ast)?.into(), + ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(), ast::Item::Impl(ast) => self.lower_impl(ast)?.into(), ast::Item::Use(ast) => self.lower_use(ast)?.into(), ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(), @@ -147,7 +155,7 @@ impl<'a> Ctx<'a> { fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let fields = self.lower_fields(&strukt.kind()); let ast_id = self.source_ast_id_map.ast_id(strukt); let res = Struct { name, visibility, generic_params, fields, ast_id }; @@ -211,7 +219,7 @@ impl<'a> Ctx<'a> { fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Union, union); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let fields = match union.record_field_list() { Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())), @@ -224,7 +232,7 @@ impl<'a> Ctx<'a> { fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()), @@ -372,8 +380,7 @@ impl<'a> Ctx<'a> { ast_id, flags, }; - res.explicit_generic_params = - self.lower_generic_params(GenericsOwner::Function(&res), func); + res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func); Some(id(self.data().functions.alloc(res))) } @@ -386,7 +393,7 @@ impl<'a> Ctx<'a> { let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); let bounds = self.lower_type_bounds(type_alias); - let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, @@ -442,27 +449,49 @@ impl<'a> Ctx<'a> { fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); + let generic_params = + self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let is_auto = trait_def.auto_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some(); - let items = trait_def.assoc_item_list().map(|list| { - list.assoc_items() - .filter_map(|item| { - let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene()); - self.lower_assoc_item(&item).map(|item| { - self.add_attrs(ModItem::from(item).into(), attrs); - item - }) - }) - .collect() - }); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let res = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; - Some(id(self.data().traits.alloc(res))) + + let items = trait_def + .assoc_item_list() + .into_iter() + .flat_map(|list| list.assoc_items()) + .filter_map(|item| { + let attrs = RawAttrs::new(self.db.upcast(), &item, self.hygiene()); + self.lower_assoc_item(&item).map(|item| { + self.add_attrs(ModItem::from(item).into(), attrs); + item + }) + }) + .collect(); + + let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; + Some(id(self.data().traits.alloc(def))) + } + + fn lower_trait_alias( + &mut self, + trait_alias_def: &ast::TraitAlias, + ) -> Option<FileItemTreeId<TraitAlias>> { + let name = trait_alias_def.name()?.as_name(); + let visibility = self.lower_visibility(trait_alias_def); + let generic_params = self.lower_generic_params( + HasImplicitSelf::Yes(trait_alias_def.type_bound_list()), + trait_alias_def, + ); + let ast_id = self.source_ast_id_map.ast_id(trait_alias_def); + + let alias = TraitAlias { name, visibility, generic_params, ast_id }; + Some(id(self.data().trait_aliases.alloc(alias))) } fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { - let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); + // Note that trait impls don't get implicit `Self` unlike traits, because here they are a + // type alias rather than a type parameter, so this is handled by the resolver. + let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only // equals itself. @@ -566,42 +595,29 @@ impl<'a> Ctx<'a> { fn lower_generic_params( &mut self, - owner: GenericsOwner<'_>, + has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, ) -> Interned<GenericParams> { let mut generics = GenericParams::default(); - match owner { - GenericsOwner::Function(_) - | GenericsOwner::Struct - | GenericsOwner::Enum - | GenericsOwner::Union - | GenericsOwner::TypeAlias => { - generics.fill(&self.body_ctx, node); - } - GenericsOwner::Trait(trait_def) => { - // traits get the Self type as an implicit first type parameter - generics.type_or_consts.alloc( - TypeParamData { - name: Some(name![Self]), - default: None, - provenance: TypeParamProvenance::TraitSelf, - } - .into(), - ); - // add super traits as bounds on Self - // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar - let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param)); - generics.fill(&self.body_ctx, node); - } - GenericsOwner::Impl => { - // Note that we don't add `Self` here: in `impl`s, `Self` is not a - // type-parameter, but rather is a type-alias for impl's target - // type, so this is handled by the resolver. - generics.fill(&self.body_ctx, node); - } + + if let HasImplicitSelf::Yes(bounds) = has_implicit_self { + // Traits and trait aliases get the Self type as an implicit first type parameter. + generics.type_or_consts.alloc( + TypeParamData { + name: Some(name![Self]), + default: None, + provenance: TypeParamProvenance::TraitSelf, + } + .into(), + ); + // add super traits as bounds on Self + // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` + let self_param = TypeRef::Path(name![Self].into()); + generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param)); } + generics.fill(&self.body_ctx, node); + generics.shrink_to_fit(); Interned::new(generics) } @@ -673,17 +689,10 @@ fn desugar_future_path(orig: TypeRef) -> Path { Path::from_known_path(path, generic_args) } -enum GenericsOwner<'a> { - /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument - /// position. - Function(&'a Function), - Struct, - Enum, - Union, - /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. - Trait(&'a ast::Trait), - TypeAlias, - Impl, +enum HasImplicitSelf { + /// Inner list is a type bound list for the implicit `Self`. + Yes(Option<ast::TypeBoundList>), + No, } fn lower_abi(abi: ast::Abi) -> Interned<str> { 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 8f230b87d..5f2999796 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 @@ -374,23 +374,24 @@ impl<'a> Printer<'a> { } w!(self, "trait {}", name); self.print_generic_params(generic_params); - match items { - Some(items) => { - self.print_where_clause_and_opening_brace(generic_params); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); - } - }); - } - None => { - w!(self, " = "); - // FIXME: Print the aliased traits - self.print_where_clause_and_opening_brace(generic_params); + self.print_where_clause_and_opening_brace(generic_params); + self.indented(|this| { + for item in &**items { + this.print_mod_item((*item).into()); } - } + }); wln!(self, "}}"); } + ModItem::TraitAlias(it) => { + let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it]; + self.print_visibility(*visibility); + w!(self, "trait {}", name); + self.print_generic_params(generic_params); + w!(self, " = "); + self.print_where_clause(generic_params); + w!(self, ";"); + wln!(self); + } ModItem::Impl(it) => { let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } = &self.tree[it]; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/keys.rs index 72beec818..f30be6b64 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/keys.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/keys.rs @@ -9,8 +9,8 @@ use syntax::{ast, AstNode, AstPtr}; use crate::{ dyn_map::{DynMap, Policy}, ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id, - MacroRulesId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, - UnionId, + MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, + TypeOrConstParamId, UnionId, }; pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>; @@ -21,6 +21,7 @@ pub const STATIC: Key<ast::Static, StaticId> = Key::new(); pub const TYPE_ALIAS: Key<ast::TypeAlias, TypeAliasId> = Key::new(); pub const IMPL: Key<ast::Impl, ImplId> = Key::new(); pub const TRAIT: Key<ast::Trait, TraitId> = Key::new(); +pub const TRAIT_ALIAS: Key<ast::TraitAlias, TraitAliasId> = Key::new(); pub const STRUCT: Key<ast::Struct, StructId> = Key::new(); pub const UNION: Key<ast::Union, UnionId> = Key::new(); pub const ENUM: Key<ast::Enum, EnumId> = Key::new(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index ab9bc615d..4096e0a38 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -181,15 +181,15 @@ impl LangItems { T: Into<AttrDefId> + Copy, { let _p = profile::span("collect_lang_item"); - if let Some(lang_item) = lang_attr(db, item).and_then(|it| LangItem::from_str(&it)) { + if let Some(lang_item) = lang_attr(db, item) { self.items.entry(lang_item).or_insert_with(|| constructor(item)); } } } -pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<SmolStr> { +pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<LangItem> { let attrs = db.attrs(item.into()); - attrs.by_key("lang").string_value().cloned() + attrs.by_key("lang").string_value().cloned().and_then(|it| LangItem::from_str(&it)) } pub enum GenericRequirement { 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 d07c5fb67..8c2e93f09 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -86,7 +86,7 @@ use crate::{ builtin_type::BuiltinType, item_tree::{ Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, ModItem, - Static, Struct, Trait, TypeAlias, Union, + Static, Struct, Trait, TraitAlias, TypeAlias, Union, }, }; @@ -128,7 +128,7 @@ impl ModuleId { } } -/// An ID of a module, **local** to a specific crate +/// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx<nameres::ModuleData>; #[derive(Debug)] @@ -262,6 +262,11 @@ pub type TraitLoc = ItemLoc<Trait>; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TraitAliasId(salsa::InternId); +pub type TraitAliasLoc = ItemLoc<TraitAlias>; +impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct TypeAliasId(salsa::InternId); type TypeAliasLoc = AssocItemLoc<TypeAlias>; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); @@ -453,6 +458,7 @@ pub enum ModuleDefId { ConstId(ConstId), StaticId(StaticId), TraitId(TraitId), + TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), MacroId(MacroId), @@ -466,6 +472,7 @@ impl_from!( ConstId, StaticId, TraitId, + TraitAliasId, TypeAliasId, BuiltinType for ModuleDefId @@ -516,6 +523,7 @@ pub enum GenericDefId { FunctionId(FunctionId), AdtId(AdtId), TraitId(TraitId), + TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), ImplId(ImplId), // enum variants cannot have generics themselves, but their parent enums @@ -528,6 +536,7 @@ impl_from!( FunctionId, AdtId(StructId, EnumId, UnionId), TraitId, + TraitAliasId, TypeAliasId, ImplId, EnumVariantId, @@ -555,6 +564,7 @@ pub enum AttrDefId { StaticId(StaticId), ConstId(ConstId), TraitId(TraitId), + TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), MacroId(MacroId), ImplId(ImplId), @@ -714,6 +724,7 @@ impl HasModule for GenericDefId { GenericDefId::FunctionId(it) => it.lookup(db).module(db), GenericDefId::AdtId(it) => it.module(db), GenericDefId::TraitId(it) => it.lookup(db).container, + GenericDefId::TraitAliasId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).module(db), GenericDefId::ImplId(it) => it.lookup(db).container, GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container, @@ -747,6 +758,7 @@ impl ModuleDefId { ModuleDefId::ConstId(id) => id.lookup(db).container.module(db), ModuleDefId::StaticId(id) => id.lookup(db).module(db), ModuleDefId::TraitId(id) => id.lookup(db).container, + ModuleDefId::TraitAliasId(id) => id.lookup(db).container, ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db), ModuleDefId::MacroId(id) => id.module(db), ModuleDefId::BuiltinType(_) => return None, @@ -765,6 +777,7 @@ impl AttrDefId { AttrDefId::StaticId(it) => it.lookup(db).module(db).krate, AttrDefId::ConstId(it) => it.lookup(db).module(db).krate, AttrDefId::TraitId(it) => it.lookup(db).container.krate, + AttrDefId::TraitAliasId(it) => it.lookup(db).container.krate, AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, AttrDefId::ImplId(it) => it.lookup(db).container.krate, AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs index 5ab90d92d..314bf22b9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests.rs @@ -20,7 +20,7 @@ use ::mbe::TokenMap; use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase}; use expect_test::Expect; use hir_expand::{ - db::{AstDatabase, TokenExpander}, + db::{ExpandDatabase, TokenExpander}, AstId, InFile, MacroDefId, MacroDefKind, MacroFile, }; use stdx::format_to; 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 bb4526672..0b72ca1ee 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 @@ -143,7 +143,7 @@ macro_rules! assert { fn main() { { - if !true { + if !(true ) { $crate::panic!("{} {:?}", arg1(a, b, c), arg2); } }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index 8358a46f0..b663a2917 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -827,6 +827,7 @@ macro_rules! rgb_color { /* parse error: expected type */ /* parse error: expected R_PAREN */ /* parse error: expected R_ANGLE */ +/* parse error: expected `::` */ /* parse error: expected COMMA */ /* parse error: expected R_ANGLE */ /* parse error: expected SEMICOLON */ diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index f42b0079d..4efe8c58a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -120,6 +120,8 @@ pub struct DefMap { registered_tools: Vec<SmolStr>, /// Unstable features of Rust enabled with `#![feature(A, B)]`. unstable_features: FxHashSet<SmolStr>, + /// #[rustc_coherence_is_core] + rustc_coherence_is_core: bool, edition: Edition, recursion_limit: Option<u32>, @@ -215,7 +217,7 @@ pub struct ModuleData { pub origin: ModuleOrigin, /// Declared visibility of this module. pub visibility: Visibility, - + /// Always [`None`] for block modules pub parent: Option<LocalModuleId>, pub children: FxHashMap<Name, LocalModuleId>, pub scope: ItemScope, @@ -292,6 +294,7 @@ impl DefMap { registered_tools: Vec::new(), unstable_features: FxHashSet::default(), diagnostics: Vec::new(), + rustc_coherence_is_core: false, } } @@ -325,6 +328,10 @@ impl DefMap { self.unstable_features.contains(feature) } + pub fn is_rustc_coherence_is_core(&self) -> bool { + self.rustc_coherence_is_core + } + pub fn root(&self) -> LocalModuleId { self.root } @@ -337,12 +344,12 @@ impl DefMap { self.proc_macro_loading_error.as_deref() } - pub(crate) fn krate(&self) -> CrateId { + pub fn krate(&self) -> CrateId { self.krate } pub(crate) fn block_id(&self) -> Option<BlockId> { - self.block.as_ref().map(|block| block.block) + self.block.map(|block| block.block) } pub(crate) fn prelude(&self) -> Option<ModuleId> { @@ -354,7 +361,7 @@ impl DefMap { } pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { - let block = self.block.as_ref().map(|b| b.block); + let block = self.block.map(|b| b.block); ModuleId { krate: self.krate, local_id, block } } @@ -425,12 +432,12 @@ impl DefMap { Some(self.block?.parent) } - /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing + /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing /// the block, if `self` corresponds to a block expression. pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { - match &self[local_mod].parent { - Some(parent) => Some(self.module_id(*parent)), - None => self.block.as_ref().map(|block| block.parent), + match self[local_mod].parent { + Some(parent) => Some(self.module_id(parent)), + None => self.block.map(|block| block.parent), } } @@ -440,11 +447,11 @@ impl DefMap { let mut buf = String::new(); let mut arc; let mut current_map = self; - while let Some(block) = ¤t_map.block { + while let Some(block) = current_map.block { go(&mut buf, current_map, "block scope", current_map.root); buf.push('\n'); arc = block.parent.def_map(db); - current_map = &*arc; + current_map = &arc; } go(&mut buf, current_map, "crate", current_map.root); return buf; @@ -468,10 +475,10 @@ impl DefMap { let mut buf = String::new(); let mut arc; let mut current_map = self; - while let Some(block) = ¤t_map.block { + while let Some(block) = current_map.block { format_to!(buf, "{:?} in {:?}\n", block.block, block.parent); arc = block.parent.def_map(db); - current_map = &*arc; + current_map = &arc; } format_to!(buf, "crate scope\n"); @@ -498,6 +505,7 @@ impl DefMap { krate: _, prelude: _, root: _, + rustc_coherence_is_core: _, } = self; extern_prelude.shrink_to_fit(); 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 4b39a20d8..ddcee77ec 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 @@ -51,7 +51,8 @@ use crate::{ AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, - ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, + ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, + UnresolvedMacro, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -86,10 +87,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T // FIXME: a hacky way to create a Name from string. let name = tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() }; - ( - name.as_name(), - ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), - ) + (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32))) }) .collect() } @@ -298,6 +296,11 @@ impl DefCollector<'_> { continue; } + if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") { + self.def_map.rustc_coherence_is_core = true; + continue; + } + if *attr_name == hir_expand::name![feature] { let features = attr.parse_path_comma_token_tree().into_iter().flatten().filter_map( @@ -580,7 +583,7 @@ impl DefCollector<'_> { let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { Some(&(_, expander)) => (expander, kind), - None => (ProcMacroExpander::dummy(self.def_map.krate), kind), + None => (ProcMacroExpander::dummy(), kind), }; let proc_macro_id = @@ -666,8 +669,10 @@ impl DefCollector<'_> { macro_: Macro2Id, vis: &RawVisibility, ) { - let vis = - self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); + let vis = self + .def_map + .resolve_visibility(self.db, module_id, vis, false) + .unwrap_or(Visibility::Public); self.def_map.modules[module_id].scope.declare(macro_.into()); self.update( module_id, @@ -831,7 +836,7 @@ impl DefCollector<'_> { let mut def = directive.status.namespaces(); let vis = self .def_map - .resolve_visibility(self.db, module_id, &directive.import.visibility) + .resolve_visibility(self.db, module_id, &directive.import.visibility, false) .unwrap_or(Visibility::Public); match import.kind { @@ -1547,7 +1552,7 @@ impl ModCollector<'_, '_> { }; let resolve_vis = |def_map: &DefMap, visibility| { def_map - .resolve_visibility(db, self.module_id, visibility) + .resolve_visibility(db, self.module_id, visibility, false) .unwrap_or(Visibility::Public) }; @@ -1707,6 +1712,20 @@ impl ModCollector<'_, '_> { false, ); } + ModItem::TraitAlias(id) => { + let it = &self.item_tree[id]; + + let vis = resolve_vis(def_map, &self.item_tree[it.visibility]); + update_def( + self.def_collector, + TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + .intern(db) + .into(), + &it.name, + vis, + false, + ); + } ModItem::TypeAlias(id) => { let it = &self.item_tree[id]; @@ -1823,7 +1842,7 @@ impl ModCollector<'_, '_> { ) -> LocalModuleId { let def_map = &mut self.def_collector.def_map; let vis = def_map - .resolve_visibility(self.def_collector.db, self.module_id, visibility) + .resolve_visibility(self.def_collector.db, self.module_id, visibility, false) .unwrap_or(Visibility::Public); let modules = &mut def_map.modules; let origin = match definition { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 1d9d5cccd..25478481d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -78,6 +78,7 @@ impl DefMap { // pub(path) // ^^^^ this visibility: &RawVisibility, + within_impl: bool, ) -> Option<Visibility> { let mut vis = match visibility { RawVisibility::Module(path) => { @@ -102,7 +103,8 @@ impl DefMap { // `super` to its parent (etc.). However, visibilities must only refer to a module in the // DefMap they're written in, so we restrict them when that happens. if let Visibility::Module(m) = vis { - if self.block_id() != m.block { + // ...unless we're resolving visibility for an associated item in an impl. + if self.block_id() != m.block && !within_impl { cov_mark::hit!(adjust_vis_in_block_def_map); vis = Visibility::Module(self.module_id(self.root())); tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index f5190b76d..13e6825f8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -223,6 +223,7 @@ pub type Ty = (); ModuleDefId::ConstId(it) => drop(db.const_data(it)), ModuleDefId::StaticId(it) => drop(db.static_data(it)), ModuleDefId::TraitId(it) => drop(db.trait_data(it)), + ModuleDefId::TraitAliasId(it) => drop(db.trait_alias_data(it)), ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)), ModuleDefId::EnumVariantId(_) | ModuleDefId::ModuleId(_) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index 36d4c36a2..f3197d180 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -8,7 +8,7 @@ use std::{ use crate::{ body::LowerCtx, - type_ref::{ConstScalarOrPath, LifetimeRef}, + type_ref::{ConstRefOrPath, LifetimeRef}, }; use hir_expand::name::Name; use intern::Interned; @@ -85,7 +85,7 @@ pub struct AssociatedTypeBinding { pub enum GenericArg { Type(TypeRef), Lifetime(LifetimeRef), - Const(ConstScalarOrPath), + Const(ConstRefOrPath), } impl Path { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index c85a11db6..b7542bd77 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -2,7 +2,7 @@ use std::iter; -use crate::type_ref::ConstScalarOrPath; +use crate::type_ref::ConstRefOrPath; use either::Either; use hir_expand::name::{name, AsName}; @@ -212,7 +212,7 @@ pub(super) fn lower_generic_args( } } ast::GenericArg::ConstArg(arg) => { - let arg = ConstScalarOrPath::from_expr_opt(arg.expr()); + let arg = ConstRefOrPath::from_expr_opt(arg.expr()); args.push(GenericArg::Const(arg)) } } 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 86958e3da..61e64fc10 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::{hash::BuildHasherDefault, sync::Arc}; +use std::{fmt, hash::BuildHasherDefault, sync::Arc}; use base_db::CrateId; use hir_expand::name::{name, Name}; @@ -12,7 +12,7 @@ use crate::{ body::scope::{ExprScopes, ScopeId}, builtin_type::BuiltinType, db::DefDatabase, - expr::{ExprId, LabelId, PatId}, + expr::{BindingId, ExprId, LabelId}, generics::{GenericParams, TypeOrConstParamData}, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, nameres::DefMap, @@ -22,7 +22,8 @@ use crate::{ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, - StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId, + StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, + VariantId, }; #[derive(Debug, Clone)] @@ -35,19 +36,34 @@ pub struct Resolver { module_scope: ModuleItemMap, } -#[derive(Debug, Clone)] +#[derive(Clone)] struct ModuleItemMap { def_map: Arc<DefMap>, module_id: LocalModuleId, } -#[derive(Debug, Clone)] +impl fmt::Debug for ModuleItemMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish() + } +} + +#[derive(Clone)] struct ExprScope { owner: DefWithBodyId, expr_scopes: Arc<ExprScopes>, scope_id: ScopeId, } +impl fmt::Debug for ExprScope { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ExprScope") + .field("owner", &self.owner) + .field("scope_id", &self.scope_id) + .finish() + } +} + #[derive(Debug, Clone)] enum Scope { /// All the items and imported names of a module @@ -74,6 +90,7 @@ pub enum TypeNs { TypeAliasId(TypeAliasId), BuiltinType(BuiltinType), TraitId(TraitId), + TraitAliasId(TraitAliasId), // Module belong to type ns, but the resolver is used when all module paths // are fully resolved. // ModuleId(ModuleId) @@ -85,10 +102,10 @@ pub enum ResolveValueResult { Partial(TypeNs, usize), } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ValueNs { ImplSelf(ImplId), - LocalBinding(PatId), + LocalBinding(BindingId), FunctionId(FunctionId), ConstId(ConstId), StaticId(StaticId), @@ -214,10 +231,12 @@ impl Resolver { db: &dyn DefDatabase, visibility: &RawVisibility, ) -> Option<Visibility> { + let within_impl = + self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some(); match visibility { RawVisibility::Module(_) => { let (item_map, module) = self.item_scope(); - item_map.resolve_visibility(db, module, visibility) + item_map.resolve_visibility(db, module, visibility, within_impl) } RawVisibility::Public => Some(Visibility::Public), } @@ -236,69 +255,81 @@ impl Resolver { return self.module_scope.resolve_path_in_value_ns(db, path); } - for scope in self.scopes() { - match scope { - Scope::ExprScope(_) if n_segments > 1 => continue, - Scope::ExprScope(scope) => { - let entry = scope - .expr_scopes - .entries(scope.scope_id) - .iter() - .find(|entry| entry.name() == first_name); - - if let Some(e) = entry { - return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); + if n_segments <= 1 { + for scope in self.scopes() { + match scope { + Scope::ExprScope(scope) => { + let entry = scope + .expr_scopes + .entries(scope.scope_id) + .iter() + .find(|entry| entry.name() == first_name); + + if let Some(e) = entry { + return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding( + e.binding(), + ))); + } } - } - Scope::GenericParams { params, def } if n_segments > 1 => { - if let Some(id) = params.find_type_by_name(first_name, *def) { - let ty = TypeNs::GenericParam(id); - return Some(ResolveValueResult::Partial(ty, 1)); + Scope::GenericParams { params, def } => { + if let Some(id) = params.find_const_by_name(first_name, *def) { + let val = ValueNs::GenericParam(id); + return Some(ResolveValueResult::ValueNs(val)); + } } - } - Scope::GenericParams { .. } if n_segments != 1 => continue, - Scope::GenericParams { params, def } => { - if let Some(id) = params.find_const_by_name(first_name, *def) { - let val = ValueNs::GenericParam(id); - return Some(ResolveValueResult::ValueNs(val)); + &Scope::ImplDefScope(impl_) => { + if first_name == &name![Self] { + return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))); + } } - } - - &Scope::ImplDefScope(impl_) => { - if first_name == &name![Self] { - return Some(if n_segments > 1 { - ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1) - } else { - ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)) - }); + // bare `Self` doesn't work in the value namespace in a struct/enum definition + Scope::AdtScope(_) => continue, + Scope::BlockScope(m) => { + if let Some(def) = m.resolve_path_in_value_ns(db, path) { + return Some(def); + } } } - // bare `Self` doesn't work in the value namespace in a struct/enum definition - Scope::AdtScope(_) if n_segments == 1 => continue, - Scope::AdtScope(adt) => { - if first_name == &name![Self] { - let ty = TypeNs::AdtSelfType(*adt); - return Some(ResolveValueResult::Partial(ty, 1)); + } + } else { + for scope in self.scopes() { + match scope { + Scope::ExprScope(_) => continue, + Scope::GenericParams { params, def } => { + if let Some(id) = params.find_type_by_name(first_name, *def) { + let ty = TypeNs::GenericParam(id); + return Some(ResolveValueResult::Partial(ty, 1)); + } } - } - - Scope::BlockScope(m) => { - if let Some(def) = m.resolve_path_in_value_ns(db, path) { - return Some(def); + &Scope::ImplDefScope(impl_) => { + if first_name == &name![Self] { + return Some(ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)); + } + } + Scope::AdtScope(adt) => { + if first_name == &name![Self] { + let ty = TypeNs::AdtSelfType(*adt); + return Some(ResolveValueResult::Partial(ty, 1)); + } + } + Scope::BlockScope(m) => { + if let Some(def) = m.resolve_path_in_value_ns(db, path) { + return Some(def); + } } } } } - if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) { - return res; + if let Some(res) = self.module_scope.resolve_path_in_value_ns(db, path) { + return Some(res); } // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back // to resolving to the primitive type, to allow this to still work in the presence of // `use core::u16;`. - if path.kind == PathKind::Plain && path.segments().len() > 1 { - if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) { + if path.kind == PathKind::Plain && n_segments > 1 { + if let Some(builtin) = BuiltinType::by_name(first_name) { return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); } } @@ -400,6 +431,8 @@ impl Resolver { } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> { + // FIXME(trait_alias): Trait alias brings aliased traits in scope! Note that supertraits of + // aliased traits are NOT brought in scope (unless also aliased). let mut traits = FxHashSet::default(); for scope in self.scopes() { @@ -428,6 +461,15 @@ impl Resolver { traits } + pub fn traits_in_scope_from_block_scopes(&self) -> impl Iterator<Item = TraitId> + '_ { + self.scopes() + .filter_map(|scope| match scope { + Scope::BlockScope(m) => Some(m.def_map[m.module_id].scope.traits()), + _ => None, + }) + .flatten() + } + pub fn module(&self) -> ModuleId { let (def_map, local_id) = self.item_scope(); def_map.module_id(local_id) @@ -459,14 +501,85 @@ impl Resolver { }) } + pub fn generic_params(&self) -> Option<&Interned<GenericParams>> { + self.scopes().find_map(|scope| match scope { + Scope::GenericParams { params, .. } => Some(params), + _ => None, + }) + } + pub fn body_owner(&self) -> Option<DefWithBodyId> { self.scopes().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), _ => None, }) } + /// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver + #[must_use] + pub fn update_to_inner_scope( + &mut self, + db: &dyn DefDatabase, + owner: DefWithBodyId, + expr_id: ExprId, + ) -> UpdateGuard { + #[inline(always)] + fn append_expr_scope( + db: &dyn DefDatabase, + resolver: &mut Resolver, + owner: DefWithBodyId, + expr_scopes: &Arc<ExprScopes>, + scope_id: ScopeId, + ) { + resolver.scopes.push(Scope::ExprScope(ExprScope { + owner, + expr_scopes: expr_scopes.clone(), + scope_id, + })); + if let Some(block) = expr_scopes.block(scope_id) { + if let Some(def_map) = db.block_def_map(block) { + let root = def_map.root(); + resolver + .scopes + .push(Scope::BlockScope(ModuleItemMap { def_map, module_id: root })); + // FIXME: This adds as many module scopes as there are blocks, but resolving in each + // already traverses all parents, so this is O(n²). I think we could only store the + // innermost module scope instead? + } + } + } + + let start = self.scopes.len(); + let innermost_scope = self.scopes().next(); + match innermost_scope { + Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { + let expr_scopes = expr_scopes.clone(); + let scope_chain = expr_scopes + .scope_chain(expr_scopes.scope_for(expr_id)) + .take_while(|&it| it != scope_id); + for scope_id in scope_chain { + append_expr_scope(db, self, owner, &expr_scopes, scope_id); + } + } + _ => { + let expr_scopes = db.expr_scopes(owner); + let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id)); + + for scope_id in scope_chain { + append_expr_scope(db, self, owner, &expr_scopes, scope_id); + } + } + } + self.scopes[start..].reverse(); + UpdateGuard(start) + } + + pub fn reset_to_guard(&mut self, UpdateGuard(start): UpdateGuard) { + self.scopes.truncate(start); + } } +pub struct UpdateGuard(usize); + impl Resolver { fn scopes(&self) -> impl Iterator<Item = &Scope> { self.scopes.iter().rev() @@ -504,7 +617,7 @@ pub enum ScopeDef { ImplSelfType(ImplId), AdtSelfType(AdtId), GenericParam(GenericParamId), - Local(PatId), + Local(BindingId), Label(LabelId), } @@ -556,17 +669,18 @@ impl Scope { acc.add(&name, ScopeDef::Label(label)) } scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { - acc.add_local(e.name(), e.pat()); + acc.add_local(e.name(), e.binding()); }); } } } } -// needs arbitrary_self_types to be a method... or maybe move to the def? pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver { + let r = owner.resolver(db); let scopes = db.expr_scopes(owner); - resolver_for_scope(db, owner, scopes.scope_for(expr_id)) + let scope_id = scopes.scope_for(expr_id); + resolver_for_scope_(db, scopes, scope_id, r, owner) } pub fn resolver_for_scope( @@ -574,8 +688,18 @@ pub fn resolver_for_scope( owner: DefWithBodyId, scope_id: Option<ScopeId>, ) -> Resolver { - let mut r = owner.resolver(db); + let r = owner.resolver(db); let scopes = db.expr_scopes(owner); + resolver_for_scope_(db, scopes, scope_id, r, owner) +} + +fn resolver_for_scope_( + db: &dyn DefDatabase, + scopes: Arc<ExprScopes>, + scope_id: Option<ScopeId>, + mut r: Resolver, + owner: DefWithBodyId, +) -> Resolver { let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); r.scopes.reserve(scope_chain.len()); @@ -641,6 +765,7 @@ impl ModuleItemMap { let ty = match module_def.take_types()? { ModuleDefId::AdtId(it) => TypeNs::AdtId(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), + ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), @@ -678,6 +803,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> { ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_)) | ModuleDefId::TraitId(_) + | ModuleDefId::TraitAliasId(_) | ModuleDefId::TypeAliasId(_) | ModuleDefId::BuiltinType(_) | ModuleDefId::MacroId(_) @@ -695,6 +821,7 @@ fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> { ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), ModuleDefId::TraitId(it) => TypeNs::TraitId(it), + ModuleDefId::TraitAliasId(it) => TypeNs::TraitAliasId(it), ModuleDefId::FunctionId(_) | ModuleDefId::ConstId(_) @@ -732,7 +859,7 @@ impl ScopeNames { self.add(name, ScopeDef::Unknown) } } - fn add_local(&mut self, name: &Name, pat: PatId) { + fn add_local(&mut self, name: &Name, binding: BindingId) { let set = self.map.entry(name.clone()).or_default(); // XXX: hack, account for local (and only local) shadowing. // @@ -743,7 +870,7 @@ impl ScopeNames { cov_mark::hit!(shadowing_shows_single_completion); return; } - set.push(ScopeDef::Local(pat)) + set.push(ScopeDef::Local(binding)) } } @@ -779,6 +906,12 @@ impl HasResolver for TraitId { } } +impl HasResolver for TraitAliasId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + } +} + impl<T: Into<AdtId> + Copy> HasResolver for T { fn resolver(self, db: &dyn DefDatabase) -> Resolver { let def = self.into(); @@ -858,6 +991,7 @@ impl HasResolver for GenericDefId { GenericDefId::FunctionId(inner) => inner.resolver(db), GenericDefId::AdtId(adt) => adt.resolver(db), GenericDefId::TraitId(inner) => inner.resolver(db), + GenericDefId::TraitAliasId(inner) => inner.resolver(db), GenericDefId::TypeAliasId(inner) => inner.resolver(db), GenericDefId::ImplId(inner) => inner.resolver(db), GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index b7908bdda..ee143b19a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -9,7 +9,7 @@ use base_db::{ salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, SourceDatabase, Upcast, }; -use hir_expand::{db::AstDatabase, InFile}; +use hir_expand::{db::ExpandDatabase, InFile}; use stdx::hash::NoHashHashSet; use syntax::{algo, ast, AstNode}; @@ -23,7 +23,7 @@ use crate::{ #[salsa::database( base_db::SourceDatabaseExtStorage, base_db::SourceDatabaseStorage, - hir_expand::db::AstDatabaseStorage, + hir_expand::db::ExpandDatabaseStorage, crate::db::InternDatabaseStorage, crate::db::DefDatabaseStorage )] @@ -40,8 +40,8 @@ impl Default for TestDB { } } -impl Upcast<dyn AstDatabase> for TestDB { - fn upcast(&self) -> &(dyn AstDatabase + 'static) { +impl Upcast<dyn ExpandDatabase> for TestDB { + fn upcast(&self) -> &(dyn ExpandDatabase + 'static) { &*self } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs index 9652b01b9..8e30f429a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/type_ref.rs @@ -116,7 +116,7 @@ pub enum TypeRef { Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), // FIXME: for full const generics, the latter element (length) here is going to have to be an // expression that is further lowered later in hir_ty. - Array(Box<TypeRef>, ConstScalarOrPath), + Array(Box<TypeRef>, ConstRefOrPath), Slice(Box<TypeRef>), /// A fn pointer. Last element of the vector is the return type. Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/), @@ -188,7 +188,7 @@ impl TypeRef { // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the // `hir_ty` level, which would allow knowing the type of: // let v: [u8; 2 + 2] = [0u8; 4]; - let len = ConstScalarOrPath::from_expr_opt(inner.expr()); + let len = ConstRefOrPath::from_expr_opt(inner.expr()); TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) } ast::Type::SliceType(inner) => { @@ -378,25 +378,25 @@ impl TypeBound { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ConstScalarOrPath { - Scalar(ConstScalar), +pub enum ConstRefOrPath { + Scalar(ConstRef), Path(Name), } -impl std::fmt::Display for ConstScalarOrPath { +impl std::fmt::Display for ConstRefOrPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - ConstScalarOrPath::Scalar(s) => s.fmt(f), - ConstScalarOrPath::Path(n) => n.fmt(f), + ConstRefOrPath::Scalar(s) => s.fmt(f), + ConstRefOrPath::Path(n) => n.fmt(f), } } } -impl ConstScalarOrPath { +impl ConstRefOrPath { pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self { match expr { Some(x) => Self::from_expr(x), - None => Self::Scalar(ConstScalar::Unknown), + None => Self::Scalar(ConstRef::Unknown), } } @@ -407,7 +407,7 @@ impl ConstScalarOrPath { ast::Expr::PathExpr(p) => { match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { Some(x) => Self::Path(x.as_name()), - None => Self::Scalar(ConstScalar::Unknown), + None => Self::Scalar(ConstRef::Unknown), } } ast::Expr::PrefixExpr(prefix_expr) => match prefix_expr.op_kind() { @@ -415,8 +415,8 @@ impl ConstScalarOrPath { let unsigned = Self::from_expr_opt(prefix_expr.expr()); // Add sign match unsigned { - Self::Scalar(ConstScalar::UInt(num)) => { - Self::Scalar(ConstScalar::Int(-(num as i128))) + Self::Scalar(ConstRef::UInt(num)) => { + Self::Scalar(ConstRef::Int(-(num as i128))) } other => other, } @@ -425,22 +425,22 @@ impl ConstScalarOrPath { }, ast::Expr::Literal(literal) => Self::Scalar(match literal.kind() { ast::LiteralKind::IntNumber(num) => { - num.value().map(ConstScalar::UInt).unwrap_or(ConstScalar::Unknown) + num.value().map(ConstRef::UInt).unwrap_or(ConstRef::Unknown) } ast::LiteralKind::Char(c) => { - c.value().map(ConstScalar::Char).unwrap_or(ConstScalar::Unknown) + c.value().map(ConstRef::Char).unwrap_or(ConstRef::Unknown) } - ast::LiteralKind::Bool(f) => ConstScalar::Bool(f), - _ => ConstScalar::Unknown, + ast::LiteralKind::Bool(f) => ConstRef::Bool(f), + _ => ConstRef::Unknown, }), - _ => Self::Scalar(ConstScalar::Unknown), + _ => Self::Scalar(ConstRef::Unknown), } } } /// A concrete constant value -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ConstScalar { +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ConstRef { Int(i128), UInt(u128), Bool(bool), @@ -454,18 +454,18 @@ pub enum ConstScalar { Unknown, } -impl ConstScalar { +impl ConstRef { pub fn builtin_type(&self) -> BuiltinType { match self { - ConstScalar::UInt(_) | ConstScalar::Unknown => BuiltinType::Uint(BuiltinUint::U128), - ConstScalar::Int(_) => BuiltinType::Int(BuiltinInt::I128), - ConstScalar::Char(_) => BuiltinType::Char, - ConstScalar::Bool(_) => BuiltinType::Bool, + ConstRef::UInt(_) | ConstRef::Unknown => BuiltinType::Uint(BuiltinUint::U128), + ConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), + ConstRef::Char(_) => BuiltinType::Char, + ConstRef::Bool(_) => BuiltinType::Bool, } } } -impl From<Literal> for ConstScalar { +impl From<Literal> for ConstRef { fn from(literal: Literal) -> Self { match literal { Literal::Char(c) => Self::Char(c), @@ -477,14 +477,14 @@ impl From<Literal> for ConstScalar { } } -impl std::fmt::Display for ConstScalar { +impl std::fmt::Display for ConstRef { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - ConstScalar::Int(num) => num.fmt(f), - ConstScalar::UInt(num) => num.fmt(f), - ConstScalar::Bool(flag) => flag.fmt(f), - ConstScalar::Char(c) => write!(f, "'{c}'"), - ConstScalar::Unknown => f.write_char('_'), + ConstRef::Int(num) => num.fmt(f), + ConstRef::UInt(num) => num.fmt(f), + ConstRef::Bool(flag) => flag.fmt(f), + ConstRef::Char(c) => write!(f, "'{c}'"), + ConstRef::Unknown => f.write_char('_'), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 087268a9e..ab76ed43d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -11,7 +11,7 @@ use crate::{ nameres::DefMap, path::{ModPath, PathKind}, resolver::HasResolver, - ConstId, FunctionId, HasModule, LocalFieldId, ModuleId, VariantId, + ConstId, FunctionId, HasModule, LocalFieldId, LocalModuleId, ModuleId, VariantId, }; /// Visibility of an item, not yet resolved. @@ -120,7 +120,7 @@ impl Visibility { self, db: &dyn DefDatabase, def_map: &DefMap, - mut from_module: crate::LocalModuleId, + mut from_module: LocalModuleId, ) -> bool { let mut to_module = match self { Visibility::Module(m) => m, @@ -131,20 +131,23 @@ impl Visibility { // visibility as the containing module (even though no items are directly nameable from // there, getting this right is important for method resolution). // In that case, we adjust the visibility of `to_module` to point to the containing module. + // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're // currently computing, so we must not call the `def_map` query for it. - let arc; - let to_module_def_map = - if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { - cov_mark::hit!(is_visible_from_same_block_def_map); - def_map - } else { - arc = to_module.def_map(db); - &arc - }; - let is_block_root = matches!(to_module.block, Some(_) if to_module_def_map[to_module.local_id].parent.is_none()); - if is_block_root { - to_module = to_module_def_map.containing_module(to_module.local_id).unwrap(); + let mut arc; + loop { + let to_module_def_map = + if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() { + cov_mark::hit!(is_visible_from_same_block_def_map); + def_map + } else { + arc = to_module.def_map(db); + &arc + }; + match to_module_def_map.parent() { + Some(parent) => to_module = parent, + None => break, + } } // from_module needs to be a descendant of to_module |