⬆️ rust-analyzer

This commit is contained in:
Laurențiu Nicola 2023-03-13 10:42:24 +02:00
parent 15b867b5db
commit b2f6fd4f96
217 changed files with 12639 additions and 3059 deletions

View file

@ -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)

View file

@ -24,7 +24,7 @@ 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},
item_scope::BuiltinShadowMode,
macro_id_to_def_id,
nameres::DefMap,
@ -270,7 +270,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 +409,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 +423,14 @@ 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();
}
}
@ -451,7 +440,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 +473,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 {

View file

@ -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) => {
@ -737,6 +750,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 +795,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 +818,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 +828,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 +849,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 +862,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 +899,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 +917,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 +936,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 +967,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 +984,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 +998,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 +1045,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 {

View file

@ -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 ");
@ -402,10 +390,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,27 +412,49 @@ 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);
}
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();
});
}
w!(self, "}}");
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);
}
if let Some(tail) = tail {
p.print_expr(*tail);
}
p.newline();
});
}
w!(self, "}}");
}
fn print_pat(&mut self, pat: PatId) {
let pat = &self.body[pat];
@ -518,14 +524,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 +629,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);
}
}

View file

@ -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()),

View file

@ -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
"#]],
)
}

View file

@ -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)),

View file

@ -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)]
@ -245,19 +245,11 @@ 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 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,
@ -299,6 +291,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>>,

View file

@ -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;
@ -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>;

View file

@ -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,
@ -282,13 +301,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 +323,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);
@ -414,6 +436,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,
@ -432,7 +461,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 },

View file

@ -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 {

View file

@ -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,

View file

@ -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),

View file

@ -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,11 +676,18 @@ 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>,
@ -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(),

View file

@ -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> {

View file

@ -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());
}
});
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);
}
}
});
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];

View file

@ -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();

View file

@ -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 {

View file

@ -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)]
@ -261,6 +261,11 @@ pub struct TraitId(salsa::InternId);
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>;
@ -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,

View file

@ -143,7 +143,7 @@ macro_rules! assert {
fn main() {
{
if !true {
if !(true ) {
$crate::panic!("{} {:?}", arg1(a, b, c), arg2);
}
};

View file

@ -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 */

View file

@ -342,7 +342,7 @@ impl DefMap {
}
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 +354,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 }
}
@ -428,9 +428,9 @@ impl DefMap {
/// Returns the module containing `local_mod`, either the parent `mod`, or the module 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 +440,11 @@ impl DefMap {
let mut buf = String::new();
let mut arc;
let mut current_map = self;
while let Some(block) = &current_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 +468,10 @@ impl DefMap {
let mut buf = String::new();
let mut arc;
let mut current_map = self;
while let Some(block) = &current_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");

View file

@ -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);
@ -666,8 +667,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 +834,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 +1550,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 +1710,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 +1840,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 {

View file

@ -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);

View file

@ -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(_)

View file

@ -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 {

View file

@ -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))
}
}

View file

@ -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 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.pat())));
if let Some(e) = entry {
return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(
e.binding(),
)));
}
}
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_)));
}
}
// 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);
}
}
}
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));
}
} 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::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::Partial(TypeNs::SelfType(impl_), 1));
}
}
}
&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_))
});
Scope::AdtScope(adt) => {
if first_name == &name![Self] {
let ty = TypeNs::AdtSelfType(*adt);
return Some(ResolveValueResult::Partial(ty, 1));
}
}
}
// 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));
}
}
Scope::BlockScope(m) => {
if let Some(def) = m.resolve_path_in_value_ns(db, path) {
return Some(def);
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),

View file

@ -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('_'),
}
}
}

View file

@ -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,
@ -142,7 +142,8 @@ impl Visibility {
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());
let is_block_root =
to_module.block.is_some() && 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();
}