mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 22:54:58 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
15b867b5db
commit
b2f6fd4f96
217 changed files with 12639 additions and 3059 deletions
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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>>,
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -143,7 +143,7 @@ macro_rules! assert {
|
|||
|
||||
fn main() {
|
||||
{
|
||||
if !true {
|
||||
if !(true ) {
|
||||
$crate::panic!("{} {:?}", arg1(a, b, c), arg2);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) = ¤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 +468,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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(_)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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('_'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue