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
|
|
|
|
2021-04-10 15:49:12 +00:00
|
|
|
use std::{mem, sync::Arc};
|
2020-07-31 17:54:16 +00:00
|
|
|
|
2019-12-03 16:07:56 +00:00
|
|
|
use either::Either;
|
2020-03-14 06:25:30 +00:00
|
|
|
use hir_expand::{
|
2022-07-21 00:06:26 +00:00
|
|
|
ast_id_map::AstIdMap,
|
2020-04-30 10:20:13 +00:00
|
|
|
hygiene::Hygiene,
|
2020-03-14 06:25:30 +00:00
|
|
|
name::{name, AsName, Name},
|
2022-07-21 00:00:58 +00:00
|
|
|
AstId, ExpandError, HirFileId, InFile,
|
2020-03-14 06:25:30 +00:00
|
|
|
};
|
2023-01-09 18:29:28 +00:00
|
|
|
use intern::Interned;
|
2021-01-14 15:47:42 +00:00
|
|
|
use la_arena::Arena;
|
2022-07-20 13:12:00 +00:00
|
|
|
use once_cell::unsync::OnceCell;
|
2021-01-27 09:16:24 +00:00
|
|
|
use profile::Count;
|
2022-03-04 18:49:08 +00:00
|
|
|
use rustc_hash::FxHashMap;
|
2023-02-18 20:32:55 +00:00
|
|
|
use smallvec::SmallVec;
|
2020-08-12 16:26:51 +00:00
|
|
|
use syntax::{
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::{
|
2021-09-27 10:54:24 +00:00
|
|
|
self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
|
2020-07-30 18:51:43 +00:00
|
|
|
SlicePatComponents,
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2020-10-23 17:27:04 +00:00
|
|
|
AstNode, AstPtr, SyntaxNodePtr,
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
2019-11-12 12:09:25 +00:00
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
use crate::{
|
2020-02-21 15:56:34 +00:00
|
|
|
adt::StructKind,
|
2022-09-02 14:57:31 +00:00
|
|
|
body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr},
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
body::{BodyDiagnostic, ExprSource, PatSource},
|
2021-02-28 00:20:04 +00:00
|
|
|
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
2019-11-23 11:44:43 +00:00
|
|
|
db::DefDatabase,
|
2019-11-12 15:46:57 +00:00
|
|
|
expr::{
|
2023-02-18 20:32:55 +00:00
|
|
|
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, ClosureKind, Expr, ExprId,
|
|
|
|
FloatTypeWrapper, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId,
|
|
|
|
RecordFieldPat, RecordLitField, Statement,
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2020-02-21 15:56:34 +00:00
|
|
|
item_scope::BuiltinShadowMode,
|
2020-04-30 10:20:13 +00:00
|
|
|
path::{GenericArgs, Path},
|
2020-05-28 19:42:22 +00:00
|
|
|
type_ref::{Mutability, Rawness, TypeRef},
|
2023-03-04 13:45:57 +00:00
|
|
|
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
|
2021-05-06 17:59:54 +00:00
|
|
|
pub struct LowerCtx<'a> {
|
2021-05-06 21:23:50 +00:00
|
|
|
pub db: &'a dyn DefDatabase,
|
2020-04-30 10:20:13 +00:00
|
|
|
hygiene: Hygiene,
|
2022-07-20 13:12:00 +00:00
|
|
|
ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
|
2020-04-30 10:20:13 +00:00
|
|
|
}
|
|
|
|
|
2021-05-06 17:59:54 +00:00
|
|
|
impl<'a> LowerCtx<'a> {
|
|
|
|
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
2021-04-10 15:49:12 +00:00
|
|
|
LowerCtx {
|
2021-05-06 17:59:54 +00:00
|
|
|
db,
|
2021-04-10 15:49:12 +00:00
|
|
|
hygiene: Hygiene::new(db.upcast(), file_id),
|
2022-07-20 13:12:00 +00:00
|
|
|
ast_id_map: Some((file_id, OnceCell::new())),
|
2021-04-10 15:49:12 +00:00
|
|
|
}
|
2020-04-30 10:20:13 +00:00
|
|
|
}
|
2021-04-10 15:49:12 +00:00
|
|
|
|
2021-05-06 17:59:54 +00:00
|
|
|
pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
|
2022-07-20 13:12:00 +00:00
|
|
|
LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
|
2021-04-10 15:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn hygiene(&self) -> &Hygiene {
|
|
|
|
&self.hygiene
|
|
|
|
}
|
|
|
|
|
2020-11-02 12:13:32 +00:00
|
|
|
pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
|
2021-05-06 21:23:50 +00:00
|
|
|
Path::from_src(ast, self)
|
2021-04-10 15:49:12 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 20:52:28 +00:00
|
|
|
pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<AstId<N>> {
|
2022-07-21 00:06:26 +00:00
|
|
|
let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
|
2023-01-25 20:52:28 +00:00
|
|
|
let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id));
|
2022-07-21 00:06:26 +00:00
|
|
|
Some(InFile::new(file_id, ast_id_map.ast_id(item)))
|
2020-04-30 10:20:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
pub(super) fn lower(
|
2020-03-13 15:05:46 +00:00
|
|
|
db: &dyn DefDatabase,
|
2019-11-14 06:38:25 +00:00
|
|
|
expander: Expander,
|
2022-10-10 07:47:09 +00:00
|
|
|
params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Option<ast::Expr>,
|
|
|
|
) -> (Body, BodySourceMap) {
|
|
|
|
ExprCollector {
|
|
|
|
db,
|
|
|
|
source_map: BodySourceMap::default(),
|
2022-07-21 00:00:58 +00:00
|
|
|
ast_id_map: db.ast_id_map(expander.current_file_id),
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Body {
|
|
|
|
exprs: Arena::default(),
|
|
|
|
pats: Arena::default(),
|
2023-02-18 20:32:55 +00:00
|
|
|
bindings: Arena::default(),
|
2020-12-23 15:34:30 +00:00
|
|
|
labels: Arena::default(),
|
2019-11-12 15:46:57 +00:00
|
|
|
params: Vec::new(),
|
2020-03-19 15:00:11 +00:00
|
|
|
body_expr: dummy_expr_id(),
|
2021-03-05 13:08:23 +00:00
|
|
|
block_scopes: Vec::new(),
|
2021-01-27 09:16:24 +00:00
|
|
|
_c: Count::new(),
|
2022-03-04 18:49:08 +00:00
|
|
|
or_pats: Default::default(),
|
2019-11-12 15:46:57 +00:00
|
|
|
},
|
2020-06-24 14:21:00 +00:00
|
|
|
expander,
|
2022-03-04 19:09:32 +00:00
|
|
|
name_to_pat_grouping: Default::default(),
|
|
|
|
is_lowering_inside_or_pat: false,
|
2022-07-24 13:32:49 +00:00
|
|
|
is_lowering_assignee_expr: false,
|
2022-09-05 13:43:26 +00:00
|
|
|
is_lowering_generator: false,
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
.collect(params, body)
|
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
struct ExprCollector<'a> {
|
|
|
|
db: &'a dyn DefDatabase,
|
2019-11-14 06:38:25 +00:00
|
|
|
expander: Expander,
|
2022-07-21 00:00:58 +00:00
|
|
|
ast_id_map: Arc<AstIdMap>,
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Body,
|
|
|
|
source_map: BodySourceMap,
|
2022-03-04 19:09:32 +00:00
|
|
|
// a poor-mans union-find?
|
|
|
|
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
|
|
|
|
is_lowering_inside_or_pat: bool,
|
2022-07-24 13:32:49 +00:00
|
|
|
is_lowering_assignee_expr: bool,
|
2022-09-05 13:43:26 +00:00
|
|
|
is_lowering_generator: bool,
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
#[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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl ExprCollector<'_> {
|
2019-11-12 15:46:57 +00:00
|
|
|
fn collect(
|
|
|
|
mut self,
|
2022-10-10 07:47:09 +00:00
|
|
|
param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
|
2019-11-12 15:46:57 +00:00
|
|
|
body: Option<ast::Expr>,
|
|
|
|
) -> (Body, BodySourceMap) {
|
2022-10-10 07:47:09 +00:00
|
|
|
if let Some((param_list, mut attr_enabled)) = param_list {
|
|
|
|
if let Some(self_param) =
|
|
|
|
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
|
|
|
|
{
|
2019-11-12 15:46:57 +00:00
|
|
|
let ptr = AstPtr::new(&self_param);
|
2023-02-18 20:32:55 +00:00
|
|
|
let binding_id = self.alloc_binding(
|
|
|
|
name![self],
|
|
|
|
BindingAnnotation::new(
|
|
|
|
self_param.mut_token().is_some() && self_param.amp_token().is_none(),
|
|
|
|
false,
|
|
|
|
),
|
2019-11-12 15:46:57 +00:00
|
|
|
);
|
2023-02-18 20:32:55 +00:00
|
|
|
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);
|
2019-11-12 15:46:57 +00:00
|
|
|
self.body.params.push(param_pat);
|
|
|
|
}
|
|
|
|
|
2022-10-10 07:47:09 +00:00
|
|
|
for pat in param_list
|
|
|
|
.params()
|
|
|
|
.zip(attr_enabled)
|
|
|
|
.filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
|
|
|
|
{
|
2019-11-12 15:46:57 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2021-05-06 17:59:54 +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
|
|
|
}
|
|
|
|
|
2022-09-02 14:57:31 +00:00
|
|
|
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
|
2019-11-14 07:30:30 +00:00
|
|
|
let src = self.expander.to_source(ptr);
|
2022-09-02 13:08:48 +00:00
|
|
|
let id = self.make_expr(expr, src.clone());
|
2019-11-14 07:30:30 +00:00
|
|
|
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 {
|
2022-09-02 13:08:48 +00:00
|
|
|
self.body.exprs.alloc(expr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2020-03-06 14:11:05 +00:00
|
|
|
fn missing_expr(&mut self) -> ExprId {
|
|
|
|
self.alloc_expr_desugared(Expr::Missing)
|
|
|
|
}
|
2022-09-02 13:08:48 +00:00
|
|
|
fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId {
|
2020-03-06 14:11:05 +00:00
|
|
|
let id = self.body.exprs.alloc(expr);
|
2019-11-14 07:30:30 +00:00
|
|
|
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
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId {
|
|
|
|
self.body.bindings.alloc(Binding { name, mode, definitions: SmallVec::new() })
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
|
2019-11-14 07:30:30 +00:00
|
|
|
let src = self.expander.to_source(ptr);
|
2022-09-02 13:08:48 +00:00
|
|
|
let id = self.make_pat(pat, src.clone());
|
2019-11-14 07:30:30 +00:00
|
|
|
self.source_map.pat_map.insert(src, id);
|
2019-11-12 15:46:57 +00:00
|
|
|
id
|
|
|
|
}
|
|
|
|
fn missing_pat(&mut self) -> PatId {
|
2022-09-02 13:08:48 +00:00
|
|
|
self.body.pats.alloc(Pat::Missing)
|
2020-03-06 14:17:48 +00:00
|
|
|
}
|
2022-09-02 13:08:48 +00:00
|
|
|
fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId {
|
2020-03-06 14:17:48 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-09-02 14:57:31 +00:00
|
|
|
fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
|
2020-12-23 15:34:30 +00:00
|
|
|
let src = self.expander.to_source(ptr);
|
|
|
|
let id = self.make_label(label, src.clone());
|
|
|
|
self.source_map.label_map.insert(src, id);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
|
|
|
|
let id = self.body.labels.alloc(label);
|
|
|
|
self.source_map.label_map_back.insert(id, src);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
2021-03-17 14:08:46 +00:00
|
|
|
self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
|
|
|
|
}
|
|
|
|
|
2021-04-07 11:45:17 +00:00
|
|
|
/// Returns `None` if and only if the expression is `#[cfg]`d out.
|
2021-03-17 14:08:46 +00:00
|
|
|
fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
|
2019-11-12 15:46:57 +00:00
|
|
|
let syntax_ptr = AstPtr::new(&expr);
|
2021-03-17 14:08:46 +00:00
|
|
|
self.check_cfg(&expr)?;
|
2020-05-28 02:21:20 +00:00
|
|
|
|
2021-03-17 14:08:46 +00:00
|
|
|
Some(match expr {
|
2019-11-12 15:46:57 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-23 03:39:26 +00:00
|
|
|
let condition = self.collect_expr_opt(e.condition());
|
2019-11-12 15:46:57 +00:00
|
|
|
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2022-01-23 03:39:26 +00:00
|
|
|
ast::Expr::LetExpr(e) => {
|
|
|
|
let pat = self.collect_pat_opt(e.pat());
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
|
|
|
self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
|
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
ast::Expr::BlockExpr(e) => match e.modifier() {
|
|
|
|
Some(ast::BlockModifier::Try(_)) => {
|
2023-03-04 13:45:57 +00:00
|
|
|
self.collect_block_(e, |id, statements, tail| Expr::TryBlock {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
})
|
2020-05-01 23:18:19 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
Some(ast::BlockModifier::Unsafe(_)) => {
|
2023-03-04 13:45:57 +00:00
|
|
|
self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
})
|
2020-05-24 20:24:36 +00:00
|
|
|
}
|
2021-09-26 09:12:57 +00:00
|
|
|
Some(ast::BlockModifier::Label(label)) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = self.collect_label(label);
|
2023-03-04 13:45:57 +00:00
|
|
|
self.collect_block_(e, |id, statements, tail| Expr::Block {
|
|
|
|
id,
|
|
|
|
statements,
|
|
|
|
tail,
|
|
|
|
label: Some(label),
|
|
|
|
})
|
2020-12-23 11:24:24 +00:00
|
|
|
}
|
2023-03-04 13:45:57 +00:00
|
|
|
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 }),
|
2021-09-26 09:12:57 +00:00
|
|
|
None => self.collect_block(e),
|
2020-05-01 23:18:19 +00:00
|
|
|
},
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::LoopExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_block_opt(e.loop_body());
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::WhileExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_block_opt(e.loop_body());
|
|
|
|
|
2022-01-23 03:39:26 +00:00
|
|
|
let condition = self.collect_expr_opt(e.condition());
|
2019-11-12 15:46:57 +00:00
|
|
|
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::ForExpr(e) => {
|
2020-12-23 15:34:30 +00:00
|
|
|
let label = e.label().map(|label| self.collect_label(label));
|
2019-11-12 15:46:57 +00:00
|
|
|
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());
|
2020-12-23 15:34:30 +00:00
|
|
|
self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
|
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() {
|
2021-03-17 14:08:46 +00:00
|
|
|
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
2021-11-20 15:00:45 +00:00
|
|
|
Box::default()
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
2022-07-24 13:32:49 +00:00
|
|
|
self.alloc_expr(
|
|
|
|
Expr::Call { callee, args, is_assignee_expr: self.is_lowering_assignee_expr },
|
|
|
|
syntax_ptr,
|
|
|
|
)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::MethodCallExpr(e) => {
|
2020-08-21 17:12:38 +00:00
|
|
|
let receiver = self.collect_expr_opt(e.receiver());
|
2019-11-12 15:46:57 +00:00
|
|
|
let args = if let Some(arg_list) = e.arg_list() {
|
2021-03-17 14:08:46 +00:00
|
|
|
arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
2021-11-20 15:00:45 +00:00
|
|
|
Box::default()
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
2021-03-30 20:06:57 +00:00
|
|
|
let generic_args = e
|
|
|
|
.generic_arg_list()
|
|
|
|
.and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
|
|
|
|
.map(Box::new);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(
|
2020-06-02 23:09:51 +00:00
|
|
|
Expr::MethodCall { receiver, method_name, args, generic_args },
|
2020-06-02 22:44:04 +00:00
|
|
|
syntax_ptr,
|
2019-11-12 15:46:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
ast::Expr::MatchExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
let arms = if let Some(match_arm_list) = e.match_arm_list() {
|
|
|
|
match_arm_list
|
|
|
|
.arms()
|
2020-10-23 17:27:04 +00:00
|
|
|
.filter_map(|arm| {
|
|
|
|
self.check_cfg(&arm).map(|()| MatchArm {
|
|
|
|
pat: self.collect_pat_opt(arm.pat()),
|
|
|
|
expr: self.collect_expr_opt(arm.expr()),
|
2022-01-23 03:39:26 +00:00
|
|
|
guard: arm
|
|
|
|
.guard()
|
|
|
|
.map(|guard| self.collect_expr_opt(guard.condition())),
|
2020-10-23 17:27:04 +00:00
|
|
|
})
|
2020-06-02 22:44:04 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
} else {
|
2021-11-20 15:00:45 +00:00
|
|
|
Box::default()
|
2020-06-02 22:44:04 +00:00
|
|
|
};
|
|
|
|
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::PathExpr(e) => {
|
|
|
|
let path = e
|
|
|
|
.path()
|
2021-05-06 17:59:54 +00:00
|
|
|
.and_then(|path| self.expander.parse_path(self.db, path))
|
2019-11-12 15:46:57 +00:00
|
|
|
.map(Expr::Path)
|
|
|
|
.unwrap_or(Expr::Missing);
|
2020-05-29 12:55:47 +00:00
|
|
|
self.alloc_expr(path, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2020-06-02 22:04:23 +00:00
|
|
|
ast::Expr::ContinueExpr(e) => self.alloc_expr(
|
2020-12-15 18:23:51 +00:00
|
|
|
Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
|
2020-05-31 10:06:22 +00:00
|
|
|
syntax_ptr,
|
2020-06-02 22:04:23 +00:00
|
|
|
),
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Expr::BreakExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(
|
2020-12-15 18:23:51 +00:00
|
|
|
Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
|
2020-05-31 08:59:40 +00:00
|
|
|
syntax_ptr,
|
2020-06-02 22:44:04 +00:00
|
|
|
)
|
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);
|
2019-11-14 07:30:30 +00:00
|
|
|
self.source_map.expr_map.insert(src, inner);
|
2020-05-29 12:55:47 +00:00
|
|
|
inner
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::ReturnExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2021-01-13 15:01:50 +00:00
|
|
|
ast::Expr::YieldExpr(e) => {
|
2022-09-05 13:43:26 +00:00
|
|
|
self.is_lowering_generator = true;
|
2021-01-13 15:01:50 +00:00
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
|
|
|
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
|
|
|
|
}
|
2022-12-28 23:17:13 +00:00
|
|
|
ast::Expr::YeetExpr(e) => {
|
|
|
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
|
|
|
self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
|
|
|
|
}
|
2020-07-30 14:21:30 +00:00
|
|
|
ast::Expr::RecordExpr(e) => {
|
2021-05-06 17:59:54 +00:00
|
|
|
let path =
|
|
|
|
e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
|
2022-07-24 13:32:49 +00:00
|
|
|
let is_assignee_expr = self.is_lowering_assignee_expr;
|
2020-07-30 14:21:30 +00:00
|
|
|
let record_lit = if let Some(nfl) = e.record_expr_field_list() {
|
2020-06-02 22:44:04 +00:00
|
|
|
let fields = nfl
|
2019-11-12 15:46:57 +00:00
|
|
|
.fields()
|
2020-04-09 16:32:02 +00:00
|
|
|
.filter_map(|field| {
|
2020-10-23 17:27:04 +00:00
|
|
|
self.check_cfg(&field)?;
|
|
|
|
|
2020-04-11 14:42:24 +00:00
|
|
|
let name = field.field_name()?.as_name();
|
2020-04-09 16:32:02 +00:00
|
|
|
|
2021-03-15 12:38:50 +00:00
|
|
|
let expr = match field.expr() {
|
|
|
|
Some(e) => self.collect_expr(e),
|
|
|
|
None => self.missing_expr(),
|
|
|
|
};
|
|
|
|
let src = self.expander.to_source(AstPtr::new(&field));
|
|
|
|
self.source_map.field_map.insert(src.clone(), expr);
|
|
|
|
self.source_map.field_map_back.insert(expr, src);
|
|
|
|
Some(RecordLitField { name, expr })
|
2019-11-12 15:46:57 +00:00
|
|
|
})
|
2020-06-02 22:44:04 +00:00
|
|
|
.collect();
|
2019-11-12 15:46:57 +00:00
|
|
|
let spread = nfl.spread().map(|s| self.collect_expr(s));
|
2022-07-22 09:12:21 +00:00
|
|
|
let ellipsis = nfl.dotdot_token().is_some();
|
2022-07-24 13:32:49 +00:00
|
|
|
Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
|
2019-11-12 15:46:57 +00:00
|
|
|
} else {
|
2022-07-24 13:32:49 +00:00
|
|
|
Expr::RecordLit {
|
|
|
|
path,
|
|
|
|
fields: Box::default(),
|
|
|
|
spread: None,
|
|
|
|
ellipsis: false,
|
|
|
|
is_assignee_expr,
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
|
2021-03-15 12:38:50 +00:00
|
|
|
self.alloc_expr(record_lit, syntax_ptr)
|
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(),
|
|
|
|
};
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::AwaitExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Await { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::TryExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Try { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::CastExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::RefExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-05-28 19:42:22 +00:00
|
|
|
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);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::PrefixExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2021-10-03 12:53:01 +00:00
|
|
|
match e.op_kind() {
|
|
|
|
Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
|
|
|
|
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-31 15:08:58 +00:00
|
|
|
ast::Expr::ClosureExpr(e) => {
|
2019-11-12 15:46:57 +00:00
|
|
|
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());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref =
|
|
|
|
param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
2019-11-12 15:46:57 +00:00
|
|
|
args.push(pat);
|
|
|
|
arg_types.push(type_ref);
|
|
|
|
}
|
|
|
|
}
|
2021-03-30 20:06:57 +00:00
|
|
|
let ret_type = e
|
|
|
|
.ret_type()
|
|
|
|
.and_then(|r| r.ty())
|
2021-04-06 14:07:45 +00:00
|
|
|
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
2022-09-05 13:43:26 +00:00
|
|
|
|
|
|
|
let prev_is_lowering_generator = self.is_lowering_generator;
|
|
|
|
self.is_lowering_generator = false;
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
let body = self.collect_expr_opt(e.body());
|
2022-09-05 13:43:26 +00:00
|
|
|
|
|
|
|
let closure_kind = if self.is_lowering_generator {
|
|
|
|
let movability = if e.static_token().is_some() {
|
|
|
|
Movability::Static
|
|
|
|
} else {
|
|
|
|
Movability::Movable
|
|
|
|
};
|
|
|
|
ClosureKind::Generator(movability)
|
|
|
|
} else {
|
|
|
|
ClosureKind::Closure
|
|
|
|
};
|
|
|
|
self.is_lowering_generator = prev_is_lowering_generator;
|
|
|
|
|
2021-11-20 15:00:45 +00:00
|
|
|
self.alloc_expr(
|
2022-05-20 13:40:32 +00:00
|
|
|
Expr::Closure {
|
|
|
|
args: args.into(),
|
|
|
|
arg_types: arg_types.into(),
|
|
|
|
ret_type,
|
|
|
|
body,
|
2022-09-05 13:43:26 +00:00
|
|
|
closure_kind,
|
2022-05-20 13:40:32 +00:00
|
|
|
},
|
2021-11-20 15:00:45 +00:00
|
|
|
syntax_ptr,
|
|
|
|
)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::BinExpr(e) => {
|
2022-07-24 13:32:49 +00:00
|
|
|
let op = e.op_kind();
|
|
|
|
if let Some(ast::BinaryOp::Assignment { op: None }) = op {
|
|
|
|
self.is_lowering_assignee_expr = true;
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
let lhs = self.collect_expr_opt(e.lhs());
|
2022-07-24 13:32:49 +00:00
|
|
|
self.is_lowering_assignee_expr = false;
|
2019-11-12 15:46:57 +00:00
|
|
|
let rhs = self.collect_expr_opt(e.rhs());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::TupleExpr(e) => {
|
2020-07-31 19:58:36 +00:00
|
|
|
let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
|
2022-07-24 13:32:49 +00:00
|
|
|
self.alloc_expr(
|
|
|
|
Expr::Tuple { exprs, is_assignee_expr: self.is_lowering_assignee_expr },
|
|
|
|
syntax_ptr,
|
|
|
|
)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Expr::BoxExpr(e) => {
|
|
|
|
let expr = self.collect_expr_opt(e.expr());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Box { expr }, syntax_ptr)
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ast::Expr::ArrayExpr(e) => {
|
|
|
|
let kind = e.kind();
|
|
|
|
|
|
|
|
match kind {
|
|
|
|
ArrayExprKind::ElementList(e) => {
|
2022-07-24 13:32:49 +00:00
|
|
|
let elements = e.map(|expr| self.collect_expr(expr)).collect();
|
|
|
|
self.alloc_expr(
|
|
|
|
Expr::Array(Array::ElementList {
|
|
|
|
elements,
|
|
|
|
is_assignee_expr: self.is_lowering_assignee_expr,
|
|
|
|
}),
|
|
|
|
syntax_ptr,
|
|
|
|
)
|
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);
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(
|
|
|
|
Expr::Array(Array::Repeat { initializer, repeat }),
|
|
|
|
syntax_ptr,
|
2019-11-12 15:46:57 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 12:55:47 +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());
|
2020-06-02 22:44:04 +00:00
|
|
|
self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
|
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() {
|
2020-06-02 22:44:04 +00:00
|
|
|
Some(range_type) => {
|
|
|
|
self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
|
|
|
|
}
|
2020-05-29 12:55:47 +00:00
|
|
|
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
2019-11-28 19:10:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-05 15:42:07 +00:00
|
|
|
ast::Expr::MacroExpr(e) => {
|
|
|
|
let e = e.macro_call()?;
|
2021-04-10 21:12:02 +00:00
|
|
|
let macro_ptr = AstPtr::new(&e);
|
2022-07-01 12:43:57 +00:00
|
|
|
let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
|
2022-03-20 18:13:50 +00:00
|
|
|
expansion.map(|it| this.collect_expr(it))
|
2020-12-15 06:39:15 +00:00
|
|
|
});
|
2022-03-20 18:07:44 +00:00
|
|
|
match id {
|
|
|
|
Some(id) => {
|
2022-07-01 12:43:57 +00:00
|
|
|
// Make the macro-call point to its expanded expression so we can query
|
|
|
|
// semantics on syntax pointers to the macro
|
|
|
|
let src = self.expander.to_source(syntax_ptr);
|
|
|
|
self.source_map.expr_map.insert(src, id);
|
2022-03-20 18:07:44 +00:00
|
|
|
id
|
|
|
|
}
|
2022-07-01 12:43:57 +00:00
|
|
|
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
2022-03-20 18:07:44 +00:00
|
|
|
}
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2022-05-26 17:14:06 +00:00
|
|
|
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
|
2021-03-17 14:08:46 +00:00
|
|
|
})
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2020-11-30 19:26:35 +00:00
|
|
|
|
2022-03-20 18:13:50 +00:00
|
|
|
fn collect_macro_call<F, T, U>(
|
2020-12-15 06:39:15 +00:00
|
|
|
&mut self,
|
2022-03-05 20:58:51 +00:00
|
|
|
mcall: ast::MacroCall,
|
2021-04-10 21:12:02 +00:00
|
|
|
syntax_ptr: AstPtr<ast::MacroCall>,
|
2022-01-11 13:34:25 +00:00
|
|
|
record_diagnostics: bool,
|
2022-03-20 18:07:44 +00:00
|
|
|
collector: F,
|
2022-03-20 18:13:50 +00:00
|
|
|
) -> U
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut Self, Option<T>) -> U,
|
|
|
|
T: ast::AstNode,
|
|
|
|
{
|
2020-12-15 14:37:37 +00:00
|
|
|
// File containing the macro call. Expansion errors will be attached here.
|
|
|
|
let outer_file = self.expander.current_file_id;
|
2020-12-15 06:39:15 +00:00
|
|
|
|
2022-03-05 20:58:51 +00:00
|
|
|
let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
|
|
|
|
let res = self.expander.enter_expand(self.db, mcall);
|
2020-12-15 14:37:37 +00:00
|
|
|
|
2021-03-16 07:46:57 +00:00
|
|
|
let res = match res {
|
|
|
|
Ok(res) => res,
|
2021-04-16 13:48:03 +00:00
|
|
|
Err(UnresolvedMacro { path }) => {
|
2022-01-11 13:34:25 +00:00
|
|
|
if record_diagnostics {
|
|
|
|
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
|
|
|
path,
|
|
|
|
});
|
|
|
|
}
|
2022-03-20 18:13:50 +00:00
|
|
|
return collector(self, None);
|
2021-03-16 07:46:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-11 13:34:25 +00:00
|
|
|
if record_diagnostics {
|
|
|
|
match &res.err {
|
2022-06-28 08:41:10 +00:00
|
|
|
Some(ExpandError::UnresolvedProcMacro(krate)) => {
|
2022-01-11 13:34:25 +00:00
|
|
|
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
2022-06-28 08:41:10 +00:00
|
|
|
krate: *krate,
|
2022-01-11 13:34:25 +00:00
|
|
|
});
|
|
|
|
}
|
2023-02-08 11:11:54 +00:00
|
|
|
Some(ExpandError::RecursionOverflowPosioned) => {
|
|
|
|
// Recursion limit has been reached in the macro expansion tree, but not in
|
|
|
|
// this very macro call. Don't add diagnostics to avoid duplication.
|
|
|
|
}
|
2022-01-11 13:34:25 +00:00
|
|
|
Some(err) => {
|
|
|
|
self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
|
|
|
|
node: InFile::new(outer_file, syntax_ptr),
|
|
|
|
message: err.to_string(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {}
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2020-12-15 14:37:37 +00:00
|
|
|
}
|
2020-12-15 06:39:15 +00:00
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
match res.value {
|
|
|
|
Some((mark, expansion)) => {
|
2023-02-08 11:11:54 +00:00
|
|
|
// Keep collecting even with expansion errors so we can provide completions and
|
|
|
|
// other services in incomplete macro expressions.
|
2022-03-05 20:58:51 +00:00
|
|
|
self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id);
|
2022-07-21 00:00:58 +00:00
|
|
|
let prev_ast_id_map = mem::replace(
|
|
|
|
&mut self.ast_id_map,
|
|
|
|
self.db.ast_id_map(self.expander.current_file_id),
|
|
|
|
);
|
2020-12-15 06:39:15 +00:00
|
|
|
|
2021-09-05 22:16:12 +00:00
|
|
|
let id = collector(self, Some(expansion));
|
2022-07-21 00:00:58 +00:00
|
|
|
self.ast_id_map = prev_ast_id_map;
|
2021-09-05 22:16:12 +00:00
|
|
|
self.expander.exit(self.db, mark);
|
|
|
|
id
|
2019-12-23 13:47:11 +00:00
|
|
|
}
|
2020-12-15 14:37:37 +00:00
|
|
|
None => collector(self, None),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
|
2021-10-03 12:53:01 +00:00
|
|
|
match expr {
|
|
|
|
Some(expr) => self.collect_expr(expr),
|
|
|
|
None => self.missing_expr(),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:58:11 +00:00
|
|
|
fn collect_macro_as_stmt(
|
|
|
|
&mut self,
|
2022-08-31 16:05:52 +00:00
|
|
|
statements: &mut Vec<Statement>,
|
2022-08-31 14:58:11 +00:00
|
|
|
mac: ast::MacroExpr,
|
2022-08-31 16:05:52 +00:00
|
|
|
) -> Option<ExprId> {
|
2022-08-31 14:58:11 +00:00
|
|
|
let mac_call = mac.macro_call()?;
|
|
|
|
let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
|
|
|
|
let macro_ptr = AstPtr::new(&mac_call);
|
|
|
|
let expansion = self.collect_macro_call(
|
|
|
|
mac_call,
|
|
|
|
macro_ptr,
|
|
|
|
false,
|
|
|
|
|this, expansion: Option<ast::MacroStmts>| match expansion {
|
|
|
|
Some(expansion) => {
|
2022-08-31 16:05:52 +00:00
|
|
|
expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
|
|
|
|
expansion.expr().and_then(|expr| match expr {
|
|
|
|
ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
|
2022-08-31 14:58:11 +00:00
|
|
|
expr => Some(this.collect_expr(expr)),
|
2022-08-31 16:05:52 +00:00
|
|
|
})
|
2022-08-31 14:58:11 +00:00
|
|
|
}
|
|
|
|
None => None,
|
|
|
|
},
|
|
|
|
);
|
2022-08-31 16:05:52 +00:00
|
|
|
match expansion {
|
|
|
|
Some(tail) => {
|
2022-08-31 14:58:11 +00:00
|
|
|
// Make the macro-call point to its expanded expression so we can query
|
|
|
|
// semantics on syntax pointers to the macro
|
|
|
|
let src = self.expander.to_source(syntax_ptr);
|
2022-08-31 16:05:52 +00:00
|
|
|
self.source_map.expr_map.insert(src, tail);
|
|
|
|
Some(tail)
|
2022-08-31 14:58:11 +00:00
|
|
|
}
|
2022-08-31 16:05:52 +00:00
|
|
|
None => None,
|
|
|
|
}
|
2022-08-31 14:58:11 +00:00
|
|
|
}
|
|
|
|
|
2022-08-31 16:05:52 +00:00
|
|
|
fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
|
2021-03-25 19:52:35 +00:00
|
|
|
match s {
|
2021-03-16 05:44:50 +00:00
|
|
|
ast::Stmt::LetStmt(stmt) => {
|
2021-03-25 19:52:35 +00:00
|
|
|
if self.check_cfg(&stmt).is_none() {
|
2022-08-31 16:05:52 +00:00
|
|
|
return;
|
2021-03-25 19:52:35 +00:00
|
|
|
}
|
2021-03-16 05:44:50 +00:00
|
|
|
let pat = self.collect_pat_opt(stmt.pat());
|
2021-04-06 14:07:45 +00:00
|
|
|
let type_ref =
|
|
|
|
stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
2021-03-16 05:44:50 +00:00
|
|
|
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
|
2021-10-07 15:05:50 +00:00
|
|
|
let else_branch = stmt
|
|
|
|
.let_else()
|
|
|
|
.and_then(|let_else| let_else.block_expr())
|
|
|
|
.map(|block| self.collect_block(block));
|
2022-08-31 16:05:52 +00:00
|
|
|
statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
|
|
|
ast::Stmt::ExprStmt(stmt) => {
|
2022-07-01 12:43:57 +00:00
|
|
|
let expr = stmt.expr();
|
2022-08-31 16:05:52 +00:00
|
|
|
match &expr {
|
|
|
|
Some(expr) if self.check_cfg(expr).is_none() => return,
|
|
|
|
_ => (),
|
2021-03-25 19:52:35 +00:00
|
|
|
}
|
2021-04-07 11:45:17 +00:00
|
|
|
let has_semi = stmt.semicolon_token().is_some();
|
2022-07-01 12:43:57 +00:00
|
|
|
// Note that macro could be expanded to multiple statements
|
2022-08-31 14:58:11 +00:00
|
|
|
if let Some(ast::Expr::MacroExpr(mac)) = expr {
|
2022-08-31 16:05:52 +00:00
|
|
|
if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
|
|
|
|
statements.push(Statement::Expr { expr, has_semi })
|
2022-08-31 14:58:11 +00:00
|
|
|
}
|
2021-03-16 05:44:50 +00:00
|
|
|
} else {
|
2022-07-01 12:43:57 +00:00
|
|
|
let expr = self.collect_expr_opt(expr);
|
2022-08-31 16:05:52 +00:00
|
|
|
statements.push(Statement::Expr { expr, has_semi });
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
2021-03-16 05:44:50 +00:00
|
|
|
}
|
2022-08-31 16:05:52 +00:00
|
|
|
ast::Stmt::Item(_item) => (),
|
2021-03-25 19:52:35 +00:00
|
|
|
}
|
2020-12-15 06:39:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
|
2023-03-04 13:45:57 +00:00
|
|
|
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 {
|
2022-07-21 00:00:58 +00:00
|
|
|
let file_local_id = self.ast_id_map.ast_id(&block);
|
|
|
|
let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
|
2021-02-04 14:04:21 +00:00
|
|
|
let block_loc =
|
|
|
|
BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
|
2021-02-01 12:19:55 +00:00
|
|
|
let block_id = self.db.intern_block(block_loc);
|
2021-03-05 13:08:23 +00:00
|
|
|
|
2021-04-04 01:16:26 +00:00
|
|
|
let (module, def_map) = match self.db.block_def_map(block_id) {
|
|
|
|
Some(def_map) => {
|
|
|
|
self.body.block_scopes.push(block_id);
|
|
|
|
(def_map.root(), def_map)
|
|
|
|
}
|
|
|
|
None => (self.expander.module, self.expander.def_map.clone()),
|
|
|
|
};
|
2021-02-01 12:19:55 +00:00
|
|
|
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
|
2021-02-04 14:04:21 +00:00
|
|
|
let prev_local_module = mem::replace(&mut self.expander.module, module);
|
2022-07-01 12:43:57 +00:00
|
|
|
|
2022-08-31 16:05:52 +00:00
|
|
|
let mut statements = Vec::new();
|
|
|
|
block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
|
2022-08-31 14:58:11 +00:00
|
|
|
let tail = block.tail_expr().and_then(|e| match e {
|
2022-08-31 16:05:52 +00:00
|
|
|
ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
|
2022-08-31 14:58:11 +00:00
|
|
|
expr => self.maybe_collect_expr(expr),
|
|
|
|
});
|
2022-07-01 13:52:52 +00:00
|
|
|
let tail = tail.or_else(|| {
|
|
|
|
let stmt = statements.pop()?;
|
|
|
|
if let Statement::Expr { expr, has_semi: false } = stmt {
|
|
|
|
return Some(expr);
|
|
|
|
}
|
|
|
|
statements.push(stmt);
|
|
|
|
None
|
|
|
|
});
|
2022-07-01 12:43:57 +00:00
|
|
|
|
2021-02-05 15:57:26 +00:00
|
|
|
let syntax_node_ptr = AstPtr::new(&block.into());
|
2023-03-04 13:45:57 +00:00
|
|
|
let expr_id = self
|
|
|
|
.alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
|
2021-02-01 12:19:55 +00:00
|
|
|
|
|
|
|
self.expander.def_map = prev_def_map;
|
2021-02-04 14:04:21 +00:00
|
|
|
self.expander.module = prev_local_module;
|
2021-02-01 12:19:55 +00:00
|
|
|
expr_id
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
|
2021-10-03 12:53:01 +00:00
|
|
|
match expr {
|
|
|
|
Some(block) => self.collect_block(block),
|
|
|
|
None => self.missing_expr(),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-23 15:34:30 +00:00
|
|
|
fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
|
|
|
|
let label = Label {
|
|
|
|
name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
|
|
|
|
};
|
|
|
|
self.alloc_label(label, AstPtr::new(&ast_label))
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:46:57 +00:00
|
|
|
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
|
2023-02-18 20:32:55 +00:00
|
|
|
let pat_id = self.collect_pat_(pat, &mut BindingList::default());
|
2022-03-04 19:09:32 +00:00
|
|
|
for (_, pats) in self.name_to_pat_grouping.drain() {
|
2022-03-04 18:49:08 +00:00
|
|
|
let pats = Arc::<[_]>::from(pats);
|
2022-03-04 19:09:32 +00:00
|
|
|
self.body.or_pats.extend(pats.iter().map(|&pat| (pat, pats.clone())));
|
2022-03-04 18:49:08 +00:00
|
|
|
}
|
2022-03-04 19:09:32 +00:00
|
|
|
self.is_lowering_inside_or_pat = false;
|
2022-03-04 18:49:08 +00:00
|
|
|
pat_id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
|
|
|
|
match pat {
|
|
|
|
Some(pat) => self.collect_pat(pat),
|
|
|
|
None => self.missing_pat(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
fn collect_pat_(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId {
|
2019-11-12 15:46:57 +00:00
|
|
|
let pattern = match &pat {
|
2020-07-31 18:09:09 +00:00
|
|
|
ast::Pat::IdentPat(bp) => {
|
2019-11-12 15:46:57 +00:00
|
|
|
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
2022-03-04 18:49:08 +00:00
|
|
|
|
2022-03-04 19:09:32 +00:00
|
|
|
let key = self.is_lowering_inside_or_pat.then(|| name.clone());
|
2020-04-09 21:35:05 +00:00
|
|
|
let annotation =
|
|
|
|
BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
|
2023-02-18 20:32:55 +00:00
|
|
|
let subpat = bp.pat().map(|subpat| self.collect_pat_(subpat, binding_list));
|
|
|
|
let (binding, pattern) = if annotation == BindingAnnotation::Unannotated
|
|
|
|
&& subpat.is_none()
|
|
|
|
{
|
2020-02-21 15:56:34 +00:00
|
|
|
// This could also be a single-segment path pattern. To
|
|
|
|
// decide that, we need to try resolving the name.
|
2021-02-01 12:19:55 +00:00
|
|
|
let (resolved, _) = self.expander.def_map.resolve_path(
|
2020-02-21 15:56:34 +00:00
|
|
|
self.db,
|
2021-02-04 14:04:21 +00:00
|
|
|
self.expander.module,
|
2020-02-21 15:56:34 +00:00
|
|
|
&name.clone().into(),
|
|
|
|
BuiltinShadowMode::Other,
|
|
|
|
);
|
|
|
|
match resolved.take_values() {
|
2023-02-18 20:32:55 +00:00
|
|
|
Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
|
2020-02-21 15:56:34 +00:00
|
|
|
Some(ModuleDefId::EnumVariantId(_)) => {
|
|
|
|
// this is only really valid for unit variants, but
|
|
|
|
// shadowing other enum variants with a pattern is
|
|
|
|
// an error anyway
|
2023-02-18 20:32:55 +00:00
|
|
|
(None, Pat::Path(name.into()))
|
2020-02-21 15:56:34 +00:00
|
|
|
}
|
|
|
|
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).
|
2023-02-18 20:32:55 +00:00
|
|
|
(None, Pat::Path(name.into()))
|
2020-02-21 15:56:34 +00:00
|
|
|
}
|
|
|
|
// shadowing statics is an error as well, so we just ignore that case here
|
2023-02-18 20:32:55 +00:00
|
|
|
_ => {
|
|
|
|
let id = binding_list.find(self, name, annotation);
|
|
|
|
(Some(id), Pat::Bind { id, subpat })
|
|
|
|
}
|
2020-02-21 15:56:34 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-02-18 20:32:55 +00:00
|
|
|
let id = binding_list.find(self, name, annotation);
|
|
|
|
(Some(id), Pat::Bind { id, subpat })
|
2022-03-04 18:49:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let ptr = AstPtr::new(&pat);
|
|
|
|
let pat = self.alloc_pat(pattern, Either::Left(ptr));
|
2023-02-18 20:32:55 +00:00
|
|
|
if let Some(binding_id) = binding {
|
|
|
|
self.add_definition_to_binding(binding_id, pat);
|
|
|
|
}
|
2022-03-04 18:49:08 +00:00
|
|
|
if let Some(key) = key {
|
2022-03-04 19:09:32 +00:00
|
|
|
self.name_to_pat_grouping.entry(key).or_default().push(pat);
|
2020-02-21 15:56:34 +00:00
|
|
|
}
|
2022-03-04 18:49:08 +00:00
|
|
|
return pat;
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Pat::TupleStructPat(p) => {
|
2021-05-06 17:59:54 +00:00
|
|
|
let path =
|
|
|
|
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
|
2023-02-18 20:32:55 +00:00
|
|
|
let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list);
|
2020-04-12 15:40:09 +00:00
|
|
|
Pat::TupleStruct { path, args, ellipsis }
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
ast::Pat::RefPat(p) => {
|
2023-02-18 20:32:55 +00:00
|
|
|
let pat = self.collect_pat_opt_(p.pat(), binding_list);
|
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) => {
|
2021-05-06 17:59:54 +00:00
|
|
|
let path =
|
|
|
|
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
|
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) => {
|
2022-03-04 19:09:32 +00:00
|
|
|
self.is_lowering_inside_or_pat = true;
|
2023-02-18 20:32:55 +00:00
|
|
|
let pats = p.pats().map(|p| self.collect_pat_(p, binding_list)).collect();
|
2020-02-09 18:57:01 +00:00
|
|
|
Pat::Or(pats)
|
|
|
|
}
|
2023-02-18 20:32:55 +00:00
|
|
|
ast::Pat::ParenPat(p) => return self.collect_pat_opt_(p.pat(), binding_list),
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Pat::TuplePat(p) => {
|
2023-02-18 20:32:55 +00:00
|
|
|
let (args, ellipsis) = self.collect_tuple_pat(p.fields(), binding_list);
|
2020-04-12 15:40:09 +00:00
|
|
|
Pat::Tuple { args, ellipsis }
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2020-07-31 18:07:21 +00:00
|
|
|
ast::Pat::WildcardPat(_) => Pat::Wild,
|
2019-11-12 15:46:57 +00:00
|
|
|
ast::Pat::RecordPat(p) => {
|
2021-05-06 17:59:54 +00:00
|
|
|
let path =
|
|
|
|
p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
|
2021-11-20 15:17:16 +00:00
|
|
|
let args = p
|
2020-07-31 17:54:16 +00:00
|
|
|
.record_pat_field_list()
|
|
|
|
.expect("every struct should have a field list")
|
|
|
|
.fields()
|
|
|
|
.filter_map(|f| {
|
|
|
|
let ast_pat = f.pat()?;
|
2023-02-18 20:32:55 +00:00
|
|
|
let pat = self.collect_pat_(ast_pat, binding_list);
|
2020-07-31 17:54:16 +00:00
|
|
|
let name = f.field_name()?.as_name();
|
2019-11-12 15:46:57 +00:00
|
|
|
Some(RecordFieldPat { name, pat })
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2020-07-31 17:54:16 +00:00
|
|
|
let ellipsis = p
|
|
|
|
.record_pat_field_list()
|
|
|
|
.expect("every struct should have a field list")
|
2021-10-02 01:57:44 +00:00
|
|
|
.rest_pat()
|
2020-07-31 17:54:16 +00:00
|
|
|
.is_some();
|
2020-04-09 03:23:51 +00:00
|
|
|
|
2020-07-31 17:54:16 +00:00
|
|
|
Pat::Record { path, args, ellipsis }
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2020-02-11 21:33:11 +00:00
|
|
|
ast::Pat::SlicePat(p) => {
|
|
|
|
let SlicePatComponents { prefix, slice, suffix } = p.components();
|
|
|
|
|
2020-07-31 19:59:40 +00:00
|
|
|
// FIXME properly handle `RestPat`
|
2020-02-11 21:33:11 +00:00
|
|
|
Pat::Slice {
|
2023-02-18 20:32:55 +00:00
|
|
|
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(),
|
2020-02-11 21:33:11 +00:00
|
|
|
}
|
|
|
|
}
|
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-07-31 19:45:29 +00:00
|
|
|
ast::Pat::RestPat(_) => {
|
2020-07-31 19:59:40 +00:00
|
|
|
// `RestPat` requires special handling and should not be mapped
|
2020-04-17 12:36:44 +00:00
|
|
|
// to a Pat. Here we are using `Pat::Missing` as a fallback for
|
2020-07-31 19:59:40 +00:00
|
|
|
// when `RestPat` is mapped to `Pat`, which can easily happen
|
2020-04-17 12:36:44 +00:00
|
|
|
// when the source code being analyzed has a malformed pattern
|
|
|
|
// which includes `..` in a place where it isn't valid.
|
|
|
|
|
|
|
|
Pat::Missing
|
|
|
|
}
|
2020-09-12 19:18:57 +00:00
|
|
|
ast::Pat::BoxPat(boxpat) => {
|
2023-02-18 20:32:55 +00:00
|
|
|
let inner = self.collect_pat_opt_(boxpat.pat(), binding_list);
|
2020-09-12 19:18:57 +00:00
|
|
|
Pat::Box { inner }
|
|
|
|
}
|
2020-12-23 11:15:38 +00:00
|
|
|
ast::Pat::ConstBlockPat(const_block_pat) => {
|
|
|
|
if let Some(expr) = const_block_pat.block_expr() {
|
|
|
|
let expr_id = self.collect_block(expr);
|
|
|
|
Pat::ConstBlock(expr_id)
|
|
|
|
} else {
|
|
|
|
Pat::Missing
|
|
|
|
}
|
2020-12-23 00:26:31 +00:00
|
|
|
}
|
2021-04-10 21:12:02 +00:00
|
|
|
ast::Pat::MacroPat(mac) => match mac.macro_call() {
|
|
|
|
Some(call) => {
|
|
|
|
let macro_ptr = AstPtr::new(&call);
|
2022-07-01 12:43:57 +00:00
|
|
|
let src = self.expander.to_source(Either::Left(AstPtr::new(&pat)));
|
2022-03-20 18:13:50 +00:00
|
|
|
let pat =
|
|
|
|
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
|
2023-02-18 20:32:55 +00:00
|
|
|
this.collect_pat_opt_(expanded_pat, binding_list)
|
2022-03-20 18:13:50 +00:00
|
|
|
});
|
2022-07-01 12:43:57 +00:00
|
|
|
self.source_map.pat_map.insert(src, pat);
|
2022-03-20 18:13:50 +00:00
|
|
|
return pat;
|
2021-04-10 21:12:02 +00:00
|
|
|
}
|
|
|
|
None => Pat::Missing,
|
|
|
|
},
|
2020-12-23 11:15:38 +00:00
|
|
|
// FIXME: implement
|
2021-04-10 21:12:02 +00:00
|
|
|
ast::Pat::RangePat(_) => Pat::Missing,
|
2019-11-12 15:46:57 +00:00
|
|
|
};
|
|
|
|
let ptr = AstPtr::new(&pat);
|
2019-12-03 16:07:56 +00:00
|
|
|
self.alloc_pat(pattern, Either::Left(ptr))
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
fn collect_pat_opt_(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId {
|
2021-10-03 12:53:01 +00:00
|
|
|
match pat {
|
2023-02-18 20:32:55 +00:00
|
|
|
Some(pat) => self.collect_pat_(pat, binding_list),
|
2021-10-03 12:53:01 +00:00
|
|
|
None => self.missing_pat(),
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-12 15:40:09 +00:00
|
|
|
|
2023-02-18 20:32:55 +00:00
|
|
|
fn collect_tuple_pat(
|
|
|
|
&mut self,
|
|
|
|
args: AstChildren<ast::Pat>,
|
|
|
|
binding_list: &mut BindingList,
|
|
|
|
) -> (Box<[PatId]>, Option<usize>) {
|
2020-04-12 15:40:09 +00:00
|
|
|
// Find the location of the `..`, if there is one. Note that we do not
|
2021-01-08 14:46:48 +00:00
|
|
|
// consider the possibility of there being multiple `..` here.
|
2020-07-31 19:45:29 +00:00
|
|
|
let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
|
2020-04-12 15:40:09 +00:00
|
|
|
// We want to skip the `..` pattern here, since we account for it above.
|
|
|
|
let args = args
|
2020-07-31 19:45:29 +00:00
|
|
|
.filter(|p| !matches!(p, ast::Pat::RestPat(_)))
|
2023-02-18 20:32:55 +00:00
|
|
|
.map(|p| self.collect_pat_(p, binding_list))
|
2020-04-12 15:40:09 +00:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
(args, ellipsis)
|
|
|
|
}
|
2020-10-23 17:27:04 +00:00
|
|
|
|
|
|
|
/// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
|
|
|
|
/// not.
|
2021-09-27 10:54:24 +00:00
|
|
|
fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
|
2020-12-17 23:23:46 +00:00
|
|
|
match self.expander.parse_attrs(self.db, owner).cfg() {
|
2020-10-23 17:27:04 +00:00
|
|
|
Some(cfg) => {
|
|
|
|
if self.expander.cfg_options().check(&cfg) != Some(false) {
|
|
|
|
return Some(());
|
|
|
|
}
|
|
|
|
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
|
|
|
|
node: InFile::new(
|
|
|
|
self.expander.current_file_id,
|
|
|
|
SyntaxNodePtr::new(owner.syntax()),
|
|
|
|
),
|
2020-10-23 17:27:04 +00:00
|
|
|
cfg,
|
|
|
|
opts: self.expander.cfg_options().clone(),
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
});
|
2020-10-23 17:27:04 +00:00
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
None => Some(()),
|
|
|
|
}
|
|
|
|
}
|
2023-02-18 20:32:55 +00:00
|
|
|
|
|
|
|
fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
|
|
|
|
self.body.bindings[binding_id].definitions.push(pat_id);
|
|
|
|
}
|
2019-11-12 15:46:57 +00:00
|
|
|
}
|
2019-11-12 12:09:25 +00:00
|
|
|
|
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 {
|
2021-05-12 12:59:35 +00:00
|
|
|
// FIXME: these should have actual values filled in, but unsure on perf impact
|
2020-11-06 21:52:22 +00:00
|
|
|
LiteralKind::IntNumber(lit) => {
|
2021-02-28 00:20:04 +00:00
|
|
|
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
|
2022-05-26 10:35:25 +00:00
|
|
|
Literal::Float(
|
|
|
|
FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
|
|
|
|
builtin,
|
|
|
|
)
|
2022-03-12 12:35:31 +00:00
|
|
|
} else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinInt::from_suffix) {
|
2021-05-12 12:59:35 +00:00
|
|
|
Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
|
2021-02-28 00:20:04 +00:00
|
|
|
} else {
|
2022-03-12 12:35:31 +00:00
|
|
|
let builtin = lit.suffix().and_then(BuiltinUint::from_suffix);
|
2021-05-12 12:59:35 +00:00
|
|
|
Literal::Uint(lit.value().unwrap_or(0), builtin)
|
2020-11-06 21:52:22 +00:00
|
|
|
}
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
2020-11-06 21:52:22 +00:00
|
|
|
LiteralKind::FloatNumber(lit) => {
|
2022-05-13 13:08:14 +00:00
|
|
|
let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
|
2022-05-26 10:35:25 +00:00
|
|
|
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
2021-05-12 12:44:01 +00:00
|
|
|
LiteralKind::ByteString(bs) => {
|
2021-11-20 15:17:16 +00:00
|
|
|
let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
|
2021-05-12 12:44:01 +00:00
|
|
|
Literal::ByteString(text)
|
|
|
|
}
|
2022-03-01 07:44:53 +00:00
|
|
|
LiteralKind::String(s) => {
|
|
|
|
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
|
|
|
|
Literal::String(text)
|
|
|
|
}
|
2022-05-05 05:10:07 +00:00
|
|
|
LiteralKind::Byte(b) => {
|
|
|
|
Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
|
|
|
|
}
|
|
|
|
LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
|
2020-04-01 11:47:41 +00:00
|
|
|
LiteralKind::Bool(val) => Literal::Bool(val),
|
2020-04-01 10:37:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|