rust-analyzer/crates/ra_hir_def/src/body/lower.rs

1074 lines
45 KiB
Rust
Raw Normal View History

2019-11-24 17:39:48 +00:00
//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
//! representation.
2019-11-12 12:09:25 +00:00
use either::Either;
2020-03-14 06:25:30 +00:00
use hir_expand::{
2020-04-30 10:20:13 +00:00
hygiene::Hygiene,
2020-03-14 06:25:30 +00:00
name::{name, AsName, Name},
2020-06-26 15:30:27 +00:00
HirFileId, MacroDefId, MacroDefKind,
2020-03-14 06:25:30 +00:00
};
use ra_arena::{map::ArenaMap, Arena};
2019-11-12 15:46:57 +00:00
use ra_syntax::{
ast::{
2019-12-20 10:19:09 +00:00
self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
SlicePatComponents, TypeAscriptionOwner,
2019-11-12 15:46:57 +00:00
},
AstNode, AstPtr,
};
2020-05-20 10:59:20 +00:00
use test_utils::mark;
2019-11-12 12:09:25 +00:00
2019-11-12 15:46:57 +00:00
use crate::{
adt::StructKind,
2020-03-06 14:11:05 +00:00
body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
2019-11-12 15:46:57 +00:00
builtin_type::{BuiltinFloat, BuiltinInt},
2019-11-23 11:44:43 +00:00
db::DefDatabase,
2019-11-12 15:46:57 +00:00
expr::{
2020-03-19 15:00:11 +00:00
dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal,
LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
2019-11-12 15:46:57 +00:00
},
item_scope::BuiltinShadowMode,
2020-06-26 15:30:27 +00:00
item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
2020-04-30 10:20:13 +00:00
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
2020-04-11 15:09:50 +00:00
AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
2019-11-12 15:46:57 +00:00
};
2020-04-11 15:00:31 +00:00
use super::{ExprSource, PatSource};
2020-04-12 15:40:09 +00:00
use ast::AstChildren;
use rustc_hash::FxHashMap;
2020-06-26 15:30:27 +00:00
use std::{any::type_name, sync::Arc};
2020-04-11 15:00:31 +00:00
2020-04-30 10:20:13 +00:00
pub(crate) struct LowerCtx {
hygiene: Hygiene,
}
impl LowerCtx {
2020-06-11 17:46:56 +00:00
pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) }
2020-04-30 10:20:13 +00:00
}
pub fn with_hygiene(hygiene: &Hygiene) -> Self {
LowerCtx { hygiene: hygiene.clone() }
}
pub fn lower_path(&self, ast: ast::Path) -> Option<Path> {
Path::from_src(ast, &self.hygiene)
}
}
2019-11-12 15:46:57 +00:00
pub(super) fn lower(
db: &dyn DefDatabase,
2019-12-20 10:19:09 +00:00
def: DefWithBodyId,
2019-11-14 06:38:25 +00:00
expander: Expander,
2019-11-12 15:46:57 +00:00
params: Option<ast::ParamList>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
2020-06-24 14:21:00 +00:00
let item_tree = db.item_tree(expander.current_file_id);
2019-11-12 15:46:57 +00:00
ExprCollector {
db,
2019-12-20 10:19:09 +00:00
def,
2019-11-12 15:46:57 +00:00
source_map: BodySourceMap::default(),
body: Body {
exprs: Arena::default(),
pats: Arena::default(),
params: Vec::new(),
2020-03-19 15:00:11 +00:00
body_expr: dummy_expr_id(),
item_scope: Default::default(),
parent_map: ArenaMap::default(),
2019-11-12 15:46:57 +00:00
},
item_trees: {
let mut map = FxHashMap::default();
map.insert(expander.current_file_id, item_tree);
map
},
2020-06-24 14:21:00 +00:00
expander,
2019-11-12 15:46:57 +00:00
}
.collect(params, body)
}
struct ExprCollector<'a> {
db: &'a dyn DefDatabase,
2019-12-20 10:19:09 +00:00
def: DefWithBodyId,
2019-11-14 06:38:25 +00:00
expander: Expander,
2019-11-12 15:46:57 +00:00
body: Body,
source_map: BodySourceMap,
2020-06-22 13:07:06 +00:00
item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
2019-11-12 15:46:57 +00:00
}
macro_rules! track_parent {
(@build $collector:ident, $parent:expr $(,)?) => {
$parent
};
(@build $collector:ident, $parent:expr, opt $expr:ident $($rest:tt)*) => {
{
if let Some(expr) = $expr {
$collector.body.parent_map.insert(expr, $parent);
}
track_parent!(@build $collector, $parent $($rest)*)
}
};
(@build $collector:ident, $parent:expr, vec $expr:ident $($rest:tt)*) => {
{
for expr in $expr {
$collector.body.parent_map.insert(expr, $parent);
}
track_parent!(@build $collector, $parent $($rest)*)
}
};
(@build $collector:ident, $parent:expr, $expr:ident $($rest:tt)*) => {
{
$collector.body.parent_map.insert($expr, $parent);
track_parent!(@build $collector, $parent $($rest)*)
}
};
($collector:ident, $parent:expr, $($rest:tt)*) => {
{
let parent = $parent;
track_parent!(@build $collector, parent, $($rest)*)
}
}
}
impl ExprCollector<'_> {
2019-11-12 15:46:57 +00:00
fn collect(
mut self,
param_list: Option<ast::ParamList>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
if let Some(param_list) = param_list {
if let Some(self_param) = param_list.self_param() {
let ptr = AstPtr::new(&self_param);
let param_pat = self.alloc_pat(
Pat::Bind {
2019-12-13 21:01:06 +00:00
name: name![self],
2019-11-12 15:46:57 +00:00
mode: BindingAnnotation::Unannotated,
subpat: None,
},
Either::Right(ptr),
2019-11-12 15:46:57 +00:00
);
self.body.params.push(param_pat);
}
for param in param_list.params() {
let pat = match param.pat() {
None => continue,
Some(pat) => pat,
};
let param_pat = self.collect_pat(pat);
self.body.params.push(param_pat);
}
};
self.body.body_expr = self.collect_expr_opt(body);
(self.body, self.source_map)
}
2020-05-17 15:37:30 +00:00
fn ctx(&self) -> LowerCtx {
2020-06-11 17:46:56 +00:00
LowerCtx::new(self.db, self.expander.current_file_id)
2020-05-17 15:37:30 +00:00
}
2019-11-12 15:46:57 +00:00
fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
let src = self.expander.to_source(ptr);
2020-04-10 22:27:00 +00:00
let id = self.make_expr(expr, Ok(src.clone()));
self.source_map.expr_map.insert(src, id);
2019-11-12 15:46:57 +00:00
id
}
// desugared exprs don't have ptr, that's wrong and should be fixed
// somehow.
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
2020-03-06 14:11:05 +00:00
self.make_expr(expr, Err(SyntheticSyntax))
2019-11-12 15:46:57 +00:00
}
2020-03-06 14:11:05 +00:00
fn empty_block(&mut self) -> ExprId {
2020-05-31 08:59:40 +00:00
self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None })
2020-03-06 14:11:05 +00:00
}
fn missing_expr(&mut self) -> ExprId {
self.alloc_expr_desugared(Expr::Missing)
}
fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
let id = self.body.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
2019-11-12 15:46:57 +00:00
id
}
2020-03-06 14:11:05 +00:00
2019-11-12 15:46:57 +00:00
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.to_source(ptr);
2020-04-10 22:27:00 +00:00
let id = self.make_pat(pat, Ok(src.clone()));
self.source_map.pat_map.insert(src, id);
2019-11-12 15:46:57 +00:00
id
}
fn missing_pat(&mut self) -> PatId {
2020-03-06 14:17:48 +00:00
self.make_pat(Pat::Missing, Err(SyntheticSyntax))
}
fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
let id = self.body.pats.alloc(pat);
self.source_map.pat_map_back.insert(id, src);
id
2019-11-12 15:46:57 +00:00
}
fn update_parent_map(
&mut self,
(parent_expr, children_exprs): (ExprId, Vec<ExprId>),
) -> ExprId {
for child_expr in children_exprs {
self.body.parent_map.insert(child_expr, parent_expr);
}
parent_expr
}
2019-11-12 15:46:57 +00:00
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
let expr_id = self.collect_expr_inner(expr);
debug_assert!({
let mut found_count = 0;
let mut incr = || {
found_count += 1;
true
};
let mut all_children_found = true;
self.body[expr_id].walk_child_exprs(|child| {
all_children_found = all_children_found
&& self
.body
.parent_map
.get(child)
.map(|parent| *parent == expr_id)
.unwrap_or(false)
&& incr()
});
if all_children_found {
let child_count_in_map =
self.body.parent_map.iter().filter(|&(_, parent)| *parent == expr_id).count();
found_count == child_count_in_map
} else {
false
}
});
expr_id
}
fn collect_expr_inner(&mut self, expr: ast::Expr) -> ExprId {
2019-11-12 15:46:57 +00:00
let syntax_ptr = AstPtr::new(&expr);
if !self.expander.is_cfg_enabled(&expr) {
return self.missing_expr();
}
2019-11-12 15:46:57 +00:00
match expr {
ast::Expr::IfExpr(e) => {
let then_branch = self.collect_block_opt(e.then_branch());
let else_branch = e.else_branch().map(|b| match b {
ast::ElseBranch::Block(it) => self.collect_block(it),
ast::ElseBranch::IfExpr(elif) => {
let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
self.collect_expr(expr)
}
});
let condition = match e.condition() {
None => self.missing_expr(),
Some(condition) => match condition.pat() {
None => self.collect_expr_opt(condition.expr()),
// if let -- desugar to match
Some(pat) => {
let pat = self.collect_pat(pat);
let match_expr = self.collect_expr_opt(condition.expr());
let placeholder_pat = self.missing_pat();
let arms = vec![
2020-02-09 18:57:01 +00:00
MatchArm { pat, expr: then_branch, guard: None },
2019-11-12 15:46:57 +00:00
MatchArm {
2020-02-09 18:57:01 +00:00
pat: placeholder_pat,
2019-11-12 15:46:57 +00:00
expr: else_branch.unwrap_or_else(|| self.empty_block()),
guard: None,
},
];
let arm_exprs = arms.iter().map(|arm| arm.expr).collect::<Vec<_>>();
return track_parent!(
self,
self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
match_expr, vec arm_exprs
);
2019-11-12 15:46:57 +00:00
}
},
};
track_parent!(
self,
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr),
then_branch, opt else_branch, condition
)
2019-11-12 15:46:57 +00:00
}
2020-05-01 23:18:19 +00:00
ast::Expr::EffectExpr(e) => match e.effect() {
ast::Effect::Try(_) => {
let body = self.collect_block_opt(e.block_expr());
track_parent!(self, self.alloc_expr(Expr::TryBlock { body }, syntax_ptr), body)
2020-05-01 23:18:19 +00:00
}
ast::Effect::Unsafe(_) => {
let body = self.collect_block_opt(e.block_expr());
track_parent!(self, self.alloc_expr(Expr::Unsafe { body }, syntax_ptr), body)
}
2020-05-01 23:18:19 +00:00
// FIXME: we need to record these effects somewhere...
ast::Effect::Async(_) | ast::Effect::Label(_) => {
self.collect_block_opt(e.block_expr())
2020-05-01 23:18:19 +00:00
}
},
ast::Expr::BlockExpr(e) => self.collect_block(e),
2019-11-12 15:46:57 +00:00
ast::Expr::LoopExpr(e) => {
let body = self.collect_block_opt(e.loop_body());
track_parent!(self, self.alloc_expr(Expr::Loop { body }, syntax_ptr), vec![body])
2020-05-31 08:59:40 +00:00
Expr::Loop {
body,
2020-05-31 10:06:22 +00:00
label: e
.label()
.and_then(|l| l.lifetime_token())
.map(|l| Name::new_lifetime(&l)),
2020-05-31 08:59:40 +00:00
},
syntax_ptr,
), body)
2019-11-12 15:46:57 +00:00
}
ast::Expr::WhileExpr(e) => {
let body = self.collect_block_opt(e.loop_body());
let condition = match e.condition() {
None => self.missing_expr(),
Some(condition) => match condition.pat() {
None => self.collect_expr_opt(condition.expr()),
// if let -- desugar to match
Some(pat) => {
2020-05-20 10:59:20 +00:00
mark::hit!(infer_resolve_while_let);
2019-11-12 15:46:57 +00:00
let pat = self.collect_pat(pat);
let match_expr = self.collect_expr_opt(condition.expr());
let placeholder_pat = self.missing_pat();
2020-05-31 08:59:40 +00:00
let break_ =
self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
2019-11-12 15:46:57 +00:00
let arms = vec![
2020-02-09 18:57:01 +00:00
MatchArm { pat, expr: body, guard: None },
MatchArm { pat: placeholder_pat, expr: break_, guard: None },
2019-11-12 15:46:57 +00:00
];
let match_expr =
self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
return track_parent!(self, self.alloc_expr(
2020-05-31 08:59:40 +00:00
Expr::Loop {
body: match_expr,
2020-05-31 10:06:22 +00:00
label: e
.label()
.and_then(|l| l.lifetime_token())
.map(|l| Name::new_lifetime(&l)),
2020-05-31 08:59:40 +00:00
},
syntax_ptr,
), match_expr);
2019-11-12 15:46:57 +00:00
}
},
};
track_parent!(self, self.alloc_expr(
2020-05-31 08:59:40 +00:00
Expr::While {
condition,
body,
2020-05-31 10:06:22 +00:00
label: e
.label()
.and_then(|l| l.lifetime_token())
.map(|l| Name::new_lifetime(&l)),
2020-05-31 08:59:40 +00:00
},
syntax_ptr,
), body, condition)
2019-11-12 15:46:57 +00:00
}
ast::Expr::ForExpr(e) => {
let iterable = self.collect_expr_opt(e.iterable());
let pat = self.collect_pat_opt(e.pat());
let body = self.collect_block_opt(e.loop_body());
track_parent!(self, self.alloc_expr(
2020-05-31 08:59:40 +00:00
Expr::For {
iterable,
pat,
body,
2020-05-31 10:06:22 +00:00
label: e
.label()
.and_then(|l| l.lifetime_token())
.map(|l| Name::new_lifetime(&l)),
2020-05-31 08:59:40 +00:00
},
syntax_ptr,
), iterable, body)
2019-11-12 15:46:57 +00:00
}
ast::Expr::CallExpr(e) => {
let callee = self.collect_expr_opt(e.expr());
let args = if let Some(arg_list) = e.arg_list() {
arg_list.args().map(|e| self.collect_expr(e)).collect()
} else {
Vec::new()
};
track_parent!(self, self.alloc_expr(Expr::Call { callee, args: args.clone() }, syntax_ptr), callee, vec args)
2019-11-12 15:46:57 +00:00
}
ast::Expr::MethodCallExpr(e) => {
let receiver = self.collect_expr_opt(e.expr());
let args = if let Some(arg_list) = e.arg_list() {
arg_list.args().map(|e| self.collect_expr(e)).collect()
} else {
vec![]
2019-11-12 15:46:57 +00:00
};
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
2020-04-30 10:20:13 +00:00
let generic_args =
2020-05-17 15:37:30 +00:00
e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
track_parent!(
self,
self.alloc_expr(
Expr::MethodCall {
receiver,
method_name,
args: args.clone(),
generic_args
},
syntax_ptr,
),
receiver,
vec args
2019-11-12 15:46:57 +00:00
)
}
ast::Expr::MatchExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
let (arms, children_exprs): (Vec<_>, Vec<_>) =
if let Some(match_arm_list) = e.match_arm_list() {
match_arm_list
.arms()
.map(|arm| {
let expr = self.collect_expr_opt(arm.expr());
(
MatchArm {
pat: self.collect_pat_opt(arm.pat()),
expr,
guard: arm
.guard()
.and_then(|guard| guard.expr())
.map(|e| self.collect_expr(e)),
},
expr,
)
})
.unzip()
} else {
(vec![], vec![])
};
track_parent!(self, self.alloc_expr(Expr::Match { expr, arms: arms.clone() }, syntax_ptr), expr, vec children_exprs)
2019-11-12 15:46:57 +00:00
}
ast::Expr::PathExpr(e) => {
let path = e
.path()
2019-11-14 06:58:39 +00:00
.and_then(|path| self.expander.parse_path(path))
2019-11-12 15:46:57 +00:00
.map(Expr::Path)
.unwrap_or(Expr::Missing);
self.alloc_expr(path, syntax_ptr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::ContinueExpr(e) => (self.alloc_expr(
2020-05-31 10:06:22 +00:00
Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
syntax_ptr,
), vec![]),
2019-11-12 15:46:57 +00:00
ast::Expr::BreakExpr(e) => {
let expr = e.expr().map(|e| self.collect_expr(e));
track_parent!(self, self.alloc_expr(
2020-05-31 08:59:40 +00:00
Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
syntax_ptr,
), opt expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::ParenExpr(e) => {
let inner = self.collect_expr_opt(e.expr());
// make the paren expr point to the inner expression as well
2020-04-11 17:25:33 +00:00
let src = self.expander.to_source(syntax_ptr);
self.source_map.expr_map.insert(src, inner);
inner
2019-11-12 15:46:57 +00:00
}
ast::Expr::ReturnExpr(e) => {
let expr = e.expr().map(|e| self.collect_expr(e));
track_parent!(self, self.alloc_expr(Expr::Return { expr }, syntax_ptr), opt expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::RecordLit(e) => {
2019-11-14 06:58:39 +00:00
let path = e.path().and_then(|path| self.expander.parse_path(path));
2019-11-12 15:46:57 +00:00
let mut field_ptrs = Vec::new();
let (record_lit, children) = if let Some(nfl) = e.record_field_list() {
let (fields, children): (Vec<_>, Vec<_>) = nfl
2019-11-12 15:46:57 +00:00
.fields()
.inspect(|field| field_ptrs.push(AstPtr::new(field)))
.filter_map(|field| {
if !self.expander.is_cfg_enabled(&field) {
return None;
}
let name = field.field_name()?.as_name();
let expr = match field.expr() {
Some(e) => self.collect_expr(e),
None => self.missing_expr(),
};
Some((RecordLitField { name, expr }, expr))
2019-11-12 15:46:57 +00:00
})
.unzip();
2019-11-12 15:46:57 +00:00
let spread = nfl.spread().map(|s| self.collect_expr(s));
(
Expr::RecordLit { path, fields, spread: spread },
children.into_iter().chain(spread.into_iter()).collect(),
)
2019-11-12 15:46:57 +00:00
} else {
(Expr::RecordLit { path, fields: Vec::new(), spread: None }, vec![])
2019-11-12 15:46:57 +00:00
};
let res = self.alloc_expr(record_lit, syntax_ptr);
for (i, ptr) in field_ptrs.into_iter().enumerate() {
2020-04-17 09:38:51 +00:00
let src = self.expander.to_source(ptr);
self.source_map.field_map.insert((res, i), src);
2019-11-12 15:46:57 +00:00
}
track_parent!(self, res, vec children)
2019-11-12 15:46:57 +00:00
}
ast::Expr::FieldExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
let name = match e.field_access() {
Some(kind) => kind.as_name(),
_ => Name::missing(),
};
track_parent!(self, self.alloc_expr(Expr::Field { expr, name }, syntax_ptr), expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::AwaitExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
track_parent!(self, self.alloc_expr(Expr::Await { expr }, syntax_ptr), expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::TryExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
track_parent!(self, self.alloc_expr(Expr::Try { expr }, syntax_ptr), expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::CastExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
2020-05-17 15:37:30 +00:00
let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref());
track_parent!(
self,
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr),
expr
)
2019-11-12 15:46:57 +00:00
}
ast::Expr::RefExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
let raw_tok = e.raw_token().is_some();
let mutability = if raw_tok {
if e.mut_token().is_some() {
Mutability::Mut
} else if e.const_token().is_some() {
Mutability::Shared
} else {
unreachable!("parser only remaps to raw_token() if matching mutability token follows")
}
} else {
Mutability::from_mutable(e.mut_token().is_some())
};
let rawness = Rawness::from_raw(raw_tok);
track_parent!(
self,
self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr),
expr
)
2019-11-12 15:46:57 +00:00
}
ast::Expr::PrefixExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
if let Some(op) = e.op_kind() {
track_parent!(
self,
self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
expr
)
2019-11-12 15:46:57 +00:00
} else {
self.alloc_expr(Expr::Missing, syntax_ptr)
2019-11-12 15:46:57 +00:00
}
}
ast::Expr::LambdaExpr(e) => {
let mut args = Vec::new();
let mut arg_types = Vec::new();
if let Some(pl) = e.param_list() {
for param in pl.params() {
let pat = self.collect_pat_opt(param.pat());
2020-04-30 10:20:13 +00:00
let type_ref =
2020-05-17 15:37:30 +00:00
param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
2019-11-12 15:46:57 +00:00
args.push(pat);
arg_types.push(type_ref);
}
}
2020-04-30 10:20:13 +00:00
let ret_type = e
.ret_type()
.and_then(|r| r.type_ref())
2020-05-17 15:37:30 +00:00
.map(|it| TypeRef::from_ast(&self.ctx(), it));
2019-11-12 15:46:57 +00:00
let body = self.collect_expr_opt(e.body());
track_parent!(
self,
self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr),
body,
)
2019-11-12 15:46:57 +00:00
}
ast::Expr::BinExpr(e) => {
let lhs = self.collect_expr_opt(e.lhs());
let rhs = self.collect_expr_opt(e.rhs());
let op = e.op_kind().map(BinaryOp::from);
track_parent!(
self,
self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr),
lhs,
rhs
)
2019-11-12 15:46:57 +00:00
}
ast::Expr::TupleExpr(e) => {
let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
track_parent!(self, self.alloc_expr(Expr::Tuple { exprs: exprs.clone() }, syntax_ptr), vec exprs)
2019-11-12 15:46:57 +00:00
}
ast::Expr::BoxExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
track_parent!(self, self.alloc_expr(Expr::Box { expr }, syntax_ptr), expr)
2019-11-12 15:46:57 +00:00
}
ast::Expr::ArrayExpr(e) => {
let kind = e.kind();
match kind {
ArrayExprKind::ElementList(e) => {
let exprs = e.map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
track_parent!(self,
self.alloc_expr(
Expr::Array(Array::ElementList(exprs.clone())),
syntax_ptr,
),
vec exprs,
)
2019-11-12 15:46:57 +00:00
}
ArrayExprKind::Repeat { initializer, repeat } => {
let initializer = self.collect_expr_opt(initializer);
let repeat = self.collect_expr_opt(repeat);
track_parent!(
self,
self.alloc_expr(
Expr::Array(Array::Repeat { initializer, repeat }),
syntax_ptr,
),
initializer,
repeat,
2019-11-12 15:46:57 +00:00
)
}
}
}
ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
2019-11-12 15:46:57 +00:00
ast::Expr::IndexExpr(e) => {
let base = self.collect_expr_opt(e.base());
let index = self.collect_expr_opt(e.index());
track_parent!(
self,
self.alloc_expr(Expr::Index { base, index }, syntax_ptr),
base,
index
)
2019-11-12 15:46:57 +00:00
}
2019-11-28 19:10:16 +00:00
ast::Expr::RangeExpr(e) => {
let lhs = e.start().map(|lhs| self.collect_expr(lhs));
let rhs = e.end().map(|rhs| self.collect_expr(rhs));
2019-11-29 06:49:12 +00:00
match e.op_kind() {
Some(range_type) => track_parent!(
self,
self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr),
opt lhs, opt rhs
),
None => self.alloc_expr(Expr::Missing, syntax_ptr),
2019-11-28 19:10:16 +00:00
}
}
2019-12-23 13:47:11 +00:00
ast::Expr::MacroCall(e) => {
2020-03-22 07:00:44 +00:00
if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
2020-03-14 06:25:30 +00:00
let mac = MacroDefId {
krate: Some(self.expander.module.krate),
ast_id: Some(self.expander.ast_id(&e)),
kind: MacroDefKind::Declarative,
2020-05-01 03:23:03 +00:00
local_inner: false,
2020-03-14 06:25:30 +00:00
};
self.body.item_scope.define_legacy_macro(name, mac);
// FIXME: do we still need to allocate this as missing ?
self.alloc_expr(Expr::Missing, syntax_ptr)
2020-03-14 06:25:30 +00:00
} else {
let macro_call = self.expander.to_source(AstPtr::new(&e));
match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) {
Some((mark, expansion)) => {
self.source_map
.expansions
.insert(macro_call, self.expander.current_file_id);
2020-06-22 13:07:06 +00:00
let item_tree = self.db.item_tree(self.expander.current_file_id);
self.item_trees.insert(self.expander.current_file_id, item_tree);
2020-03-14 06:25:30 +00:00
let id = self.collect_expr(expansion);
self.expander.exit(self.db, mark);
id
2020-03-14 06:25:30 +00:00
}
None => self.alloc_expr(Expr::Missing, syntax_ptr),
2019-12-23 13:47:11 +00:00
}
2019-11-12 15:46:57 +00:00
}
2019-12-23 13:47:11 +00:00
}
// FIXME implement HIR for these:
ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
2019-11-12 15:46:57 +00:00
}
}
fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
2020-06-26 15:30:27 +00:00
let id = self.expander.ast_id(ast);
let tree = &self.item_trees[&id.file_id];
2020-06-22 13:07:06 +00:00
// FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
2020-06-22 13:07:06 +00:00
// Root file (non-macro).
2020-06-26 15:30:27 +00:00
let item_tree_id = tree
.all_inner_items()
2020-06-22 13:07:06 +00:00
.chain(tree.top_level_items().iter().copied())
2020-06-26 15:30:27 +00:00
.filter_map(|mod_item| mod_item.downcast::<N>())
.find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
.or_else(|| {
log::debug!(
"couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
type_name::<N>(),
id,
ast.syntax(),
ast.syntax(),
);
None
})?;
2020-06-26 15:30:27 +00:00
Some(ItemTreeId::new(id.file_id, item_tree_id))
2020-06-22 13:07:06 +00:00
}
2019-11-12 15:46:57 +00:00
fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
if let Some(expr) = expr {
self.collect_expr(expr)
} else {
self.missing_expr()
}
}
2020-05-01 23:18:19 +00:00
fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
let parent_and_children = self.collect_block_inner(block);
self.update_parent_map(parent_and_children)
}
fn collect_block_inner(&mut self, block: ast::BlockExpr) -> (ExprId, Vec<ExprId>) {
2020-05-01 23:18:19 +00:00
let syntax_node_ptr = AstPtr::new(&block.clone().into());
2019-12-20 10:19:09 +00:00
self.collect_block_items(&block);
let (statements, children_exprs): (Vec<_>, Vec<_>) = block
2019-11-12 15:46:57 +00:00
.statements()
2020-04-19 19:15:49 +00:00
.map(|s| match s {
2019-11-12 15:46:57 +00:00
ast::Stmt::LetStmt(stmt) => {
let pat = self.collect_pat_opt(stmt.pat());
2020-05-17 15:37:30 +00:00
let type_ref =
stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx(), it));
2019-11-12 15:46:57 +00:00
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
(Statement::Let { pat, type_ref, initializer }, initializer)
}
ast::Stmt::ExprStmt(stmt) => {
let expr = self.collect_expr_opt(stmt.expr());
(Statement::Expr(expr), Some(expr))
}
2019-11-12 15:46:57 +00:00
})
.unzip();
2019-11-12 15:46:57 +00:00
let tail = block.expr().map(|e| self.collect_expr(e));
2020-05-31 08:59:40 +00:00
let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t));
let children_exprs = children_exprs.into_iter().flatten().chain(tail.into_iter()).collect();
(self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr), children_exprs)
2019-11-12 15:46:57 +00:00
}
2020-05-01 23:18:19 +00:00
fn collect_block_items(&mut self, block: &ast::BlockExpr) {
2019-12-20 11:20:49 +00:00
let container = ContainerId::DefWithBodyId(self.def);
2020-06-22 13:07:06 +00:00
let items = block
.items()
.filter_map(|item| {
let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
ast::ModuleItem::FnDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-22 13:07:06 +00:00
(
2020-06-26 15:30:27 +00:00
FunctionLoc { container: container.into(), id }.intern(self.db).into(),
2020-06-22 13:07:06 +00:00
def.name(),
)
}
ast::ModuleItem::TypeAliasDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-22 13:07:06 +00:00
(
2020-06-26 15:30:27 +00:00
TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
2020-06-22 13:07:06 +00:00
def.name(),
)
}
ast::ModuleItem::ConstDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-22 13:07:06 +00:00
(
2020-06-26 15:30:27 +00:00
ConstLoc { container: container.into(), id }.intern(self.db).into(),
2020-06-22 13:07:06 +00:00
def.name(),
)
}
ast::ModuleItem::StaticDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-26 15:30:27 +00:00
(StaticLoc { container, id }.intern(self.db).into(), def.name())
2020-06-22 13:07:06 +00:00
}
ast::ModuleItem::StructDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-26 15:30:27 +00:00
(StructLoc { container, id }.intern(self.db).into(), def.name())
2020-06-22 13:07:06 +00:00
}
ast::ModuleItem::EnumDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-26 15:30:27 +00:00
(EnumLoc { container, id }.intern(self.db).into(), def.name())
2020-06-22 13:07:06 +00:00
}
ast::ModuleItem::UnionDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-26 15:30:27 +00:00
(UnionLoc { container, id }.intern(self.db).into(), def.name())
2020-06-22 13:07:06 +00:00
}
ast::ModuleItem::TraitDef(def) => {
let id = self.find_inner_item(&def)?;
2020-06-26 15:30:27 +00:00
(TraitLoc { container, id }.intern(self.db).into(), def.name())
2020-06-22 13:07:06 +00:00
}
ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks
ast::ModuleItem::ImplDef(_)
| ast::ModuleItem::UseItem(_)
| ast::ModuleItem::ExternCrateItem(_)
| ast::ModuleItem::Module(_)
| ast::ModuleItem::MacroCall(_) => return None,
};
Some((def, name))
})
.collect::<Vec<_>>();
for (def, name) in items {
self.body.item_scope.define_def(def);
if let Some(name) = name {
let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
2020-05-04 17:15:27 +00:00
let has_constructor = match def {
ModuleDefId::AdtId(AdtId::StructId(s)) => {
2020-05-04 17:15:27 +00:00
self.db.struct_data(s).variant_data.kind() != StructKind::Record
}
2020-05-04 17:15:27 +00:00
_ => true,
};
self.body.item_scope.push_res(
name.as_name(),
2020-05-04 17:15:27 +00:00
crate::per_ns::PerNs::from_def(def, vis, has_constructor),
);
}
2019-12-20 10:19:09 +00:00
}
}
2019-11-12 15:46:57 +00:00
fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
if let Some(block) = expr {
self.collect_block(block)
} else {
self.missing_expr()
}
}
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
let pattern = match &pat {
ast::Pat::BindPat(bp) => {
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
2020-04-09 21:35:05 +00:00
let annotation =
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
2019-11-12 15:46:57 +00:00
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
// This could also be a single-segment path pattern. To
// decide that, we need to try resolving the name.
let (resolved, _) = self.expander.crate_def_map.resolve_path(
self.db,
self.expander.module.local_id,
&name.clone().into(),
BuiltinShadowMode::Other,
);
match resolved.take_values() {
Some(ModuleDefId::ConstId(_)) => 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())
}
Some(ModuleDefId::AdtId(AdtId::StructId(s)))
if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
{
// Funnily enough, record structs *can* be shadowed
// by pattern bindings (but unit or tuple structs
// can't).
Pat::Path(name.into())
}
// shadowing statics is an error as well, so we just ignore that case here
_ => Pat::Bind { name, mode: annotation, subpat },
}
} else {
Pat::Bind { name, mode: annotation, subpat }
}
2019-11-12 15:46:57 +00:00
}
ast::Pat::TupleStructPat(p) => {
2019-11-14 06:58:39 +00:00
let path = p.path().and_then(|path| self.expander.parse_path(path));
2020-04-12 15:40:09 +00:00
let (args, ellipsis) = self.collect_tuple_pat(p.args());
Pat::TupleStruct { path, args, ellipsis }
2019-11-12 15:46:57 +00:00
}
ast::Pat::RefPat(p) => {
let pat = self.collect_pat_opt(p.pat());
2020-04-09 21:35:05 +00:00
let mutability = Mutability::from_mutable(p.mut_token().is_some());
2019-11-12 15:46:57 +00:00
Pat::Ref { pat, mutability }
}
ast::Pat::PathPat(p) => {
2019-11-14 06:58:39 +00:00
let path = p.path().and_then(|path| self.expander.parse_path(path));
2019-11-12 15:46:57 +00:00
path.map(Pat::Path).unwrap_or(Pat::Missing)
}
2020-02-09 18:57:01 +00:00
ast::Pat::OrPat(p) => {
let pats = p.pats().map(|p| self.collect_pat(p)).collect();
Pat::Or(pats)
}
ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
2019-11-12 15:46:57 +00:00
ast::Pat::TuplePat(p) => {
2020-04-12 15:40:09 +00:00
let (args, ellipsis) = self.collect_tuple_pat(p.args());
Pat::Tuple { args, ellipsis }
2019-11-12 15:46:57 +00:00
}
2020-04-12 15:40:09 +00:00
ast::Pat::PlaceholderPat(_) => Pat::Wild,
2019-11-12 15:46:57 +00:00
ast::Pat::RecordPat(p) => {
2019-11-14 06:58:39 +00:00
let path = p.path().and_then(|path| self.expander.parse_path(path));
2019-11-12 15:46:57 +00:00
let record_field_pat_list =
p.record_field_pat_list().expect("every struct should have a field list");
let mut fields: Vec<_> = record_field_pat_list
.bind_pats()
.filter_map(|bind_pat| {
let ast_pat =
ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
let pat = self.collect_pat(ast_pat);
let name = bind_pat.name()?.as_name();
Some(RecordFieldPat { name, pat })
})
.collect();
let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
let ast_pat = f.pat()?;
let pat = self.collect_pat(ast_pat);
let name = f.field_name()?.as_name();
2019-11-12 15:46:57 +00:00
Some(RecordFieldPat { name, pat })
});
fields.extend(iter);
let ellipsis = record_field_pat_list.dotdot_token().is_some();
Pat::Record { path, args: fields, ellipsis }
2019-11-12 15:46:57 +00:00
}
ast::Pat::SlicePat(p) => {
let SlicePatComponents { prefix, slice, suffix } = p.components();
2020-04-17 12:36:44 +00:00
// FIXME properly handle `DotDotPat`
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(),
}
}
2020-04-01 10:37:51 +00:00
ast::Pat::LiteralPat(lit) => {
if let Some(ast_lit) = lit.literal() {
let expr = Expr::Literal(ast_lit.kind().into());
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
let expr_id = self.alloc_expr(expr, expr_ptr);
Pat::Lit(expr_id)
} else {
Pat::Missing
}
}
2020-04-17 12:36:44 +00:00
ast::Pat::DotDotPat(_) => {
// `DotDotPat` requires special handling and should not be mapped
// to a Pat. Here we are using `Pat::Missing` as a fallback for
// when `DotDotPat` is mapped to `Pat`, which can easily happen
// when the source code being analyzed has a malformed pattern
// which includes `..` in a place where it isn't valid.
Pat::Missing
}
2019-11-12 15:46:57 +00:00
// FIXME: implement
ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
2019-11-12 15:46:57 +00:00
};
let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, Either::Left(ptr))
2019-11-12 15:46:57 +00:00
}
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
if let Some(pat) = pat {
self.collect_pat(pat)
} else {
self.missing_pat()
}
}
2020-04-12 15:40:09 +00:00
fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
// Find the location of the `..`, if there is one. Note that we do not
// consider the possiblity of there being multiple `..` here.
let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_)));
// We want to skip the `..` pattern here, since we account for it above.
let args = args
.filter(|p| !matches!(p, ast::Pat::DotDotPat(_)))
.map(|p| self.collect_pat(p))
.collect();
(args, ellipsis)
}
2019-11-12 15:46:57 +00:00
}
2019-11-12 12:09:25 +00:00
impl From<ast::BinOp> for BinaryOp {
fn from(ast_op: ast::BinOp) -> Self {
match ast_op {
ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
ast::BinOp::LesserEqualTest => {
BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
}
ast::BinOp::GreaterEqualTest => {
BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
}
ast::BinOp::LesserTest => {
BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
}
ast::BinOp::GreaterTest => {
BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
}
ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
}
}
}
2020-04-01 10:37:51 +00:00
impl From<ast::LiteralKind> for Literal {
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
match ast_lit_kind {
LiteralKind::IntNumber { suffix } => {
let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it));
Literal::Int(Default::default(), known_name)
}
LiteralKind::FloatNumber { suffix } => {
let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it));
Literal::Float(Default::default(), known_name)
}
LiteralKind::ByteString => Literal::ByteString(Default::default()),
LiteralKind::String => Literal::String(Default::default()),
LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)),
LiteralKind::Bool(val) => Literal::Bool(val),
2020-04-01 10:37:51 +00:00
LiteralKind::Char => Literal::Char(Default::default()),
}
}
}